From 07de078a3b5b7b0043d9f81bb5a9e750a3a0c7c1 Mon Sep 17 00:00:00 2001 From: vnugent Date: Fri, 26 Jul 2024 23:37:15 -0400 Subject: refactor: Span invasion, checks and fix some evp api --- src/providers/openssl.c | 230 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 180 insertions(+), 50 deletions(-) (limited to 'src/providers/openssl.c') diff --git a/src/providers/openssl.c b/src/providers/openssl.c index 5bade3b..7f405ef 100644 --- a/src/providers/openssl.c +++ b/src/providers/openssl.c @@ -27,6 +27,8 @@ #define _OSSL_FAIL(x) if(!(x)) return CSTATUS_FAIL; #define ossl_md_sha256() EVP_MD_fetch(NULL, "SHA2-256", NULL) +#define ossl_evp_fetch_chacha20() EVP_CIPHER_fetch(NULL, "ChaCha20", NULL) +#define ossl_mac_fetch_hmac() EVP_MAC_fetch(NULL, "hmac", NULL) #ifndef _IMPL_SECURE_ZERO_MEMSET @@ -67,9 +69,18 @@ _IMPLSTB cstatus_t _ossl_sha256_digest(cspan_t data, sha256_t digestOut32) { - _overflow_check(data.size) + _overflow_check(data.size); - _OSSL_FAIL(SHA256(data.data, data.size, digestOut32)) + DEBUG_ASSERT(digestOut32 != NULL); + DEBUG_ASSERT(ncSpanIsValidC(data)); + + _OSSL_FAIL( + SHA256( + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data), + digestOut32 + ) + ); return CSTATUS_OK; } @@ -95,17 +106,17 @@ _OSSL_FAIL( HMAC( ossl_md_sha256(), - key.data, - key.size, - data.data, - data.size, + ncSpanGetOffsetC(key, 0), + ncSpanGetSizeC(key), + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data), hmacOut32, &hmacLen ) - ) + ); /* digest length should match the actual digest size */ - DEBUG_ASSERT(hmacLen == sizeof(sha256_t)) + DEBUG_ASSERT(hmacLen == sizeof(sha256_t)); return CSTATUS_OK; } @@ -118,54 +129,91 @@ #define _IMPL_CRYPTO_SHA256_HKDF_EXPAND _ossl_sha256_hkdf_expand - cstatus_t _ossl_hkdf_update(void* ctx, cspan_t data) + struct ossl_hmac_state { + EVP_MAC_CTX* libCtx; + OSSL_PARAM params[2]; + cspan_t prk; + }; + + static cstatus_t _ossl_hmac_init(const struct ossl_hmac_state* osslCtx) { - DEBUG_ASSERT(ctx != NULL) + DEBUG_ASSERT(ncSpanIsValidC(osslCtx->prk)); + DEBUG_ASSERT(osslCtx->params != NULL); - _overflow_check(data.size) + _OSSL_FAIL( + EVP_MAC_init( + osslCtx->libCtx, + ncSpanGetOffsetC(osslCtx->prk, 0), + ncSpanGetSizeC(osslCtx->prk), + osslCtx->params + ) + ); + + return CSTATUS_OK; + } + + static cstatus_t _ossl_hkdf_update(void* ctx, cspan_t data) + { + const struct ossl_hmac_state* osslCtx; + + DEBUG_ASSERT(ctx != NULL); + _overflow_check(data.size); + + osslCtx = (const struct ossl_hmac_state*)ctx; + + DEBUG_ASSERT(osslCtx->libCtx != NULL); _OSSL_FAIL( EVP_MAC_update( - (EVP_MAC_CTX*)ctx, - data.data, - data.size + osslCtx->libCtx, + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data) ) - ) + ); return CSTATUS_OK; } - cstatus_t _ossl_hkdf_finish(void* ctx, sha256_t hmacOut32) + static cstatus_t _ossl_hkdf_finish(void* ctx, sha256_t hmacOut32) { + const struct ossl_hmac_state* osslCtx; size_t hmacSize; DEBUG_ASSERT(ctx != NULL); - DEBUG_ASSERT(hmacOut32 != NULL) + DEBUG_ASSERT(hmacOut32 != NULL); + osslCtx = (const struct ossl_hmac_state*)ctx; hmacSize = 0; + DEBUG_ASSERT(osslCtx->libCtx != NULL); + _OSSL_FAIL( EVP_MAC_final( - (EVP_MAC_CTX*)ctx, - hmacOut32, - &hmacSize, + osslCtx->libCtx, + hmacOut32, + &hmacSize, sizeof(sha256_t) ) - ) + ); /* When configured for sha256, should always be the same size in/out */ - DEBUG_ASSERT(hmacSize == sizeof(sha256_t)) - - return CSTATUS_OK; + DEBUG_ASSERT(hmacSize == sizeof(sha256_t)); + + /* + * Context must be re-initalized after finalize + * See lifecycle https://docs.openssl.org/3.0/man7/life_cycle-mac/#copyright + */ + + return _ossl_hmac_init(osslCtx); } + _IMPLSTB cstatus_t _ossl_sha256_hkdf_expand(cspan_t prk, cspan_t info, span_t okm) { EVP_MAC* mac; - EVP_MAC_CTX* ctx; cstatus_t result; - OSSL_PARAM params[2]; - struct nc_hkdf_fn_cb_struct handler; + struct ossl_hmac_state hkdfState; + struct nc_hkdf_fn_cb_struct handler; result = CSTATUS_FAIL; @@ -173,41 +221,47 @@ handler.finish = _ossl_hkdf_finish; _overflow_check(prk.size); + _overflow_check(info.size); + _overflow_check(okm.size); + + hkdfState.params[0] = OSSL_PARAM_construct_utf8_string("digest", "sha256", 0); + hkdfState.params[1] = OSSL_PARAM_construct_end(); + + hkdfState.prk = prk; /* * Silly openssl stuff. Enable hmac with sha256 using the system default * security provider. The one-shot flag must also be disabled (0) because * we need to call update multiple times. - * - * "provider=default,digest=SHA256,digest-oneshot=0" */ - ctx = NULL; - mac = EVP_MAC_fetch(NULL, "HMAC", NULL); + mac = ossl_mac_fetch_hmac(); if (mac == NULL) { goto Cleanup; } - if ((ctx = EVP_MAC_CTX_new(mac)) == NULL) + hkdfState.libCtx = EVP_MAC_CTX_new(mac); + + if (hkdfState.libCtx == NULL) { goto Cleanup; } - params[0] = OSSL_PARAM_construct_utf8_string("digest", "SHA2-256", 0); - params[1] = OSSL_PARAM_construct_end(); - - if (!EVP_MAC_init(ctx, prk.data, prk.size, params)) + if (_ossl_hmac_init(&hkdfState) != CSTATUS_OK) { goto Cleanup; } - result = hkdfExpandProcess(&handler, ctx, info, okm); + DEBUG_ASSERT(EVP_MAC_CTX_get_mac_size(hkdfState.libCtx) == sizeof(sha256_t)); + + /* Pass the library */ + result = hkdfExpandProcess(&handler, &hkdfState, info, okm); Cleanup: - if (ctx) EVP_MAC_CTX_free(ctx); + if (hkdfState.libCtx) EVP_MAC_CTX_free(hkdfState.libCtx); if (mac) EVP_MAC_free(mac); return result; @@ -221,39 +275,115 @@ #define _IMPL_CHACHA20_CRYPT _ossl_chacha20_crypt - _IMPLSTB cstatus_t _ossl_chacha20_crypt( - const uint8_t* key, - const uint8_t* nonce, - const uint8_t* input, - uint8_t* output, - uint32_t dataLen + _IMPLSTB cstatus_t _ossl_chacha20_cipher_core( + const EVP_CIPHER* cipher, + cspan_t key, + cspan_t iv, + cspan_t input, + span_t output ) { cstatus_t result; EVP_CIPHER_CTX* ctx; + int tempLen, osslResult; - result = CSTATUS_FAIL; + DEBUG_ASSERT2(ncSpanGetSize(output) <= ncSpanGetSizeC(input), "Output buffer must be equal or larger than the input buffer"); + DEBUG_ASSERT(cipher != NULL); + + result = CSTATUS_FAIL; - if ((ctx = EVP_CIPHER_CTX_new()) == NULL) + ctx = EVP_CIPHER_CTX_new(); + + if (ctx == NULL) { - return CSTATUS_FAIL; + goto Cleanup; } - if (!EVP_EncryptInit_ex(ctx, EVP_chacha20(), NULL, key, nonce)) + osslResult = EVP_EncryptInit_ex2( + ctx, + cipher, + ncSpanGetOffsetC(key, 0), + ncSpanGetOffsetC(iv, 0), + NULL + ); + + if (!osslResult) { goto Cleanup; } - if (!EVP_EncryptUpdate(ctx, output, (int*)&dataLen, input, dataLen)) + osslResult = EVP_EncryptUpdate( + ctx, + ncSpanGetOffset(output, 0), + &tempLen, + ncSpanGetOffsetC(input, 0), + ncSpanGetSizeC(input) + ); + + if (!osslResult) { goto Cleanup; } + /* + * We can't get a pointer outside the range of the + * output buffer + */ + if (((uint32_t)tempLen) < ncSpanGetSize(output)) + { + if (!EVP_EncryptFinal_ex(ctx, ncSpanGetOffset(output, tempLen), &tempLen)) + { + goto Cleanup; + } + } + result = CSTATUS_OK; Cleanup: - EVP_CIPHER_CTX_free(ctx); + if (ctx) EVP_CIPHER_CTX_free(ctx); + + return result; + } + + _IMPLSTB cstatus_t _ossl_chacha20_crypt( + const uint8_t* key, + const uint8_t* nonce, + const uint8_t* input, + uint8_t* output, + uint32_t dataLen + ) + { + cstatus_t result; + EVP_CIPHER* cipher; + cspan_t keySpan, nonceSpan, inputSpan; + span_t outputSpan; + + result = CSTATUS_FAIL; + + ncSpanInitC(&keySpan, key, CHACHA_KEY_SIZE); + ncSpanInitC(&nonceSpan, nonce, CHACHA_NONCE_SIZE); + ncSpanInitC(&inputSpan, input, dataLen); + ncSpanInit(&outputSpan, output, dataLen); + + cipher = ossl_evp_fetch_chacha20(); + + if (cipher == NULL) + { + goto Cleanup; + } + + result = _ossl_chacha20_cipher_core( + cipher, + keySpan, + nonceSpan, + inputSpan, + outputSpan + ); + + Cleanup: + + if (cipher) EVP_CIPHER_free(cipher); return result; } -- cgit