123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631 |
- /*
- * 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_hash.h"
- #include "crypto/s2n_fips.h"
- #include "crypto/s2n_hmac.h"
- #include "crypto/s2n_openssl.h"
- #include "error/s2n_errno.h"
- #include "utils/s2n_safety.h"
- static bool s2n_use_custom_md5_sha1()
- {
- #if defined(S2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH)
- return false;
- #else
- return true;
- #endif
- }
- static bool s2n_use_evp_impl()
- {
- return s2n_is_in_fips_mode();
- }
- bool s2n_hash_evp_fully_supported()
- {
- return s2n_use_evp_impl() && !s2n_use_custom_md5_sha1();
- }
- const EVP_MD *s2n_hash_alg_to_evp_md(s2n_hash_algorithm alg)
- {
- switch (alg) {
- case S2N_HASH_MD5:
- return EVP_md5();
- 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();
- #if defined(S2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH)
- case S2N_HASH_MD5_SHA1:
- return EVP_md5_sha1();
- #endif
- default:
- return NULL;
- }
- }
- int s2n_hash_digest_size(s2n_hash_algorithm alg, uint8_t *out)
- {
- POSIX_ENSURE(S2N_MEM_IS_WRITABLE_CHECK(out, sizeof(*out)), S2N_ERR_PRECONDITION_VIOLATION);
- /* clang-format off */
- 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:
- POSIX_BAIL(S2N_ERR_HASH_INVALID_ALGORITHM);
- }
- /* clang-format on */
- 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)
- {
- POSIX_ENSURE(S2N_MEM_IS_WRITABLE_CHECK(block_size, sizeof(*block_size)), S2N_ERR_PRECONDITION_VIOLATION);
- /* clang-format off */
- 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:
- POSIX_BAIL(S2N_ERR_HASH_INVALID_ALGORITHM);
- }
- /* clang-format on */
- 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)
- {
- POSIX_PRECONDITION(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 = (struct s2n_hash_state){ 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:
- POSIX_GUARD_OSSL(MD5_Init(&state->digest.low_level.md5), S2N_ERR_HASH_INIT_FAILED);
- break;
- case S2N_HASH_SHA1:
- POSIX_GUARD_OSSL(SHA1_Init(&state->digest.low_level.sha1), S2N_ERR_HASH_INIT_FAILED);
- break;
- case S2N_HASH_SHA224:
- POSIX_GUARD_OSSL(SHA224_Init(&state->digest.low_level.sha224), S2N_ERR_HASH_INIT_FAILED);
- break;
- case S2N_HASH_SHA256:
- POSIX_GUARD_OSSL(SHA256_Init(&state->digest.low_level.sha256), S2N_ERR_HASH_INIT_FAILED);
- break;
- case S2N_HASH_SHA384:
- POSIX_GUARD_OSSL(SHA384_Init(&state->digest.low_level.sha384), S2N_ERR_HASH_INIT_FAILED);
- break;
- case S2N_HASH_SHA512:
- POSIX_GUARD_OSSL(SHA512_Init(&state->digest.low_level.sha512), S2N_ERR_HASH_INIT_FAILED);
- break;
- case S2N_HASH_MD5_SHA1:
- POSIX_GUARD_OSSL(SHA1_Init(&state->digest.low_level.md5_sha1.sha1), S2N_ERR_HASH_INIT_FAILED);
- POSIX_GUARD_OSSL(MD5_Init(&state->digest.low_level.md5_sha1.md5), S2N_ERR_HASH_INIT_FAILED);
- break;
- default:
- POSIX_BAIL(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)
- {
- POSIX_ENSURE(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY);
- switch (state->alg) {
- case S2N_HASH_NONE:
- break;
- case S2N_HASH_MD5:
- POSIX_GUARD_OSSL(MD5_Update(&state->digest.low_level.md5, data, size), S2N_ERR_HASH_UPDATE_FAILED);
- break;
- case S2N_HASH_SHA1:
- POSIX_GUARD_OSSL(SHA1_Update(&state->digest.low_level.sha1, data, size), S2N_ERR_HASH_UPDATE_FAILED);
- break;
- case S2N_HASH_SHA224:
- POSIX_GUARD_OSSL(SHA224_Update(&state->digest.low_level.sha224, data, size), S2N_ERR_HASH_UPDATE_FAILED);
- break;
- case S2N_HASH_SHA256:
- POSIX_GUARD_OSSL(SHA256_Update(&state->digest.low_level.sha256, data, size), S2N_ERR_HASH_UPDATE_FAILED);
- break;
- case S2N_HASH_SHA384:
- POSIX_GUARD_OSSL(SHA384_Update(&state->digest.low_level.sha384, data, size), S2N_ERR_HASH_UPDATE_FAILED);
- break;
- case S2N_HASH_SHA512:
- POSIX_GUARD_OSSL(SHA512_Update(&state->digest.low_level.sha512, data, size), S2N_ERR_HASH_UPDATE_FAILED);
- break;
- case S2N_HASH_MD5_SHA1:
- POSIX_GUARD_OSSL(SHA1_Update(&state->digest.low_level.md5_sha1.sha1, data, size), S2N_ERR_HASH_UPDATE_FAILED);
- POSIX_GUARD_OSSL(MD5_Update(&state->digest.low_level.md5_sha1.md5, data, size), S2N_ERR_HASH_UPDATE_FAILED);
- break;
- default:
- POSIX_BAIL(S2N_ERR_HASH_INVALID_ALGORITHM);
- }
- POSIX_ENSURE(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)
- {
- POSIX_ENSURE(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY);
- switch (state->alg) {
- case S2N_HASH_NONE:
- break;
- case S2N_HASH_MD5:
- POSIX_ENSURE_EQ(size, MD5_DIGEST_LENGTH);
- POSIX_GUARD_OSSL(MD5_Final(out, &state->digest.low_level.md5), S2N_ERR_HASH_DIGEST_FAILED);
- break;
- case S2N_HASH_SHA1:
- POSIX_ENSURE_EQ(size, SHA_DIGEST_LENGTH);
- POSIX_GUARD_OSSL(SHA1_Final(out, &state->digest.low_level.sha1), S2N_ERR_HASH_DIGEST_FAILED);
- break;
- case S2N_HASH_SHA224:
- POSIX_ENSURE_EQ(size, SHA224_DIGEST_LENGTH);
- POSIX_GUARD_OSSL(SHA224_Final(out, &state->digest.low_level.sha224), S2N_ERR_HASH_DIGEST_FAILED);
- break;
- case S2N_HASH_SHA256:
- POSIX_ENSURE_EQ(size, SHA256_DIGEST_LENGTH);
- POSIX_GUARD_OSSL(SHA256_Final(out, &state->digest.low_level.sha256), S2N_ERR_HASH_DIGEST_FAILED);
- break;
- case S2N_HASH_SHA384:
- POSIX_ENSURE_EQ(size, SHA384_DIGEST_LENGTH);
- POSIX_GUARD_OSSL(SHA384_Final(out, &state->digest.low_level.sha384), S2N_ERR_HASH_DIGEST_FAILED);
- break;
- case S2N_HASH_SHA512:
- POSIX_ENSURE_EQ(size, SHA512_DIGEST_LENGTH);
- POSIX_GUARD_OSSL(SHA512_Final(out, &state->digest.low_level.sha512), S2N_ERR_HASH_DIGEST_FAILED);
- break;
- case S2N_HASH_MD5_SHA1:
- POSIX_ENSURE_EQ(size, MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH);
- POSIX_GUARD_OSSL(SHA1_Final(((uint8_t *) out) + MD5_DIGEST_LENGTH, &state->digest.low_level.md5_sha1.sha1), S2N_ERR_HASH_DIGEST_FAILED);
- POSIX_GUARD_OSSL(MD5_Final(out, &state->digest.low_level.md5_sha1.md5), S2N_ERR_HASH_DIGEST_FAILED);
- break;
- default:
- POSIX_BAIL(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)
- {
- POSIX_CHECKED_MEMCPY(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)
- {
- POSIX_ENSURE_REF(state->digest.high_level.evp.ctx = S2N_EVP_MD_CTX_NEW());
- if (s2n_use_custom_md5_sha1()) {
- POSIX_ENSURE_REF(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().
- */
- POSIX_GUARD(s2n_digest_allow_md5_for_fips(&state->digest.high_level.evp));
- if (s2n_use_custom_md5_sha1()) {
- POSIX_GUARD(s2n_digest_allow_md5_for_fips(&state->digest.high_level.evp_md5_secondary));
- }
- return S2N_SUCCESS;
- }
- static int s2n_evp_hash_init(struct s2n_hash_state *state, s2n_hash_algorithm alg)
- {
- POSIX_ENSURE_REF(state->digest.high_level.evp.ctx);
- state->alg = alg;
- state->is_ready_for_input = 1;
- state->currently_in_hash = 0;
- if (alg == S2N_HASH_NONE) {
- return S2N_SUCCESS;
- }
- if (alg == S2N_HASH_MD5_SHA1 && s2n_use_custom_md5_sha1()) {
- POSIX_ENSURE_REF(state->digest.high_level.evp_md5_secondary.ctx);
- POSIX_GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, EVP_sha1(), NULL), S2N_ERR_HASH_INIT_FAILED);
- POSIX_GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp_md5_secondary.ctx, EVP_md5(), NULL), S2N_ERR_HASH_INIT_FAILED);
- return S2N_SUCCESS;
- }
- POSIX_ENSURE_REF(s2n_hash_alg_to_evp_md(alg));
- POSIX_GUARD_OSSL(EVP_DigestInit_ex(state->digest.high_level.evp.ctx, s2n_hash_alg_to_evp_md(alg), NULL), S2N_ERR_HASH_INIT_FAILED);
- return S2N_SUCCESS;
- }
- static int s2n_evp_hash_update(struct s2n_hash_state *state, const void *data, uint32_t size)
- {
- POSIX_ENSURE(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY);
- POSIX_ENSURE(size <= (UINT64_MAX - state->currently_in_hash), S2N_ERR_INTEGER_OVERFLOW);
- state->currently_in_hash += size;
- if (state->alg == S2N_HASH_NONE) {
- return S2N_SUCCESS;
- }
- POSIX_ENSURE_REF(EVP_MD_CTX_md(state->digest.high_level.evp.ctx));
- POSIX_GUARD_OSSL(EVP_DigestUpdate(state->digest.high_level.evp.ctx, data, size), S2N_ERR_HASH_UPDATE_FAILED);
- if (state->alg == S2N_HASH_MD5_SHA1 && s2n_use_custom_md5_sha1()) {
- POSIX_ENSURE_REF(EVP_MD_CTX_md(state->digest.high_level.evp_md5_secondary.ctx));
- POSIX_GUARD_OSSL(EVP_DigestUpdate(state->digest.high_level.evp_md5_secondary.ctx, data, size), S2N_ERR_HASH_UPDATE_FAILED);
- }
- return S2N_SUCCESS;
- }
- static int s2n_evp_hash_digest(struct s2n_hash_state *state, void *out, uint32_t size)
- {
- POSIX_ENSURE(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY);
- state->currently_in_hash = 0;
- state->is_ready_for_input = 0;
- unsigned int digest_size = size;
- uint8_t expected_digest_size = 0;
- POSIX_GUARD(s2n_hash_digest_size(state->alg, &expected_digest_size));
- POSIX_ENSURE_EQ(digest_size, expected_digest_size);
- if (state->alg == S2N_HASH_NONE) {
- return S2N_SUCCESS;
- }
- POSIX_ENSURE_REF(EVP_MD_CTX_md(state->digest.high_level.evp.ctx));
- if (state->alg == S2N_HASH_MD5_SHA1 && s2n_use_custom_md5_sha1()) {
- POSIX_ENSURE_REF(EVP_MD_CTX_md(state->digest.high_level.evp_md5_secondary.ctx));
- uint8_t sha1_digest_size = 0;
- POSIX_GUARD(s2n_hash_digest_size(S2N_HASH_SHA1, &sha1_digest_size));
- unsigned int sha1_primary_digest_size = sha1_digest_size;
- unsigned int md5_secondary_digest_size = digest_size - sha1_primary_digest_size;
- POSIX_ENSURE(EVP_MD_CTX_size(state->digest.high_level.evp.ctx) <= sha1_digest_size, S2N_ERR_HASH_DIGEST_FAILED);
- POSIX_ENSURE((size_t) EVP_MD_CTX_size(state->digest.high_level.evp_md5_secondary.ctx) <= md5_secondary_digest_size, S2N_ERR_HASH_DIGEST_FAILED);
- POSIX_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);
- POSIX_GUARD_OSSL(EVP_DigestFinal_ex(state->digest.high_level.evp_md5_secondary.ctx, out, &md5_secondary_digest_size), S2N_ERR_HASH_DIGEST_FAILED);
- return S2N_SUCCESS;
- }
- POSIX_ENSURE((size_t) EVP_MD_CTX_size(state->digest.high_level.evp.ctx) <= digest_size, S2N_ERR_HASH_DIGEST_FAILED);
- POSIX_GUARD_OSSL(EVP_DigestFinal_ex(state->digest.high_level.evp.ctx, out, &digest_size), S2N_ERR_HASH_DIGEST_FAILED);
- return S2N_SUCCESS;
- }
- static int s2n_evp_hash_copy(struct s2n_hash_state *to, struct s2n_hash_state *from)
- {
- 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;
- if (from->alg == S2N_HASH_NONE) {
- return S2N_SUCCESS;
- }
- POSIX_ENSURE_REF(to->digest.high_level.evp.ctx);
- POSIX_GUARD_OSSL(EVP_MD_CTX_copy_ex(to->digest.high_level.evp.ctx, from->digest.high_level.evp.ctx), S2N_ERR_HASH_COPY_FAILED);
- if (from->alg == S2N_HASH_MD5_SHA1 && s2n_use_custom_md5_sha1()) {
- POSIX_ENSURE_REF(to->digest.high_level.evp_md5_secondary.ctx);
- POSIX_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);
- }
- bool is_md5_allowed_for_fips = false;
- POSIX_GUARD_RESULT(s2n_digest_is_md5_allowed_for_fips(&from->digest.high_level.evp, &is_md5_allowed_for_fips));
- if (is_md5_allowed_for_fips && (from->alg == S2N_HASH_MD5 || from->alg == S2N_HASH_MD5_SHA1)) {
- POSIX_GUARD(s2n_hash_allow_md5_for_fips(to));
- }
- 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;
- POSIX_GUARD_RESULT(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;
- }
- POSIX_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 && s2n_use_custom_md5_sha1()) {
- POSIX_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) {
- POSIX_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);
- state->digest.high_level.evp.ctx = NULL;
- if (s2n_use_custom_md5_sha1()) {
- S2N_EVP_MD_CTX_FREE(state->digest.high_level.evp_md5_secondary.ctx);
- 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_low_level_hash;
- if (s2n_use_evp_impl()) {
- state->hash_impl = &s2n_evp_hash;
- }
- return S2N_SUCCESS;
- }
- int s2n_hash_new(struct s2n_hash_state *state)
- {
- POSIX_ENSURE_REF(state);
- /* Set hash_impl on initial hash creation.
- * When in FIPS mode, the EVP API's must be used for hashes.
- */
- POSIX_GUARD(s2n_hash_set_impl(state));
- POSIX_ENSURE_REF(state->hash_impl->alloc);
- POSIX_GUARD(state->hash_impl->alloc(state));
- return S2N_SUCCESS;
- }
- S2N_RESULT s2n_hash_state_validate(struct s2n_hash_state *state)
- {
- RESULT_ENSURE_REF(state);
- return S2N_RESULT_OK;
- }
- int s2n_hash_allow_md5_for_fips(struct s2n_hash_state *state)
- {
- POSIX_ENSURE_REF(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.
- */
- POSIX_GUARD(s2n_hash_set_impl(state));
- POSIX_ENSURE_REF(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)
- {
- POSIX_ENSURE_REF(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.
- */
- POSIX_GUARD(s2n_hash_set_impl(state));
- bool is_md5_allowed_for_fips = false;
- POSIX_GUARD_RESULT(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.
- */
- POSIX_ENSURE_REF(state->hash_impl->init);
- return state->hash_impl->init(state, alg);
- } else {
- POSIX_BAIL(S2N_ERR_HASH_INVALID_ALGORITHM);
- }
- }
- int s2n_hash_update(struct s2n_hash_state *state, const void *data, uint32_t size)
- {
- POSIX_PRECONDITION(s2n_hash_state_validate(state));
- POSIX_ENSURE(S2N_MEM_IS_READABLE(data, size), S2N_ERR_PRECONDITION_VIOLATION);
- POSIX_ENSURE_REF(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)
- {
- POSIX_PRECONDITION(s2n_hash_state_validate(state));
- POSIX_ENSURE(S2N_MEM_IS_READABLE(out, size), S2N_ERR_PRECONDITION_VIOLATION);
- POSIX_ENSURE_REF(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)
- {
- POSIX_PRECONDITION(s2n_hash_state_validate(to));
- POSIX_PRECONDITION(s2n_hash_state_validate(from));
- POSIX_ENSURE_REF(from->hash_impl->copy);
- return from->hash_impl->copy(to, from);
- }
- int s2n_hash_reset(struct s2n_hash_state *state)
- {
- POSIX_ENSURE_REF(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.
- */
- POSIX_GUARD(s2n_hash_set_impl(state));
- POSIX_ENSURE_REF(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.
- */
- POSIX_GUARD(s2n_hash_set_impl(state));
- POSIX_ENSURE_REF(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)
- {
- POSIX_PRECONDITION(s2n_hash_state_validate(state));
- POSIX_ENSURE(S2N_MEM_IS_WRITABLE_CHECK(out, sizeof(*out)), S2N_ERR_PRECONDITION_VIOLATION);
- POSIX_ENSURE(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)
- {
- POSIX_PRECONDITION(s2n_hash_state_validate(state));
- POSIX_ENSURE(S2N_MEM_IS_WRITABLE_CHECK(out, sizeof(*out)), S2N_ERR_PRECONDITION_VIOLATION);
- POSIX_ENSURE(state->is_ready_for_input, S2N_ERR_HASH_NOT_READY);
- uint64_t hash_block_size;
- POSIX_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;
- }
|