From f938617d45d1ef62a3315591174a7dc6862aa8b7 Mon Sep 17 00:00:00 2001 From: vnugent Date: Wed, 23 Oct 2024 21:59:03 -0400 Subject: fix: Add Valgrind to testing suite, openssl fixes --- src/providers/openssl-helpers.c | 244 ++++++++++++++++++++++++++++++++++++++++ src/providers/openssl.c | 230 ++++++++++++++++++------------------- 2 files changed, 355 insertions(+), 119 deletions(-) create mode 100644 src/providers/openssl-helpers.c (limited to 'src/providers') diff --git a/src/providers/openssl-helpers.c b/src/providers/openssl-helpers.c new file mode 100644 index 0000000..6037a2f --- /dev/null +++ b/src/providers/openssl-helpers.c @@ -0,0 +1,244 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Package: noscrypt +* File: providers/openssl.c +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public License +* as published by the Free Software Foundation; either version 2.1 +* of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with noscrypt. If not, see http://www.gnu.org/licenses/. +*/ + + +#include +#include + +#define OSSL_SHA256 "SHA2-256" +#define OSSL_HMAC "hmac" +#define ossl_evp_fetch_chacha20() EVP_CIPHER_fetch(NULL, "ChaCha20", NULL) + + +typedef enum { + + EvpStateTypeDigest, + + EvpStateTypeMac + +} _evp_state_type; + +struct ossl_evp_state { + void* _context; + void* _cipher; + + OSSL_PARAM params[2]; + + _evp_state_type type; + + cspan_t _prk; +}; + + +_IMPLSTB EVP_MAC_CTX* _osslEvpGetMacContext(const struct ossl_evp_state* state) +{ + DEBUG_ASSERT(state != NULL); + DEBUG_ASSERT(state->type == EvpStateTypeMac); + + return (EVP_MAC_CTX*)state->_context; +} + +_IMPLSTB EVP_MD_CTX* _osslEvpGetMdContext(const struct ossl_evp_state* state) +{ + DEBUG_ASSERT(state != NULL); + DEBUG_ASSERT(state->type == EvpStateTypeDigest); + + return (EVP_MD_CTX*)state->_context; +} + +_IMPLSTB cspan_t _osslEvpGetPrk(const struct ossl_evp_state* state) +{ + DEBUG_ASSERT(state != NULL); + + return state->_prk; +} + +_IMPLSTB void _osslEvpSetPrk(struct ossl_evp_state* state, cspan_t prk) +{ + DEBUG_ASSERT(state != NULL); + + state->_prk = prk; +} + +_IMPLSTB cstatus_t _osslEvpUpdate(const struct ossl_evp_state* state, cspan_t data) +{ + int result; + + DEBUG_ASSERT(state != NULL); + + result = 0; + + switch (state->type) + { + case EvpStateTypeDigest: + result = EVP_DigestUpdate( + _osslEvpGetMdContext(state), + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data) + ); + break; + + case EvpStateTypeMac: + result = EVP_MAC_update( + _osslEvpGetMacContext(state), + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data) + ); + break; + + } + + return (cstatus_t)(result != 0); +} + +_IMPLSTB cstatus_t _osslEvpFinal(const struct ossl_evp_state* state, span_t out) +{ + int result; + size_t hmacLen; + unsigned int mdLen; + + DEBUG_ASSERT(state != NULL); + + result = 0; + mdLen = hmacLen = ncSpanGetSize(out); + + switch (state->type) + { + case EvpStateTypeDigest: + result = EVP_DigestFinal_ex( + _osslEvpGetMdContext(state), + ncSpanGetOffset(out, 0), + &mdLen + ); + + return (cstatus_t)(result != 0 && mdLen == ncSpanGetSize(out)); + + case EvpStateTypeMac: + result = EVP_MAC_final( + _osslEvpGetMacContext(state), + ncSpanGetOffset(out, 0), + &hmacLen, + hmacLen + ); + return (cstatus_t)(result != 0 && hmacLen == ncSpanGetSize(out)); + } + + /* + * If the result is non-zero and the hash length is equal to the output + * buffer size, return success, otherwise return failure. + */ + + return CSTATUS_FAIL; +} + +_IMPLSTB cstatus_t _osslEvpMacInit(const struct ossl_evp_state* state) +{ + int result; + + DEBUG_ASSERT(state != NULL); + DEBUG_ASSERT(state->type == EvpStateTypeMac); + DEBUG_ASSERT(ncSpanIsValidC(state->_prk)); + + result = EVP_MAC_init( + _osslEvpGetMacContext(state), + ncSpanGetOffsetC(state->_prk, 0), + ncSpanGetSizeC(state->_prk), + state->params + ); + + return (cstatus_t)(result != 0); +} + +_IMPLSTB void _osslEvpFree(struct ossl_evp_state* state) +{ + DEBUG_ASSERT(state != NULL); + + switch (state->type) + { + case EvpStateTypeDigest: + if (state->_context) EVP_MD_CTX_free(state->_context); + if (state->_cipher) EVP_MD_free(state->_cipher); + break; + case EvpStateTypeMac: + if (state->_context) EVP_MAC_CTX_free(state->_context); + if (state->_cipher) EVP_MAC_free(state->_cipher); + break; + } +} + +_IMPLSTB cstatus_t _osslEvpInit( + struct ossl_evp_state* state, + _evp_state_type type, + const char* providerName +) +{ + DEBUG_ASSERT(state != NULL); + DEBUG_ASSERT(providerName != NULL); + + state->type = type; + + switch (type) + { + case EvpStateTypeDigest: + state->_cipher = EVP_MD_fetch(NULL, providerName, NULL); + state->_context = EVP_MD_CTX_new(); + break; + case EvpStateTypeMac: + + state->_cipher = EVP_MAC_fetch(NULL, providerName, NULL); + + if (state->_cipher) + { + state->_context = EVP_MAC_CTX_new((EVP_MAC*)(state->_cipher)); + } + + break; + default: + return CSTATUS_FAIL; + } + + /* + * Ensure allocations succeded, otherwise free the context + * and return a failure status. + */ + if (state->_cipher == NULL || state->_context == NULL) + { + return CSTATUS_FAIL; + } + + /* + * If the type is a digest, initialize the digest context + */ + if (type == EvpStateTypeDigest) + { + if ( + !EVP_DigestInit_ex( + state->_context, + state->_cipher, + NULL + ) + ) + { + return CSTATUS_FAIL; + } + } + + return CSTATUS_OK; +} diff --git a/src/providers/openssl.c b/src/providers/openssl.c index c2933fb..7167fac 100644 --- a/src/providers/openssl.c +++ b/src/providers/openssl.c @@ -22,13 +22,7 @@ /* Setup openssl */ #ifdef OPENSSL_CRYPTO_LIB -#include - -#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) +#include "openssl-helpers.c" #ifndef _IMPL_SECURE_ZERO_MEMSET @@ -63,156 +57,161 @@ #ifndef _IMPL_CRYPTO_SHA256_DIGEST - #include - #define _IMPL_CRYPTO_SHA256_DIGEST _ossl_sha256_digest _IMPLSTB cstatus_t _ossl_sha256_digest(cspan_t data, sha256_t digestOut32) { - _overflow_check(data.size); + cstatus_t result; + span_t digestSpan; + struct ossl_evp_state evpState; + DEBUG_ASSERT(digestOut32 != NULL); DEBUG_ASSERT(ncSpanIsValidC(data)); - _OSSL_FAIL( - SHA256( - ncSpanGetOffsetC(data, 0), - ncSpanGetSizeC(data), - digestOut32 - ) - ); + result = CSTATUS_FAIL; + + _overflow_check(data.size); + + ncSpanInit(&digestSpan, digestOut32, sizeof(sha256_t)); + + /* + * Allocate and initalize the context + */ + if (!_osslEvpInit(&evpState, EvpStateTypeDigest, OSSL_SHA256)) + { + goto Cleanup; + } - return CSTATUS_OK; + if (!_osslEvpUpdate(&evpState, data)) + { + goto Cleanup; + } + + if (!_osslEvpFinal(&evpState, digestSpan)) + { + goto Cleanup; + } + + Cleanup: + + _osslEvpFree(&evpState); + + return result; } #endif #ifndef _IMPL_CRYPTO_SHA256_HMAC - #include - /* Export function */ #define _IMPL_CRYPTO_SHA256_HMAC _ossl_hmac_sha256 _IMPLSTB cstatus_t _ossl_hmac_sha256(cspan_t key, cspan_t data, sha256_t hmacOut32) { - unsigned int hmacLen; + cstatus_t result; + span_t digestSpan; + struct ossl_evp_state evpState; + + result = CSTATUS_FAIL; _overflow_check(key.size) _overflow_check(data.size) - hmacLen = sizeof(sha256_t); - - _OSSL_FAIL( - HMAC( - ossl_md_sha256(), - 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)); + ncSpanInit(&digestSpan, hmacOut32, sizeof(sha256_t)); - return CSTATUS_OK; - } + /* + * Allocate and initalize the context + */ + if (!_osslEvpInit(&evpState, EvpStateTypeMac, OSSL_HMAC)) + { + goto Cleanup; + } -#endif /* !_IMPL_CRYPTO_SHA256_HMAC */ + /* + * To use HMAC the digest parameters must be set + * before the context can be initialized + */ -#ifndef _IMPL_CRYPTO_SHA256_HKDF_EXPAND + evpState.params[0] = OSSL_PARAM_construct_utf8_string("digest", "sha256", 0); + evpState.params[1] = OSSL_PARAM_construct_end(); + + /* + * PRK Data must be assigned before the hmac + * can be initialized + */ + + _osslEvpSetPrk(&evpState, key); - #include + if (!_osslEvpMacInit(&evpState)) + { + goto Cleanup; + } - #define _IMPL_CRYPTO_SHA256_HKDF_EXPAND _ossl_sha256_hkdf_expand + if (!_osslEvpUpdate(&evpState, data)) + { + goto Cleanup; + } - struct ossl_hmac_state { - EVP_MAC_CTX* libCtx; - OSSL_PARAM params[2]; - cspan_t prk; - }; + if (!_osslEvpFinal(&evpState, digestSpan)) + { + goto Cleanup; + } + + result = CSTATUS_OK; - static cstatus_t _ossl_hmac_init(const struct ossl_hmac_state* osslCtx) - { - DEBUG_ASSERT(ncSpanIsValidC(osslCtx->prk)); - DEBUG_ASSERT(osslCtx->params != NULL); - - _OSSL_FAIL( - EVP_MAC_init( - osslCtx->libCtx, - ncSpanGetOffsetC(osslCtx->prk, 0), - ncSpanGetSizeC(osslCtx->prk), - osslCtx->params - ) - ); + Cleanup: + + _osslEvpFree(&evpState); + + return result; - return CSTATUS_OK; } +#endif /* !_IMPL_CRYPTO_SHA256_HMAC */ + +#ifndef _IMPL_CRYPTO_SHA256_HKDF_EXPAND + + #define _IMPL_CRYPTO_SHA256_HKDF_EXPAND _ossl_sha256_hkdf_expand + 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( - osslCtx->libCtx, - ncSpanGetOffsetC(data, 0), - ncSpanGetSizeC(data) - ) + return _osslEvpUpdate( + (const struct ossl_evp_state*)ctx, + data ); - - return CSTATUS_OK; } static cstatus_t _ossl_hkdf_finish(void* ctx, sha256_t hmacOut32) { - const struct ossl_hmac_state* osslCtx; - size_t hmacSize; + span_t hmacSpan; DEBUG_ASSERT(ctx != NULL); DEBUG_ASSERT(hmacOut32 != NULL); - osslCtx = (const struct ossl_hmac_state*)ctx; - hmacSize = 0; + ncSpanInit(&hmacSpan, hmacOut32, sizeof(sha256_t)); - DEBUG_ASSERT(osslCtx->libCtx != NULL); - - _OSSL_FAIL( - EVP_MAC_final( - 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)); + if (!_osslEvpFinal((const struct ossl_evp_state*)ctx, hmacSpan)) + { + return CSTATUS_FAIL; + } /* * 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); + return _osslEvpMacInit((const struct ossl_evp_state*)ctx); } _IMPLSTB cstatus_t _ossl_sha256_hkdf_expand(cspan_t prk, cspan_t info, span_t okm) { - EVP_MAC* mac; cstatus_t result; - struct ossl_hmac_state hkdfState; + struct ossl_evp_state hkdfState; struct nc_hkdf_fn_cb_struct handler; result = CSTATUS_FAIL; @@ -224,45 +223,40 @@ _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. + * PRK Must be set before any call to MacInit + * + * Params must also be set for sha256 digest for mac */ + _osslEvpSetPrk(&hkdfState, prk); - mac = ossl_mac_fetch_hmac(); + hkdfState.params[0] = OSSL_PARAM_construct_utf8_string("digest", "sha256", 0); + hkdfState.params[1] = OSSL_PARAM_construct_end(); - if (mac == NULL) + if (!_osslEvpInit(&hkdfState, EvpStateTypeMac, OSSL_HMAC)) { goto Cleanup; } - hkdfState.libCtx = EVP_MAC_CTX_new(mac); - - if (hkdfState.libCtx == NULL) - { - goto Cleanup; - } + /* + * 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. + */ - if (_ossl_hmac_init(&hkdfState) != CSTATUS_OK) + if (_osslEvpMacInit(&hkdfState) != CSTATUS_OK) { goto Cleanup; } - DEBUG_ASSERT(EVP_MAC_CTX_get_mac_size(hkdfState.libCtx) == sizeof(sha256_t)); + DEBUG_ASSERT(EVP_MAC_CTX_get_mac_size(_osslEvpGetMacContext(&hkdfState)) == sizeof(sha256_t)); /* Pass the library */ result = hkdfExpandProcess(&handler, &hkdfState, info, okm); Cleanup: - - if (hkdfState.libCtx) EVP_MAC_CTX_free(hkdfState.libCtx); - if (mac) EVP_MAC_free(mac); + + _osslEvpFree(&hkdfState); return result; } @@ -271,8 +265,6 @@ #ifndef _IMPL_CHACHA20_CRYPT - #include - #define _IMPL_CHACHA20_CRYPT _ossl_chacha20_crypt _IMPLSTB cstatus_t _ossl_cipher_core( -- cgit From 3c17d3d5f3e34a9302212856b019ddb7842a8a66 Mon Sep 17 00:00:00 2001 From: vnugent Date: Fri, 25 Oct 2024 02:21:25 -0400 Subject: make ossl updates work --- Taskfile.yaml | 1 + src/providers/openssl-helpers.c | 21 +++++++++++---------- src/providers/openssl.c | 2 ++ 3 files changed, 14 insertions(+), 10 deletions(-) (limited to 'src/providers') diff --git a/Taskfile.yaml b/Taskfile.yaml index 7430244..ea12599 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -98,6 +98,7 @@ tasks: silent: true - cmd: cmake --install {{ .CMAKE_BUILD_DIR }} {{ .CLI_ARGS }} + #Test executable and library must be built for tests to run memcheck: desc: 'Runs Valgrind memcheck in debug mode against the nctest executable (Linux only)' platforms: diff --git a/src/providers/openssl-helpers.c b/src/providers/openssl-helpers.c index 6037a2f..42e98c3 100644 --- a/src/providers/openssl-helpers.c +++ b/src/providers/openssl-helpers.c @@ -37,7 +37,7 @@ typedef enum { struct ossl_evp_state { void* _context; - void* _cipher; + void* _providerHandle; OSSL_PARAM params[2]; @@ -82,6 +82,7 @@ _IMPLSTB cstatus_t _osslEvpUpdate(const struct ossl_evp_state* state, cspan_t da int result; DEBUG_ASSERT(state != NULL); + DEBUG_ASSERT(state->_context != NULL); result = 0; @@ -174,11 +175,11 @@ _IMPLSTB void _osslEvpFree(struct ossl_evp_state* state) { case EvpStateTypeDigest: if (state->_context) EVP_MD_CTX_free(state->_context); - if (state->_cipher) EVP_MD_free(state->_cipher); + if (state->_providerHandle) EVP_MD_free(state->_providerHandle); break; case EvpStateTypeMac: if (state->_context) EVP_MAC_CTX_free(state->_context); - if (state->_cipher) EVP_MAC_free(state->_cipher); + if (state->_providerHandle) EVP_MAC_free(state->_providerHandle); break; } } @@ -197,16 +198,16 @@ _IMPLSTB cstatus_t _osslEvpInit( switch (type) { case EvpStateTypeDigest: - state->_cipher = EVP_MD_fetch(NULL, providerName, NULL); + state->_providerHandle = EVP_MD_fetch(NULL, providerName, NULL); state->_context = EVP_MD_CTX_new(); break; case EvpStateTypeMac: - state->_cipher = EVP_MAC_fetch(NULL, providerName, NULL); + state->_providerHandle = EVP_MAC_fetch(NULL, providerName, NULL); - if (state->_cipher) + if (state->_providerHandle) { - state->_context = EVP_MAC_CTX_new((EVP_MAC*)(state->_cipher)); + state->_context = EVP_MAC_CTX_new((EVP_MAC*)(state->_providerHandle)); } break; @@ -218,7 +219,7 @@ _IMPLSTB cstatus_t _osslEvpInit( * Ensure allocations succeded, otherwise free the context * and return a failure status. */ - if (state->_cipher == NULL || state->_context == NULL) + if (state->_providerHandle == NULL || state->_context == NULL) { return CSTATUS_FAIL; } @@ -230,8 +231,8 @@ _IMPLSTB cstatus_t _osslEvpInit( { if ( !EVP_DigestInit_ex( - state->_context, - state->_cipher, + (EVP_MD_CTX*)state->_context, + (EVP_MD*)state->_providerHandle, NULL ) ) diff --git a/src/providers/openssl.c b/src/providers/openssl.c index 7167fac..4b41f1a 100644 --- a/src/providers/openssl.c +++ b/src/providers/openssl.c @@ -93,6 +93,8 @@ goto Cleanup; } + result = CSTATUS_OK; + Cleanup: _osslEvpFree(&evpState); -- cgit From b8a85bed14044c2d40b9cad3c19f878468e4f408 Mon Sep 17 00:00:00 2001 From: vnugent Date: Sun, 3 Nov 2024 00:39:19 -0400 Subject: introduce cipher to evp helpers --- src/providers/openssl-helpers.c | 196 ++++++++++++++++++++++++++++++++++------ src/providers/openssl.c | 186 ++++++++++++++++---------------------- 2 files changed, 246 insertions(+), 136 deletions(-) (limited to 'src/providers') diff --git a/src/providers/openssl-helpers.c b/src/providers/openssl-helpers.c index 42e98c3..bc3a272 100644 --- a/src/providers/openssl-helpers.c +++ b/src/providers/openssl-helpers.c @@ -24,22 +24,24 @@ #define OSSL_SHA256 "SHA2-256" #define OSSL_HMAC "hmac" -#define ossl_evp_fetch_chacha20() EVP_CIPHER_fetch(NULL, "ChaCha20", NULL) +#define OSSL_CHACHA20 "ChaCha20" typedef enum { + EvpStateTypeInvalid, + EvpStateTypeDigest, - EvpStateTypeMac + EvpStateTypeMac, + + EvpStateTypeCipher } _evp_state_type; struct ossl_evp_state { void* _context; - void* _providerHandle; - - OSSL_PARAM params[2]; + void* _providerHandle; _evp_state_type type; @@ -63,6 +65,14 @@ _IMPLSTB EVP_MD_CTX* _osslEvpGetMdContext(const struct ossl_evp_state* state) return (EVP_MD_CTX*)state->_context; } +_IMPLSTB EVP_CIPHER_CTX* _osslEvpGetCipherContext(const struct ossl_evp_state* state) +{ + DEBUG_ASSERT(state != NULL); + DEBUG_ASSERT(state->type == EvpStateTypeCipher); + + return (EVP_CIPHER_CTX*)state->_context; +} + _IMPLSTB cspan_t _osslEvpGetPrk(const struct ossl_evp_state* state) { DEBUG_ASSERT(state != NULL); @@ -104,41 +114,135 @@ _IMPLSTB cstatus_t _osslEvpUpdate(const struct ossl_evp_state* state, cspan_t da ); break; + default: + break; } return (cstatus_t)(result != 0); } -_IMPLSTB cstatus_t _osslEvpFinal(const struct ossl_evp_state* state, span_t out) +_IMPLSTB cstatus_t _osslEvpCipherUpdate( + const struct ossl_evp_state* state, + cspan_t input, + span_t output, + int* bytesConsumed +) { int result; - size_t hmacLen; - unsigned int mdLen; DEBUG_ASSERT(state != NULL); + DEBUG_ASSERT(state->_context != NULL); + DEBUG_ASSERT(state->type == EvpStateTypeCipher); + + result = EVP_EncryptUpdate( + _osslEvpGetCipherContext(state), + ncSpanGetOffset(output, 0), + bytesConsumed, + ncSpanGetOffsetC(input, 0), + ncSpanGetSizeC(input) + ); - result = 0; - mdLen = hmacLen = ncSpanGetSize(out); + return (cstatus_t)(result != 0); +} + +_IMPLSTB cstatus_t __digestFinal(const struct ossl_evp_state* state, span_t out) +{ + int result; + unsigned int mdOut; + + DEBUG_ASSERT(state != NULL); + DEBUG_ASSERT(state->type == EvpStateTypeDigest); + + mdOut = ncSpanGetSize(out); + + /* If the output span is empty, nothing to do */ + if (mdOut == 0) + { + return CSTATUS_OK; + } + + result = EVP_DigestFinal_ex( + _osslEvpGetMdContext(state), + ncSpanGetOffset(out, 0), + &mdOut + ); + + return (cstatus_t)(result != 0 && mdOut == ncSpanGetSize(out)); +} + +_IMPLSTB cstatus_t __macFinal(const struct ossl_evp_state* state, span_t out) +{ + int result; + size_t macOut; + + DEBUG_ASSERT(state != NULL); + DEBUG_ASSERT(state->type == EvpStateTypeMac); + + macOut = ncSpanGetSize(out); + + /* If the output span is empty, nothing to do */ + if (macOut == 0) + { + return CSTATUS_OK; + } + + result = EVP_MAC_final( + _osslEvpGetMacContext(state), + ncSpanGetOffset(out, 0), + &macOut, + macOut + ); + + return (cstatus_t)(result != 0 && macOut == ncSpanGetSize(out)); +} + +_IMPLSTB cstatus_t __cipherFinal(const struct ossl_evp_state* state, span_t out) +{ + int result, cipherOut; + + DEBUG_ASSERT(state != NULL); + DEBUG_ASSERT(state->type == EvpStateTypeCipher); + + /* guard small integer overflow */ + if (ncSpanGetSize(out) > INT_MAX) + { + return CSTATUS_FAIL; + } + + cipherOut = (int)ncSpanGetSize(out); + + /* If the output span is empty, nothing to do */ + if (cipherOut == 0) + { + return CSTATUS_OK; + } + + result = EVP_CipherFinal_ex( + _osslEvpGetCipherContext(state), + ncSpanGetOffset(out, 0), + &cipherOut + ); + + return (cstatus_t)(result != 0 && cipherOut >= 0 && (uint32_t)cipherOut == ncSpanGetSize(out)); +} + +static cstatus_t _osslEvpFinal(const struct ossl_evp_state* state, span_t out) +{ + DEBUG_ASSERT(state != NULL); switch (state->type) { case EvpStateTypeDigest: - result = EVP_DigestFinal_ex( - _osslEvpGetMdContext(state), - ncSpanGetOffset(out, 0), - &mdLen - ); - - return (cstatus_t)(result != 0 && mdLen == ncSpanGetSize(out)); + return __digestFinal(state, out); case EvpStateTypeMac: - result = EVP_MAC_final( - _osslEvpGetMacContext(state), - ncSpanGetOffset(out, 0), - &hmacLen, - hmacLen - ); - return (cstatus_t)(result != 0 && hmacLen == ncSpanGetSize(out)); + return __macFinal(state, out); + + case EvpStateTypeCipher: + return __cipherFinal(state, out); + + default: + break; } /* @@ -149,7 +253,7 @@ _IMPLSTB cstatus_t _osslEvpFinal(const struct ossl_evp_state* state, span_t out) return CSTATUS_FAIL; } -_IMPLSTB cstatus_t _osslEvpMacInit(const struct ossl_evp_state* state) +_IMPLSTB cstatus_t _osslEvpMacInit(const struct ossl_evp_state* state, const OSSL_PARAM* params) { int result; @@ -161,12 +265,39 @@ _IMPLSTB cstatus_t _osslEvpMacInit(const struct ossl_evp_state* state) _osslEvpGetMacContext(state), ncSpanGetOffsetC(state->_prk, 0), ncSpanGetSizeC(state->_prk), - state->params + params ); return (cstatus_t)(result != 0); } +_IMPLSTB cstatus_t _osslEvpCipherInit(const struct ossl_evp_state* state, cspan_t key, cspan_t iv) +{ + int osslResult; + const EVP_CIPHER* cipher; + + DEBUG_ASSERT(state != NULL); + + cipher = (const EVP_CIPHER*)state->_providerHandle; + + /* + * Sanity check on key and IV sizes for the created + * cipher + */ + DEBUG_ASSERT((uint32_t)EVP_CIPHER_get_key_length(cipher) == ncSpanGetSizeC(key)); + DEBUG_ASSERT((uint32_t)EVP_CIPHER_iv_length(cipher) == ncSpanGetSizeC(iv)); + + osslResult = EVP_EncryptInit_ex2( + _osslEvpGetCipherContext(state), + cipher, + ncSpanGetOffsetC(key, 0), + ncSpanGetOffsetC(iv, 0), + NULL + ); + + return (cstatus_t)(osslResult != 0); +} + _IMPLSTB void _osslEvpFree(struct ossl_evp_state* state) { DEBUG_ASSERT(state != NULL); @@ -181,6 +312,12 @@ _IMPLSTB void _osslEvpFree(struct ossl_evp_state* state) if (state->_context) EVP_MAC_CTX_free(state->_context); if (state->_providerHandle) EVP_MAC_free(state->_providerHandle); break; + case EvpStateTypeCipher: + if (state->_context) EVP_CIPHER_CTX_free(state->_context); + if (state->_providerHandle) EVP_CIPHER_free(state->_providerHandle); + break; + default: + break; } } @@ -211,6 +348,11 @@ _IMPLSTB cstatus_t _osslEvpInit( } break; + case EvpStateTypeCipher: + state->_providerHandle = EVP_CIPHER_fetch(NULL, providerName, NULL); + state->_context = EVP_CIPHER_CTX_new(); + break; + default: return CSTATUS_FAIL; } @@ -231,7 +373,7 @@ _IMPLSTB cstatus_t _osslEvpInit( { if ( !EVP_DigestInit_ex( - (EVP_MD_CTX*)state->_context, + _osslEvpGetMdContext(state), (EVP_MD*)state->_providerHandle, NULL ) diff --git a/src/providers/openssl.c b/src/providers/openssl.c index 4b41f1a..73a7902 100644 --- a/src/providers/openssl.c +++ b/src/providers/openssl.c @@ -63,8 +63,7 @@ { cstatus_t result; span_t digestSpan; - struct ossl_evp_state evpState; - + struct ossl_evp_state evpState; DEBUG_ASSERT(digestOut32 != NULL); DEBUG_ASSERT(ncSpanIsValidC(data)); @@ -112,7 +111,8 @@ _IMPLSTB cstatus_t _ossl_hmac_sha256(cspan_t key, cspan_t data, sha256_t hmacOut32) { cstatus_t result; - span_t digestSpan; + span_t digestSpan; + OSSL_PARAM params[2]; struct ossl_evp_state evpState; result = CSTATUS_FAIL; @@ -135,8 +135,8 @@ * before the context can be initialized */ - evpState.params[0] = OSSL_PARAM_construct_utf8_string("digest", "sha256", 0); - evpState.params[1] = OSSL_PARAM_construct_end(); + params[0] = OSSL_PARAM_construct_utf8_string("digest", "sha256", 0); + params[1] = OSSL_PARAM_construct_end(); /* * PRK Data must be assigned before the hmac @@ -145,7 +145,7 @@ _osslEvpSetPrk(&evpState, key); - if (!_osslEvpMacInit(&evpState)) + if (!_osslEvpMacInit(&evpState, params)) { goto Cleanup; } @@ -176,13 +176,22 @@ #define _IMPL_CRYPTO_SHA256_HKDF_EXPAND _ossl_sha256_hkdf_expand + struct _hkdf_state { + OSSL_PARAM params[2]; + struct ossl_evp_state evpState; + }; + static cstatus_t _ossl_hkdf_update(void* ctx, cspan_t data) { + const struct _hkdf_state* state; + DEBUG_ASSERT(ctx != NULL); _overflow_check(data.size); + state = (const struct _hkdf_state*)ctx; + return _osslEvpUpdate( - (const struct ossl_evp_state*)ctx, + &state->evpState, data ); } @@ -190,13 +199,15 @@ static cstatus_t _ossl_hkdf_finish(void* ctx, sha256_t hmacOut32) { span_t hmacSpan; + const struct _hkdf_state* state; DEBUG_ASSERT(ctx != NULL); DEBUG_ASSERT(hmacOut32 != NULL); + state = (const struct _hkdf_state*)ctx; ncSpanInit(&hmacSpan, hmacOut32, sizeof(sha256_t)); - if (!_osslEvpFinal((const struct ossl_evp_state*)ctx, hmacSpan)) + if (!_osslEvpFinal(&state->evpState, hmacSpan)) { return CSTATUS_FAIL; } @@ -206,14 +217,14 @@ * See lifecycle https://docs.openssl.org/3.0/man7/life_cycle-mac/#copyright */ - return _osslEvpMacInit((const struct ossl_evp_state*)ctx); + return _osslEvpMacInit(&state->evpState, state->params); } _IMPLSTB cstatus_t _ossl_sha256_hkdf_expand(cspan_t prk, cspan_t info, span_t okm) { cstatus_t result; - struct ossl_evp_state hkdfState; + struct _hkdf_state state; struct nc_hkdf_fn_cb_struct handler; result = CSTATUS_FAIL; @@ -230,15 +241,7 @@ * * Params must also be set for sha256 digest for mac */ - _osslEvpSetPrk(&hkdfState, prk); - - hkdfState.params[0] = OSSL_PARAM_construct_utf8_string("digest", "sha256", 0); - hkdfState.params[1] = OSSL_PARAM_construct_end(); - - if (!_osslEvpInit(&hkdfState, EvpStateTypeMac, OSSL_HMAC)) - { - goto Cleanup; - } + _osslEvpSetPrk(&state.evpState, prk); /* * Silly openssl stuff. Enable hmac with sha256 using the system default @@ -246,103 +249,38 @@ * we need to call update multiple times. */ - if (_osslEvpMacInit(&hkdfState) != CSTATUS_OK) - { - goto Cleanup; - } - - DEBUG_ASSERT(EVP_MAC_CTX_get_mac_size(_osslEvpGetMacContext(&hkdfState)) == sizeof(sha256_t)); - - /* Pass the library */ - result = hkdfExpandProcess(&handler, &hkdfState, info, okm); - - Cleanup: - - _osslEvpFree(&hkdfState); - - return result; - } - -#endif /* !_IMPL_CRYPTO_SHA256_HKDF_EXPAND */ - -#ifndef _IMPL_CHACHA20_CRYPT - - #define _IMPL_CHACHA20_CRYPT _ossl_chacha20_crypt - - _IMPLSTB cstatus_t _ossl_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; - - DEBUG_ASSERT2(ncSpanGetSize(output) <= ncSpanGetSizeC(input), "Output buffer must be equal or larger than the input buffer"); - DEBUG_ASSERT(cipher != NULL); - - DEBUG_ASSERT((uint32_t)EVP_CIPHER_get_key_length(cipher) == ncSpanGetSizeC(key)); - DEBUG_ASSERT((uint32_t)EVP_CIPHER_iv_length(cipher) == ncSpanGetSizeC(iv)); - - result = CSTATUS_FAIL; - - ctx = EVP_CIPHER_CTX_new(); - - if (ctx == NULL) - { - goto Cleanup; - } - - osslResult = EVP_EncryptInit_ex2( - ctx, - cipher, - ncSpanGetOffsetC(key, 0), - ncSpanGetOffsetC(iv, 0), - NULL - ); + state.params[0] = OSSL_PARAM_construct_utf8_string("digest", "sha256", 0); + state.params[1] = OSSL_PARAM_construct_end(); - if (!osslResult) + if (!_osslEvpInit(&state.evpState, EvpStateTypeMac, OSSL_HMAC)) { goto Cleanup; } - osslResult = EVP_EncryptUpdate( - ctx, - ncSpanGetOffset(output, 0), - &tempLen, - ncSpanGetOffsetC(input, 0), - ncSpanGetSizeC(input) - ); - - if (!osslResult) + if (_osslEvpMacInit(&state.evpState, state.params) != CSTATUS_OK) { 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; - } - } + /* Sanity check mac size */ + DEBUG_ASSERT(EVP_MAC_CTX_get_mac_size(_osslEvpGetMacContext(&state.evpState)) == sizeof(sha256_t)); - result = CSTATUS_OK; + /* Pass to the library */ + result = hkdfExpandProcess(&handler, &state, info, okm); Cleanup: - if (ctx) EVP_CIPHER_CTX_free(ctx); + _osslEvpFree(&state.evpState); return result; } +#endif /* !_IMPL_CRYPTO_SHA256_HKDF_EXPAND */ + +#ifndef _IMPL_CHACHA20_CRYPT + + #define _IMPL_CHACHA20_CRYPT _ossl_chacha20_crypt + _IMPLSTB cstatus_t _ossl_chacha20_crypt( const uint8_t* key, const uint8_t* nonce, @@ -352,12 +290,23 @@ ) { cstatus_t result; - EVP_CIPHER* cipher; + struct ossl_evp_state state; uint8_t chaChaIv[CHACHA_NONCE_SIZE + 4]; cspan_t keySpan, nonceSpan, inputSpan; span_t outputSpan; + int bytesWritten; result = CSTATUS_FAIL; + bytesWritten = 0; + + /* + * Alloc and init the cipher state for ChaCha20 in + * cipher mode + */ + if (!_osslEvpInit(&state, EvpStateTypeCipher, OSSL_CHACHA20)) + { + goto Cleanup; + } /* * RFC 7539 ChaCha20 requires a 16 byte initialization vector. A @@ -375,24 +324,43 @@ ncSpanInitC(&inputSpan, input, dataLen); ncSpanInit(&outputSpan, output, dataLen); - cipher = ossl_evp_fetch_chacha20(); + if (!_osslEvpCipherInit(&state, keySpan, nonceSpan)) + { + goto Cleanup; + } - if (cipher == NULL) + if (!_osslEvpCipherUpdate(&state, inputSpan, outputSpan, &bytesWritten)) { goto Cleanup; } + + /* + * Possible static asser that int size must be 32bit or smaller + */ + if (bytesWritten < 0 || bytesWritten > INT32_MAX) + { + goto Cleanup; + } + + DEBUG_ASSERT((uint32_t)bytesWritten <= dataLen) - result = _ossl_cipher_core( - cipher, - keySpan, - nonceSpan, - inputSpan, - outputSpan + /* shift output span by consumed data amount */ + outputSpan = ncSpanSlice( + outputSpan, + (uint32_t)bytesWritten, + dataLen - (uint32_t)bytesWritten ); + if (!_osslEvpFinal(&state, outputSpan)) + { + goto Cleanup; + } + + result = CSTATUS_OK; + Cleanup: - if (cipher) EVP_CIPHER_free(cipher); + _osslEvpFree(&state); return result; } -- cgit From e0d30c1d8f407bfef05a9cc36398bb0894a96c39 Mon Sep 17 00:00:00 2001 From: vnugent Date: Sun, 3 Nov 2024 12:44:22 -0500 Subject: Once over and fix all valgrind warnings --- src/providers/openssl-helpers.c | 5 +++-- src/providers/openssl.c | 6 ++---- tests/test.c | 7 +++++-- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src/providers') diff --git a/src/providers/openssl-helpers.c b/src/providers/openssl-helpers.c index bc3a272..5369457 100644 --- a/src/providers/openssl-helpers.c +++ b/src/providers/openssl-helpers.c @@ -2,7 +2,7 @@ * Copyright (c) 2024 Vaughn Nugent * * Package: noscrypt -* File: providers/openssl.c +* File: providers/openssl-helpers.c * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -113,8 +113,9 @@ _IMPLSTB cstatus_t _osslEvpUpdate(const struct ossl_evp_state* state, cspan_t da ncSpanGetSizeC(data) ); break; - + /* Cipher is not supported by this api */ default: + DEBUG_ASSERT2(0, "Called update on an invalid state type"); break; } diff --git a/src/providers/openssl.c b/src/providers/openssl.c index 73a7902..925386d 100644 --- a/src/providers/openssl.c +++ b/src/providers/openssl.c @@ -167,7 +167,6 @@ _osslEvpFree(&evpState); return result; - } #endif /* !_IMPL_CRYPTO_SHA256_HMAC */ @@ -186,7 +185,6 @@ const struct _hkdf_state* state; DEBUG_ASSERT(ctx != NULL); - _overflow_check(data.size); state = (const struct _hkdf_state*)ctx; @@ -231,8 +229,7 @@ handler.update = _ossl_hkdf_update; handler.finish = _ossl_hkdf_finish; - - _overflow_check(prk.size); + _overflow_check(info.size); _overflow_check(okm.size); @@ -336,6 +333,7 @@ /* * Possible static asser that int size must be 32bit or smaller + * so it can be cast safely to uint32 */ if (bytesWritten < 0 || bytesWritten > INT32_MAX) { diff --git a/tests/test.c b/tests/test.c index e8ce756..a1f5abe 100644 --- a/tests/test.c +++ b/tests/test.c @@ -289,10 +289,13 @@ static int TestPublicApiArgumentValidation() NCPublicKey pubKey; uint8_t hmacKeyOut[NC_HMAC_KEY_SIZE]; uint8_t nonce[NC_NIP44_IV_SIZE]; - + NCEncryptionArgs cryptoData; - PRINTL("TEST: Public API argument validation tests") + PRINTL("TEST: Public API argument validation tests"); + + /* Zero fill the structure to inialize */ + ZERO_FILL(&cryptoData, sizeof(cryptoData)); { TEST(NCEncryptionGetIvSize(NC_ENC_VERSION_NIP44), sizeof(nonce)); -- cgit