diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/restricted/aws/s2n/crypto | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) | |
download | ydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/aws/s2n/crypto')
46 files changed, 6855 insertions, 6855 deletions
diff --git a/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_aes_gcm.c b/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_aes_gcm.c index 55418362d0..d5ee2063aa 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_aes_gcm.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_aes_gcm.c @@ -1,364 +1,364 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/aes.h> -#include <openssl/evp.h> - -#include "crypto/s2n_cipher.h" - -#include "tls/s2n_crypto.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" - -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) -#define S2N_AEAD_AES_GCM_AVAILABLE -#endif - -static uint8_t s2n_aead_cipher_aes128_gcm_available() -{ -#if defined(S2N_AEAD_AES_GCM_AVAILABLE) - return (EVP_aead_aes_128_gcm() ? 1 : 0); -#else - return (EVP_aes_128_gcm() ? 1 : 0); -#endif -} - -static uint8_t s2n_aead_cipher_aes256_gcm_available() -{ -#if defined(S2N_AEAD_AES_GCM_AVAILABLE) - return (EVP_aead_aes_256_gcm() ? 1 : 0); -#else - return (EVP_aes_256_gcm() ? 1 : 0); -#endif -} - -#if defined(S2N_AEAD_AES_GCM_AVAILABLE) /* BoringSSL and AWS-LC AEAD API implementation */ - -static int s2n_aead_cipher_aes_gcm_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) -{ - notnull_check(in); - notnull_check(out); - notnull_check(iv); - notnull_check(key); - notnull_check(aad); - - /* The size of the |in| blob includes the size of the data and the size of the AES-GCM tag */ - gte_check(in->size, S2N_TLS_GCM_TAG_LEN); - gte_check(out->size, in->size); - eq_check(iv->size, S2N_TLS_GCM_IV_LEN); - - /* Adjust input length to account for the Tag length */ - size_t in_len = in->size - S2N_TLS_GCM_TAG_LEN; - size_t out_len = 0; - - GUARD_OSSL(EVP_AEAD_CTX_seal(key->evp_aead_ctx, out->data, &out_len, out->size, iv->data, iv->size, in->data, in_len, aad->data, aad->size), S2N_ERR_ENCRYPT); - - S2N_ERROR_IF((in_len + S2N_TLS_GCM_TAG_LEN) != out_len, S2N_ERR_ENCRYPT); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes_gcm_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) -{ - notnull_check(in); - notnull_check(out); - notnull_check(iv); - notnull_check(key); - notnull_check(aad); - - gte_check(in->size, S2N_TLS_GCM_TAG_LEN); - gte_check(out->size, in->size - S2N_TLS_GCM_TAG_LEN); - eq_check(iv->size, S2N_TLS_GCM_IV_LEN); - - size_t out_len = 0; - - GUARD_OSSL(EVP_AEAD_CTX_open(key->evp_aead_ctx, out->data, &out_len, out->size, iv->data, iv->size, in->data, in->size, aad->data, aad->size), S2N_ERR_DECRYPT); - - S2N_ERROR_IF((in->size - S2N_TLS_GCM_TAG_LEN) != out_len, S2N_ERR_ENCRYPT); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes128_gcm_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - notnull_check(key); - notnull_check(in); - - eq_check(in->size, S2N_TLS_AES_128_GCM_KEY_LEN); - - GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_aes_128_gcm(), in->data, in->size, S2N_TLS_GCM_TAG_LEN, NULL), S2N_ERR_KEY_INIT); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes256_gcm_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - notnull_check(key); - notnull_check(in); - - eq_check(in->size, S2N_TLS_AES_256_GCM_KEY_LEN); - - GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_aes_256_gcm(), in->data, in->size, S2N_TLS_GCM_TAG_LEN, NULL), S2N_ERR_KEY_INIT); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes128_gcm_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - notnull_check(key); - notnull_check(in); - - eq_check(in->size, S2N_TLS_AES_128_GCM_KEY_LEN); - - GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_aes_128_gcm(), in->data, in->size, S2N_TLS_GCM_TAG_LEN, NULL), S2N_ERR_KEY_INIT); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes256_gcm_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - notnull_check(key); - notnull_check(in); - - eq_check(in->size, S2N_TLS_AES_256_GCM_KEY_LEN); - - GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_aes_256_gcm(), in->data, in->size, S2N_TLS_GCM_TAG_LEN, NULL), S2N_ERR_KEY_INIT); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes_gcm_init(struct s2n_session_key *key) -{ - notnull_check(key); - - EVP_AEAD_CTX_zero(key->evp_aead_ctx); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes_gcm_destroy_key(struct s2n_session_key *key) -{ - notnull_check(key); - - EVP_AEAD_CTX_cleanup(key->evp_aead_ctx); - - return S2N_SUCCESS; -} - -#else /* Standard AES-GCM implementation */ - -static int s2n_aead_cipher_aes_gcm_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) -{ - /* The size of the |in| blob includes the size of the data and the size of the ChaCha20-Poly1305 tag */ - gte_check(in->size, S2N_TLS_GCM_TAG_LEN); - gte_check(out->size, in->size); - eq_check(iv->size, S2N_TLS_GCM_IV_LEN); - - /* Initialize the IV */ - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); - - /* Adjust input length and buffer pointer to account for the Tag length */ - int in_len = in->size - S2N_TLS_GCM_TAG_LEN; - uint8_t *tag_data = out->data + out->size - S2N_TLS_GCM_TAG_LEN; - - int out_len; - /* Specify the AAD */ - GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, NULL, &out_len, aad->data, aad->size), S2N_ERR_ENCRYPT); - - /* Encrypt the data */ - GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, out->data, &out_len, in->data, in_len), S2N_ERR_ENCRYPT); - - /* When using AES-GCM, *out_len is the number of bytes written by EVP_EncryptUpdate. Since the tag is not written during this call, we do not take S2N_TLS_GCM_TAG_LEN into account */ - S2N_ERROR_IF(in_len != out_len, S2N_ERR_ENCRYPT); - - /* Finalize */ - GUARD_OSSL(EVP_EncryptFinal_ex(key->evp_cipher_ctx, out->data, &out_len), S2N_ERR_ENCRYPT); - - /* write the tag */ - GUARD_OSSL(EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_GET_TAG, S2N_TLS_GCM_TAG_LEN, tag_data), S2N_ERR_ENCRYPT); - - /* When using AES-GCM, EVP_EncryptFinal_ex does not write any bytes. So, we should expect *out_len = 0. */ - S2N_ERROR_IF(0 != out_len, S2N_ERR_ENCRYPT); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes_gcm_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) -{ - gte_check(in->size, S2N_TLS_GCM_TAG_LEN); - gte_check(out->size, in->size); - eq_check(iv->size, S2N_TLS_GCM_IV_LEN); - - /* Initialize the IV */ - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); - - /* Adjust input length and buffer pointer to account for the Tag length */ - int in_len = in->size - S2N_TLS_GCM_TAG_LEN; - uint8_t *tag_data = in->data + in->size - S2N_TLS_GCM_TAG_LEN; - - /* Set the TAG */ - GUARD_OSSL(EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_TAG, S2N_TLS_GCM_TAG_LEN, tag_data), S2N_ERR_DECRYPT); - - int out_len; - /* Specify the AAD */ - GUARD_OSSL(EVP_DecryptUpdate(key->evp_cipher_ctx, NULL, &out_len, aad->data, aad->size), S2N_ERR_DECRYPT); - - int evp_decrypt_rc = 1; - /* Decrypt the data, but don't short circuit tag verification. EVP_Decrypt* return 0 on failure, 1 for success. */ - evp_decrypt_rc &= EVP_DecryptUpdate(key->evp_cipher_ctx, out->data, &out_len, in->data, in_len); - - /* Verify the tag */ - evp_decrypt_rc &= EVP_DecryptFinal_ex(key->evp_cipher_ctx, out->data, &out_len); - - S2N_ERROR_IF(evp_decrypt_rc != 1, S2N_ERR_DECRYPT); - - /* While we verify the content of out_len in s2n_aead_cipher_aes_gcm_encrypt, we refrain from this here. This is to avoid doing any branching before the ciphertext is verified. */ - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes128_gcm_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, S2N_TLS_AES_128_GCM_KEY_LEN); - - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_aes_128_gcm(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); - - EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL); - - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes256_gcm_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, S2N_TLS_AES_256_GCM_KEY_LEN); - - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); - - EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL); - - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes128_gcm_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, S2N_TLS_AES_128_GCM_KEY_LEN); - - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_aes_128_gcm(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); - - EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL); - - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes256_gcm_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, S2N_TLS_AES_256_GCM_KEY_LEN); - - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); - - EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL); - - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes_gcm_init(struct s2n_session_key *key) -{ - s2n_evp_ctx_init(key->evp_cipher_ctx); - - return S2N_SUCCESS; -} - -static int s2n_aead_cipher_aes_gcm_destroy_key(struct s2n_session_key *key) -{ - EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); - - return S2N_SUCCESS; -} - -#endif - -struct s2n_cipher s2n_aes128_gcm = { - .key_material_size = S2N_TLS_AES_128_GCM_KEY_LEN, - .type = S2N_AEAD, - .io.aead = { - .record_iv_size = S2N_TLS_GCM_EXPLICIT_IV_LEN, - .fixed_iv_size = S2N_TLS_GCM_FIXED_IV_LEN, - .tag_size = S2N_TLS_GCM_TAG_LEN, - .decrypt = s2n_aead_cipher_aes_gcm_decrypt, - .encrypt = s2n_aead_cipher_aes_gcm_encrypt}, - .is_available = s2n_aead_cipher_aes128_gcm_available, - .init = s2n_aead_cipher_aes_gcm_init, - .set_encryption_key = s2n_aead_cipher_aes128_gcm_set_encryption_key, - .set_decryption_key = s2n_aead_cipher_aes128_gcm_set_decryption_key, - .destroy_key = s2n_aead_cipher_aes_gcm_destroy_key, -}; - -struct s2n_cipher s2n_aes256_gcm = { - .key_material_size = S2N_TLS_AES_256_GCM_KEY_LEN, - .type = S2N_AEAD, - .io.aead = { - .record_iv_size = S2N_TLS_GCM_EXPLICIT_IV_LEN, - .fixed_iv_size = S2N_TLS_GCM_FIXED_IV_LEN, - .tag_size = S2N_TLS_GCM_TAG_LEN, - .decrypt = s2n_aead_cipher_aes_gcm_decrypt, - .encrypt = s2n_aead_cipher_aes_gcm_encrypt}, - .is_available = s2n_aead_cipher_aes256_gcm_available, - .init = s2n_aead_cipher_aes_gcm_init, - .set_encryption_key = s2n_aead_cipher_aes256_gcm_set_encryption_key, - .set_decryption_key = s2n_aead_cipher_aes256_gcm_set_decryption_key, - .destroy_key = s2n_aead_cipher_aes_gcm_destroy_key, -}; - -/* TLS 1.3 GCM ciphers */ -struct s2n_cipher s2n_tls13_aes128_gcm = { - .key_material_size = S2N_TLS_AES_128_GCM_KEY_LEN, - .type = S2N_AEAD, - .io.aead = { - .record_iv_size = S2N_TLS13_RECORD_IV_LEN, - .fixed_iv_size = S2N_TLS13_FIXED_IV_LEN, - .tag_size = S2N_TLS_GCM_TAG_LEN, - .decrypt = s2n_aead_cipher_aes_gcm_decrypt, - .encrypt = s2n_aead_cipher_aes_gcm_encrypt}, - .is_available = s2n_aead_cipher_aes128_gcm_available, - .init = s2n_aead_cipher_aes_gcm_init, - .set_encryption_key = s2n_aead_cipher_aes128_gcm_set_encryption_key, - .set_decryption_key = s2n_aead_cipher_aes128_gcm_set_decryption_key, - .destroy_key = s2n_aead_cipher_aes_gcm_destroy_key, -}; - -struct s2n_cipher s2n_tls13_aes256_gcm = { - .key_material_size = S2N_TLS_AES_256_GCM_KEY_LEN, - .type = S2N_AEAD, - .io.aead = { - .record_iv_size = S2N_TLS13_RECORD_IV_LEN, - .fixed_iv_size = S2N_TLS13_FIXED_IV_LEN, - .tag_size = S2N_TLS_GCM_TAG_LEN, - .decrypt = s2n_aead_cipher_aes_gcm_decrypt, - .encrypt = s2n_aead_cipher_aes_gcm_encrypt}, - .is_available = s2n_aead_cipher_aes256_gcm_available, - .init = s2n_aead_cipher_aes_gcm_init, - .set_encryption_key = s2n_aead_cipher_aes256_gcm_set_encryption_key, - .set_decryption_key = s2n_aead_cipher_aes256_gcm_set_decryption_key, - .destroy_key = s2n_aead_cipher_aes_gcm_destroy_key, -}; +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/aes.h> +#include <openssl/evp.h> + +#include "crypto/s2n_cipher.h" + +#include "tls/s2n_crypto.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#define S2N_AEAD_AES_GCM_AVAILABLE +#endif + +static uint8_t s2n_aead_cipher_aes128_gcm_available() +{ +#if defined(S2N_AEAD_AES_GCM_AVAILABLE) + return (EVP_aead_aes_128_gcm() ? 1 : 0); +#else + return (EVP_aes_128_gcm() ? 1 : 0); +#endif +} + +static uint8_t s2n_aead_cipher_aes256_gcm_available() +{ +#if defined(S2N_AEAD_AES_GCM_AVAILABLE) + return (EVP_aead_aes_256_gcm() ? 1 : 0); +#else + return (EVP_aes_256_gcm() ? 1 : 0); +#endif +} + +#if defined(S2N_AEAD_AES_GCM_AVAILABLE) /* BoringSSL and AWS-LC AEAD API implementation */ + +static int s2n_aead_cipher_aes_gcm_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) +{ + notnull_check(in); + notnull_check(out); + notnull_check(iv); + notnull_check(key); + notnull_check(aad); + + /* The size of the |in| blob includes the size of the data and the size of the AES-GCM tag */ + gte_check(in->size, S2N_TLS_GCM_TAG_LEN); + gte_check(out->size, in->size); + eq_check(iv->size, S2N_TLS_GCM_IV_LEN); + + /* Adjust input length to account for the Tag length */ + size_t in_len = in->size - S2N_TLS_GCM_TAG_LEN; + size_t out_len = 0; + + GUARD_OSSL(EVP_AEAD_CTX_seal(key->evp_aead_ctx, out->data, &out_len, out->size, iv->data, iv->size, in->data, in_len, aad->data, aad->size), S2N_ERR_ENCRYPT); + + S2N_ERROR_IF((in_len + S2N_TLS_GCM_TAG_LEN) != out_len, S2N_ERR_ENCRYPT); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes_gcm_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) +{ + notnull_check(in); + notnull_check(out); + notnull_check(iv); + notnull_check(key); + notnull_check(aad); + + gte_check(in->size, S2N_TLS_GCM_TAG_LEN); + gte_check(out->size, in->size - S2N_TLS_GCM_TAG_LEN); + eq_check(iv->size, S2N_TLS_GCM_IV_LEN); + + size_t out_len = 0; + + GUARD_OSSL(EVP_AEAD_CTX_open(key->evp_aead_ctx, out->data, &out_len, out->size, iv->data, iv->size, in->data, in->size, aad->data, aad->size), S2N_ERR_DECRYPT); + + S2N_ERROR_IF((in->size - S2N_TLS_GCM_TAG_LEN) != out_len, S2N_ERR_ENCRYPT); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes128_gcm_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + notnull_check(key); + notnull_check(in); + + eq_check(in->size, S2N_TLS_AES_128_GCM_KEY_LEN); + + GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_aes_128_gcm(), in->data, in->size, S2N_TLS_GCM_TAG_LEN, NULL), S2N_ERR_KEY_INIT); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes256_gcm_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + notnull_check(key); + notnull_check(in); + + eq_check(in->size, S2N_TLS_AES_256_GCM_KEY_LEN); + + GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_aes_256_gcm(), in->data, in->size, S2N_TLS_GCM_TAG_LEN, NULL), S2N_ERR_KEY_INIT); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes128_gcm_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + notnull_check(key); + notnull_check(in); + + eq_check(in->size, S2N_TLS_AES_128_GCM_KEY_LEN); + + GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_aes_128_gcm(), in->data, in->size, S2N_TLS_GCM_TAG_LEN, NULL), S2N_ERR_KEY_INIT); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes256_gcm_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + notnull_check(key); + notnull_check(in); + + eq_check(in->size, S2N_TLS_AES_256_GCM_KEY_LEN); + + GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_aes_256_gcm(), in->data, in->size, S2N_TLS_GCM_TAG_LEN, NULL), S2N_ERR_KEY_INIT); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes_gcm_init(struct s2n_session_key *key) +{ + notnull_check(key); + + EVP_AEAD_CTX_zero(key->evp_aead_ctx); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes_gcm_destroy_key(struct s2n_session_key *key) +{ + notnull_check(key); + + EVP_AEAD_CTX_cleanup(key->evp_aead_ctx); + + return S2N_SUCCESS; +} + +#else /* Standard AES-GCM implementation */ + +static int s2n_aead_cipher_aes_gcm_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) +{ + /* The size of the |in| blob includes the size of the data and the size of the ChaCha20-Poly1305 tag */ + gte_check(in->size, S2N_TLS_GCM_TAG_LEN); + gte_check(out->size, in->size); + eq_check(iv->size, S2N_TLS_GCM_IV_LEN); + + /* Initialize the IV */ + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); + + /* Adjust input length and buffer pointer to account for the Tag length */ + int in_len = in->size - S2N_TLS_GCM_TAG_LEN; + uint8_t *tag_data = out->data + out->size - S2N_TLS_GCM_TAG_LEN; + + int out_len; + /* Specify the AAD */ + GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, NULL, &out_len, aad->data, aad->size), S2N_ERR_ENCRYPT); + + /* Encrypt the data */ + GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, out->data, &out_len, in->data, in_len), S2N_ERR_ENCRYPT); + + /* When using AES-GCM, *out_len is the number of bytes written by EVP_EncryptUpdate. Since the tag is not written during this call, we do not take S2N_TLS_GCM_TAG_LEN into account */ + S2N_ERROR_IF(in_len != out_len, S2N_ERR_ENCRYPT); + + /* Finalize */ + GUARD_OSSL(EVP_EncryptFinal_ex(key->evp_cipher_ctx, out->data, &out_len), S2N_ERR_ENCRYPT); + + /* write the tag */ + GUARD_OSSL(EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_GET_TAG, S2N_TLS_GCM_TAG_LEN, tag_data), S2N_ERR_ENCRYPT); + + /* When using AES-GCM, EVP_EncryptFinal_ex does not write any bytes. So, we should expect *out_len = 0. */ + S2N_ERROR_IF(0 != out_len, S2N_ERR_ENCRYPT); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes_gcm_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) +{ + gte_check(in->size, S2N_TLS_GCM_TAG_LEN); + gte_check(out->size, in->size); + eq_check(iv->size, S2N_TLS_GCM_IV_LEN); + + /* Initialize the IV */ + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); + + /* Adjust input length and buffer pointer to account for the Tag length */ + int in_len = in->size - S2N_TLS_GCM_TAG_LEN; + uint8_t *tag_data = in->data + in->size - S2N_TLS_GCM_TAG_LEN; + + /* Set the TAG */ + GUARD_OSSL(EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_TAG, S2N_TLS_GCM_TAG_LEN, tag_data), S2N_ERR_DECRYPT); + + int out_len; + /* Specify the AAD */ + GUARD_OSSL(EVP_DecryptUpdate(key->evp_cipher_ctx, NULL, &out_len, aad->data, aad->size), S2N_ERR_DECRYPT); + + int evp_decrypt_rc = 1; + /* Decrypt the data, but don't short circuit tag verification. EVP_Decrypt* return 0 on failure, 1 for success. */ + evp_decrypt_rc &= EVP_DecryptUpdate(key->evp_cipher_ctx, out->data, &out_len, in->data, in_len); + + /* Verify the tag */ + evp_decrypt_rc &= EVP_DecryptFinal_ex(key->evp_cipher_ctx, out->data, &out_len); + + S2N_ERROR_IF(evp_decrypt_rc != 1, S2N_ERR_DECRYPT); + + /* While we verify the content of out_len in s2n_aead_cipher_aes_gcm_encrypt, we refrain from this here. This is to avoid doing any branching before the ciphertext is verified. */ + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes128_gcm_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, S2N_TLS_AES_128_GCM_KEY_LEN); + + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_aes_128_gcm(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); + + EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL); + + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes256_gcm_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, S2N_TLS_AES_256_GCM_KEY_LEN); + + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); + + EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL); + + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes128_gcm_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, S2N_TLS_AES_128_GCM_KEY_LEN); + + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_aes_128_gcm(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); + + EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL); + + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes256_gcm_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, S2N_TLS_AES_256_GCM_KEY_LEN); + + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); + + EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, S2N_TLS_GCM_IV_LEN, NULL); + + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes_gcm_init(struct s2n_session_key *key) +{ + s2n_evp_ctx_init(key->evp_cipher_ctx); + + return S2N_SUCCESS; +} + +static int s2n_aead_cipher_aes_gcm_destroy_key(struct s2n_session_key *key) +{ + EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); + + return S2N_SUCCESS; +} + +#endif + +struct s2n_cipher s2n_aes128_gcm = { + .key_material_size = S2N_TLS_AES_128_GCM_KEY_LEN, + .type = S2N_AEAD, + .io.aead = { + .record_iv_size = S2N_TLS_GCM_EXPLICIT_IV_LEN, + .fixed_iv_size = S2N_TLS_GCM_FIXED_IV_LEN, + .tag_size = S2N_TLS_GCM_TAG_LEN, + .decrypt = s2n_aead_cipher_aes_gcm_decrypt, + .encrypt = s2n_aead_cipher_aes_gcm_encrypt}, + .is_available = s2n_aead_cipher_aes128_gcm_available, + .init = s2n_aead_cipher_aes_gcm_init, + .set_encryption_key = s2n_aead_cipher_aes128_gcm_set_encryption_key, + .set_decryption_key = s2n_aead_cipher_aes128_gcm_set_decryption_key, + .destroy_key = s2n_aead_cipher_aes_gcm_destroy_key, +}; + +struct s2n_cipher s2n_aes256_gcm = { + .key_material_size = S2N_TLS_AES_256_GCM_KEY_LEN, + .type = S2N_AEAD, + .io.aead = { + .record_iv_size = S2N_TLS_GCM_EXPLICIT_IV_LEN, + .fixed_iv_size = S2N_TLS_GCM_FIXED_IV_LEN, + .tag_size = S2N_TLS_GCM_TAG_LEN, + .decrypt = s2n_aead_cipher_aes_gcm_decrypt, + .encrypt = s2n_aead_cipher_aes_gcm_encrypt}, + .is_available = s2n_aead_cipher_aes256_gcm_available, + .init = s2n_aead_cipher_aes_gcm_init, + .set_encryption_key = s2n_aead_cipher_aes256_gcm_set_encryption_key, + .set_decryption_key = s2n_aead_cipher_aes256_gcm_set_decryption_key, + .destroy_key = s2n_aead_cipher_aes_gcm_destroy_key, +}; + +/* TLS 1.3 GCM ciphers */ +struct s2n_cipher s2n_tls13_aes128_gcm = { + .key_material_size = S2N_TLS_AES_128_GCM_KEY_LEN, + .type = S2N_AEAD, + .io.aead = { + .record_iv_size = S2N_TLS13_RECORD_IV_LEN, + .fixed_iv_size = S2N_TLS13_FIXED_IV_LEN, + .tag_size = S2N_TLS_GCM_TAG_LEN, + .decrypt = s2n_aead_cipher_aes_gcm_decrypt, + .encrypt = s2n_aead_cipher_aes_gcm_encrypt}, + .is_available = s2n_aead_cipher_aes128_gcm_available, + .init = s2n_aead_cipher_aes_gcm_init, + .set_encryption_key = s2n_aead_cipher_aes128_gcm_set_encryption_key, + .set_decryption_key = s2n_aead_cipher_aes128_gcm_set_decryption_key, + .destroy_key = s2n_aead_cipher_aes_gcm_destroy_key, +}; + +struct s2n_cipher s2n_tls13_aes256_gcm = { + .key_material_size = S2N_TLS_AES_256_GCM_KEY_LEN, + .type = S2N_AEAD, + .io.aead = { + .record_iv_size = S2N_TLS13_RECORD_IV_LEN, + .fixed_iv_size = S2N_TLS13_FIXED_IV_LEN, + .tag_size = S2N_TLS_GCM_TAG_LEN, + .decrypt = s2n_aead_cipher_aes_gcm_decrypt, + .encrypt = s2n_aead_cipher_aes_gcm_encrypt}, + .is_available = s2n_aead_cipher_aes256_gcm_available, + .init = s2n_aead_cipher_aes_gcm_init, + .set_encryption_key = s2n_aead_cipher_aes256_gcm_set_encryption_key, + .set_decryption_key = s2n_aead_cipher_aes256_gcm_set_decryption_key, + .destroy_key = s2n_aead_cipher_aes_gcm_destroy_key, +}; diff --git a/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_chacha20_poly1305.c b/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_chacha20_poly1305.c index 5c395a4b26..00dba89271 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_chacha20_poly1305.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_chacha20_poly1305.c @@ -1,275 +1,275 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/evp.h> - -#include "crypto/s2n_cipher.h" -#include "crypto/s2n_openssl.h" - -#include "tls/s2n_crypto.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" - -/* We support two different backing implementations of ChaCha20-Poly1305: one - * implementation for OpenSSL (>= 1.1.0, see - * https://www.openssl.org/news/cl110.txt) and one implementation for BoringSSL - * and AWS-LC. LibreSSL supports ChaCha20-Poly1305, but the interface is - * different. - * Note, the order in the if/elif below matters because both BoringSSL and - * AWS-LC define OPENSSL_VERSION_NUMBER. */ -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) -#define S2N_CHACHA20_POLY1305_AVAILABLE_BSSL_AWSLC -#elif (S2N_OPENSSL_VERSION_AT_LEAST(1,1,0)) -#define S2N_CHACHA20_POLY1305_AVAILABLE_OSSL -#endif - -static uint8_t s2n_aead_chacha20_poly1305_available(void) -{ -#if defined(S2N_CHACHA20_POLY1305_AVAILABLE_OSSL) || defined(S2N_CHACHA20_POLY1305_AVAILABLE_BSSL_AWSLC) - return 1; -#else - return 0; -#endif -} - -#if defined(S2N_CHACHA20_POLY1305_AVAILABLE_OSSL) /* OpenSSL implementation */ - -static int s2n_aead_chacha20_poly1305_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) -{ - gte_check(in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN); - /* The size of the |in| blob includes the size of the data and the size of the ChaCha20-Poly1305 tag */ - gte_check(out->size, in->size); - eq_check(iv->size, S2N_TLS_CHACHA20_POLY1305_IV_LEN); - - /* Initialize the IV */ - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); - - /* Adjust input length and buffer pointer to account for the Tag length */ - int in_len = in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN; - uint8_t *tag_data = out->data + out->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN; - - int out_len; - /* Specify the AAD */ - GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, NULL, &out_len, aad->data, aad->size), S2N_ERR_ENCRYPT); - - /* Encrypt the data */ - GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, out->data, &out_len, in->data, in_len), S2N_ERR_ENCRYPT); - - /* For OpenSSL 1.1.0 and 1.1.1, when using ChaCha20-Poly1305, *out_len is the number of bytes written by EVP_EncryptUpdate. Since the tag is not written during this call, we do not take S2N_TLS_CHACHA20_POLY1305_TAG_LEN into account */ - S2N_ERROR_IF(in_len != out_len, S2N_ERR_ENCRYPT); - - /* Finalize */ - GUARD_OSSL(EVP_EncryptFinal_ex(key->evp_cipher_ctx, out->data, &out_len), S2N_ERR_ENCRYPT); - - /* Write the tag */ - GUARD_OSSL(EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_GET_TAG, S2N_TLS_CHACHA20_POLY1305_TAG_LEN, tag_data), S2N_ERR_ENCRYPT); - - /* For OpenSSL 1.1.0 and 1.1.1, when using ChaCha20-Poly1305, EVP_EncryptFinal_ex does not write any bytes. So, we should expect *out_len = 0. */ - S2N_ERROR_IF(0 != out_len, S2N_ERR_ENCRYPT); - - return 0; -} - -static int s2n_aead_chacha20_poly1305_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) -{ - gte_check(in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN); - gte_check(out->size, in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN); - eq_check(iv->size, S2N_TLS_CHACHA20_POLY1305_IV_LEN); - - /* Initialize the IV */ - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); - - /* Adjust input length and buffer pointer to account for the Tag length */ - int in_len = in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN; - uint8_t *tag_data = in->data + in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN; - - /* Set the TAG */ - GUARD_OSSL(EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_TAG, S2N_TLS_CHACHA20_POLY1305_TAG_LEN, tag_data), S2N_ERR_DECRYPT); - - int out_len; - /* Specify the AAD */ - GUARD_OSSL(EVP_DecryptUpdate(key->evp_cipher_ctx, NULL, &out_len, aad->data, aad->size), S2N_ERR_DECRYPT); - - int evp_decrypt_rc = 1; - /* Decrypt the data, but don't short circuit tag verification. EVP_Decrypt* return 0 on failure, 1 for success. */ - evp_decrypt_rc &= EVP_DecryptUpdate(key->evp_cipher_ctx, out->data, &out_len, in->data, in_len); - - /* Verify the tag */ - evp_decrypt_rc &= EVP_DecryptFinal_ex(key->evp_cipher_ctx, out->data, &out_len); - - S2N_ERROR_IF(evp_decrypt_rc != 1, S2N_ERR_DECRYPT); - - /* While we verify the content of out_len in s2n_aead_chacha20_poly1305_encrypt, we refrain from this here. This is to avoid doing any branching before the ciphertext is verified. */ - - return 0; -} - -static int s2n_aead_chacha20_poly1305_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, S2N_TLS_CHACHA20_POLY1305_KEY_LEN); - - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); - - EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_SET_IVLEN, S2N_TLS_CHACHA20_POLY1305_IV_LEN, NULL); - - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -static int s2n_aead_chacha20_poly1305_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, S2N_TLS_CHACHA20_POLY1305_KEY_LEN); - - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); - - EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_SET_IVLEN, S2N_TLS_CHACHA20_POLY1305_IV_LEN, NULL); - - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -static int s2n_aead_chacha20_poly1305_init(struct s2n_session_key *key) -{ - s2n_evp_ctx_init(key->evp_cipher_ctx); - - return 0; -} - -static int s2n_aead_chacha20_poly1305_destroy_key(struct s2n_session_key *key) -{ - EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); - - return 0; -} - -#elif defined(S2N_CHACHA20_POLY1305_AVAILABLE_BSSL_AWSLC) /* BoringSSL and AWS-LC implementation */ - -static int s2n_aead_chacha20_poly1305_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) -{ - gte_check(in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN); - /* The size of the |in| blob includes the size of the data and the size of the ChaCha20-Poly1305 tag */ - gte_check(out->size, in->size); - eq_check(iv->size, S2N_TLS_CHACHA20_POLY1305_IV_LEN); - - /* Adjust input length to account for the Tag length */ - size_t in_len = in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN; - size_t out_len = 0; - - GUARD_OSSL(EVP_AEAD_CTX_seal(key->evp_aead_ctx, out->data, &out_len, out->size, iv->data, iv->size, in->data, in_len, aad->data, aad->size), S2N_ERR_ENCRYPT); - - S2N_ERROR_IF((in_len + S2N_TLS_CHACHA20_POLY1305_TAG_LEN) != out_len, S2N_ERR_ENCRYPT); - - return 0; -} - -static int s2n_aead_chacha20_poly1305_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) -{ - gte_check(in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN); - gte_check(out->size, in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN); - eq_check(iv->size, S2N_TLS_CHACHA20_POLY1305_IV_LEN); - - size_t out_len = 0; - - GUARD_OSSL(EVP_AEAD_CTX_open(key->evp_aead_ctx, out->data, &out_len, out->size, iv->data, iv->size, in->data, in->size, aad->data, aad->size), S2N_ERR_DECRYPT); - - S2N_ERROR_IF((in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN) != out_len, S2N_ERR_ENCRYPT); - - return 0; -} - -static int s2n_aead_chacha20_poly1305_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, S2N_TLS_CHACHA20_POLY1305_KEY_LEN); - - GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_chacha20_poly1305(), in->data, in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -static int s2n_aead_chacha20_poly1305_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, S2N_TLS_CHACHA20_POLY1305_KEY_LEN); - - GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_chacha20_poly1305(), in->data, in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -static int s2n_aead_chacha20_poly1305_init(struct s2n_session_key *key) -{ - EVP_AEAD_CTX_zero(key->evp_aead_ctx); - - return 0; -} - -static int s2n_aead_chacha20_poly1305_destroy_key(struct s2n_session_key *key) -{ - EVP_AEAD_CTX_cleanup(key->evp_aead_ctx); - - return 0; -} - -#else /* No ChaCha20-Poly1305 implementation exists for chosen cryptographic provider (E.g Openssl 1.0.x) */ - -static int s2n_aead_chacha20_poly1305_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) -{ - S2N_ERROR(S2N_ERR_ENCRYPT); -} - -static int s2n_aead_chacha20_poly1305_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) -{ - S2N_ERROR(S2N_ERR_DECRYPT); -} - -static int s2n_aead_chacha20_poly1305_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - S2N_ERROR(S2N_ERR_KEY_INIT); -} - -static int s2n_aead_chacha20_poly1305_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - S2N_ERROR(S2N_ERR_KEY_INIT); -} - -static int s2n_aead_chacha20_poly1305_init(struct s2n_session_key *key) -{ - S2N_ERROR(S2N_ERR_KEY_INIT); -} - -static int s2n_aead_chacha20_poly1305_destroy_key(struct s2n_session_key *key) -{ - S2N_ERROR(S2N_ERR_KEY_DESTROY); -} - -#endif - -struct s2n_cipher s2n_chacha20_poly1305 = { - .key_material_size = S2N_TLS_CHACHA20_POLY1305_KEY_LEN, - .type = S2N_AEAD, - .io.aead = { - .record_iv_size = S2N_TLS_CHACHA20_POLY1305_EXPLICIT_IV_LEN, - .fixed_iv_size = S2N_TLS_CHACHA20_POLY1305_FIXED_IV_LEN, - .tag_size = S2N_TLS_CHACHA20_POLY1305_TAG_LEN, - .decrypt = s2n_aead_chacha20_poly1305_decrypt, - .encrypt = s2n_aead_chacha20_poly1305_encrypt}, - .is_available = s2n_aead_chacha20_poly1305_available, - .init = s2n_aead_chacha20_poly1305_init, - .set_encryption_key = s2n_aead_chacha20_poly1305_set_encryption_key, - .set_decryption_key = s2n_aead_chacha20_poly1305_set_decryption_key, - .destroy_key = s2n_aead_chacha20_poly1305_destroy_key, -}; +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/evp.h> + +#include "crypto/s2n_cipher.h" +#include "crypto/s2n_openssl.h" + +#include "tls/s2n_crypto.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" + +/* We support two different backing implementations of ChaCha20-Poly1305: one + * implementation for OpenSSL (>= 1.1.0, see + * https://www.openssl.org/news/cl110.txt) and one implementation for BoringSSL + * and AWS-LC. LibreSSL supports ChaCha20-Poly1305, but the interface is + * different. + * Note, the order in the if/elif below matters because both BoringSSL and + * AWS-LC define OPENSSL_VERSION_NUMBER. */ +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#define S2N_CHACHA20_POLY1305_AVAILABLE_BSSL_AWSLC +#elif (S2N_OPENSSL_VERSION_AT_LEAST(1,1,0)) +#define S2N_CHACHA20_POLY1305_AVAILABLE_OSSL +#endif + +static uint8_t s2n_aead_chacha20_poly1305_available(void) +{ +#if defined(S2N_CHACHA20_POLY1305_AVAILABLE_OSSL) || defined(S2N_CHACHA20_POLY1305_AVAILABLE_BSSL_AWSLC) + return 1; +#else + return 0; +#endif +} + +#if defined(S2N_CHACHA20_POLY1305_AVAILABLE_OSSL) /* OpenSSL implementation */ + +static int s2n_aead_chacha20_poly1305_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) +{ + gte_check(in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN); + /* The size of the |in| blob includes the size of the data and the size of the ChaCha20-Poly1305 tag */ + gte_check(out->size, in->size); + eq_check(iv->size, S2N_TLS_CHACHA20_POLY1305_IV_LEN); + + /* Initialize the IV */ + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); + + /* Adjust input length and buffer pointer to account for the Tag length */ + int in_len = in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN; + uint8_t *tag_data = out->data + out->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN; + + int out_len; + /* Specify the AAD */ + GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, NULL, &out_len, aad->data, aad->size), S2N_ERR_ENCRYPT); + + /* Encrypt the data */ + GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, out->data, &out_len, in->data, in_len), S2N_ERR_ENCRYPT); + + /* For OpenSSL 1.1.0 and 1.1.1, when using ChaCha20-Poly1305, *out_len is the number of bytes written by EVP_EncryptUpdate. Since the tag is not written during this call, we do not take S2N_TLS_CHACHA20_POLY1305_TAG_LEN into account */ + S2N_ERROR_IF(in_len != out_len, S2N_ERR_ENCRYPT); + + /* Finalize */ + GUARD_OSSL(EVP_EncryptFinal_ex(key->evp_cipher_ctx, out->data, &out_len), S2N_ERR_ENCRYPT); + + /* Write the tag */ + GUARD_OSSL(EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_GET_TAG, S2N_TLS_CHACHA20_POLY1305_TAG_LEN, tag_data), S2N_ERR_ENCRYPT); + + /* For OpenSSL 1.1.0 and 1.1.1, when using ChaCha20-Poly1305, EVP_EncryptFinal_ex does not write any bytes. So, we should expect *out_len = 0. */ + S2N_ERROR_IF(0 != out_len, S2N_ERR_ENCRYPT); + + return 0; +} + +static int s2n_aead_chacha20_poly1305_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) +{ + gte_check(in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN); + gte_check(out->size, in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN); + eq_check(iv->size, S2N_TLS_CHACHA20_POLY1305_IV_LEN); + + /* Initialize the IV */ + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); + + /* Adjust input length and buffer pointer to account for the Tag length */ + int in_len = in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN; + uint8_t *tag_data = in->data + in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN; + + /* Set the TAG */ + GUARD_OSSL(EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_GCM_SET_TAG, S2N_TLS_CHACHA20_POLY1305_TAG_LEN, tag_data), S2N_ERR_DECRYPT); + + int out_len; + /* Specify the AAD */ + GUARD_OSSL(EVP_DecryptUpdate(key->evp_cipher_ctx, NULL, &out_len, aad->data, aad->size), S2N_ERR_DECRYPT); + + int evp_decrypt_rc = 1; + /* Decrypt the data, but don't short circuit tag verification. EVP_Decrypt* return 0 on failure, 1 for success. */ + evp_decrypt_rc &= EVP_DecryptUpdate(key->evp_cipher_ctx, out->data, &out_len, in->data, in_len); + + /* Verify the tag */ + evp_decrypt_rc &= EVP_DecryptFinal_ex(key->evp_cipher_ctx, out->data, &out_len); + + S2N_ERROR_IF(evp_decrypt_rc != 1, S2N_ERR_DECRYPT); + + /* While we verify the content of out_len in s2n_aead_chacha20_poly1305_encrypt, we refrain from this here. This is to avoid doing any branching before the ciphertext is verified. */ + + return 0; +} + +static int s2n_aead_chacha20_poly1305_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, S2N_TLS_CHACHA20_POLY1305_KEY_LEN); + + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); + + EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_SET_IVLEN, S2N_TLS_CHACHA20_POLY1305_IV_LEN, NULL); + + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +static int s2n_aead_chacha20_poly1305_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, S2N_TLS_CHACHA20_POLY1305_KEY_LEN); + + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL), S2N_ERR_KEY_INIT); + + EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_SET_IVLEN, S2N_TLS_CHACHA20_POLY1305_IV_LEN, NULL); + + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +static int s2n_aead_chacha20_poly1305_init(struct s2n_session_key *key) +{ + s2n_evp_ctx_init(key->evp_cipher_ctx); + + return 0; +} + +static int s2n_aead_chacha20_poly1305_destroy_key(struct s2n_session_key *key) +{ + EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); + + return 0; +} + +#elif defined(S2N_CHACHA20_POLY1305_AVAILABLE_BSSL_AWSLC) /* BoringSSL and AWS-LC implementation */ + +static int s2n_aead_chacha20_poly1305_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) +{ + gte_check(in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN); + /* The size of the |in| blob includes the size of the data and the size of the ChaCha20-Poly1305 tag */ + gte_check(out->size, in->size); + eq_check(iv->size, S2N_TLS_CHACHA20_POLY1305_IV_LEN); + + /* Adjust input length to account for the Tag length */ + size_t in_len = in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN; + size_t out_len = 0; + + GUARD_OSSL(EVP_AEAD_CTX_seal(key->evp_aead_ctx, out->data, &out_len, out->size, iv->data, iv->size, in->data, in_len, aad->data, aad->size), S2N_ERR_ENCRYPT); + + S2N_ERROR_IF((in_len + S2N_TLS_CHACHA20_POLY1305_TAG_LEN) != out_len, S2N_ERR_ENCRYPT); + + return 0; +} + +static int s2n_aead_chacha20_poly1305_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) +{ + gte_check(in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN); + gte_check(out->size, in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN); + eq_check(iv->size, S2N_TLS_CHACHA20_POLY1305_IV_LEN); + + size_t out_len = 0; + + GUARD_OSSL(EVP_AEAD_CTX_open(key->evp_aead_ctx, out->data, &out_len, out->size, iv->data, iv->size, in->data, in->size, aad->data, aad->size), S2N_ERR_DECRYPT); + + S2N_ERROR_IF((in->size - S2N_TLS_CHACHA20_POLY1305_TAG_LEN) != out_len, S2N_ERR_ENCRYPT); + + return 0; +} + +static int s2n_aead_chacha20_poly1305_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, S2N_TLS_CHACHA20_POLY1305_KEY_LEN); + + GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_chacha20_poly1305(), in->data, in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +static int s2n_aead_chacha20_poly1305_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, S2N_TLS_CHACHA20_POLY1305_KEY_LEN); + + GUARD_OSSL(EVP_AEAD_CTX_init(key->evp_aead_ctx, EVP_aead_chacha20_poly1305(), in->data, in->size, S2N_TLS_CHACHA20_POLY1305_TAG_LEN, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +static int s2n_aead_chacha20_poly1305_init(struct s2n_session_key *key) +{ + EVP_AEAD_CTX_zero(key->evp_aead_ctx); + + return 0; +} + +static int s2n_aead_chacha20_poly1305_destroy_key(struct s2n_session_key *key) +{ + EVP_AEAD_CTX_cleanup(key->evp_aead_ctx); + + return 0; +} + +#else /* No ChaCha20-Poly1305 implementation exists for chosen cryptographic provider (E.g Openssl 1.0.x) */ + +static int s2n_aead_chacha20_poly1305_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) +{ + S2N_ERROR(S2N_ERR_ENCRYPT); +} + +static int s2n_aead_chacha20_poly1305_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *aad, struct s2n_blob *in, struct s2n_blob *out) +{ + S2N_ERROR(S2N_ERR_DECRYPT); +} + +static int s2n_aead_chacha20_poly1305_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + S2N_ERROR(S2N_ERR_KEY_INIT); +} + +static int s2n_aead_chacha20_poly1305_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + S2N_ERROR(S2N_ERR_KEY_INIT); +} + +static int s2n_aead_chacha20_poly1305_init(struct s2n_session_key *key) +{ + S2N_ERROR(S2N_ERR_KEY_INIT); +} + +static int s2n_aead_chacha20_poly1305_destroy_key(struct s2n_session_key *key) +{ + S2N_ERROR(S2N_ERR_KEY_DESTROY); +} + +#endif + +struct s2n_cipher s2n_chacha20_poly1305 = { + .key_material_size = S2N_TLS_CHACHA20_POLY1305_KEY_LEN, + .type = S2N_AEAD, + .io.aead = { + .record_iv_size = S2N_TLS_CHACHA20_POLY1305_EXPLICIT_IV_LEN, + .fixed_iv_size = S2N_TLS_CHACHA20_POLY1305_FIXED_IV_LEN, + .tag_size = S2N_TLS_CHACHA20_POLY1305_TAG_LEN, + .decrypt = s2n_aead_chacha20_poly1305_decrypt, + .encrypt = s2n_aead_chacha20_poly1305_encrypt}, + .is_available = s2n_aead_chacha20_poly1305_available, + .init = s2n_aead_chacha20_poly1305_init, + .set_encryption_key = s2n_aead_chacha20_poly1305_set_encryption_key, + .set_decryption_key = s2n_aead_chacha20_poly1305_set_decryption_key, + .destroy_key = s2n_aead_chacha20_poly1305_destroy_key, +}; diff --git a/contrib/restricted/aws/s2n/crypto/s2n_cbc_cipher_3des.c b/contrib/restricted/aws/s2n/crypto/s2n_cbc_cipher_3des.c index dcd190bd8a..b992d6bc83 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_cbc_cipher_3des.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_cbc_cipher_3des.c @@ -1,103 +1,103 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/evp.h> - -#include "error/s2n_errno.h" - -#include "crypto/s2n_cipher.h" -#include "crypto/s2n_openssl.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" - -static uint8_t s2n_cbc_cipher_3des_available() -{ - return (EVP_des_ede3_cbc() ? 1 : 0); -} - -static int s2n_cbc_cipher_3des_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) -{ - gte_check(out->size, in->size); - - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); - - int len = out->size; - GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_ENCRYPT); - S2N_ERROR_IF(len != in->size, S2N_ERR_ENCRYPT); - - return 0; -} - -static int s2n_cbc_cipher_3des_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) -{ - gte_check(out->size, in->size); - - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); - - int len = out->size; - GUARD_OSSL(EVP_DecryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_DECRYPT); - - return 0; -} - -static int s2n_cbc_cipher_3des_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 192 / 8); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_des_ede3_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -static int s2n_cbc_cipher_3des_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 192 / 8); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_des_ede3_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -static int s2n_cbc_cipher_3des_init(struct s2n_session_key *key) -{ - s2n_evp_ctx_init(key->evp_cipher_ctx); - - return 0; -} - -static int s2n_cbc_cipher_3des_destroy_key(struct s2n_session_key *key) -{ - EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); - - return 0; -} - -struct s2n_cipher s2n_3des = { - .key_material_size = 24, - .type = S2N_CBC, - .io.cbc = { - .block_size = 8, - .record_iv_size = 8, - .decrypt = s2n_cbc_cipher_3des_decrypt, - .encrypt = s2n_cbc_cipher_3des_encrypt}, - .is_available = s2n_cbc_cipher_3des_available, - .init = s2n_cbc_cipher_3des_init, - .set_decryption_key = s2n_cbc_cipher_3des_set_decryption_key, - .set_encryption_key = s2n_cbc_cipher_3des_set_encryption_key, - .destroy_key = s2n_cbc_cipher_3des_destroy_key, -}; +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/evp.h> + +#include "error/s2n_errno.h" + +#include "crypto/s2n_cipher.h" +#include "crypto/s2n_openssl.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" + +static uint8_t s2n_cbc_cipher_3des_available() +{ + return (EVP_des_ede3_cbc() ? 1 : 0); +} + +static int s2n_cbc_cipher_3des_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) +{ + gte_check(out->size, in->size); + + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); + + int len = out->size; + GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_ENCRYPT); + S2N_ERROR_IF(len != in->size, S2N_ERR_ENCRYPT); + + return 0; +} + +static int s2n_cbc_cipher_3des_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) +{ + gte_check(out->size, in->size); + + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); + + int len = out->size; + GUARD_OSSL(EVP_DecryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_DECRYPT); + + return 0; +} + +static int s2n_cbc_cipher_3des_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 192 / 8); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_des_ede3_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +static int s2n_cbc_cipher_3des_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 192 / 8); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_des_ede3_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +static int s2n_cbc_cipher_3des_init(struct s2n_session_key *key) +{ + s2n_evp_ctx_init(key->evp_cipher_ctx); + + return 0; +} + +static int s2n_cbc_cipher_3des_destroy_key(struct s2n_session_key *key) +{ + EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); + + return 0; +} + +struct s2n_cipher s2n_3des = { + .key_material_size = 24, + .type = S2N_CBC, + .io.cbc = { + .block_size = 8, + .record_iv_size = 8, + .decrypt = s2n_cbc_cipher_3des_decrypt, + .encrypt = s2n_cbc_cipher_3des_encrypt}, + .is_available = s2n_cbc_cipher_3des_available, + .init = s2n_cbc_cipher_3des_init, + .set_decryption_key = s2n_cbc_cipher_3des_set_decryption_key, + .set_encryption_key = s2n_cbc_cipher_3des_set_encryption_key, + .destroy_key = s2n_cbc_cipher_3des_destroy_key, +}; diff --git a/contrib/restricted/aws/s2n/crypto/s2n_cbc_cipher_aes.c b/contrib/restricted/aws/s2n/crypto/s2n_cbc_cipher_aes.c index 2a0fbaf66e..1dee9b56f7 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_cbc_cipher_aes.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_cbc_cipher_aes.c @@ -1,143 +1,143 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/aes.h> - -#include "error/s2n_errno.h" - -#include "crypto/s2n_cipher.h" -#include "crypto/s2n_openssl.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" - -static uint8_t s2n_cbc_cipher_aes128_available() -{ - return (EVP_aes_128_cbc() ? 1 : 0); -} - -static uint8_t s2n_cbc_cipher_aes256_available() -{ - return (EVP_aes_256_cbc() ? 1 : 0); -} - -static int s2n_cbc_cipher_aes_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) -{ - gte_check(out->size, in->size); - - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); - - int len = out->size; - GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_ENCRYPT); - S2N_ERROR_IF(len != in->size, S2N_ERR_ENCRYPT); - - return 0; -} - -int s2n_cbc_cipher_aes_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) -{ - gte_check(out->size, in->size); - - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); - int len = out->size; - GUARD_OSSL(EVP_DecryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_DECRYPT); - - return 0; -} - -int s2n_cbc_cipher_aes128_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 128 / 8); - - /* Always returns 1 */ - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_aes_128_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -static int s2n_cbc_cipher_aes128_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 128 / 8); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_aes_128_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -static int s2n_cbc_cipher_aes256_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 256 / 8); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_aes_256_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -int s2n_cbc_cipher_aes256_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 256 / 8); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_aes_256_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -static int s2n_cbc_cipher_aes_init(struct s2n_session_key *key) -{ - s2n_evp_ctx_init(key->evp_cipher_ctx); - - return 0; -} - -static int s2n_cbc_cipher_aes_destroy_key(struct s2n_session_key *key) -{ - EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); - - return 0; -} - -struct s2n_cipher s2n_aes128 = { - .key_material_size = 16, - .type = S2N_CBC, - .io.cbc = { - .block_size = 16, - .record_iv_size = 16, - .decrypt = s2n_cbc_cipher_aes_decrypt, - .encrypt = s2n_cbc_cipher_aes_encrypt}, - .is_available = s2n_cbc_cipher_aes128_available, - .init = s2n_cbc_cipher_aes_init, - .set_decryption_key = s2n_cbc_cipher_aes128_set_decryption_key, - .set_encryption_key = s2n_cbc_cipher_aes128_set_encryption_key, - .destroy_key = s2n_cbc_cipher_aes_destroy_key, -}; - -struct s2n_cipher s2n_aes256 = { - .key_material_size = 32, - .type = S2N_CBC, - .io.cbc = { - .block_size = 16, - .record_iv_size = 16, - .decrypt = s2n_cbc_cipher_aes_decrypt, - .encrypt = s2n_cbc_cipher_aes_encrypt}, - .is_available = s2n_cbc_cipher_aes256_available, - .init = s2n_cbc_cipher_aes_init, - .set_decryption_key = s2n_cbc_cipher_aes256_set_decryption_key, - .set_encryption_key = s2n_cbc_cipher_aes256_set_encryption_key, - .destroy_key = s2n_cbc_cipher_aes_destroy_key, -}; +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/aes.h> + +#include "error/s2n_errno.h" + +#include "crypto/s2n_cipher.h" +#include "crypto/s2n_openssl.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" + +static uint8_t s2n_cbc_cipher_aes128_available() +{ + return (EVP_aes_128_cbc() ? 1 : 0); +} + +static uint8_t s2n_cbc_cipher_aes256_available() +{ + return (EVP_aes_256_cbc() ? 1 : 0); +} + +static int s2n_cbc_cipher_aes_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) +{ + gte_check(out->size, in->size); + + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); + + int len = out->size; + GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_ENCRYPT); + S2N_ERROR_IF(len != in->size, S2N_ERR_ENCRYPT); + + return 0; +} + +int s2n_cbc_cipher_aes_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) +{ + gte_check(out->size, in->size); + + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); + int len = out->size; + GUARD_OSSL(EVP_DecryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_DECRYPT); + + return 0; +} + +int s2n_cbc_cipher_aes128_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 128 / 8); + + /* Always returns 1 */ + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_aes_128_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +static int s2n_cbc_cipher_aes128_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 128 / 8); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_aes_128_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +static int s2n_cbc_cipher_aes256_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 256 / 8); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_aes_256_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +int s2n_cbc_cipher_aes256_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 256 / 8); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_aes_256_cbc(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +static int s2n_cbc_cipher_aes_init(struct s2n_session_key *key) +{ + s2n_evp_ctx_init(key->evp_cipher_ctx); + + return 0; +} + +static int s2n_cbc_cipher_aes_destroy_key(struct s2n_session_key *key) +{ + EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); + + return 0; +} + +struct s2n_cipher s2n_aes128 = { + .key_material_size = 16, + .type = S2N_CBC, + .io.cbc = { + .block_size = 16, + .record_iv_size = 16, + .decrypt = s2n_cbc_cipher_aes_decrypt, + .encrypt = s2n_cbc_cipher_aes_encrypt}, + .is_available = s2n_cbc_cipher_aes128_available, + .init = s2n_cbc_cipher_aes_init, + .set_decryption_key = s2n_cbc_cipher_aes128_set_decryption_key, + .set_encryption_key = s2n_cbc_cipher_aes128_set_encryption_key, + .destroy_key = s2n_cbc_cipher_aes_destroy_key, +}; + +struct s2n_cipher s2n_aes256 = { + .key_material_size = 32, + .type = S2N_CBC, + .io.cbc = { + .block_size = 16, + .record_iv_size = 16, + .decrypt = s2n_cbc_cipher_aes_decrypt, + .encrypt = s2n_cbc_cipher_aes_encrypt}, + .is_available = s2n_cbc_cipher_aes256_available, + .init = s2n_cbc_cipher_aes_init, + .set_decryption_key = s2n_cbc_cipher_aes256_set_decryption_key, + .set_encryption_key = s2n_cbc_cipher_aes256_set_encryption_key, + .destroy_key = s2n_cbc_cipher_aes_destroy_key, +}; diff --git a/contrib/restricted/aws/s2n/crypto/s2n_certificate.c b/contrib/restricted/aws/s2n/crypto/s2n_certificate.c index 39646c3f28..988a5f6971 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_certificate.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_certificate.c @@ -1,534 +1,534 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif - -#include <s2n.h> -#include <openssl/x509v3.h> -#include <openssl/pem.h> -#include <string.h> -#include <strings.h> - -#include "crypto/s2n_certificate.h" -#include "utils/s2n_array.h" -#include "utils/s2n_safety.h" -#include "utils/s2n_mem.h" - -#include "tls/extensions/s2n_extension_list.h" -#include "tls/s2n_connection.h" - -int s2n_cert_set_cert_type(struct s2n_cert *cert, s2n_pkey_type pkey_type) -{ - notnull_check(cert); - cert->pkey_type = pkey_type; - GUARD(s2n_pkey_setup_for_type(&cert->public_key, pkey_type)); - return 0; -} - -int s2n_create_cert_chain_from_stuffer(struct s2n_cert_chain *cert_chain_out, struct s2n_stuffer *chain_in_stuffer) -{ - DEFER_CLEANUP(struct s2n_stuffer cert_out_stuffer = {0}, s2n_stuffer_free); - GUARD(s2n_stuffer_growable_alloc(&cert_out_stuffer, 2048)); - - struct s2n_cert **insert = &cert_chain_out->head; - uint32_t chain_size = 0; - do { - struct s2n_cert *new_node = NULL; - - if (s2n_stuffer_certificate_from_pem(chain_in_stuffer, &cert_out_stuffer) < 0) { - if (chain_size == 0) { - S2N_ERROR(S2N_ERR_NO_CERTIFICATE_IN_PEM); - } - break; - } - struct s2n_blob mem = {0}; - GUARD(s2n_alloc(&mem, sizeof(struct s2n_cert))); - new_node = (struct s2n_cert *)(void *)mem.data; - - if (s2n_alloc(&new_node->raw, s2n_stuffer_data_available(&cert_out_stuffer)) != S2N_SUCCESS) { - GUARD(s2n_free(&mem)); - S2N_ERROR_PRESERVE_ERRNO(); - } - if (s2n_stuffer_read(&cert_out_stuffer, &new_node->raw) != S2N_SUCCESS) { - GUARD(s2n_free(&mem)); - S2N_ERROR_PRESERVE_ERRNO(); - } - - /* Additional 3 bytes for the length field in the protocol */ - chain_size += new_node->raw.size + 3; - new_node->next = NULL; - *insert = new_node; - insert = &new_node->next; - } while (s2n_stuffer_data_available(chain_in_stuffer)); - - /* Leftover data at this point means one of two things: - * A bug in s2n's PEM parsing OR a malformed PEM in the user's chain. - * Be conservative and fail instead of using a partial chain. - */ - S2N_ERROR_IF(s2n_stuffer_data_available(chain_in_stuffer) > 0, S2N_ERR_INVALID_PEM); - - cert_chain_out->chain_size = chain_size; - - return 0; -} - -int s2n_cert_chain_and_key_set_cert_chain_from_stuffer(struct s2n_cert_chain_and_key *cert_and_key, struct s2n_stuffer *chain_in_stuffer) -{ - return s2n_create_cert_chain_from_stuffer(cert_and_key->cert_chain, chain_in_stuffer); -} - -int s2n_cert_chain_and_key_set_cert_chain(struct s2n_cert_chain_and_key *cert_and_key, const char *cert_chain_pem) -{ - struct s2n_stuffer chain_in_stuffer = {0}; - - /* Turn the chain into a stuffer */ - GUARD(s2n_stuffer_alloc_ro_from_string(&chain_in_stuffer, cert_chain_pem)); - int rc = s2n_cert_chain_and_key_set_cert_chain_from_stuffer(cert_and_key, &chain_in_stuffer); - - GUARD(s2n_stuffer_free(&chain_in_stuffer)); - - return rc; -} - -int s2n_cert_chain_and_key_set_private_key(struct s2n_cert_chain_and_key *cert_and_key, const char *private_key_pem) -{ - DEFER_CLEANUP(struct s2n_stuffer key_in_stuffer = {0}, s2n_stuffer_free); - DEFER_CLEANUP(struct s2n_stuffer key_out_stuffer = {0}, s2n_stuffer_free); - struct s2n_blob key_blob = {0}; - - GUARD(s2n_pkey_zero_init(cert_and_key->private_key)); - - /* Put the private key pem in a stuffer */ - GUARD(s2n_stuffer_alloc_ro_from_string(&key_in_stuffer, private_key_pem)); - GUARD(s2n_stuffer_growable_alloc(&key_out_stuffer, strlen(private_key_pem))); - - /* Convert pem to asn1 and asn1 to the private key. Handles both PKCS#1 and PKCS#8 formats */ - GUARD(s2n_stuffer_private_key_from_pem(&key_in_stuffer, &key_out_stuffer)); - key_blob.size = s2n_stuffer_data_available(&key_out_stuffer); - key_blob.data = s2n_stuffer_raw_read(&key_out_stuffer, key_blob.size); - notnull_check(key_blob.data); - - /* Get key type and create appropriate key context */ - GUARD(s2n_asn1der_to_private_key(cert_and_key->private_key, &key_blob)); - - return 0; -} - -int s2n_cert_chain_and_key_set_ocsp_data(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length) -{ - notnull_check(chain_and_key); - GUARD(s2n_free(&chain_and_key->ocsp_status)); - if (data && length) { - GUARD(s2n_alloc(&chain_and_key->ocsp_status, length)); - memcpy_check(chain_and_key->ocsp_status.data, data, length); - } - return 0; -} - -int s2n_cert_chain_and_key_set_sct_list(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length) -{ - notnull_check(chain_and_key); - GUARD(s2n_free(&chain_and_key->sct_list)); - if (data && length) { - GUARD(s2n_alloc(&chain_and_key->sct_list, length)); - memcpy_check(chain_and_key->sct_list.data, data, length); - } - return 0; -} - -struct s2n_cert_chain_and_key *s2n_cert_chain_and_key_new(void) -{ - struct s2n_cert_chain_and_key *chain_and_key; - struct s2n_blob chain_and_key_mem, cert_chain_mem, pkey_mem; - - GUARD_PTR(s2n_alloc(&chain_and_key_mem, sizeof(struct s2n_cert_chain_and_key))); - chain_and_key = (struct s2n_cert_chain_and_key *)(void *)chain_and_key_mem.data; - - /* Allocate the memory for the chain and key */ - if (s2n_alloc(&cert_chain_mem, sizeof(struct s2n_cert_chain)) != S2N_SUCCESS) { - goto cleanup; - } - chain_and_key->cert_chain = (struct s2n_cert_chain *)(void *)cert_chain_mem.data; - - if (s2n_alloc(&pkey_mem, sizeof(s2n_cert_private_key)) != S2N_SUCCESS) { - goto cleanup; - } - chain_and_key->private_key = (s2n_cert_private_key *)(void *)pkey_mem.data; - - chain_and_key->cert_chain->head = NULL; - if (s2n_pkey_zero_init(chain_and_key->private_key) != S2N_SUCCESS) { - goto cleanup; - } - memset(&chain_and_key->ocsp_status, 0, sizeof(chain_and_key->ocsp_status)); - memset(&chain_and_key->sct_list, 0, sizeof(chain_and_key->sct_list)); - chain_and_key->cn_names = s2n_array_new(sizeof(struct s2n_blob)); - if (!chain_and_key->cn_names) { - goto cleanup; - } - - chain_and_key->san_names = s2n_array_new(sizeof(struct s2n_blob)); - if (!chain_and_key->san_names) { - goto cleanup; - } - - chain_and_key->context = NULL; - - return chain_and_key; - cleanup: - s2n_free(&pkey_mem); - s2n_free(&cert_chain_mem); - s2n_free(&chain_and_key_mem); - return NULL; -} - -DEFINE_POINTER_CLEANUP_FUNC(GENERAL_NAMES *, GENERAL_NAMES_free); - -int s2n_cert_chain_and_key_load_sans(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert) -{ - notnull_check(chain_and_key->san_names); - - DEFER_CLEANUP(GENERAL_NAMES *san_names = X509_get_ext_d2i(x509_cert, NID_subject_alt_name, NULL, NULL), GENERAL_NAMES_free_pointer); - if (san_names == NULL) { - /* No SAN extension */ - return 0; - } - - const int num_san_names = sk_GENERAL_NAME_num(san_names); - for (int i = 0; i < num_san_names; i++) { - GENERAL_NAME *san_name = sk_GENERAL_NAME_value(san_names, i); - if (!san_name) { - continue; - } - - if (san_name->type == GEN_DNS) { - /* Decoding isn't necessary here since a DNS SAN name is ASCII(type V_ASN1_IA5STRING) */ - unsigned char *san_str = san_name->d.dNSName->data; - const size_t san_str_len = san_name->d.dNSName->length; - struct s2n_blob *san_blob = NULL; - GUARD_AS_POSIX(s2n_array_pushback(chain_and_key->san_names, (void **)&san_blob)); - if (!san_blob) { - S2N_ERROR(S2N_ERR_NULL_SANS); - } - - if (s2n_alloc(san_blob, san_str_len)) { - S2N_ERROR_PRESERVE_ERRNO(); - } - - memcpy_check(san_blob->data, san_str, san_str_len); - san_blob->size = san_str_len; - /* normalize san_blob to lowercase */ - GUARD(s2n_blob_char_to_lower(san_blob)); - } - } - - return 0; -} - -/* Parse CN names from the Subject of the leaf certificate. Technically there can by multiple CNs - * in the Subject but practically very few certificates in the wild will have more than one CN. - * Since the data for this certificate is coming from the application and not from an untrusted - * source, we will try our best to parse all of the CNs. - * - * A recent CAB thread proposed removing support for multiple CNs: - * https://cabforum.org/pipermail/public/2016-April/007242.html - */ - -DEFINE_POINTER_CLEANUP_FUNC(unsigned char *, OPENSSL_free); - -int s2n_cert_chain_and_key_load_cns(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert) -{ - notnull_check(chain_and_key->cn_names); - - X509_NAME *subject = X509_get_subject_name(x509_cert); - if (!subject) { - return 0; - } - - int lastpos = -1; - while((lastpos = X509_NAME_get_index_by_NID(subject, NID_commonName, lastpos)) >= 0) { - X509_NAME_ENTRY *name_entry = X509_NAME_get_entry(subject, lastpos); - if (!name_entry) { - continue; - } - - ASN1_STRING *asn1_str = X509_NAME_ENTRY_get_data(name_entry); - if (!asn1_str) { - continue; - } - - /* We need to try and decode the CN since it may be encoded as unicode with a - * direct ASCII equivalent. Any non ASCII bytes in the string will fail later when we - * actually compare hostnames. - */ - DEFER_CLEANUP(unsigned char *utf8_str, OPENSSL_free_pointer); - const int utf8_out_len = ASN1_STRING_to_UTF8(&utf8_str, asn1_str); - if (utf8_out_len < 0) { - /* On failure, ASN1_STRING_to_UTF8 does not allocate any memory */ - continue; - } else if (utf8_out_len == 0) { - /* We still need to free memory here see https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7521 */ - OPENSSL_free(utf8_str); - } else { - struct s2n_blob *cn_name = NULL; - GUARD_AS_POSIX(s2n_array_pushback(chain_and_key->cn_names, (void **)&cn_name)); - if (cn_name == NULL) { - S2N_ERROR(S2N_ERR_NULL_CN_NAME); - } - - if (s2n_alloc(cn_name, utf8_out_len) < 0) { - S2N_ERROR_PRESERVE_ERRNO(); - } - memcpy_check(cn_name->data, utf8_str, utf8_out_len); - cn_name->size = utf8_out_len; - /* normalize cn_name to lowercase */ - GUARD(s2n_blob_char_to_lower(cn_name)); - } - } - - return 0; -} - -static int s2n_cert_chain_and_key_set_names(struct s2n_cert_chain_and_key *chain_and_key, struct s2n_blob *leaf_bytes) -{ - const unsigned char *leaf_der = leaf_bytes->data; - X509 *cert = d2i_X509(NULL, &leaf_der, leaf_bytes->size); - if (!cert) { - S2N_ERROR(S2N_ERR_INVALID_PEM); - } - - GUARD(s2n_cert_chain_and_key_load_sans(chain_and_key, cert)); - /* For current use cases, we *could* avoid populating the common names if any sans were loaded in - * s2n_cert_chain_and_key_load_sans. Let's unconditionally populate this field to avoid surprises - * in the future. - */ - GUARD(s2n_cert_chain_and_key_load_cns(chain_and_key, cert)); - - X509_free(cert); - return 0; -} - -int s2n_cert_chain_and_key_load_pem(struct s2n_cert_chain_and_key *chain_and_key, const char *chain_pem, const char *private_key_pem) -{ - notnull_check(chain_and_key); - - GUARD(s2n_cert_chain_and_key_set_cert_chain(chain_and_key, chain_pem)); - GUARD(s2n_cert_chain_and_key_set_private_key(chain_and_key, private_key_pem)); - - /* Parse the leaf cert for the public key and certificate type */ - DEFER_CLEANUP(struct s2n_pkey public_key = {0}, s2n_pkey_free); - s2n_pkey_type pkey_type = S2N_PKEY_TYPE_UNKNOWN; - GUARD(s2n_asn1der_to_public_key_and_type(&public_key, &pkey_type, &chain_and_key->cert_chain->head->raw)); - S2N_ERROR_IF(pkey_type == S2N_PKEY_TYPE_UNKNOWN, S2N_ERR_CERT_TYPE_UNSUPPORTED); - GUARD(s2n_cert_set_cert_type(chain_and_key->cert_chain->head, pkey_type)); - - /* Validate the leaf cert's public key matches the provided private key */ - GUARD(s2n_pkey_match(&public_key, chain_and_key->private_key)); - - /* Populate name information from the SAN/CN for the leaf certificate */ - GUARD(s2n_cert_chain_and_key_set_names(chain_and_key, &chain_and_key->cert_chain->head->raw)); - - return 0; -} - -int s2n_cert_chain_and_key_free(struct s2n_cert_chain_and_key *cert_and_key) -{ - if (cert_and_key == NULL) { - return 0; - } - - /* Walk the chain and free the certs */ - if (cert_and_key->cert_chain) { - struct s2n_cert *node = cert_and_key->cert_chain->head; - while (node) { - /* Free the cert */ - GUARD(s2n_free(&node->raw)); - /* update head so it won't point to freed memory */ - cert_and_key->cert_chain->head = node->next; - /* Free the node */ - GUARD(s2n_free_object((uint8_t **)&node, sizeof(struct s2n_cert))); - node = cert_and_key->cert_chain->head; - } - - GUARD(s2n_free_object((uint8_t **)&cert_and_key->cert_chain, sizeof(struct s2n_cert_chain))); - } - - if (cert_and_key->private_key) { - GUARD(s2n_pkey_free(cert_and_key->private_key)); - GUARD(s2n_free_object((uint8_t **)&cert_and_key->private_key, sizeof(s2n_cert_private_key))); - } - - uint32_t len = 0; - - if (cert_and_key->san_names) { - GUARD_AS_POSIX(s2n_array_num_elements(cert_and_key->san_names, &len)); - for (uint32_t i = 0; i < len; i++) { - struct s2n_blob *san_name = NULL; - GUARD_AS_POSIX(s2n_array_get(cert_and_key->san_names, i, (void **)&san_name)); - GUARD(s2n_free(san_name)); - } - GUARD_AS_POSIX(s2n_array_free(cert_and_key->san_names)); - cert_and_key->san_names = NULL; - } - - if (cert_and_key->cn_names) { - GUARD_AS_POSIX(s2n_array_num_elements(cert_and_key->cn_names, &len)); - for (uint32_t i = 0; i < len; i++) { - struct s2n_blob *cn_name = NULL; - GUARD_AS_POSIX(s2n_array_get(cert_and_key->cn_names, i, (void **)&cn_name)); - GUARD(s2n_free(cn_name)); - } - GUARD_AS_POSIX(s2n_array_free(cert_and_key->cn_names)); - cert_and_key->cn_names = NULL; - } - - GUARD(s2n_free(&cert_and_key->ocsp_status)); - GUARD(s2n_free(&cert_and_key->sct_list)); - - GUARD(s2n_free_object((uint8_t **)&cert_and_key, sizeof(struct s2n_cert_chain_and_key))); - return 0; -} - -int s2n_send_cert_chain(struct s2n_connection *conn, struct s2n_stuffer *out, struct s2n_cert_chain_and_key *chain_and_key) -{ - notnull_check(conn); - notnull_check(out); - notnull_check(chain_and_key); - struct s2n_cert_chain *chain = chain_and_key->cert_chain; - notnull_check(chain); - struct s2n_cert *cur_cert = chain->head; - notnull_check(cur_cert); - - struct s2n_stuffer_reservation cert_chain_size = {0}; - GUARD(s2n_stuffer_reserve_uint24(out, &cert_chain_size)); - - /* Send certs and extensions (in TLS 1.3) */ - bool first_entry = true; - while (cur_cert) { - notnull_check(cur_cert); - GUARD(s2n_stuffer_write_uint24(out, cur_cert->raw.size)); - GUARD(s2n_stuffer_write_bytes(out, cur_cert->raw.data, cur_cert->raw.size)); - - /* According to https://tools.ietf.org/html/rfc8446#section-4.4.2, - * If an extension applies to the entire chain, it SHOULD be included in - * the first CertificateEntry. - * While the spec allow extensions to be included in other certificate - * entries, only the first matter to use here */ - if (conn->actual_protocol_version >= S2N_TLS13) { - if (first_entry) { - GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_CERTIFICATE, conn, out)); - first_entry = false; - } else { - GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_EMPTY, conn, out)); - } - } - cur_cert = cur_cert->next; - } - - GUARD(s2n_stuffer_write_vector_size(&cert_chain_size)); - - return 0; -} - -int s2n_send_empty_cert_chain(struct s2n_stuffer *out) -{ - notnull_check(out); - GUARD(s2n_stuffer_write_uint24(out, 0)); - return 0; -} - -static int s2n_does_cert_san_match_hostname(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name) -{ - notnull_check(chain_and_key); - notnull_check(dns_name); - - struct s2n_array *san_names = chain_and_key->san_names; - uint32_t len = 0; - GUARD_AS_POSIX(s2n_array_num_elements(san_names, &len)); - for (uint32_t i = 0; i < len; i++) { - struct s2n_blob *san_name = NULL; - GUARD_AS_POSIX(s2n_array_get(san_names, i, (void **)&san_name)); - notnull_check(san_name); - if ((dns_name->size == san_name->size) && (strncasecmp((const char *) dns_name->data, (const char *) san_name->data, dns_name->size) == 0)) { - return 1; - } - } - - return 0; -} - -static int s2n_does_cert_cn_match_hostname(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name) -{ - notnull_check(chain_and_key); - notnull_check(dns_name); - - struct s2n_array *cn_names = chain_and_key->cn_names; - uint32_t len = 0; - GUARD_AS_POSIX(s2n_array_num_elements(cn_names, &len)); - for (uint32_t i = 0; i < len; i++) { - struct s2n_blob *cn_name = NULL; - GUARD_AS_POSIX(s2n_array_get(cn_names, i, (void **)&cn_name)); - notnull_check(cn_name); - if ((dns_name->size == cn_name->size) && (strncasecmp((const char *) dns_name->data, (const char *) cn_name->data, dns_name->size) == 0)) { - return 1; - } - } - - return 0; -} - -int s2n_cert_chain_and_key_matches_dns_name(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name) -{ - uint32_t len = 0; - GUARD_AS_POSIX(s2n_array_num_elements(chain_and_key->san_names, &len)); - if (len > 0) { - if (s2n_does_cert_san_match_hostname(chain_and_key, dns_name)) { - return 1; - } - } else { - /* Per https://tools.ietf.org/html/rfc6125#section-6.4.4 we only will - * consider the CN for matching if no valid DNS entries are provided - * in a SAN. - */ - if (s2n_does_cert_cn_match_hostname(chain_and_key, dns_name)) { - return 1; - } - } - - return 0; -} - -int s2n_cert_chain_and_key_set_ctx(struct s2n_cert_chain_and_key *cert_and_key, void *ctx) -{ - cert_and_key->context = ctx; - return 0; -} - -void *s2n_cert_chain_and_key_get_ctx(struct s2n_cert_chain_and_key *cert_and_key) -{ - return cert_and_key->context; -} - -s2n_pkey_type s2n_cert_chain_and_key_get_pkey_type(struct s2n_cert_chain_and_key *chain_and_key) -{ - return chain_and_key->cert_chain->head->pkey_type; -} - -s2n_cert_private_key *s2n_cert_chain_and_key_get_private_key(struct s2n_cert_chain_and_key *chain_and_key) -{ - ENSURE_REF_PTR(chain_and_key); - return chain_and_key->private_key; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include <s2n.h> +#include <openssl/x509v3.h> +#include <openssl/pem.h> +#include <string.h> +#include <strings.h> + +#include "crypto/s2n_certificate.h" +#include "utils/s2n_array.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_mem.h" + +#include "tls/extensions/s2n_extension_list.h" +#include "tls/s2n_connection.h" + +int s2n_cert_set_cert_type(struct s2n_cert *cert, s2n_pkey_type pkey_type) +{ + notnull_check(cert); + cert->pkey_type = pkey_type; + GUARD(s2n_pkey_setup_for_type(&cert->public_key, pkey_type)); + return 0; +} + +int s2n_create_cert_chain_from_stuffer(struct s2n_cert_chain *cert_chain_out, struct s2n_stuffer *chain_in_stuffer) +{ + DEFER_CLEANUP(struct s2n_stuffer cert_out_stuffer = {0}, s2n_stuffer_free); + GUARD(s2n_stuffer_growable_alloc(&cert_out_stuffer, 2048)); + + struct s2n_cert **insert = &cert_chain_out->head; + uint32_t chain_size = 0; + do { + struct s2n_cert *new_node = NULL; + + if (s2n_stuffer_certificate_from_pem(chain_in_stuffer, &cert_out_stuffer) < 0) { + if (chain_size == 0) { + S2N_ERROR(S2N_ERR_NO_CERTIFICATE_IN_PEM); + } + break; + } + struct s2n_blob mem = {0}; + GUARD(s2n_alloc(&mem, sizeof(struct s2n_cert))); + new_node = (struct s2n_cert *)(void *)mem.data; + + if (s2n_alloc(&new_node->raw, s2n_stuffer_data_available(&cert_out_stuffer)) != S2N_SUCCESS) { + GUARD(s2n_free(&mem)); + S2N_ERROR_PRESERVE_ERRNO(); + } + if (s2n_stuffer_read(&cert_out_stuffer, &new_node->raw) != S2N_SUCCESS) { + GUARD(s2n_free(&mem)); + S2N_ERROR_PRESERVE_ERRNO(); + } + + /* Additional 3 bytes for the length field in the protocol */ + chain_size += new_node->raw.size + 3; + new_node->next = NULL; + *insert = new_node; + insert = &new_node->next; + } while (s2n_stuffer_data_available(chain_in_stuffer)); + + /* Leftover data at this point means one of two things: + * A bug in s2n's PEM parsing OR a malformed PEM in the user's chain. + * Be conservative and fail instead of using a partial chain. + */ + S2N_ERROR_IF(s2n_stuffer_data_available(chain_in_stuffer) > 0, S2N_ERR_INVALID_PEM); + + cert_chain_out->chain_size = chain_size; + + return 0; +} + +int s2n_cert_chain_and_key_set_cert_chain_from_stuffer(struct s2n_cert_chain_and_key *cert_and_key, struct s2n_stuffer *chain_in_stuffer) +{ + return s2n_create_cert_chain_from_stuffer(cert_and_key->cert_chain, chain_in_stuffer); +} + +int s2n_cert_chain_and_key_set_cert_chain(struct s2n_cert_chain_and_key *cert_and_key, const char *cert_chain_pem) +{ + struct s2n_stuffer chain_in_stuffer = {0}; + + /* Turn the chain into a stuffer */ + GUARD(s2n_stuffer_alloc_ro_from_string(&chain_in_stuffer, cert_chain_pem)); + int rc = s2n_cert_chain_and_key_set_cert_chain_from_stuffer(cert_and_key, &chain_in_stuffer); + + GUARD(s2n_stuffer_free(&chain_in_stuffer)); + + return rc; +} + +int s2n_cert_chain_and_key_set_private_key(struct s2n_cert_chain_and_key *cert_and_key, const char *private_key_pem) +{ + DEFER_CLEANUP(struct s2n_stuffer key_in_stuffer = {0}, s2n_stuffer_free); + DEFER_CLEANUP(struct s2n_stuffer key_out_stuffer = {0}, s2n_stuffer_free); + struct s2n_blob key_blob = {0}; + + GUARD(s2n_pkey_zero_init(cert_and_key->private_key)); + + /* Put the private key pem in a stuffer */ + GUARD(s2n_stuffer_alloc_ro_from_string(&key_in_stuffer, private_key_pem)); + GUARD(s2n_stuffer_growable_alloc(&key_out_stuffer, strlen(private_key_pem))); + + /* Convert pem to asn1 and asn1 to the private key. Handles both PKCS#1 and PKCS#8 formats */ + GUARD(s2n_stuffer_private_key_from_pem(&key_in_stuffer, &key_out_stuffer)); + key_blob.size = s2n_stuffer_data_available(&key_out_stuffer); + key_blob.data = s2n_stuffer_raw_read(&key_out_stuffer, key_blob.size); + notnull_check(key_blob.data); + + /* Get key type and create appropriate key context */ + GUARD(s2n_asn1der_to_private_key(cert_and_key->private_key, &key_blob)); + + return 0; +} + +int s2n_cert_chain_and_key_set_ocsp_data(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length) +{ + notnull_check(chain_and_key); + GUARD(s2n_free(&chain_and_key->ocsp_status)); + if (data && length) { + GUARD(s2n_alloc(&chain_and_key->ocsp_status, length)); + memcpy_check(chain_and_key->ocsp_status.data, data, length); + } + return 0; +} + +int s2n_cert_chain_and_key_set_sct_list(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length) +{ + notnull_check(chain_and_key); + GUARD(s2n_free(&chain_and_key->sct_list)); + if (data && length) { + GUARD(s2n_alloc(&chain_and_key->sct_list, length)); + memcpy_check(chain_and_key->sct_list.data, data, length); + } + return 0; +} + +struct s2n_cert_chain_and_key *s2n_cert_chain_and_key_new(void) +{ + struct s2n_cert_chain_and_key *chain_and_key; + struct s2n_blob chain_and_key_mem, cert_chain_mem, pkey_mem; + + GUARD_PTR(s2n_alloc(&chain_and_key_mem, sizeof(struct s2n_cert_chain_and_key))); + chain_and_key = (struct s2n_cert_chain_and_key *)(void *)chain_and_key_mem.data; + + /* Allocate the memory for the chain and key */ + if (s2n_alloc(&cert_chain_mem, sizeof(struct s2n_cert_chain)) != S2N_SUCCESS) { + goto cleanup; + } + chain_and_key->cert_chain = (struct s2n_cert_chain *)(void *)cert_chain_mem.data; + + if (s2n_alloc(&pkey_mem, sizeof(s2n_cert_private_key)) != S2N_SUCCESS) { + goto cleanup; + } + chain_and_key->private_key = (s2n_cert_private_key *)(void *)pkey_mem.data; + + chain_and_key->cert_chain->head = NULL; + if (s2n_pkey_zero_init(chain_and_key->private_key) != S2N_SUCCESS) { + goto cleanup; + } + memset(&chain_and_key->ocsp_status, 0, sizeof(chain_and_key->ocsp_status)); + memset(&chain_and_key->sct_list, 0, sizeof(chain_and_key->sct_list)); + chain_and_key->cn_names = s2n_array_new(sizeof(struct s2n_blob)); + if (!chain_and_key->cn_names) { + goto cleanup; + } + + chain_and_key->san_names = s2n_array_new(sizeof(struct s2n_blob)); + if (!chain_and_key->san_names) { + goto cleanup; + } + + chain_and_key->context = NULL; + + return chain_and_key; + cleanup: + s2n_free(&pkey_mem); + s2n_free(&cert_chain_mem); + s2n_free(&chain_and_key_mem); + return NULL; +} + +DEFINE_POINTER_CLEANUP_FUNC(GENERAL_NAMES *, GENERAL_NAMES_free); + +int s2n_cert_chain_and_key_load_sans(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert) +{ + notnull_check(chain_and_key->san_names); + + DEFER_CLEANUP(GENERAL_NAMES *san_names = X509_get_ext_d2i(x509_cert, NID_subject_alt_name, NULL, NULL), GENERAL_NAMES_free_pointer); + if (san_names == NULL) { + /* No SAN extension */ + return 0; + } + + const int num_san_names = sk_GENERAL_NAME_num(san_names); + for (int i = 0; i < num_san_names; i++) { + GENERAL_NAME *san_name = sk_GENERAL_NAME_value(san_names, i); + if (!san_name) { + continue; + } + + if (san_name->type == GEN_DNS) { + /* Decoding isn't necessary here since a DNS SAN name is ASCII(type V_ASN1_IA5STRING) */ + unsigned char *san_str = san_name->d.dNSName->data; + const size_t san_str_len = san_name->d.dNSName->length; + struct s2n_blob *san_blob = NULL; + GUARD_AS_POSIX(s2n_array_pushback(chain_and_key->san_names, (void **)&san_blob)); + if (!san_blob) { + S2N_ERROR(S2N_ERR_NULL_SANS); + } + + if (s2n_alloc(san_blob, san_str_len)) { + S2N_ERROR_PRESERVE_ERRNO(); + } + + memcpy_check(san_blob->data, san_str, san_str_len); + san_blob->size = san_str_len; + /* normalize san_blob to lowercase */ + GUARD(s2n_blob_char_to_lower(san_blob)); + } + } + + return 0; +} + +/* Parse CN names from the Subject of the leaf certificate. Technically there can by multiple CNs + * in the Subject but practically very few certificates in the wild will have more than one CN. + * Since the data for this certificate is coming from the application and not from an untrusted + * source, we will try our best to parse all of the CNs. + * + * A recent CAB thread proposed removing support for multiple CNs: + * https://cabforum.org/pipermail/public/2016-April/007242.html + */ + +DEFINE_POINTER_CLEANUP_FUNC(unsigned char *, OPENSSL_free); + +int s2n_cert_chain_and_key_load_cns(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert) +{ + notnull_check(chain_and_key->cn_names); + + X509_NAME *subject = X509_get_subject_name(x509_cert); + if (!subject) { + return 0; + } + + int lastpos = -1; + while((lastpos = X509_NAME_get_index_by_NID(subject, NID_commonName, lastpos)) >= 0) { + X509_NAME_ENTRY *name_entry = X509_NAME_get_entry(subject, lastpos); + if (!name_entry) { + continue; + } + + ASN1_STRING *asn1_str = X509_NAME_ENTRY_get_data(name_entry); + if (!asn1_str) { + continue; + } + + /* We need to try and decode the CN since it may be encoded as unicode with a + * direct ASCII equivalent. Any non ASCII bytes in the string will fail later when we + * actually compare hostnames. + */ + DEFER_CLEANUP(unsigned char *utf8_str, OPENSSL_free_pointer); + const int utf8_out_len = ASN1_STRING_to_UTF8(&utf8_str, asn1_str); + if (utf8_out_len < 0) { + /* On failure, ASN1_STRING_to_UTF8 does not allocate any memory */ + continue; + } else if (utf8_out_len == 0) { + /* We still need to free memory here see https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7521 */ + OPENSSL_free(utf8_str); + } else { + struct s2n_blob *cn_name = NULL; + GUARD_AS_POSIX(s2n_array_pushback(chain_and_key->cn_names, (void **)&cn_name)); + if (cn_name == NULL) { + S2N_ERROR(S2N_ERR_NULL_CN_NAME); + } + + if (s2n_alloc(cn_name, utf8_out_len) < 0) { + S2N_ERROR_PRESERVE_ERRNO(); + } + memcpy_check(cn_name->data, utf8_str, utf8_out_len); + cn_name->size = utf8_out_len; + /* normalize cn_name to lowercase */ + GUARD(s2n_blob_char_to_lower(cn_name)); + } + } + + return 0; +} + +static int s2n_cert_chain_and_key_set_names(struct s2n_cert_chain_and_key *chain_and_key, struct s2n_blob *leaf_bytes) +{ + const unsigned char *leaf_der = leaf_bytes->data; + X509 *cert = d2i_X509(NULL, &leaf_der, leaf_bytes->size); + if (!cert) { + S2N_ERROR(S2N_ERR_INVALID_PEM); + } + + GUARD(s2n_cert_chain_and_key_load_sans(chain_and_key, cert)); + /* For current use cases, we *could* avoid populating the common names if any sans were loaded in + * s2n_cert_chain_and_key_load_sans. Let's unconditionally populate this field to avoid surprises + * in the future. + */ + GUARD(s2n_cert_chain_and_key_load_cns(chain_and_key, cert)); + + X509_free(cert); + return 0; +} + +int s2n_cert_chain_and_key_load_pem(struct s2n_cert_chain_and_key *chain_and_key, const char *chain_pem, const char *private_key_pem) +{ + notnull_check(chain_and_key); + + GUARD(s2n_cert_chain_and_key_set_cert_chain(chain_and_key, chain_pem)); + GUARD(s2n_cert_chain_and_key_set_private_key(chain_and_key, private_key_pem)); + + /* Parse the leaf cert for the public key and certificate type */ + DEFER_CLEANUP(struct s2n_pkey public_key = {0}, s2n_pkey_free); + s2n_pkey_type pkey_type = S2N_PKEY_TYPE_UNKNOWN; + GUARD(s2n_asn1der_to_public_key_and_type(&public_key, &pkey_type, &chain_and_key->cert_chain->head->raw)); + S2N_ERROR_IF(pkey_type == S2N_PKEY_TYPE_UNKNOWN, S2N_ERR_CERT_TYPE_UNSUPPORTED); + GUARD(s2n_cert_set_cert_type(chain_and_key->cert_chain->head, pkey_type)); + + /* Validate the leaf cert's public key matches the provided private key */ + GUARD(s2n_pkey_match(&public_key, chain_and_key->private_key)); + + /* Populate name information from the SAN/CN for the leaf certificate */ + GUARD(s2n_cert_chain_and_key_set_names(chain_and_key, &chain_and_key->cert_chain->head->raw)); + + return 0; +} + +int s2n_cert_chain_and_key_free(struct s2n_cert_chain_and_key *cert_and_key) +{ + if (cert_and_key == NULL) { + return 0; + } + + /* Walk the chain and free the certs */ + if (cert_and_key->cert_chain) { + struct s2n_cert *node = cert_and_key->cert_chain->head; + while (node) { + /* Free the cert */ + GUARD(s2n_free(&node->raw)); + /* update head so it won't point to freed memory */ + cert_and_key->cert_chain->head = node->next; + /* Free the node */ + GUARD(s2n_free_object((uint8_t **)&node, sizeof(struct s2n_cert))); + node = cert_and_key->cert_chain->head; + } + + GUARD(s2n_free_object((uint8_t **)&cert_and_key->cert_chain, sizeof(struct s2n_cert_chain))); + } + + if (cert_and_key->private_key) { + GUARD(s2n_pkey_free(cert_and_key->private_key)); + GUARD(s2n_free_object((uint8_t **)&cert_and_key->private_key, sizeof(s2n_cert_private_key))); + } + + uint32_t len = 0; + + if (cert_and_key->san_names) { + GUARD_AS_POSIX(s2n_array_num_elements(cert_and_key->san_names, &len)); + for (uint32_t i = 0; i < len; i++) { + struct s2n_blob *san_name = NULL; + GUARD_AS_POSIX(s2n_array_get(cert_and_key->san_names, i, (void **)&san_name)); + GUARD(s2n_free(san_name)); + } + GUARD_AS_POSIX(s2n_array_free(cert_and_key->san_names)); + cert_and_key->san_names = NULL; + } + + if (cert_and_key->cn_names) { + GUARD_AS_POSIX(s2n_array_num_elements(cert_and_key->cn_names, &len)); + for (uint32_t i = 0; i < len; i++) { + struct s2n_blob *cn_name = NULL; + GUARD_AS_POSIX(s2n_array_get(cert_and_key->cn_names, i, (void **)&cn_name)); + GUARD(s2n_free(cn_name)); + } + GUARD_AS_POSIX(s2n_array_free(cert_and_key->cn_names)); + cert_and_key->cn_names = NULL; + } + + GUARD(s2n_free(&cert_and_key->ocsp_status)); + GUARD(s2n_free(&cert_and_key->sct_list)); + + GUARD(s2n_free_object((uint8_t **)&cert_and_key, sizeof(struct s2n_cert_chain_and_key))); + return 0; +} + +int s2n_send_cert_chain(struct s2n_connection *conn, struct s2n_stuffer *out, struct s2n_cert_chain_and_key *chain_and_key) +{ + notnull_check(conn); + notnull_check(out); + notnull_check(chain_and_key); + struct s2n_cert_chain *chain = chain_and_key->cert_chain; + notnull_check(chain); + struct s2n_cert *cur_cert = chain->head; + notnull_check(cur_cert); + + struct s2n_stuffer_reservation cert_chain_size = {0}; + GUARD(s2n_stuffer_reserve_uint24(out, &cert_chain_size)); + + /* Send certs and extensions (in TLS 1.3) */ + bool first_entry = true; + while (cur_cert) { + notnull_check(cur_cert); + GUARD(s2n_stuffer_write_uint24(out, cur_cert->raw.size)); + GUARD(s2n_stuffer_write_bytes(out, cur_cert->raw.data, cur_cert->raw.size)); + + /* According to https://tools.ietf.org/html/rfc8446#section-4.4.2, + * If an extension applies to the entire chain, it SHOULD be included in + * the first CertificateEntry. + * While the spec allow extensions to be included in other certificate + * entries, only the first matter to use here */ + if (conn->actual_protocol_version >= S2N_TLS13) { + if (first_entry) { + GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_CERTIFICATE, conn, out)); + first_entry = false; + } else { + GUARD(s2n_extension_list_send(S2N_EXTENSION_LIST_EMPTY, conn, out)); + } + } + cur_cert = cur_cert->next; + } + + GUARD(s2n_stuffer_write_vector_size(&cert_chain_size)); + + return 0; +} + +int s2n_send_empty_cert_chain(struct s2n_stuffer *out) +{ + notnull_check(out); + GUARD(s2n_stuffer_write_uint24(out, 0)); + return 0; +} + +static int s2n_does_cert_san_match_hostname(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name) +{ + notnull_check(chain_and_key); + notnull_check(dns_name); + + struct s2n_array *san_names = chain_and_key->san_names; + uint32_t len = 0; + GUARD_AS_POSIX(s2n_array_num_elements(san_names, &len)); + for (uint32_t i = 0; i < len; i++) { + struct s2n_blob *san_name = NULL; + GUARD_AS_POSIX(s2n_array_get(san_names, i, (void **)&san_name)); + notnull_check(san_name); + if ((dns_name->size == san_name->size) && (strncasecmp((const char *) dns_name->data, (const char *) san_name->data, dns_name->size) == 0)) { + return 1; + } + } + + return 0; +} + +static int s2n_does_cert_cn_match_hostname(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name) +{ + notnull_check(chain_and_key); + notnull_check(dns_name); + + struct s2n_array *cn_names = chain_and_key->cn_names; + uint32_t len = 0; + GUARD_AS_POSIX(s2n_array_num_elements(cn_names, &len)); + for (uint32_t i = 0; i < len; i++) { + struct s2n_blob *cn_name = NULL; + GUARD_AS_POSIX(s2n_array_get(cn_names, i, (void **)&cn_name)); + notnull_check(cn_name); + if ((dns_name->size == cn_name->size) && (strncasecmp((const char *) dns_name->data, (const char *) cn_name->data, dns_name->size) == 0)) { + return 1; + } + } + + return 0; +} + +int s2n_cert_chain_and_key_matches_dns_name(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name) +{ + uint32_t len = 0; + GUARD_AS_POSIX(s2n_array_num_elements(chain_and_key->san_names, &len)); + if (len > 0) { + if (s2n_does_cert_san_match_hostname(chain_and_key, dns_name)) { + return 1; + } + } else { + /* Per https://tools.ietf.org/html/rfc6125#section-6.4.4 we only will + * consider the CN for matching if no valid DNS entries are provided + * in a SAN. + */ + if (s2n_does_cert_cn_match_hostname(chain_and_key, dns_name)) { + return 1; + } + } + + return 0; +} + +int s2n_cert_chain_and_key_set_ctx(struct s2n_cert_chain_and_key *cert_and_key, void *ctx) +{ + cert_and_key->context = ctx; + return 0; +} + +void *s2n_cert_chain_and_key_get_ctx(struct s2n_cert_chain_and_key *cert_and_key) +{ + return cert_and_key->context; +} + +s2n_pkey_type s2n_cert_chain_and_key_get_pkey_type(struct s2n_cert_chain_and_key *chain_and_key) +{ + return chain_and_key->cert_chain->head->pkey_type; +} + +s2n_cert_private_key *s2n_cert_chain_and_key_get_private_key(struct s2n_cert_chain_and_key *chain_and_key) +{ + ENSURE_REF_PTR(chain_and_key); + return chain_and_key->private_key; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_certificate.h b/contrib/restricted/aws/s2n/crypto/s2n_certificate.h index 2395595641..28b87a44e9 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_certificate.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_certificate.h @@ -1,75 +1,75 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <stdint.h> - -#include <openssl/x509.h> - -#include <s2n.h> -#include "crypto/s2n_pkey.h" -#include "stuffer/s2n_stuffer.h" - -#define S2N_CERT_TYPE_COUNT S2N_PKEY_TYPE_SENTINEL - -struct s2n_cert { - s2n_pkey_type pkey_type; - s2n_cert_public_key public_key; - struct s2n_blob raw; - struct s2n_cert *next; -}; - -struct s2n_cert_chain { - uint32_t chain_size; - struct s2n_cert *head; -}; - -struct s2n_cert_chain_and_key { - struct s2n_cert_chain *cert_chain; - s2n_cert_private_key *private_key; - struct s2n_blob ocsp_status; - struct s2n_blob sct_list; - /* DNS type SubjectAlternative names from the leaf certificate to match - * with the server_name extension. We ignore non-DNS SANs here since the - * server_name extension only supports DNS. - */ - struct s2n_array *san_names; - /* CommonName values from the leaf certificate's Subject to match with the - * server_name extension. Decoded as UTF8. - */ - struct s2n_array *cn_names; - /* Application defined data related to this cert. */ - void *context; -}; - -struct certs_by_type { - struct s2n_cert_chain_and_key *certs[S2N_CERT_TYPE_COUNT]; -}; - -int s2n_cert_chain_and_key_set_ocsp_data(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length); -int s2n_cert_chain_and_key_set_sct_list(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length); -/* Exposed for fuzzing */ -int s2n_cert_chain_and_key_load_cns(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert); -int s2n_cert_chain_and_key_load_sans(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert); -int s2n_cert_chain_and_key_matches_dns_name(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name); - -int s2n_cert_set_cert_type(struct s2n_cert *cert, s2n_pkey_type pkey_type); -int s2n_send_cert_chain(struct s2n_connection *conn, struct s2n_stuffer *out, struct s2n_cert_chain_and_key *chain_and_key); -int s2n_send_empty_cert_chain(struct s2n_stuffer *out); -int s2n_create_cert_chain_from_stuffer(struct s2n_cert_chain *cert_chain_out, struct s2n_stuffer *chain_in_stuffer); -int s2n_cert_chain_and_key_set_cert_chain(struct s2n_cert_chain_and_key *cert_and_key, const char *cert_chain_pem); -int s2n_cert_chain_and_key_set_private_key(struct s2n_cert_chain_and_key *cert_and_key, const char *private_key_pem); -s2n_pkey_type s2n_cert_chain_and_key_get_pkey_type(struct s2n_cert_chain_and_key *chain_and_key); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <stdint.h> + +#include <openssl/x509.h> + +#include <s2n.h> +#include "crypto/s2n_pkey.h" +#include "stuffer/s2n_stuffer.h" + +#define S2N_CERT_TYPE_COUNT S2N_PKEY_TYPE_SENTINEL + +struct s2n_cert { + s2n_pkey_type pkey_type; + s2n_cert_public_key public_key; + struct s2n_blob raw; + struct s2n_cert *next; +}; + +struct s2n_cert_chain { + uint32_t chain_size; + struct s2n_cert *head; +}; + +struct s2n_cert_chain_and_key { + struct s2n_cert_chain *cert_chain; + s2n_cert_private_key *private_key; + struct s2n_blob ocsp_status; + struct s2n_blob sct_list; + /* DNS type SubjectAlternative names from the leaf certificate to match + * with the server_name extension. We ignore non-DNS SANs here since the + * server_name extension only supports DNS. + */ + struct s2n_array *san_names; + /* CommonName values from the leaf certificate's Subject to match with the + * server_name extension. Decoded as UTF8. + */ + struct s2n_array *cn_names; + /* Application defined data related to this cert. */ + void *context; +}; + +struct certs_by_type { + struct s2n_cert_chain_and_key *certs[S2N_CERT_TYPE_COUNT]; +}; + +int s2n_cert_chain_and_key_set_ocsp_data(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length); +int s2n_cert_chain_and_key_set_sct_list(struct s2n_cert_chain_and_key *chain_and_key, const uint8_t *data, uint32_t length); +/* Exposed for fuzzing */ +int s2n_cert_chain_and_key_load_cns(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert); +int s2n_cert_chain_and_key_load_sans(struct s2n_cert_chain_and_key *chain_and_key, X509 *x509_cert); +int s2n_cert_chain_and_key_matches_dns_name(const struct s2n_cert_chain_and_key *chain_and_key, const struct s2n_blob *dns_name); + +int s2n_cert_set_cert_type(struct s2n_cert *cert, s2n_pkey_type pkey_type); +int s2n_send_cert_chain(struct s2n_connection *conn, struct s2n_stuffer *out, struct s2n_cert_chain_and_key *chain_and_key); +int s2n_send_empty_cert_chain(struct s2n_stuffer *out); +int s2n_create_cert_chain_from_stuffer(struct s2n_cert_chain *cert_chain_out, struct s2n_stuffer *chain_in_stuffer); +int s2n_cert_chain_and_key_set_cert_chain(struct s2n_cert_chain_and_key *cert_and_key, const char *cert_chain_pem); +int s2n_cert_chain_and_key_set_private_key(struct s2n_cert_chain_and_key *cert_and_key, const char *private_key_pem); +s2n_pkey_type s2n_cert_chain_and_key_get_pkey_type(struct s2n_cert_chain_and_key *chain_and_key); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_cipher.c b/contrib/restricted/aws/s2n/crypto/s2n_cipher.c index 8a83980518..85333651cb 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_cipher.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_cipher.c @@ -1,56 +1,56 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/evp.h> -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) -#error #include <openssl/mem.h> -#endif - -#include "crypto/s2n_cipher.h" - -#include "utils/s2n_safety.h" - -int s2n_session_key_alloc(struct s2n_session_key *key) -{ - eq_check(key->evp_cipher_ctx, NULL); - notnull_check(key->evp_cipher_ctx = EVP_CIPHER_CTX_new()); -#if defined(S2N_CIPHER_AEAD_API_AVAILABLE) - eq_check(key->evp_aead_ctx, NULL); - key->evp_aead_ctx = OPENSSL_malloc(sizeof(EVP_AEAD_CTX)); - if (key->evp_aead_ctx == NULL) { - EVP_CIPHER_CTX_free(key->evp_cipher_ctx); - S2N_ERROR_PRESERVE_ERRNO(); - } - EVP_AEAD_CTX_zero(key->evp_aead_ctx); -#endif - - return 0; -} - -int s2n_session_key_free(struct s2n_session_key *key) -{ - if (key->evp_cipher_ctx != NULL) { - EVP_CIPHER_CTX_free(key->evp_cipher_ctx); - key->evp_cipher_ctx = NULL; - } -#if defined(S2N_CIPHER_AEAD_API_AVAILABLE) - if (key->evp_aead_ctx != NULL) { - EVP_AEAD_CTX_free(key->evp_aead_ctx); - key->evp_aead_ctx = NULL; - } -#endif - - return 0; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/evp.h> +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#error #include <openssl/mem.h> +#endif + +#include "crypto/s2n_cipher.h" + +#include "utils/s2n_safety.h" + +int s2n_session_key_alloc(struct s2n_session_key *key) +{ + eq_check(key->evp_cipher_ctx, NULL); + notnull_check(key->evp_cipher_ctx = EVP_CIPHER_CTX_new()); +#if defined(S2N_CIPHER_AEAD_API_AVAILABLE) + eq_check(key->evp_aead_ctx, NULL); + key->evp_aead_ctx = OPENSSL_malloc(sizeof(EVP_AEAD_CTX)); + if (key->evp_aead_ctx == NULL) { + EVP_CIPHER_CTX_free(key->evp_cipher_ctx); + S2N_ERROR_PRESERVE_ERRNO(); + } + EVP_AEAD_CTX_zero(key->evp_aead_ctx); +#endif + + return 0; +} + +int s2n_session_key_free(struct s2n_session_key *key) +{ + if (key->evp_cipher_ctx != NULL) { + EVP_CIPHER_CTX_free(key->evp_cipher_ctx); + key->evp_cipher_ctx = NULL; + } +#if defined(S2N_CIPHER_AEAD_API_AVAILABLE) + if (key->evp_aead_ctx != NULL) { + EVP_AEAD_CTX_free(key->evp_aead_ctx); + key->evp_aead_ctx = NULL; + } +#endif + + return 0; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_cipher.h b/contrib/restricted/aws/s2n/crypto/s2n_cipher.h index 811f3e081d..ed1b122828 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_cipher.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_cipher.h @@ -1,104 +1,104 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <openssl/evp.h> -#include <openssl/aes.h> -#include <openssl/rc4.h> -#include <openssl/des.h> -#include <openssl/rsa.h> -#include <openssl/dh.h> - -#include "crypto/s2n_crypto.h" - -#include "utils/s2n_blob.h" - -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) -#define S2N_CIPHER_AEAD_API_AVAILABLE -#endif - -struct s2n_session_key { - EVP_CIPHER_CTX *evp_cipher_ctx; -#if defined(S2N_CIPHER_AEAD_API_AVAILABLE) - EVP_AEAD_CTX *evp_aead_ctx; -#endif -}; - -struct s2n_stream_cipher { - int (*decrypt) (struct s2n_session_key * key, struct s2n_blob * in, struct s2n_blob * out); - int (*encrypt) (struct s2n_session_key * key, struct s2n_blob * in, struct s2n_blob * out); -}; - -struct s2n_cbc_cipher { - uint8_t block_size; - uint8_t record_iv_size; - int (*decrypt) (struct s2n_session_key * key, struct s2n_blob * iv, struct s2n_blob * in, struct s2n_blob * out); - int (*encrypt) (struct s2n_session_key * key, struct s2n_blob * iv, struct s2n_blob * in, struct s2n_blob * out); -}; - -struct s2n_aead_cipher { - uint8_t fixed_iv_size; - uint8_t record_iv_size; - uint8_t tag_size; - int (*decrypt) (struct s2n_session_key * key, struct s2n_blob * iv, struct s2n_blob * add, struct s2n_blob * in, struct s2n_blob * out); - int (*encrypt) (struct s2n_session_key * key, struct s2n_blob * iv, struct s2n_blob * add, struct s2n_blob * in, struct s2n_blob * out); -}; - -struct s2n_composite_cipher { - uint8_t block_size; - uint8_t record_iv_size; - uint8_t mac_key_size; - int (*decrypt) (struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out); - int (*encrypt) (struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out); - int (*set_mac_write_key) (struct s2n_session_key *key, uint8_t *mac_key, uint32_t mac_size); - int (*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); -}; - -struct s2n_cipher { - enum { S2N_STREAM, S2N_CBC, S2N_AEAD, S2N_COMPOSITE } type; - union { - struct s2n_stream_cipher stream; - struct s2n_aead_cipher aead; - struct s2n_cbc_cipher cbc; - struct s2n_composite_cipher comp; - } io; - uint8_t key_material_size; - uint8_t (*is_available) (void); - int (*init) (struct s2n_session_key *key); - int (*set_decryption_key) (struct s2n_session_key *key, struct s2n_blob *in); - int (*set_encryption_key) (struct s2n_session_key *key, struct s2n_blob *in); - int (*destroy_key) (struct s2n_session_key *key); -}; - -extern int s2n_session_key_alloc(struct s2n_session_key *key); -extern int s2n_session_key_free(struct s2n_session_key *key); - -extern struct s2n_cipher s2n_null_cipher; -extern struct s2n_cipher s2n_rc4; -extern struct s2n_cipher s2n_aes128; -extern struct s2n_cipher s2n_aes256; -extern struct s2n_cipher s2n_3des; -extern struct s2n_cipher s2n_aes128_gcm; -extern struct s2n_cipher s2n_aes256_gcm; -extern struct s2n_cipher s2n_aes128_sha; -extern struct s2n_cipher s2n_aes256_sha; -extern struct s2n_cipher s2n_aes128_sha256; -extern struct s2n_cipher s2n_aes256_sha256; -extern struct s2n_cipher s2n_chacha20_poly1305; - -extern struct s2n_cipher s2n_tls13_aes128_gcm; -extern struct s2n_cipher s2n_tls13_aes256_gcm; +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <openssl/evp.h> +#include <openssl/aes.h> +#include <openssl/rc4.h> +#include <openssl/des.h> +#include <openssl/rsa.h> +#include <openssl/dh.h> + +#include "crypto/s2n_crypto.h" + +#include "utils/s2n_blob.h" + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#define S2N_CIPHER_AEAD_API_AVAILABLE +#endif + +struct s2n_session_key { + EVP_CIPHER_CTX *evp_cipher_ctx; +#if defined(S2N_CIPHER_AEAD_API_AVAILABLE) + EVP_AEAD_CTX *evp_aead_ctx; +#endif +}; + +struct s2n_stream_cipher { + int (*decrypt) (struct s2n_session_key * key, struct s2n_blob * in, struct s2n_blob * out); + int (*encrypt) (struct s2n_session_key * key, struct s2n_blob * in, struct s2n_blob * out); +}; + +struct s2n_cbc_cipher { + uint8_t block_size; + uint8_t record_iv_size; + int (*decrypt) (struct s2n_session_key * key, struct s2n_blob * iv, struct s2n_blob * in, struct s2n_blob * out); + int (*encrypt) (struct s2n_session_key * key, struct s2n_blob * iv, struct s2n_blob * in, struct s2n_blob * out); +}; + +struct s2n_aead_cipher { + uint8_t fixed_iv_size; + uint8_t record_iv_size; + uint8_t tag_size; + int (*decrypt) (struct s2n_session_key * key, struct s2n_blob * iv, struct s2n_blob * add, struct s2n_blob * in, struct s2n_blob * out); + int (*encrypt) (struct s2n_session_key * key, struct s2n_blob * iv, struct s2n_blob * add, struct s2n_blob * in, struct s2n_blob * out); +}; + +struct s2n_composite_cipher { + uint8_t block_size; + uint8_t record_iv_size; + uint8_t mac_key_size; + int (*decrypt) (struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out); + int (*encrypt) (struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out); + int (*set_mac_write_key) (struct s2n_session_key *key, uint8_t *mac_key, uint32_t mac_size); + int (*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); +}; + +struct s2n_cipher { + enum { S2N_STREAM, S2N_CBC, S2N_AEAD, S2N_COMPOSITE } type; + union { + struct s2n_stream_cipher stream; + struct s2n_aead_cipher aead; + struct s2n_cbc_cipher cbc; + struct s2n_composite_cipher comp; + } io; + uint8_t key_material_size; + uint8_t (*is_available) (void); + int (*init) (struct s2n_session_key *key); + int (*set_decryption_key) (struct s2n_session_key *key, struct s2n_blob *in); + int (*set_encryption_key) (struct s2n_session_key *key, struct s2n_blob *in); + int (*destroy_key) (struct s2n_session_key *key); +}; + +extern int s2n_session_key_alloc(struct s2n_session_key *key); +extern int s2n_session_key_free(struct s2n_session_key *key); + +extern struct s2n_cipher s2n_null_cipher; +extern struct s2n_cipher s2n_rc4; +extern struct s2n_cipher s2n_aes128; +extern struct s2n_cipher s2n_aes256; +extern struct s2n_cipher s2n_3des; +extern struct s2n_cipher s2n_aes128_gcm; +extern struct s2n_cipher s2n_aes256_gcm; +extern struct s2n_cipher s2n_aes128_sha; +extern struct s2n_cipher s2n_aes256_sha; +extern struct s2n_cipher s2n_aes128_sha256; +extern struct s2n_cipher s2n_aes256_sha256; +extern struct s2n_cipher s2n_chacha20_poly1305; + +extern struct s2n_cipher s2n_tls13_aes128_gcm; +extern struct s2n_cipher s2n_tls13_aes256_gcm; 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 60eee634b3..f4cb75ca33 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 @@ -1,363 +1,363 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/aes.h> -#include <openssl/evp.h> -#include <openssl/sha.h> - -#include "crypto/s2n_cipher.h" -#include "crypto/s2n_fips.h" -#include "crypto/s2n_openssl.h" - -#include "tls/s2n_crypto.h" - -#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. - */ -#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) -/* 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) -#define 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. - */ -#if S2N_OPENSSL_VERSION_AT_LEAST(1,0,2) -#define S2N_AES_SHA256_COMPOSITE_AVAILABLE -#endif - -#endif - -/* Silly accessors, but we avoid using version macro guards in multiple places */ -static const EVP_CIPHER *s2n_evp_aes_128_cbc_hmac_sha1(void) -{ - #if defined(S2N_AES_SHA1_COMPOSITE_AVAILABLE) - return EVP_aes_128_cbc_hmac_sha1(); - #else - return NULL; - #endif -} - -static const EVP_CIPHER *s2n_evp_aes_256_cbc_hmac_sha1(void) -{ - #if defined(S2N_AES_SHA1_COMPOSITE_AVAILABLE) - return EVP_aes_256_cbc_hmac_sha1(); - #else - return NULL; - #endif -} - -static const EVP_CIPHER *s2n_evp_aes_128_cbc_hmac_sha256(void) -{ - #if defined(S2N_AES_SHA256_COMPOSITE_AVAILABLE) - return EVP_aes_128_cbc_hmac_sha256(); - #else - return NULL; - #endif -} - -static const EVP_CIPHER *s2n_evp_aes_256_cbc_hmac_sha256(void) -{ - #if defined(S2N_AES_SHA256_COMPOSITE_AVAILABLE) - return EVP_aes_256_cbc_hmac_sha256(); - #else - return NULL; - #endif -} - -static uint8_t s2n_composite_cipher_aes128_sha_available(void) -{ - /* EVP_aes_128_cbc_hmac_sha1() returns NULL if the implementations aren't available. - * See https://github.com/openssl/openssl/blob/master/crypto/evp/e_aes_cbc_hmac_sha1.c#L952 - * - * Composite ciphers cannot be used when FIPS mode is set. Ciphers require the - * EVP_CIPH_FLAG_FIPS OpenSSL flag to be set for use when in FIPS mode, and composite - * ciphers cause OpenSSL errors due to the lack of the flag. - */ - return (!s2n_is_in_fips_mode() && s2n_evp_aes_128_cbc_hmac_sha1() ? 1 : 0); -} - -static uint8_t s2n_composite_cipher_aes256_sha_available(void) -{ - /* Composite ciphers cannot be used when FIPS mode is set. Ciphers require the - * EVP_CIPH_FLAG_FIPS OpenSSL flag to be set for use when in FIPS mode, and composite - * ciphers cause OpenSSL errors due to the lack of the flag. - */ - return (!s2n_is_in_fips_mode() && s2n_evp_aes_256_cbc_hmac_sha1() ? 1 : 0); -} - -static uint8_t s2n_composite_cipher_aes128_sha256_available(void) -{ - /* Composite ciphers cannot be used when FIPS mode is set. Ciphers require the - * EVP_CIPH_FLAG_FIPS OpenSSL flag to be set for use when in FIPS mode, and composite - * ciphers cause OpenSSL errors due to the lack of the flag. - */ - return (!s2n_is_in_fips_mode() && s2n_evp_aes_128_cbc_hmac_sha256() ? 1 : 0); -} - -static uint8_t s2n_composite_cipher_aes256_sha256_available(void) -{ - /* Composite ciphers cannot be used when FIPS mode is set. Ciphers require the - * EVP_CIPH_FLAG_FIPS OpenSSL flag to be set for use when in FIPS mode, and composite - * ciphers cause OpenSSL errors due to the lack of the flag. - */ - return (!s2n_is_in_fips_mode() && s2n_evp_aes_256_cbc_hmac_sha256() ? 1 : 0); -} - -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. - */ -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) - S2N_ERROR(S2N_ERR_NO_SUPPORTED_LIBCRYPTO_API); -#else - uint8_t ctrl_buf[S2N_TLS12_AAD_LEN]; - struct s2n_blob ctrl_blob = { .data = ctrl_buf, .size = S2N_TLS12_AAD_LEN }; - struct s2n_stuffer ctrl_stuffer = {0}; - GUARD(s2n_stuffer_init(&ctrl_stuffer, &ctrl_blob)); - - GUARD(s2n_stuffer_write_bytes(&ctrl_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); - GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, content_type)); - GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, protocol_version / 10)); - GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, protocol_version % 10)); - GUARD(s2n_stuffer_write_uint16(&ctrl_stuffer, payload_and_eiv_len)); - - /* This will unnecessarily mangle the input buffer, which is fine since it's temporary - * Return value will be length of digest, padding, and padding length byte. - * See https://github.com/openssl/openssl/blob/master/crypto/evp/e_aes_cbc_hmac_sha1.c#L814 - * and https://github.com/openssl/openssl/blob/4f0c475719defd7c051964ef9964cc6e5b3a63bf/ssl/record/ssl3_record.c#L743 - */ - int ctrl_ret = EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_TLS1_AAD, S2N_TLS12_AAD_LEN, ctrl_buf); - - S2N_ERROR_IF(ctrl_ret < 0, S2N_ERR_INITIAL_HMAC); - - *extra = ctrl_ret; - return 0; -#endif -} - -static int s2n_composite_cipher_aes_sha_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) -{ - eq_check(out->size, in->size); - - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); - GUARD_OSSL(EVP_Cipher(key->evp_cipher_ctx, out->data, in->data, in->size), S2N_ERR_ENCRYPT); - - return 0; -} - -static int s2n_composite_cipher_aes_sha_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) -{ - eq_check(out->size, in->size); - - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); - GUARD_OSSL(EVP_Cipher(key->evp_cipher_ctx, out->data, in->data, in->size), S2N_ERR_DECRYPT); - - return 0; -} - -static int s2n_composite_cipher_aes_sha_set_mac_write_key(struct s2n_session_key *key, uint8_t *mac_key, uint32_t mac_size) -{ - eq_check(mac_size, SHA_DIGEST_LENGTH); - - EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_SET_MAC_KEY, mac_size, mac_key); - - return 0; -} - -static int s2n_composite_cipher_aes_sha256_set_mac_write_key(struct s2n_session_key *key, uint8_t *mac_key, uint32_t mac_size) -{ - eq_check(mac_size, SHA256_DIGEST_LENGTH); - - EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_SET_MAC_KEY, mac_size, mac_key); - - return 0; -} - - -static int s2n_composite_cipher_aes128_sha_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 16); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - EVP_EncryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_128_cbc_hmac_sha1(), NULL, in->data, NULL); - - return 0; -} - -static int s2n_composite_cipher_aes128_sha_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 16); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - EVP_DecryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_128_cbc_hmac_sha1(), NULL, in->data, NULL); - - return 0; -} - -static int s2n_composite_cipher_aes256_sha_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 32); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - EVP_EncryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_256_cbc_hmac_sha1(), NULL, in->data, NULL); - - return 0; -} - -static int s2n_composite_cipher_aes256_sha_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 32); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - EVP_DecryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_256_cbc_hmac_sha1(), NULL, in->data, NULL); - - return 0; -} - -static int s2n_composite_cipher_aes128_sha256_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 16); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - EVP_EncryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_128_cbc_hmac_sha256(), NULL, in->data, NULL); - - return 0; -} - -static int s2n_composite_cipher_aes128_sha256_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 16); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - EVP_DecryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_128_cbc_hmac_sha256(), NULL, in->data, NULL); - - return 0; -} - -static int s2n_composite_cipher_aes256_sha256_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 32); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - EVP_EncryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_256_cbc_hmac_sha256(), NULL, in->data, NULL); - - return 0; -} - -static int s2n_composite_cipher_aes256_sha256_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 32); - - EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); - EVP_DecryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_256_cbc_hmac_sha256(), NULL, in->data, NULL); - - return 0; -} - -static int s2n_composite_cipher_aes_sha_init(struct s2n_session_key *key) -{ - s2n_evp_ctx_init(key->evp_cipher_ctx); - - return 0; -} - -static int s2n_composite_cipher_aes_sha_destroy_key(struct s2n_session_key *key) -{ - EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); - - return 0; -} - -struct s2n_cipher s2n_aes128_sha = { - .key_material_size = 16, - .type = S2N_COMPOSITE, - .io.comp = { - .block_size = 16, - .record_iv_size = 16, - .mac_key_size = SHA_DIGEST_LENGTH, - .decrypt = s2n_composite_cipher_aes_sha_decrypt, - .encrypt = s2n_composite_cipher_aes_sha_encrypt, - .set_mac_write_key = s2n_composite_cipher_aes_sha_set_mac_write_key, - .initial_hmac = s2n_composite_cipher_aes_sha_initial_hmac }, - .is_available = s2n_composite_cipher_aes128_sha_available, - .init = s2n_composite_cipher_aes_sha_init, - .set_encryption_key = s2n_composite_cipher_aes128_sha_set_encryption_key, - .set_decryption_key = s2n_composite_cipher_aes128_sha_set_decryption_key, - .destroy_key = s2n_composite_cipher_aes_sha_destroy_key, -}; - -struct s2n_cipher s2n_aes256_sha = { - .key_material_size = 32, - .type = S2N_COMPOSITE, - .io.comp = { - .block_size = 16, - .record_iv_size = 16, - .mac_key_size = SHA_DIGEST_LENGTH, - .decrypt = s2n_composite_cipher_aes_sha_decrypt, - .encrypt = s2n_composite_cipher_aes_sha_encrypt, - .set_mac_write_key = s2n_composite_cipher_aes_sha_set_mac_write_key, - .initial_hmac = s2n_composite_cipher_aes_sha_initial_hmac }, - .is_available = s2n_composite_cipher_aes256_sha_available, - .init = s2n_composite_cipher_aes_sha_init, - .set_encryption_key = s2n_composite_cipher_aes256_sha_set_encryption_key, - .set_decryption_key = s2n_composite_cipher_aes256_sha_set_decryption_key, - .destroy_key = s2n_composite_cipher_aes_sha_destroy_key, -}; - -struct s2n_cipher s2n_aes128_sha256 = { - .key_material_size = 16, - .type = S2N_COMPOSITE, - .io.comp = { - .block_size = 16, - .record_iv_size = 16, - .mac_key_size = SHA256_DIGEST_LENGTH, - .decrypt = s2n_composite_cipher_aes_sha_decrypt, - .encrypt = s2n_composite_cipher_aes_sha_encrypt, - .set_mac_write_key = s2n_composite_cipher_aes_sha256_set_mac_write_key, - .initial_hmac = s2n_composite_cipher_aes_sha_initial_hmac }, - .is_available = s2n_composite_cipher_aes128_sha256_available, - .init = s2n_composite_cipher_aes_sha_init, - .set_encryption_key = s2n_composite_cipher_aes128_sha256_set_encryption_key, - .set_decryption_key = s2n_composite_cipher_aes128_sha256_set_decryption_key, - .destroy_key = s2n_composite_cipher_aes_sha_destroy_key, -}; - -struct s2n_cipher s2n_aes256_sha256 = { - .key_material_size = 32, - .type = S2N_COMPOSITE, - .io.comp = { - .block_size = 16, - .record_iv_size = 16, - .mac_key_size = SHA256_DIGEST_LENGTH, - .decrypt = s2n_composite_cipher_aes_sha_decrypt, - .encrypt = s2n_composite_cipher_aes_sha_encrypt, - .set_mac_write_key = s2n_composite_cipher_aes_sha256_set_mac_write_key, - .initial_hmac = s2n_composite_cipher_aes_sha_initial_hmac }, - .is_available = s2n_composite_cipher_aes256_sha256_available, - .init = s2n_composite_cipher_aes_sha_init, - .set_encryption_key = s2n_composite_cipher_aes256_sha256_set_encryption_key, - .set_decryption_key = s2n_composite_cipher_aes256_sha256_set_decryption_key, - .destroy_key = s2n_composite_cipher_aes_sha_destroy_key, -}; +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/aes.h> +#include <openssl/evp.h> +#include <openssl/sha.h> + +#include "crypto/s2n_cipher.h" +#include "crypto/s2n_fips.h" +#include "crypto/s2n_openssl.h" + +#include "tls/s2n_crypto.h" + +#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. + */ +#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) +/* 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) +#define 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. + */ +#if S2N_OPENSSL_VERSION_AT_LEAST(1,0,2) +#define S2N_AES_SHA256_COMPOSITE_AVAILABLE +#endif + +#endif + +/* Silly accessors, but we avoid using version macro guards in multiple places */ +static const EVP_CIPHER *s2n_evp_aes_128_cbc_hmac_sha1(void) +{ + #if defined(S2N_AES_SHA1_COMPOSITE_AVAILABLE) + return EVP_aes_128_cbc_hmac_sha1(); + #else + return NULL; + #endif +} + +static const EVP_CIPHER *s2n_evp_aes_256_cbc_hmac_sha1(void) +{ + #if defined(S2N_AES_SHA1_COMPOSITE_AVAILABLE) + return EVP_aes_256_cbc_hmac_sha1(); + #else + return NULL; + #endif +} + +static const EVP_CIPHER *s2n_evp_aes_128_cbc_hmac_sha256(void) +{ + #if defined(S2N_AES_SHA256_COMPOSITE_AVAILABLE) + return EVP_aes_128_cbc_hmac_sha256(); + #else + return NULL; + #endif +} + +static const EVP_CIPHER *s2n_evp_aes_256_cbc_hmac_sha256(void) +{ + #if defined(S2N_AES_SHA256_COMPOSITE_AVAILABLE) + return EVP_aes_256_cbc_hmac_sha256(); + #else + return NULL; + #endif +} + +static uint8_t s2n_composite_cipher_aes128_sha_available(void) +{ + /* EVP_aes_128_cbc_hmac_sha1() returns NULL if the implementations aren't available. + * See https://github.com/openssl/openssl/blob/master/crypto/evp/e_aes_cbc_hmac_sha1.c#L952 + * + * Composite ciphers cannot be used when FIPS mode is set. Ciphers require the + * EVP_CIPH_FLAG_FIPS OpenSSL flag to be set for use when in FIPS mode, and composite + * ciphers cause OpenSSL errors due to the lack of the flag. + */ + return (!s2n_is_in_fips_mode() && s2n_evp_aes_128_cbc_hmac_sha1() ? 1 : 0); +} + +static uint8_t s2n_composite_cipher_aes256_sha_available(void) +{ + /* Composite ciphers cannot be used when FIPS mode is set. Ciphers require the + * EVP_CIPH_FLAG_FIPS OpenSSL flag to be set for use when in FIPS mode, and composite + * ciphers cause OpenSSL errors due to the lack of the flag. + */ + return (!s2n_is_in_fips_mode() && s2n_evp_aes_256_cbc_hmac_sha1() ? 1 : 0); +} + +static uint8_t s2n_composite_cipher_aes128_sha256_available(void) +{ + /* Composite ciphers cannot be used when FIPS mode is set. Ciphers require the + * EVP_CIPH_FLAG_FIPS OpenSSL flag to be set for use when in FIPS mode, and composite + * ciphers cause OpenSSL errors due to the lack of the flag. + */ + return (!s2n_is_in_fips_mode() && s2n_evp_aes_128_cbc_hmac_sha256() ? 1 : 0); +} + +static uint8_t s2n_composite_cipher_aes256_sha256_available(void) +{ + /* Composite ciphers cannot be used when FIPS mode is set. Ciphers require the + * EVP_CIPH_FLAG_FIPS OpenSSL flag to be set for use when in FIPS mode, and composite + * ciphers cause OpenSSL errors due to the lack of the flag. + */ + return (!s2n_is_in_fips_mode() && s2n_evp_aes_256_cbc_hmac_sha256() ? 1 : 0); +} + +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. + */ +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) + S2N_ERROR(S2N_ERR_NO_SUPPORTED_LIBCRYPTO_API); +#else + uint8_t ctrl_buf[S2N_TLS12_AAD_LEN]; + struct s2n_blob ctrl_blob = { .data = ctrl_buf, .size = S2N_TLS12_AAD_LEN }; + struct s2n_stuffer ctrl_stuffer = {0}; + GUARD(s2n_stuffer_init(&ctrl_stuffer, &ctrl_blob)); + + GUARD(s2n_stuffer_write_bytes(&ctrl_stuffer, sequence_number, S2N_TLS_SEQUENCE_NUM_LEN)); + GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, content_type)); + GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, protocol_version / 10)); + GUARD(s2n_stuffer_write_uint8(&ctrl_stuffer, protocol_version % 10)); + GUARD(s2n_stuffer_write_uint16(&ctrl_stuffer, payload_and_eiv_len)); + + /* This will unnecessarily mangle the input buffer, which is fine since it's temporary + * Return value will be length of digest, padding, and padding length byte. + * See https://github.com/openssl/openssl/blob/master/crypto/evp/e_aes_cbc_hmac_sha1.c#L814 + * and https://github.com/openssl/openssl/blob/4f0c475719defd7c051964ef9964cc6e5b3a63bf/ssl/record/ssl3_record.c#L743 + */ + int ctrl_ret = EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_TLS1_AAD, S2N_TLS12_AAD_LEN, ctrl_buf); + + S2N_ERROR_IF(ctrl_ret < 0, S2N_ERR_INITIAL_HMAC); + + *extra = ctrl_ret; + return 0; +#endif +} + +static int s2n_composite_cipher_aes_sha_encrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) +{ + eq_check(out->size, in->size); + + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); + GUARD_OSSL(EVP_Cipher(key->evp_cipher_ctx, out->data, in->data, in->size), S2N_ERR_ENCRYPT); + + return 0; +} + +static int s2n_composite_cipher_aes_sha_decrypt(struct s2n_session_key *key, struct s2n_blob *iv, struct s2n_blob *in, struct s2n_blob *out) +{ + eq_check(out->size, in->size); + + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, NULL, NULL, NULL, iv->data), S2N_ERR_KEY_INIT); + GUARD_OSSL(EVP_Cipher(key->evp_cipher_ctx, out->data, in->data, in->size), S2N_ERR_DECRYPT); + + return 0; +} + +static int s2n_composite_cipher_aes_sha_set_mac_write_key(struct s2n_session_key *key, uint8_t *mac_key, uint32_t mac_size) +{ + eq_check(mac_size, SHA_DIGEST_LENGTH); + + EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_SET_MAC_KEY, mac_size, mac_key); + + return 0; +} + +static int s2n_composite_cipher_aes_sha256_set_mac_write_key(struct s2n_session_key *key, uint8_t *mac_key, uint32_t mac_size) +{ + eq_check(mac_size, SHA256_DIGEST_LENGTH); + + EVP_CIPHER_CTX_ctrl(key->evp_cipher_ctx, EVP_CTRL_AEAD_SET_MAC_KEY, mac_size, mac_key); + + return 0; +} + + +static int s2n_composite_cipher_aes128_sha_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 16); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + EVP_EncryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_128_cbc_hmac_sha1(), NULL, in->data, NULL); + + return 0; +} + +static int s2n_composite_cipher_aes128_sha_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 16); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + EVP_DecryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_128_cbc_hmac_sha1(), NULL, in->data, NULL); + + return 0; +} + +static int s2n_composite_cipher_aes256_sha_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 32); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + EVP_EncryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_256_cbc_hmac_sha1(), NULL, in->data, NULL); + + return 0; +} + +static int s2n_composite_cipher_aes256_sha_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 32); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + EVP_DecryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_256_cbc_hmac_sha1(), NULL, in->data, NULL); + + return 0; +} + +static int s2n_composite_cipher_aes128_sha256_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 16); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + EVP_EncryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_128_cbc_hmac_sha256(), NULL, in->data, NULL); + + return 0; +} + +static int s2n_composite_cipher_aes128_sha256_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 16); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + EVP_DecryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_128_cbc_hmac_sha256(), NULL, in->data, NULL); + + return 0; +} + +static int s2n_composite_cipher_aes256_sha256_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 32); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + EVP_EncryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_256_cbc_hmac_sha256(), NULL, in->data, NULL); + + return 0; +} + +static int s2n_composite_cipher_aes256_sha256_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 32); + + EVP_CIPHER_CTX_set_padding(key->evp_cipher_ctx, EVP_CIPH_NO_PADDING); + EVP_DecryptInit_ex(key->evp_cipher_ctx, s2n_evp_aes_256_cbc_hmac_sha256(), NULL, in->data, NULL); + + return 0; +} + +static int s2n_composite_cipher_aes_sha_init(struct s2n_session_key *key) +{ + s2n_evp_ctx_init(key->evp_cipher_ctx); + + return 0; +} + +static int s2n_composite_cipher_aes_sha_destroy_key(struct s2n_session_key *key) +{ + EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); + + return 0; +} + +struct s2n_cipher s2n_aes128_sha = { + .key_material_size = 16, + .type = S2N_COMPOSITE, + .io.comp = { + .block_size = 16, + .record_iv_size = 16, + .mac_key_size = SHA_DIGEST_LENGTH, + .decrypt = s2n_composite_cipher_aes_sha_decrypt, + .encrypt = s2n_composite_cipher_aes_sha_encrypt, + .set_mac_write_key = s2n_composite_cipher_aes_sha_set_mac_write_key, + .initial_hmac = s2n_composite_cipher_aes_sha_initial_hmac }, + .is_available = s2n_composite_cipher_aes128_sha_available, + .init = s2n_composite_cipher_aes_sha_init, + .set_encryption_key = s2n_composite_cipher_aes128_sha_set_encryption_key, + .set_decryption_key = s2n_composite_cipher_aes128_sha_set_decryption_key, + .destroy_key = s2n_composite_cipher_aes_sha_destroy_key, +}; + +struct s2n_cipher s2n_aes256_sha = { + .key_material_size = 32, + .type = S2N_COMPOSITE, + .io.comp = { + .block_size = 16, + .record_iv_size = 16, + .mac_key_size = SHA_DIGEST_LENGTH, + .decrypt = s2n_composite_cipher_aes_sha_decrypt, + .encrypt = s2n_composite_cipher_aes_sha_encrypt, + .set_mac_write_key = s2n_composite_cipher_aes_sha_set_mac_write_key, + .initial_hmac = s2n_composite_cipher_aes_sha_initial_hmac }, + .is_available = s2n_composite_cipher_aes256_sha_available, + .init = s2n_composite_cipher_aes_sha_init, + .set_encryption_key = s2n_composite_cipher_aes256_sha_set_encryption_key, + .set_decryption_key = s2n_composite_cipher_aes256_sha_set_decryption_key, + .destroy_key = s2n_composite_cipher_aes_sha_destroy_key, +}; + +struct s2n_cipher s2n_aes128_sha256 = { + .key_material_size = 16, + .type = S2N_COMPOSITE, + .io.comp = { + .block_size = 16, + .record_iv_size = 16, + .mac_key_size = SHA256_DIGEST_LENGTH, + .decrypt = s2n_composite_cipher_aes_sha_decrypt, + .encrypt = s2n_composite_cipher_aes_sha_encrypt, + .set_mac_write_key = s2n_composite_cipher_aes_sha256_set_mac_write_key, + .initial_hmac = s2n_composite_cipher_aes_sha_initial_hmac }, + .is_available = s2n_composite_cipher_aes128_sha256_available, + .init = s2n_composite_cipher_aes_sha_init, + .set_encryption_key = s2n_composite_cipher_aes128_sha256_set_encryption_key, + .set_decryption_key = s2n_composite_cipher_aes128_sha256_set_decryption_key, + .destroy_key = s2n_composite_cipher_aes_sha_destroy_key, +}; + +struct s2n_cipher s2n_aes256_sha256 = { + .key_material_size = 32, + .type = S2N_COMPOSITE, + .io.comp = { + .block_size = 16, + .record_iv_size = 16, + .mac_key_size = SHA256_DIGEST_LENGTH, + .decrypt = s2n_composite_cipher_aes_sha_decrypt, + .encrypt = s2n_composite_cipher_aes_sha_encrypt, + .set_mac_write_key = s2n_composite_cipher_aes_sha256_set_mac_write_key, + .initial_hmac = s2n_composite_cipher_aes_sha_initial_hmac }, + .is_available = s2n_composite_cipher_aes256_sha256_available, + .init = s2n_composite_cipher_aes_sha_init, + .set_encryption_key = s2n_composite_cipher_aes256_sha256_set_encryption_key, + .set_decryption_key = s2n_composite_cipher_aes256_sha256_set_decryption_key, + .destroy_key = s2n_composite_cipher_aes_sha_destroy_key, +}; diff --git a/contrib/restricted/aws/s2n/crypto/s2n_crypto.h b/contrib/restricted/aws/s2n/crypto/s2n_crypto.h index 86e029c361..7f815038e6 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_crypto.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_crypto.h @@ -1,22 +1,22 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <openssl/aes.h> -#include <openssl/rc4.h> -#include <openssl/des.h> -#include <openssl/rsa.h> -#include <openssl/dh.h> +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <openssl/aes.h> +#include <openssl/rc4.h> +#include <openssl/des.h> +#include <openssl/rsa.h> +#include <openssl/dh.h> diff --git a/contrib/restricted/aws/s2n/crypto/s2n_dhe.c b/contrib/restricted/aws/s2n/crypto/s2n_dhe.c index 9304a4b46f..d755f94789 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_dhe.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_dhe.c @@ -1,339 +1,339 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include "crypto/s2n_dhe.h" - -#include <openssl/bn.h> -#include <openssl/dh.h> -#include <openssl/evp.h> -#include <stdint.h> - -#include "crypto/s2n_openssl.h" -#include "error/s2n_errno.h" -#include "stuffer/s2n_stuffer.h" -#include "utils/s2n_blob.h" -#include "utils/s2n_mem.h" -#include "utils/s2n_safety.h" - -#define S2N_MIN_DH_PRIME_SIZE_BYTES (2048 / 8) - -/* Caller is not responsible for freeing values returned by these accessors - * Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html - */ -static const BIGNUM *s2n_get_Ys_dh_param(struct s2n_dh_params *dh_params) -{ - const BIGNUM *Ys; - -/* DH made opaque in Openssl 1.1.0 */ -#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER) - DH_get0_key(dh_params->dh, &Ys, NULL); -#else - Ys = dh_params->dh->pub_key; -#endif - - return Ys; -} - -static const BIGNUM *s2n_get_p_dh_param(struct s2n_dh_params *dh_params) -{ - const BIGNUM *p; -#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER) - DH_get0_pqg(dh_params->dh, &p, NULL, NULL); -#else - p = dh_params->dh->p; -#endif - - return p; -} - -static const BIGNUM *s2n_get_g_dh_param(struct s2n_dh_params *dh_params) -{ - const BIGNUM *g; -#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER) - DH_get0_pqg(dh_params->dh, NULL, NULL, &g); -#else - g = dh_params->dh->g; -#endif - - return g; -} - -static int s2n_check_p_g_dh_params(struct s2n_dh_params *dh_params) -{ - notnull_check(dh_params); - notnull_check(dh_params->dh); - - const BIGNUM *p = s2n_get_p_dh_param(dh_params); - const BIGNUM *g = s2n_get_g_dh_param(dh_params); - - notnull_check(g); - notnull_check(p); - - S2N_ERROR_IF(DH_size(dh_params->dh) < S2N_MIN_DH_PRIME_SIZE_BYTES, S2N_ERR_DH_PARAMS_CREATE); - S2N_ERROR_IF(BN_is_zero(g), S2N_ERR_DH_PARAMS_CREATE); - S2N_ERROR_IF(BN_is_zero(p), S2N_ERR_DH_PARAMS_CREATE); - - return S2N_SUCCESS; -} - -static int s2n_check_pub_key_dh_params(struct s2n_dh_params *dh_params) -{ - const BIGNUM *pub_key = s2n_get_Ys_dh_param(dh_params); - - notnull_check(pub_key); - - S2N_ERROR_IF(BN_is_zero(pub_key), S2N_ERR_DH_PARAMS_CREATE); - - return S2N_SUCCESS; -} - -static int s2n_set_p_g_Ys_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *p, struct s2n_blob *g, - struct s2n_blob *Ys) -{ - ENSURE_POSIX(p->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW); - ENSURE_POSIX(g->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW); - ENSURE_POSIX(Ys->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW); - BIGNUM *bn_p = BN_bin2bn(( const unsigned char * )p->data, p->size, NULL); - BIGNUM *bn_g = BN_bin2bn(( const unsigned char * )g->data, g->size, NULL); - BIGNUM *bn_Ys = BN_bin2bn(( const unsigned char * )Ys->data, Ys->size, NULL); - -#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER) - /* Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html: - * values that have been passed in should not be freed directly after this function has been called - */ - GUARD_OSSL(DH_set0_pqg(dh_params->dh, bn_p, NULL, bn_g), S2N_ERR_DH_PARAMS_CREATE); - - /* Same as DH_set0_pqg */ - GUARD_OSSL(DH_set0_key(dh_params->dh, bn_Ys, NULL), S2N_ERR_DH_PARAMS_CREATE); -#else - dh_params->dh->p = bn_p; - dh_params->dh->g = bn_g; - dh_params->dh->pub_key = bn_Ys; -#endif - - return S2N_SUCCESS; -} - -int s2n_check_all_dh_params(struct s2n_dh_params *dh_params) -{ - GUARD(s2n_check_p_g_dh_params(dh_params)); - GUARD(s2n_check_pub_key_dh_params(dh_params)); - - return S2N_SUCCESS; -} - -int s2n_pkcs3_to_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *pkcs3) -{ - notnull_check(dh_params); - PRECONDITION_POSIX(s2n_blob_validate(pkcs3)); - - uint8_t *original_ptr = pkcs3->data; - dh_params->dh = d2i_DHparams(NULL, ( const unsigned char ** )( void * )&pkcs3->data, pkcs3->size); - GUARD(s2n_check_p_g_dh_params(dh_params)); - if (pkcs3->data - original_ptr != pkcs3->size) { - DH_free(dh_params->dh); - S2N_ERROR(S2N_ERR_INVALID_PKCS3); - } - pkcs3->data = original_ptr; - - /* Require at least 2048 bits for the DH size */ - if (DH_size(dh_params->dh) < S2N_MIN_DH_PRIME_SIZE_BYTES) { - DH_free(dh_params->dh); - S2N_ERROR(S2N_ERR_DH_TOO_SMALL); - } - - /* Check the generator and prime */ - GUARD(s2n_dh_params_check(dh_params)); - - return S2N_SUCCESS; -} - -int s2n_dh_p_g_Ys_to_dh_params(struct s2n_dh_params *server_dh_params, struct s2n_blob *p, struct s2n_blob *g, - struct s2n_blob *Ys) -{ - ENSURE_POSIX_REF(server_dh_params); - PRECONDITION_POSIX(s2n_blob_validate(p)); - PRECONDITION_POSIX(s2n_blob_validate(g)); - PRECONDITION_POSIX(s2n_blob_validate(Ys)); - - server_dh_params->dh = DH_new(); - ENSURE_POSIX(server_dh_params->dh != NULL, S2N_ERR_DH_PARAMS_CREATE); - - GUARD(s2n_set_p_g_Ys_dh_params(server_dh_params, p, g, Ys)); - GUARD(s2n_check_all_dh_params(server_dh_params)); - - return S2N_SUCCESS; -} - -int s2n_dh_params_to_p_g_Ys(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *out, struct s2n_blob *output) -{ - GUARD(s2n_check_all_dh_params(server_dh_params)); - PRECONDITION_POSIX(s2n_stuffer_validate(out)); - PRECONDITION_POSIX(s2n_blob_validate(output)); - - const BIGNUM *bn_p = s2n_get_p_dh_param(server_dh_params); - const BIGNUM *bn_g = s2n_get_g_dh_param(server_dh_params); - const BIGNUM *bn_Ys = s2n_get_Ys_dh_param(server_dh_params); - - uint16_t p_size = BN_num_bytes(bn_p); - uint16_t g_size = BN_num_bytes(bn_g); - uint16_t Ys_size = BN_num_bytes(bn_Ys); - uint8_t *p = NULL; - uint8_t *g = NULL; - uint8_t *Ys = NULL; - - output->data = s2n_stuffer_raw_write(out, 0); - notnull_check(output->data); - - GUARD(s2n_stuffer_write_uint16(out, p_size)); - p = s2n_stuffer_raw_write(out, p_size); - notnull_check(p); - ENSURE_POSIX(BN_bn2bin(bn_p, p) == p_size, S2N_ERR_DH_SERIALIZING); - - GUARD(s2n_stuffer_write_uint16(out, g_size)); - g = s2n_stuffer_raw_write(out, g_size); - notnull_check(g); - ENSURE_POSIX(BN_bn2bin(bn_g, g) == g_size, S2N_ERR_DH_SERIALIZING); - - GUARD(s2n_stuffer_write_uint16(out, Ys_size)); - Ys = s2n_stuffer_raw_write(out, Ys_size); - notnull_check(Ys); - ENSURE_POSIX(BN_bn2bin(bn_Ys, Ys) == Ys_size, S2N_ERR_DH_SERIALIZING); - - output->size = p_size + 2 + g_size + 2 + Ys_size + 2; - - return S2N_SUCCESS; -} - -int s2n_dh_compute_shared_secret_as_client(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_out, - struct s2n_blob *shared_key) -{ - struct s2n_dh_params client_params = { 0 }; - uint8_t * client_pub_key = NULL; - uint16_t client_pub_key_size = 0; - int shared_key_size = 0; - - GUARD(s2n_dh_params_check(server_dh_params)); - GUARD(s2n_dh_params_copy(server_dh_params, &client_params)); - GUARD(s2n_dh_generate_ephemeral_key(&client_params)); - GUARD(s2n_alloc(shared_key, DH_size(server_dh_params->dh))); - - const BIGNUM *client_pub_key_bn = s2n_get_Ys_dh_param(&client_params); - ENSURE_POSIX_REF(client_pub_key_bn); - client_pub_key_size = BN_num_bytes(client_pub_key_bn); - GUARD(s2n_stuffer_write_uint16(Yc_out, client_pub_key_size)); - client_pub_key = s2n_stuffer_raw_write(Yc_out, client_pub_key_size); - if (client_pub_key == NULL) { - GUARD(s2n_free(shared_key)); - GUARD(s2n_dh_params_free(&client_params)); - S2N_ERROR(S2N_ERR_DH_WRITING_PUBLIC_KEY); - } - - if (BN_bn2bin(client_pub_key_bn, client_pub_key) != client_pub_key_size) { - GUARD(s2n_free(shared_key)); - GUARD(s2n_dh_params_free(&client_params)); - S2N_ERROR(S2N_ERR_DH_COPYING_PUBLIC_KEY); - } - - /* server_dh_params already validated */ - const BIGNUM *server_pub_key_bn = s2n_get_Ys_dh_param(server_dh_params); - shared_key_size = DH_compute_key(shared_key->data, server_pub_key_bn, client_params.dh); - if (shared_key_size < 0) { - GUARD(s2n_free(shared_key)); - GUARD(s2n_dh_params_free(&client_params)); - S2N_ERROR(S2N_ERR_DH_SHARED_SECRET); - } - - shared_key->size = shared_key_size; - - GUARD(s2n_dh_params_free(&client_params)); - - return S2N_SUCCESS; -} - -int s2n_dh_compute_shared_secret_as_server(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_in, - struct s2n_blob *shared_key) -{ - uint16_t Yc_length = 0; - struct s2n_blob Yc = { 0 }; - int shared_key_size = 0; - BIGNUM * pub_key = NULL; - - GUARD(s2n_check_all_dh_params(server_dh_params)); - - GUARD(s2n_stuffer_read_uint16(Yc_in, &Yc_length)); - Yc.size = Yc_length; - Yc.data = s2n_stuffer_raw_read(Yc_in, Yc.size); - notnull_check(Yc.data); - - pub_key = BN_bin2bn(( const unsigned char * )Yc.data, Yc.size, NULL); - notnull_check(pub_key); - int server_dh_params_size = DH_size(server_dh_params->dh); - ENSURE_POSIX(server_dh_params_size <= INT32_MAX, S2N_ERR_INTEGER_OVERFLOW); - GUARD(s2n_alloc(shared_key, server_dh_params_size)); - - shared_key_size = DH_compute_key(shared_key->data, pub_key, server_dh_params->dh); - if (shared_key_size <= 0) { - BN_free(pub_key); - S2N_ERROR(S2N_ERR_DH_SHARED_SECRET); - } - - shared_key->size = shared_key_size; - - BN_free(pub_key); - - return S2N_SUCCESS; -} - -int s2n_dh_params_check(struct s2n_dh_params *dh_params) -{ - notnull_check(dh_params); - notnull_check(dh_params->dh); - int codes = 0; - - GUARD_OSSL(DH_check(dh_params->dh, &codes), S2N_ERR_DH_PARAMETER_CHECK); - ENSURE_POSIX(codes == 0, S2N_ERR_DH_PARAMETER_CHECK); - - return S2N_SUCCESS; -} - -int s2n_dh_params_copy(struct s2n_dh_params *from, struct s2n_dh_params *to) -{ - GUARD(s2n_check_p_g_dh_params(from)); - notnull_check(to); - - to->dh = DHparams_dup(from->dh); - ENSURE_POSIX(to->dh != NULL, S2N_ERR_DH_COPYING_PARAMETERS); - - return S2N_SUCCESS; -} - -int s2n_dh_generate_ephemeral_key(struct s2n_dh_params *dh_params) -{ - GUARD(s2n_check_p_g_dh_params(dh_params)); - - GUARD_OSSL(DH_generate_key(dh_params->dh), S2N_ERR_DH_GENERATING_PARAMETERS); - - return S2N_SUCCESS; -} - -int s2n_dh_params_free(struct s2n_dh_params *dh_params) -{ - notnull_check(dh_params); - DH_free(dh_params->dh); - dh_params->dh = NULL; - - return S2N_SUCCESS; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include "crypto/s2n_dhe.h" + +#include <openssl/bn.h> +#include <openssl/dh.h> +#include <openssl/evp.h> +#include <stdint.h> + +#include "crypto/s2n_openssl.h" +#include "error/s2n_errno.h" +#include "stuffer/s2n_stuffer.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_mem.h" +#include "utils/s2n_safety.h" + +#define S2N_MIN_DH_PRIME_SIZE_BYTES (2048 / 8) + +/* Caller is not responsible for freeing values returned by these accessors + * Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html + */ +static const BIGNUM *s2n_get_Ys_dh_param(struct s2n_dh_params *dh_params) +{ + const BIGNUM *Ys; + +/* DH made opaque in Openssl 1.1.0 */ +#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER) + DH_get0_key(dh_params->dh, &Ys, NULL); +#else + Ys = dh_params->dh->pub_key; +#endif + + return Ys; +} + +static const BIGNUM *s2n_get_p_dh_param(struct s2n_dh_params *dh_params) +{ + const BIGNUM *p; +#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER) + DH_get0_pqg(dh_params->dh, &p, NULL, NULL); +#else + p = dh_params->dh->p; +#endif + + return p; +} + +static const BIGNUM *s2n_get_g_dh_param(struct s2n_dh_params *dh_params) +{ + const BIGNUM *g; +#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER) + DH_get0_pqg(dh_params->dh, NULL, NULL, &g); +#else + g = dh_params->dh->g; +#endif + + return g; +} + +static int s2n_check_p_g_dh_params(struct s2n_dh_params *dh_params) +{ + notnull_check(dh_params); + notnull_check(dh_params->dh); + + const BIGNUM *p = s2n_get_p_dh_param(dh_params); + const BIGNUM *g = s2n_get_g_dh_param(dh_params); + + notnull_check(g); + notnull_check(p); + + S2N_ERROR_IF(DH_size(dh_params->dh) < S2N_MIN_DH_PRIME_SIZE_BYTES, S2N_ERR_DH_PARAMS_CREATE); + S2N_ERROR_IF(BN_is_zero(g), S2N_ERR_DH_PARAMS_CREATE); + S2N_ERROR_IF(BN_is_zero(p), S2N_ERR_DH_PARAMS_CREATE); + + return S2N_SUCCESS; +} + +static int s2n_check_pub_key_dh_params(struct s2n_dh_params *dh_params) +{ + const BIGNUM *pub_key = s2n_get_Ys_dh_param(dh_params); + + notnull_check(pub_key); + + S2N_ERROR_IF(BN_is_zero(pub_key), S2N_ERR_DH_PARAMS_CREATE); + + return S2N_SUCCESS; +} + +static int s2n_set_p_g_Ys_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *p, struct s2n_blob *g, + struct s2n_blob *Ys) +{ + ENSURE_POSIX(p->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW); + ENSURE_POSIX(g->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW); + ENSURE_POSIX(Ys->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW); + BIGNUM *bn_p = BN_bin2bn(( const unsigned char * )p->data, p->size, NULL); + BIGNUM *bn_g = BN_bin2bn(( const unsigned char * )g->data, g->size, NULL); + BIGNUM *bn_Ys = BN_bin2bn(( const unsigned char * )Ys->data, Ys->size, NULL); + +#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER) + /* Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html: + * values that have been passed in should not be freed directly after this function has been called + */ + GUARD_OSSL(DH_set0_pqg(dh_params->dh, bn_p, NULL, bn_g), S2N_ERR_DH_PARAMS_CREATE); + + /* Same as DH_set0_pqg */ + GUARD_OSSL(DH_set0_key(dh_params->dh, bn_Ys, NULL), S2N_ERR_DH_PARAMS_CREATE); +#else + dh_params->dh->p = bn_p; + dh_params->dh->g = bn_g; + dh_params->dh->pub_key = bn_Ys; +#endif + + return S2N_SUCCESS; +} + +int s2n_check_all_dh_params(struct s2n_dh_params *dh_params) +{ + GUARD(s2n_check_p_g_dh_params(dh_params)); + GUARD(s2n_check_pub_key_dh_params(dh_params)); + + return S2N_SUCCESS; +} + +int s2n_pkcs3_to_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *pkcs3) +{ + notnull_check(dh_params); + PRECONDITION_POSIX(s2n_blob_validate(pkcs3)); + + uint8_t *original_ptr = pkcs3->data; + dh_params->dh = d2i_DHparams(NULL, ( const unsigned char ** )( void * )&pkcs3->data, pkcs3->size); + GUARD(s2n_check_p_g_dh_params(dh_params)); + if (pkcs3->data - original_ptr != pkcs3->size) { + DH_free(dh_params->dh); + S2N_ERROR(S2N_ERR_INVALID_PKCS3); + } + pkcs3->data = original_ptr; + + /* Require at least 2048 bits for the DH size */ + if (DH_size(dh_params->dh) < S2N_MIN_DH_PRIME_SIZE_BYTES) { + DH_free(dh_params->dh); + S2N_ERROR(S2N_ERR_DH_TOO_SMALL); + } + + /* Check the generator and prime */ + GUARD(s2n_dh_params_check(dh_params)); + + return S2N_SUCCESS; +} + +int s2n_dh_p_g_Ys_to_dh_params(struct s2n_dh_params *server_dh_params, struct s2n_blob *p, struct s2n_blob *g, + struct s2n_blob *Ys) +{ + ENSURE_POSIX_REF(server_dh_params); + PRECONDITION_POSIX(s2n_blob_validate(p)); + PRECONDITION_POSIX(s2n_blob_validate(g)); + PRECONDITION_POSIX(s2n_blob_validate(Ys)); + + server_dh_params->dh = DH_new(); + ENSURE_POSIX(server_dh_params->dh != NULL, S2N_ERR_DH_PARAMS_CREATE); + + GUARD(s2n_set_p_g_Ys_dh_params(server_dh_params, p, g, Ys)); + GUARD(s2n_check_all_dh_params(server_dh_params)); + + return S2N_SUCCESS; +} + +int s2n_dh_params_to_p_g_Ys(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *out, struct s2n_blob *output) +{ + GUARD(s2n_check_all_dh_params(server_dh_params)); + PRECONDITION_POSIX(s2n_stuffer_validate(out)); + PRECONDITION_POSIX(s2n_blob_validate(output)); + + const BIGNUM *bn_p = s2n_get_p_dh_param(server_dh_params); + const BIGNUM *bn_g = s2n_get_g_dh_param(server_dh_params); + const BIGNUM *bn_Ys = s2n_get_Ys_dh_param(server_dh_params); + + uint16_t p_size = BN_num_bytes(bn_p); + uint16_t g_size = BN_num_bytes(bn_g); + uint16_t Ys_size = BN_num_bytes(bn_Ys); + uint8_t *p = NULL; + uint8_t *g = NULL; + uint8_t *Ys = NULL; + + output->data = s2n_stuffer_raw_write(out, 0); + notnull_check(output->data); + + GUARD(s2n_stuffer_write_uint16(out, p_size)); + p = s2n_stuffer_raw_write(out, p_size); + notnull_check(p); + ENSURE_POSIX(BN_bn2bin(bn_p, p) == p_size, S2N_ERR_DH_SERIALIZING); + + GUARD(s2n_stuffer_write_uint16(out, g_size)); + g = s2n_stuffer_raw_write(out, g_size); + notnull_check(g); + ENSURE_POSIX(BN_bn2bin(bn_g, g) == g_size, S2N_ERR_DH_SERIALIZING); + + GUARD(s2n_stuffer_write_uint16(out, Ys_size)); + Ys = s2n_stuffer_raw_write(out, Ys_size); + notnull_check(Ys); + ENSURE_POSIX(BN_bn2bin(bn_Ys, Ys) == Ys_size, S2N_ERR_DH_SERIALIZING); + + output->size = p_size + 2 + g_size + 2 + Ys_size + 2; + + return S2N_SUCCESS; +} + +int s2n_dh_compute_shared_secret_as_client(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_out, + struct s2n_blob *shared_key) +{ + struct s2n_dh_params client_params = { 0 }; + uint8_t * client_pub_key = NULL; + uint16_t client_pub_key_size = 0; + int shared_key_size = 0; + + GUARD(s2n_dh_params_check(server_dh_params)); + GUARD(s2n_dh_params_copy(server_dh_params, &client_params)); + GUARD(s2n_dh_generate_ephemeral_key(&client_params)); + GUARD(s2n_alloc(shared_key, DH_size(server_dh_params->dh))); + + const BIGNUM *client_pub_key_bn = s2n_get_Ys_dh_param(&client_params); + ENSURE_POSIX_REF(client_pub_key_bn); + client_pub_key_size = BN_num_bytes(client_pub_key_bn); + GUARD(s2n_stuffer_write_uint16(Yc_out, client_pub_key_size)); + client_pub_key = s2n_stuffer_raw_write(Yc_out, client_pub_key_size); + if (client_pub_key == NULL) { + GUARD(s2n_free(shared_key)); + GUARD(s2n_dh_params_free(&client_params)); + S2N_ERROR(S2N_ERR_DH_WRITING_PUBLIC_KEY); + } + + if (BN_bn2bin(client_pub_key_bn, client_pub_key) != client_pub_key_size) { + GUARD(s2n_free(shared_key)); + GUARD(s2n_dh_params_free(&client_params)); + S2N_ERROR(S2N_ERR_DH_COPYING_PUBLIC_KEY); + } + + /* server_dh_params already validated */ + const BIGNUM *server_pub_key_bn = s2n_get_Ys_dh_param(server_dh_params); + shared_key_size = DH_compute_key(shared_key->data, server_pub_key_bn, client_params.dh); + if (shared_key_size < 0) { + GUARD(s2n_free(shared_key)); + GUARD(s2n_dh_params_free(&client_params)); + S2N_ERROR(S2N_ERR_DH_SHARED_SECRET); + } + + shared_key->size = shared_key_size; + + GUARD(s2n_dh_params_free(&client_params)); + + return S2N_SUCCESS; +} + +int s2n_dh_compute_shared_secret_as_server(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_in, + struct s2n_blob *shared_key) +{ + uint16_t Yc_length = 0; + struct s2n_blob Yc = { 0 }; + int shared_key_size = 0; + BIGNUM * pub_key = NULL; + + GUARD(s2n_check_all_dh_params(server_dh_params)); + + GUARD(s2n_stuffer_read_uint16(Yc_in, &Yc_length)); + Yc.size = Yc_length; + Yc.data = s2n_stuffer_raw_read(Yc_in, Yc.size); + notnull_check(Yc.data); + + pub_key = BN_bin2bn(( const unsigned char * )Yc.data, Yc.size, NULL); + notnull_check(pub_key); + int server_dh_params_size = DH_size(server_dh_params->dh); + ENSURE_POSIX(server_dh_params_size <= INT32_MAX, S2N_ERR_INTEGER_OVERFLOW); + GUARD(s2n_alloc(shared_key, server_dh_params_size)); + + shared_key_size = DH_compute_key(shared_key->data, pub_key, server_dh_params->dh); + if (shared_key_size <= 0) { + BN_free(pub_key); + S2N_ERROR(S2N_ERR_DH_SHARED_SECRET); + } + + shared_key->size = shared_key_size; + + BN_free(pub_key); + + return S2N_SUCCESS; +} + +int s2n_dh_params_check(struct s2n_dh_params *dh_params) +{ + notnull_check(dh_params); + notnull_check(dh_params->dh); + int codes = 0; + + GUARD_OSSL(DH_check(dh_params->dh, &codes), S2N_ERR_DH_PARAMETER_CHECK); + ENSURE_POSIX(codes == 0, S2N_ERR_DH_PARAMETER_CHECK); + + return S2N_SUCCESS; +} + +int s2n_dh_params_copy(struct s2n_dh_params *from, struct s2n_dh_params *to) +{ + GUARD(s2n_check_p_g_dh_params(from)); + notnull_check(to); + + to->dh = DHparams_dup(from->dh); + ENSURE_POSIX(to->dh != NULL, S2N_ERR_DH_COPYING_PARAMETERS); + + return S2N_SUCCESS; +} + +int s2n_dh_generate_ephemeral_key(struct s2n_dh_params *dh_params) +{ + GUARD(s2n_check_p_g_dh_params(dh_params)); + + GUARD_OSSL(DH_generate_key(dh_params->dh), S2N_ERR_DH_GENERATING_PARAMETERS); + + return S2N_SUCCESS; +} + +int s2n_dh_params_free(struct s2n_dh_params *dh_params) +{ + notnull_check(dh_params); + DH_free(dh_params->dh); + dh_params->dh = NULL; + + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_dhe.h b/contrib/restricted/aws/s2n/crypto/s2n_dhe.h index f9e004e5e5..483462a413 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_dhe.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_dhe.h @@ -1,36 +1,36 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <openssl/dh.h> - -#include "stuffer/s2n_stuffer.h" - -#include "utils/s2n_blob.h" - -struct s2n_dh_params { - DH *dh; -}; - -extern int s2n_pkcs3_to_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *pkcs3); -extern int s2n_dh_p_g_Ys_to_dh_params(struct s2n_dh_params *server_dh_params, struct s2n_blob *p, struct s2n_blob *g, struct s2n_blob *ys); -extern int s2n_dh_params_to_p_g_Ys(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *out, struct s2n_blob *output); -extern int s2n_dh_compute_shared_secret_as_server(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key); -extern int s2n_dh_compute_shared_secret_as_client(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key); -extern int s2n_dh_params_copy(struct s2n_dh_params *from, struct s2n_dh_params *to); -extern int s2n_dh_params_check(struct s2n_dh_params *dh_params); -extern int s2n_dh_generate_ephemeral_key(struct s2n_dh_params *dh_params); -extern int s2n_dh_params_free(struct s2n_dh_params *dh_params); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <openssl/dh.h> + +#include "stuffer/s2n_stuffer.h" + +#include "utils/s2n_blob.h" + +struct s2n_dh_params { + DH *dh; +}; + +extern int s2n_pkcs3_to_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *pkcs3); +extern int s2n_dh_p_g_Ys_to_dh_params(struct s2n_dh_params *server_dh_params, struct s2n_blob *p, struct s2n_blob *g, struct s2n_blob *ys); +extern int s2n_dh_params_to_p_g_Ys(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *out, struct s2n_blob *output); +extern int s2n_dh_compute_shared_secret_as_server(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key); +extern int s2n_dh_compute_shared_secret_as_client(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key); +extern int s2n_dh_params_copy(struct s2n_dh_params *from, struct s2n_dh_params *to); +extern int s2n_dh_params_check(struct s2n_dh_params *dh_params); +extern int s2n_dh_generate_ephemeral_key(struct s2n_dh_params *dh_params); +extern int s2n_dh_params_free(struct s2n_dh_params *dh_params); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_drbg.c b/contrib/restricted/aws/s2n/crypto/s2n_drbg.c index abcd819e04..bd1e78cc47 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_drbg.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_drbg.c @@ -1,228 +1,228 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <sys/param.h> - -#include <openssl/evp.h> - -#include "crypto/s2n_drbg.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_random.h" -#include "utils/s2n_blob.h" - -#define s2n_drbg_key_size(drgb) EVP_CIPHER_CTX_key_length((drbg)->ctx) -#define s2n_drbg_seed_size(drgb) (S2N_DRBG_BLOCK_SIZE + s2n_drbg_key_size(drgb)) - -/* This function is the same as s2n_increment_sequence_number - but it does not check for overflow, since overflow is - acceptable in DRBG */ -int s2n_increment_drbg_counter(struct s2n_blob *counter) -{ - for (int i = counter->size - 1; i >= 0; i--) { - counter->data[i] += 1; - if (counter->data[i]) { - break; - } - - /* seq[i] wrapped, so let it carry */ - } - return 0; -} - -static int s2n_drbg_block_encrypt(EVP_CIPHER_CTX * ctx, uint8_t in[S2N_DRBG_BLOCK_SIZE], uint8_t out[S2N_DRBG_BLOCK_SIZE]) -{ - notnull_check(ctx); - int len = S2N_DRBG_BLOCK_SIZE; - GUARD_OSSL(EVP_EncryptUpdate(ctx, out, &len, in, S2N_DRBG_BLOCK_SIZE), S2N_ERR_DRBG); - eq_check(len, S2N_DRBG_BLOCK_SIZE); - - return 0; -} - -static int s2n_drbg_bits(struct s2n_drbg *drbg, struct s2n_blob *out) -{ - notnull_check(drbg); - notnull_check(drbg->ctx); - notnull_check(out); - - struct s2n_blob value = {0}; - GUARD(s2n_blob_init(&value, drbg->v, sizeof(drbg->v))); - int block_aligned_size = out->size - (out->size % S2N_DRBG_BLOCK_SIZE); - - /* Per NIST SP800-90A 10.2.1.2: */ - for (int i = 0; i < block_aligned_size; i += S2N_DRBG_BLOCK_SIZE) { - GUARD(s2n_increment_drbg_counter(&value)); - GUARD(s2n_drbg_block_encrypt(drbg->ctx, drbg->v, out->data + i)); - drbg->bytes_used += S2N_DRBG_BLOCK_SIZE; - } - - if (out->size <= block_aligned_size) { - return 0; - } - - uint8_t spare_block[S2N_DRBG_BLOCK_SIZE]; - GUARD(s2n_increment_drbg_counter(&value)); - GUARD(s2n_drbg_block_encrypt(drbg->ctx, drbg->v, spare_block)); - drbg->bytes_used += S2N_DRBG_BLOCK_SIZE; - - memcpy_check(out->data + block_aligned_size, spare_block, out->size - block_aligned_size); - - return 0; -} - -static int s2n_drbg_update(struct s2n_drbg *drbg, struct s2n_blob *provided_data) -{ - notnull_check(drbg); - notnull_check(drbg->ctx); - - s2n_stack_blob(temp_blob, s2n_drbg_seed_size(drgb), S2N_DRBG_MAX_SEED_SIZE); - - eq_check(provided_data->size, s2n_drbg_seed_size(drbg)); - - GUARD(s2n_drbg_bits(drbg, &temp_blob)); - - /* XOR in the provided data */ - for (int i = 0; i < provided_data->size; i++) { - temp_blob.data[i] ^= provided_data->data[i]; - } - - /* Update the key and value */ - GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, NULL, NULL, temp_blob.data, NULL), S2N_ERR_DRBG); - - memcpy_check(drbg->v, temp_blob.data + s2n_drbg_key_size(drbg), S2N_DRBG_BLOCK_SIZE); - - return 0; -} - -static int s2n_drbg_mix_in_entropy(struct s2n_drbg *drbg, struct s2n_blob *entropy, struct s2n_blob *ps) -{ - notnull_check(drbg); - notnull_check(drbg->ctx); - notnull_check(entropy); - - gte_check(entropy->size, ps->size); - - for (int i = 0; i < ps->size; i++) { - entropy->data[i] ^= ps->data[i]; - } - - GUARD(s2n_drbg_update(drbg, entropy)); - - return 0; -} - -static int s2n_drbg_seed(struct s2n_drbg *drbg, struct s2n_blob *ps) -{ - s2n_stack_blob(blob, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE); - - GUARD_AS_POSIX(s2n_get_seed_entropy(&blob)); - GUARD(s2n_drbg_mix_in_entropy(drbg, &blob, ps)); - - drbg->bytes_used = 0; - - return 0; -} - -static int s2n_drbg_mix(struct s2n_drbg *drbg, struct s2n_blob *ps) -{ - s2n_stack_blob(blob, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE); - - GUARD_AS_POSIX(s2n_get_mix_entropy(&blob)); - GUARD(s2n_drbg_mix_in_entropy(drbg, &blob, ps)); - - drbg->mixes += 1; - - return 0; -} - -int s2n_drbg_instantiate(struct s2n_drbg *drbg, struct s2n_blob *personalization_string, const s2n_drbg_mode mode) -{ - notnull_check(drbg); - - drbg->ctx = EVP_CIPHER_CTX_new(); - S2N_ERROR_IF(!drbg->ctx, S2N_ERR_DRBG); - - s2n_evp_ctx_init(drbg->ctx); - - switch(mode) { - case S2N_AES_128_CTR_NO_DF_PR: - GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, EVP_aes_128_ecb(), NULL, NULL, NULL), S2N_ERR_DRBG); - break; - case S2N_AES_256_CTR_NO_DF_PR: - GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, EVP_aes_256_ecb(), NULL, NULL, NULL), S2N_ERR_DRBG); - break; - default: - S2N_ERROR(S2N_ERR_DRBG); - } - - lte_check(s2n_drbg_key_size(drbg), S2N_DRBG_MAX_KEY_SIZE); - lte_check(s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE); - - static const uint8_t zero_key[S2N_DRBG_MAX_KEY_SIZE] = {0}; - - /* Start off with zeroed data, per 10.2.1.3.1 item 4 and 5 */ - memset(drbg->v, 0, sizeof(drbg->v)); - GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, NULL, NULL, zero_key, NULL), S2N_ERR_DRBG); - - /* Copy the personalization string */ - s2n_stack_blob(ps, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE); - GUARD(s2n_blob_zero(&ps)); - - memcpy_check(ps.data, personalization_string->data, MIN(ps.size, personalization_string->size)); - - /* Seed the DRBG */ - GUARD(s2n_drbg_seed(drbg, &ps)); - - return 0; -} - -int s2n_drbg_generate(struct s2n_drbg *drbg, struct s2n_blob *blob) -{ - notnull_check(drbg); - notnull_check(drbg->ctx); - s2n_stack_blob(zeros, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE); - - S2N_ERROR_IF(blob->size > S2N_DRBG_GENERATE_LIMIT, S2N_ERR_DRBG_REQUEST_SIZE); - - /* Always mix in additional entropy, for prediction resistance */ - GUARD(s2n_drbg_mix(drbg, &zeros)); - GUARD(s2n_drbg_bits(drbg, blob)); - GUARD(s2n_drbg_update(drbg, &zeros)); - - return 0; -} - -int s2n_drbg_wipe(struct s2n_drbg *drbg) -{ - notnull_check(drbg); - if (drbg->ctx) { - GUARD_OSSL(EVP_CIPHER_CTX_cleanup(drbg->ctx), S2N_ERR_DRBG); - - EVP_CIPHER_CTX_free(drbg->ctx); - drbg->ctx = NULL; - } - - *drbg = (struct s2n_drbg) {0}; - return 0; -} - -int s2n_drbg_bytes_used(struct s2n_drbg *drbg, uint64_t *bytes_used) -{ - notnull_check(drbg); - notnull_check(bytes_used); - *bytes_used = drbg->bytes_used; - return 0; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <sys/param.h> + +#include <openssl/evp.h> + +#include "crypto/s2n_drbg.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_random.h" +#include "utils/s2n_blob.h" + +#define s2n_drbg_key_size(drgb) EVP_CIPHER_CTX_key_length((drbg)->ctx) +#define s2n_drbg_seed_size(drgb) (S2N_DRBG_BLOCK_SIZE + s2n_drbg_key_size(drgb)) + +/* This function is the same as s2n_increment_sequence_number + but it does not check for overflow, since overflow is + acceptable in DRBG */ +int s2n_increment_drbg_counter(struct s2n_blob *counter) +{ + for (int i = counter->size - 1; i >= 0; i--) { + counter->data[i] += 1; + if (counter->data[i]) { + break; + } + + /* seq[i] wrapped, so let it carry */ + } + return 0; +} + +static int s2n_drbg_block_encrypt(EVP_CIPHER_CTX * ctx, uint8_t in[S2N_DRBG_BLOCK_SIZE], uint8_t out[S2N_DRBG_BLOCK_SIZE]) +{ + notnull_check(ctx); + int len = S2N_DRBG_BLOCK_SIZE; + GUARD_OSSL(EVP_EncryptUpdate(ctx, out, &len, in, S2N_DRBG_BLOCK_SIZE), S2N_ERR_DRBG); + eq_check(len, S2N_DRBG_BLOCK_SIZE); + + return 0; +} + +static int s2n_drbg_bits(struct s2n_drbg *drbg, struct s2n_blob *out) +{ + notnull_check(drbg); + notnull_check(drbg->ctx); + notnull_check(out); + + struct s2n_blob value = {0}; + GUARD(s2n_blob_init(&value, drbg->v, sizeof(drbg->v))); + int block_aligned_size = out->size - (out->size % S2N_DRBG_BLOCK_SIZE); + + /* Per NIST SP800-90A 10.2.1.2: */ + for (int i = 0; i < block_aligned_size; i += S2N_DRBG_BLOCK_SIZE) { + GUARD(s2n_increment_drbg_counter(&value)); + GUARD(s2n_drbg_block_encrypt(drbg->ctx, drbg->v, out->data + i)); + drbg->bytes_used += S2N_DRBG_BLOCK_SIZE; + } + + if (out->size <= block_aligned_size) { + return 0; + } + + uint8_t spare_block[S2N_DRBG_BLOCK_SIZE]; + GUARD(s2n_increment_drbg_counter(&value)); + GUARD(s2n_drbg_block_encrypt(drbg->ctx, drbg->v, spare_block)); + drbg->bytes_used += S2N_DRBG_BLOCK_SIZE; + + memcpy_check(out->data + block_aligned_size, spare_block, out->size - block_aligned_size); + + return 0; +} + +static int s2n_drbg_update(struct s2n_drbg *drbg, struct s2n_blob *provided_data) +{ + notnull_check(drbg); + notnull_check(drbg->ctx); + + s2n_stack_blob(temp_blob, s2n_drbg_seed_size(drgb), S2N_DRBG_MAX_SEED_SIZE); + + eq_check(provided_data->size, s2n_drbg_seed_size(drbg)); + + GUARD(s2n_drbg_bits(drbg, &temp_blob)); + + /* XOR in the provided data */ + for (int i = 0; i < provided_data->size; i++) { + temp_blob.data[i] ^= provided_data->data[i]; + } + + /* Update the key and value */ + GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, NULL, NULL, temp_blob.data, NULL), S2N_ERR_DRBG); + + memcpy_check(drbg->v, temp_blob.data + s2n_drbg_key_size(drbg), S2N_DRBG_BLOCK_SIZE); + + return 0; +} + +static int s2n_drbg_mix_in_entropy(struct s2n_drbg *drbg, struct s2n_blob *entropy, struct s2n_blob *ps) +{ + notnull_check(drbg); + notnull_check(drbg->ctx); + notnull_check(entropy); + + gte_check(entropy->size, ps->size); + + for (int i = 0; i < ps->size; i++) { + entropy->data[i] ^= ps->data[i]; + } + + GUARD(s2n_drbg_update(drbg, entropy)); + + return 0; +} + +static int s2n_drbg_seed(struct s2n_drbg *drbg, struct s2n_blob *ps) +{ + s2n_stack_blob(blob, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE); + + GUARD_AS_POSIX(s2n_get_seed_entropy(&blob)); + GUARD(s2n_drbg_mix_in_entropy(drbg, &blob, ps)); + + drbg->bytes_used = 0; + + return 0; +} + +static int s2n_drbg_mix(struct s2n_drbg *drbg, struct s2n_blob *ps) +{ + s2n_stack_blob(blob, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE); + + GUARD_AS_POSIX(s2n_get_mix_entropy(&blob)); + GUARD(s2n_drbg_mix_in_entropy(drbg, &blob, ps)); + + drbg->mixes += 1; + + return 0; +} + +int s2n_drbg_instantiate(struct s2n_drbg *drbg, struct s2n_blob *personalization_string, const s2n_drbg_mode mode) +{ + notnull_check(drbg); + + drbg->ctx = EVP_CIPHER_CTX_new(); + S2N_ERROR_IF(!drbg->ctx, S2N_ERR_DRBG); + + s2n_evp_ctx_init(drbg->ctx); + + switch(mode) { + case S2N_AES_128_CTR_NO_DF_PR: + GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, EVP_aes_128_ecb(), NULL, NULL, NULL), S2N_ERR_DRBG); + break; + case S2N_AES_256_CTR_NO_DF_PR: + GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, EVP_aes_256_ecb(), NULL, NULL, NULL), S2N_ERR_DRBG); + break; + default: + S2N_ERROR(S2N_ERR_DRBG); + } + + lte_check(s2n_drbg_key_size(drbg), S2N_DRBG_MAX_KEY_SIZE); + lte_check(s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE); + + static const uint8_t zero_key[S2N_DRBG_MAX_KEY_SIZE] = {0}; + + /* Start off with zeroed data, per 10.2.1.3.1 item 4 and 5 */ + memset(drbg->v, 0, sizeof(drbg->v)); + GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, NULL, NULL, zero_key, NULL), S2N_ERR_DRBG); + + /* Copy the personalization string */ + s2n_stack_blob(ps, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE); + GUARD(s2n_blob_zero(&ps)); + + memcpy_check(ps.data, personalization_string->data, MIN(ps.size, personalization_string->size)); + + /* Seed the DRBG */ + GUARD(s2n_drbg_seed(drbg, &ps)); + + return 0; +} + +int s2n_drbg_generate(struct s2n_drbg *drbg, struct s2n_blob *blob) +{ + notnull_check(drbg); + notnull_check(drbg->ctx); + s2n_stack_blob(zeros, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE); + + S2N_ERROR_IF(blob->size > S2N_DRBG_GENERATE_LIMIT, S2N_ERR_DRBG_REQUEST_SIZE); + + /* Always mix in additional entropy, for prediction resistance */ + GUARD(s2n_drbg_mix(drbg, &zeros)); + GUARD(s2n_drbg_bits(drbg, blob)); + GUARD(s2n_drbg_update(drbg, &zeros)); + + return 0; +} + +int s2n_drbg_wipe(struct s2n_drbg *drbg) +{ + notnull_check(drbg); + if (drbg->ctx) { + GUARD_OSSL(EVP_CIPHER_CTX_cleanup(drbg->ctx), S2N_ERR_DRBG); + + EVP_CIPHER_CTX_free(drbg->ctx); + drbg->ctx = NULL; + } + + *drbg = (struct s2n_drbg) {0}; + return 0; +} + +int s2n_drbg_bytes_used(struct s2n_drbg *drbg, uint64_t *bytes_used) +{ + notnull_check(drbg); + notnull_check(bytes_used); + *bytes_used = drbg->bytes_used; + return 0; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_drbg.h b/contrib/restricted/aws/s2n/crypto/s2n_drbg.h index 58562d17eb..dbd72ad8ff 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_drbg.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_drbg.h @@ -1,66 +1,66 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <openssl/evp.h> - -#include "crypto/s2n_hash.h" -#include "utils/s2n_blob.h" -#include "utils/s2n_result.h" - -#define S2N_DRBG_BLOCK_SIZE 16 -#define S2N_DRBG_MAX_KEY_SIZE 32 -#define S2N_DRBG_MAX_SEED_SIZE (S2N_DRBG_BLOCK_SIZE + S2N_DRBG_MAX_KEY_SIZE) - -/* The maximum size of any one request: from NIST SP800-90A 10.2.1 Table 3 */ -#define S2N_DRBG_GENERATE_LIMIT 8192 - -/* We reseed after 2^35 bytes have been generated: from NIST SP800-90A 10.2.1 Table 3 */ -#define S2N_DRBG_RESEED_LIMIT 34359738368 - -struct s2n_drbg { - /* Track how many bytes have been used */ - uint64_t bytes_used; - - EVP_CIPHER_CTX *ctx; - - /* The current DRBG 'value' */ - uint8_t v[S2N_DRBG_BLOCK_SIZE]; - - /* Used only by the unit tests: how many times has entropy been mixed in */ - uint64_t mixes; -}; - -/* - * S2N_AES_128_CTR_NO_DF_PR is a deterministic random bit generator using AES 128 in counter mode (AES_128_CTR). It does not - * use a derivation function (NO_DF) on the seed but does have prediction resistance (PR). - * - * S2N_AES_256_CTR_NO_DF_PR is a deterministic random bit generator using AES 256 in counter mode (AES_128_CTR). It does not - * use a derivation function on the seed but does have prediction resistance. - */ -typedef enum {S2N_AES_128_CTR_NO_DF_PR, S2N_AES_256_CTR_NO_DF_PR} s2n_drbg_mode; - -/* Per NIST SP 800-90C 6.3 - * - * s2n's DRBG does provide prediction resistance - * and does not support the additional_input parameter (which per 800-90C may be zero). - * - * The security strength provided by s2n's DRBG is either 128 or 256 bits depending on the s2n_drbg_mode passed in. - */ -extern int s2n_drbg_instantiate(struct s2n_drbg *drbg, struct s2n_blob *personalization_string, const s2n_drbg_mode mode); -extern int s2n_drbg_generate(struct s2n_drbg *drbg, struct s2n_blob *returned_bits); -extern int s2n_drbg_wipe(struct s2n_drbg *drbg); -extern int s2n_drbg_bytes_used(struct s2n_drbg *drbg, uint64_t *bytes_used); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <openssl/evp.h> + +#include "crypto/s2n_hash.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_result.h" + +#define S2N_DRBG_BLOCK_SIZE 16 +#define S2N_DRBG_MAX_KEY_SIZE 32 +#define S2N_DRBG_MAX_SEED_SIZE (S2N_DRBG_BLOCK_SIZE + S2N_DRBG_MAX_KEY_SIZE) + +/* The maximum size of any one request: from NIST SP800-90A 10.2.1 Table 3 */ +#define S2N_DRBG_GENERATE_LIMIT 8192 + +/* We reseed after 2^35 bytes have been generated: from NIST SP800-90A 10.2.1 Table 3 */ +#define S2N_DRBG_RESEED_LIMIT 34359738368 + +struct s2n_drbg { + /* Track how many bytes have been used */ + uint64_t bytes_used; + + EVP_CIPHER_CTX *ctx; + + /* The current DRBG 'value' */ + uint8_t v[S2N_DRBG_BLOCK_SIZE]; + + /* Used only by the unit tests: how many times has entropy been mixed in */ + uint64_t mixes; +}; + +/* + * S2N_AES_128_CTR_NO_DF_PR is a deterministic random bit generator using AES 128 in counter mode (AES_128_CTR). It does not + * use a derivation function (NO_DF) on the seed but does have prediction resistance (PR). + * + * S2N_AES_256_CTR_NO_DF_PR is a deterministic random bit generator using AES 256 in counter mode (AES_128_CTR). It does not + * use a derivation function on the seed but does have prediction resistance. + */ +typedef enum {S2N_AES_128_CTR_NO_DF_PR, S2N_AES_256_CTR_NO_DF_PR} s2n_drbg_mode; + +/* Per NIST SP 800-90C 6.3 + * + * s2n's DRBG does provide prediction resistance + * and does not support the additional_input parameter (which per 800-90C may be zero). + * + * The security strength provided by s2n's DRBG is either 128 or 256 bits depending on the s2n_drbg_mode passed in. + */ +extern int s2n_drbg_instantiate(struct s2n_drbg *drbg, struct s2n_blob *personalization_string, const s2n_drbg_mode mode); +extern int s2n_drbg_generate(struct s2n_drbg *drbg, struct s2n_blob *returned_bits); +extern int s2n_drbg_wipe(struct s2n_drbg *drbg); +extern int s2n_drbg_bytes_used(struct s2n_drbg *drbg, uint64_t *bytes_used); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_ecc_evp.c b/contrib/restricted/aws/s2n/crypto/s2n_ecc_evp.c index 7ae2a73094..b94c534bea 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_ecc_evp.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_ecc_evp.c @@ -1,501 +1,501 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include "crypto/s2n_ecc_evp.h" - -#include <openssl/ecdh.h> -#include <openssl/evp.h> -#if defined(OPENSSL_IS_AWSLC) -#error #include <openssl/mem.h> -#endif - -#include <stdint.h> - -#include "tls/s2n_tls_parameters.h" -#include "utils/s2n_mem.h" -#include "utils/s2n_safety.h" - -#define TLS_EC_CURVE_TYPE_NAMED 3 - -DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY *, EVP_PKEY_free); -DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY_CTX *, EVP_PKEY_CTX_free); -DEFINE_POINTER_CLEANUP_FUNC(EC_KEY *, EC_KEY_free); - -#if !EVP_APIS_SUPPORTED -DEFINE_POINTER_CLEANUP_FUNC(EC_POINT *, EC_POINT_free); -#endif - -#if EVP_APIS_SUPPORTED -static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey); -#else -static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out); -static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length); -static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY *ec_key); -#endif -static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey); -static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey); -static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret); - -/* IANA values can be found here: https://tools.ietf.org/html/rfc8446#appendix-B.3.1.4 */ - -const struct s2n_ecc_named_curve s2n_ecc_curve_secp256r1 = -{ - .iana_id = TLS_EC_CURVE_SECP_256_R1, - .libcrypto_nid = NID_X9_62_prime256v1, - .name = "secp256r1", - .share_size = SECP256R1_SHARE_SIZE, - .generate_key = s2n_ecc_evp_generate_key_nist_curves, -}; - -const struct s2n_ecc_named_curve s2n_ecc_curve_secp384r1 = -{ - .iana_id = TLS_EC_CURVE_SECP_384_R1, - .libcrypto_nid = NID_secp384r1, - .name = "secp384r1", - .share_size = SECP384R1_SHARE_SIZE, - .generate_key = s2n_ecc_evp_generate_key_nist_curves, -}; - -const struct s2n_ecc_named_curve s2n_ecc_curve_secp521r1 = -{ - .iana_id = TLS_EC_CURVE_SECP_521_R1, - .libcrypto_nid = NID_secp521r1, - .name = "secp521r1", - .share_size = SECP521R1_SHARE_SIZE, - .generate_key = s2n_ecc_evp_generate_key_nist_curves, -}; - -#if EVP_APIS_SUPPORTED -const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = { - .iana_id = TLS_EC_CURVE_ECDH_X25519, - .libcrypto_nid = NID_X25519, - .name = "x25519", - .share_size = X25519_SHARE_SIZE, - .generate_key = s2n_ecc_evp_generate_key_x25519, -}; -#else -const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = {0}; -#endif - -/* All curves that s2n supports. New curves MUST be added here. - * This list is a super set of all the curves present in s2n_ecc_preferences list. - */ -const struct s2n_ecc_named_curve *const s2n_all_supported_curves_list[] = { - &s2n_ecc_curve_secp256r1, - &s2n_ecc_curve_secp384r1, -#if EVP_APIS_SUPPORTED - &s2n_ecc_curve_x25519, -#endif - &s2n_ecc_curve_secp521r1, -}; - -const size_t s2n_all_supported_curves_list_len = s2n_array_len(s2n_all_supported_curves_list); - - -int s2n_is_evp_apis_supported() -{ - return EVP_APIS_SUPPORTED; -} - -#if EVP_APIS_SUPPORTED -static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey) { - - DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(named_curve->libcrypto_nid, NULL), - EVP_PKEY_CTX_free_pointer); - S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY); - - GUARD_OSSL(EVP_PKEY_keygen_init(pctx), S2N_ERR_ECDHE_GEN_KEY); - GUARD_OSSL(EVP_PKEY_keygen(pctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY); - S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY); - - return 0; -} -#endif - -static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey) { - - DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer); - S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY); - - GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_GEN_KEY); - GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, named_curve->libcrypto_nid), S2N_ERR_ECDHE_GEN_KEY); - - DEFER_CLEANUP(EVP_PKEY *params = NULL, EVP_PKEY_free_pointer); - GUARD_OSSL(EVP_PKEY_paramgen(pctx, ¶ms), S2N_ERR_ECDHE_GEN_KEY); - S2N_ERROR_IF(params == NULL, S2N_ERR_ECDHE_GEN_KEY); - - DEFER_CLEANUP(EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(params, NULL), EVP_PKEY_CTX_free_pointer); - S2N_ERROR_IF(kctx == NULL, S2N_ERR_ECDHE_GEN_KEY); - - GUARD_OSSL(EVP_PKEY_keygen_init(kctx), S2N_ERR_ECDHE_GEN_KEY); - GUARD_OSSL(EVP_PKEY_keygen(kctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY); - S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY); - - return 0; -} - -static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey) { - notnull_check(named_curve); - S2N_ERROR_IF(named_curve->generate_key == NULL, S2N_ERR_ECDHE_GEN_KEY); - - return named_curve->generate_key(named_curve, evp_pkey); -} - -static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret) { - notnull_check(peer_public); - notnull_check(own_key); - - /* From RFC 8446 Section 4.2.8.2: For the curves secp256r1 and secp384r1 peers MUST validate each other's - * public value Q by ensuring that the point is a valid point on the elliptic curve. - * For the curve x25519 the peer public-key validation check doesn't apply. - */ - if (iana_id == TLS_EC_CURVE_SECP_256_R1 || iana_id == TLS_EC_CURVE_SECP_384_R1) { - DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(peer_public), EC_KEY_free_pointer); - S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); - GUARD_OSSL(EC_KEY_check_key(ec_key), S2N_ERR_ECDHE_SHARED_SECRET); - } - - size_t shared_secret_size; - - DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(own_key, NULL), EVP_PKEY_CTX_free_pointer); - S2N_ERROR_IF(ctx == NULL, S2N_ERR_ECDHE_SHARED_SECRET); - - GUARD_OSSL(EVP_PKEY_derive_init(ctx), S2N_ERR_ECDHE_SHARED_SECRET); - GUARD_OSSL(EVP_PKEY_derive_set_peer(ctx, peer_public), S2N_ERR_ECDHE_SHARED_SECRET); - GUARD_OSSL(EVP_PKEY_derive(ctx, NULL, &shared_secret_size), S2N_ERR_ECDHE_SHARED_SECRET); - GUARD(s2n_alloc(shared_secret, shared_secret_size)); - - if (EVP_PKEY_derive(ctx, shared_secret->data, &shared_secret_size) != 1) { - GUARD(s2n_free(shared_secret)); - S2N_ERROR(S2N_ERR_ECDHE_SHARED_SECRET); - } - - return 0; -} - -int s2n_ecc_evp_generate_ephemeral_key(struct s2n_ecc_evp_params *ecc_evp_params) { - notnull_check(ecc_evp_params->negotiated_curve); - S2N_ERROR_IF(ecc_evp_params->evp_pkey != NULL, S2N_ERR_ECDHE_GEN_KEY); - S2N_ERROR_IF(s2n_ecc_evp_generate_own_key(ecc_evp_params->negotiated_curve, &ecc_evp_params->evp_pkey) != 0, - S2N_ERR_ECDHE_GEN_KEY); - S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY); - return 0; -} - -int s2n_ecc_evp_compute_shared_secret_from_params(struct s2n_ecc_evp_params *private_ecc_evp_params, - struct s2n_ecc_evp_params *public_ecc_evp_params, - struct s2n_blob *shared_key) { - notnull_check(private_ecc_evp_params->negotiated_curve); - notnull_check(private_ecc_evp_params->evp_pkey); - notnull_check(public_ecc_evp_params->negotiated_curve); - notnull_check(public_ecc_evp_params->evp_pkey); - S2N_ERROR_IF(private_ecc_evp_params->negotiated_curve->iana_id != public_ecc_evp_params->negotiated_curve->iana_id, - S2N_ERR_ECDHE_UNSUPPORTED_CURVE); - GUARD(s2n_ecc_evp_compute_shared_secret(private_ecc_evp_params->evp_pkey, public_ecc_evp_params->evp_pkey, - private_ecc_evp_params->negotiated_curve->iana_id, shared_key)); - return 0; -} - -int s2n_ecc_evp_compute_shared_secret_as_server(struct s2n_ecc_evp_params *ecc_evp_params, - struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key) { - notnull_check(ecc_evp_params->negotiated_curve); - notnull_check(ecc_evp_params->evp_pkey); - notnull_check(Yc_in); - - uint8_t client_public_len; - struct s2n_blob client_public_blob = {0}; - - DEFER_CLEANUP(EVP_PKEY *peer_key = EVP_PKEY_new(), EVP_PKEY_free_pointer); - S2N_ERROR_IF(peer_key == NULL, S2N_ERR_BAD_MESSAGE); - GUARD(s2n_stuffer_read_uint8(Yc_in, &client_public_len)); - client_public_blob.size = client_public_len; - client_public_blob.data = s2n_stuffer_raw_read(Yc_in, client_public_blob.size); - notnull_check(client_public_blob.data); - -#if EVP_APIS_SUPPORTED - if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) { - GUARD(EVP_PKEY_set_type(peer_key, ecc_evp_params->negotiated_curve->libcrypto_nid)); - } else { - DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer); - S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING); - GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING); - GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING); - GUARD_OSSL(EVP_PKEY_paramgen(pctx, &peer_key), S2N_ERR_ECDHE_SERIALIZING); - } - GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(peer_key, client_public_blob.data, client_public_blob.size), - S2N_ERR_ECDHE_SERIALIZING); -#else - DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid), - EC_KEY_free_pointer); - S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); - - DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(&client_public_blob, ec_key), EC_POINT_free_pointer); - S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE); - - int success = EC_KEY_set_public_key(ec_key, point); - GUARD_OSSL(EVP_PKEY_set1_EC_KEY(peer_key, ec_key), S2N_ERR_ECDHE_SERIALIZING); - S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE); -#endif - - return s2n_ecc_evp_compute_shared_secret(ecc_evp_params->evp_pkey, peer_key, - ecc_evp_params->negotiated_curve->iana_id, shared_key); - -} - -int s2n_ecc_evp_compute_shared_secret_as_client(struct s2n_ecc_evp_params *ecc_evp_params, - struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key) { - - DEFER_CLEANUP(struct s2n_ecc_evp_params client_params = {0}, s2n_ecc_evp_params_free); - - notnull_check(ecc_evp_params->negotiated_curve); - client_params.negotiated_curve = ecc_evp_params->negotiated_curve; - GUARD(s2n_ecc_evp_generate_own_key(client_params.negotiated_curve, &client_params.evp_pkey)); - S2N_ERROR_IF(client_params.evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY); - - if (s2n_ecc_evp_compute_shared_secret(client_params.evp_pkey, ecc_evp_params->evp_pkey, - ecc_evp_params->negotiated_curve->iana_id, shared_key) != S2N_SUCCESS) { - S2N_ERROR(S2N_ERR_ECDHE_SHARED_SECRET); - } - - GUARD(s2n_stuffer_write_uint8(Yc_out, client_params.negotiated_curve->share_size)); - - if (s2n_ecc_evp_write_params_point(&client_params, Yc_out) != 0) { - S2N_ERROR(S2N_ERR_ECDHE_SERIALIZING); - } - return 0; - -} - -#if (!EVP_APIS_SUPPORTED) -static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length) { - size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); - S2N_ERROR_IF(ret == 0, S2N_ERR_ECDHE_SERIALIZING); - S2N_ERROR_IF(ret > UINT8_MAX, S2N_ERR_ECDHE_SERIALIZING); - *length = (uint8_t)ret; - return 0; -} - -static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out) { - size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, out->data, out->size, NULL); - S2N_ERROR_IF(ret != out->size, S2N_ERR_ECDHE_SERIALIZING); - return 0; -} - -static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY *ec_key) { - const EC_GROUP *group = EC_KEY_get0_group(ec_key); - EC_POINT *point = EC_POINT_new(group); - if (point == NULL) { - S2N_ERROR_PTR(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); - } - if (EC_POINT_oct2point(group, point, blob->data, blob->size, NULL) != 1) { - EC_POINT_free(point); - S2N_ERROR_PTR(S2N_ERR_BAD_MESSAGE); - } - return point; -} -#endif - -int s2n_ecc_evp_read_params_point(struct s2n_stuffer *in, int point_size, struct s2n_blob *point_blob) { - notnull_check(in); - notnull_check(point_blob); - gte_check(point_size, 0); - - /* Extract point from stuffer */ - point_blob->size = point_size; - point_blob->data = s2n_stuffer_raw_read(in, point_size); - notnull_check(point_blob->data); - - return 0; -} - -int s2n_ecc_evp_read_params(struct s2n_stuffer *in, struct s2n_blob *data_to_verify, - struct s2n_ecdhe_raw_server_params *raw_server_ecc_params) { - notnull_check(in); - uint8_t curve_type; - uint8_t point_length; - - /* Remember where we started reading the data */ - data_to_verify->data = s2n_stuffer_raw_read(in, 0); - notnull_check(data_to_verify->data); - - /* Read the curve */ - GUARD(s2n_stuffer_read_uint8(in, &curve_type)); - S2N_ERROR_IF(curve_type != TLS_EC_CURVE_TYPE_NAMED, S2N_ERR_BAD_MESSAGE); - raw_server_ecc_params->curve_blob.data = s2n_stuffer_raw_read(in, 2); - notnull_check(raw_server_ecc_params->curve_blob.data); - raw_server_ecc_params->curve_blob.size = 2; - - /* Read the point */ - GUARD(s2n_stuffer_read_uint8(in, &point_length)); - - GUARD(s2n_ecc_evp_read_params_point(in, point_length, &raw_server_ecc_params->point_blob)); - - /* curve type (1) + iana (2) + key share size (1) + key share */ - data_to_verify->size = point_length + 4; - - return 0; -} - -int s2n_ecc_evp_write_params_point(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out) { - notnull_check(ecc_evp_params); - notnull_check(ecc_evp_params->negotiated_curve); - notnull_check(ecc_evp_params->evp_pkey); - notnull_check(out); - -#if EVP_APIS_SUPPORTED - struct s2n_blob point_blob = {0}; - uint8_t *encoded_point = NULL; - - size_t size = EVP_PKEY_get1_tls_encodedpoint(ecc_evp_params->evp_pkey, &encoded_point); - if (size != ecc_evp_params->negotiated_curve->share_size) { - OPENSSL_free(encoded_point); - S2N_ERROR(S2N_ERR_ECDHE_SERIALIZING); - } - else { - point_blob.data = s2n_stuffer_raw_write(out, ecc_evp_params->negotiated_curve->share_size); - notnull_check(point_blob.data); - memcpy_check(point_blob.data, encoded_point, size); - OPENSSL_free(encoded_point); - } -#else - uint8_t point_len; - struct s2n_blob point_blob = {0}; - - DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(ecc_evp_params->evp_pkey), EC_KEY_free_pointer); - S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); - const EC_POINT *point = EC_KEY_get0_public_key(ec_key); - const EC_GROUP *group = EC_KEY_get0_group(ec_key); - S2N_ERROR_IF(point == NULL || group == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); - - GUARD(s2n_ecc_evp_calculate_point_length(point, group, &point_len)); - S2N_ERROR_IF(point_len != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING); - point_blob.data = s2n_stuffer_raw_write(out, point_len); - notnull_check(point_blob.data); - point_blob.size = point_len; - - GUARD(s2n_ecc_evp_write_point_data_snug(point, group, &point_blob)); -#endif - return 0; -} - -int s2n_ecc_evp_write_params(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out, - struct s2n_blob *written) { - notnull_check(ecc_evp_params); - notnull_check(ecc_evp_params->negotiated_curve); - notnull_check(ecc_evp_params->evp_pkey); - notnull_check(out); - notnull_check(written); - - uint8_t key_share_size = ecc_evp_params->negotiated_curve->share_size; - /* Remember where the written data starts */ - written->data = s2n_stuffer_raw_write(out, 0); - notnull_check(written->data); - - GUARD(s2n_stuffer_write_uint8(out, TLS_EC_CURVE_TYPE_NAMED)); - GUARD(s2n_stuffer_write_uint16(out, ecc_evp_params->negotiated_curve->iana_id)); - GUARD(s2n_stuffer_write_uint8(out, key_share_size)); - - GUARD(s2n_ecc_evp_write_params_point(ecc_evp_params, out)); - - /* key share + key share size (1) + iana (2) + curve type (1) */ - written->size = key_share_size + 4; - - return written->size; -} - -int s2n_ecc_evp_parse_params_point(struct s2n_blob *point_blob, struct s2n_ecc_evp_params *ecc_evp_params) { - notnull_check(point_blob->data); - notnull_check(ecc_evp_params->negotiated_curve); - S2N_ERROR_IF(point_blob->size != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING); - -#if EVP_APIS_SUPPORTED - if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) { - if (ecc_evp_params->evp_pkey == NULL) { - ecc_evp_params->evp_pkey = EVP_PKEY_new(); - } - S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE); - GUARD(EVP_PKEY_set_type(ecc_evp_params->evp_pkey, ecc_evp_params->negotiated_curve->libcrypto_nid)); - } - else { - DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer); - S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING); - GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING); - GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING); - GUARD_OSSL(EVP_PKEY_paramgen(pctx, &ecc_evp_params->evp_pkey), S2N_ERR_ECDHE_SERIALIZING); - } - GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(ecc_evp_params->evp_pkey, point_blob->data, point_blob->size), - S2N_ERR_ECDHE_SERIALIZING); -#else - if (ecc_evp_params->evp_pkey == NULL) { - ecc_evp_params->evp_pkey = EVP_PKEY_new(); - } - S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE); - /* Create a key to store the point */ - DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid), - EC_KEY_free_pointer); - S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); - - /* Parse and store the server public point */ - DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(point_blob, ec_key), EC_POINT_free_pointer); - S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE); - - /* Set the point as the public key */ - int success = EC_KEY_set_public_key(ec_key, point); - - GUARD_OSSL(EVP_PKEY_set1_EC_KEY(ecc_evp_params->evp_pkey,ec_key), S2N_ERR_ECDHE_SERIALIZING); - - /* EC_KEY_set_public_key returns 1 on success, 0 on failure */ - S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE); - -#endif - return 0; -} - -int s2n_ecc_evp_parse_params(struct s2n_ecdhe_raw_server_params *raw_server_ecc_params, - struct s2n_ecc_evp_params *ecc_evp_params) { - S2N_ERROR_IF( - s2n_ecc_evp_find_supported_curve(&raw_server_ecc_params->curve_blob, &ecc_evp_params->negotiated_curve) != 0, - S2N_ERR_ECDHE_UNSUPPORTED_CURVE); - return s2n_ecc_evp_parse_params_point(&raw_server_ecc_params->point_blob, ecc_evp_params); -} - -int s2n_ecc_evp_find_supported_curve(struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **found) { - struct s2n_stuffer iana_ids_in = {0}; - - GUARD(s2n_stuffer_init(&iana_ids_in, iana_ids)); - GUARD(s2n_stuffer_write(&iana_ids_in, iana_ids)); - for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { - const struct s2n_ecc_named_curve *supported_curve = s2n_all_supported_curves_list[i]; - for (int j = 0; j < iana_ids->size / 2; j++) { - uint16_t iana_id; - GUARD(s2n_stuffer_read_uint16(&iana_ids_in, &iana_id)); - if (supported_curve->iana_id == iana_id) { - *found = supported_curve; - return 0; - } - } - GUARD(s2n_stuffer_reread(&iana_ids_in)); - } - - S2N_ERROR(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); -} - -int s2n_ecc_evp_params_free(struct s2n_ecc_evp_params *ecc_evp_params) { - if (ecc_evp_params->evp_pkey != NULL) { - EVP_PKEY_free(ecc_evp_params->evp_pkey); - ecc_evp_params->evp_pkey = NULL; - } - return 0; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include "crypto/s2n_ecc_evp.h" + +#include <openssl/ecdh.h> +#include <openssl/evp.h> +#if defined(OPENSSL_IS_AWSLC) +#error #include <openssl/mem.h> +#endif + +#include <stdint.h> + +#include "tls/s2n_tls_parameters.h" +#include "utils/s2n_mem.h" +#include "utils/s2n_safety.h" + +#define TLS_EC_CURVE_TYPE_NAMED 3 + +DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY *, EVP_PKEY_free); +DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY_CTX *, EVP_PKEY_CTX_free); +DEFINE_POINTER_CLEANUP_FUNC(EC_KEY *, EC_KEY_free); + +#if !EVP_APIS_SUPPORTED +DEFINE_POINTER_CLEANUP_FUNC(EC_POINT *, EC_POINT_free); +#endif + +#if EVP_APIS_SUPPORTED +static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey); +#else +static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out); +static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length); +static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY *ec_key); +#endif +static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey); +static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey); +static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret); + +/* IANA values can be found here: https://tools.ietf.org/html/rfc8446#appendix-B.3.1.4 */ + +const struct s2n_ecc_named_curve s2n_ecc_curve_secp256r1 = +{ + .iana_id = TLS_EC_CURVE_SECP_256_R1, + .libcrypto_nid = NID_X9_62_prime256v1, + .name = "secp256r1", + .share_size = SECP256R1_SHARE_SIZE, + .generate_key = s2n_ecc_evp_generate_key_nist_curves, +}; + +const struct s2n_ecc_named_curve s2n_ecc_curve_secp384r1 = +{ + .iana_id = TLS_EC_CURVE_SECP_384_R1, + .libcrypto_nid = NID_secp384r1, + .name = "secp384r1", + .share_size = SECP384R1_SHARE_SIZE, + .generate_key = s2n_ecc_evp_generate_key_nist_curves, +}; + +const struct s2n_ecc_named_curve s2n_ecc_curve_secp521r1 = +{ + .iana_id = TLS_EC_CURVE_SECP_521_R1, + .libcrypto_nid = NID_secp521r1, + .name = "secp521r1", + .share_size = SECP521R1_SHARE_SIZE, + .generate_key = s2n_ecc_evp_generate_key_nist_curves, +}; + +#if EVP_APIS_SUPPORTED +const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = { + .iana_id = TLS_EC_CURVE_ECDH_X25519, + .libcrypto_nid = NID_X25519, + .name = "x25519", + .share_size = X25519_SHARE_SIZE, + .generate_key = s2n_ecc_evp_generate_key_x25519, +}; +#else +const struct s2n_ecc_named_curve s2n_ecc_curve_x25519 = {0}; +#endif + +/* All curves that s2n supports. New curves MUST be added here. + * This list is a super set of all the curves present in s2n_ecc_preferences list. + */ +const struct s2n_ecc_named_curve *const s2n_all_supported_curves_list[] = { + &s2n_ecc_curve_secp256r1, + &s2n_ecc_curve_secp384r1, +#if EVP_APIS_SUPPORTED + &s2n_ecc_curve_x25519, +#endif + &s2n_ecc_curve_secp521r1, +}; + +const size_t s2n_all_supported_curves_list_len = s2n_array_len(s2n_all_supported_curves_list); + + +int s2n_is_evp_apis_supported() +{ + return EVP_APIS_SUPPORTED; +} + +#if EVP_APIS_SUPPORTED +static int s2n_ecc_evp_generate_key_x25519(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey) { + + DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(named_curve->libcrypto_nid, NULL), + EVP_PKEY_CTX_free_pointer); + S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY); + + GUARD_OSSL(EVP_PKEY_keygen_init(pctx), S2N_ERR_ECDHE_GEN_KEY); + GUARD_OSSL(EVP_PKEY_keygen(pctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY); + S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY); + + return 0; +} +#endif + +static int s2n_ecc_evp_generate_key_nist_curves(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey) { + + DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer); + S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_GEN_KEY); + + GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_GEN_KEY); + GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, named_curve->libcrypto_nid), S2N_ERR_ECDHE_GEN_KEY); + + DEFER_CLEANUP(EVP_PKEY *params = NULL, EVP_PKEY_free_pointer); + GUARD_OSSL(EVP_PKEY_paramgen(pctx, ¶ms), S2N_ERR_ECDHE_GEN_KEY); + S2N_ERROR_IF(params == NULL, S2N_ERR_ECDHE_GEN_KEY); + + DEFER_CLEANUP(EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(params, NULL), EVP_PKEY_CTX_free_pointer); + S2N_ERROR_IF(kctx == NULL, S2N_ERR_ECDHE_GEN_KEY); + + GUARD_OSSL(EVP_PKEY_keygen_init(kctx), S2N_ERR_ECDHE_GEN_KEY); + GUARD_OSSL(EVP_PKEY_keygen(kctx, evp_pkey), S2N_ERR_ECDHE_GEN_KEY); + S2N_ERROR_IF(evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY); + + return 0; +} + +static int s2n_ecc_evp_generate_own_key(const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey) { + notnull_check(named_curve); + S2N_ERROR_IF(named_curve->generate_key == NULL, S2N_ERR_ECDHE_GEN_KEY); + + return named_curve->generate_key(named_curve, evp_pkey); +} + +static int s2n_ecc_evp_compute_shared_secret(EVP_PKEY *own_key, EVP_PKEY *peer_public, uint16_t iana_id, struct s2n_blob *shared_secret) { + notnull_check(peer_public); + notnull_check(own_key); + + /* From RFC 8446 Section 4.2.8.2: For the curves secp256r1 and secp384r1 peers MUST validate each other's + * public value Q by ensuring that the point is a valid point on the elliptic curve. + * For the curve x25519 the peer public-key validation check doesn't apply. + */ + if (iana_id == TLS_EC_CURVE_SECP_256_R1 || iana_id == TLS_EC_CURVE_SECP_384_R1) { + DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(peer_public), EC_KEY_free_pointer); + S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + GUARD_OSSL(EC_KEY_check_key(ec_key), S2N_ERR_ECDHE_SHARED_SECRET); + } + + size_t shared_secret_size; + + DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(own_key, NULL), EVP_PKEY_CTX_free_pointer); + S2N_ERROR_IF(ctx == NULL, S2N_ERR_ECDHE_SHARED_SECRET); + + GUARD_OSSL(EVP_PKEY_derive_init(ctx), S2N_ERR_ECDHE_SHARED_SECRET); + GUARD_OSSL(EVP_PKEY_derive_set_peer(ctx, peer_public), S2N_ERR_ECDHE_SHARED_SECRET); + GUARD_OSSL(EVP_PKEY_derive(ctx, NULL, &shared_secret_size), S2N_ERR_ECDHE_SHARED_SECRET); + GUARD(s2n_alloc(shared_secret, shared_secret_size)); + + if (EVP_PKEY_derive(ctx, shared_secret->data, &shared_secret_size) != 1) { + GUARD(s2n_free(shared_secret)); + S2N_ERROR(S2N_ERR_ECDHE_SHARED_SECRET); + } + + return 0; +} + +int s2n_ecc_evp_generate_ephemeral_key(struct s2n_ecc_evp_params *ecc_evp_params) { + notnull_check(ecc_evp_params->negotiated_curve); + S2N_ERROR_IF(ecc_evp_params->evp_pkey != NULL, S2N_ERR_ECDHE_GEN_KEY); + S2N_ERROR_IF(s2n_ecc_evp_generate_own_key(ecc_evp_params->negotiated_curve, &ecc_evp_params->evp_pkey) != 0, + S2N_ERR_ECDHE_GEN_KEY); + S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY); + return 0; +} + +int s2n_ecc_evp_compute_shared_secret_from_params(struct s2n_ecc_evp_params *private_ecc_evp_params, + struct s2n_ecc_evp_params *public_ecc_evp_params, + struct s2n_blob *shared_key) { + notnull_check(private_ecc_evp_params->negotiated_curve); + notnull_check(private_ecc_evp_params->evp_pkey); + notnull_check(public_ecc_evp_params->negotiated_curve); + notnull_check(public_ecc_evp_params->evp_pkey); + S2N_ERROR_IF(private_ecc_evp_params->negotiated_curve->iana_id != public_ecc_evp_params->negotiated_curve->iana_id, + S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + GUARD(s2n_ecc_evp_compute_shared_secret(private_ecc_evp_params->evp_pkey, public_ecc_evp_params->evp_pkey, + private_ecc_evp_params->negotiated_curve->iana_id, shared_key)); + return 0; +} + +int s2n_ecc_evp_compute_shared_secret_as_server(struct s2n_ecc_evp_params *ecc_evp_params, + struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key) { + notnull_check(ecc_evp_params->negotiated_curve); + notnull_check(ecc_evp_params->evp_pkey); + notnull_check(Yc_in); + + uint8_t client_public_len; + struct s2n_blob client_public_blob = {0}; + + DEFER_CLEANUP(EVP_PKEY *peer_key = EVP_PKEY_new(), EVP_PKEY_free_pointer); + S2N_ERROR_IF(peer_key == NULL, S2N_ERR_BAD_MESSAGE); + GUARD(s2n_stuffer_read_uint8(Yc_in, &client_public_len)); + client_public_blob.size = client_public_len; + client_public_blob.data = s2n_stuffer_raw_read(Yc_in, client_public_blob.size); + notnull_check(client_public_blob.data); + +#if EVP_APIS_SUPPORTED + if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) { + GUARD(EVP_PKEY_set_type(peer_key, ecc_evp_params->negotiated_curve->libcrypto_nid)); + } else { + DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer); + S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING); + GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING); + GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING); + GUARD_OSSL(EVP_PKEY_paramgen(pctx, &peer_key), S2N_ERR_ECDHE_SERIALIZING); + } + GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(peer_key, client_public_blob.data, client_public_blob.size), + S2N_ERR_ECDHE_SERIALIZING); +#else + DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid), + EC_KEY_free_pointer); + S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + + DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(&client_public_blob, ec_key), EC_POINT_free_pointer); + S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE); + + int success = EC_KEY_set_public_key(ec_key, point); + GUARD_OSSL(EVP_PKEY_set1_EC_KEY(peer_key, ec_key), S2N_ERR_ECDHE_SERIALIZING); + S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE); +#endif + + return s2n_ecc_evp_compute_shared_secret(ecc_evp_params->evp_pkey, peer_key, + ecc_evp_params->negotiated_curve->iana_id, shared_key); + +} + +int s2n_ecc_evp_compute_shared_secret_as_client(struct s2n_ecc_evp_params *ecc_evp_params, + struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key) { + + DEFER_CLEANUP(struct s2n_ecc_evp_params client_params = {0}, s2n_ecc_evp_params_free); + + notnull_check(ecc_evp_params->negotiated_curve); + client_params.negotiated_curve = ecc_evp_params->negotiated_curve; + GUARD(s2n_ecc_evp_generate_own_key(client_params.negotiated_curve, &client_params.evp_pkey)); + S2N_ERROR_IF(client_params.evp_pkey == NULL, S2N_ERR_ECDHE_GEN_KEY); + + if (s2n_ecc_evp_compute_shared_secret(client_params.evp_pkey, ecc_evp_params->evp_pkey, + ecc_evp_params->negotiated_curve->iana_id, shared_key) != S2N_SUCCESS) { + S2N_ERROR(S2N_ERR_ECDHE_SHARED_SECRET); + } + + GUARD(s2n_stuffer_write_uint8(Yc_out, client_params.negotiated_curve->share_size)); + + if (s2n_ecc_evp_write_params_point(&client_params, Yc_out) != 0) { + S2N_ERROR(S2N_ERR_ECDHE_SERIALIZING); + } + return 0; + +} + +#if (!EVP_APIS_SUPPORTED) +static int s2n_ecc_evp_calculate_point_length(const EC_POINT *point, const EC_GROUP *group, uint8_t *length) { + size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); + S2N_ERROR_IF(ret == 0, S2N_ERR_ECDHE_SERIALIZING); + S2N_ERROR_IF(ret > UINT8_MAX, S2N_ERR_ECDHE_SERIALIZING); + *length = (uint8_t)ret; + return 0; +} + +static int s2n_ecc_evp_write_point_data_snug(const EC_POINT *point, const EC_GROUP *group, struct s2n_blob *out) { + size_t ret = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, out->data, out->size, NULL); + S2N_ERROR_IF(ret != out->size, S2N_ERR_ECDHE_SERIALIZING); + return 0; +} + +static EC_POINT *s2n_ecc_evp_blob_to_point(struct s2n_blob *blob, const EC_KEY *ec_key) { + const EC_GROUP *group = EC_KEY_get0_group(ec_key); + EC_POINT *point = EC_POINT_new(group); + if (point == NULL) { + S2N_ERROR_PTR(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + } + if (EC_POINT_oct2point(group, point, blob->data, blob->size, NULL) != 1) { + EC_POINT_free(point); + S2N_ERROR_PTR(S2N_ERR_BAD_MESSAGE); + } + return point; +} +#endif + +int s2n_ecc_evp_read_params_point(struct s2n_stuffer *in, int point_size, struct s2n_blob *point_blob) { + notnull_check(in); + notnull_check(point_blob); + gte_check(point_size, 0); + + /* Extract point from stuffer */ + point_blob->size = point_size; + point_blob->data = s2n_stuffer_raw_read(in, point_size); + notnull_check(point_blob->data); + + return 0; +} + +int s2n_ecc_evp_read_params(struct s2n_stuffer *in, struct s2n_blob *data_to_verify, + struct s2n_ecdhe_raw_server_params *raw_server_ecc_params) { + notnull_check(in); + uint8_t curve_type; + uint8_t point_length; + + /* Remember where we started reading the data */ + data_to_verify->data = s2n_stuffer_raw_read(in, 0); + notnull_check(data_to_verify->data); + + /* Read the curve */ + GUARD(s2n_stuffer_read_uint8(in, &curve_type)); + S2N_ERROR_IF(curve_type != TLS_EC_CURVE_TYPE_NAMED, S2N_ERR_BAD_MESSAGE); + raw_server_ecc_params->curve_blob.data = s2n_stuffer_raw_read(in, 2); + notnull_check(raw_server_ecc_params->curve_blob.data); + raw_server_ecc_params->curve_blob.size = 2; + + /* Read the point */ + GUARD(s2n_stuffer_read_uint8(in, &point_length)); + + GUARD(s2n_ecc_evp_read_params_point(in, point_length, &raw_server_ecc_params->point_blob)); + + /* curve type (1) + iana (2) + key share size (1) + key share */ + data_to_verify->size = point_length + 4; + + return 0; +} + +int s2n_ecc_evp_write_params_point(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out) { + notnull_check(ecc_evp_params); + notnull_check(ecc_evp_params->negotiated_curve); + notnull_check(ecc_evp_params->evp_pkey); + notnull_check(out); + +#if EVP_APIS_SUPPORTED + struct s2n_blob point_blob = {0}; + uint8_t *encoded_point = NULL; + + size_t size = EVP_PKEY_get1_tls_encodedpoint(ecc_evp_params->evp_pkey, &encoded_point); + if (size != ecc_evp_params->negotiated_curve->share_size) { + OPENSSL_free(encoded_point); + S2N_ERROR(S2N_ERR_ECDHE_SERIALIZING); + } + else { + point_blob.data = s2n_stuffer_raw_write(out, ecc_evp_params->negotiated_curve->share_size); + notnull_check(point_blob.data); + memcpy_check(point_blob.data, encoded_point, size); + OPENSSL_free(encoded_point); + } +#else + uint8_t point_len; + struct s2n_blob point_blob = {0}; + + DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(ecc_evp_params->evp_pkey), EC_KEY_free_pointer); + S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + const EC_POINT *point = EC_KEY_get0_public_key(ec_key); + const EC_GROUP *group = EC_KEY_get0_group(ec_key); + S2N_ERROR_IF(point == NULL || group == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + + GUARD(s2n_ecc_evp_calculate_point_length(point, group, &point_len)); + S2N_ERROR_IF(point_len != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING); + point_blob.data = s2n_stuffer_raw_write(out, point_len); + notnull_check(point_blob.data); + point_blob.size = point_len; + + GUARD(s2n_ecc_evp_write_point_data_snug(point, group, &point_blob)); +#endif + return 0; +} + +int s2n_ecc_evp_write_params(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out, + struct s2n_blob *written) { + notnull_check(ecc_evp_params); + notnull_check(ecc_evp_params->negotiated_curve); + notnull_check(ecc_evp_params->evp_pkey); + notnull_check(out); + notnull_check(written); + + uint8_t key_share_size = ecc_evp_params->negotiated_curve->share_size; + /* Remember where the written data starts */ + written->data = s2n_stuffer_raw_write(out, 0); + notnull_check(written->data); + + GUARD(s2n_stuffer_write_uint8(out, TLS_EC_CURVE_TYPE_NAMED)); + GUARD(s2n_stuffer_write_uint16(out, ecc_evp_params->negotiated_curve->iana_id)); + GUARD(s2n_stuffer_write_uint8(out, key_share_size)); + + GUARD(s2n_ecc_evp_write_params_point(ecc_evp_params, out)); + + /* key share + key share size (1) + iana (2) + curve type (1) */ + written->size = key_share_size + 4; + + return written->size; +} + +int s2n_ecc_evp_parse_params_point(struct s2n_blob *point_blob, struct s2n_ecc_evp_params *ecc_evp_params) { + notnull_check(point_blob->data); + notnull_check(ecc_evp_params->negotiated_curve); + S2N_ERROR_IF(point_blob->size != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING); + +#if EVP_APIS_SUPPORTED + if (ecc_evp_params->negotiated_curve->libcrypto_nid == NID_X25519) { + if (ecc_evp_params->evp_pkey == NULL) { + ecc_evp_params->evp_pkey = EVP_PKEY_new(); + } + S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE); + GUARD(EVP_PKEY_set_type(ecc_evp_params->evp_pkey, ecc_evp_params->negotiated_curve->libcrypto_nid)); + } + else { + DEFER_CLEANUP(EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL), EVP_PKEY_CTX_free_pointer); + S2N_ERROR_IF(pctx == NULL, S2N_ERR_ECDHE_SERIALIZING); + GUARD_OSSL(EVP_PKEY_paramgen_init(pctx), S2N_ERR_ECDHE_SERIALIZING); + GUARD_OSSL(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecc_evp_params->negotiated_curve->libcrypto_nid), S2N_ERR_ECDHE_SERIALIZING); + GUARD_OSSL(EVP_PKEY_paramgen(pctx, &ecc_evp_params->evp_pkey), S2N_ERR_ECDHE_SERIALIZING); + } + GUARD_OSSL(EVP_PKEY_set1_tls_encodedpoint(ecc_evp_params->evp_pkey, point_blob->data, point_blob->size), + S2N_ERR_ECDHE_SERIALIZING); +#else + if (ecc_evp_params->evp_pkey == NULL) { + ecc_evp_params->evp_pkey = EVP_PKEY_new(); + } + S2N_ERROR_IF(ecc_evp_params->evp_pkey == NULL, S2N_ERR_BAD_MESSAGE); + /* Create a key to store the point */ + DEFER_CLEANUP(EC_KEY *ec_key = EC_KEY_new_by_curve_name(ecc_evp_params->negotiated_curve->libcrypto_nid), + EC_KEY_free_pointer); + S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + + /* Parse and store the server public point */ + DEFER_CLEANUP(EC_POINT *point = s2n_ecc_evp_blob_to_point(point_blob, ec_key), EC_POINT_free_pointer); + S2N_ERROR_IF(point == NULL, S2N_ERR_BAD_MESSAGE); + + /* Set the point as the public key */ + int success = EC_KEY_set_public_key(ec_key, point); + + GUARD_OSSL(EVP_PKEY_set1_EC_KEY(ecc_evp_params->evp_pkey,ec_key), S2N_ERR_ECDHE_SERIALIZING); + + /* EC_KEY_set_public_key returns 1 on success, 0 on failure */ + S2N_ERROR_IF(success == 0, S2N_ERR_BAD_MESSAGE); + +#endif + return 0; +} + +int s2n_ecc_evp_parse_params(struct s2n_ecdhe_raw_server_params *raw_server_ecc_params, + struct s2n_ecc_evp_params *ecc_evp_params) { + S2N_ERROR_IF( + s2n_ecc_evp_find_supported_curve(&raw_server_ecc_params->curve_blob, &ecc_evp_params->negotiated_curve) != 0, + S2N_ERR_ECDHE_UNSUPPORTED_CURVE); + return s2n_ecc_evp_parse_params_point(&raw_server_ecc_params->point_blob, ecc_evp_params); +} + +int s2n_ecc_evp_find_supported_curve(struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **found) { + struct s2n_stuffer iana_ids_in = {0}; + + GUARD(s2n_stuffer_init(&iana_ids_in, iana_ids)); + GUARD(s2n_stuffer_write(&iana_ids_in, iana_ids)); + for (int i = 0; i < s2n_all_supported_curves_list_len; i++) { + const struct s2n_ecc_named_curve *supported_curve = s2n_all_supported_curves_list[i]; + for (int j = 0; j < iana_ids->size / 2; j++) { + uint16_t iana_id; + GUARD(s2n_stuffer_read_uint16(&iana_ids_in, &iana_id)); + if (supported_curve->iana_id == iana_id) { + *found = supported_curve; + return 0; + } + } + GUARD(s2n_stuffer_reread(&iana_ids_in)); + } + + S2N_ERROR(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); +} + +int s2n_ecc_evp_params_free(struct s2n_ecc_evp_params *ecc_evp_params) { + if (ecc_evp_params->evp_pkey != NULL) { + EVP_PKEY_free(ecc_evp_params->evp_pkey); + ecc_evp_params->evp_pkey = NULL; + } + return 0; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_ecc_evp.h b/contrib/restricted/aws/s2n/crypto/s2n_ecc_evp.h index f9b8c8f7e2..e8905f2d28 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_ecc_evp.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_ecc_evp.h @@ -1,89 +1,89 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <openssl/evp.h> - -#include "crypto/s2n_hash.h" -#include "tls/s2n_kex_data.h" -#include "stuffer/s2n_stuffer.h" -#include "tls/s2n_tls_parameters.h" -#include "utils/s2n_safety.h" - -/* Share sizes are described here: https://tools.ietf.org/html/rfc8446#section-4.2.8.2 - * and include the extra "legacy_form" byte */ -#define SECP256R1_SHARE_SIZE ((32 * 2 ) + 1) -#define SECP384R1_SHARE_SIZE ((48 * 2 ) + 1) -#define SECP521R1_SHARE_SIZE ((66 * 2 ) + 1) -#define X25519_SHARE_SIZE (32) - -struct s2n_ecc_named_curve { - /* See https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 */ - uint16_t iana_id; - /* See nid_list in openssl/ssl/t1_lib.c */ - int libcrypto_nid; - const char *name; - const uint8_t share_size; - int (*generate_key) (const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey); -}; - -extern const struct s2n_ecc_named_curve s2n_ecc_curve_secp256r1; -extern const struct s2n_ecc_named_curve s2n_ecc_curve_secp384r1; -extern const struct s2n_ecc_named_curve s2n_ecc_curve_secp521r1; -extern const struct s2n_ecc_named_curve s2n_ecc_curve_x25519; - -/* BoringSSL only supports using EVP_PKEY_X25519 with "modern" EC EVP APIs. BoringSSL has a note to possibly add this in - * the future. See https://github.com/google/boringssl/blob/master/crypto/evp/p_x25519_asn1.c#L233 - */ -#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) - #define EVP_APIS_SUPPORTED 1 - #define S2N_ECC_EVP_SUPPORTED_CURVES_COUNT 4 -#else - #define EVP_APIS_SUPPORTED 0 - #define S2N_ECC_EVP_SUPPORTED_CURVES_COUNT 3 -#endif - -extern const struct s2n_ecc_named_curve *const s2n_all_supported_curves_list[]; -extern const size_t s2n_all_supported_curves_list_len; - -struct s2n_ecc_evp_params { - const struct s2n_ecc_named_curve *negotiated_curve; - EVP_PKEY *evp_pkey; -}; - -int s2n_ecc_evp_generate_ephemeral_key(struct s2n_ecc_evp_params *ecc_evp_params); -int s2n_ecc_evp_compute_shared_secret_from_params(struct s2n_ecc_evp_params *private_ecc_evp_params, - struct s2n_ecc_evp_params *public_ecc_evp_params, - struct s2n_blob *shared_key); -int s2n_ecc_evp_write_params_point(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out); -int s2n_ecc_evp_read_params_point(struct s2n_stuffer *in, int point_size, struct s2n_blob *point_blob); -int s2n_ecc_evp_compute_shared_secret_from_params(struct s2n_ecc_evp_params *private_ecc_evp_params, - struct s2n_ecc_evp_params *public_ecc_evp_params, - struct s2n_blob *shared_key); -int s2n_ecc_evp_compute_shared_secret_as_server(struct s2n_ecc_evp_params *server_ecc_evp_params, - struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key); -int s2n_ecc_evp_compute_shared_secret_as_client(struct s2n_ecc_evp_params *server_ecc_evp_params, - struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key); -int s2n_ecc_evp_parse_params_point(struct s2n_blob *point_blob, struct s2n_ecc_evp_params *ecc_evp_params); -int s2n_ecc_evp_write_params(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out, - struct s2n_blob *written); -int s2n_ecc_evp_read_params(struct s2n_stuffer *in, struct s2n_blob *data_to_verify, - struct s2n_ecdhe_raw_server_params *raw_server_ecc_params); -int s2n_ecc_evp_parse_params(struct s2n_ecdhe_raw_server_params *raw_server_ecc_params, - struct s2n_ecc_evp_params *ecc_evp_params); -int s2n_ecc_evp_find_supported_curve(struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **found); -int s2n_ecc_evp_params_free(struct s2n_ecc_evp_params *ecc_evp_params); -int s2n_is_evp_apis_supported(); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <openssl/evp.h> + +#include "crypto/s2n_hash.h" +#include "tls/s2n_kex_data.h" +#include "stuffer/s2n_stuffer.h" +#include "tls/s2n_tls_parameters.h" +#include "utils/s2n_safety.h" + +/* Share sizes are described here: https://tools.ietf.org/html/rfc8446#section-4.2.8.2 + * and include the extra "legacy_form" byte */ +#define SECP256R1_SHARE_SIZE ((32 * 2 ) + 1) +#define SECP384R1_SHARE_SIZE ((48 * 2 ) + 1) +#define SECP521R1_SHARE_SIZE ((66 * 2 ) + 1) +#define X25519_SHARE_SIZE (32) + +struct s2n_ecc_named_curve { + /* See https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 */ + uint16_t iana_id; + /* See nid_list in openssl/ssl/t1_lib.c */ + int libcrypto_nid; + const char *name; + const uint8_t share_size; + int (*generate_key) (const struct s2n_ecc_named_curve *named_curve, EVP_PKEY **evp_pkey); +}; + +extern const struct s2n_ecc_named_curve s2n_ecc_curve_secp256r1; +extern const struct s2n_ecc_named_curve s2n_ecc_curve_secp384r1; +extern const struct s2n_ecc_named_curve s2n_ecc_curve_secp521r1; +extern const struct s2n_ecc_named_curve s2n_ecc_curve_x25519; + +/* BoringSSL only supports using EVP_PKEY_X25519 with "modern" EC EVP APIs. BoringSSL has a note to possibly add this in + * the future. See https://github.com/google/boringssl/blob/master/crypto/evp/p_x25519_asn1.c#L233 + */ +#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) + #define EVP_APIS_SUPPORTED 1 + #define S2N_ECC_EVP_SUPPORTED_CURVES_COUNT 4 +#else + #define EVP_APIS_SUPPORTED 0 + #define S2N_ECC_EVP_SUPPORTED_CURVES_COUNT 3 +#endif + +extern const struct s2n_ecc_named_curve *const s2n_all_supported_curves_list[]; +extern const size_t s2n_all_supported_curves_list_len; + +struct s2n_ecc_evp_params { + const struct s2n_ecc_named_curve *negotiated_curve; + EVP_PKEY *evp_pkey; +}; + +int s2n_ecc_evp_generate_ephemeral_key(struct s2n_ecc_evp_params *ecc_evp_params); +int s2n_ecc_evp_compute_shared_secret_from_params(struct s2n_ecc_evp_params *private_ecc_evp_params, + struct s2n_ecc_evp_params *public_ecc_evp_params, + struct s2n_blob *shared_key); +int s2n_ecc_evp_write_params_point(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out); +int s2n_ecc_evp_read_params_point(struct s2n_stuffer *in, int point_size, struct s2n_blob *point_blob); +int s2n_ecc_evp_compute_shared_secret_from_params(struct s2n_ecc_evp_params *private_ecc_evp_params, + struct s2n_ecc_evp_params *public_ecc_evp_params, + struct s2n_blob *shared_key); +int s2n_ecc_evp_compute_shared_secret_as_server(struct s2n_ecc_evp_params *server_ecc_evp_params, + struct s2n_stuffer *Yc_in, struct s2n_blob *shared_key); +int s2n_ecc_evp_compute_shared_secret_as_client(struct s2n_ecc_evp_params *server_ecc_evp_params, + struct s2n_stuffer *Yc_out, struct s2n_blob *shared_key); +int s2n_ecc_evp_parse_params_point(struct s2n_blob *point_blob, struct s2n_ecc_evp_params *ecc_evp_params); +int s2n_ecc_evp_write_params(struct s2n_ecc_evp_params *ecc_evp_params, struct s2n_stuffer *out, + struct s2n_blob *written); +int s2n_ecc_evp_read_params(struct s2n_stuffer *in, struct s2n_blob *data_to_verify, + struct s2n_ecdhe_raw_server_params *raw_server_ecc_params); +int s2n_ecc_evp_parse_params(struct s2n_ecdhe_raw_server_params *raw_server_ecc_params, + struct s2n_ecc_evp_params *ecc_evp_params); +int s2n_ecc_evp_find_supported_curve(struct s2n_blob *iana_ids, const struct s2n_ecc_named_curve **found); +int s2n_ecc_evp_params_free(struct s2n_ecc_evp_params *ecc_evp_params); +int s2n_is_evp_apis_supported(); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_ecdsa.c b/contrib/restricted/aws/s2n/crypto/s2n_ecdsa.c index d1d37d1bee..05893201ca 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_ecdsa.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_ecdsa.c @@ -1,173 +1,173 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/ec.h> -#include <openssl/ecdsa.h> -#include <openssl/x509.h> -#include "stuffer/s2n_stuffer.h" - -#include "error/s2n_errno.h" -#include "utils/s2n_blob.h" -#include "utils/s2n_mem.h" -#include "utils/s2n_random.h" -#include "utils/s2n_safety.h" - -#include "crypto/s2n_ecdsa.h" -#include "crypto/s2n_ecc_evp.h" -#include "crypto/s2n_hash.h" -#include "crypto/s2n_openssl.h" -#include "crypto/s2n_pkey.h" - -int s2n_ecdsa_der_signature_size(const struct s2n_pkey *pkey) -{ - const struct s2n_ecdsa_key *ecdsa_key = &pkey->key.ecdsa_key; - notnull_check(ecdsa_key->ec_key); - - return ECDSA_size(ecdsa_key->ec_key); -} - -static int s2n_ecdsa_sign(const struct s2n_pkey *priv, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature) -{ - sig_alg_check(sig_alg, S2N_SIGNATURE_ECDSA); - - const s2n_ecdsa_private_key *key = &priv->key.ecdsa_key; - notnull_check(key->ec_key); - - uint8_t digest_length; - GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); - lte_check(digest_length, S2N_MAX_DIGEST_LEN); - - uint8_t digest_out[S2N_MAX_DIGEST_LEN]; - GUARD(s2n_hash_digest(digest, digest_out, digest_length)); - - unsigned int signature_size = signature->size; - GUARD_OSSL(ECDSA_sign(0, digest_out, digest_length, signature->data, &signature_size, key->ec_key), S2N_ERR_SIGN); - S2N_ERROR_IF(signature_size > signature->size, S2N_ERR_SIZE_MISMATCH); - signature->size = signature_size; - - GUARD(s2n_hash_reset(digest)); - - return 0; -} - -static int s2n_ecdsa_verify(const struct s2n_pkey *pub, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature) -{ - sig_alg_check(sig_alg, S2N_SIGNATURE_ECDSA); - - const s2n_ecdsa_public_key *key = &pub->key.ecdsa_key; - notnull_check(key->ec_key); - - uint8_t digest_length; - GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); - lte_check(digest_length, S2N_MAX_DIGEST_LEN); - - uint8_t digest_out[S2N_MAX_DIGEST_LEN]; - GUARD(s2n_hash_digest(digest, digest_out, digest_length)); - - /* ECDSA_verify ignores the first parameter */ - GUARD_OSSL(ECDSA_verify(0, digest_out, digest_length, signature->data, signature->size, key->ec_key), S2N_ERR_VERIFY_SIGNATURE); - - GUARD(s2n_hash_reset(digest)); - - return 0; -} - -static int s2n_ecdsa_keys_match(const struct s2n_pkey *pub, const struct s2n_pkey *priv) -{ - uint8_t input[16] = { 1 }; - DEFER_CLEANUP(struct s2n_blob signature = { 0 }, s2n_free); - DEFER_CLEANUP(struct s2n_hash_state state_in = { 0 }, s2n_hash_free); - DEFER_CLEANUP(struct s2n_hash_state state_out = { 0 }, s2n_hash_free); - - /* s2n_hash_new only allocates memory when using high-level EVP hashes, currently restricted to FIPS mode. */ - GUARD(s2n_hash_new(&state_in)); - GUARD(s2n_hash_new(&state_out)); - - GUARD(s2n_hash_init(&state_in, S2N_HASH_SHA1)); - GUARD(s2n_hash_init(&state_out, S2N_HASH_SHA1)); - GUARD(s2n_hash_update(&state_in, input, sizeof(input))); - GUARD(s2n_hash_update(&state_out, input, sizeof(input))); - - GUARD(s2n_alloc(&signature, s2n_ecdsa_der_signature_size(priv))); - - GUARD(s2n_ecdsa_sign(priv, S2N_SIGNATURE_ECDSA, &state_in, &signature)); - GUARD(s2n_ecdsa_verify(pub, S2N_SIGNATURE_ECDSA, &state_out, &signature)); - - return 0; -} - -static int s2n_ecdsa_key_free(struct s2n_pkey *pkey) -{ - struct s2n_ecdsa_key *ecdsa_key = &pkey->key.ecdsa_key; - if (ecdsa_key->ec_key == NULL) { - return 0; - } - - EC_KEY_free(ecdsa_key->ec_key); - ecdsa_key->ec_key = NULL; - - return 0; -} - -static int s2n_ecdsa_check_key_exists(const struct s2n_pkey *pkey) -{ - const struct s2n_ecdsa_key *ecdsa_key = &pkey->key.ecdsa_key; - notnull_check(ecdsa_key->ec_key); - return 0; -} - -int s2n_evp_pkey_to_ecdsa_private_key(s2n_ecdsa_private_key *ecdsa_key, EVP_PKEY *evp_private_key) -{ - EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(evp_private_key); - S2N_ERROR_IF(ec_key == NULL, S2N_ERR_DECODE_PRIVATE_KEY); - - ecdsa_key->ec_key = ec_key; - return 0; -} - -int s2n_evp_pkey_to_ecdsa_public_key(s2n_ecdsa_public_key *ecdsa_key, EVP_PKEY *evp_public_key) -{ - EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(evp_public_key); - S2N_ERROR_IF(ec_key == NULL, S2N_ERR_DECODE_CERTIFICATE); - - ecdsa_key->ec_key = ec_key; - return 0; -} - -int s2n_ecdsa_pkey_init(struct s2n_pkey *pkey) { - pkey->size = &s2n_ecdsa_der_signature_size; - pkey->sign = &s2n_ecdsa_sign; - pkey->verify = &s2n_ecdsa_verify; - pkey->encrypt = NULL; /* No function for encryption */ - pkey->decrypt = NULL; /* No function for decryption */ - pkey->match = &s2n_ecdsa_keys_match; - pkey->free = &s2n_ecdsa_key_free; - pkey->check_key = &s2n_ecdsa_check_key_exists; - return 0; -} - -int s2n_ecdsa_pkey_matches_curve(const struct s2n_ecdsa_key *ecdsa_key, const struct s2n_ecc_named_curve *curve) -{ - notnull_check(ecdsa_key); - notnull_check(ecdsa_key->ec_key); - notnull_check(curve); - - int curve_id = EC_GROUP_get_curve_name(EC_KEY_get0_group(ecdsa_key->ec_key)); - eq_check(curve_id, curve->libcrypto_nid); - - return 0; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/ec.h> +#include <openssl/ecdsa.h> +#include <openssl/x509.h> +#include "stuffer/s2n_stuffer.h" + +#include "error/s2n_errno.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_mem.h" +#include "utils/s2n_random.h" +#include "utils/s2n_safety.h" + +#include "crypto/s2n_ecdsa.h" +#include "crypto/s2n_ecc_evp.h" +#include "crypto/s2n_hash.h" +#include "crypto/s2n_openssl.h" +#include "crypto/s2n_pkey.h" + +int s2n_ecdsa_der_signature_size(const struct s2n_pkey *pkey) +{ + const struct s2n_ecdsa_key *ecdsa_key = &pkey->key.ecdsa_key; + notnull_check(ecdsa_key->ec_key); + + return ECDSA_size(ecdsa_key->ec_key); +} + +static int s2n_ecdsa_sign(const struct s2n_pkey *priv, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature) +{ + sig_alg_check(sig_alg, S2N_SIGNATURE_ECDSA); + + const s2n_ecdsa_private_key *key = &priv->key.ecdsa_key; + notnull_check(key->ec_key); + + uint8_t digest_length; + GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); + lte_check(digest_length, S2N_MAX_DIGEST_LEN); + + uint8_t digest_out[S2N_MAX_DIGEST_LEN]; + GUARD(s2n_hash_digest(digest, digest_out, digest_length)); + + unsigned int signature_size = signature->size; + GUARD_OSSL(ECDSA_sign(0, digest_out, digest_length, signature->data, &signature_size, key->ec_key), S2N_ERR_SIGN); + S2N_ERROR_IF(signature_size > signature->size, S2N_ERR_SIZE_MISMATCH); + signature->size = signature_size; + + GUARD(s2n_hash_reset(digest)); + + return 0; +} + +static int s2n_ecdsa_verify(const struct s2n_pkey *pub, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature) +{ + sig_alg_check(sig_alg, S2N_SIGNATURE_ECDSA); + + const s2n_ecdsa_public_key *key = &pub->key.ecdsa_key; + notnull_check(key->ec_key); + + uint8_t digest_length; + GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); + lte_check(digest_length, S2N_MAX_DIGEST_LEN); + + uint8_t digest_out[S2N_MAX_DIGEST_LEN]; + GUARD(s2n_hash_digest(digest, digest_out, digest_length)); + + /* ECDSA_verify ignores the first parameter */ + GUARD_OSSL(ECDSA_verify(0, digest_out, digest_length, signature->data, signature->size, key->ec_key), S2N_ERR_VERIFY_SIGNATURE); + + GUARD(s2n_hash_reset(digest)); + + return 0; +} + +static int s2n_ecdsa_keys_match(const struct s2n_pkey *pub, const struct s2n_pkey *priv) +{ + uint8_t input[16] = { 1 }; + DEFER_CLEANUP(struct s2n_blob signature = { 0 }, s2n_free); + DEFER_CLEANUP(struct s2n_hash_state state_in = { 0 }, s2n_hash_free); + DEFER_CLEANUP(struct s2n_hash_state state_out = { 0 }, s2n_hash_free); + + /* s2n_hash_new only allocates memory when using high-level EVP hashes, currently restricted to FIPS mode. */ + GUARD(s2n_hash_new(&state_in)); + GUARD(s2n_hash_new(&state_out)); + + GUARD(s2n_hash_init(&state_in, S2N_HASH_SHA1)); + GUARD(s2n_hash_init(&state_out, S2N_HASH_SHA1)); + GUARD(s2n_hash_update(&state_in, input, sizeof(input))); + GUARD(s2n_hash_update(&state_out, input, sizeof(input))); + + GUARD(s2n_alloc(&signature, s2n_ecdsa_der_signature_size(priv))); + + GUARD(s2n_ecdsa_sign(priv, S2N_SIGNATURE_ECDSA, &state_in, &signature)); + GUARD(s2n_ecdsa_verify(pub, S2N_SIGNATURE_ECDSA, &state_out, &signature)); + + return 0; +} + +static int s2n_ecdsa_key_free(struct s2n_pkey *pkey) +{ + struct s2n_ecdsa_key *ecdsa_key = &pkey->key.ecdsa_key; + if (ecdsa_key->ec_key == NULL) { + return 0; + } + + EC_KEY_free(ecdsa_key->ec_key); + ecdsa_key->ec_key = NULL; + + return 0; +} + +static int s2n_ecdsa_check_key_exists(const struct s2n_pkey *pkey) +{ + const struct s2n_ecdsa_key *ecdsa_key = &pkey->key.ecdsa_key; + notnull_check(ecdsa_key->ec_key); + return 0; +} + +int s2n_evp_pkey_to_ecdsa_private_key(s2n_ecdsa_private_key *ecdsa_key, EVP_PKEY *evp_private_key) +{ + EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(evp_private_key); + S2N_ERROR_IF(ec_key == NULL, S2N_ERR_DECODE_PRIVATE_KEY); + + ecdsa_key->ec_key = ec_key; + return 0; +} + +int s2n_evp_pkey_to_ecdsa_public_key(s2n_ecdsa_public_key *ecdsa_key, EVP_PKEY *evp_public_key) +{ + EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(evp_public_key); + S2N_ERROR_IF(ec_key == NULL, S2N_ERR_DECODE_CERTIFICATE); + + ecdsa_key->ec_key = ec_key; + return 0; +} + +int s2n_ecdsa_pkey_init(struct s2n_pkey *pkey) { + pkey->size = &s2n_ecdsa_der_signature_size; + pkey->sign = &s2n_ecdsa_sign; + pkey->verify = &s2n_ecdsa_verify; + pkey->encrypt = NULL; /* No function for encryption */ + pkey->decrypt = NULL; /* No function for decryption */ + pkey->match = &s2n_ecdsa_keys_match; + pkey->free = &s2n_ecdsa_key_free; + pkey->check_key = &s2n_ecdsa_check_key_exists; + return 0; +} + +int s2n_ecdsa_pkey_matches_curve(const struct s2n_ecdsa_key *ecdsa_key, const struct s2n_ecc_named_curve *curve) +{ + notnull_check(ecdsa_key); + notnull_check(ecdsa_key->ec_key); + notnull_check(curve); + + int curve_id = EC_GROUP_get_curve_name(EC_KEY_get0_group(ecdsa_key->ec_key)); + eq_check(curve_id, curve->libcrypto_nid); + + return 0; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_ecdsa.h b/contrib/restricted/aws/s2n/crypto/s2n_ecdsa.h index 6911cf4387..84216a99be 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_ecdsa.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_ecdsa.h @@ -1,43 +1,43 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <openssl/ecdsa.h> -#include <stdint.h> -#include <s2n.h> - -#include "stuffer/s2n_stuffer.h" - -#include "crypto/s2n_ecc_evp.h" -#include "crypto/s2n_hash.h" - -#include "utils/s2n_blob.h" - -/* Forward declaration to avoid the circular dependency with s2n_pkey.h */ -struct s2n_pkey; - -struct s2n_ecdsa_key { - EC_KEY *ec_key; -}; - -typedef struct s2n_ecdsa_key s2n_ecdsa_public_key; -typedef struct s2n_ecdsa_key s2n_ecdsa_private_key; - -extern int s2n_ecdsa_pkey_init(struct s2n_pkey *pkey); -extern int s2n_ecdsa_pkey_matches_curve(const struct s2n_ecdsa_key *ecdsa_key, const struct s2n_ecc_named_curve *curve); - -extern int s2n_evp_pkey_to_ecdsa_public_key(s2n_ecdsa_public_key *ecdsa_key, EVP_PKEY *pkey); -extern int s2n_evp_pkey_to_ecdsa_private_key(s2n_ecdsa_private_key *ecdsa_key, EVP_PKEY *pkey); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <openssl/ecdsa.h> +#include <stdint.h> +#include <s2n.h> + +#include "stuffer/s2n_stuffer.h" + +#include "crypto/s2n_ecc_evp.h" +#include "crypto/s2n_hash.h" + +#include "utils/s2n_blob.h" + +/* Forward declaration to avoid the circular dependency with s2n_pkey.h */ +struct s2n_pkey; + +struct s2n_ecdsa_key { + EC_KEY *ec_key; +}; + +typedef struct s2n_ecdsa_key s2n_ecdsa_public_key; +typedef struct s2n_ecdsa_key s2n_ecdsa_private_key; + +extern int s2n_ecdsa_pkey_init(struct s2n_pkey *pkey); +extern int s2n_ecdsa_pkey_matches_curve(const struct s2n_ecdsa_key *ecdsa_key, const struct s2n_ecc_named_curve *curve); + +extern int s2n_evp_pkey_to_ecdsa_public_key(s2n_ecdsa_public_key *ecdsa_key, EVP_PKEY *pkey); +extern int s2n_evp_pkey_to_ecdsa_private_key(s2n_ecdsa_private_key *ecdsa_key, EVP_PKEY *pkey); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_evp.c b/contrib/restricted/aws/s2n/crypto/s2n_evp.c index 11aac21f75..a8fad67b48 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_evp.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_evp.c @@ -1,47 +1,47 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include "crypto/s2n_evp.h" -#include "crypto/s2n_fips.h" -#include "error/s2n_errno.h" -#include "utils/s2n_safety.h" - -int s2n_digest_allow_md5_for_fips(struct s2n_evp_digest *evp_digest) -{ - notnull_check(evp_digest); - /* This is only to be used for EVP digests that will require MD5 to be used - * to comply with the TLS 1.0 and 1.1 RFC's for the PRF. MD5 cannot be used - * outside of the TLS 1.0 and 1.1 PRF when in FIPS mode. - */ - S2N_ERROR_IF(!s2n_is_in_fips_mode() || (evp_digest->ctx == NULL), S2N_ERR_ALLOW_MD5_FOR_FIPS_FAILED); - -#if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) - EVP_MD_CTX_set_flags(evp_digest->ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); -#endif - return S2N_SUCCESS; -} - -S2N_RESULT s2n_digest_is_md5_allowed_for_fips(struct s2n_evp_digest *evp_digest, bool *out) -{ - ENSURE_REF(out); - *out = false; -#if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) - if (evp_digest && evp_digest->ctx && s2n_is_in_fips_mode() && EVP_MD_CTX_test_flags(evp_digest->ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW)) { - /* s2n is in FIPS mode and the EVP digest allows MD5. */ - *out = true; - } -#endif - return S2N_RESULT_OK; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include "crypto/s2n_evp.h" +#include "crypto/s2n_fips.h" +#include "error/s2n_errno.h" +#include "utils/s2n_safety.h" + +int s2n_digest_allow_md5_for_fips(struct s2n_evp_digest *evp_digest) +{ + notnull_check(evp_digest); + /* This is only to be used for EVP digests that will require MD5 to be used + * to comply with the TLS 1.0 and 1.1 RFC's for the PRF. MD5 cannot be used + * outside of the TLS 1.0 and 1.1 PRF when in FIPS mode. + */ + S2N_ERROR_IF(!s2n_is_in_fips_mode() || (evp_digest->ctx == NULL), S2N_ERR_ALLOW_MD5_FOR_FIPS_FAILED); + +#if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) + EVP_MD_CTX_set_flags(evp_digest->ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); +#endif + return S2N_SUCCESS; +} + +S2N_RESULT s2n_digest_is_md5_allowed_for_fips(struct s2n_evp_digest *evp_digest, bool *out) +{ + ENSURE_REF(out); + *out = false; +#if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) + if (evp_digest && evp_digest->ctx && s2n_is_in_fips_mode() && EVP_MD_CTX_test_flags(evp_digest->ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW)) { + /* s2n is in FIPS mode and the EVP digest allows MD5. */ + *out = true; + } +#endif + return S2N_RESULT_OK; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_evp.h b/contrib/restricted/aws/s2n/crypto/s2n_evp.h index 92d30bccc8..80a059df2b 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_evp.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_evp.h @@ -1,45 +1,45 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <openssl/evp.h> - -#include "crypto/s2n_openssl.h" -#include "utils/s2n_result.h" - -struct s2n_evp_digest { - const EVP_MD *md; - EVP_MD_CTX *ctx; -}; - -struct s2n_evp_hmac_state { - struct s2n_evp_digest evp_digest; - EVP_PKEY *mac_key; -}; - -/* Define API's that change based on the OpenSSL Major Version. */ -#if S2N_OPENSSL_VERSION_AT_LEAST(1,1,0) && !defined(LIBRESSL_VERSION_NUMBER) -#define S2N_EVP_MD_CTX_NEW() (EVP_MD_CTX_new()) -#define S2N_EVP_MD_CTX_RESET(md_ctx) (EVP_MD_CTX_reset(md_ctx)) -#define S2N_EVP_MD_CTX_FREE(md_ctx) (EVP_MD_CTX_free(md_ctx)) -#else -#define S2N_EVP_MD_CTX_NEW() (EVP_MD_CTX_create()) -#define S2N_EVP_MD_CTX_RESET(md_ctx) (EVP_MD_CTX_cleanup(md_ctx)) -#define S2N_EVP_MD_CTX_FREE(md_ctx) (EVP_MD_CTX_destroy(md_ctx)) -#endif - -extern int s2n_digest_allow_md5_for_fips(struct s2n_evp_digest *evp_digest); -extern S2N_RESULT s2n_digest_is_md5_allowed_for_fips(struct s2n_evp_digest *evp_digest, bool *out); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <openssl/evp.h> + +#include "crypto/s2n_openssl.h" +#include "utils/s2n_result.h" + +struct s2n_evp_digest { + const EVP_MD *md; + EVP_MD_CTX *ctx; +}; + +struct s2n_evp_hmac_state { + struct s2n_evp_digest evp_digest; + EVP_PKEY *mac_key; +}; + +/* Define API's that change based on the OpenSSL Major Version. */ +#if S2N_OPENSSL_VERSION_AT_LEAST(1,1,0) && !defined(LIBRESSL_VERSION_NUMBER) +#define S2N_EVP_MD_CTX_NEW() (EVP_MD_CTX_new()) +#define S2N_EVP_MD_CTX_RESET(md_ctx) (EVP_MD_CTX_reset(md_ctx)) +#define S2N_EVP_MD_CTX_FREE(md_ctx) (EVP_MD_CTX_free(md_ctx)) +#else +#define S2N_EVP_MD_CTX_NEW() (EVP_MD_CTX_create()) +#define S2N_EVP_MD_CTX_RESET(md_ctx) (EVP_MD_CTX_cleanup(md_ctx)) +#define S2N_EVP_MD_CTX_FREE(md_ctx) (EVP_MD_CTX_destroy(md_ctx)) +#endif + +extern int s2n_digest_allow_md5_for_fips(struct s2n_evp_digest *evp_digest); +extern S2N_RESULT s2n_digest_is_md5_allowed_for_fips(struct s2n_evp_digest *evp_digest, bool *out); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_fips.c b/contrib/restricted/aws/s2n/crypto/s2n_fips.c index d939cc3b53..d8ae231c15 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_fips.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_fips.c @@ -1,40 +1,40 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/crypto.h> - -#include "crypto/s2n_fips.h" - -static int s2n_fips_mode = 0; - -int s2n_fips_init(void) -{ - s2n_fips_mode = 0; - -#ifdef OPENSSL_FIPS - /* FIPS mode can be entered only if OPENSSL_FIPS is defined */ - if (FIPS_mode()) { - s2n_fips_mode = 1; - } -#endif - - return 0; -} - -/* Return 1 if FIPS mode is enabled, 0 otherwise. FIPS mode must be enabled prior to calling s2n_init(). */ -int s2n_is_in_fips_mode(void) -{ - return s2n_fips_mode; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/crypto.h> + +#include "crypto/s2n_fips.h" + +static int s2n_fips_mode = 0; + +int s2n_fips_init(void) +{ + s2n_fips_mode = 0; + +#ifdef OPENSSL_FIPS + /* FIPS mode can be entered only if OPENSSL_FIPS is defined */ + if (FIPS_mode()) { + s2n_fips_mode = 1; + } +#endif + + return 0; +} + +/* Return 1 if FIPS mode is enabled, 0 otherwise. FIPS mode must be enabled prior to calling s2n_init(). */ +int s2n_is_in_fips_mode(void) +{ + return s2n_fips_mode; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_fips.h b/contrib/restricted/aws/s2n/crypto/s2n_fips.h index 23c3ea4bd0..7f54a24371 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_fips.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_fips.h @@ -1,19 +1,19 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -extern int s2n_fips_init(void); -extern int s2n_is_in_fips_mode(void); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +extern int s2n_fips_init(void); +extern int s2n_is_in_fips_mode(void); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_hash.c b/contrib/restricted/aws/s2n/crypto/s2n_hash.c index 0a3ad28130..9aef3bd400 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_hash.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_hash.c @@ -1,647 +1,647 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include "error/s2n_errno.h" - -#include "crypto/s2n_hash.h" -#include "crypto/s2n_hmac.h" -#include "crypto/s2n_openssl.h" -#include "crypto/s2n_fips.h" - -#include "utils/s2n_safety.h" - -int s2n_hash_hmac_alg(s2n_hash_algorithm hash_alg, s2n_hmac_algorithm *out) -{ - ENSURE_POSIX(S2N_MEM_IS_READABLE(out, sizeof(*out)), S2N_ERR_PRECONDITION_VIOLATION); - switch(hash_alg) { - case S2N_HASH_NONE: *out = S2N_HMAC_NONE; break; - case S2N_HASH_MD5: *out = S2N_HMAC_MD5; break; - case S2N_HASH_SHA1: *out = S2N_HMAC_SHA1; break; - case S2N_HASH_SHA224: *out = S2N_HMAC_SHA224; break; - case S2N_HASH_SHA256: *out = S2N_HMAC_SHA256; break; - case S2N_HASH_SHA384: *out = S2N_HMAC_SHA384; break; - case S2N_HASH_SHA512: *out = S2N_HMAC_SHA512; break; - case S2N_HASH_MD5_SHA1: /* Fall through ... */ - default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } - return S2N_SUCCESS; -} - -int s2n_hash_digest_size(s2n_hash_algorithm alg, uint8_t *out) -{ - notnull_check(out); - switch (alg) { - case S2N_HASH_NONE: *out = 0; break; - case S2N_HASH_MD5: *out = MD5_DIGEST_LENGTH; break; - case S2N_HASH_SHA1: *out = SHA_DIGEST_LENGTH; break; - case S2N_HASH_SHA224: *out = SHA224_DIGEST_LENGTH; break; - case S2N_HASH_SHA256: *out = SHA256_DIGEST_LENGTH; break; - case S2N_HASH_SHA384: *out = SHA384_DIGEST_LENGTH; break; - case S2N_HASH_SHA512: *out = SHA512_DIGEST_LENGTH; break; - case S2N_HASH_MD5_SHA1: *out = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH; break; - default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } - return S2N_SUCCESS; -} - -/* NOTE: s2n_hash_const_time_get_currently_in_hash_block takes advantage of the fact that - * hash_block_size is a power of 2. This is true for all hashes we currently support - * If this ever becomes untrue, this would require fixing*/ -int s2n_hash_block_size(s2n_hash_algorithm alg, uint64_t *block_size) -{ - ENSURE_POSIX(S2N_MEM_IS_READABLE(block_size, sizeof(*block_size)), S2N_ERR_PRECONDITION_VIOLATION); - switch(alg) { - case S2N_HASH_NONE: *block_size = 64; break; - case S2N_HASH_MD5: *block_size = 64; break; - case S2N_HASH_SHA1: *block_size = 64; break; - case S2N_HASH_SHA224: *block_size = 64; break; - case S2N_HASH_SHA256: *block_size = 64; break; - case S2N_HASH_SHA384: *block_size = 128; break; - case S2N_HASH_SHA512: *block_size = 128; break; - case S2N_HASH_MD5_SHA1: *block_size = 64; break; - default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } - return S2N_SUCCESS; -} - -/* Return true if hash algorithm is available, false otherwise. */ -bool s2n_hash_is_available(s2n_hash_algorithm alg) -{ - switch (alg) { - case S2N_HASH_MD5: - case S2N_HASH_MD5_SHA1: - /* return false if in FIPS mode, as MD5 algs are not available in FIPS mode. */ - return !s2n_is_in_fips_mode(); - case S2N_HASH_NONE: - case S2N_HASH_SHA1: - case S2N_HASH_SHA224: - case S2N_HASH_SHA256: - case S2N_HASH_SHA384: - case S2N_HASH_SHA512: - return true; - case S2N_HASH_SENTINEL: - return false; - } - return false; -} - -int s2n_hash_is_ready_for_input(struct s2n_hash_state *state) -{ - PRECONDITION_POSIX(s2n_hash_state_validate(state)); - return state->is_ready_for_input; -} - -static int s2n_low_level_hash_new(struct s2n_hash_state *state) -{ - /* s2n_hash_new will always call the corresponding implementation of the s2n_hash - * being used. For the s2n_low_level_hash implementation, new is a no-op. - */ - - state->is_ready_for_input = 0; - state->currently_in_hash = 0; - return S2N_SUCCESS; -} - -static int s2n_low_level_hash_init(struct s2n_hash_state *state, s2n_hash_algorithm alg) -{ - switch (alg) { - case S2N_HASH_NONE: - break; - case S2N_HASH_MD5: - GUARD_OSSL(MD5_Init(&state->digest.low_level.md5), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_SHA1: - GUARD_OSSL(SHA1_Init(&state->digest.low_level.sha1), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_SHA224: - GUARD_OSSL(SHA224_Init(&state->digest.low_level.sha224), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_SHA256: - GUARD_OSSL(SHA256_Init(&state->digest.low_level.sha256), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_SHA384: - GUARD_OSSL(SHA384_Init(&state->digest.low_level.sha384), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_SHA512: - GUARD_OSSL(SHA512_Init(&state->digest.low_level.sha512), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_MD5_SHA1: - GUARD_OSSL(SHA1_Init(&state->digest.low_level.md5_sha1.sha1), S2N_ERR_HASH_INIT_FAILED);; - GUARD_OSSL(MD5_Init(&state->digest.low_level.md5_sha1.md5), S2N_ERR_HASH_INIT_FAILED);; - break; - - default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } - - state->alg = alg; - state->is_ready_for_input = 1; - state->currently_in_hash = 0; - - return 0; -} - -static int s2n_low_level_hash_update(struct s2n_hash_state *state, const void *data, uint32_t size) -{ - ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); - - switch (state->alg) { - case S2N_HASH_NONE: - break; - case S2N_HASH_MD5: - GUARD_OSSL(MD5_Update(&state->digest.low_level.md5, data, size), S2N_ERR_HASH_UPDATE_FAILED); - break; - case S2N_HASH_SHA1: - GUARD_OSSL(SHA1_Update(&state->digest.low_level.sha1, data, size), S2N_ERR_HASH_UPDATE_FAILED); - break; - case S2N_HASH_SHA224: - GUARD_OSSL(SHA224_Update(&state->digest.low_level.sha224, data, size), S2N_ERR_HASH_UPDATE_FAILED); - break; - case S2N_HASH_SHA256: - GUARD_OSSL(SHA256_Update(&state->digest.low_level.sha256, data, size), S2N_ERR_HASH_UPDATE_FAILED); - break; - case S2N_HASH_SHA384: - GUARD_OSSL(SHA384_Update(&state->digest.low_level.sha384, data, size), S2N_ERR_HASH_UPDATE_FAILED); - break; - case S2N_HASH_SHA512: - GUARD_OSSL(SHA512_Update(&state->digest.low_level.sha512, data, size), S2N_ERR_HASH_UPDATE_FAILED); - break; - case S2N_HASH_MD5_SHA1: - GUARD_OSSL(SHA1_Update(&state->digest.low_level.md5_sha1.sha1, data, size), S2N_ERR_HASH_UPDATE_FAILED); - GUARD_OSSL(MD5_Update(&state->digest.low_level.md5_sha1.md5, data, size), S2N_ERR_HASH_UPDATE_FAILED); - break; - default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } - - ENSURE_POSIX(size <= (UINT64_MAX - state->currently_in_hash), S2N_ERR_INTEGER_OVERFLOW); - state->currently_in_hash += size; - - return S2N_SUCCESS; -} - -static int s2n_low_level_hash_digest(struct s2n_hash_state *state, void *out, uint32_t size) -{ - ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); - - switch (state->alg) { - case S2N_HASH_NONE: - break; - case S2N_HASH_MD5: - eq_check(size, MD5_DIGEST_LENGTH); - GUARD_OSSL(MD5_Final(out, &state->digest.low_level.md5), S2N_ERR_HASH_DIGEST_FAILED); - break; - case S2N_HASH_SHA1: - eq_check(size, SHA_DIGEST_LENGTH); - GUARD_OSSL(SHA1_Final(out, &state->digest.low_level.sha1), S2N_ERR_HASH_DIGEST_FAILED); - break; - case S2N_HASH_SHA224: - eq_check(size, SHA224_DIGEST_LENGTH); - GUARD_OSSL(SHA224_Final(out, &state->digest.low_level.sha224), S2N_ERR_HASH_DIGEST_FAILED); - break; - case S2N_HASH_SHA256: - eq_check(size, SHA256_DIGEST_LENGTH); - GUARD_OSSL(SHA256_Final(out, &state->digest.low_level.sha256), S2N_ERR_HASH_DIGEST_FAILED); - break; - case S2N_HASH_SHA384: - eq_check(size, SHA384_DIGEST_LENGTH); - GUARD_OSSL(SHA384_Final(out, &state->digest.low_level.sha384), S2N_ERR_HASH_DIGEST_FAILED); - break; - case S2N_HASH_SHA512: - eq_check(size, SHA512_DIGEST_LENGTH); - GUARD_OSSL(SHA512_Final(out, &state->digest.low_level.sha512), S2N_ERR_HASH_DIGEST_FAILED); - break; - case S2N_HASH_MD5_SHA1: - eq_check(size, MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH); - GUARD_OSSL(SHA1_Final(((uint8_t *) out) + MD5_DIGEST_LENGTH, &state->digest.low_level.md5_sha1.sha1), S2N_ERR_HASH_DIGEST_FAILED); - GUARD_OSSL(MD5_Final(out, &state->digest.low_level.md5_sha1.md5), S2N_ERR_HASH_DIGEST_FAILED); - break; - default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } - - state->currently_in_hash = 0; - state->is_ready_for_input = 0; - return 0; -} - -static int s2n_low_level_hash_copy(struct s2n_hash_state *to, struct s2n_hash_state *from) -{ - memcpy_check(to, from, sizeof(struct s2n_hash_state)); - return 0; -} - -static int s2n_low_level_hash_reset(struct s2n_hash_state *state) -{ - /* hash_init resets the ready_for_input and currently_in_hash fields. */ - return s2n_low_level_hash_init(state, state->alg); -} - -static int s2n_low_level_hash_free(struct s2n_hash_state *state) -{ - /* s2n_hash_free will always call the corresponding implementation of the s2n_hash - * being used. For the s2n_low_level_hash implementation, free is a no-op. - */ - state->is_ready_for_input = 0; - return S2N_SUCCESS; -} - -static int s2n_evp_hash_new(struct s2n_hash_state *state) -{ - notnull_check(state->digest.high_level.evp.ctx = S2N_EVP_MD_CTX_NEW()); - notnull_check(state->digest.high_level.evp_md5_secondary.ctx = S2N_EVP_MD_CTX_NEW()); - state->is_ready_for_input = 0; - state->currently_in_hash = 0; - - return S2N_SUCCESS; -} - -static int s2n_evp_hash_allow_md5_for_fips(struct s2n_hash_state *state) -{ - /* This is only to be used for s2n_hash_states that will require MD5 to be used - * to comply with the TLS 1.0 and 1.1 RFC's for the PRF. MD5 cannot be used - * outside of the TLS 1.0 and 1.1 PRF when in FIPS mode. When needed, this must - * be called prior to s2n_hash_init(). - */ - GUARD(s2n_digest_allow_md5_for_fips(&state->digest.high_level.evp_md5_secondary)); - return s2n_digest_allow_md5_for_fips(&state->digest.high_level.evp); -} - -static int s2n_evp_hash_init(struct s2n_hash_state *state, s2n_hash_algorithm alg) -{ - notnull_check(state->digest.high_level.evp.ctx); - notnull_check(state->digest.high_level.evp_md5_secondary.ctx); - switch (alg) { - case S2N_HASH_NONE: - break; - case S2N_HASH_MD5: - GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_md5(), NULL), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_SHA1: - GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha1(), NULL), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_SHA224: - GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha224(), NULL), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_SHA256: - GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha256(), NULL), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_SHA384: - GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha384(), NULL), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_SHA512: - GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha512(), NULL), S2N_ERR_HASH_INIT_FAILED); - break; - case S2N_HASH_MD5_SHA1: - GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha1(), NULL), S2N_ERR_HASH_INIT_FAILED); - GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp_md5_secondary.ctx, EVP_md5(), NULL), S2N_ERR_HASH_INIT_FAILED); - break; - default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } - - state->alg = alg; - state->is_ready_for_input = 1; - state->currently_in_hash = 0; - - return S2N_SUCCESS; -} - -static int s2n_evp_hash_update(struct s2n_hash_state *state, const void *data, uint32_t size) -{ - ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); - - switch (state->alg) { - case S2N_HASH_NONE: - break; - case S2N_HASH_MD5: - case S2N_HASH_SHA1: - case S2N_HASH_SHA224: - case S2N_HASH_SHA256: - case S2N_HASH_SHA384: - case S2N_HASH_SHA512: - notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp.ctx)); - GUARD_OSSL(EVP_DigestUpdate(state->digest.high_level.evp.ctx, data, size), S2N_ERR_HASH_UPDATE_FAILED); - break; - case S2N_HASH_MD5_SHA1: - notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp.ctx)); - notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp_md5_secondary.ctx)); - GUARD_OSSL(EVP_DigestUpdate(state->digest.high_level.evp.ctx, data, size), S2N_ERR_HASH_UPDATE_FAILED); - GUARD_OSSL(EVP_DigestUpdate(state->digest.high_level.evp_md5_secondary.ctx, data, size), S2N_ERR_HASH_UPDATE_FAILED); - break; - default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } - - ENSURE_POSIX(size <= (UINT64_MAX - state->currently_in_hash), S2N_ERR_INTEGER_OVERFLOW); - state->currently_in_hash += size; - - return S2N_SUCCESS; -} - -static int s2n_evp_hash_digest(struct s2n_hash_state *state, void *out, uint32_t size) -{ - ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); - - unsigned int digest_size = size; - uint8_t expected_digest_size; - GUARD(s2n_hash_digest_size(state->alg, &expected_digest_size)); - eq_check(digest_size, expected_digest_size); - - /* Used for S2N_HASH_MD5_SHA1 case to specify the exact size of each digest. */ - uint8_t sha1_digest_size; - unsigned int sha1_primary_digest_size; - unsigned int md5_secondary_digest_size; - - switch (state->alg) { - case S2N_HASH_NONE: - break; - case S2N_HASH_MD5: - case S2N_HASH_SHA1: - case S2N_HASH_SHA224: - case S2N_HASH_SHA256: - case S2N_HASH_SHA384: - case S2N_HASH_SHA512: - notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp.ctx)); - ENSURE_POSIX(EVP_MD_CTX_size(state->digest.high_level.evp.ctx) <= digest_size, S2N_ERR_HASH_DIGEST_FAILED); - GUARD_OSSL(EVP_DigestFinal_ex(state->digest.high_level.evp.ctx, out, &digest_size), S2N_ERR_HASH_DIGEST_FAILED); - break; - case S2N_HASH_MD5_SHA1: - notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp.ctx)); - notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp_md5_secondary.ctx)); - GUARD(s2n_hash_digest_size(S2N_HASH_SHA1, &sha1_digest_size)); - sha1_primary_digest_size = sha1_digest_size; - md5_secondary_digest_size = digest_size - sha1_primary_digest_size; - ENSURE_POSIX(EVP_MD_CTX_size(state->digest.high_level.evp.ctx) <= sha1_digest_size, S2N_ERR_HASH_DIGEST_FAILED); - ENSURE_POSIX(EVP_MD_CTX_size(state->digest.high_level.evp_md5_secondary.ctx) <= md5_secondary_digest_size, S2N_ERR_HASH_DIGEST_FAILED); - - GUARD_OSSL(EVP_DigestFinal_ex(state->digest.high_level.evp.ctx, ((uint8_t *) out) + MD5_DIGEST_LENGTH, &sha1_primary_digest_size), S2N_ERR_HASH_DIGEST_FAILED); - GUARD_OSSL(EVP_DigestFinal_ex(state->digest.high_level.evp_md5_secondary.ctx, out, &md5_secondary_digest_size), S2N_ERR_HASH_DIGEST_FAILED); - break; - default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } - - state->currently_in_hash = 0; - state->is_ready_for_input = 0; - return S2N_SUCCESS; -} - -static int s2n_evp_hash_copy(struct s2n_hash_state *to, struct s2n_hash_state *from) -{ - bool is_md5_allowed_for_fips = false; - switch (from->alg) { - case S2N_HASH_NONE: - break; - case S2N_HASH_MD5: - GUARD_AS_POSIX(s2n_digest_is_md5_allowed_for_fips(&from->digest.high_level.evp, &is_md5_allowed_for_fips)); - if (is_md5_allowed_for_fips) { - GUARD(s2n_hash_allow_md5_for_fips(to)); - } - FALL_THROUGH; - case S2N_HASH_SHA1: - case S2N_HASH_SHA224: - case S2N_HASH_SHA256: - case S2N_HASH_SHA384: - case S2N_HASH_SHA512: - notnull_check(to->digest.high_level.evp.ctx); - GUARD_OSSL(EVP_MD_CTX_copy_ex(to->digest.high_level.evp.ctx, from->digest.high_level.evp.ctx), S2N_ERR_HASH_COPY_FAILED); - break; - case S2N_HASH_MD5_SHA1: - notnull_check(to->digest.high_level.evp.ctx); - notnull_check(to->digest.high_level.evp_md5_secondary.ctx); - GUARD_AS_POSIX(s2n_digest_is_md5_allowed_for_fips(&from->digest.high_level.evp, &is_md5_allowed_for_fips)); - if (is_md5_allowed_for_fips) { - GUARD(s2n_hash_allow_md5_for_fips(to)); - } - GUARD_OSSL(EVP_MD_CTX_copy_ex(to->digest.high_level.evp.ctx, from->digest.high_level.evp.ctx), S2N_ERR_HASH_COPY_FAILED); - GUARD_OSSL(EVP_MD_CTX_copy_ex(to->digest.high_level.evp_md5_secondary.ctx, from->digest.high_level.evp_md5_secondary.ctx), S2N_ERR_HASH_COPY_FAILED); - break; - default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } - - to->hash_impl = from->hash_impl; - to->alg = from->alg; - to->is_ready_for_input = from->is_ready_for_input; - to->currently_in_hash = from->currently_in_hash; - - return S2N_SUCCESS; -} - -static int s2n_evp_hash_reset(struct s2n_hash_state *state) -{ - int reset_md5_for_fips = 0; - bool is_md5_allowed_for_fips = false; - GUARD_AS_POSIX(s2n_digest_is_md5_allowed_for_fips(&state->digest.high_level.evp, &is_md5_allowed_for_fips)); - if ((state->alg == S2N_HASH_MD5 || state->alg == S2N_HASH_MD5_SHA1) && is_md5_allowed_for_fips) { - reset_md5_for_fips = 1; - } - - GUARD_OSSL(S2N_EVP_MD_CTX_RESET(state->digest.high_level.evp.ctx), S2N_ERR_HASH_WIPE_FAILED); - - if (state->alg == S2N_HASH_MD5_SHA1) { - GUARD_OSSL(S2N_EVP_MD_CTX_RESET(state->digest.high_level.evp_md5_secondary.ctx), S2N_ERR_HASH_WIPE_FAILED); - } - - if (reset_md5_for_fips) { - GUARD(s2n_hash_allow_md5_for_fips(state)); - } - - /* hash_init resets the ready_for_input and currently_in_hash fields. */ - return s2n_evp_hash_init(state, state->alg); -} - -static int s2n_evp_hash_free(struct s2n_hash_state *state) -{ - S2N_EVP_MD_CTX_FREE(state->digest.high_level.evp.ctx); - S2N_EVP_MD_CTX_FREE(state->digest.high_level.evp_md5_secondary.ctx); - state->digest.high_level.evp.ctx = NULL; - state->digest.high_level.evp_md5_secondary.ctx = NULL; - state->is_ready_for_input = 0; - return S2N_SUCCESS; -} - -static const struct s2n_hash s2n_low_level_hash = { - .alloc = &s2n_low_level_hash_new, - .allow_md5_for_fips = NULL, - .init = &s2n_low_level_hash_init, - .update = &s2n_low_level_hash_update, - .digest = &s2n_low_level_hash_digest, - .copy = &s2n_low_level_hash_copy, - .reset = &s2n_low_level_hash_reset, - .free = &s2n_low_level_hash_free, -}; - -static const struct s2n_hash s2n_evp_hash = { - .alloc = &s2n_evp_hash_new, - .allow_md5_for_fips = &s2n_evp_hash_allow_md5_for_fips, - .init = &s2n_evp_hash_init, - .update = &s2n_evp_hash_update, - .digest = &s2n_evp_hash_digest, - .copy = &s2n_evp_hash_copy, - .reset = &s2n_evp_hash_reset, - .free = &s2n_evp_hash_free, -}; - -static int s2n_hash_set_impl(struct s2n_hash_state *state) -{ - state->hash_impl = s2n_is_in_fips_mode() ? &s2n_evp_hash : &s2n_low_level_hash; - - return S2N_SUCCESS; -} - -int s2n_hash_new(struct s2n_hash_state *state) -{ - notnull_check(state); - /* Set hash_impl on initial hash creation. - * When in FIPS mode, the EVP API's must be used for hashes. - */ - GUARD(s2n_hash_set_impl(state)); - - notnull_check(state->hash_impl->alloc); - - GUARD(state->hash_impl->alloc(state)); - return S2N_SUCCESS; -} - -S2N_RESULT s2n_hash_state_validate(struct s2n_hash_state *state) -{ - ENSURE_REF(state); - ENSURE_REF(state->hash_impl); - return S2N_RESULT_OK; -} - -int s2n_hash_allow_md5_for_fips(struct s2n_hash_state *state) -{ - notnull_check(state); - /* Ensure that hash_impl is set, as it may have been reset for s2n_hash_state on s2n_connection_wipe. - * When in FIPS mode, the EVP API's must be used for hashes. - */ - GUARD(s2n_hash_set_impl(state)); - - notnull_check(state->hash_impl->allow_md5_for_fips); - - return state->hash_impl->allow_md5_for_fips(state); -} - -int s2n_hash_init(struct s2n_hash_state *state, s2n_hash_algorithm alg) -{ - notnull_check(state); - /* Ensure that hash_impl is set, as it may have been reset for s2n_hash_state on s2n_connection_wipe. - * When in FIPS mode, the EVP API's must be used for hashes. - */ - GUARD(s2n_hash_set_impl(state)); - - bool is_md5_allowed_for_fips = false; - GUARD_AS_POSIX(s2n_digest_is_md5_allowed_for_fips(&state->digest.high_level.evp, &is_md5_allowed_for_fips)); - - if (s2n_hash_is_available(alg) || - ((alg == S2N_HASH_MD5 || alg == S2N_HASH_MD5_SHA1) && is_md5_allowed_for_fips)) { - /* s2n will continue to initialize an "unavailable" hash when s2n is in FIPS mode and - * FIPS is forcing the hash to be made available. - */ - notnull_check(state->hash_impl->init); - - return state->hash_impl->init(state, alg); - } else { - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } -} - -int s2n_hash_update(struct s2n_hash_state *state, const void *data, uint32_t size) -{ - PRECONDITION_POSIX(s2n_hash_state_validate(state)); - ENSURE_POSIX(S2N_MEM_IS_READABLE(data, size), S2N_ERR_PRECONDITION_VIOLATION); - notnull_check(state->hash_impl->update); - - return state->hash_impl->update(state, data, size); -} - -int s2n_hash_digest(struct s2n_hash_state *state, void *out, uint32_t size) -{ - PRECONDITION_POSIX(s2n_hash_state_validate(state)); - ENSURE_POSIX(S2N_MEM_IS_READABLE(out, size), S2N_ERR_PRECONDITION_VIOLATION); - notnull_check(state->hash_impl->digest); - - return state->hash_impl->digest(state, out, size); -} - -int s2n_hash_copy(struct s2n_hash_state *to, struct s2n_hash_state *from) -{ - PRECONDITION_POSIX(s2n_hash_state_validate(to)); - PRECONDITION_POSIX(s2n_hash_state_validate(from)); - notnull_check(from->hash_impl->copy); - - return from->hash_impl->copy(to, from); -} - -int s2n_hash_reset(struct s2n_hash_state *state) -{ - notnull_check(state); - /* Ensure that hash_impl is set, as it may have been reset for s2n_hash_state on s2n_connection_wipe. - * When in FIPS mode, the EVP API's must be used for hashes. - */ - GUARD(s2n_hash_set_impl(state)); - - notnull_check(state->hash_impl->reset); - - return state->hash_impl->reset(state); -} - -int s2n_hash_free(struct s2n_hash_state *state) -{ - if (state == NULL) - { - return S2N_SUCCESS; - } - /* Ensure that hash_impl is set, as it may have been reset for s2n_hash_state on s2n_connection_wipe. - * When in FIPS mode, the EVP API's must be used for hashes. - */ - GUARD(s2n_hash_set_impl(state)); - - notnull_check(state->hash_impl->free); - - return state->hash_impl->free(state); -} - -int s2n_hash_get_currently_in_hash_total(struct s2n_hash_state *state, uint64_t *out) -{ - PRECONDITION_POSIX(s2n_hash_state_validate(state)); - ENSURE_POSIX(S2N_MEM_IS_READABLE(out, sizeof(*out)), S2N_ERR_PRECONDITION_VIOLATION); - ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); - - *out = state->currently_in_hash; - return S2N_SUCCESS; -} - - -/* Calculate, in constant time, the number of bytes currently in the hash_block */ -int s2n_hash_const_time_get_currently_in_hash_block(struct s2n_hash_state *state, uint64_t *out) -{ - PRECONDITION_POSIX(s2n_hash_state_validate(state)); - ENSURE_POSIX(S2N_MEM_IS_READABLE(out, sizeof(*out)), S2N_ERR_PRECONDITION_VIOLATION); - ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); - uint64_t hash_block_size; - GUARD(s2n_hash_block_size(state->alg, &hash_block_size)); - - /* Requires that hash_block_size is a power of 2. This is true for all hashes we currently support - * If this ever becomes untrue, this would require fixing this*/ - *out = state->currently_in_hash & (hash_block_size - 1); - return S2N_SUCCESS; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include "error/s2n_errno.h" + +#include "crypto/s2n_hash.h" +#include "crypto/s2n_hmac.h" +#include "crypto/s2n_openssl.h" +#include "crypto/s2n_fips.h" + +#include "utils/s2n_safety.h" + +int s2n_hash_hmac_alg(s2n_hash_algorithm hash_alg, s2n_hmac_algorithm *out) +{ + ENSURE_POSIX(S2N_MEM_IS_READABLE(out, sizeof(*out)), S2N_ERR_PRECONDITION_VIOLATION); + switch(hash_alg) { + case S2N_HASH_NONE: *out = S2N_HMAC_NONE; break; + case S2N_HASH_MD5: *out = S2N_HMAC_MD5; break; + case S2N_HASH_SHA1: *out = S2N_HMAC_SHA1; break; + case S2N_HASH_SHA224: *out = S2N_HMAC_SHA224; break; + case S2N_HASH_SHA256: *out = S2N_HMAC_SHA256; break; + case S2N_HASH_SHA384: *out = S2N_HMAC_SHA384; break; + case S2N_HASH_SHA512: *out = S2N_HMAC_SHA512; break; + case S2N_HASH_MD5_SHA1: /* Fall through ... */ + default: + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } + return S2N_SUCCESS; +} + +int s2n_hash_digest_size(s2n_hash_algorithm alg, uint8_t *out) +{ + notnull_check(out); + switch (alg) { + case S2N_HASH_NONE: *out = 0; break; + case S2N_HASH_MD5: *out = MD5_DIGEST_LENGTH; break; + case S2N_HASH_SHA1: *out = SHA_DIGEST_LENGTH; break; + case S2N_HASH_SHA224: *out = SHA224_DIGEST_LENGTH; break; + case S2N_HASH_SHA256: *out = SHA256_DIGEST_LENGTH; break; + case S2N_HASH_SHA384: *out = SHA384_DIGEST_LENGTH; break; + case S2N_HASH_SHA512: *out = SHA512_DIGEST_LENGTH; break; + case S2N_HASH_MD5_SHA1: *out = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH; break; + default: + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } + return S2N_SUCCESS; +} + +/* NOTE: s2n_hash_const_time_get_currently_in_hash_block takes advantage of the fact that + * hash_block_size is a power of 2. This is true for all hashes we currently support + * If this ever becomes untrue, this would require fixing*/ +int s2n_hash_block_size(s2n_hash_algorithm alg, uint64_t *block_size) +{ + ENSURE_POSIX(S2N_MEM_IS_READABLE(block_size, sizeof(*block_size)), S2N_ERR_PRECONDITION_VIOLATION); + switch(alg) { + case S2N_HASH_NONE: *block_size = 64; break; + case S2N_HASH_MD5: *block_size = 64; break; + case S2N_HASH_SHA1: *block_size = 64; break; + case S2N_HASH_SHA224: *block_size = 64; break; + case S2N_HASH_SHA256: *block_size = 64; break; + case S2N_HASH_SHA384: *block_size = 128; break; + case S2N_HASH_SHA512: *block_size = 128; break; + case S2N_HASH_MD5_SHA1: *block_size = 64; break; + default: + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } + return S2N_SUCCESS; +} + +/* Return true if hash algorithm is available, false otherwise. */ +bool s2n_hash_is_available(s2n_hash_algorithm alg) +{ + switch (alg) { + case S2N_HASH_MD5: + case S2N_HASH_MD5_SHA1: + /* return false if in FIPS mode, as MD5 algs are not available in FIPS mode. */ + return !s2n_is_in_fips_mode(); + case S2N_HASH_NONE: + case S2N_HASH_SHA1: + case S2N_HASH_SHA224: + case S2N_HASH_SHA256: + case S2N_HASH_SHA384: + case S2N_HASH_SHA512: + return true; + case S2N_HASH_SENTINEL: + return false; + } + return false; +} + +int s2n_hash_is_ready_for_input(struct s2n_hash_state *state) +{ + PRECONDITION_POSIX(s2n_hash_state_validate(state)); + return state->is_ready_for_input; +} + +static int s2n_low_level_hash_new(struct s2n_hash_state *state) +{ + /* s2n_hash_new will always call the corresponding implementation of the s2n_hash + * being used. For the s2n_low_level_hash implementation, new is a no-op. + */ + + state->is_ready_for_input = 0; + state->currently_in_hash = 0; + return S2N_SUCCESS; +} + +static int s2n_low_level_hash_init(struct s2n_hash_state *state, s2n_hash_algorithm alg) +{ + switch (alg) { + case S2N_HASH_NONE: + break; + case S2N_HASH_MD5: + GUARD_OSSL(MD5_Init(&state->digest.low_level.md5), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_SHA1: + GUARD_OSSL(SHA1_Init(&state->digest.low_level.sha1), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_SHA224: + GUARD_OSSL(SHA224_Init(&state->digest.low_level.sha224), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_SHA256: + GUARD_OSSL(SHA256_Init(&state->digest.low_level.sha256), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_SHA384: + GUARD_OSSL(SHA384_Init(&state->digest.low_level.sha384), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_SHA512: + GUARD_OSSL(SHA512_Init(&state->digest.low_level.sha512), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_MD5_SHA1: + GUARD_OSSL(SHA1_Init(&state->digest.low_level.md5_sha1.sha1), S2N_ERR_HASH_INIT_FAILED);; + GUARD_OSSL(MD5_Init(&state->digest.low_level.md5_sha1.md5), S2N_ERR_HASH_INIT_FAILED);; + break; + + default: + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } + + state->alg = alg; + state->is_ready_for_input = 1; + state->currently_in_hash = 0; + + return 0; +} + +static int s2n_low_level_hash_update(struct s2n_hash_state *state, const void *data, uint32_t size) +{ + ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); + + switch (state->alg) { + case S2N_HASH_NONE: + break; + case S2N_HASH_MD5: + GUARD_OSSL(MD5_Update(&state->digest.low_level.md5, data, size), S2N_ERR_HASH_UPDATE_FAILED); + break; + case S2N_HASH_SHA1: + GUARD_OSSL(SHA1_Update(&state->digest.low_level.sha1, data, size), S2N_ERR_HASH_UPDATE_FAILED); + break; + case S2N_HASH_SHA224: + GUARD_OSSL(SHA224_Update(&state->digest.low_level.sha224, data, size), S2N_ERR_HASH_UPDATE_FAILED); + break; + case S2N_HASH_SHA256: + GUARD_OSSL(SHA256_Update(&state->digest.low_level.sha256, data, size), S2N_ERR_HASH_UPDATE_FAILED); + break; + case S2N_HASH_SHA384: + GUARD_OSSL(SHA384_Update(&state->digest.low_level.sha384, data, size), S2N_ERR_HASH_UPDATE_FAILED); + break; + case S2N_HASH_SHA512: + GUARD_OSSL(SHA512_Update(&state->digest.low_level.sha512, data, size), S2N_ERR_HASH_UPDATE_FAILED); + break; + case S2N_HASH_MD5_SHA1: + GUARD_OSSL(SHA1_Update(&state->digest.low_level.md5_sha1.sha1, data, size), S2N_ERR_HASH_UPDATE_FAILED); + GUARD_OSSL(MD5_Update(&state->digest.low_level.md5_sha1.md5, data, size), S2N_ERR_HASH_UPDATE_FAILED); + break; + default: + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } + + ENSURE_POSIX(size <= (UINT64_MAX - state->currently_in_hash), S2N_ERR_INTEGER_OVERFLOW); + state->currently_in_hash += size; + + return S2N_SUCCESS; +} + +static int s2n_low_level_hash_digest(struct s2n_hash_state *state, void *out, uint32_t size) +{ + ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); + + switch (state->alg) { + case S2N_HASH_NONE: + break; + case S2N_HASH_MD5: + eq_check(size, MD5_DIGEST_LENGTH); + GUARD_OSSL(MD5_Final(out, &state->digest.low_level.md5), S2N_ERR_HASH_DIGEST_FAILED); + break; + case S2N_HASH_SHA1: + eq_check(size, SHA_DIGEST_LENGTH); + GUARD_OSSL(SHA1_Final(out, &state->digest.low_level.sha1), S2N_ERR_HASH_DIGEST_FAILED); + break; + case S2N_HASH_SHA224: + eq_check(size, SHA224_DIGEST_LENGTH); + GUARD_OSSL(SHA224_Final(out, &state->digest.low_level.sha224), S2N_ERR_HASH_DIGEST_FAILED); + break; + case S2N_HASH_SHA256: + eq_check(size, SHA256_DIGEST_LENGTH); + GUARD_OSSL(SHA256_Final(out, &state->digest.low_level.sha256), S2N_ERR_HASH_DIGEST_FAILED); + break; + case S2N_HASH_SHA384: + eq_check(size, SHA384_DIGEST_LENGTH); + GUARD_OSSL(SHA384_Final(out, &state->digest.low_level.sha384), S2N_ERR_HASH_DIGEST_FAILED); + break; + case S2N_HASH_SHA512: + eq_check(size, SHA512_DIGEST_LENGTH); + GUARD_OSSL(SHA512_Final(out, &state->digest.low_level.sha512), S2N_ERR_HASH_DIGEST_FAILED); + break; + case S2N_HASH_MD5_SHA1: + eq_check(size, MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH); + GUARD_OSSL(SHA1_Final(((uint8_t *) out) + MD5_DIGEST_LENGTH, &state->digest.low_level.md5_sha1.sha1), S2N_ERR_HASH_DIGEST_FAILED); + GUARD_OSSL(MD5_Final(out, &state->digest.low_level.md5_sha1.md5), S2N_ERR_HASH_DIGEST_FAILED); + break; + default: + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } + + state->currently_in_hash = 0; + state->is_ready_for_input = 0; + return 0; +} + +static int s2n_low_level_hash_copy(struct s2n_hash_state *to, struct s2n_hash_state *from) +{ + memcpy_check(to, from, sizeof(struct s2n_hash_state)); + return 0; +} + +static int s2n_low_level_hash_reset(struct s2n_hash_state *state) +{ + /* hash_init resets the ready_for_input and currently_in_hash fields. */ + return s2n_low_level_hash_init(state, state->alg); +} + +static int s2n_low_level_hash_free(struct s2n_hash_state *state) +{ + /* s2n_hash_free will always call the corresponding implementation of the s2n_hash + * being used. For the s2n_low_level_hash implementation, free is a no-op. + */ + state->is_ready_for_input = 0; + return S2N_SUCCESS; +} + +static int s2n_evp_hash_new(struct s2n_hash_state *state) +{ + notnull_check(state->digest.high_level.evp.ctx = S2N_EVP_MD_CTX_NEW()); + notnull_check(state->digest.high_level.evp_md5_secondary.ctx = S2N_EVP_MD_CTX_NEW()); + state->is_ready_for_input = 0; + state->currently_in_hash = 0; + + return S2N_SUCCESS; +} + +static int s2n_evp_hash_allow_md5_for_fips(struct s2n_hash_state *state) +{ + /* This is only to be used for s2n_hash_states that will require MD5 to be used + * to comply with the TLS 1.0 and 1.1 RFC's for the PRF. MD5 cannot be used + * outside of the TLS 1.0 and 1.1 PRF when in FIPS mode. When needed, this must + * be called prior to s2n_hash_init(). + */ + GUARD(s2n_digest_allow_md5_for_fips(&state->digest.high_level.evp_md5_secondary)); + return s2n_digest_allow_md5_for_fips(&state->digest.high_level.evp); +} + +static int s2n_evp_hash_init(struct s2n_hash_state *state, s2n_hash_algorithm alg) +{ + notnull_check(state->digest.high_level.evp.ctx); + notnull_check(state->digest.high_level.evp_md5_secondary.ctx); + switch (alg) { + case S2N_HASH_NONE: + break; + case S2N_HASH_MD5: + GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_md5(), NULL), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_SHA1: + GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha1(), NULL), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_SHA224: + GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha224(), NULL), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_SHA256: + GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha256(), NULL), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_SHA384: + GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha384(), NULL), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_SHA512: + GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha512(), NULL), S2N_ERR_HASH_INIT_FAILED); + break; + case S2N_HASH_MD5_SHA1: + GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha1(), NULL), S2N_ERR_HASH_INIT_FAILED); + GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp_md5_secondary.ctx, EVP_md5(), NULL), S2N_ERR_HASH_INIT_FAILED); + break; + default: + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } + + state->alg = alg; + state->is_ready_for_input = 1; + state->currently_in_hash = 0; + + return S2N_SUCCESS; +} + +static int s2n_evp_hash_update(struct s2n_hash_state *state, const void *data, uint32_t size) +{ + ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); + + switch (state->alg) { + case S2N_HASH_NONE: + break; + case S2N_HASH_MD5: + case S2N_HASH_SHA1: + case S2N_HASH_SHA224: + case S2N_HASH_SHA256: + case S2N_HASH_SHA384: + case S2N_HASH_SHA512: + notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp.ctx)); + GUARD_OSSL(EVP_DigestUpdate(state->digest.high_level.evp.ctx, data, size), S2N_ERR_HASH_UPDATE_FAILED); + break; + case S2N_HASH_MD5_SHA1: + notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp.ctx)); + notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp_md5_secondary.ctx)); + GUARD_OSSL(EVP_DigestUpdate(state->digest.high_level.evp.ctx, data, size), S2N_ERR_HASH_UPDATE_FAILED); + GUARD_OSSL(EVP_DigestUpdate(state->digest.high_level.evp_md5_secondary.ctx, data, size), S2N_ERR_HASH_UPDATE_FAILED); + break; + default: + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } + + ENSURE_POSIX(size <= (UINT64_MAX - state->currently_in_hash), S2N_ERR_INTEGER_OVERFLOW); + state->currently_in_hash += size; + + return S2N_SUCCESS; +} + +static int s2n_evp_hash_digest(struct s2n_hash_state *state, void *out, uint32_t size) +{ + ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); + + unsigned int digest_size = size; + uint8_t expected_digest_size; + GUARD(s2n_hash_digest_size(state->alg, &expected_digest_size)); + eq_check(digest_size, expected_digest_size); + + /* Used for S2N_HASH_MD5_SHA1 case to specify the exact size of each digest. */ + uint8_t sha1_digest_size; + unsigned int sha1_primary_digest_size; + unsigned int md5_secondary_digest_size; + + switch (state->alg) { + case S2N_HASH_NONE: + break; + case S2N_HASH_MD5: + case S2N_HASH_SHA1: + case S2N_HASH_SHA224: + case S2N_HASH_SHA256: + case S2N_HASH_SHA384: + case S2N_HASH_SHA512: + notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp.ctx)); + ENSURE_POSIX(EVP_MD_CTX_size(state->digest.high_level.evp.ctx) <= digest_size, S2N_ERR_HASH_DIGEST_FAILED); + GUARD_OSSL(EVP_DigestFinal_ex(state->digest.high_level.evp.ctx, out, &digest_size), S2N_ERR_HASH_DIGEST_FAILED); + break; + case S2N_HASH_MD5_SHA1: + notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp.ctx)); + notnull_check(EVP_MD_CTX_md(state->digest.high_level.evp_md5_secondary.ctx)); + GUARD(s2n_hash_digest_size(S2N_HASH_SHA1, &sha1_digest_size)); + sha1_primary_digest_size = sha1_digest_size; + md5_secondary_digest_size = digest_size - sha1_primary_digest_size; + ENSURE_POSIX(EVP_MD_CTX_size(state->digest.high_level.evp.ctx) <= sha1_digest_size, S2N_ERR_HASH_DIGEST_FAILED); + ENSURE_POSIX(EVP_MD_CTX_size(state->digest.high_level.evp_md5_secondary.ctx) <= md5_secondary_digest_size, S2N_ERR_HASH_DIGEST_FAILED); + + GUARD_OSSL(EVP_DigestFinal_ex(state->digest.high_level.evp.ctx, ((uint8_t *) out) + MD5_DIGEST_LENGTH, &sha1_primary_digest_size), S2N_ERR_HASH_DIGEST_FAILED); + GUARD_OSSL(EVP_DigestFinal_ex(state->digest.high_level.evp_md5_secondary.ctx, out, &md5_secondary_digest_size), S2N_ERR_HASH_DIGEST_FAILED); + break; + default: + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } + + state->currently_in_hash = 0; + state->is_ready_for_input = 0; + return S2N_SUCCESS; +} + +static int s2n_evp_hash_copy(struct s2n_hash_state *to, struct s2n_hash_state *from) +{ + bool is_md5_allowed_for_fips = false; + switch (from->alg) { + case S2N_HASH_NONE: + break; + case S2N_HASH_MD5: + GUARD_AS_POSIX(s2n_digest_is_md5_allowed_for_fips(&from->digest.high_level.evp, &is_md5_allowed_for_fips)); + if (is_md5_allowed_for_fips) { + GUARD(s2n_hash_allow_md5_for_fips(to)); + } + FALL_THROUGH; + case S2N_HASH_SHA1: + case S2N_HASH_SHA224: + case S2N_HASH_SHA256: + case S2N_HASH_SHA384: + case S2N_HASH_SHA512: + notnull_check(to->digest.high_level.evp.ctx); + GUARD_OSSL(EVP_MD_CTX_copy_ex(to->digest.high_level.evp.ctx, from->digest.high_level.evp.ctx), S2N_ERR_HASH_COPY_FAILED); + break; + case S2N_HASH_MD5_SHA1: + notnull_check(to->digest.high_level.evp.ctx); + notnull_check(to->digest.high_level.evp_md5_secondary.ctx); + GUARD_AS_POSIX(s2n_digest_is_md5_allowed_for_fips(&from->digest.high_level.evp, &is_md5_allowed_for_fips)); + if (is_md5_allowed_for_fips) { + GUARD(s2n_hash_allow_md5_for_fips(to)); + } + GUARD_OSSL(EVP_MD_CTX_copy_ex(to->digest.high_level.evp.ctx, from->digest.high_level.evp.ctx), S2N_ERR_HASH_COPY_FAILED); + GUARD_OSSL(EVP_MD_CTX_copy_ex(to->digest.high_level.evp_md5_secondary.ctx, from->digest.high_level.evp_md5_secondary.ctx), S2N_ERR_HASH_COPY_FAILED); + break; + default: + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } + + to->hash_impl = from->hash_impl; + to->alg = from->alg; + to->is_ready_for_input = from->is_ready_for_input; + to->currently_in_hash = from->currently_in_hash; + + return S2N_SUCCESS; +} + +static int s2n_evp_hash_reset(struct s2n_hash_state *state) +{ + int reset_md5_for_fips = 0; + bool is_md5_allowed_for_fips = false; + GUARD_AS_POSIX(s2n_digest_is_md5_allowed_for_fips(&state->digest.high_level.evp, &is_md5_allowed_for_fips)); + if ((state->alg == S2N_HASH_MD5 || state->alg == S2N_HASH_MD5_SHA1) && is_md5_allowed_for_fips) { + reset_md5_for_fips = 1; + } + + GUARD_OSSL(S2N_EVP_MD_CTX_RESET(state->digest.high_level.evp.ctx), S2N_ERR_HASH_WIPE_FAILED); + + if (state->alg == S2N_HASH_MD5_SHA1) { + GUARD_OSSL(S2N_EVP_MD_CTX_RESET(state->digest.high_level.evp_md5_secondary.ctx), S2N_ERR_HASH_WIPE_FAILED); + } + + if (reset_md5_for_fips) { + GUARD(s2n_hash_allow_md5_for_fips(state)); + } + + /* hash_init resets the ready_for_input and currently_in_hash fields. */ + return s2n_evp_hash_init(state, state->alg); +} + +static int s2n_evp_hash_free(struct s2n_hash_state *state) +{ + S2N_EVP_MD_CTX_FREE(state->digest.high_level.evp.ctx); + S2N_EVP_MD_CTX_FREE(state->digest.high_level.evp_md5_secondary.ctx); + state->digest.high_level.evp.ctx = NULL; + state->digest.high_level.evp_md5_secondary.ctx = NULL; + state->is_ready_for_input = 0; + return S2N_SUCCESS; +} + +static const struct s2n_hash s2n_low_level_hash = { + .alloc = &s2n_low_level_hash_new, + .allow_md5_for_fips = NULL, + .init = &s2n_low_level_hash_init, + .update = &s2n_low_level_hash_update, + .digest = &s2n_low_level_hash_digest, + .copy = &s2n_low_level_hash_copy, + .reset = &s2n_low_level_hash_reset, + .free = &s2n_low_level_hash_free, +}; + +static const struct s2n_hash s2n_evp_hash = { + .alloc = &s2n_evp_hash_new, + .allow_md5_for_fips = &s2n_evp_hash_allow_md5_for_fips, + .init = &s2n_evp_hash_init, + .update = &s2n_evp_hash_update, + .digest = &s2n_evp_hash_digest, + .copy = &s2n_evp_hash_copy, + .reset = &s2n_evp_hash_reset, + .free = &s2n_evp_hash_free, +}; + +static int s2n_hash_set_impl(struct s2n_hash_state *state) +{ + state->hash_impl = s2n_is_in_fips_mode() ? &s2n_evp_hash : &s2n_low_level_hash; + + return S2N_SUCCESS; +} + +int s2n_hash_new(struct s2n_hash_state *state) +{ + notnull_check(state); + /* Set hash_impl on initial hash creation. + * When in FIPS mode, the EVP API's must be used for hashes. + */ + GUARD(s2n_hash_set_impl(state)); + + notnull_check(state->hash_impl->alloc); + + GUARD(state->hash_impl->alloc(state)); + return S2N_SUCCESS; +} + +S2N_RESULT s2n_hash_state_validate(struct s2n_hash_state *state) +{ + ENSURE_REF(state); + ENSURE_REF(state->hash_impl); + return S2N_RESULT_OK; +} + +int s2n_hash_allow_md5_for_fips(struct s2n_hash_state *state) +{ + notnull_check(state); + /* Ensure that hash_impl is set, as it may have been reset for s2n_hash_state on s2n_connection_wipe. + * When in FIPS mode, the EVP API's must be used for hashes. + */ + GUARD(s2n_hash_set_impl(state)); + + notnull_check(state->hash_impl->allow_md5_for_fips); + + return state->hash_impl->allow_md5_for_fips(state); +} + +int s2n_hash_init(struct s2n_hash_state *state, s2n_hash_algorithm alg) +{ + notnull_check(state); + /* Ensure that hash_impl is set, as it may have been reset for s2n_hash_state on s2n_connection_wipe. + * When in FIPS mode, the EVP API's must be used for hashes. + */ + GUARD(s2n_hash_set_impl(state)); + + bool is_md5_allowed_for_fips = false; + GUARD_AS_POSIX(s2n_digest_is_md5_allowed_for_fips(&state->digest.high_level.evp, &is_md5_allowed_for_fips)); + + if (s2n_hash_is_available(alg) || + ((alg == S2N_HASH_MD5 || alg == S2N_HASH_MD5_SHA1) && is_md5_allowed_for_fips)) { + /* s2n will continue to initialize an "unavailable" hash when s2n is in FIPS mode and + * FIPS is forcing the hash to be made available. + */ + notnull_check(state->hash_impl->init); + + return state->hash_impl->init(state, alg); + } else { + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } +} + +int s2n_hash_update(struct s2n_hash_state *state, const void *data, uint32_t size) +{ + PRECONDITION_POSIX(s2n_hash_state_validate(state)); + ENSURE_POSIX(S2N_MEM_IS_READABLE(data, size), S2N_ERR_PRECONDITION_VIOLATION); + notnull_check(state->hash_impl->update); + + return state->hash_impl->update(state, data, size); +} + +int s2n_hash_digest(struct s2n_hash_state *state, void *out, uint32_t size) +{ + PRECONDITION_POSIX(s2n_hash_state_validate(state)); + ENSURE_POSIX(S2N_MEM_IS_READABLE(out, size), S2N_ERR_PRECONDITION_VIOLATION); + notnull_check(state->hash_impl->digest); + + return state->hash_impl->digest(state, out, size); +} + +int s2n_hash_copy(struct s2n_hash_state *to, struct s2n_hash_state *from) +{ + PRECONDITION_POSIX(s2n_hash_state_validate(to)); + PRECONDITION_POSIX(s2n_hash_state_validate(from)); + notnull_check(from->hash_impl->copy); + + return from->hash_impl->copy(to, from); +} + +int s2n_hash_reset(struct s2n_hash_state *state) +{ + notnull_check(state); + /* Ensure that hash_impl is set, as it may have been reset for s2n_hash_state on s2n_connection_wipe. + * When in FIPS mode, the EVP API's must be used for hashes. + */ + GUARD(s2n_hash_set_impl(state)); + + notnull_check(state->hash_impl->reset); + + return state->hash_impl->reset(state); +} + +int s2n_hash_free(struct s2n_hash_state *state) +{ + if (state == NULL) + { + return S2N_SUCCESS; + } + /* Ensure that hash_impl is set, as it may have been reset for s2n_hash_state on s2n_connection_wipe. + * When in FIPS mode, the EVP API's must be used for hashes. + */ + GUARD(s2n_hash_set_impl(state)); + + notnull_check(state->hash_impl->free); + + return state->hash_impl->free(state); +} + +int s2n_hash_get_currently_in_hash_total(struct s2n_hash_state *state, uint64_t *out) +{ + PRECONDITION_POSIX(s2n_hash_state_validate(state)); + ENSURE_POSIX(S2N_MEM_IS_READABLE(out, sizeof(*out)), S2N_ERR_PRECONDITION_VIOLATION); + ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); + + *out = state->currently_in_hash; + return S2N_SUCCESS; +} + + +/* Calculate, in constant time, the number of bytes currently in the hash_block */ +int s2n_hash_const_time_get_currently_in_hash_block(struct s2n_hash_state *state, uint64_t *out) +{ + PRECONDITION_POSIX(s2n_hash_state_validate(state)); + ENSURE_POSIX(S2N_MEM_IS_READABLE(out, sizeof(*out)), S2N_ERR_PRECONDITION_VIOLATION); + ENSURE_POSIX(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY); + uint64_t hash_block_size; + GUARD(s2n_hash_block_size(state->alg, &hash_block_size)); + + /* Requires that hash_block_size is a power of 2. This is true for all hashes we currently support + * If this ever becomes untrue, this would require fixing this*/ + *out = state->currently_in_hash & (hash_block_size - 1); + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_hash.h b/contrib/restricted/aws/s2n/crypto/s2n_hash.h index 2ca40e77ca..ad5ac74830 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_hash.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_hash.h @@ -1,104 +1,104 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <stdint.h> -#include <stdbool.h> - -#include <openssl/md5.h> -#include <openssl/sha.h> - -#include "crypto/s2n_evp.h" - -#define S2N_MAX_DIGEST_LEN SHA512_DIGEST_LENGTH - -typedef enum { - S2N_HASH_NONE=0, - S2N_HASH_MD5, - S2N_HASH_SHA1, - S2N_HASH_SHA224, - S2N_HASH_SHA256, - S2N_HASH_SHA384, - S2N_HASH_SHA512, - S2N_HASH_MD5_SHA1, - /* Don't add any hash algorithms below S2N_HASH_SENTINEL */ - S2N_HASH_SENTINEL -} s2n_hash_algorithm; - -/* The low_level_digest stores all OpenSSL structs that are alg-specific to be used with OpenSSL's low-level hash API's. */ -union s2n_hash_low_level_digest { - MD5_CTX md5; - SHA_CTX sha1; - SHA256_CTX sha224; - SHA256_CTX sha256; - SHA512_CTX sha384; - SHA512_CTX sha512; - struct { - MD5_CTX md5; - SHA_CTX sha1; - } md5_sha1; -}; - -/* The evp_digest stores all OpenSSL structs to be used with OpenSSL's EVP hash API's. */ -struct s2n_hash_evp_digest { - struct s2n_evp_digest evp; - /* Always store a secondary evp_digest to allow resetting a hash_state to MD5_SHA1 from another alg. */ - struct s2n_evp_digest evp_md5_secondary; -}; - -/* s2n_hash_state stores the s2n_hash implementation being used (low-level or EVP), - * the hash algorithm being used at the time, and either low_level or high_level (EVP) OpenSSL digest structs. - */ -struct s2n_hash_state { - const struct s2n_hash *hash_impl; - s2n_hash_algorithm alg; - uint8_t is_ready_for_input; - uint64_t currently_in_hash; - union { - union s2n_hash_low_level_digest low_level; - struct s2n_hash_evp_digest high_level; - } digest; -}; - -/* The s2n hash implementation is abstracted to allow for separate implementations, using - * either OpenSSL's low-level algorithm-specific API's or OpenSSL's EVP API's. - */ -struct s2n_hash { - int (*alloc) (struct s2n_hash_state *state); - int (*allow_md5_for_fips) (struct s2n_hash_state *state); - int (*init) (struct s2n_hash_state *state, s2n_hash_algorithm alg); - int (*update) (struct s2n_hash_state *state, const void *data, uint32_t size); - int (*digest) (struct s2n_hash_state *state, void *out, uint32_t size); - int (*copy) (struct s2n_hash_state *to, struct s2n_hash_state *from); - int (*reset) (struct s2n_hash_state *state); - int (*free) (struct s2n_hash_state *state); -}; - -extern int s2n_hash_digest_size(s2n_hash_algorithm alg, uint8_t *out); -extern int s2n_hash_block_size(s2n_hash_algorithm alg, uint64_t *block_size); -extern bool s2n_hash_is_available(s2n_hash_algorithm alg); -extern int s2n_hash_is_ready_for_input(struct s2n_hash_state *state); -extern int s2n_hash_new(struct s2n_hash_state *state); -S2N_RESULT s2n_hash_state_validate(struct s2n_hash_state *state); -extern int s2n_hash_allow_md5_for_fips(struct s2n_hash_state *state); -extern int s2n_hash_init(struct s2n_hash_state *state, s2n_hash_algorithm alg); -extern int s2n_hash_update(struct s2n_hash_state *state, const void *data, uint32_t size); -extern int s2n_hash_digest(struct s2n_hash_state *state, void *out, uint32_t size); -extern int s2n_hash_copy(struct s2n_hash_state *to, struct s2n_hash_state *from); -extern int s2n_hash_reset(struct s2n_hash_state *state); -extern int s2n_hash_free(struct s2n_hash_state *state); -extern int s2n_hash_get_currently_in_hash_total(struct s2n_hash_state *state, uint64_t *out); -extern int s2n_hash_const_time_get_currently_in_hash_block(struct s2n_hash_state *state, uint64_t *out); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#include <openssl/md5.h> +#include <openssl/sha.h> + +#include "crypto/s2n_evp.h" + +#define S2N_MAX_DIGEST_LEN SHA512_DIGEST_LENGTH + +typedef enum { + S2N_HASH_NONE=0, + S2N_HASH_MD5, + S2N_HASH_SHA1, + S2N_HASH_SHA224, + S2N_HASH_SHA256, + S2N_HASH_SHA384, + S2N_HASH_SHA512, + S2N_HASH_MD5_SHA1, + /* Don't add any hash algorithms below S2N_HASH_SENTINEL */ + S2N_HASH_SENTINEL +} s2n_hash_algorithm; + +/* The low_level_digest stores all OpenSSL structs that are alg-specific to be used with OpenSSL's low-level hash API's. */ +union s2n_hash_low_level_digest { + MD5_CTX md5; + SHA_CTX sha1; + SHA256_CTX sha224; + SHA256_CTX sha256; + SHA512_CTX sha384; + SHA512_CTX sha512; + struct { + MD5_CTX md5; + SHA_CTX sha1; + } md5_sha1; +}; + +/* The evp_digest stores all OpenSSL structs to be used with OpenSSL's EVP hash API's. */ +struct s2n_hash_evp_digest { + struct s2n_evp_digest evp; + /* Always store a secondary evp_digest to allow resetting a hash_state to MD5_SHA1 from another alg. */ + struct s2n_evp_digest evp_md5_secondary; +}; + +/* s2n_hash_state stores the s2n_hash implementation being used (low-level or EVP), + * the hash algorithm being used at the time, and either low_level or high_level (EVP) OpenSSL digest structs. + */ +struct s2n_hash_state { + const struct s2n_hash *hash_impl; + s2n_hash_algorithm alg; + uint8_t is_ready_for_input; + uint64_t currently_in_hash; + union { + union s2n_hash_low_level_digest low_level; + struct s2n_hash_evp_digest high_level; + } digest; +}; + +/* The s2n hash implementation is abstracted to allow for separate implementations, using + * either OpenSSL's low-level algorithm-specific API's or OpenSSL's EVP API's. + */ +struct s2n_hash { + int (*alloc) (struct s2n_hash_state *state); + int (*allow_md5_for_fips) (struct s2n_hash_state *state); + int (*init) (struct s2n_hash_state *state, s2n_hash_algorithm alg); + int (*update) (struct s2n_hash_state *state, const void *data, uint32_t size); + int (*digest) (struct s2n_hash_state *state, void *out, uint32_t size); + int (*copy) (struct s2n_hash_state *to, struct s2n_hash_state *from); + int (*reset) (struct s2n_hash_state *state); + int (*free) (struct s2n_hash_state *state); +}; + +extern int s2n_hash_digest_size(s2n_hash_algorithm alg, uint8_t *out); +extern int s2n_hash_block_size(s2n_hash_algorithm alg, uint64_t *block_size); +extern bool s2n_hash_is_available(s2n_hash_algorithm alg); +extern int s2n_hash_is_ready_for_input(struct s2n_hash_state *state); +extern int s2n_hash_new(struct s2n_hash_state *state); +S2N_RESULT s2n_hash_state_validate(struct s2n_hash_state *state); +extern int s2n_hash_allow_md5_for_fips(struct s2n_hash_state *state); +extern int s2n_hash_init(struct s2n_hash_state *state, s2n_hash_algorithm alg); +extern int s2n_hash_update(struct s2n_hash_state *state, const void *data, uint32_t size); +extern int s2n_hash_digest(struct s2n_hash_state *state, void *out, uint32_t size); +extern int s2n_hash_copy(struct s2n_hash_state *to, struct s2n_hash_state *from); +extern int s2n_hash_reset(struct s2n_hash_state *state); +extern int s2n_hash_free(struct s2n_hash_state *state); +extern int s2n_hash_get_currently_in_hash_total(struct s2n_hash_state *state, uint64_t *out); +extern int s2n_hash_const_time_get_currently_in_hash_block(struct s2n_hash_state *state, uint64_t *out); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_hkdf.c b/contrib/restricted/aws/s2n/crypto/s2n_hkdf.c index cefd528fdf..9282bbdfb4 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_hkdf.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_hkdf.c @@ -1,126 +1,126 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <stdio.h> - -#include "error/s2n_errno.h" - -#include "stuffer/s2n_stuffer.h" - -#include "crypto/s2n_hmac.h" - -#include "utils/s2n_blob.h" -#include "utils/s2n_safety.h" -#include "utils/s2n_mem.h" - -#define MAX_DIGEST_SIZE 64 /* Current highest is SHA512 */ -#define MAX_HKDF_ROUNDS 255 - -/* Reference: RFC 5869 */ - -int s2n_hkdf_extract(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt, - const struct s2n_blob *key, struct s2n_blob *pseudo_rand_key) -{ - uint8_t hmac_size; - GUARD(s2n_hmac_digest_size(alg, &hmac_size)); - pseudo_rand_key->size = hmac_size; - GUARD(s2n_hmac_init(hmac, alg, salt->data, salt->size)); - GUARD(s2n_hmac_update(hmac, key->data, key->size)); - GUARD(s2n_hmac_digest(hmac, pseudo_rand_key->data, pseudo_rand_key->size)); - - GUARD(s2n_hmac_reset(hmac)); - - return 0; -} - -static int s2n_hkdf_expand(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *pseudo_rand_key, - const struct s2n_blob *info, struct s2n_blob *output) -{ - uint8_t prev[MAX_DIGEST_SIZE] = { 0 }; - - uint32_t done_len = 0; - uint8_t hash_len; - GUARD(s2n_hmac_digest_size(alg, &hash_len)); - uint32_t total_rounds = output->size / hash_len; - if (output->size % hash_len) { - total_rounds++; - } - - S2N_ERROR_IF(total_rounds > MAX_HKDF_ROUNDS || total_rounds == 0, S2N_ERR_HKDF_OUTPUT_SIZE); - - for (uint32_t curr_round = 1; curr_round <= total_rounds; curr_round++) { - uint32_t cat_len; - GUARD(s2n_hmac_init(hmac, alg, pseudo_rand_key->data, pseudo_rand_key->size)); - if (curr_round != 1) { - GUARD(s2n_hmac_update(hmac, prev, hash_len)); - } - GUARD(s2n_hmac_update(hmac, info->data, info->size)); - GUARD(s2n_hmac_update(hmac, &curr_round, 1)); - GUARD(s2n_hmac_digest(hmac, prev, hash_len)); - - cat_len = hash_len; - if (done_len + hash_len > output->size) { - cat_len = output->size - done_len; - } - - memcpy_check(output->data + done_len, prev, cat_len); - - done_len += cat_len; - - GUARD(s2n_hmac_reset(hmac)); - } - - return 0; -} - -int s2n_hkdf_expand_label(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *secret, const struct s2n_blob *label, - const struct s2n_blob *context, struct s2n_blob *output) -{ - /* Per RFC8446: 7.1, a HKDF label is a 2 byte length field, and two 1...255 byte arrays with a one byte length field each. */ - uint8_t hkdf_label_buf[2 + 256 + 256]; - struct s2n_blob hkdf_label_blob = {0}; - struct s2n_stuffer hkdf_label = {0}; - - /* RFC8446 specifies that labels must be 12 characters or less, to avoid - ** incurring two hash rounds. - */ - lte_check(label->size, 12); - - GUARD(s2n_blob_init(&hkdf_label_blob, hkdf_label_buf, sizeof(hkdf_label_buf))); - GUARD(s2n_stuffer_init(&hkdf_label, &hkdf_label_blob)); - GUARD(s2n_stuffer_write_uint16(&hkdf_label, output->size)); - GUARD(s2n_stuffer_write_uint8(&hkdf_label, label->size + sizeof("tls13 ") - 1)); - GUARD(s2n_stuffer_write_str(&hkdf_label, "tls13 ")); - GUARD(s2n_stuffer_write(&hkdf_label, label)); - GUARD(s2n_stuffer_write_uint8(&hkdf_label, context->size)); - GUARD(s2n_stuffer_write(&hkdf_label, context)); - - hkdf_label_blob.size = s2n_stuffer_data_available(&hkdf_label); - GUARD(s2n_hkdf_expand(hmac, alg, secret, &hkdf_label_blob, output)); - - return 0; -} - -int s2n_hkdf(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt, - const struct s2n_blob *key, const struct s2n_blob *info, struct s2n_blob *output) -{ - uint8_t prk_pad[MAX_DIGEST_SIZE]; - struct s2n_blob pseudo_rand_key = {.data = prk_pad,.size = sizeof(prk_pad) }; - - GUARD(s2n_hkdf_extract(hmac, alg, salt, key, &pseudo_rand_key)); - GUARD(s2n_hkdf_expand(hmac, alg, &pseudo_rand_key, info, output)); - - return 0; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <stdio.h> + +#include "error/s2n_errno.h" + +#include "stuffer/s2n_stuffer.h" + +#include "crypto/s2n_hmac.h" + +#include "utils/s2n_blob.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_mem.h" + +#define MAX_DIGEST_SIZE 64 /* Current highest is SHA512 */ +#define MAX_HKDF_ROUNDS 255 + +/* Reference: RFC 5869 */ + +int s2n_hkdf_extract(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt, + const struct s2n_blob *key, struct s2n_blob *pseudo_rand_key) +{ + uint8_t hmac_size; + GUARD(s2n_hmac_digest_size(alg, &hmac_size)); + pseudo_rand_key->size = hmac_size; + GUARD(s2n_hmac_init(hmac, alg, salt->data, salt->size)); + GUARD(s2n_hmac_update(hmac, key->data, key->size)); + GUARD(s2n_hmac_digest(hmac, pseudo_rand_key->data, pseudo_rand_key->size)); + + GUARD(s2n_hmac_reset(hmac)); + + return 0; +} + +static int s2n_hkdf_expand(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *pseudo_rand_key, + const struct s2n_blob *info, struct s2n_blob *output) +{ + uint8_t prev[MAX_DIGEST_SIZE] = { 0 }; + + uint32_t done_len = 0; + uint8_t hash_len; + GUARD(s2n_hmac_digest_size(alg, &hash_len)); + uint32_t total_rounds = output->size / hash_len; + if (output->size % hash_len) { + total_rounds++; + } + + S2N_ERROR_IF(total_rounds > MAX_HKDF_ROUNDS || total_rounds == 0, S2N_ERR_HKDF_OUTPUT_SIZE); + + for (uint32_t curr_round = 1; curr_round <= total_rounds; curr_round++) { + uint32_t cat_len; + GUARD(s2n_hmac_init(hmac, alg, pseudo_rand_key->data, pseudo_rand_key->size)); + if (curr_round != 1) { + GUARD(s2n_hmac_update(hmac, prev, hash_len)); + } + GUARD(s2n_hmac_update(hmac, info->data, info->size)); + GUARD(s2n_hmac_update(hmac, &curr_round, 1)); + GUARD(s2n_hmac_digest(hmac, prev, hash_len)); + + cat_len = hash_len; + if (done_len + hash_len > output->size) { + cat_len = output->size - done_len; + } + + memcpy_check(output->data + done_len, prev, cat_len); + + done_len += cat_len; + + GUARD(s2n_hmac_reset(hmac)); + } + + return 0; +} + +int s2n_hkdf_expand_label(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *secret, const struct s2n_blob *label, + const struct s2n_blob *context, struct s2n_blob *output) +{ + /* Per RFC8446: 7.1, a HKDF label is a 2 byte length field, and two 1...255 byte arrays with a one byte length field each. */ + uint8_t hkdf_label_buf[2 + 256 + 256]; + struct s2n_blob hkdf_label_blob = {0}; + struct s2n_stuffer hkdf_label = {0}; + + /* RFC8446 specifies that labels must be 12 characters or less, to avoid + ** incurring two hash rounds. + */ + lte_check(label->size, 12); + + GUARD(s2n_blob_init(&hkdf_label_blob, hkdf_label_buf, sizeof(hkdf_label_buf))); + GUARD(s2n_stuffer_init(&hkdf_label, &hkdf_label_blob)); + GUARD(s2n_stuffer_write_uint16(&hkdf_label, output->size)); + GUARD(s2n_stuffer_write_uint8(&hkdf_label, label->size + sizeof("tls13 ") - 1)); + GUARD(s2n_stuffer_write_str(&hkdf_label, "tls13 ")); + GUARD(s2n_stuffer_write(&hkdf_label, label)); + GUARD(s2n_stuffer_write_uint8(&hkdf_label, context->size)); + GUARD(s2n_stuffer_write(&hkdf_label, context)); + + hkdf_label_blob.size = s2n_stuffer_data_available(&hkdf_label); + GUARD(s2n_hkdf_expand(hmac, alg, secret, &hkdf_label_blob, output)); + + return 0; +} + +int s2n_hkdf(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt, + const struct s2n_blob *key, const struct s2n_blob *info, struct s2n_blob *output) +{ + uint8_t prk_pad[MAX_DIGEST_SIZE]; + struct s2n_blob pseudo_rand_key = {.data = prk_pad,.size = sizeof(prk_pad) }; + + GUARD(s2n_hkdf_extract(hmac, alg, salt, key, &pseudo_rand_key)); + GUARD(s2n_hkdf_expand(hmac, alg, &pseudo_rand_key, info, output)); + + return 0; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_hkdf.h b/contrib/restricted/aws/s2n/crypto/s2n_hkdf.h index 9df0e766ba..a0759ba305 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_hkdf.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_hkdf.h @@ -1,31 +1,31 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <stdint.h> - -#include "utils/s2n_blob.h" - -#include "crypto/s2n_hmac.h" - -extern int s2n_hkdf(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt, - const struct s2n_blob *key, const struct s2n_blob *info, struct s2n_blob *output); - -extern int s2n_hkdf_extract(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt, - const struct s2n_blob *key, struct s2n_blob *pseudo_rand_key); - -extern int s2n_hkdf_expand_label(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *secret, const struct s2n_blob *label, - const struct s2n_blob *context, struct s2n_blob *output); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <stdint.h> + +#include "utils/s2n_blob.h" + +#include "crypto/s2n_hmac.h" + +extern int s2n_hkdf(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt, + const struct s2n_blob *key, const struct s2n_blob *info, struct s2n_blob *output); + +extern int s2n_hkdf_extract(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *salt, + const struct s2n_blob *key, struct s2n_blob *pseudo_rand_key); + +extern int s2n_hkdf_expand_label(struct s2n_hmac_state *hmac, s2n_hmac_algorithm alg, const struct s2n_blob *secret, const struct s2n_blob *label, + const struct s2n_blob *context, struct s2n_blob *output); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_hmac.c b/contrib/restricted/aws/s2n/crypto/s2n_hmac.c index 8f5acf045a..5362be79ba 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_hmac.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_hmac.c @@ -1,350 +1,350 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/md5.h> -#include <openssl/sha.h> - -#include "error/s2n_errno.h" - -#include "crypto/s2n_hmac.h" -#include "crypto/s2n_hash.h" -#include "crypto/s2n_fips.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" -#include "utils/s2n_mem.h" - -#include <stdint.h> - - -int s2n_hmac_hash_alg(s2n_hmac_algorithm hmac_alg, s2n_hash_algorithm *out) -{ - switch(hmac_alg) { - case S2N_HMAC_NONE: *out = S2N_HASH_NONE; break; - case S2N_HMAC_MD5: *out = S2N_HASH_MD5; break; - case S2N_HMAC_SHA1: *out = S2N_HASH_SHA1; break; - case S2N_HMAC_SHA224: *out = S2N_HASH_SHA224; break; - case S2N_HMAC_SHA256: *out = S2N_HASH_SHA256; break; - case S2N_HMAC_SHA384: *out = S2N_HASH_SHA384; break; - case S2N_HMAC_SHA512: *out = S2N_HASH_SHA512; break; - case S2N_HMAC_SSLv3_MD5: *out = S2N_HASH_MD5; break; - case S2N_HMAC_SSLv3_SHA1: *out = S2N_HASH_SHA1; break; - default: - S2N_ERROR(S2N_ERR_HMAC_INVALID_ALGORITHM); - } - return 0; -} - -int s2n_hmac_digest_size(s2n_hmac_algorithm hmac_alg, uint8_t *out) -{ - s2n_hash_algorithm hash_alg; - GUARD(s2n_hmac_hash_alg(hmac_alg, &hash_alg)); - GUARD(s2n_hash_digest_size(hash_alg, out)); - return 0; -} - -/* Return 1 if hmac algorithm is available, 0 otherwise. */ -int s2n_hmac_is_available(s2n_hmac_algorithm hmac_alg) -{ - int is_available = 0; - switch(hmac_alg) { - case S2N_HMAC_MD5: - case S2N_HMAC_SSLv3_MD5: - case S2N_HMAC_SSLv3_SHA1: - /* Set is_available to 0 if in FIPS mode, as MD5/SSLv3 algs are not available in FIPS mode. */ - is_available = !s2n_is_in_fips_mode(); - break; - case S2N_HMAC_NONE: - case S2N_HMAC_SHA1: - case S2N_HMAC_SHA224: - case S2N_HMAC_SHA256: - case S2N_HMAC_SHA384: - case S2N_HMAC_SHA512: - is_available = 1; - break; - default: - S2N_ERROR(S2N_ERR_HMAC_INVALID_ALGORITHM); - } - - return is_available; -} - -static int s2n_sslv3_mac_init(struct s2n_hmac_state *state, s2n_hmac_algorithm alg, const void *key, uint32_t klen) -{ - for (int i = 0; i < state->xor_pad_size; i++) { - state->xor_pad[i] = 0x36; - } - - GUARD(s2n_hash_update(&state->inner_just_key, key, klen)); - GUARD(s2n_hash_update(&state->inner_just_key, state->xor_pad, state->xor_pad_size)); - - for (int i = 0; i < state->xor_pad_size; i++) { - state->xor_pad[i] = 0x5c; - } - - GUARD(s2n_hash_update(&state->outer_just_key, key, klen)); - GUARD(s2n_hash_update(&state->outer_just_key, state->xor_pad, state->xor_pad_size)); - - return 0; -} - -static int s2n_tls_hmac_init(struct s2n_hmac_state *state, s2n_hmac_algorithm alg, const void *key, uint32_t klen) -{ - memset(&state->xor_pad, 0, sizeof(state->xor_pad)); - - if (klen > state->xor_pad_size) { - GUARD(s2n_hash_update(&state->outer, key, klen)); - GUARD(s2n_hash_digest(&state->outer, state->digest_pad, state->digest_size)); - memcpy_check(state->xor_pad, state->digest_pad, state->digest_size); - } else { - memcpy_check(state->xor_pad, key, klen); - } - - for (int i = 0; i < state->xor_pad_size; i++) { - state->xor_pad[i] ^= 0x36; - } - - GUARD(s2n_hash_update(&state->inner_just_key, state->xor_pad, state->xor_pad_size)); - - /* 0x36 xor 0x5c == 0x6a */ - for (int i = 0; i < state->xor_pad_size; i++) { - state->xor_pad[i] ^= 0x6a; - } - - GUARD(s2n_hash_update(&state->outer_just_key, state->xor_pad, state->xor_pad_size)); - return 0; -} - -int s2n_hmac_xor_pad_size(s2n_hmac_algorithm hmac_alg, uint16_t *xor_pad_size) -{ - switch(hmac_alg) { - case S2N_HMAC_NONE: *xor_pad_size = 64; break; - case S2N_HMAC_MD5: *xor_pad_size = 64; break; - case S2N_HMAC_SHA1: *xor_pad_size = 64; break; - case S2N_HMAC_SHA224: *xor_pad_size = 64; break; - case S2N_HMAC_SHA256: *xor_pad_size = 64; break; - case S2N_HMAC_SHA384: *xor_pad_size = 128; break; - case S2N_HMAC_SHA512: *xor_pad_size = 128; break; - case S2N_HMAC_SSLv3_MD5: *xor_pad_size = 48; break; - case S2N_HMAC_SSLv3_SHA1: *xor_pad_size = 40; break; - default: - S2N_ERROR(S2N_ERR_HMAC_INVALID_ALGORITHM); - } - return 0; -} - -int s2n_hmac_hash_block_size(s2n_hmac_algorithm hmac_alg, uint16_t *block_size) -{ - switch(hmac_alg) { - case S2N_HMAC_NONE: *block_size = 64; break; - case S2N_HMAC_MD5: *block_size = 64; break; - case S2N_HMAC_SHA1: *block_size = 64; break; - case S2N_HMAC_SHA224: *block_size = 64; break; - case S2N_HMAC_SHA256: *block_size = 64; break; - case S2N_HMAC_SHA384: *block_size = 128; break; - case S2N_HMAC_SHA512: *block_size = 128; break; - case S2N_HMAC_SSLv3_MD5: *block_size = 64; break; - case S2N_HMAC_SSLv3_SHA1: *block_size = 64; break; - default: - S2N_ERROR(S2N_ERR_HMAC_INVALID_ALGORITHM); - } - return 0; -} - -int s2n_hmac_new(struct s2n_hmac_state *state) -{ - GUARD(s2n_hash_new(&state->inner)); - GUARD(s2n_hash_new(&state->inner_just_key)); - GUARD(s2n_hash_new(&state->outer)); - GUARD(s2n_hash_new(&state->outer_just_key)); - - return 0; -} - -int s2n_hmac_init(struct s2n_hmac_state *state, s2n_hmac_algorithm alg, const void *key, uint32_t klen) -{ - if (!s2n_hmac_is_available(alg)) { - /* Prevent hmacs from being used if they are not available. */ - S2N_ERROR(S2N_ERR_HMAC_INVALID_ALGORITHM); - } - - state->alg = alg; - GUARD(s2n_hmac_hash_block_size(alg, &state->hash_block_size)); - state->currently_in_hash_block = 0; - GUARD(s2n_hmac_xor_pad_size(alg, &state->xor_pad_size)); - GUARD(s2n_hmac_digest_size(alg, &state->digest_size)); - - gte_check(sizeof(state->xor_pad), state->xor_pad_size); - gte_check(sizeof(state->digest_pad), state->digest_size); - /* key needs to be as large as the biggest block size */ - gte_check(sizeof(state->xor_pad), state->hash_block_size); - - s2n_hash_algorithm hash_alg; - GUARD(s2n_hmac_hash_alg(alg, &hash_alg)); - - GUARD(s2n_hash_init(&state->inner, hash_alg)); - GUARD(s2n_hash_init(&state->inner_just_key, hash_alg)); - GUARD(s2n_hash_init(&state->outer, hash_alg)); - GUARD(s2n_hash_init(&state->outer_just_key, hash_alg)); - - if (alg == S2N_HMAC_SSLv3_SHA1 || alg == S2N_HMAC_SSLv3_MD5) { - GUARD(s2n_sslv3_mac_init(state, alg, key, klen)); - } else { - GUARD(s2n_tls_hmac_init(state, alg, key, klen)); - } - - /* Once we have produced inner_just_key and outer_just_key, don't need the key material in xor_pad, so wipe it. - * Since xor_pad is used as a source of bytes in s2n_hmac_digest_two_compression_rounds, - * this also prevents uninitilized bytes being used. - */ - memset(&state->xor_pad, 0, sizeof(state->xor_pad)); - GUARD(s2n_hmac_reset(state)); - - return 0; -} - -int s2n_hmac_update(struct s2n_hmac_state *state, const void *in, uint32_t size) -{ - /* Keep track of how much of the current hash block is full - * - * Why the 4294949760 constant in this code? 4294949760 is the highest 32-bit - * value that is congruent to 0 modulo all of our HMAC block sizes, that is also - * at least 16k smaller than 2^32. It therefore has no effect on the mathematical - * result, and no valid record size can cause it to overflow. +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/md5.h> +#include <openssl/sha.h> + +#include "error/s2n_errno.h" + +#include "crypto/s2n_hmac.h" +#include "crypto/s2n_hash.h" +#include "crypto/s2n_fips.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_mem.h" + +#include <stdint.h> + + +int s2n_hmac_hash_alg(s2n_hmac_algorithm hmac_alg, s2n_hash_algorithm *out) +{ + switch(hmac_alg) { + case S2N_HMAC_NONE: *out = S2N_HASH_NONE; break; + case S2N_HMAC_MD5: *out = S2N_HASH_MD5; break; + case S2N_HMAC_SHA1: *out = S2N_HASH_SHA1; break; + case S2N_HMAC_SHA224: *out = S2N_HASH_SHA224; break; + case S2N_HMAC_SHA256: *out = S2N_HASH_SHA256; break; + case S2N_HMAC_SHA384: *out = S2N_HASH_SHA384; break; + case S2N_HMAC_SHA512: *out = S2N_HASH_SHA512; break; + case S2N_HMAC_SSLv3_MD5: *out = S2N_HASH_MD5; break; + case S2N_HMAC_SSLv3_SHA1: *out = S2N_HASH_SHA1; break; + default: + S2N_ERROR(S2N_ERR_HMAC_INVALID_ALGORITHM); + } + return 0; +} + +int s2n_hmac_digest_size(s2n_hmac_algorithm hmac_alg, uint8_t *out) +{ + s2n_hash_algorithm hash_alg; + GUARD(s2n_hmac_hash_alg(hmac_alg, &hash_alg)); + GUARD(s2n_hash_digest_size(hash_alg, out)); + return 0; +} + +/* Return 1 if hmac algorithm is available, 0 otherwise. */ +int s2n_hmac_is_available(s2n_hmac_algorithm hmac_alg) +{ + int is_available = 0; + switch(hmac_alg) { + case S2N_HMAC_MD5: + case S2N_HMAC_SSLv3_MD5: + case S2N_HMAC_SSLv3_SHA1: + /* Set is_available to 0 if in FIPS mode, as MD5/SSLv3 algs are not available in FIPS mode. */ + is_available = !s2n_is_in_fips_mode(); + break; + case S2N_HMAC_NONE: + case S2N_HMAC_SHA1: + case S2N_HMAC_SHA224: + case S2N_HMAC_SHA256: + case S2N_HMAC_SHA384: + case S2N_HMAC_SHA512: + is_available = 1; + break; + default: + S2N_ERROR(S2N_ERR_HMAC_INVALID_ALGORITHM); + } + + return is_available; +} + +static int s2n_sslv3_mac_init(struct s2n_hmac_state *state, s2n_hmac_algorithm alg, const void *key, uint32_t klen) +{ + for (int i = 0; i < state->xor_pad_size; i++) { + state->xor_pad[i] = 0x36; + } + + GUARD(s2n_hash_update(&state->inner_just_key, key, klen)); + GUARD(s2n_hash_update(&state->inner_just_key, state->xor_pad, state->xor_pad_size)); + + for (int i = 0; i < state->xor_pad_size; i++) { + state->xor_pad[i] = 0x5c; + } + + GUARD(s2n_hash_update(&state->outer_just_key, key, klen)); + GUARD(s2n_hash_update(&state->outer_just_key, state->xor_pad, state->xor_pad_size)); + + return 0; +} + +static int s2n_tls_hmac_init(struct s2n_hmac_state *state, s2n_hmac_algorithm alg, const void *key, uint32_t klen) +{ + memset(&state->xor_pad, 0, sizeof(state->xor_pad)); + + if (klen > state->xor_pad_size) { + GUARD(s2n_hash_update(&state->outer, key, klen)); + GUARD(s2n_hash_digest(&state->outer, state->digest_pad, state->digest_size)); + memcpy_check(state->xor_pad, state->digest_pad, state->digest_size); + } else { + memcpy_check(state->xor_pad, key, klen); + } + + for (int i = 0; i < state->xor_pad_size; i++) { + state->xor_pad[i] ^= 0x36; + } + + GUARD(s2n_hash_update(&state->inner_just_key, state->xor_pad, state->xor_pad_size)); + + /* 0x36 xor 0x5c == 0x6a */ + for (int i = 0; i < state->xor_pad_size; i++) { + state->xor_pad[i] ^= 0x6a; + } + + GUARD(s2n_hash_update(&state->outer_just_key, state->xor_pad, state->xor_pad_size)); + return 0; +} + +int s2n_hmac_xor_pad_size(s2n_hmac_algorithm hmac_alg, uint16_t *xor_pad_size) +{ + switch(hmac_alg) { + case S2N_HMAC_NONE: *xor_pad_size = 64; break; + case S2N_HMAC_MD5: *xor_pad_size = 64; break; + case S2N_HMAC_SHA1: *xor_pad_size = 64; break; + case S2N_HMAC_SHA224: *xor_pad_size = 64; break; + case S2N_HMAC_SHA256: *xor_pad_size = 64; break; + case S2N_HMAC_SHA384: *xor_pad_size = 128; break; + case S2N_HMAC_SHA512: *xor_pad_size = 128; break; + case S2N_HMAC_SSLv3_MD5: *xor_pad_size = 48; break; + case S2N_HMAC_SSLv3_SHA1: *xor_pad_size = 40; break; + default: + S2N_ERROR(S2N_ERR_HMAC_INVALID_ALGORITHM); + } + return 0; +} + +int s2n_hmac_hash_block_size(s2n_hmac_algorithm hmac_alg, uint16_t *block_size) +{ + switch(hmac_alg) { + case S2N_HMAC_NONE: *block_size = 64; break; + case S2N_HMAC_MD5: *block_size = 64; break; + case S2N_HMAC_SHA1: *block_size = 64; break; + case S2N_HMAC_SHA224: *block_size = 64; break; + case S2N_HMAC_SHA256: *block_size = 64; break; + case S2N_HMAC_SHA384: *block_size = 128; break; + case S2N_HMAC_SHA512: *block_size = 128; break; + case S2N_HMAC_SSLv3_MD5: *block_size = 64; break; + case S2N_HMAC_SSLv3_SHA1: *block_size = 64; break; + default: + S2N_ERROR(S2N_ERR_HMAC_INVALID_ALGORITHM); + } + return 0; +} + +int s2n_hmac_new(struct s2n_hmac_state *state) +{ + GUARD(s2n_hash_new(&state->inner)); + GUARD(s2n_hash_new(&state->inner_just_key)); + GUARD(s2n_hash_new(&state->outer)); + GUARD(s2n_hash_new(&state->outer_just_key)); + + return 0; +} + +int s2n_hmac_init(struct s2n_hmac_state *state, s2n_hmac_algorithm alg, const void *key, uint32_t klen) +{ + if (!s2n_hmac_is_available(alg)) { + /* Prevent hmacs from being used if they are not available. */ + S2N_ERROR(S2N_ERR_HMAC_INVALID_ALGORITHM); + } + + state->alg = alg; + GUARD(s2n_hmac_hash_block_size(alg, &state->hash_block_size)); + state->currently_in_hash_block = 0; + GUARD(s2n_hmac_xor_pad_size(alg, &state->xor_pad_size)); + GUARD(s2n_hmac_digest_size(alg, &state->digest_size)); + + gte_check(sizeof(state->xor_pad), state->xor_pad_size); + gte_check(sizeof(state->digest_pad), state->digest_size); + /* key needs to be as large as the biggest block size */ + gte_check(sizeof(state->xor_pad), state->hash_block_size); + + s2n_hash_algorithm hash_alg; + GUARD(s2n_hmac_hash_alg(alg, &hash_alg)); + + GUARD(s2n_hash_init(&state->inner, hash_alg)); + GUARD(s2n_hash_init(&state->inner_just_key, hash_alg)); + GUARD(s2n_hash_init(&state->outer, hash_alg)); + GUARD(s2n_hash_init(&state->outer_just_key, hash_alg)); + + if (alg == S2N_HMAC_SSLv3_SHA1 || alg == S2N_HMAC_SSLv3_MD5) { + GUARD(s2n_sslv3_mac_init(state, alg, key, klen)); + } else { + GUARD(s2n_tls_hmac_init(state, alg, key, klen)); + } + + /* Once we have produced inner_just_key and outer_just_key, don't need the key material in xor_pad, so wipe it. + * Since xor_pad is used as a source of bytes in s2n_hmac_digest_two_compression_rounds, + * this also prevents uninitilized bytes being used. + */ + memset(&state->xor_pad, 0, sizeof(state->xor_pad)); + GUARD(s2n_hmac_reset(state)); + + return 0; +} + +int s2n_hmac_update(struct s2n_hmac_state *state, const void *in, uint32_t size) +{ + /* Keep track of how much of the current hash block is full * - * The value was found with the following python code; + * Why the 4294949760 constant in this code? 4294949760 is the highest 32-bit + * value that is congruent to 0 modulo all of our HMAC block sizes, that is also + * at least 16k smaller than 2^32. It therefore has no effect on the mathematical + * result, and no valid record size can cause it to overflow. + * + * The value was found with the following python code; + * + * x = (2 ** 32) - (2 ** 14) + * while True: + * if x % 40 | x % 48 | x % 64 | x % 128 == 0: + * break + * x -= 1 + * print x * - * x = (2 ** 32) - (2 ** 14) - * while True: - * if x % 40 | x % 48 | x % 64 | x % 128 == 0: - * break - * x -= 1 - * print x - * - * What it does do however is ensure that the mod operation takes a - * constant number of instruction cycles, regardless of the size of the - * input. On some platforms, including Intel, the operation can take a - * smaller number of cycles if the input is "small". - */ - state->currently_in_hash_block += (4294949760 + size) % state->hash_block_size; - state->currently_in_hash_block %= state->hash_block_size; - - return s2n_hash_update(&state->inner, in, size); -} - -int s2n_hmac_digest(struct s2n_hmac_state *state, void *out, uint32_t size) -{ - GUARD(s2n_hash_digest(&state->inner, state->digest_pad, state->digest_size)); - GUARD(s2n_hash_copy(&state->outer, &state->outer_just_key)); - GUARD(s2n_hash_update(&state->outer, state->digest_pad, state->digest_size)); - - return s2n_hash_digest(&state->outer, out, size); -} - -int s2n_hmac_digest_two_compression_rounds(struct s2n_hmac_state *state, void *out, uint32_t size) -{ - /* Do the "real" work of this function. */ - GUARD(s2n_hmac_digest(state, out, size)); - - /* If there were 9 or more bytes of space left in the current hash block - * then the serialized length, plus an 0x80 byte, will have fit in that block. - * If there were fewer than 9 then adding the length will have caused an extra - * compression block round. This digest function always does two compression rounds, - * even if there is no need for the second. - * - * 17 bytes if the block size is 128. - */ - const uint8_t space_left = (state->hash_block_size == 128) ? 17 : 9; - if (state->currently_in_hash_block > (state->hash_block_size - space_left)) { - return 0; - } - - /* Can't reuse a hash after it has been finalized, so reset and push another block in */ - GUARD(s2n_hash_reset(&state->inner)); - - /* No-op s2n_hash_update to normalize timing and guard against Lucky13. This does not affect the value of *out. */ - return s2n_hash_update(&state->inner, state->xor_pad, state->hash_block_size); -} - -int s2n_hmac_free(struct s2n_hmac_state *state) -{ - GUARD(s2n_hash_free(&state->inner)); - GUARD(s2n_hash_free(&state->inner_just_key)); - GUARD(s2n_hash_free(&state->outer)); - GUARD(s2n_hash_free(&state->outer_just_key)); - - return 0; -} - -int s2n_hmac_reset(struct s2n_hmac_state *state) -{ - GUARD(s2n_hash_copy(&state->inner, &state->inner_just_key)); - - uint64_t bytes_in_hash; - GUARD(s2n_hash_get_currently_in_hash_total(&state->inner, &bytes_in_hash)); - /* The length of the key is not private, so don't need to do tricky math here */ - state->currently_in_hash_block = bytes_in_hash % state->hash_block_size; - return 0; -} - -int s2n_hmac_digest_verify(const void *a, const void *b, uint32_t len) -{ - return 0 - !s2n_constant_time_equals(a, b, len); -} - -int s2n_hmac_copy(struct s2n_hmac_state *to, struct s2n_hmac_state *from) -{ - /* memcpy cannot be used on s2n_hmac_state as the underlying s2n_hash implementation's - * copy must be used. This is enforced when the s2n_hash implementation is s2n_evp_hash. - */ - to->alg = from->alg; - to->hash_block_size = from->hash_block_size; - to->currently_in_hash_block = from->currently_in_hash_block; - to->xor_pad_size = from->xor_pad_size; - to->digest_size = from->digest_size; - - GUARD(s2n_hash_copy(&to->inner, &from->inner)); - GUARD(s2n_hash_copy(&to->inner_just_key, &from->inner_just_key)); - GUARD(s2n_hash_copy(&to->outer, &from->outer)); - GUARD(s2n_hash_copy(&to->outer_just_key, &from->outer_just_key)); - - - memcpy_check(to->xor_pad, from->xor_pad, sizeof(to->xor_pad)); - memcpy_check(to->digest_pad, from->digest_pad, sizeof(to->digest_pad)); - - return 0; -} - - -/* Preserve the handlers for hmac state pointers to avoid re-allocation - * Only valid if the HMAC is in EVP mode - */ -int s2n_hmac_save_evp_hash_state(struct s2n_hmac_evp_backup* backup, struct s2n_hmac_state* hmac) -{ - backup->inner = hmac->inner.digest.high_level; - backup->inner_just_key = hmac->inner_just_key.digest.high_level; - backup->outer = hmac->outer.digest.high_level; - backup->outer_just_key = hmac->outer_just_key.digest.high_level; - return 0; -} - -int s2n_hmac_restore_evp_hash_state(struct s2n_hmac_evp_backup* backup, struct s2n_hmac_state* hmac) -{ - hmac->inner.digest.high_level = backup->inner; - hmac->inner_just_key.digest.high_level = backup->inner_just_key; - hmac->outer.digest.high_level = backup->outer; - hmac->outer_just_key.digest.high_level = backup->outer_just_key; - return 0; -} + * What it does do however is ensure that the mod operation takes a + * constant number of instruction cycles, regardless of the size of the + * input. On some platforms, including Intel, the operation can take a + * smaller number of cycles if the input is "small". + */ + state->currently_in_hash_block += (4294949760 + size) % state->hash_block_size; + state->currently_in_hash_block %= state->hash_block_size; + + return s2n_hash_update(&state->inner, in, size); +} + +int s2n_hmac_digest(struct s2n_hmac_state *state, void *out, uint32_t size) +{ + GUARD(s2n_hash_digest(&state->inner, state->digest_pad, state->digest_size)); + GUARD(s2n_hash_copy(&state->outer, &state->outer_just_key)); + GUARD(s2n_hash_update(&state->outer, state->digest_pad, state->digest_size)); + + return s2n_hash_digest(&state->outer, out, size); +} + +int s2n_hmac_digest_two_compression_rounds(struct s2n_hmac_state *state, void *out, uint32_t size) +{ + /* Do the "real" work of this function. */ + GUARD(s2n_hmac_digest(state, out, size)); + + /* If there were 9 or more bytes of space left in the current hash block + * then the serialized length, plus an 0x80 byte, will have fit in that block. + * If there were fewer than 9 then adding the length will have caused an extra + * compression block round. This digest function always does two compression rounds, + * even if there is no need for the second. + * + * 17 bytes if the block size is 128. + */ + const uint8_t space_left = (state->hash_block_size == 128) ? 17 : 9; + if (state->currently_in_hash_block > (state->hash_block_size - space_left)) { + return 0; + } + + /* Can't reuse a hash after it has been finalized, so reset and push another block in */ + GUARD(s2n_hash_reset(&state->inner)); + + /* No-op s2n_hash_update to normalize timing and guard against Lucky13. This does not affect the value of *out. */ + return s2n_hash_update(&state->inner, state->xor_pad, state->hash_block_size); +} + +int s2n_hmac_free(struct s2n_hmac_state *state) +{ + GUARD(s2n_hash_free(&state->inner)); + GUARD(s2n_hash_free(&state->inner_just_key)); + GUARD(s2n_hash_free(&state->outer)); + GUARD(s2n_hash_free(&state->outer_just_key)); + + return 0; +} + +int s2n_hmac_reset(struct s2n_hmac_state *state) +{ + GUARD(s2n_hash_copy(&state->inner, &state->inner_just_key)); + + uint64_t bytes_in_hash; + GUARD(s2n_hash_get_currently_in_hash_total(&state->inner, &bytes_in_hash)); + /* The length of the key is not private, so don't need to do tricky math here */ + state->currently_in_hash_block = bytes_in_hash % state->hash_block_size; + return 0; +} + +int s2n_hmac_digest_verify(const void *a, const void *b, uint32_t len) +{ + return 0 - !s2n_constant_time_equals(a, b, len); +} + +int s2n_hmac_copy(struct s2n_hmac_state *to, struct s2n_hmac_state *from) +{ + /* memcpy cannot be used on s2n_hmac_state as the underlying s2n_hash implementation's + * copy must be used. This is enforced when the s2n_hash implementation is s2n_evp_hash. + */ + to->alg = from->alg; + to->hash_block_size = from->hash_block_size; + to->currently_in_hash_block = from->currently_in_hash_block; + to->xor_pad_size = from->xor_pad_size; + to->digest_size = from->digest_size; + + GUARD(s2n_hash_copy(&to->inner, &from->inner)); + GUARD(s2n_hash_copy(&to->inner_just_key, &from->inner_just_key)); + GUARD(s2n_hash_copy(&to->outer, &from->outer)); + GUARD(s2n_hash_copy(&to->outer_just_key, &from->outer_just_key)); + + + memcpy_check(to->xor_pad, from->xor_pad, sizeof(to->xor_pad)); + memcpy_check(to->digest_pad, from->digest_pad, sizeof(to->digest_pad)); + + return 0; +} + + +/* Preserve the handlers for hmac state pointers to avoid re-allocation + * Only valid if the HMAC is in EVP mode + */ +int s2n_hmac_save_evp_hash_state(struct s2n_hmac_evp_backup* backup, struct s2n_hmac_state* hmac) +{ + backup->inner = hmac->inner.digest.high_level; + backup->inner_just_key = hmac->inner_just_key.digest.high_level; + backup->outer = hmac->outer.digest.high_level; + backup->outer_just_key = hmac->outer_just_key.digest.high_level; + return 0; +} + +int s2n_hmac_restore_evp_hash_state(struct s2n_hmac_evp_backup* backup, struct s2n_hmac_state* hmac) +{ + hmac->inner.digest.high_level = backup->inner; + hmac->inner_just_key.digest.high_level = backup->inner_just_key; + hmac->outer.digest.high_level = backup->outer; + hmac->outer_just_key.digest.high_level = backup->outer_just_key; + return 0; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_hmac.h b/contrib/restricted/aws/s2n/crypto/s2n_hmac.h index b54966f8c3..e2be24dd05 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_hmac.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_hmac.h @@ -1,79 +1,79 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <stdint.h> - -#include "crypto/s2n_hash.h" - -typedef enum { - S2N_HMAC_NONE, - S2N_HMAC_MD5, - S2N_HMAC_SHA1, - S2N_HMAC_SHA224, - S2N_HMAC_SHA256, - S2N_HMAC_SHA384, - S2N_HMAC_SHA512, - S2N_HMAC_SSLv3_MD5, - S2N_HMAC_SSLv3_SHA1 -} s2n_hmac_algorithm; - -struct s2n_hmac_state { - s2n_hmac_algorithm alg; - - uint16_t hash_block_size; - uint32_t currently_in_hash_block; - uint16_t xor_pad_size; - uint8_t digest_size; - - struct s2n_hash_state inner; - struct s2n_hash_state inner_just_key; - struct s2n_hash_state outer; - struct s2n_hash_state outer_just_key; - - - /* key needs to be as large as the biggest block size */ - uint8_t xor_pad[128]; - - /* For storing the inner digest */ - uint8_t digest_pad[SHA512_DIGEST_LENGTH]; -}; - -struct s2n_hmac_evp_backup { - struct s2n_hash_evp_digest inner; - struct s2n_hash_evp_digest inner_just_key; - struct s2n_hash_evp_digest outer; - struct s2n_hash_evp_digest outer_just_key; -}; - -extern int s2n_hmac_digest_size(s2n_hmac_algorithm alg, uint8_t *out); -extern int s2n_hmac_is_available(s2n_hmac_algorithm alg); -extern int s2n_hmac_hash_alg(s2n_hmac_algorithm hmac_alg, s2n_hash_algorithm *out); -extern int s2n_hash_hmac_alg(s2n_hash_algorithm hash_alg, s2n_hmac_algorithm *out); - -extern int s2n_hmac_new(struct s2n_hmac_state *state); -extern int s2n_hmac_init(struct s2n_hmac_state *state, s2n_hmac_algorithm alg, const void *key, uint32_t klen); -extern int s2n_hmac_update(struct s2n_hmac_state *state, const void *in, uint32_t size); -extern int s2n_hmac_digest(struct s2n_hmac_state *state, void *out, uint32_t size); -extern int s2n_hmac_digest_two_compression_rounds(struct s2n_hmac_state *state, void *out, uint32_t size); -extern int s2n_hmac_digest_verify(const void *a, const void *b, uint32_t len); -extern int s2n_hmac_free(struct s2n_hmac_state *state); -extern int s2n_hmac_reset(struct s2n_hmac_state *state); -extern int s2n_hmac_copy(struct s2n_hmac_state *to, struct s2n_hmac_state *from); -extern int s2n_hmac_save_evp_hash_state(struct s2n_hmac_evp_backup* backup, struct s2n_hmac_state* hmac); -extern int s2n_hmac_restore_evp_hash_state(struct s2n_hmac_evp_backup* backup, struct s2n_hmac_state* hmac); - - +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <stdint.h> + +#include "crypto/s2n_hash.h" + +typedef enum { + S2N_HMAC_NONE, + S2N_HMAC_MD5, + S2N_HMAC_SHA1, + S2N_HMAC_SHA224, + S2N_HMAC_SHA256, + S2N_HMAC_SHA384, + S2N_HMAC_SHA512, + S2N_HMAC_SSLv3_MD5, + S2N_HMAC_SSLv3_SHA1 +} s2n_hmac_algorithm; + +struct s2n_hmac_state { + s2n_hmac_algorithm alg; + + uint16_t hash_block_size; + uint32_t currently_in_hash_block; + uint16_t xor_pad_size; + uint8_t digest_size; + + struct s2n_hash_state inner; + struct s2n_hash_state inner_just_key; + struct s2n_hash_state outer; + struct s2n_hash_state outer_just_key; + + + /* key needs to be as large as the biggest block size */ + uint8_t xor_pad[128]; + + /* For storing the inner digest */ + uint8_t digest_pad[SHA512_DIGEST_LENGTH]; +}; + +struct s2n_hmac_evp_backup { + struct s2n_hash_evp_digest inner; + struct s2n_hash_evp_digest inner_just_key; + struct s2n_hash_evp_digest outer; + struct s2n_hash_evp_digest outer_just_key; +}; + +extern int s2n_hmac_digest_size(s2n_hmac_algorithm alg, uint8_t *out); +extern int s2n_hmac_is_available(s2n_hmac_algorithm alg); +extern int s2n_hmac_hash_alg(s2n_hmac_algorithm hmac_alg, s2n_hash_algorithm *out); +extern int s2n_hash_hmac_alg(s2n_hash_algorithm hash_alg, s2n_hmac_algorithm *out); + +extern int s2n_hmac_new(struct s2n_hmac_state *state); +extern int s2n_hmac_init(struct s2n_hmac_state *state, s2n_hmac_algorithm alg, const void *key, uint32_t klen); +extern int s2n_hmac_update(struct s2n_hmac_state *state, const void *in, uint32_t size); +extern int s2n_hmac_digest(struct s2n_hmac_state *state, void *out, uint32_t size); +extern int s2n_hmac_digest_two_compression_rounds(struct s2n_hmac_state *state, void *out, uint32_t size); +extern int s2n_hmac_digest_verify(const void *a, const void *b, uint32_t len); +extern int s2n_hmac_free(struct s2n_hmac_state *state); +extern int s2n_hmac_reset(struct s2n_hmac_state *state); +extern int s2n_hmac_copy(struct s2n_hmac_state *to, struct s2n_hmac_state *from); +extern int s2n_hmac_save_evp_hash_state(struct s2n_hmac_evp_backup* backup, struct s2n_hmac_state* hmac); +extern int s2n_hmac_restore_evp_hash_state(struct s2n_hmac_evp_backup* backup, struct s2n_hmac_state* hmac); + + diff --git a/contrib/restricted/aws/s2n/crypto/s2n_openssl.h b/contrib/restricted/aws/s2n/crypto/s2n_openssl.h index 92c53c26fd..a7ec6c8739 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_openssl.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_openssl.h @@ -1,49 +1,49 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -/** - * openssl with OPENSSL_VERSION_NUMBER < 0x10100003L made data type details unavailable - * libressl use openssl with data type details available, but mandatorily set - * OPENSSL_VERSION_NUMBER = 0x20000000L, insane! - * https://github.com/aws/aws-sdk-cpp/pull/507/commits/2c99f1fe0c4b4683280caeb161538d4724d6a179 - */ -#if defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER == 0x20000000L) -#undef OPENSSL_VERSION_NUMBER -#define OPENSSL_VERSION_NUMBER 0x1000107fL -#endif - -/* Per https://wiki.openssl.org/index.php/Manual:OPENSSL_VERSION_NUMBER(3) - * OPENSSL_VERSION_NUMBER in hex is: MNNFFRBB major minor fix final beta/patch. - * bitwise: MMMMNNNNNNNNFFFFFFFFRRRRBBBBBBBB - * For our purposes we're only concerned about major/minor/fix. Patch versions don't usually introduce - * features. - */ - -#define S2N_OPENSSL_VERSION_AT_LEAST(major, minor, fix) \ - (OPENSSL_VERSION_NUMBER >= ((major << 28) + (minor << 20) + (fix << 12))) - -#if (S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)) && (!defined(OPENSSL_IS_BORINGSSL)) && (!defined(OPENSSL_IS_AWSLC)) -#define s2n_evp_ctx_init(ctx) GUARD_OSSL(EVP_CIPHER_CTX_init(ctx), S2N_ERR_DRBG) -#else -#define s2n_evp_ctx_init(ctx) EVP_CIPHER_CTX_init(ctx) -#endif - -#if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_FIPS) && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_AWSLC) -#define S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND 1 -#else -#define S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND 0 -#endif +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +/** + * openssl with OPENSSL_VERSION_NUMBER < 0x10100003L made data type details unavailable + * libressl use openssl with data type details available, but mandatorily set + * OPENSSL_VERSION_NUMBER = 0x20000000L, insane! + * https://github.com/aws/aws-sdk-cpp/pull/507/commits/2c99f1fe0c4b4683280caeb161538d4724d6a179 + */ +#if defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER == 0x20000000L) +#undef OPENSSL_VERSION_NUMBER +#define OPENSSL_VERSION_NUMBER 0x1000107fL +#endif + +/* Per https://wiki.openssl.org/index.php/Manual:OPENSSL_VERSION_NUMBER(3) + * OPENSSL_VERSION_NUMBER in hex is: MNNFFRBB major minor fix final beta/patch. + * bitwise: MMMMNNNNNNNNFFFFFFFFRRRRBBBBBBBB + * For our purposes we're only concerned about major/minor/fix. Patch versions don't usually introduce + * features. + */ + +#define S2N_OPENSSL_VERSION_AT_LEAST(major, minor, fix) \ + (OPENSSL_VERSION_NUMBER >= ((major << 28) + (minor << 20) + (fix << 12))) + +#if (S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)) && (!defined(OPENSSL_IS_BORINGSSL)) && (!defined(OPENSSL_IS_AWSLC)) +#define s2n_evp_ctx_init(ctx) GUARD_OSSL(EVP_CIPHER_CTX_init(ctx), S2N_ERR_DRBG) +#else +#define s2n_evp_ctx_init(ctx) EVP_CIPHER_CTX_init(ctx) +#endif + +#if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_FIPS) && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_AWSLC) +#define S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND 1 +#else +#define S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND 0 +#endif diff --git a/contrib/restricted/aws/s2n/crypto/s2n_openssl_evp.h b/contrib/restricted/aws/s2n/crypto/s2n_openssl_evp.h index 4b033bf2b2..1c9b874ac2 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_openssl_evp.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_openssl_evp.h @@ -1,22 +1,22 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <openssl/evp.h> - -#include "utils/s2n_safety.h" - -DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY*, EVP_PKEY_free); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <openssl/evp.h> + +#include "utils/s2n_safety.h" + +DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY*, EVP_PKEY_free); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_openssl_x509.h b/contrib/restricted/aws/s2n/crypto/s2n_openssl_x509.h index 812b7233ba..38d89c8d7a 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_openssl_x509.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_openssl_x509.h @@ -1,22 +1,22 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <openssl/x509.h> - -#include "utils/s2n_safety.h" - -DEFINE_POINTER_CLEANUP_FUNC(X509*, X509_free); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <openssl/x509.h> + +#include "utils/s2n_safety.h" + +DEFINE_POINTER_CLEANUP_FUNC(X509*, X509_free); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_pkey.c b/contrib/restricted/aws/s2n/crypto/s2n_pkey.c index 9123e88080..b280cc0854 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_pkey.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_pkey.c @@ -1,235 +1,235 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/evp.h> -#include <crypto/s2n_openssl_evp.h> -#include <crypto/s2n_openssl_x509.h> - -#include "error/s2n_errno.h" -#include "crypto/s2n_rsa_pss.h" -#include "crypto/s2n_pkey.h" - -#include "utils/s2n_safety.h" - -int s2n_pkey_zero_init(struct s2n_pkey *pkey) -{ - pkey->pkey = NULL; - pkey->size = NULL; - pkey->sign = NULL; - pkey->verify = NULL; - pkey->encrypt = NULL; - pkey->decrypt = NULL; - pkey->match = NULL; - pkey->free = NULL; - pkey->check_key = NULL; - return 0; -} - -int s2n_pkey_setup_for_type(struct s2n_pkey *pkey, s2n_pkey_type pkey_type) -{ - switch(pkey_type) { - case S2N_PKEY_TYPE_RSA: - return s2n_rsa_pkey_init(pkey); - case S2N_PKEY_TYPE_ECDSA: - return s2n_ecdsa_pkey_init(pkey); - case S2N_PKEY_TYPE_RSA_PSS: - return s2n_rsa_pss_pkey_init(pkey); - case S2N_PKEY_TYPE_SENTINEL: - case S2N_PKEY_TYPE_UNKNOWN: - S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); - } - S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); -} - -int s2n_pkey_check_key_exists(const struct s2n_pkey *pkey) -{ - notnull_check(pkey->pkey); - notnull_check(pkey->check_key); - - return pkey->check_key(pkey); -} - -int s2n_pkey_size(const struct s2n_pkey *pkey) -{ - notnull_check(pkey->size); - - return pkey->size(pkey); -} - -int s2n_pkey_sign(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature) -{ - notnull_check(pkey->sign); - - return pkey->sign(pkey, sig_alg, digest, signature); -} - -int s2n_pkey_verify(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature) -{ - notnull_check(pkey); - notnull_check(pkey->verify); - - return pkey->verify(pkey, sig_alg, digest, signature); -} - -int s2n_pkey_encrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out) -{ - notnull_check(pkey->encrypt); - - return pkey->encrypt(pkey, in, out); -} - -int s2n_pkey_decrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out) -{ - notnull_check(pkey->decrypt); - - return pkey->decrypt(pkey, in, out); -} - -int s2n_pkey_match(const struct s2n_pkey *pub_key, const struct s2n_pkey *priv_key) -{ - notnull_check(pub_key->match); - - S2N_ERROR_IF(pub_key->match != priv_key->match, S2N_ERR_KEY_MISMATCH); - - return pub_key->match(pub_key, priv_key); -} - -int s2n_pkey_free(struct s2n_pkey *key) -{ - if (key != NULL && key->free != NULL) { - GUARD(key->free(key)); - } - - if (key->pkey != NULL) { - EVP_PKEY_free(key->pkey); - key->pkey = NULL; - } - - return S2N_SUCCESS; -} - -int s2n_asn1der_to_private_key(struct s2n_pkey *priv_key, struct s2n_blob *asn1der) -{ - uint8_t *key_to_parse = asn1der->data; - - /* Detect key type */ - DEFER_CLEANUP(EVP_PKEY *evp_private_key = d2i_AutoPrivateKey(NULL, (const unsigned char **)(void *)&key_to_parse, asn1der->size), - EVP_PKEY_free_pointer); - S2N_ERROR_IF(evp_private_key == NULL, S2N_ERR_DECODE_PRIVATE_KEY); - - /* If key parsing is successful, d2i_AutoPrivateKey increments *key_to_parse to the byte following the parsed data */ - uint32_t parsed_len = key_to_parse - asn1der->data; - if (parsed_len != asn1der->size) { - S2N_ERROR(S2N_ERR_DECODE_PRIVATE_KEY); - } - - /* Initialize s2n_pkey according to key type */ - int type = EVP_PKEY_base_id(evp_private_key); - - int ret; - switch (type) { - case EVP_PKEY_RSA: - ret = s2n_rsa_pkey_init(priv_key); - if (ret != 0) { - break; - } - ret = s2n_evp_pkey_to_rsa_private_key(&priv_key->key.rsa_key, evp_private_key); - break; - case EVP_PKEY_RSA_PSS: - ret = s2n_rsa_pss_pkey_init(priv_key); - if (ret != 0) { - break; - } - ret = s2n_evp_pkey_to_rsa_pss_private_key(&priv_key->key.rsa_key, evp_private_key); - break; - case EVP_PKEY_EC: - ret = s2n_ecdsa_pkey_init(priv_key); - if (ret != 0) { - break; - } - ret = s2n_evp_pkey_to_ecdsa_private_key(&priv_key->key.ecdsa_key, evp_private_key); - break; - default: - S2N_ERROR(S2N_ERR_DECODE_PRIVATE_KEY); - } - - priv_key->pkey = evp_private_key; - /* Reset to avoid DEFER_CLEANUP freeing our key */ - evp_private_key = NULL; - - return ret; -} - -int s2n_asn1der_to_public_key_and_type(struct s2n_pkey *pub_key, s2n_pkey_type *pkey_type_out, struct s2n_blob *asn1der) -{ - uint8_t *cert_to_parse = asn1der->data; - DEFER_CLEANUP(X509 *cert = NULL, X509_free_pointer); - - cert = d2i_X509(NULL, (const unsigned char **)(void *)&cert_to_parse, asn1der->size); - S2N_ERROR_IF(cert == NULL, S2N_ERR_DECODE_CERTIFICATE); - - /* If cert parsing is successful, d2i_X509 increments *cert_to_parse to the byte following the parsed data */ - uint32_t parsed_len = cert_to_parse - asn1der->data; - - /* Some TLS clients in the wild send one extra trailing byte after the Certificate. - * Allow this in s2n for backwards compatibility with existing clients. */ - uint32_t trailing_bytes = asn1der->size - parsed_len; - ENSURE_POSIX(trailing_bytes <= 1, S2N_ERR_DECODE_CERTIFICATE); - - DEFER_CLEANUP(EVP_PKEY *evp_public_key = X509_get_pubkey(cert), EVP_PKEY_free_pointer); - S2N_ERROR_IF(evp_public_key == NULL, S2N_ERR_DECODE_CERTIFICATE); - - /* Check for success in decoding certificate according to type */ - int type = EVP_PKEY_base_id(evp_public_key); - - int ret; - switch (type) { - case EVP_PKEY_RSA: - ret = s2n_rsa_pkey_init(pub_key); - if (ret != 0) { - break; - } - ret = s2n_evp_pkey_to_rsa_public_key(&pub_key->key.rsa_key, evp_public_key); - *pkey_type_out = S2N_PKEY_TYPE_RSA; - break; - case EVP_PKEY_RSA_PSS: - ret = s2n_rsa_pss_pkey_init(pub_key); - if (ret != 0) { - break; - } - ret = s2n_evp_pkey_to_rsa_pss_public_key(&pub_key->key.rsa_key, evp_public_key); - *pkey_type_out = S2N_PKEY_TYPE_RSA_PSS; - break; - case EVP_PKEY_EC: - ret = s2n_ecdsa_pkey_init(pub_key); - if (ret != 0) { - break; - } - ret = s2n_evp_pkey_to_ecdsa_public_key(&pub_key->key.ecdsa_key, evp_public_key); - *pkey_type_out = S2N_PKEY_TYPE_ECDSA; - break; - default: - S2N_ERROR(S2N_ERR_DECODE_CERTIFICATE); - } - - pub_key->pkey = evp_public_key; - /* Reset to avoid DEFER_CLEANUP freeing our key */ - evp_public_key = NULL; - - return ret; -} - +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/evp.h> +#include <crypto/s2n_openssl_evp.h> +#include <crypto/s2n_openssl_x509.h> + +#include "error/s2n_errno.h" +#include "crypto/s2n_rsa_pss.h" +#include "crypto/s2n_pkey.h" + +#include "utils/s2n_safety.h" + +int s2n_pkey_zero_init(struct s2n_pkey *pkey) +{ + pkey->pkey = NULL; + pkey->size = NULL; + pkey->sign = NULL; + pkey->verify = NULL; + pkey->encrypt = NULL; + pkey->decrypt = NULL; + pkey->match = NULL; + pkey->free = NULL; + pkey->check_key = NULL; + return 0; +} + +int s2n_pkey_setup_for_type(struct s2n_pkey *pkey, s2n_pkey_type pkey_type) +{ + switch(pkey_type) { + case S2N_PKEY_TYPE_RSA: + return s2n_rsa_pkey_init(pkey); + case S2N_PKEY_TYPE_ECDSA: + return s2n_ecdsa_pkey_init(pkey); + case S2N_PKEY_TYPE_RSA_PSS: + return s2n_rsa_pss_pkey_init(pkey); + case S2N_PKEY_TYPE_SENTINEL: + case S2N_PKEY_TYPE_UNKNOWN: + S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); + } + S2N_ERROR(S2N_ERR_CERT_TYPE_UNSUPPORTED); +} + +int s2n_pkey_check_key_exists(const struct s2n_pkey *pkey) +{ + notnull_check(pkey->pkey); + notnull_check(pkey->check_key); + + return pkey->check_key(pkey); +} + +int s2n_pkey_size(const struct s2n_pkey *pkey) +{ + notnull_check(pkey->size); + + return pkey->size(pkey); +} + +int s2n_pkey_sign(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature) +{ + notnull_check(pkey->sign); + + return pkey->sign(pkey, sig_alg, digest, signature); +} + +int s2n_pkey_verify(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature) +{ + notnull_check(pkey); + notnull_check(pkey->verify); + + return pkey->verify(pkey, sig_alg, digest, signature); +} + +int s2n_pkey_encrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out) +{ + notnull_check(pkey->encrypt); + + return pkey->encrypt(pkey, in, out); +} + +int s2n_pkey_decrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out) +{ + notnull_check(pkey->decrypt); + + return pkey->decrypt(pkey, in, out); +} + +int s2n_pkey_match(const struct s2n_pkey *pub_key, const struct s2n_pkey *priv_key) +{ + notnull_check(pub_key->match); + + S2N_ERROR_IF(pub_key->match != priv_key->match, S2N_ERR_KEY_MISMATCH); + + return pub_key->match(pub_key, priv_key); +} + +int s2n_pkey_free(struct s2n_pkey *key) +{ + if (key != NULL && key->free != NULL) { + GUARD(key->free(key)); + } + + if (key->pkey != NULL) { + EVP_PKEY_free(key->pkey); + key->pkey = NULL; + } + + return S2N_SUCCESS; +} + +int s2n_asn1der_to_private_key(struct s2n_pkey *priv_key, struct s2n_blob *asn1der) +{ + uint8_t *key_to_parse = asn1der->data; + + /* Detect key type */ + DEFER_CLEANUP(EVP_PKEY *evp_private_key = d2i_AutoPrivateKey(NULL, (const unsigned char **)(void *)&key_to_parse, asn1der->size), + EVP_PKEY_free_pointer); + S2N_ERROR_IF(evp_private_key == NULL, S2N_ERR_DECODE_PRIVATE_KEY); + + /* If key parsing is successful, d2i_AutoPrivateKey increments *key_to_parse to the byte following the parsed data */ + uint32_t parsed_len = key_to_parse - asn1der->data; + if (parsed_len != asn1der->size) { + S2N_ERROR(S2N_ERR_DECODE_PRIVATE_KEY); + } + + /* Initialize s2n_pkey according to key type */ + int type = EVP_PKEY_base_id(evp_private_key); + + int ret; + switch (type) { + case EVP_PKEY_RSA: + ret = s2n_rsa_pkey_init(priv_key); + if (ret != 0) { + break; + } + ret = s2n_evp_pkey_to_rsa_private_key(&priv_key->key.rsa_key, evp_private_key); + break; + case EVP_PKEY_RSA_PSS: + ret = s2n_rsa_pss_pkey_init(priv_key); + if (ret != 0) { + break; + } + ret = s2n_evp_pkey_to_rsa_pss_private_key(&priv_key->key.rsa_key, evp_private_key); + break; + case EVP_PKEY_EC: + ret = s2n_ecdsa_pkey_init(priv_key); + if (ret != 0) { + break; + } + ret = s2n_evp_pkey_to_ecdsa_private_key(&priv_key->key.ecdsa_key, evp_private_key); + break; + default: + S2N_ERROR(S2N_ERR_DECODE_PRIVATE_KEY); + } + + priv_key->pkey = evp_private_key; + /* Reset to avoid DEFER_CLEANUP freeing our key */ + evp_private_key = NULL; + + return ret; +} + +int s2n_asn1der_to_public_key_and_type(struct s2n_pkey *pub_key, s2n_pkey_type *pkey_type_out, struct s2n_blob *asn1der) +{ + uint8_t *cert_to_parse = asn1der->data; + DEFER_CLEANUP(X509 *cert = NULL, X509_free_pointer); + + cert = d2i_X509(NULL, (const unsigned char **)(void *)&cert_to_parse, asn1der->size); + S2N_ERROR_IF(cert == NULL, S2N_ERR_DECODE_CERTIFICATE); + + /* If cert parsing is successful, d2i_X509 increments *cert_to_parse to the byte following the parsed data */ + uint32_t parsed_len = cert_to_parse - asn1der->data; + + /* Some TLS clients in the wild send one extra trailing byte after the Certificate. + * Allow this in s2n for backwards compatibility with existing clients. */ + uint32_t trailing_bytes = asn1der->size - parsed_len; + ENSURE_POSIX(trailing_bytes <= 1, S2N_ERR_DECODE_CERTIFICATE); + + DEFER_CLEANUP(EVP_PKEY *evp_public_key = X509_get_pubkey(cert), EVP_PKEY_free_pointer); + S2N_ERROR_IF(evp_public_key == NULL, S2N_ERR_DECODE_CERTIFICATE); + + /* Check for success in decoding certificate according to type */ + int type = EVP_PKEY_base_id(evp_public_key); + + int ret; + switch (type) { + case EVP_PKEY_RSA: + ret = s2n_rsa_pkey_init(pub_key); + if (ret != 0) { + break; + } + ret = s2n_evp_pkey_to_rsa_public_key(&pub_key->key.rsa_key, evp_public_key); + *pkey_type_out = S2N_PKEY_TYPE_RSA; + break; + case EVP_PKEY_RSA_PSS: + ret = s2n_rsa_pss_pkey_init(pub_key); + if (ret != 0) { + break; + } + ret = s2n_evp_pkey_to_rsa_pss_public_key(&pub_key->key.rsa_key, evp_public_key); + *pkey_type_out = S2N_PKEY_TYPE_RSA_PSS; + break; + case EVP_PKEY_EC: + ret = s2n_ecdsa_pkey_init(pub_key); + if (ret != 0) { + break; + } + ret = s2n_evp_pkey_to_ecdsa_public_key(&pub_key->key.ecdsa_key, evp_public_key); + *pkey_type_out = S2N_PKEY_TYPE_ECDSA; + break; + default: + S2N_ERROR(S2N_ERR_DECODE_CERTIFICATE); + } + + pub_key->pkey = evp_public_key; + /* Reset to avoid DEFER_CLEANUP freeing our key */ + evp_public_key = NULL; + + return ret; +} + diff --git a/contrib/restricted/aws/s2n/crypto/s2n_pkey.h b/contrib/restricted/aws/s2n/crypto/s2n_pkey.h index 1da8f785c6..c39468695a 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_pkey.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_pkey.h @@ -1,73 +1,73 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <openssl/evp.h> - -#include "crypto/s2n_signature.h" -#include "crypto/s2n_ecdsa.h" -#include "crypto/s2n_hash.h" -#include "crypto/s2n_rsa.h" - -#include "utils/s2n_blob.h" - -/* Public/Private Key Type */ -typedef enum { - S2N_PKEY_TYPE_UNKNOWN = -1, - S2N_PKEY_TYPE_RSA = 0, - S2N_PKEY_TYPE_ECDSA, - S2N_PKEY_TYPE_RSA_PSS, - S2N_PKEY_TYPE_SENTINEL -} s2n_pkey_type; - -/* Structure that models a public or private key and type-specific operations */ -struct s2n_pkey { - /* Legacy OpenSSL APIs operate on specific keys, but the more recent - * APIs all operate on EVP_PKEY. Let's store both for backwards compatibility. */ - union { - struct s2n_rsa_key rsa_key; - struct s2n_ecdsa_key ecdsa_key; - } key; - EVP_PKEY *pkey; - - int (*size)(const struct s2n_pkey *key); - int (*sign)(const struct s2n_pkey *priv_key, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature); - int (*verify)(const struct s2n_pkey *pub_key, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature); - int (*encrypt)(const struct s2n_pkey *key, struct s2n_blob *in, struct s2n_blob *out); - int (*decrypt)(const struct s2n_pkey *key, struct s2n_blob *in, struct s2n_blob *out); - int (*match)(const struct s2n_pkey *pub_key, const struct s2n_pkey *priv_key); - int (*free)(struct s2n_pkey *key); - int (*check_key)(const struct s2n_pkey *key); -}; - -int s2n_pkey_zero_init(struct s2n_pkey *pkey); -int s2n_pkey_setup_for_type(struct s2n_pkey *pkey, s2n_pkey_type pkey_type); -int s2n_pkey_check_key_exists(const struct s2n_pkey *pkey); - -int s2n_pkey_size(const struct s2n_pkey *pkey); -int s2n_pkey_sign(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature); -int s2n_pkey_verify(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature); -int s2n_pkey_encrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out); -int s2n_pkey_decrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out); -int s2n_pkey_match(const struct s2n_pkey *pub_key, const struct s2n_pkey *priv_key); -int s2n_pkey_free(struct s2n_pkey *pkey); - -int s2n_asn1der_to_private_key(struct s2n_pkey *priv_key, struct s2n_blob *asn1der); -int s2n_asn1der_to_public_key_and_type(struct s2n_pkey *pub_key, s2n_pkey_type *pkey_type, struct s2n_blob *asn1der); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <openssl/evp.h> + +#include "crypto/s2n_signature.h" +#include "crypto/s2n_ecdsa.h" +#include "crypto/s2n_hash.h" +#include "crypto/s2n_rsa.h" + +#include "utils/s2n_blob.h" + +/* Public/Private Key Type */ +typedef enum { + S2N_PKEY_TYPE_UNKNOWN = -1, + S2N_PKEY_TYPE_RSA = 0, + S2N_PKEY_TYPE_ECDSA, + S2N_PKEY_TYPE_RSA_PSS, + S2N_PKEY_TYPE_SENTINEL +} s2n_pkey_type; + +/* Structure that models a public or private key and type-specific operations */ +struct s2n_pkey { + /* Legacy OpenSSL APIs operate on specific keys, but the more recent + * APIs all operate on EVP_PKEY. Let's store both for backwards compatibility. */ + union { + struct s2n_rsa_key rsa_key; + struct s2n_ecdsa_key ecdsa_key; + } key; + EVP_PKEY *pkey; + + int (*size)(const struct s2n_pkey *key); + int (*sign)(const struct s2n_pkey *priv_key, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature); + int (*verify)(const struct s2n_pkey *pub_key, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature); + int (*encrypt)(const struct s2n_pkey *key, struct s2n_blob *in, struct s2n_blob *out); + int (*decrypt)(const struct s2n_pkey *key, struct s2n_blob *in, struct s2n_blob *out); + int (*match)(const struct s2n_pkey *pub_key, const struct s2n_pkey *priv_key); + int (*free)(struct s2n_pkey *key); + int (*check_key)(const struct s2n_pkey *key); +}; + +int s2n_pkey_zero_init(struct s2n_pkey *pkey); +int s2n_pkey_setup_for_type(struct s2n_pkey *pkey, s2n_pkey_type pkey_type); +int s2n_pkey_check_key_exists(const struct s2n_pkey *pkey); + +int s2n_pkey_size(const struct s2n_pkey *pkey); +int s2n_pkey_sign(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature); +int s2n_pkey_verify(const struct s2n_pkey *pkey, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature); +int s2n_pkey_encrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out); +int s2n_pkey_decrypt(const struct s2n_pkey *pkey, struct s2n_blob *in, struct s2n_blob *out); +int s2n_pkey_match(const struct s2n_pkey *pub_key, const struct s2n_pkey *priv_key); +int s2n_pkey_free(struct s2n_pkey *pkey); + +int s2n_asn1der_to_private_key(struct s2n_pkey *priv_key, struct s2n_blob *asn1der); +int s2n_asn1der_to_public_key_and_type(struct s2n_pkey *pub_key, s2n_pkey_type *pkey_type, struct s2n_blob *asn1der); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_rsa.c b/contrib/restricted/aws/s2n/crypto/s2n_rsa.c index 38eba11e0b..88b6603e7a 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_rsa.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_rsa.c @@ -1,190 +1,190 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/evp.h> -#include <openssl/rsa.h> -#include <stdint.h> - -#include "error/s2n_errno.h" - -#include "stuffer/s2n_stuffer.h" - -#include "crypto/s2n_hash.h" -#include "crypto/s2n_drbg.h" -#include "crypto/s2n_rsa.h" -#include "crypto/s2n_rsa_signing.h" -#include "crypto/s2n_pkey.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_random.h" -#include "utils/s2n_blob.h" - -static int s2n_rsa_modulus_check(RSA *rsa) -{ - /* RSA was made opaque starting in Openssl 1.1.0 */ - #if S2N_OPENSSL_VERSION_AT_LEAST(1,1,0) && !defined(LIBRESSL_VERSION_NUMBER) - const BIGNUM *n = NULL; - /* RSA still owns the memory for n */ - RSA_get0_key(rsa, &n, NULL, NULL); - notnull_check(n); - #else - notnull_check(rsa->n); - #endif - return 0; -} - -static int s2n_rsa_encrypted_size(const struct s2n_pkey *key) -{ - const struct s2n_rsa_key *rsa_key = &key->key.rsa_key; - notnull_check(rsa_key->rsa); - GUARD(s2n_rsa_modulus_check(rsa_key->rsa)); - - return RSA_size(rsa_key->rsa); -} - -static int s2n_rsa_sign(const struct s2n_pkey *priv, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature) -{ - switch(sig_alg) { - case S2N_SIGNATURE_RSA: - return s2n_rsa_pkcs1v15_sign(priv, digest, signature); - case S2N_SIGNATURE_RSA_PSS_RSAE: - return s2n_rsa_pss_sign(priv, digest, signature); - default: - S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); - } - - return S2N_SUCCESS; -} - -static int s2n_rsa_verify(const struct s2n_pkey *pub, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature) -{ - switch(sig_alg) { - case S2N_SIGNATURE_RSA: - return s2n_rsa_pkcs1v15_verify(pub, digest, signature); - case S2N_SIGNATURE_RSA_PSS_RSAE: - return s2n_rsa_pss_verify(pub, digest, signature); - default: - S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); - } - - return S2N_SUCCESS; -} - -static int s2n_rsa_encrypt(const struct s2n_pkey *pub, struct s2n_blob *in, struct s2n_blob *out) -{ - S2N_ERROR_IF(out->size < s2n_rsa_encrypted_size(pub), S2N_ERR_NOMEM); - - const s2n_rsa_public_key *key = &pub->key.rsa_key; - int r = RSA_public_encrypt(in->size, (unsigned char *)in->data, (unsigned char *)out->data, key->rsa, RSA_PKCS1_PADDING); - S2N_ERROR_IF(r != out->size, S2N_ERR_SIZE_MISMATCH); - - return 0; -} - -static int s2n_rsa_decrypt(const struct s2n_pkey *priv, struct s2n_blob *in, struct s2n_blob *out) -{ - unsigned char intermediate[4096]; - const int expected_size = s2n_rsa_encrypted_size(priv); - - GUARD(expected_size); - S2N_ERROR_IF(expected_size > sizeof(intermediate), S2N_ERR_NOMEM); - S2N_ERROR_IF(out->size > sizeof(intermediate), S2N_ERR_NOMEM); - - GUARD_AS_POSIX(s2n_get_public_random_data(out)); - - const s2n_rsa_private_key *key = &priv->key.rsa_key; - int r = RSA_private_decrypt(in->size, (unsigned char *)in->data, intermediate, key->rsa, RSA_NO_PADDING); - S2N_ERROR_IF(r != expected_size, S2N_ERR_SIZE_MISMATCH); - - s2n_constant_time_pkcs1_unpad_or_dont(out->data, intermediate, r, out->size); - - return 0; -} - -static int s2n_rsa_keys_match(const struct s2n_pkey *pub, const struct s2n_pkey *priv) -{ - uint8_t plain_inpad[36] = {1}, plain_outpad[36] = {0}, encpad[8192]; - struct s2n_blob plain_in = { 0 }, plain_out = { 0 }, enc = { 0 }; - - plain_in.data = plain_inpad; - plain_in.size = sizeof(plain_inpad); - - enc.data = encpad; - enc.size = s2n_rsa_encrypted_size(pub); - lte_check(enc.size, sizeof(encpad)); - GUARD(s2n_rsa_encrypt(pub, &plain_in, &enc)); - - plain_out.data = plain_outpad; - plain_out.size = sizeof(plain_outpad); - GUARD(s2n_rsa_decrypt(priv, &enc, &plain_out)); - - S2N_ERROR_IF(memcmp(plain_in.data, plain_out.data, plain_in.size), S2N_ERR_KEY_MISMATCH); - - return 0; -} - -static int s2n_rsa_key_free(struct s2n_pkey *pkey) -{ - struct s2n_rsa_key *rsa_key = &pkey->key.rsa_key; - if (rsa_key->rsa == NULL) { - return 0; - } - - RSA_free(rsa_key->rsa); - rsa_key->rsa = NULL; - - return 0; -} - -static int s2n_rsa_check_key_exists(const struct s2n_pkey *pkey) -{ - const struct s2n_rsa_key *rsa_key = &pkey->key.rsa_key; - notnull_check(rsa_key->rsa); - return 0; -} - -int s2n_evp_pkey_to_rsa_public_key(s2n_rsa_public_key *rsa_key, EVP_PKEY *evp_public_key) -{ - RSA *rsa = EVP_PKEY_get1_RSA(evp_public_key); - S2N_ERROR_IF(rsa == NULL, S2N_ERR_DECODE_CERTIFICATE); - - rsa_key->rsa = rsa; - return 0; -} - -int s2n_evp_pkey_to_rsa_private_key(s2n_rsa_private_key *rsa_key, EVP_PKEY *evp_private_key) -{ - RSA *rsa = EVP_PKEY_get1_RSA(evp_private_key); - S2N_ERROR_IF(rsa == NULL, S2N_ERR_DECODE_PRIVATE_KEY); - - rsa_key->rsa = rsa; - return 0; -} - -int s2n_rsa_pkey_init(struct s2n_pkey *pkey) -{ - pkey->size = &s2n_rsa_encrypted_size; - pkey->sign = &s2n_rsa_sign; - pkey->verify = &s2n_rsa_verify; - pkey->encrypt = &s2n_rsa_encrypt; - pkey->decrypt = &s2n_rsa_decrypt; - pkey->match = &s2n_rsa_keys_match; - pkey->free = &s2n_rsa_key_free; - pkey->check_key = &s2n_rsa_check_key_exists; - return 0; -} - +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/evp.h> +#include <openssl/rsa.h> +#include <stdint.h> + +#include "error/s2n_errno.h" + +#include "stuffer/s2n_stuffer.h" + +#include "crypto/s2n_hash.h" +#include "crypto/s2n_drbg.h" +#include "crypto/s2n_rsa.h" +#include "crypto/s2n_rsa_signing.h" +#include "crypto/s2n_pkey.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_random.h" +#include "utils/s2n_blob.h" + +static int s2n_rsa_modulus_check(RSA *rsa) +{ + /* RSA was made opaque starting in Openssl 1.1.0 */ + #if S2N_OPENSSL_VERSION_AT_LEAST(1,1,0) && !defined(LIBRESSL_VERSION_NUMBER) + const BIGNUM *n = NULL; + /* RSA still owns the memory for n */ + RSA_get0_key(rsa, &n, NULL, NULL); + notnull_check(n); + #else + notnull_check(rsa->n); + #endif + return 0; +} + +static int s2n_rsa_encrypted_size(const struct s2n_pkey *key) +{ + const struct s2n_rsa_key *rsa_key = &key->key.rsa_key; + notnull_check(rsa_key->rsa); + GUARD(s2n_rsa_modulus_check(rsa_key->rsa)); + + return RSA_size(rsa_key->rsa); +} + +static int s2n_rsa_sign(const struct s2n_pkey *priv, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature) +{ + switch(sig_alg) { + case S2N_SIGNATURE_RSA: + return s2n_rsa_pkcs1v15_sign(priv, digest, signature); + case S2N_SIGNATURE_RSA_PSS_RSAE: + return s2n_rsa_pss_sign(priv, digest, signature); + default: + S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); + } + + return S2N_SUCCESS; +} + +static int s2n_rsa_verify(const struct s2n_pkey *pub, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature) +{ + switch(sig_alg) { + case S2N_SIGNATURE_RSA: + return s2n_rsa_pkcs1v15_verify(pub, digest, signature); + case S2N_SIGNATURE_RSA_PSS_RSAE: + return s2n_rsa_pss_verify(pub, digest, signature); + default: + S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); + } + + return S2N_SUCCESS; +} + +static int s2n_rsa_encrypt(const struct s2n_pkey *pub, struct s2n_blob *in, struct s2n_blob *out) +{ + S2N_ERROR_IF(out->size < s2n_rsa_encrypted_size(pub), S2N_ERR_NOMEM); + + const s2n_rsa_public_key *key = &pub->key.rsa_key; + int r = RSA_public_encrypt(in->size, (unsigned char *)in->data, (unsigned char *)out->data, key->rsa, RSA_PKCS1_PADDING); + S2N_ERROR_IF(r != out->size, S2N_ERR_SIZE_MISMATCH); + + return 0; +} + +static int s2n_rsa_decrypt(const struct s2n_pkey *priv, struct s2n_blob *in, struct s2n_blob *out) +{ + unsigned char intermediate[4096]; + const int expected_size = s2n_rsa_encrypted_size(priv); + + GUARD(expected_size); + S2N_ERROR_IF(expected_size > sizeof(intermediate), S2N_ERR_NOMEM); + S2N_ERROR_IF(out->size > sizeof(intermediate), S2N_ERR_NOMEM); + + GUARD_AS_POSIX(s2n_get_public_random_data(out)); + + const s2n_rsa_private_key *key = &priv->key.rsa_key; + int r = RSA_private_decrypt(in->size, (unsigned char *)in->data, intermediate, key->rsa, RSA_NO_PADDING); + S2N_ERROR_IF(r != expected_size, S2N_ERR_SIZE_MISMATCH); + + s2n_constant_time_pkcs1_unpad_or_dont(out->data, intermediate, r, out->size); + + return 0; +} + +static int s2n_rsa_keys_match(const struct s2n_pkey *pub, const struct s2n_pkey *priv) +{ + uint8_t plain_inpad[36] = {1}, plain_outpad[36] = {0}, encpad[8192]; + struct s2n_blob plain_in = { 0 }, plain_out = { 0 }, enc = { 0 }; + + plain_in.data = plain_inpad; + plain_in.size = sizeof(plain_inpad); + + enc.data = encpad; + enc.size = s2n_rsa_encrypted_size(pub); + lte_check(enc.size, sizeof(encpad)); + GUARD(s2n_rsa_encrypt(pub, &plain_in, &enc)); + + plain_out.data = plain_outpad; + plain_out.size = sizeof(plain_outpad); + GUARD(s2n_rsa_decrypt(priv, &enc, &plain_out)); + + S2N_ERROR_IF(memcmp(plain_in.data, plain_out.data, plain_in.size), S2N_ERR_KEY_MISMATCH); + + return 0; +} + +static int s2n_rsa_key_free(struct s2n_pkey *pkey) +{ + struct s2n_rsa_key *rsa_key = &pkey->key.rsa_key; + if (rsa_key->rsa == NULL) { + return 0; + } + + RSA_free(rsa_key->rsa); + rsa_key->rsa = NULL; + + return 0; +} + +static int s2n_rsa_check_key_exists(const struct s2n_pkey *pkey) +{ + const struct s2n_rsa_key *rsa_key = &pkey->key.rsa_key; + notnull_check(rsa_key->rsa); + return 0; +} + +int s2n_evp_pkey_to_rsa_public_key(s2n_rsa_public_key *rsa_key, EVP_PKEY *evp_public_key) +{ + RSA *rsa = EVP_PKEY_get1_RSA(evp_public_key); + S2N_ERROR_IF(rsa == NULL, S2N_ERR_DECODE_CERTIFICATE); + + rsa_key->rsa = rsa; + return 0; +} + +int s2n_evp_pkey_to_rsa_private_key(s2n_rsa_private_key *rsa_key, EVP_PKEY *evp_private_key) +{ + RSA *rsa = EVP_PKEY_get1_RSA(evp_private_key); + S2N_ERROR_IF(rsa == NULL, S2N_ERR_DECODE_PRIVATE_KEY); + + rsa_key->rsa = rsa; + return 0; +} + +int s2n_rsa_pkey_init(struct s2n_pkey *pkey) +{ + pkey->size = &s2n_rsa_encrypted_size; + pkey->sign = &s2n_rsa_sign; + pkey->verify = &s2n_rsa_verify; + pkey->encrypt = &s2n_rsa_encrypt; + pkey->decrypt = &s2n_rsa_decrypt; + pkey->match = &s2n_rsa_keys_match; + pkey->free = &s2n_rsa_key_free; + pkey->check_key = &s2n_rsa_check_key_exists; + return 0; +} + diff --git a/contrib/restricted/aws/s2n/crypto/s2n_rsa.h b/contrib/restricted/aws/s2n/crypto/s2n_rsa.h index 3d153eaf3d..e6673fbe02 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_rsa.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_rsa.h @@ -1,40 +1,40 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <stdint.h> -#include <s2n.h> - -#include <openssl/rsa.h> - -#include "crypto/s2n_hash.h" - -#include "utils/s2n_blob.h" - -/* Forward declaration to avoid the circular dependency with s2n_pkey.h */ -struct s2n_pkey; - -struct s2n_rsa_key { - RSA *rsa; -}; - -typedef struct s2n_rsa_key s2n_rsa_public_key; -typedef struct s2n_rsa_key s2n_rsa_private_key; - -extern int s2n_rsa_pkey_init(struct s2n_pkey *pkey); - -extern int s2n_evp_pkey_to_rsa_public_key(s2n_rsa_public_key *rsa_key, EVP_PKEY *pkey); -extern int s2n_evp_pkey_to_rsa_private_key(s2n_rsa_private_key *rsa_key, EVP_PKEY *pkey); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <stdint.h> +#include <s2n.h> + +#include <openssl/rsa.h> + +#include "crypto/s2n_hash.h" + +#include "utils/s2n_blob.h" + +/* Forward declaration to avoid the circular dependency with s2n_pkey.h */ +struct s2n_pkey; + +struct s2n_rsa_key { + RSA *rsa; +}; + +typedef struct s2n_rsa_key s2n_rsa_public_key; +typedef struct s2n_rsa_key s2n_rsa_private_key; + +extern int s2n_rsa_pkey_init(struct s2n_pkey *pkey); + +extern int s2n_evp_pkey_to_rsa_public_key(s2n_rsa_public_key *rsa_key, EVP_PKEY *pkey); +extern int s2n_evp_pkey_to_rsa_private_key(s2n_rsa_private_key *rsa_key, EVP_PKEY *pkey); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_rsa_pss.c b/contrib/restricted/aws/s2n/crypto/s2n_rsa_pss.c index 1bb444b25c..7fd13ff2b6 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_rsa_pss.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_rsa_pss.c @@ -1,241 +1,241 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/evp.h> -#include <openssl/rsa.h> -#include <stdint.h> - -#include "error/s2n_errno.h" - -#include "stuffer/s2n_stuffer.h" - -#include "crypto/s2n_hash.h" -#include "crypto/s2n_openssl.h" -#include "crypto/s2n_rsa.h" -#include "crypto/s2n_rsa_pss.h" -#include "crypto/s2n_rsa_signing.h" -#include "crypto/s2n_pkey.h" - -#include "utils/s2n_blob.h" -#include "utils/s2n_random.h" -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" - -/* Checks whether PSS Certs is supported */ -int s2n_is_rsa_pss_certs_supported() -{ - return RSA_PSS_CERTS_SUPPORTED; -} - -#if RSA_PSS_CERTS_SUPPORTED - -static int s2n_rsa_pss_size(const struct s2n_pkey *key) -{ - notnull_check(key); - - /* For more info, see: https://www.openssl.org/docs/man1.1.0/man3/EVP_PKEY_size.html */ - return EVP_PKEY_size(key->pkey); -} - -static int s2n_rsa_is_private_key(RSA *rsa_key) -{ - const BIGNUM *d = NULL; - RSA_get0_key(rsa_key, NULL, NULL, &d); - - if (d != NULL) { - return 1; - } - return 0; -} - -int s2n_rsa_pss_key_sign(const struct s2n_pkey *priv, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature_out) -{ - notnull_check(priv); - sig_alg_check(sig_alg, S2N_SIGNATURE_RSA_PSS_PSS); - - /* Not Possible to Sign with Public Key */ - S2N_ERROR_IF(!s2n_rsa_is_private_key(priv->key.rsa_key.rsa), S2N_ERR_KEY_MISMATCH); - - return s2n_rsa_pss_sign(priv, digest, signature_out); -} - -int s2n_rsa_pss_key_verify(const struct s2n_pkey *pub, s2n_signature_algorithm sig_alg, - struct s2n_hash_state *digest, struct s2n_blob *signature_in) -{ - notnull_check(pub); - sig_alg_check(sig_alg, S2N_SIGNATURE_RSA_PSS_PSS); - - /* Using Private Key to Verify means the public/private keys were likely swapped, and likely indicates a bug. */ - S2N_ERROR_IF(s2n_rsa_is_private_key(pub->key.rsa_key.rsa), S2N_ERR_KEY_MISMATCH); - - return s2n_rsa_pss_verify(pub, digest, signature_in); -} - -static int s2n_rsa_pss_validate_sign_verify_match(const struct s2n_pkey *pub, const struct s2n_pkey *priv) -{ - /* Generate a random blob to sign and verify */ - s2n_stack_blob(random_data, RSA_PSS_SIGN_VERIFY_RANDOM_BLOB_SIZE, RSA_PSS_SIGN_VERIFY_RANDOM_BLOB_SIZE); - GUARD_AS_POSIX(s2n_get_private_random_data(&random_data)); - - /* Sign/Verify API's only accept Hashes, so hash our Random Data */ - DEFER_CLEANUP(struct s2n_hash_state sign_hash = {0}, s2n_hash_free); - DEFER_CLEANUP(struct s2n_hash_state verify_hash = {0}, s2n_hash_free); - GUARD(s2n_hash_new(&sign_hash)); - GUARD(s2n_hash_new(&verify_hash)); - GUARD(s2n_hash_init(&sign_hash, S2N_HASH_SHA256)); - GUARD(s2n_hash_init(&verify_hash, S2N_HASH_SHA256)); - GUARD(s2n_hash_update(&sign_hash, random_data.data, random_data.size)); - GUARD(s2n_hash_update(&verify_hash, random_data.data, random_data.size)); - - /* Sign and Verify the Hash of the Random Blob */ - s2n_stack_blob(signature_data, RSA_PSS_SIGN_VERIFY_SIGNATURE_SIZE, RSA_PSS_SIGN_VERIFY_SIGNATURE_SIZE); - GUARD(s2n_rsa_pss_key_sign(priv, S2N_SIGNATURE_RSA_PSS_PSS, &sign_hash, &signature_data)); - GUARD(s2n_rsa_pss_key_verify(pub, S2N_SIGNATURE_RSA_PSS_PSS, &verify_hash, &signature_data)); - - return 0; -} - -static int s2n_rsa_validate_params_equal(const RSA *pub, const RSA *priv) -{ - const BIGNUM *pub_val_e = NULL; - const BIGNUM *pub_val_n = NULL; - RSA_get0_key(pub, &pub_val_n, &pub_val_e, NULL); - - const BIGNUM *priv_val_e = NULL; - const BIGNUM *priv_val_n = NULL; - RSA_get0_key(priv, &priv_val_n, &priv_val_e, NULL); - - if (pub_val_e == NULL || priv_val_e == NULL) { - S2N_ERROR(S2N_ERR_KEY_CHECK); - } - - if (pub_val_n == NULL || priv_val_n == NULL) { - S2N_ERROR(S2N_ERR_KEY_CHECK); - } - - S2N_ERROR_IF(BN_cmp(pub_val_e, priv_val_e) != 0, S2N_ERR_KEY_MISMATCH); - S2N_ERROR_IF(BN_cmp(pub_val_n, priv_val_n) != 0, S2N_ERR_KEY_MISMATCH); - - return 0; -} - -static int s2n_rsa_validate_params_match(const struct s2n_pkey *pub, const struct s2n_pkey *priv) -{ - notnull_check(pub); - notnull_check(priv); - - /* OpenSSL Documentation Links: - * - https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_get0_RSA.html - * - https://www.openssl.org/docs/manmaster/man3/RSA_get0_key.html - */ - RSA *pub_rsa_key = pub->key.rsa_key.rsa; - RSA *priv_rsa_key = priv->key.rsa_key.rsa; - - notnull_check(pub_rsa_key); - notnull_check(priv_rsa_key); - - GUARD(s2n_rsa_validate_params_equal(pub_rsa_key, priv_rsa_key)); - - return 0; -} - - -static int s2n_rsa_pss_keys_match(const struct s2n_pkey *pub, const struct s2n_pkey *priv) -{ - notnull_check(pub); - notnull_check(pub->pkey); - notnull_check(priv); - notnull_check(priv->pkey); - - GUARD(s2n_rsa_validate_params_match(pub, priv)); - - /* Validate that verify(sign(message)) for a random message is verified correctly */ - GUARD(s2n_rsa_pss_validate_sign_verify_match(pub, priv)); - - return 0; -} - -static int s2n_rsa_pss_key_free(struct s2n_pkey *pkey) -{ - /* This object does not own the reference to the key -- - * s2n_pkey handles it. */ - - return 0; -} - -int s2n_evp_pkey_to_rsa_pss_public_key(struct s2n_rsa_key *rsa_key, EVP_PKEY *pkey) { - RSA *pub_rsa_key = EVP_PKEY_get0_RSA(pkey); - - S2N_ERROR_IF(s2n_rsa_is_private_key(pub_rsa_key), S2N_ERR_KEY_MISMATCH); - - rsa_key->rsa = pub_rsa_key; - return 0; -} - -int s2n_evp_pkey_to_rsa_pss_private_key(struct s2n_rsa_key *rsa_key, EVP_PKEY *pkey) -{ - RSA *priv_rsa_key = EVP_PKEY_get0_RSA(pkey); - notnull_check(priv_rsa_key); - - /* Documentation: https://www.openssl.org/docs/man1.1.1/man3/RSA_check_key.html */ - S2N_ERROR_IF(!s2n_rsa_is_private_key(priv_rsa_key), S2N_ERR_KEY_MISMATCH); - - /* Check that the mandatory properties of a RSA Private Key are valid. - * - Documentation: https://www.openssl.org/docs/man1.1.1/man3/RSA_check_key.html - */ - GUARD_OSSL(RSA_check_key(priv_rsa_key), S2N_ERR_KEY_CHECK); - - rsa_key->rsa = priv_rsa_key; - return 0; -} - -int s2n_rsa_pss_pkey_init(struct s2n_pkey *pkey) -{ - GUARD(s2n_rsa_pkey_init(pkey)); - - pkey->size = &s2n_rsa_pss_size; - pkey->sign = &s2n_rsa_pss_key_sign; - pkey->verify = &s2n_rsa_pss_key_verify; - - /* RSA PSS only supports Sign and Verify. - * RSA PSS should never be used for Key Exchange. ECDHE should be used instead since it provides Forward Secrecy. */ - pkey->encrypt = NULL; /* No function for encryption */ - pkey->decrypt = NULL; /* No function for decryption */ - - pkey->match = &s2n_rsa_pss_keys_match; - pkey->free = &s2n_rsa_pss_key_free; - - return 0; -} - -#else - -int s2n_evp_pkey_to_rsa_pss_public_key(struct s2n_rsa_key *rsa_pss_key, EVP_PKEY *pkey) -{ - S2N_ERROR(S2N_RSA_PSS_NOT_SUPPORTED); -} - -int s2n_evp_pkey_to_rsa_pss_private_key(struct s2n_rsa_key *rsa_pss_key, EVP_PKEY *pkey) -{ - S2N_ERROR(S2N_RSA_PSS_NOT_SUPPORTED); -} - -int s2n_rsa_pss_pkey_init(struct s2n_pkey *pkey) -{ - S2N_ERROR(S2N_RSA_PSS_NOT_SUPPORTED); -} - -#endif +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/evp.h> +#include <openssl/rsa.h> +#include <stdint.h> + +#include "error/s2n_errno.h" + +#include "stuffer/s2n_stuffer.h" + +#include "crypto/s2n_hash.h" +#include "crypto/s2n_openssl.h" +#include "crypto/s2n_rsa.h" +#include "crypto/s2n_rsa_pss.h" +#include "crypto/s2n_rsa_signing.h" +#include "crypto/s2n_pkey.h" + +#include "utils/s2n_blob.h" +#include "utils/s2n_random.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" + +/* Checks whether PSS Certs is supported */ +int s2n_is_rsa_pss_certs_supported() +{ + return RSA_PSS_CERTS_SUPPORTED; +} + +#if RSA_PSS_CERTS_SUPPORTED + +static int s2n_rsa_pss_size(const struct s2n_pkey *key) +{ + notnull_check(key); + + /* For more info, see: https://www.openssl.org/docs/man1.1.0/man3/EVP_PKEY_size.html */ + return EVP_PKEY_size(key->pkey); +} + +static int s2n_rsa_is_private_key(RSA *rsa_key) +{ + const BIGNUM *d = NULL; + RSA_get0_key(rsa_key, NULL, NULL, &d); + + if (d != NULL) { + return 1; + } + return 0; +} + +int s2n_rsa_pss_key_sign(const struct s2n_pkey *priv, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature_out) +{ + notnull_check(priv); + sig_alg_check(sig_alg, S2N_SIGNATURE_RSA_PSS_PSS); + + /* Not Possible to Sign with Public Key */ + S2N_ERROR_IF(!s2n_rsa_is_private_key(priv->key.rsa_key.rsa), S2N_ERR_KEY_MISMATCH); + + return s2n_rsa_pss_sign(priv, digest, signature_out); +} + +int s2n_rsa_pss_key_verify(const struct s2n_pkey *pub, s2n_signature_algorithm sig_alg, + struct s2n_hash_state *digest, struct s2n_blob *signature_in) +{ + notnull_check(pub); + sig_alg_check(sig_alg, S2N_SIGNATURE_RSA_PSS_PSS); + + /* Using Private Key to Verify means the public/private keys were likely swapped, and likely indicates a bug. */ + S2N_ERROR_IF(s2n_rsa_is_private_key(pub->key.rsa_key.rsa), S2N_ERR_KEY_MISMATCH); + + return s2n_rsa_pss_verify(pub, digest, signature_in); +} + +static int s2n_rsa_pss_validate_sign_verify_match(const struct s2n_pkey *pub, const struct s2n_pkey *priv) +{ + /* Generate a random blob to sign and verify */ + s2n_stack_blob(random_data, RSA_PSS_SIGN_VERIFY_RANDOM_BLOB_SIZE, RSA_PSS_SIGN_VERIFY_RANDOM_BLOB_SIZE); + GUARD_AS_POSIX(s2n_get_private_random_data(&random_data)); + + /* Sign/Verify API's only accept Hashes, so hash our Random Data */ + DEFER_CLEANUP(struct s2n_hash_state sign_hash = {0}, s2n_hash_free); + DEFER_CLEANUP(struct s2n_hash_state verify_hash = {0}, s2n_hash_free); + GUARD(s2n_hash_new(&sign_hash)); + GUARD(s2n_hash_new(&verify_hash)); + GUARD(s2n_hash_init(&sign_hash, S2N_HASH_SHA256)); + GUARD(s2n_hash_init(&verify_hash, S2N_HASH_SHA256)); + GUARD(s2n_hash_update(&sign_hash, random_data.data, random_data.size)); + GUARD(s2n_hash_update(&verify_hash, random_data.data, random_data.size)); + + /* Sign and Verify the Hash of the Random Blob */ + s2n_stack_blob(signature_data, RSA_PSS_SIGN_VERIFY_SIGNATURE_SIZE, RSA_PSS_SIGN_VERIFY_SIGNATURE_SIZE); + GUARD(s2n_rsa_pss_key_sign(priv, S2N_SIGNATURE_RSA_PSS_PSS, &sign_hash, &signature_data)); + GUARD(s2n_rsa_pss_key_verify(pub, S2N_SIGNATURE_RSA_PSS_PSS, &verify_hash, &signature_data)); + + return 0; +} + +static int s2n_rsa_validate_params_equal(const RSA *pub, const RSA *priv) +{ + const BIGNUM *pub_val_e = NULL; + const BIGNUM *pub_val_n = NULL; + RSA_get0_key(pub, &pub_val_n, &pub_val_e, NULL); + + const BIGNUM *priv_val_e = NULL; + const BIGNUM *priv_val_n = NULL; + RSA_get0_key(priv, &priv_val_n, &priv_val_e, NULL); + + if (pub_val_e == NULL || priv_val_e == NULL) { + S2N_ERROR(S2N_ERR_KEY_CHECK); + } + + if (pub_val_n == NULL || priv_val_n == NULL) { + S2N_ERROR(S2N_ERR_KEY_CHECK); + } + + S2N_ERROR_IF(BN_cmp(pub_val_e, priv_val_e) != 0, S2N_ERR_KEY_MISMATCH); + S2N_ERROR_IF(BN_cmp(pub_val_n, priv_val_n) != 0, S2N_ERR_KEY_MISMATCH); + + return 0; +} + +static int s2n_rsa_validate_params_match(const struct s2n_pkey *pub, const struct s2n_pkey *priv) +{ + notnull_check(pub); + notnull_check(priv); + + /* OpenSSL Documentation Links: + * - https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_get0_RSA.html + * - https://www.openssl.org/docs/manmaster/man3/RSA_get0_key.html + */ + RSA *pub_rsa_key = pub->key.rsa_key.rsa; + RSA *priv_rsa_key = priv->key.rsa_key.rsa; + + notnull_check(pub_rsa_key); + notnull_check(priv_rsa_key); + + GUARD(s2n_rsa_validate_params_equal(pub_rsa_key, priv_rsa_key)); + + return 0; +} + + +static int s2n_rsa_pss_keys_match(const struct s2n_pkey *pub, const struct s2n_pkey *priv) +{ + notnull_check(pub); + notnull_check(pub->pkey); + notnull_check(priv); + notnull_check(priv->pkey); + + GUARD(s2n_rsa_validate_params_match(pub, priv)); + + /* Validate that verify(sign(message)) for a random message is verified correctly */ + GUARD(s2n_rsa_pss_validate_sign_verify_match(pub, priv)); + + return 0; +} + +static int s2n_rsa_pss_key_free(struct s2n_pkey *pkey) +{ + /* This object does not own the reference to the key -- + * s2n_pkey handles it. */ + + return 0; +} + +int s2n_evp_pkey_to_rsa_pss_public_key(struct s2n_rsa_key *rsa_key, EVP_PKEY *pkey) { + RSA *pub_rsa_key = EVP_PKEY_get0_RSA(pkey); + + S2N_ERROR_IF(s2n_rsa_is_private_key(pub_rsa_key), S2N_ERR_KEY_MISMATCH); + + rsa_key->rsa = pub_rsa_key; + return 0; +} + +int s2n_evp_pkey_to_rsa_pss_private_key(struct s2n_rsa_key *rsa_key, EVP_PKEY *pkey) +{ + RSA *priv_rsa_key = EVP_PKEY_get0_RSA(pkey); + notnull_check(priv_rsa_key); + + /* Documentation: https://www.openssl.org/docs/man1.1.1/man3/RSA_check_key.html */ + S2N_ERROR_IF(!s2n_rsa_is_private_key(priv_rsa_key), S2N_ERR_KEY_MISMATCH); + + /* Check that the mandatory properties of a RSA Private Key are valid. + * - Documentation: https://www.openssl.org/docs/man1.1.1/man3/RSA_check_key.html + */ + GUARD_OSSL(RSA_check_key(priv_rsa_key), S2N_ERR_KEY_CHECK); + + rsa_key->rsa = priv_rsa_key; + return 0; +} + +int s2n_rsa_pss_pkey_init(struct s2n_pkey *pkey) +{ + GUARD(s2n_rsa_pkey_init(pkey)); + + pkey->size = &s2n_rsa_pss_size; + pkey->sign = &s2n_rsa_pss_key_sign; + pkey->verify = &s2n_rsa_pss_key_verify; + + /* RSA PSS only supports Sign and Verify. + * RSA PSS should never be used for Key Exchange. ECDHE should be used instead since it provides Forward Secrecy. */ + pkey->encrypt = NULL; /* No function for encryption */ + pkey->decrypt = NULL; /* No function for decryption */ + + pkey->match = &s2n_rsa_pss_keys_match; + pkey->free = &s2n_rsa_pss_key_free; + + return 0; +} + +#else + +int s2n_evp_pkey_to_rsa_pss_public_key(struct s2n_rsa_key *rsa_pss_key, EVP_PKEY *pkey) +{ + S2N_ERROR(S2N_RSA_PSS_NOT_SUPPORTED); +} + +int s2n_evp_pkey_to_rsa_pss_private_key(struct s2n_rsa_key *rsa_pss_key, EVP_PKEY *pkey) +{ + S2N_ERROR(S2N_RSA_PSS_NOT_SUPPORTED); +} + +int s2n_rsa_pss_pkey_init(struct s2n_pkey *pkey) +{ + S2N_ERROR(S2N_RSA_PSS_NOT_SUPPORTED); +} + +#endif diff --git a/contrib/restricted/aws/s2n/crypto/s2n_rsa_pss.h b/contrib/restricted/aws/s2n/crypto/s2n_rsa_pss.h index 70516551fb..6d69e9431d 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_rsa_pss.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_rsa_pss.h @@ -1,45 +1,45 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <stdint.h> -#include <s2n.h> - -#include "crypto/s2n_openssl.h" -#include "crypto/s2n_rsa.h" -#include "crypto/s2n_rsa_signing.h" - -#define RSA_PSS_SIGN_VERIFY_RANDOM_BLOB_SIZE 32 -#define RSA_PSS_SIGN_VERIFY_SIGNATURE_SIZE 256 - -#ifndef EVP_PKEY_RSA_PSS -#define EVP_PKEY_RSA_PSS EVP_PKEY_NONE -#endif - -/* OpenSSL 1.1.1d 10 Sep 2019 is broken, so disable on that version. For further info see: crypto/evp/p_lib.c:469 - * - * This feature requires this Openssl commit for Openssl 1.1.x versions: openssl/openssl@4088b92 - */ -#if RSA_PSS_SIGNING_SUPPORTED && OPENSSL_VERSION_NUMBER > 0x1010104fL -#define RSA_PSS_CERTS_SUPPORTED 1 -#else -#define RSA_PSS_CERTS_SUPPORTED 0 -#endif - -int s2n_is_rsa_pss_certs_supported(); -int s2n_rsa_pss_pkey_init(struct s2n_pkey *pkey); -int s2n_evp_pkey_to_rsa_pss_public_key(struct s2n_rsa_key *rsa_key, EVP_PKEY *pkey); -int s2n_evp_pkey_to_rsa_pss_private_key(struct s2n_rsa_key *rsa_key, EVP_PKEY *pkey); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <stdint.h> +#include <s2n.h> + +#include "crypto/s2n_openssl.h" +#include "crypto/s2n_rsa.h" +#include "crypto/s2n_rsa_signing.h" + +#define RSA_PSS_SIGN_VERIFY_RANDOM_BLOB_SIZE 32 +#define RSA_PSS_SIGN_VERIFY_SIGNATURE_SIZE 256 + +#ifndef EVP_PKEY_RSA_PSS +#define EVP_PKEY_RSA_PSS EVP_PKEY_NONE +#endif + +/* OpenSSL 1.1.1d 10 Sep 2019 is broken, so disable on that version. For further info see: crypto/evp/p_lib.c:469 + * + * This feature requires this Openssl commit for Openssl 1.1.x versions: openssl/openssl@4088b92 + */ +#if RSA_PSS_SIGNING_SUPPORTED && OPENSSL_VERSION_NUMBER > 0x1010104fL +#define RSA_PSS_CERTS_SUPPORTED 1 +#else +#define RSA_PSS_CERTS_SUPPORTED 0 +#endif + +int s2n_is_rsa_pss_certs_supported(); +int s2n_rsa_pss_pkey_init(struct s2n_pkey *pkey); +int s2n_evp_pkey_to_rsa_pss_public_key(struct s2n_rsa_key *rsa_key, EVP_PKEY *pkey); +int s2n_evp_pkey_to_rsa_pss_private_key(struct s2n_rsa_key *rsa_key, EVP_PKEY *pkey); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_rsa_signing.c b/contrib/restricted/aws/s2n/crypto/s2n_rsa_signing.c index 313565380f..3ac4fbf4d0 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_rsa_signing.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_rsa_signing.c @@ -1,206 +1,206 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/evp.h> -#include <openssl/rsa.h> - -#include "error/s2n_errno.h" - -#include "stuffer/s2n_stuffer.h" - -#include "crypto/s2n_hash.h" -#include "crypto/s2n_rsa_pss.h" -#include "crypto/s2n_rsa_signing.h" -#include "crypto/s2n_pkey.h" - -#include "utils/s2n_blob.h" -#include "utils/s2n_safety.h" - -static int s2n_hash_alg_to_NID[] = { - [S2N_HASH_MD5_SHA1] = NID_md5_sha1, - [S2N_HASH_SHA1] = NID_sha1, - [S2N_HASH_SHA224] = NID_sha224, - [S2N_HASH_SHA256] = NID_sha256, - [S2N_HASH_SHA384] = NID_sha384, - [S2N_HASH_SHA512] = NID_sha512 }; - -int s2n_hash_NID_type(s2n_hash_algorithm alg, int *out) -{ - switch(alg) { - case S2N_HASH_MD5_SHA1: - case S2N_HASH_SHA1: - case S2N_HASH_SHA224: - case S2N_HASH_SHA256: - case S2N_HASH_SHA384: - case S2N_HASH_SHA512: - *out = s2n_hash_alg_to_NID[alg]; - break; - default: - S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); - } - return 0; -} - -int s2n_rsa_pkcs1v15_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature) -{ - uint8_t digest_length; - int NID_type; - GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); - GUARD(s2n_hash_NID_type(digest->alg, &NID_type)); - lte_check(digest_length, S2N_MAX_DIGEST_LEN); - - const s2n_rsa_private_key *key = &priv->key.rsa_key; - - uint8_t digest_out[S2N_MAX_DIGEST_LEN]; - GUARD(s2n_hash_digest(digest, digest_out, digest_length)); - - unsigned int signature_size = signature->size; - GUARD_OSSL(RSA_sign(NID_type, digest_out, digest_length, signature->data, &signature_size, key->rsa), S2N_ERR_SIGN); - S2N_ERROR_IF(signature_size > signature->size, S2N_ERR_SIZE_MISMATCH); - signature->size = signature_size; - - return 0; -} - -int s2n_rsa_pkcs1v15_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature) -{ - uint8_t digest_length; - int digest_NID_type; - GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); - GUARD(s2n_hash_NID_type(digest->alg, &digest_NID_type)); - lte_check(digest_length, S2N_MAX_DIGEST_LEN); - - const s2n_rsa_public_key *key = &pub->key.rsa_key; - - uint8_t digest_out[S2N_MAX_DIGEST_LEN]; - GUARD(s2n_hash_digest(digest, digest_out, digest_length)); - - GUARD_OSSL(RSA_verify(digest_NID_type, digest_out, digest_length, signature->data, signature->size, key->rsa), S2N_ERR_VERIFY_SIGNATURE); - - return 0; -} - -/* this function returns whether RSA PSS signing is supported */ -int s2n_is_rsa_pss_signing_supported() -{ - return RSA_PSS_SIGNING_SUPPORTED; -} - -#if RSA_PSS_SIGNING_SUPPORTED - -const EVP_MD* s2n_hash_alg_to_evp_alg(s2n_hash_algorithm alg) -{ - switch (alg) { - case S2N_HASH_MD5_SHA1: - return EVP_md5_sha1(); - case S2N_HASH_SHA1: - return EVP_sha1(); - case S2N_HASH_SHA224: - return EVP_sha224(); - case S2N_HASH_SHA256: - return EVP_sha256(); - case S2N_HASH_SHA384: - return EVP_sha384(); - case S2N_HASH_SHA512: - return EVP_sha512(); - default: - return NULL; - } -} - -/* On some versions of OpenSSL, "EVP_PKEY_CTX_set_signature_md()" is just a macro that casts digest_alg to "void*", - * which fails to compile when the "-Werror=cast-qual" compiler flag is enabled. So we work around this OpenSSL - * issue by turning off this compiler check for this one function with a cast through. */ -static int s2n_evp_pkey_ctx_set_rsa_signature_digest(EVP_PKEY_CTX *ctx, const EVP_MD* digest_alg) -{ - GUARD_OSSL(EVP_PKEY_CTX_set_signature_md(ctx,(EVP_MD*) (uintptr_t) digest_alg), S2N_ERR_INVALID_SIGNATURE_ALGORITHM); - GUARD_OSSL(EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, (EVP_MD*) (uintptr_t) digest_alg), S2N_ERR_INVALID_SIGNATURE_ALGORITHM); - return 0; -} - -static void s2n_evp_pkey_ctx_free(EVP_PKEY_CTX **ctx) -{ - EVP_PKEY_CTX_free(*ctx); -} - -int s2n_rsa_pss_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature_out) -{ - notnull_check(priv); - - uint8_t digest_length; - uint8_t digest_data[S2N_MAX_DIGEST_LEN]; - GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); - GUARD(s2n_hash_digest(digest, digest_data, digest_length)); - - const EVP_MD* digest_alg = s2n_hash_alg_to_evp_alg(digest->alg); - notnull_check(digest_alg); - - /* For more info see: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_sign.html */ - DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(priv->pkey, NULL), s2n_evp_pkey_ctx_free); - notnull_check(ctx); - - size_t signature_len = signature_out->size; - GUARD_OSSL(EVP_PKEY_sign_init(ctx), S2N_ERR_SIGN); - GUARD_OSSL(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING), S2N_ERR_SIGN); - GUARD(s2n_evp_pkey_ctx_set_rsa_signature_digest(ctx, digest_alg)); - GUARD_OSSL(EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST), S2N_ERR_SIGN); - - /* Calling EVP_PKEY_sign() with NULL will only update the signature_len parameter so users can validate sizes. */ - GUARD_OSSL(EVP_PKEY_sign(ctx, NULL, &signature_len, digest_data, digest_length), S2N_ERR_SIGN); - S2N_ERROR_IF(signature_len > signature_out->size, S2N_ERR_SIZE_MISMATCH); - - /* Actually sign the the digest */ - GUARD_OSSL(EVP_PKEY_sign(ctx, signature_out->data, &signature_len, digest_data, digest_length), S2N_ERR_SIGN); - signature_out->size = signature_len; - - return 0; -} - -int s2n_rsa_pss_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature_in) -{ - notnull_check(pub); - - uint8_t digest_length; - uint8_t digest_data[S2N_MAX_DIGEST_LEN]; - GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); - GUARD(s2n_hash_digest(digest, digest_data, digest_length)); - const EVP_MD* digest_alg = s2n_hash_alg_to_evp_alg(digest->alg); - notnull_check(digest_alg); - - /* For more info see: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_verify.html */ - DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pub->pkey, NULL), s2n_evp_pkey_ctx_free); - notnull_check(ctx); - - GUARD_OSSL(EVP_PKEY_verify_init(ctx), S2N_ERR_VERIFY_SIGNATURE); - GUARD_OSSL(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING), S2N_ERR_SIGN); - GUARD(s2n_evp_pkey_ctx_set_rsa_signature_digest(ctx, digest_alg)); - GUARD_OSSL(EVP_PKEY_verify(ctx, signature_in->data, signature_in->size, digest_data, digest_length), S2N_ERR_VERIFY_SIGNATURE); - - return 0; -} - -#else - -int s2n_rsa_pss_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature_out) -{ - S2N_ERROR(S2N_RSA_PSS_NOT_SUPPORTED); -} - -int s2n_rsa_pss_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature_in) -{ - S2N_ERROR(S2N_RSA_PSS_NOT_SUPPORTED); -} - -#endif +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/evp.h> +#include <openssl/rsa.h> + +#include "error/s2n_errno.h" + +#include "stuffer/s2n_stuffer.h" + +#include "crypto/s2n_hash.h" +#include "crypto/s2n_rsa_pss.h" +#include "crypto/s2n_rsa_signing.h" +#include "crypto/s2n_pkey.h" + +#include "utils/s2n_blob.h" +#include "utils/s2n_safety.h" + +static int s2n_hash_alg_to_NID[] = { + [S2N_HASH_MD5_SHA1] = NID_md5_sha1, + [S2N_HASH_SHA1] = NID_sha1, + [S2N_HASH_SHA224] = NID_sha224, + [S2N_HASH_SHA256] = NID_sha256, + [S2N_HASH_SHA384] = NID_sha384, + [S2N_HASH_SHA512] = NID_sha512 }; + +int s2n_hash_NID_type(s2n_hash_algorithm alg, int *out) +{ + switch(alg) { + case S2N_HASH_MD5_SHA1: + case S2N_HASH_SHA1: + case S2N_HASH_SHA224: + case S2N_HASH_SHA256: + case S2N_HASH_SHA384: + case S2N_HASH_SHA512: + *out = s2n_hash_alg_to_NID[alg]; + break; + default: + S2N_ERROR(S2N_ERR_HASH_INVALID_ALGORITHM); + } + return 0; +} + +int s2n_rsa_pkcs1v15_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature) +{ + uint8_t digest_length; + int NID_type; + GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); + GUARD(s2n_hash_NID_type(digest->alg, &NID_type)); + lte_check(digest_length, S2N_MAX_DIGEST_LEN); + + const s2n_rsa_private_key *key = &priv->key.rsa_key; + + uint8_t digest_out[S2N_MAX_DIGEST_LEN]; + GUARD(s2n_hash_digest(digest, digest_out, digest_length)); + + unsigned int signature_size = signature->size; + GUARD_OSSL(RSA_sign(NID_type, digest_out, digest_length, signature->data, &signature_size, key->rsa), S2N_ERR_SIGN); + S2N_ERROR_IF(signature_size > signature->size, S2N_ERR_SIZE_MISMATCH); + signature->size = signature_size; + + return 0; +} + +int s2n_rsa_pkcs1v15_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature) +{ + uint8_t digest_length; + int digest_NID_type; + GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); + GUARD(s2n_hash_NID_type(digest->alg, &digest_NID_type)); + lte_check(digest_length, S2N_MAX_DIGEST_LEN); + + const s2n_rsa_public_key *key = &pub->key.rsa_key; + + uint8_t digest_out[S2N_MAX_DIGEST_LEN]; + GUARD(s2n_hash_digest(digest, digest_out, digest_length)); + + GUARD_OSSL(RSA_verify(digest_NID_type, digest_out, digest_length, signature->data, signature->size, key->rsa), S2N_ERR_VERIFY_SIGNATURE); + + return 0; +} + +/* this function returns whether RSA PSS signing is supported */ +int s2n_is_rsa_pss_signing_supported() +{ + return RSA_PSS_SIGNING_SUPPORTED; +} + +#if RSA_PSS_SIGNING_SUPPORTED + +const EVP_MD* s2n_hash_alg_to_evp_alg(s2n_hash_algorithm alg) +{ + switch (alg) { + case S2N_HASH_MD5_SHA1: + return EVP_md5_sha1(); + case S2N_HASH_SHA1: + return EVP_sha1(); + case S2N_HASH_SHA224: + return EVP_sha224(); + case S2N_HASH_SHA256: + return EVP_sha256(); + case S2N_HASH_SHA384: + return EVP_sha384(); + case S2N_HASH_SHA512: + return EVP_sha512(); + default: + return NULL; + } +} + +/* On some versions of OpenSSL, "EVP_PKEY_CTX_set_signature_md()" is just a macro that casts digest_alg to "void*", + * which fails to compile when the "-Werror=cast-qual" compiler flag is enabled. So we work around this OpenSSL + * issue by turning off this compiler check for this one function with a cast through. */ +static int s2n_evp_pkey_ctx_set_rsa_signature_digest(EVP_PKEY_CTX *ctx, const EVP_MD* digest_alg) +{ + GUARD_OSSL(EVP_PKEY_CTX_set_signature_md(ctx,(EVP_MD*) (uintptr_t) digest_alg), S2N_ERR_INVALID_SIGNATURE_ALGORITHM); + GUARD_OSSL(EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, (EVP_MD*) (uintptr_t) digest_alg), S2N_ERR_INVALID_SIGNATURE_ALGORITHM); + return 0; +} + +static void s2n_evp_pkey_ctx_free(EVP_PKEY_CTX **ctx) +{ + EVP_PKEY_CTX_free(*ctx); +} + +int s2n_rsa_pss_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature_out) +{ + notnull_check(priv); + + uint8_t digest_length; + uint8_t digest_data[S2N_MAX_DIGEST_LEN]; + GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); + GUARD(s2n_hash_digest(digest, digest_data, digest_length)); + + const EVP_MD* digest_alg = s2n_hash_alg_to_evp_alg(digest->alg); + notnull_check(digest_alg); + + /* For more info see: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_sign.html */ + DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(priv->pkey, NULL), s2n_evp_pkey_ctx_free); + notnull_check(ctx); + + size_t signature_len = signature_out->size; + GUARD_OSSL(EVP_PKEY_sign_init(ctx), S2N_ERR_SIGN); + GUARD_OSSL(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING), S2N_ERR_SIGN); + GUARD(s2n_evp_pkey_ctx_set_rsa_signature_digest(ctx, digest_alg)); + GUARD_OSSL(EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST), S2N_ERR_SIGN); + + /* Calling EVP_PKEY_sign() with NULL will only update the signature_len parameter so users can validate sizes. */ + GUARD_OSSL(EVP_PKEY_sign(ctx, NULL, &signature_len, digest_data, digest_length), S2N_ERR_SIGN); + S2N_ERROR_IF(signature_len > signature_out->size, S2N_ERR_SIZE_MISMATCH); + + /* Actually sign the the digest */ + GUARD_OSSL(EVP_PKEY_sign(ctx, signature_out->data, &signature_len, digest_data, digest_length), S2N_ERR_SIGN); + signature_out->size = signature_len; + + return 0; +} + +int s2n_rsa_pss_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature_in) +{ + notnull_check(pub); + + uint8_t digest_length; + uint8_t digest_data[S2N_MAX_DIGEST_LEN]; + GUARD(s2n_hash_digest_size(digest->alg, &digest_length)); + GUARD(s2n_hash_digest(digest, digest_data, digest_length)); + const EVP_MD* digest_alg = s2n_hash_alg_to_evp_alg(digest->alg); + notnull_check(digest_alg); + + /* For more info see: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_verify.html */ + DEFER_CLEANUP(EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pub->pkey, NULL), s2n_evp_pkey_ctx_free); + notnull_check(ctx); + + GUARD_OSSL(EVP_PKEY_verify_init(ctx), S2N_ERR_VERIFY_SIGNATURE); + GUARD_OSSL(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING), S2N_ERR_SIGN); + GUARD(s2n_evp_pkey_ctx_set_rsa_signature_digest(ctx, digest_alg)); + GUARD_OSSL(EVP_PKEY_verify(ctx, signature_in->data, signature_in->size, digest_data, digest_length), S2N_ERR_VERIFY_SIGNATURE); + + return 0; +} + +#else + +int s2n_rsa_pss_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature_out) +{ + S2N_ERROR(S2N_RSA_PSS_NOT_SUPPORTED); +} + +int s2n_rsa_pss_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature_in) +{ + S2N_ERROR(S2N_RSA_PSS_NOT_SUPPORTED); +} + +#endif diff --git a/contrib/restricted/aws/s2n/crypto/s2n_rsa_signing.h b/contrib/restricted/aws/s2n/crypto/s2n_rsa_signing.h index 6013768a96..94c33dfa24 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_rsa_signing.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_rsa_signing.h @@ -1,37 +1,37 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <s2n.h> - -#include "utils/s2n_blob.h" -#include "crypto/s2n_openssl.h" -#include "crypto/s2n_rsa.h" - -/* Check for libcrypto 1.1 for RSA PSS Signing and EV_Key usage */ -#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 1) && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) -#define RSA_PSS_SIGNING_SUPPORTED 1 -#else -#define RSA_PSS_SIGNING_SUPPORTED 0 -#endif - -int s2n_rsa_pkcs1v15_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature); -int s2n_rsa_pkcs1v15_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature); - -int s2n_rsa_pss_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature_out); -int s2n_rsa_pss_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature_in); - -int s2n_is_rsa_pss_signing_supported(); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <s2n.h> + +#include "utils/s2n_blob.h" +#include "crypto/s2n_openssl.h" +#include "crypto/s2n_rsa.h" + +/* Check for libcrypto 1.1 for RSA PSS Signing and EV_Key usage */ +#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 1) && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) +#define RSA_PSS_SIGNING_SUPPORTED 1 +#else +#define RSA_PSS_SIGNING_SUPPORTED 0 +#endif + +int s2n_rsa_pkcs1v15_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature); +int s2n_rsa_pkcs1v15_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature); + +int s2n_rsa_pss_sign(const struct s2n_pkey *priv, struct s2n_hash_state *digest, struct s2n_blob *signature_out); +int s2n_rsa_pss_verify(const struct s2n_pkey *pub, struct s2n_hash_state *digest, struct s2n_blob *signature_in); + +int s2n_is_rsa_pss_signing_supported(); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_sequence.c b/contrib/restricted/aws/s2n/crypto/s2n_sequence.c index 2211653817..1deac1b522 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_sequence.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_sequence.c @@ -1,58 +1,58 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include "crypto/s2n_sequence.h" - -#include "tls/s2n_crypto.h" - -#include "error/s2n_errno.h" - -#include "utils/s2n_blob.h" - -#define SEQUENCE_NUMBER_POWER 8 - -int s2n_increment_sequence_number(struct s2n_blob *sequence_number) -{ - for (int i = sequence_number->size - 1; i >= 0; i--) { - sequence_number->data[i] += 1; - if (sequence_number->data[i]) { - break; - } - - /* RFC 5246 6.1: If a TLS implementation would need to wrap a sequence number, it must - * renegotiate instead. We don't support renegotiation. Caller needs to create a new session. - * This condition is very unlikely. It requires 2^64 - 1 records to be sent. - */ - S2N_ERROR_IF(i == 0, S2N_ERR_RECORD_LIMIT); - - /* seq[i] wrapped, so let it carry */ - } - - return 0; -} - -int s2n_sequence_number_to_uint64(struct s2n_blob *sequence_number, uint64_t *output) -{ - notnull_check(sequence_number); - - uint8_t shift = 0; - *output = 0; - - for (int i = sequence_number->size - 1; i >= 0; i--) { - *output += ((uint64_t) sequence_number->data[i]) << shift; - shift += SEQUENCE_NUMBER_POWER; - } - return S2N_SUCCESS; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include "crypto/s2n_sequence.h" + +#include "tls/s2n_crypto.h" + +#include "error/s2n_errno.h" + +#include "utils/s2n_blob.h" + +#define SEQUENCE_NUMBER_POWER 8 + +int s2n_increment_sequence_number(struct s2n_blob *sequence_number) +{ + for (int i = sequence_number->size - 1; i >= 0; i--) { + sequence_number->data[i] += 1; + if (sequence_number->data[i]) { + break; + } + + /* RFC 5246 6.1: If a TLS implementation would need to wrap a sequence number, it must + * renegotiate instead. We don't support renegotiation. Caller needs to create a new session. + * This condition is very unlikely. It requires 2^64 - 1 records to be sent. + */ + S2N_ERROR_IF(i == 0, S2N_ERR_RECORD_LIMIT); + + /* seq[i] wrapped, so let it carry */ + } + + return 0; +} + +int s2n_sequence_number_to_uint64(struct s2n_blob *sequence_number, uint64_t *output) +{ + notnull_check(sequence_number); + + uint8_t shift = 0; + *output = 0; + + for (int i = sequence_number->size - 1; i >= 0; i--) { + *output += ((uint64_t) sequence_number->data[i]) << shift; + shift += SEQUENCE_NUMBER_POWER; + } + return S2N_SUCCESS; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_sequence.h b/contrib/restricted/aws/s2n/crypto/s2n_sequence.h index 6fd824458a..c91e4d8783 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_sequence.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_sequence.h @@ -1,23 +1,23 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include "crypto/s2n_sequence.h" - -#include "utils/s2n_blob.h" - -extern int s2n_increment_sequence_number(struct s2n_blob *sequence_number); -int s2n_sequence_number_to_uint64(struct s2n_blob *sequence_number, uint64_t *output); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include "crypto/s2n_sequence.h" + +#include "utils/s2n_blob.h" + +extern int s2n_increment_sequence_number(struct s2n_blob *sequence_number); +int s2n_sequence_number_to_uint64(struct s2n_blob *sequence_number, uint64_t *output); diff --git a/contrib/restricted/aws/s2n/crypto/s2n_signature.h b/contrib/restricted/aws/s2n/crypto/s2n_signature.h index 0206578a5a..0a5d2c5d37 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_signature.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_signature.h @@ -1,29 +1,29 @@ -/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include "tls/s2n_tls_parameters.h" - -#define sig_alg_check(a, b) do { if ( (a) != (b) ) { S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); } } while(0) - -typedef enum { - S2N_SIGNATURE_ANONYMOUS = TLS_SIGNATURE_ALGORITHM_ANONYMOUS, - S2N_SIGNATURE_RSA = TLS_SIGNATURE_ALGORITHM_RSA, - S2N_SIGNATURE_ECDSA = TLS_SIGNATURE_ALGORITHM_ECDSA, - - /* Use Private Range for RSA PSS */ - S2N_SIGNATURE_RSA_PSS_RSAE = TLS_SIGNATURE_ALGORITHM_PRIVATE, - S2N_SIGNATURE_RSA_PSS_PSS -} s2n_signature_algorithm; +/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include "tls/s2n_tls_parameters.h" + +#define sig_alg_check(a, b) do { if ( (a) != (b) ) { S2N_ERROR(S2N_ERR_INVALID_SIGNATURE_ALGORITHM); } } while(0) + +typedef enum { + S2N_SIGNATURE_ANONYMOUS = TLS_SIGNATURE_ALGORITHM_ANONYMOUS, + S2N_SIGNATURE_RSA = TLS_SIGNATURE_ALGORITHM_RSA, + S2N_SIGNATURE_ECDSA = TLS_SIGNATURE_ALGORITHM_ECDSA, + + /* Use Private Range for RSA PSS */ + S2N_SIGNATURE_RSA_PSS_RSAE = TLS_SIGNATURE_ALGORITHM_PRIVATE, + S2N_SIGNATURE_RSA_PSS_PSS +} s2n_signature_algorithm; diff --git a/contrib/restricted/aws/s2n/crypto/s2n_stream_cipher_null.c b/contrib/restricted/aws/s2n/crypto/s2n_stream_cipher_null.c index ef09ea0a0f..8922a1c9e0 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_stream_cipher_null.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_stream_cipher_null.c @@ -1,64 +1,64 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include "error/s2n_errno.h" - -#include "crypto/s2n_cipher.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" - -static uint8_t s2n_stream_cipher_null_available() -{ - return 1; -} - -static int s2n_stream_cipher_null_endecrypt(struct s2n_session_key *key, struct s2n_blob *in, struct s2n_blob *out) -{ - S2N_ERROR_IF(out->size < in->size, S2N_ERR_SIZE_MISMATCH); - - if (in->data != out->data) { - memcpy_check(out->data, in->data, out->size); - } - return 0; -} - -static int s2n_stream_cipher_null_get_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - return 0; -} - -static int s2n_stream_cipher_null_destroy_key(struct s2n_session_key *key) -{ - return 0; -} - -static int s2n_stream_cipher_null_init(struct s2n_session_key *key) -{ - return 0; -} - -struct s2n_cipher s2n_null_cipher = { - .type = S2N_STREAM, - .key_material_size = 0, - .io.stream = { - .decrypt = s2n_stream_cipher_null_endecrypt, - .encrypt = s2n_stream_cipher_null_endecrypt}, - .is_available = s2n_stream_cipher_null_available, - .init = s2n_stream_cipher_null_init, - .set_encryption_key = s2n_stream_cipher_null_get_key, - .set_decryption_key = s2n_stream_cipher_null_get_key, - .destroy_key = s2n_stream_cipher_null_destroy_key, -}; +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include "error/s2n_errno.h" + +#include "crypto/s2n_cipher.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" + +static uint8_t s2n_stream_cipher_null_available() +{ + return 1; +} + +static int s2n_stream_cipher_null_endecrypt(struct s2n_session_key *key, struct s2n_blob *in, struct s2n_blob *out) +{ + S2N_ERROR_IF(out->size < in->size, S2N_ERR_SIZE_MISMATCH); + + if (in->data != out->data) { + memcpy_check(out->data, in->data, out->size); + } + return 0; +} + +static int s2n_stream_cipher_null_get_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + return 0; +} + +static int s2n_stream_cipher_null_destroy_key(struct s2n_session_key *key) +{ + return 0; +} + +static int s2n_stream_cipher_null_init(struct s2n_session_key *key) +{ + return 0; +} + +struct s2n_cipher s2n_null_cipher = { + .type = S2N_STREAM, + .key_material_size = 0, + .io.stream = { + .decrypt = s2n_stream_cipher_null_endecrypt, + .encrypt = s2n_stream_cipher_null_endecrypt}, + .is_available = s2n_stream_cipher_null_available, + .init = s2n_stream_cipher_null_init, + .set_encryption_key = s2n_stream_cipher_null_get_key, + .set_decryption_key = s2n_stream_cipher_null_get_key, + .destroy_key = s2n_stream_cipher_null_destroy_key, +}; diff --git a/contrib/restricted/aws/s2n/crypto/s2n_stream_cipher_rc4.c b/contrib/restricted/aws/s2n/crypto/s2n_stream_cipher_rc4.c index 78c5ea3d8b..8177af6d75 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_stream_cipher_rc4.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_stream_cipher_rc4.c @@ -1,94 +1,94 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <openssl/rc4.h> - -#include "crypto/s2n_cipher.h" -#include "crypto/s2n_openssl.h" - -#include "utils/s2n_safety.h" -#include "utils/s2n_blob.h" - -static uint8_t s2n_stream_cipher_rc4_available() -{ - return (EVP_rc4() ? 1 : 0); -} - -static int s2n_stream_cipher_rc4_encrypt(struct s2n_session_key *key, struct s2n_blob *in, struct s2n_blob *out) -{ - gte_check(out->size, in->size); - - int len = out->size; - GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_ENCRYPT); - - S2N_ERROR_IF(len != in->size, S2N_ERR_ENCRYPT); - - return 0; -} - -static int s2n_stream_cipher_rc4_decrypt(struct s2n_session_key *key, struct s2n_blob *in, struct s2n_blob *out) -{ - gte_check(out->size, in->size); - - int len = out->size; - GUARD_OSSL(EVP_DecryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_ENCRYPT); - - S2N_ERROR_IF(len != in->size, S2N_ERR_ENCRYPT); - - return 0; -} - -static int s2n_stream_cipher_rc4_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 16); - GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_rc4(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -static int s2n_stream_cipher_rc4_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) -{ - eq_check(in->size, 16); - GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_rc4(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); - - return 0; -} - -static int s2n_stream_cipher_rc4_init(struct s2n_session_key *key) -{ - s2n_evp_ctx_init(key->evp_cipher_ctx); - - return 0; -} - -static int s2n_stream_cipher_rc4_destroy_key(struct s2n_session_key *key) -{ - EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); - - return 0; -} - -struct s2n_cipher s2n_rc4 = { - .type = S2N_STREAM, - .key_material_size = 16, - .io.stream = { - .decrypt = s2n_stream_cipher_rc4_decrypt, - .encrypt = s2n_stream_cipher_rc4_encrypt}, - .is_available = s2n_stream_cipher_rc4_available, - .init = s2n_stream_cipher_rc4_init, - .set_decryption_key = s2n_stream_cipher_rc4_set_decryption_key, - .set_encryption_key = s2n_stream_cipher_rc4_set_encryption_key, - .destroy_key = s2n_stream_cipher_rc4_destroy_key, -}; +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <openssl/rc4.h> + +#include "crypto/s2n_cipher.h" +#include "crypto/s2n_openssl.h" + +#include "utils/s2n_safety.h" +#include "utils/s2n_blob.h" + +static uint8_t s2n_stream_cipher_rc4_available() +{ + return (EVP_rc4() ? 1 : 0); +} + +static int s2n_stream_cipher_rc4_encrypt(struct s2n_session_key *key, struct s2n_blob *in, struct s2n_blob *out) +{ + gte_check(out->size, in->size); + + int len = out->size; + GUARD_OSSL(EVP_EncryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_ENCRYPT); + + S2N_ERROR_IF(len != in->size, S2N_ERR_ENCRYPT); + + return 0; +} + +static int s2n_stream_cipher_rc4_decrypt(struct s2n_session_key *key, struct s2n_blob *in, struct s2n_blob *out) +{ + gte_check(out->size, in->size); + + int len = out->size; + GUARD_OSSL(EVP_DecryptUpdate(key->evp_cipher_ctx, out->data, &len, in->data, in->size), S2N_ERR_ENCRYPT); + + S2N_ERROR_IF(len != in->size, S2N_ERR_ENCRYPT); + + return 0; +} + +static int s2n_stream_cipher_rc4_set_encryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 16); + GUARD_OSSL(EVP_EncryptInit_ex(key->evp_cipher_ctx, EVP_rc4(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +static int s2n_stream_cipher_rc4_set_decryption_key(struct s2n_session_key *key, struct s2n_blob *in) +{ + eq_check(in->size, 16); + GUARD_OSSL(EVP_DecryptInit_ex(key->evp_cipher_ctx, EVP_rc4(), NULL, in->data, NULL), S2N_ERR_KEY_INIT); + + return 0; +} + +static int s2n_stream_cipher_rc4_init(struct s2n_session_key *key) +{ + s2n_evp_ctx_init(key->evp_cipher_ctx); + + return 0; +} + +static int s2n_stream_cipher_rc4_destroy_key(struct s2n_session_key *key) +{ + EVP_CIPHER_CTX_cleanup(key->evp_cipher_ctx); + + return 0; +} + +struct s2n_cipher s2n_rc4 = { + .type = S2N_STREAM, + .key_material_size = 16, + .io.stream = { + .decrypt = s2n_stream_cipher_rc4_decrypt, + .encrypt = s2n_stream_cipher_rc4_encrypt}, + .is_available = s2n_stream_cipher_rc4_available, + .init = s2n_stream_cipher_rc4_init, + .set_decryption_key = s2n_stream_cipher_rc4_set_decryption_key, + .set_encryption_key = s2n_stream_cipher_rc4_set_encryption_key, + .destroy_key = s2n_stream_cipher_rc4_destroy_key, +}; diff --git a/contrib/restricted/aws/s2n/crypto/s2n_tls13_keys.c b/contrib/restricted/aws/s2n/crypto/s2n_tls13_keys.c index 978ce2431e..b0e814ce55 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_tls13_keys.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_tls13_keys.c @@ -1,338 +1,338 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include <stdio.h> - -#include "error/s2n_errno.h" - -#include "stuffer/s2n_stuffer.h" - -#include "crypto/s2n_hmac.h" -#include "crypto/s2n_hkdf.h" -#include "crypto/s2n_tls13_keys.h" - -#include "utils/s2n_blob.h" -#include "utils/s2n_safety.h" -#include "utils/s2n_mem.h" -#include "utils/s2n_safety.h" - -/* - * There are 9 keys that can be generated by the end of a TLS 1.3 handshake. - * We currently support the following, more will be supported - * when the relevant TLS 1.3 features are worked on. - * - * [x] binder_key - * [ ] client_early_traffic_secret - * [ ] early_exporter_master_secret - * [x] client_handshake_traffic_secret - * [x] server_handshake_traffic_secret - * [x] client_application_traffic_secret_0 - * [x] server_application_traffic_secret_0 - * [ ] exporter_master_secret - * [ ] resumption_master_secret - * - * The TLS 1.3 key generation can be divided into 3 phases - * 1. early secrets - * 2. handshake secrets - * 3. master secrets - * - * In each phase, secrets are first extracted with HKDF-Extract that takes in - * both an ikm (input keying material) and a salt. Some keys can be derived/expanded - * from the extract before a "tls13 derived" Derive-Secret is used to - * derive the input salt for the next phase. - */ - -/* - * Define TLS 1.3 HKDF labels as specified in - * https://tools.ietf.org/html/rfc8446#section-7.1 - */ -S2N_BLOB_LABEL(s2n_tls13_label_derived_secret, "derived") - -S2N_BLOB_LABEL(s2n_tls13_label_external_psk_binder_key, "ext binder") -S2N_BLOB_LABEL(s2n_tls13_label_resumption_psk_binder_key, "res binder") - -S2N_BLOB_LABEL(s2n_tls13_label_client_early_traffic_secret, "c e traffic") -S2N_BLOB_LABEL(s2n_tls13_label_early_exporter_master_secret, "e exp master") - -S2N_BLOB_LABEL(s2n_tls13_label_client_handshake_traffic_secret, "c hs traffic") -S2N_BLOB_LABEL(s2n_tls13_label_server_handshake_traffic_secret, "s hs traffic") - -S2N_BLOB_LABEL(s2n_tls13_label_client_application_traffic_secret, "c ap traffic") -S2N_BLOB_LABEL(s2n_tls13_label_server_application_traffic_secret, "s ap traffic") - -S2N_BLOB_LABEL(s2n_tls13_label_exporter_master_secret, "exp master") -S2N_BLOB_LABEL(s2n_tls13_label_resumption_master_secret, "res master") - -/* - * Traffic secret labels - */ -S2N_BLOB_LABEL(s2n_tls13_label_traffic_secret_key, "key") -S2N_BLOB_LABEL(s2n_tls13_label_traffic_secret_iv, "iv") - -/* - * TLS 1.3 Finished label - */ -S2N_BLOB_LABEL(s2n_tls13_label_finished, "finished") - -/* - * TLS 1.3 KeyUpdate label - */ -S2N_BLOB_LABEL(s2n_tls13_label_application_traffic_secret_update, "traffic upd") - -static const struct s2n_blob zero_length_blob = { .data = NULL, .size = 0 }; - -/* Message transcript hash based on selected HMAC algorithm */ -static int s2n_tls13_transcript_message_hash(struct s2n_tls13_keys *keys, const struct s2n_blob *message, struct s2n_blob *message_digest) -{ - notnull_check(keys); - notnull_check(message); - notnull_check(message_digest); - - DEFER_CLEANUP(struct s2n_hash_state hash_state, s2n_hash_free); - GUARD(s2n_hash_new(&hash_state)); - GUARD(s2n_hash_init(&hash_state, keys->hash_algorithm)); - GUARD(s2n_hash_update(&hash_state, message->data, message->size)); - GUARD(s2n_hash_digest(&hash_state, message_digest->data, message_digest->size)); - - return 0; -} - -/* - * Initializes the tls13_keys struct - */ -int s2n_tls13_keys_init(struct s2n_tls13_keys *keys, s2n_hmac_algorithm alg) -{ - notnull_check(keys); - - keys->hmac_algorithm = alg; - GUARD(s2n_hmac_hash_alg(alg, &keys->hash_algorithm)); - GUARD(s2n_hash_digest_size(keys->hash_algorithm, &keys->size)); - GUARD(s2n_blob_init(&keys->extract_secret, keys->extract_secret_bytes, keys->size)); - GUARD(s2n_blob_init(&keys->derive_secret, keys->derive_secret_bytes, keys->size)); - GUARD(s2n_hmac_new(&keys->hmac)); - - return 0; -} - -/* - * Frees any allocation - */ -int s2n_tls13_keys_free(struct s2n_tls13_keys *keys) { - notnull_check(keys); - - GUARD(s2n_hmac_free(&keys->hmac)); - - return 0; -} - -/* - * Derives binder_key from PSK. - */ -int s2n_tls13_derive_binder_key(struct s2n_tls13_keys *keys, struct s2n_psk *psk) -{ - notnull_check(keys); - notnull_check(psk); - - struct s2n_blob *early_secret = &keys->extract_secret; - struct s2n_blob *binder_key = &keys->derive_secret; - - /* Extract the early secret */ - GUARD(s2n_hkdf_extract(&keys->hmac, keys->hmac_algorithm, &zero_length_blob, - &psk->secret, early_secret)); - - /* Choose the correct label for the psk type */ - const struct s2n_blob *label_blob; - if (psk->type == S2N_PSK_TYPE_EXTERNAL) { - label_blob = &s2n_tls13_label_external_psk_binder_key; - } else { - label_blob = &s2n_tls13_label_resumption_psk_binder_key; - } - - /* Derive the binder_key */ - s2n_tls13_key_blob(message_digest, keys->size); - GUARD(s2n_tls13_transcript_message_hash(keys, &zero_length_blob, &message_digest)); - GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, early_secret, - label_blob, &message_digest, binder_key)); - - return S2N_SUCCESS; -} - -/* - * Derives early secrets - */ -int s2n_tls13_derive_early_secrets(struct s2n_tls13_keys *keys) -{ - notnull_check(keys); - - s2n_tls13_key_blob(psk_ikm, keys->size); /* in 1-RTT, PSK is 0-filled of key length */ - - /* Early Secret */ - GUARD(s2n_hkdf_extract(&keys->hmac, keys->hmac_algorithm, &zero_length_blob, &psk_ikm, &keys->extract_secret)); - - /* client_early_traffic_secret and early_exporter_master_secret can be derived here */ - - /* derive next secret */ - s2n_tls13_key_blob(message_digest, keys->size); - GUARD(s2n_tls13_transcript_message_hash(keys, &zero_length_blob, &message_digest)); - GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, &keys->extract_secret, - &s2n_tls13_label_derived_secret, &message_digest, &keys->derive_secret)); - - return 0; -} - -/* - * Derives handshake secrets - */ -int s2n_tls13_derive_handshake_secrets(struct s2n_tls13_keys *keys, - const struct s2n_blob *ecdhe, - struct s2n_hash_state *client_server_hello_hash, - struct s2n_blob *client_secret, - struct s2n_blob *server_secret) -{ - notnull_check(keys); - notnull_check(ecdhe); - notnull_check(client_server_hello_hash); - notnull_check(client_secret); - notnull_check(server_secret); - - /* Handshake Secret */ - GUARD(s2n_hkdf_extract(&keys->hmac, keys->hmac_algorithm, &keys->derive_secret, ecdhe, &keys->extract_secret)); - - s2n_tls13_key_blob(message_digest, keys->size); - - /* copy the hash */ - DEFER_CLEANUP(struct s2n_hash_state hkdf_hash_copy, s2n_hash_free); - GUARD(s2n_hash_new(&hkdf_hash_copy)); - GUARD(s2n_hash_copy(&hkdf_hash_copy, client_server_hello_hash)); - s2n_hash_digest(&hkdf_hash_copy, message_digest.data, message_digest.size); - - /* produce client + server traffic secrets */ - GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, &keys->extract_secret, - &s2n_tls13_label_client_handshake_traffic_secret, &message_digest, client_secret)); - GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, &keys->extract_secret, - &s2n_tls13_label_server_handshake_traffic_secret, &message_digest, server_secret)); - - /* derive next secret */ - GUARD(s2n_tls13_transcript_message_hash(keys, &zero_length_blob, &message_digest)); - GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, &keys->extract_secret, - &s2n_tls13_label_derived_secret, &message_digest, &keys->derive_secret)); - - return 0; -} - -int s2n_tls13_extract_master_secret(struct s2n_tls13_keys *keys) -{ - s2n_tls13_key_blob(empty_key, keys->size); - - /* Extract master secret from derived secret */ - GUARD(s2n_hkdf_extract(&keys->hmac, keys->hmac_algorithm, &keys->derive_secret, &empty_key, &keys->extract_secret)); - - return S2N_SUCCESS; -} - -int s2n_tls13_derive_application_secret(struct s2n_tls13_keys *keys, struct s2n_hash_state *hashes, struct s2n_blob *secret_blob, s2n_mode mode) -{ - notnull_check(keys); - notnull_check(hashes); - notnull_check(secret_blob); - - const struct s2n_blob *label_blob; - if (mode == S2N_CLIENT) { - label_blob = &s2n_tls13_label_client_application_traffic_secret; - } else { - label_blob = &s2n_tls13_label_server_application_traffic_secret; - } - - /* Sanity check that input hash is of expected type */ - S2N_ERROR_IF(keys->hash_algorithm != hashes->alg, S2N_ERR_HASH_INVALID_ALGORITHM); - - s2n_tls13_key_blob(message_digest, keys->size); - - /* copy the hashes into the message_digest */ - DEFER_CLEANUP(struct s2n_hash_state hkdf_hash_copy, s2n_hash_free); - GUARD(s2n_hash_new(&hkdf_hash_copy)); - GUARD(s2n_hash_copy(&hkdf_hash_copy, hashes)); - GUARD(s2n_hash_digest(&hkdf_hash_copy, message_digest.data, message_digest.size)); - - /* Derive traffic secret from master secret */ - GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, &keys->extract_secret, - label_blob, &message_digest, secret_blob)); - - return S2N_SUCCESS; -} - -/* - * Derive Traffic Key and IV based on input secret - */ -int s2n_tls13_derive_traffic_keys(struct s2n_tls13_keys *keys, struct s2n_blob *secret, struct s2n_blob *key, struct s2n_blob *iv) -{ - notnull_check(keys); - notnull_check(secret); - notnull_check(key); - notnull_check(iv); - - GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, secret, - &s2n_tls13_label_traffic_secret_key, &zero_length_blob, key)); - GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, secret, - &s2n_tls13_label_traffic_secret_iv, &zero_length_blob, iv)); - return 0; -} - -/* - * Generate finished key for compute finished hashes/MACs - * https://tools.ietf.org/html/rfc8446#section-4.4.4 - */ -int s2n_tls13_derive_finished_key(struct s2n_tls13_keys *keys, struct s2n_blob *secret_key, struct s2n_blob *output_finish_key) -{ - GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, secret_key, &s2n_tls13_label_finished, &zero_length_blob, output_finish_key)); - - return 0; -} - -/* - * Compute finished verify data using HMAC - * with a finished key and hash state - * https://tools.ietf.org/html/rfc8446#section-4.4.4 - */ -int s2n_tls13_calculate_finished_mac(struct s2n_tls13_keys *keys, struct s2n_blob *finished_key, struct s2n_hash_state *hash_state, struct s2n_blob *finished_verify) -{ - /* Set up a blob to contain hash */ - s2n_tls13_key_blob(transcript_hash, keys->size); - - /* Make a copy of the hash state */ - DEFER_CLEANUP(struct s2n_hash_state hash_state_copy, s2n_hash_free); - GUARD(s2n_hash_new(&hash_state_copy)); - GUARD(s2n_hash_copy(&hash_state_copy, hash_state)); - GUARD(s2n_hash_digest(&hash_state_copy, transcript_hash.data, transcript_hash.size)); - - GUARD(s2n_hkdf_extract(&keys->hmac, keys->hmac_algorithm, finished_key, &transcript_hash, finished_verify)); - - return 0; -} - -/* - * Derives next generation of traffic secret - */ -int s2n_tls13_update_application_traffic_secret(struct s2n_tls13_keys *keys, struct s2n_blob *old_secret, struct s2n_blob *new_secret) -{ - notnull_check(keys); - notnull_check(old_secret); - notnull_check(new_secret); - - GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, old_secret, - &s2n_tls13_label_application_traffic_secret_update, &zero_length_blob, new_secret)); - - return 0; -} +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <stdio.h> + +#include "error/s2n_errno.h" + +#include "stuffer/s2n_stuffer.h" + +#include "crypto/s2n_hmac.h" +#include "crypto/s2n_hkdf.h" +#include "crypto/s2n_tls13_keys.h" + +#include "utils/s2n_blob.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_mem.h" +#include "utils/s2n_safety.h" + +/* + * There are 9 keys that can be generated by the end of a TLS 1.3 handshake. + * We currently support the following, more will be supported + * when the relevant TLS 1.3 features are worked on. + * + * [x] binder_key + * [ ] client_early_traffic_secret + * [ ] early_exporter_master_secret + * [x] client_handshake_traffic_secret + * [x] server_handshake_traffic_secret + * [x] client_application_traffic_secret_0 + * [x] server_application_traffic_secret_0 + * [ ] exporter_master_secret + * [ ] resumption_master_secret + * + * The TLS 1.3 key generation can be divided into 3 phases + * 1. early secrets + * 2. handshake secrets + * 3. master secrets + * + * In each phase, secrets are first extracted with HKDF-Extract that takes in + * both an ikm (input keying material) and a salt. Some keys can be derived/expanded + * from the extract before a "tls13 derived" Derive-Secret is used to + * derive the input salt for the next phase. + */ + +/* + * Define TLS 1.3 HKDF labels as specified in + * https://tools.ietf.org/html/rfc8446#section-7.1 + */ +S2N_BLOB_LABEL(s2n_tls13_label_derived_secret, "derived") + +S2N_BLOB_LABEL(s2n_tls13_label_external_psk_binder_key, "ext binder") +S2N_BLOB_LABEL(s2n_tls13_label_resumption_psk_binder_key, "res binder") + +S2N_BLOB_LABEL(s2n_tls13_label_client_early_traffic_secret, "c e traffic") +S2N_BLOB_LABEL(s2n_tls13_label_early_exporter_master_secret, "e exp master") + +S2N_BLOB_LABEL(s2n_tls13_label_client_handshake_traffic_secret, "c hs traffic") +S2N_BLOB_LABEL(s2n_tls13_label_server_handshake_traffic_secret, "s hs traffic") + +S2N_BLOB_LABEL(s2n_tls13_label_client_application_traffic_secret, "c ap traffic") +S2N_BLOB_LABEL(s2n_tls13_label_server_application_traffic_secret, "s ap traffic") + +S2N_BLOB_LABEL(s2n_tls13_label_exporter_master_secret, "exp master") +S2N_BLOB_LABEL(s2n_tls13_label_resumption_master_secret, "res master") + +/* + * Traffic secret labels + */ +S2N_BLOB_LABEL(s2n_tls13_label_traffic_secret_key, "key") +S2N_BLOB_LABEL(s2n_tls13_label_traffic_secret_iv, "iv") + +/* + * TLS 1.3 Finished label + */ +S2N_BLOB_LABEL(s2n_tls13_label_finished, "finished") + +/* + * TLS 1.3 KeyUpdate label + */ +S2N_BLOB_LABEL(s2n_tls13_label_application_traffic_secret_update, "traffic upd") + +static const struct s2n_blob zero_length_blob = { .data = NULL, .size = 0 }; + +/* Message transcript hash based on selected HMAC algorithm */ +static int s2n_tls13_transcript_message_hash(struct s2n_tls13_keys *keys, const struct s2n_blob *message, struct s2n_blob *message_digest) +{ + notnull_check(keys); + notnull_check(message); + notnull_check(message_digest); + + DEFER_CLEANUP(struct s2n_hash_state hash_state, s2n_hash_free); + GUARD(s2n_hash_new(&hash_state)); + GUARD(s2n_hash_init(&hash_state, keys->hash_algorithm)); + GUARD(s2n_hash_update(&hash_state, message->data, message->size)); + GUARD(s2n_hash_digest(&hash_state, message_digest->data, message_digest->size)); + + return 0; +} + +/* + * Initializes the tls13_keys struct + */ +int s2n_tls13_keys_init(struct s2n_tls13_keys *keys, s2n_hmac_algorithm alg) +{ + notnull_check(keys); + + keys->hmac_algorithm = alg; + GUARD(s2n_hmac_hash_alg(alg, &keys->hash_algorithm)); + GUARD(s2n_hash_digest_size(keys->hash_algorithm, &keys->size)); + GUARD(s2n_blob_init(&keys->extract_secret, keys->extract_secret_bytes, keys->size)); + GUARD(s2n_blob_init(&keys->derive_secret, keys->derive_secret_bytes, keys->size)); + GUARD(s2n_hmac_new(&keys->hmac)); + + return 0; +} + +/* + * Frees any allocation + */ +int s2n_tls13_keys_free(struct s2n_tls13_keys *keys) { + notnull_check(keys); + + GUARD(s2n_hmac_free(&keys->hmac)); + + return 0; +} + +/* + * Derives binder_key from PSK. + */ +int s2n_tls13_derive_binder_key(struct s2n_tls13_keys *keys, struct s2n_psk *psk) +{ + notnull_check(keys); + notnull_check(psk); + + struct s2n_blob *early_secret = &keys->extract_secret; + struct s2n_blob *binder_key = &keys->derive_secret; + + /* Extract the early secret */ + GUARD(s2n_hkdf_extract(&keys->hmac, keys->hmac_algorithm, &zero_length_blob, + &psk->secret, early_secret)); + + /* Choose the correct label for the psk type */ + const struct s2n_blob *label_blob; + if (psk->type == S2N_PSK_TYPE_EXTERNAL) { + label_blob = &s2n_tls13_label_external_psk_binder_key; + } else { + label_blob = &s2n_tls13_label_resumption_psk_binder_key; + } + + /* Derive the binder_key */ + s2n_tls13_key_blob(message_digest, keys->size); + GUARD(s2n_tls13_transcript_message_hash(keys, &zero_length_blob, &message_digest)); + GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, early_secret, + label_blob, &message_digest, binder_key)); + + return S2N_SUCCESS; +} + +/* + * Derives early secrets + */ +int s2n_tls13_derive_early_secrets(struct s2n_tls13_keys *keys) +{ + notnull_check(keys); + + s2n_tls13_key_blob(psk_ikm, keys->size); /* in 1-RTT, PSK is 0-filled of key length */ + + /* Early Secret */ + GUARD(s2n_hkdf_extract(&keys->hmac, keys->hmac_algorithm, &zero_length_blob, &psk_ikm, &keys->extract_secret)); + + /* client_early_traffic_secret and early_exporter_master_secret can be derived here */ + + /* derive next secret */ + s2n_tls13_key_blob(message_digest, keys->size); + GUARD(s2n_tls13_transcript_message_hash(keys, &zero_length_blob, &message_digest)); + GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, &keys->extract_secret, + &s2n_tls13_label_derived_secret, &message_digest, &keys->derive_secret)); + + return 0; +} + +/* + * Derives handshake secrets + */ +int s2n_tls13_derive_handshake_secrets(struct s2n_tls13_keys *keys, + const struct s2n_blob *ecdhe, + struct s2n_hash_state *client_server_hello_hash, + struct s2n_blob *client_secret, + struct s2n_blob *server_secret) +{ + notnull_check(keys); + notnull_check(ecdhe); + notnull_check(client_server_hello_hash); + notnull_check(client_secret); + notnull_check(server_secret); + + /* Handshake Secret */ + GUARD(s2n_hkdf_extract(&keys->hmac, keys->hmac_algorithm, &keys->derive_secret, ecdhe, &keys->extract_secret)); + + s2n_tls13_key_blob(message_digest, keys->size); + + /* copy the hash */ + DEFER_CLEANUP(struct s2n_hash_state hkdf_hash_copy, s2n_hash_free); + GUARD(s2n_hash_new(&hkdf_hash_copy)); + GUARD(s2n_hash_copy(&hkdf_hash_copy, client_server_hello_hash)); + s2n_hash_digest(&hkdf_hash_copy, message_digest.data, message_digest.size); + + /* produce client + server traffic secrets */ + GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, &keys->extract_secret, + &s2n_tls13_label_client_handshake_traffic_secret, &message_digest, client_secret)); + GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, &keys->extract_secret, + &s2n_tls13_label_server_handshake_traffic_secret, &message_digest, server_secret)); + + /* derive next secret */ + GUARD(s2n_tls13_transcript_message_hash(keys, &zero_length_blob, &message_digest)); + GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, &keys->extract_secret, + &s2n_tls13_label_derived_secret, &message_digest, &keys->derive_secret)); + + return 0; +} + +int s2n_tls13_extract_master_secret(struct s2n_tls13_keys *keys) +{ + s2n_tls13_key_blob(empty_key, keys->size); + + /* Extract master secret from derived secret */ + GUARD(s2n_hkdf_extract(&keys->hmac, keys->hmac_algorithm, &keys->derive_secret, &empty_key, &keys->extract_secret)); + + return S2N_SUCCESS; +} + +int s2n_tls13_derive_application_secret(struct s2n_tls13_keys *keys, struct s2n_hash_state *hashes, struct s2n_blob *secret_blob, s2n_mode mode) +{ + notnull_check(keys); + notnull_check(hashes); + notnull_check(secret_blob); + + const struct s2n_blob *label_blob; + if (mode == S2N_CLIENT) { + label_blob = &s2n_tls13_label_client_application_traffic_secret; + } else { + label_blob = &s2n_tls13_label_server_application_traffic_secret; + } + + /* Sanity check that input hash is of expected type */ + S2N_ERROR_IF(keys->hash_algorithm != hashes->alg, S2N_ERR_HASH_INVALID_ALGORITHM); + + s2n_tls13_key_blob(message_digest, keys->size); + + /* copy the hashes into the message_digest */ + DEFER_CLEANUP(struct s2n_hash_state hkdf_hash_copy, s2n_hash_free); + GUARD(s2n_hash_new(&hkdf_hash_copy)); + GUARD(s2n_hash_copy(&hkdf_hash_copy, hashes)); + GUARD(s2n_hash_digest(&hkdf_hash_copy, message_digest.data, message_digest.size)); + + /* Derive traffic secret from master secret */ + GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, &keys->extract_secret, + label_blob, &message_digest, secret_blob)); + + return S2N_SUCCESS; +} + +/* + * Derive Traffic Key and IV based on input secret + */ +int s2n_tls13_derive_traffic_keys(struct s2n_tls13_keys *keys, struct s2n_blob *secret, struct s2n_blob *key, struct s2n_blob *iv) +{ + notnull_check(keys); + notnull_check(secret); + notnull_check(key); + notnull_check(iv); + + GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, secret, + &s2n_tls13_label_traffic_secret_key, &zero_length_blob, key)); + GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, secret, + &s2n_tls13_label_traffic_secret_iv, &zero_length_blob, iv)); + return 0; +} + +/* + * Generate finished key for compute finished hashes/MACs + * https://tools.ietf.org/html/rfc8446#section-4.4.4 + */ +int s2n_tls13_derive_finished_key(struct s2n_tls13_keys *keys, struct s2n_blob *secret_key, struct s2n_blob *output_finish_key) +{ + GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, secret_key, &s2n_tls13_label_finished, &zero_length_blob, output_finish_key)); + + return 0; +} + +/* + * Compute finished verify data using HMAC + * with a finished key and hash state + * https://tools.ietf.org/html/rfc8446#section-4.4.4 + */ +int s2n_tls13_calculate_finished_mac(struct s2n_tls13_keys *keys, struct s2n_blob *finished_key, struct s2n_hash_state *hash_state, struct s2n_blob *finished_verify) +{ + /* Set up a blob to contain hash */ + s2n_tls13_key_blob(transcript_hash, keys->size); + + /* Make a copy of the hash state */ + DEFER_CLEANUP(struct s2n_hash_state hash_state_copy, s2n_hash_free); + GUARD(s2n_hash_new(&hash_state_copy)); + GUARD(s2n_hash_copy(&hash_state_copy, hash_state)); + GUARD(s2n_hash_digest(&hash_state_copy, transcript_hash.data, transcript_hash.size)); + + GUARD(s2n_hkdf_extract(&keys->hmac, keys->hmac_algorithm, finished_key, &transcript_hash, finished_verify)); + + return 0; +} + +/* + * Derives next generation of traffic secret + */ +int s2n_tls13_update_application_traffic_secret(struct s2n_tls13_keys *keys, struct s2n_blob *old_secret, struct s2n_blob *new_secret) +{ + notnull_check(keys); + notnull_check(old_secret); + notnull_check(new_secret); + + GUARD(s2n_hkdf_expand_label(&keys->hmac, keys->hmac_algorithm, old_secret, + &s2n_tls13_label_application_traffic_secret_update, &zero_length_blob, new_secret)); + + return 0; +} diff --git a/contrib/restricted/aws/s2n/crypto/s2n_tls13_keys.h b/contrib/restricted/aws/s2n/crypto/s2n_tls13_keys.h index c572f6edfd..19631c8aa8 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_tls13_keys.h +++ b/contrib/restricted/aws/s2n/crypto/s2n_tls13_keys.h @@ -1,89 +1,89 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#pragma once - -#include <stdint.h> - -#include "crypto/s2n_hmac.h" -#include "crypto/s2n_hkdf.h" -#include "stuffer/s2n_stuffer.h" -#include "tls/s2n_tls_parameters.h" -#include "tls/s2n_psk.h" -#include "utils/s2n_blob.h" -#include "utils/s2n_safety.h" -#include "utils/s2n_mem.h" -#include "utils/s2n_safety.h" - -#define S2N_TLS13_SECRET_MAX_LEN SHA384_DIGEST_LENGTH - -struct s2n_tls13_keys { - s2n_hmac_algorithm hmac_algorithm; - s2n_hash_algorithm hash_algorithm; - - uint8_t size; - - /* we only need to keep these 2 rolling secrets at any point, - * since other secrets to be used can be generated from these - */ - struct s2n_blob extract_secret; - struct s2n_blob derive_secret; - uint8_t extract_secret_bytes[S2N_TLS13_SECRET_MAX_LEN]; - uint8_t derive_secret_bytes[S2N_TLS13_SECRET_MAX_LEN]; - - struct s2n_hmac_state hmac; -}; - -/* Defines TLS 1.3 HKDF Labels */ -extern const struct s2n_blob s2n_tls13_label_derived_secret; -extern const struct s2n_blob s2n_tls13_label_external_psk_binder_key; -extern const struct s2n_blob s2n_tls13_label_resumption_psk_binder_key; - -extern const struct s2n_blob s2n_tls13_label_client_early_traffic_secret; -extern const struct s2n_blob s2n_tls13_label_early_exporter_master_secret; - -extern const struct s2n_blob s2n_tls13_label_client_handshake_traffic_secret; -extern const struct s2n_blob s2n_tls13_label_server_handshake_traffic_secret; - -extern const struct s2n_blob s2n_tls13_label_client_application_traffic_secret; -extern const struct s2n_blob s2n_tls13_label_server_application_traffic_secret; - -extern const struct s2n_blob s2n_tls13_label_exporter_master_secret; -extern const struct s2n_blob s2n_tls13_label_resumption_master_secret; - -/* Traffic secret labels */ - -extern const struct s2n_blob s2n_tls13_label_traffic_secret_key; -extern const struct s2n_blob s2n_tls13_label_traffic_secret_iv; - -#define s2n_tls13_key_blob(name, bytes) \ - s2n_stack_blob(name, bytes, S2N_TLS13_SECRET_MAX_LEN) - -int s2n_tls13_keys_init(struct s2n_tls13_keys *handshake, s2n_hmac_algorithm alg); -int s2n_tls13_keys_free(struct s2n_tls13_keys *keys); -int s2n_tls13_derive_binder_key(struct s2n_tls13_keys *keys, struct s2n_psk *psk); -int s2n_tls13_derive_early_secrets(struct s2n_tls13_keys *handshake); -int s2n_tls13_derive_handshake_secrets(struct s2n_tls13_keys *handshake, - const struct s2n_blob *ecdhe, - struct s2n_hash_state *client_server_hello_hash, - struct s2n_blob *client_secret, - struct s2n_blob *server_secret); -int s2n_tls13_extract_master_secret(struct s2n_tls13_keys *handshake); -int s2n_tls13_derive_application_secret(struct s2n_tls13_keys *handshake, struct s2n_hash_state *hashes, struct s2n_blob *secret_blob, s2n_mode mode); - -int s2n_tls13_derive_traffic_keys(struct s2n_tls13_keys *handshake, struct s2n_blob *secret, struct s2n_blob *key, struct s2n_blob *iv); -int s2n_tls13_derive_finished_key(struct s2n_tls13_keys *keys, struct s2n_blob *secret_key, struct s2n_blob *output_finish_key); -int s2n_tls13_calculate_finished_mac(struct s2n_tls13_keys *keys, struct s2n_blob *finished_key, struct s2n_hash_state *hash_state, struct s2n_blob *finished_verify); -int s2n_tls13_update_application_traffic_secret(struct s2n_tls13_keys *keys, struct s2n_blob *old_secret, struct s2n_blob *new_secret); +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#pragma once + +#include <stdint.h> + +#include "crypto/s2n_hmac.h" +#include "crypto/s2n_hkdf.h" +#include "stuffer/s2n_stuffer.h" +#include "tls/s2n_tls_parameters.h" +#include "tls/s2n_psk.h" +#include "utils/s2n_blob.h" +#include "utils/s2n_safety.h" +#include "utils/s2n_mem.h" +#include "utils/s2n_safety.h" + +#define S2N_TLS13_SECRET_MAX_LEN SHA384_DIGEST_LENGTH + +struct s2n_tls13_keys { + s2n_hmac_algorithm hmac_algorithm; + s2n_hash_algorithm hash_algorithm; + + uint8_t size; + + /* we only need to keep these 2 rolling secrets at any point, + * since other secrets to be used can be generated from these + */ + struct s2n_blob extract_secret; + struct s2n_blob derive_secret; + uint8_t extract_secret_bytes[S2N_TLS13_SECRET_MAX_LEN]; + uint8_t derive_secret_bytes[S2N_TLS13_SECRET_MAX_LEN]; + + struct s2n_hmac_state hmac; +}; + +/* Defines TLS 1.3 HKDF Labels */ +extern const struct s2n_blob s2n_tls13_label_derived_secret; +extern const struct s2n_blob s2n_tls13_label_external_psk_binder_key; +extern const struct s2n_blob s2n_tls13_label_resumption_psk_binder_key; + +extern const struct s2n_blob s2n_tls13_label_client_early_traffic_secret; +extern const struct s2n_blob s2n_tls13_label_early_exporter_master_secret; + +extern const struct s2n_blob s2n_tls13_label_client_handshake_traffic_secret; +extern const struct s2n_blob s2n_tls13_label_server_handshake_traffic_secret; + +extern const struct s2n_blob s2n_tls13_label_client_application_traffic_secret; +extern const struct s2n_blob s2n_tls13_label_server_application_traffic_secret; + +extern const struct s2n_blob s2n_tls13_label_exporter_master_secret; +extern const struct s2n_blob s2n_tls13_label_resumption_master_secret; + +/* Traffic secret labels */ + +extern const struct s2n_blob s2n_tls13_label_traffic_secret_key; +extern const struct s2n_blob s2n_tls13_label_traffic_secret_iv; + +#define s2n_tls13_key_blob(name, bytes) \ + s2n_stack_blob(name, bytes, S2N_TLS13_SECRET_MAX_LEN) + +int s2n_tls13_keys_init(struct s2n_tls13_keys *handshake, s2n_hmac_algorithm alg); +int s2n_tls13_keys_free(struct s2n_tls13_keys *keys); +int s2n_tls13_derive_binder_key(struct s2n_tls13_keys *keys, struct s2n_psk *psk); +int s2n_tls13_derive_early_secrets(struct s2n_tls13_keys *handshake); +int s2n_tls13_derive_handshake_secrets(struct s2n_tls13_keys *handshake, + const struct s2n_blob *ecdhe, + struct s2n_hash_state *client_server_hello_hash, + struct s2n_blob *client_secret, + struct s2n_blob *server_secret); +int s2n_tls13_extract_master_secret(struct s2n_tls13_keys *handshake); +int s2n_tls13_derive_application_secret(struct s2n_tls13_keys *handshake, struct s2n_hash_state *hashes, struct s2n_blob *secret_blob, s2n_mode mode); + +int s2n_tls13_derive_traffic_keys(struct s2n_tls13_keys *handshake, struct s2n_blob *secret, struct s2n_blob *key, struct s2n_blob *iv); +int s2n_tls13_derive_finished_key(struct s2n_tls13_keys *keys, struct s2n_blob *secret_key, struct s2n_blob *output_finish_key); +int s2n_tls13_calculate_finished_mac(struct s2n_tls13_keys *keys, struct s2n_blob *finished_key, struct s2n_hash_state *hash_state, struct s2n_blob *finished_verify); +int s2n_tls13_update_application_traffic_secret(struct s2n_tls13_keys *keys, struct s2n_blob *old_secret, struct s2n_blob *new_secret); |