diff --git a/docs/api/00-mainpage.md b/docs/api/00-mainpage.md index 5212f41b..73be9674 100644 --- a/docs/api/00-mainpage.md +++ b/docs/api/00-mainpage.md @@ -34,33 +34,47 @@ The BSL as a whole is separated into two primary layers of implementation: an AP The Frontend library provides the service API for the BSL to be called by its associated [BPA integration](@ref bpa-integrators) and for stable public APIs used by [Policy Provider implementations](@ref policy-providers) and [Security Context implementations](@ref security-contexts). The Backend library implements forward-declared structs and functions from the Frontend using specific concrete data containers, algorithms, _etc._ -The BSL source repository also contains @ref example-pps and @ref example-default-scs to actually exercise the BSL during testing, and a @ref mock-bpa which allows as-built integration testing of the BSL using a pseudo-daemon process. +The following diagram shows the relationships between major BSL components, where solid lines indicate direct API calls and dashed lines indicate registered callback uses. @dot digraph example { - node [shape=record, fontname=Helvetica, fontsize=10]; + graph [fontname=Helvetica]; + node [shape=box, fontname=Helvetica, fontsize=10]; + newrank=true; - frontend [ label="Frontend" ]; - backend [ label=<Backend> ]; - frontend -> backend [ dir=back ]; + subgraph cluster_bsl { + label="BSL"; + frontend [ label="Frontend" ]; + backend [ label=<Backend> ]; + } + frontend -> backend [ style=solid ]; host [ label="Host" ]; bpa [ label="BPA" ]; - crypto [ label="Crypto\nFunctions" ]; - reg_pol [ label="Policy\nRegistry" ]; - reg_sc [ label="Security Context\nRegistry" ]; - backend -> host [ arrowhead="open", style="dashed" ]; - backend -> bpa [ arrowhead="open", style="dashed" ]; - backend -> crypto [ arrowhead="open", style="dashed" ]; - backend -> reg_pol [ arrowhead="open", style="dashed" ]; - backend -> reg_sc [ arrowhead="open", style="dashed" ]; + reg_pp [ label=<Policy Providers> ]; + reg_sc [ label=<Security Contexts> ]; + backend -> host [ arrowhead="open", style=dashed ]; + backend -> bpa [ arrowhead="open", style=dashed ]; + backend -> reg_pp [ arrowhead="open", style=dashed ]; + backend -> reg_sc [ arrowhead="open", style=dashed ]; + { rank=same; host; bpa; reg_sc; reg_pp; } + + subgraph cluster_crypto { + label="BSL crypto"; + rank=same; + crypto [ label="Crypto\nFunctions" ]; + keystore [ label="Key Store" ]; + } + reg_sc -> crypto [ arrowhead="open", style=solid ]; + crypto -> keystore [ arrowhead="open", style=solid ]; + keystore -> bpa [ arrowhead="open", style=dashed ]; } @enddot The BSL comes with a @ref frontend and a @ref backend_dyn implementation which uses heap-allocated, dynamically-sized data structures and run-time registration capabilities. For a more constrained (_e.g._, flight software) environment an alternative backend could be implemented with fixed-size data containers and constant-time registry lookup algorithms. -Along with these libraries are also two integration extensions: an _Example Policy_ module and a _Default Security Contexts_ module. +The BSL source repository also contains @ref example-pps and @ref example-scs to actually exercise the BSL during testing, and a @ref mock-bpa which allows as-built integration testing of the BSL using a pseudo-daemon process. Together these use the abstract Frontend and populate the otherwise empty Dynamic Backend registries to create an out-of-the-box usable BPSec implementation. # Dependencies @@ -88,8 +102,8 @@ This is the concrete implementation of a backend using dynamic heap-allocated co It uses POSIX APIs to provide necessary Host functions for the BSL, and OpenSSL APIs to provide crypto functions for the BSL. -@defgroup example_pp Example Policy Provider -@brief Implementation of a simple rule-based policy provider. +@defgroup example_pp Sample Policy Provider +@brief Implementation of a simple rule-based policy provider configured with JSON input. This group contains files used by the Example Policy Provider library included with the BSL. @@ -100,12 +114,26 @@ This group contains files used by the Example Policy Provider library included w This group contains files used by the Default Security Contexts (RFC 9173 @cite rfc9173) library included with the BSL. +@defgroup cose_sc COSE Context +@brief Implementation of the COSE Context using the BSL crypto API. + +This group contains files used by the COSE Context (draft @cite draft-ietf-dtn-bpsec-cose) library included with the BSL. + + +@defgroup crypto Cryptographic Processing and Key Store API +@brief Implementation of the BSL crypto API by a software backend and user of the BSL key store interface. + +This group contains files used by the Default Security Contexts (RFC 9173 @cite rfc9173) library included with the BSL. + + @defgroup mock_bpa Example/Mock BP Agent @brief Files used in the Mock BPA used for testing. The Mock BPA performs whole-bundle encoding and decoding (CODEC) functions, but no other stateful bundle processing. This allows end-to-end bundle testing with real policy configurations. +The Mock BPA also implements an in-memory key store registered with the BSL crypto library. + @defgroup unit_test Unit Testing @brief Files used for unit testing of BSL behaviors. diff --git a/docs/api/02-bpa-integrators.md b/docs/api/02-bpa-integrators.md index a4fc96ae..2f3a2e72 100644 --- a/docs/api/02-bpa-integrators.md +++ b/docs/api/02-bpa-integrators.md @@ -77,9 +77,13 @@ digraph bpa_interaction { } @enddot -# BPA Callback API {#bpa-callback-api} +# BPA Callback APIs {#bpa-callback-api} Separate from the API used to call into the BSL to initiate security processing, the BSL relies on specific functions provided by the BPA to do its normal processing. -Some of these functions are for introspecting and manipulating specific bundle or block contents, others are for encoding and decoding EID and EID Pattern values. +Some of these functions are for introspecting and manipulating specific bundle or block contents, others are for encoding and decoding EID and EID Pattern values, and a separate set are used by the internal BSL crypto library for key store access. -The BSL dynamic backend declares a set of functions which are delegated to the BPA, which are registered in the dynamic backend using the ::BSL_HostDescriptors_t struct and the BSL_HostDescriptors_Set() function. +The BSL dynamic backend declares a set of functions which are delegated to the BPA. +These are registered in the dynamic backend using the ::BSL_HostDescriptors_t struct and the BSL_HostDescriptors_Set() function. + +The BSL crypto library declares a set of functions which are delegated to the BPA. +These are registered in the crypto library using the ::BSL_KeyStore_Descriptors_t struct and the BSL_KeyStore_Init() function. diff --git a/docs/api/04-examples-and-mocks.md b/docs/api/04-examples-and-mocks.md index 8610876d..0e3557ff 100644 --- a/docs/api/04-examples-and-mocks.md +++ b/docs/api/04-examples-and-mocks.md @@ -39,11 +39,13 @@ This PP is registered and used by the @ref mock-bpa for many BSL testing cases. Sources related to these example PPs are associated with the @ref example_pp group. -# Example Default Security Contexts {#example-default-scs} +# Example Security Contexts {#example-scs} The two Default Security Contexts defined in RFC 9173 @cite rfc9173 offer minimal, interoperable, and pre-shared-key-focused integrity and confidentiality operations. -An implementation of these two SCs is maintained as part of the BSL source and uses the BSL crypto library as an interface to the OpenSSL library @cite lib:openssl from the host OS. +The COSE Context defined in an internet draft @cite draft-ietf-dtn-bpsec-cose offers more full-featured, layered symmetric key options including key wrapping and key derivation. + +An implementation of each of these SCs is maintained as part of the BSL source and uses the BSL crypto library as an wrapper for the OpenSSL library @cite lib:openssl from the host OS and a key store registered with the crypto library (part of the @ref bpa-callback-api). These SCs are registered and used by the @ref mock-bpa for BSL testing. Sources related to these example SCs are associated with the @ref default_sc group. @@ -55,7 +57,7 @@ The Mock BPA uses an un-framed UDPCL-like interface for its underlayer and also The Mock BPA is limited to a single registered endpoint, and does no other handling normally required by RFC 9171 @cite rfc9171. So for this reason it is not a true BPA and must not be treated as one. -Upon startup, the Mock BPA registers a single [ION-based Example Policy Provider](@ref example-pps) and the two [example Default Security Contexts](@ref example-default-scs). +Upon startup, the Mock BPA registers a single [ION-based Example Policy Provider](@ref example-pps) and all of the [example Security Contexts](@ref example-scs). Sources related to the Mock BPA are associated with the @ref mock_bpa group. @@ -75,7 +77,7 @@ The path to the JSON file should be passed to the Mock BPA with the `-j` command ## Key Management -The keys used by the example SCs registered in the Mock BPA's Cryptographic Library instance are obtained from a file using the JSON Web Key (JWK) format of RFC 7517 @cite rfc7517. +The keys used by the example SCs registered in the Mock BPA's key store are obtained from a file using either the JSON Web Key (JWK) Set format of RFC 7517 @cite rfc7517 or the COSE Key Set format of RFC 9052 @cite rfc9052. The implementation to support these SCs only handles symmetric keys and only the minimal header parameters needed for key ID ("kid") and symmetric key material itself ("k"). @@ -94,4 +96,4 @@ The table below contains the Mock BPA executable command line options. See the M | `-s` | The endpoint ID of the local security source used to handle BPSec. | | `-p` | The comma-separated bit fields representing policies to initialize Mock BPA with. | | `-j` | The path to a ION-Like Policy JSON-encoded policy structure file containing policies to initialize Mock BPA with. | -| `-k` | The path to a JSON Web Key (JWK) formatted file containing keys to register with the BPA's Cryptographic Library instance. | +| `-k` | The path to a JSON Web Key (JWK) file (named ".json") or COSE Key Set (named ".cbor") containing keys to register with the BPA's key store. | diff --git a/docs/api/dictionary.txt b/docs/api/dictionary.txt index f91cc4d6..5fca1d8a 100644 --- a/docs/api/dictionary.txt +++ b/docs/api/dictionary.txt @@ -51,6 +51,7 @@ callee's calloc CALLOC Carsten +cbor CBOR CCSDS cek @@ -127,6 +128,7 @@ isspace JHU Josefsson JPL +json JSON JWK JWKs diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd3b0472..3e7f5325 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,9 +54,11 @@ target_include_directories(bsl_front PUBLIC add_library(bsl_crypto) target_sources(bsl_crypto PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/bsl/crypto/CryptoInterface.h + ${CMAKE_CURRENT_SOURCE_DIR}/bsl/crypto/KeyStore.h ) target_sources(bsl_crypto PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bsl/crypto/CryptoInterface.c + ${CMAKE_CURRENT_SOURCE_DIR}/bsl/crypto/KeyStore.c ) set_target_properties(bsl_crypto PROPERTIES @@ -180,7 +182,7 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/eidpat.h ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/encode.h ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/decode.h - ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/key_registry.h + ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/KeyStore.h ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/ctr.h ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/MockBPA.h ) @@ -194,7 +196,7 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/eidpat.c ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/encode.c ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/decode.c - ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/key_registry.c + ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/KeyStore.c ${CMAKE_CURRENT_SOURCE_DIR}/bsl/mock_bpa/ctr.c ) set_target_properties(bsl_mock_bpa diff --git a/src/bsl/crypto/CryptoInterface.c b/src/bsl/crypto/CryptoInterface.c index 24e75108..6a6ae1fc 100644 --- a/src/bsl/crypto/CryptoInterface.c +++ b/src/bsl/crypto/CryptoInterface.c @@ -20,8 +20,8 @@ * subcontract 1700763. */ /** @file + * @ingroup crypto * Backend cryptography implementation - * @ingroup backend_dyn */ #include "CryptoInterface.h" @@ -29,9 +29,6 @@ #include "bsl/front/TextUtil.h" #include "bsl/dynamic/IdValPair.h" -#include -#include -#include #include #include #include @@ -42,133 +39,32 @@ #include #endif /* defined(HAVE_VALGRIND) */ -/** - * Struct to hold private key information - */ -typedef struct BSL_CryptoKey_s -{ - /// Pointer to raw key information - BSL_Data_t raw; - /// Additional parameter dictionary - BSLB_IdValPairPtrMap_t params; - /// Statistics related to this key - BSL_Crypto_KeyStats_t stats; - /// Mutex for #stats - pthread_mutex_t stats_mutex; -} BSL_CryptoKey_t; - -static void BSL_CryptoKey_Init(BSL_CryptoKey_t *key) -{ - ASSERT_ARG_NONNULL(key); - - BSL_Data_Init(&(key->raw)); - BSLB_IdValPairPtrMap_init(key->params); - - for (uint64_t i = 0; i < BSL_CRYPTO_KEYSTATS_MAX_INDEX; i++) - { - key->stats.stats[i] = 0; - } - pthread_mutex_init(&key->stats_mutex, NULL); -} - -static void BSL_CryptoKey_Deinit(BSL_CryptoKey_t *key) -{ - ASSERT_ARG_NONNULL(key); - - BSL_Data_Deinit(&(key->raw)); - BSLB_IdValPairPtrMap_clear(key->params); - - pthread_mutex_destroy(&key->stats_mutex); - for (uint64_t i = 0; i < BSL_CRYPTO_KEYSTATS_MAX_INDEX; i++) - { - key->stats.stats[i] = 0; - } -} - -/** M*LIB OPLIST for ::BSL_CryptoKey_t - */ -#define M_OPL_BSL_CryptoKey_t() \ - M_OPEXTEND(M_POD_OPLIST, INIT(API_2(BSL_CryptoKey_Init)), INIT_SET(0), SET(0), CLEAR(API_2(BSL_CryptoKey_Deinit))) - -/** @struct BSL_CryptoKeyPtr_t - * Thread-safe shared pointer to memory-stable ::BSL_CryptoKey_t struct. - */ -/** @struct BSL_CryptoKeyDict_t - * Stable dict of crypto keys (key: key ID | value: BSL_CryptoKeyPtr_t) - */ -/// @cond Doxygen_Suppress -// NOLINTBEGIN -// GCOV_EXCL_START -M_SHARED_PTR_DEF(BSL_CryptoKeyPtr, BSL_CryptoKey_t, M_OPL_BSL_CryptoKey_t()) -#define M_OPL_BSL_CryptoKeyPtr() M_SHARED_PTR_OPLIST(BSL_CryptoKeyPtr, M_OPL_BSL_CryptoKey_t()) -M_DICT_DEF2(BSL_CryptoKeyDict, m_bstring_t, M_BSTRING_OPLIST, BSL_CryptoKeyPtr_t *, M_OPL_BSL_CryptoKeyPtr()) -// GCOV_EXCL_STOP -// NOLINTEND -/// @endcond +extern BSL_KeyStore_Descriptors_t BSL_KeyStore_State; /// Random bytes generator -static BSL_Crypto_RandBytesFn rand_bytes_generator; - -/// Crypto key registry -static BSL_CryptoKeyDict_t StaticKeyRegistry; -static pthread_mutex_t StaticCryptoMutex = PTHREAD_MUTEX_INITIALIZER; - -void BSL_CryptoInit(void) -{ - pthread_mutex_lock(&StaticCryptoMutex); - BSL_CryptoKeyDict_init(StaticKeyRegistry); - pthread_mutex_unlock(&StaticCryptoMutex); - rand_bytes_generator = RAND_bytes; -} - -void BSL_CryptoDeinit(void) -{ - pthread_mutex_lock(&StaticCryptoMutex); - BSL_CryptoKeyDict_clear(StaticKeyRegistry); - pthread_mutex_unlock(&StaticCryptoMutex); -} +static BSL_Crypto_RandBytesFn rand_bytes_generator = RAND_bytes; void BSL_Crypto_SetRngGenerator(BSL_Crypto_RandBytesFn rand_gen_fn) { rand_bytes_generator = rand_gen_fn; } -void BSL_Crypto_ReleaseKeyHandle(BSL_Crypto_KeyHandle_t keyhandle) -{ - if (!keyhandle) - { - return; - } - - BSL_CryptoKeyPtr_t *ptr = keyhandle; - BSL_CryptoKeyPtr_release(ptr); -} - -bool BSL_Crypto_CompareKeys(BSL_Crypto_KeyHandle_t hdl1, BSL_Crypto_KeyHandle_t hdl2) -{ - if (!hdl1 || !hdl2) - { - return false; - } - const BSL_CryptoKey_t *key1 = BSL_CryptoKeyPtr_ref(hdl1); - const BSL_CryptoKey_t *key2 = BSL_CryptoKeyPtr_ref(hdl2); - - return BSL_Crypto_Compare(key1->raw.ptr, key1->raw.len, key2->raw.ptr, key2->raw.len); -} - int BSL_Crypto_UnwrapKey(BSL_Crypto_KeyHandle_t kek_handle, const BSL_Data_t *wrapped_key, BSL_Crypto_KeyHandle_t *cek_handle) { ASSERT_ARG_NONNULL(kek_handle); ASSERT_ARG_NONNULL(wrapped_key); ASSERT_ARG_NONNULL(cek_handle); + *cek_handle = NULL; - BSL_CryptoKey_t *kek = BSL_CryptoKeyPtr_ref(kek_handle); + int retval = BSL_SUCCESS; + int res; - *cek_handle = NULL; + BSL_Data_t kek_view; + CHK_PRECONDITION(BSL_SUCCESS == BSL_KeyStore_State.get_keymat(kek_handle, &kek_view)); const EVP_CIPHER *cipher; - switch (kek->raw.len) + switch (kek_view.len) { case 16: { @@ -193,64 +89,85 @@ int BSL_Crypto_UnwrapKey(BSL_Crypto_KeyHandle_t kek_handle, const BSL_Data_t *wr } EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); - CHK_PROPERTY(ctx != NULL); - - BSL_CryptoKeyPtr_t *cek_ptr = BSL_CryptoKeyPtr_new(); - // managed struct - BSL_CryptoKey_t *cek = BSL_CryptoKeyPtr_ref(cek_ptr); - CHK_PROPERTY(cek != NULL); - - // wrapped key always 8 bytes greater than CEK @cite rfc3394 (2.2.1) - BSL_Data_Resize(&cek->raw, wrapped_key->len - 8); - - BSL_LOG_PLAINTEXT_PTR("using KEK", cek_handle, kek->raw.ptr, kek->raw.len); - int dec_result = EVP_DecryptInit_ex(ctx, cipher, NULL, kek->raw.ptr, NULL); - if (dec_result != 1) + // GCOV_EXCL_START + if (ctx == NULL) { - BSL_LOG_ERR("EVP_DecryptInit_ex: %s", ERR_error_string(ERR_get_error(), NULL)); - BSL_CryptoKeyPtr_release(cek_ptr); + BSL_LOG_ERR("Could not create cipher context"); return BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; } - EVP_CIPHER_CTX_set_padding(ctx, 0); + // GCOV_EXCL_STOP - pthread_mutex_lock(&kek->stats_mutex); - kek->stats.stats[BSL_CRYPTO_KEYSTATS_TIMES_USED]++; - kek->stats.stats[BSL_CRYPTO_KEYSTATS_BYTES_PROCESSED] += cek->raw.len; - pthread_mutex_unlock(&kek->stats_mutex); + BSL_Data_t cek_keymat; + // wrapped key always 8 bytes greater than CEK @cite rfc3394 (2.2.1) + res = BSL_Data_InitBuffer(&cek_keymat, wrapped_key->len - 8); + if (BSL_SUCCESS != res) + { + retval = res; + } - int out_len = (int)cek->raw.len; - BSL_LOG_PLAINTEXT_PTR("wrapped key", cek_handle, wrapped_key->ptr, wrapped_key->len); - int decrypt_res = EVP_DecryptUpdate(ctx, cek->raw.ptr, &out_len, wrapped_key->ptr, wrapped_key->len); - if (decrypt_res != 1) + if (BSL_SUCCESS == retval) { - BSL_LOG_ERR("EVP_DecryptUpdate: %s", ERR_error_string(ERR_get_error(), NULL)); - EVP_CIPHER_CTX_free(ctx); - BSL_CryptoKeyPtr_release(cek_ptr); - return BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + BSL_LOG_PLAINTEXT_PTR("using KEK", cek_handle, kek_view.ptr, kek_view.len); + res = EVP_DecryptInit_ex(ctx, cipher, NULL, kek_view.ptr, NULL); + // GCOV_EXCL_START + if (res != 1) + { + BSL_LOG_ERR("EVP_DecryptInit_ex: %s", ERR_error_string(ERR_get_error(), NULL)); + retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + } + // GCOV_EXCL_STOP + EVP_CIPHER_CTX_set_padding(ctx, 0); } - cek->raw.len = (size_t)out_len; - uint8_t buf[EVP_CIPHER_CTX_block_size(ctx)]; - int final_len = 0; - int res = EVP_DecryptFinal_ex(ctx, buf, &final_len); - if (res != 1) + BSL_KeyStore_State.update_stats(kek_handle, 1, cek_keymat.len); + + int out_len; + if (BSL_SUCCESS == retval) { - BSL_LOG_ERR("Failed DecryptFinal: %s", ERR_error_string(ERR_get_error(), NULL)); - EVP_CIPHER_CTX_free(ctx); - BSL_CryptoKeyPtr_release(cek_ptr); - return BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + out_len = (int)cek_keymat.len; + BSL_LOG_PLAINTEXT_PTR("wrapped key", cek_handle, wrapped_key->ptr, wrapped_key->len); + res = EVP_DecryptUpdate(ctx, cek_keymat.ptr, &out_len, wrapped_key->ptr, (int)wrapped_key->len); + // GCOV_EXCL_START + if (res != 1) + { + BSL_LOG_ERR("EVP_DecryptUpdate: %s", ERR_error_string(ERR_get_error(), NULL)); + retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + } + // GCOV_EXCL_STOP + else + { + cek_keymat.len = (size_t)out_len; + } } - if (final_len > 0) + if (BSL_SUCCESS == retval) { - BSL_Data_AppendFrom(&cek->raw, (size_t)final_len, buf); + out_len = 0; + res = EVP_DecryptFinal_ex(ctx, NULL, &out_len); + // GCOV_EXCL_START + if (res != 1) + { + BSL_LOG_ERR("Failed DecryptFinal: %s", ERR_error_string(ERR_get_error(), NULL)); + retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + } + else if (out_len > 0) + { + BSL_LOG_ERR("Key wrap without padding should not have any final data"); + retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + } + // GCOV_EXCL_STOP + BSL_LOG_PLAINTEXT_PTR("unwrapped key", cek_handle, cek_keymat.ptr, cek_keymat.len); } EVP_CIPHER_CTX_free(ctx); - BSL_LOG_PLAINTEXT_PTR("unwrapped key", cek, cek->raw.ptr, cek->raw.len); - *cek_handle = cek_ptr; - return 0; + if (BSL_SUCCESS == retval) + { + retval = BSL_Crypto_LoadKey(cek_keymat.ptr, cek_keymat.len, cek_handle); + } + BSL_Data_Deinit(&cek_keymat); + + return retval; } int BSL_Crypto_WrapKey(BSL_Crypto_KeyHandle_t kek_handle, BSL_Crypto_KeyHandle_t cek_handle, BSL_Data_t *wrapped_key) @@ -259,11 +176,17 @@ int BSL_Crypto_WrapKey(BSL_Crypto_KeyHandle_t kek_handle, BSL_Crypto_KeyHandle_t CHK_ARG_NONNULL(cek_handle); CHK_ARG_NONNULL(wrapped_key); - BSL_CryptoKey_t *kek = BSL_CryptoKeyPtr_ref(kek_handle); - BSL_CryptoKey_t *cek = BSL_CryptoKeyPtr_ref(cek_handle); + int retval = BSL_SUCCESS; + int res; + + BSL_Data_t kek_view; + CHK_PRECONDITION(BSL_SUCCESS == BSL_KeyStore_State.get_keymat(kek_handle, &kek_view)); + + BSL_Data_t cek_view; + CHK_PRECONDITION(BSL_SUCCESS == BSL_KeyStore_State.get_keymat(cek_handle, &cek_view)); const EVP_CIPHER *cipher; - switch (kek->raw.len) + switch (kek_view.len) { case 16: { @@ -288,54 +211,69 @@ int BSL_Crypto_WrapKey(BSL_Crypto_KeyHandle_t kek_handle, BSL_Crypto_KeyHandle_t } EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + // GCOV_EXCL_START if (ctx == NULL) { BSL_LOG_ERR("Could not create cipher context"); - return -1; + return BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; } + // GCOV_EXCL_STOP - BSL_LOG_PLAINTEXT_PTR("using KEK", cek_handle, kek->raw.ptr, kek->raw.len); - int enc_result = EVP_EncryptInit_ex(ctx, cipher, NULL, kek->raw.ptr, NULL); - if (!enc_result) + // wrapped key always 8 bytes greater than CEK @cite rfc3394 (2.2.1) + res = BSL_Data_Resize(wrapped_key, cek_view.len + 8); + if (BSL_SUCCESS != res) { - EVP_CIPHER_CTX_free(ctx); - return -1; + retval = res; } - pthread_mutex_lock(&kek->stats_mutex); - kek->stats.stats[BSL_CRYPTO_KEYSTATS_TIMES_USED]++; - kek->stats.stats[BSL_CRYPTO_KEYSTATS_BYTES_PROCESSED] += cek->raw.len; - pthread_mutex_unlock(&kek->stats_mutex); - - // wrapped key always 8 bytes greater than CEK @cite rfc3394 (2.2.1) - BSL_Data_Resize(wrapped_key, cek->raw.len + 8); - - int out_len = (int)wrapped_key->len; - BSL_LOG_PLAINTEXT_PTR("unwrapped key", cek_handle, cek->raw.ptr, cek->raw.len); - if (!EVP_EncryptUpdate(ctx, (unsigned char *)wrapped_key->ptr, &out_len, cek->raw.ptr, cek->raw.len)) + if (BSL_SUCCESS == retval) { - EVP_CIPHER_CTX_free(ctx); - return -2; + BSL_LOG_PLAINTEXT_PTR("using KEK", cek_handle, kek_view.ptr, kek_view.len); + // GCOV_EXCL_START + res = EVP_EncryptInit_ex(ctx, cipher, NULL, kek_view.ptr, NULL); + if (res != 1) + { + retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + } + // GCOV_EXCL_STOP } - wrapped_key->len = (size_t)out_len; - uint8_t buf[EVP_CIPHER_CTX_block_size(ctx)]; - int final_len = 0; - if (!EVP_EncryptFinal_ex(ctx, buf, &final_len)) + BSL_KeyStore_State.update_stats(kek_handle, 1, cek_view.len); + + int out_len; + if (BSL_SUCCESS == retval) { - EVP_CIPHER_CTX_free(ctx); - return -1; + out_len = (int)wrapped_key->len; + BSL_LOG_PLAINTEXT_PTR("unwrapped key", cek_handle, cek_view.ptr, cek_view.len); + res = EVP_EncryptUpdate(ctx, (unsigned char *)wrapped_key->ptr, &out_len, cek_view.ptr, (int)cek_view.len); + if (res != 1) + { + retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + } + wrapped_key->len = (size_t)out_len; } - if (final_len > 0) + if (BSL_SUCCESS == retval) { - BSL_Data_AppendFrom(&cek->raw, final_len, buf); + out_len = 0; + res = EVP_EncryptFinal_ex(ctx, NULL, &out_len); + // GCOV_EXCL_START + if (res != 1) + { + retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + } + else if (out_len > 0) + { + BSL_LOG_ERR("Key wrap without padding should not have any final data"); + retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + } + // GCOV_EXCL_STOP + BSL_LOG_PLAINTEXT_PTR("wrapped key", cek_handle, wrapped_key->ptr, wrapped_key->len); } EVP_CIPHER_CTX_free(ctx); - BSL_LOG_PLAINTEXT_PTR("wrapped key", cek_handle, wrapped_key->ptr, wrapped_key->len); - return 0; + return retval; } // work-around allowance for empty salt and info @@ -346,10 +284,11 @@ static const uint8_t BSL_Crypto_zero = 0; int BSL_Crypto_KDF(BSL_Crypto_KeyHandle_t kdk_handle, BSL_Crypto_KDFVariant_t func, const BSL_Data_t *salt, const BSL_Data_t *info, size_t keylen, BSL_Crypto_KeyHandle_t *cek_handle) { + CHK_ARG_NONNULL(cek_handle); + *cek_handle = NULL; CHK_ARG_NONNULL(kdk_handle); CHK_ARG_NONNULL(salt); CHK_ARG_NONNULL(info); - CHK_ARG_NONNULL(cek_handle); CHK_PRECONDITION(keylen > 0); char *digest_name; @@ -366,38 +305,42 @@ int BSL_Crypto_KDF(BSL_Crypto_KeyHandle_t kdk_handle, BSL_Crypto_KDFVariant_t fu return BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; } - BSL_CryptoKey_t *kdk = BSL_CryptoKeyPtr_ref(kdk_handle); - CHK_PRECONDITION(kdk->raw.len > 0); + int retval = BSL_SUCCESS; + int res; - BSL_CryptoKeyPtr_t *cek_ptr = BSL_CryptoKeyPtr_new(); - // managed struct - BSL_CryptoKey_t *cek = BSL_CryptoKeyPtr_ref(cek_ptr); - CHK_PROPERTY(cek != NULL); + BSL_Data_t kdk_view; + CHK_PRECONDITION(BSL_SUCCESS == BSL_KeyStore_State.get_keymat(kdk_handle, &kdk_view)); - if (BSL_SUCCESS != BSL_Data_Resize(&cek->raw, keylen)) + BSL_Data_t cek_keymat; + if (BSL_SUCCESS != BSL_Data_InitBuffer(&cek_keymat, keylen)) { - BSL_CryptoKeyPtr_release(cek_ptr); - return BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; } - int retval = BSL_SUCCESS; - - EVP_KDF *kdf = EVP_KDF_fetch(NULL, "HKDF", NULL); - if (!kdf) + EVP_KDF *kdf = NULL; + if (BSL_SUCCESS == retval) { - BSL_LOG_ERR("EVP_KDF_fetch: %s", ERR_error_string(ERR_get_error(), NULL)); - retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + kdf = EVP_KDF_fetch(NULL, "HKDF", NULL); + // GCOV_EXCL_START + if (!kdf) + { + BSL_LOG_ERR("EVP_KDF_fetch: %s", ERR_error_string(ERR_get_error(), NULL)); + retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + } + // GCOV_EXCL_STOP } EVP_KDF_CTX *kctx = NULL; if (BSL_SUCCESS == retval) { kctx = EVP_KDF_CTX_new(kdf); + // GCOV_EXCL_START if (!kctx) { BSL_LOG_ERR("EVP_KDF_CTX_new: %s", ERR_error_string(ERR_get_error(), NULL)); retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; } + // GCOV_EXCL_STOP } if (kdf) { @@ -410,27 +353,26 @@ int BSL_Crypto_KDF(BSL_Crypto_KeyHandle_t kdk_handle, BSL_Crypto_KDFVariant_t fu OSSL_PARAM *par = params; *par++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, digest_name, strlen(digest_name)); - BSL_LOG_PLAINTEXT_PTR("using key", kctx, kdk->raw.ptr, kdk->raw.len); - *par++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, kdk->raw.ptr, kdk->raw.len); + BSL_LOG_PLAINTEXT_PTR("using key", kctx, kdk_view.ptr, kdk_view.len); + *par++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, kdk_view.ptr, kdk_view.len); BSL_LOG_PLAINTEXT_PTR("using salt", kctx, salt->ptr, salt->len); *par++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, BSL_Crypto_PtrOrZero(salt->ptr), salt->len); BSL_LOG_PLAINTEXT_PTR("using info", kctx, info->ptr, info->len); *par++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, BSL_Crypto_PtrOrZero(info->ptr), info->len); *par = OSSL_PARAM_construct_end(); - pthread_mutex_lock(&kdk->stats_mutex); - kdk->stats.stats[BSL_CRYPTO_KEYSTATS_TIMES_USED]++; - kdk->stats.stats[BSL_CRYPTO_KEYSTATS_BYTES_PROCESSED] += cek->raw.len; - pthread_mutex_unlock(&kdk->stats_mutex); + BSL_KeyStore_State.update_stats(kdk_handle, 1, cek_keymat.len); - int res = EVP_KDF_derive(kctx, cek->raw.ptr, cek->raw.len, params); - BSL_LOG_DEBUG("EVP_KDF_derive gave %zu bytes, return %d", cek->raw.len, res); - BSL_LOG_PLAINTEXT_PTR("KDF out", kctx, cek->raw.ptr, cek->raw.len); + res = EVP_KDF_derive(kctx, cek_keymat.ptr, cek_keymat.len, params); + BSL_LOG_DEBUG("EVP_KDF_derive gave %zu bytes, return %d", cek_keymat.len, res); + BSL_LOG_PLAINTEXT_PTR("KDF out", kctx, cek_keymat.ptr, cek_keymat.len); + // GCOV_EXCL_START if (res <= 0) { BSL_LOG_ERR("EVP_KDF_derive: %s", ERR_error_string(ERR_get_error(), NULL)); retval = BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; } + // GCOV_EXCL_STOP } if (kctx) { @@ -439,13 +381,10 @@ int BSL_Crypto_KDF(BSL_Crypto_KeyHandle_t kdk_handle, BSL_Crypto_KDFVariant_t fu if (BSL_SUCCESS == retval) { - *cek_handle = cek_ptr; - } - else - { - *cek_handle = NULL; - BSL_CryptoKeyPtr_release(cek_ptr); + retval = BSL_Crypto_LoadKey(cek_keymat.ptr, cek_keymat.len, cek_handle); } + + BSL_Data_Deinit(&cek_keymat); return retval; } @@ -471,10 +410,11 @@ int BSL_AuthCtx_Init(BSL_AuthCtx_t *hmac_ctx, BSL_Crypto_KeyHandle_t keyhandle, return BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; } - hmac_ctx->keyhandle = BSL_CryptoKeyPtr_acquire(keyhandle); + hmac_ctx->keyhandle = BSL_KeyStore_State.acquire_key(keyhandle); + CHK_PRECONDITION(hmac_ctx->keyhandle); - BSL_CryptoKey_t *key_info = BSL_CryptoKeyPtr_ref(hmac_ctx->keyhandle); - CHK_PRECONDITION(key_info->raw.len > 0); + BSL_Data_t key_view; + CHK_PRECONDITION(BSL_SUCCESS == BSL_KeyStore_State.get_keymat(hmac_ctx->keyhandle, &key_view)); EVP_MAC *mac = EVP_MAC_fetch(NULL, "HMAC", NULL); CHK_PRECONDITION(mac != NULL); @@ -486,27 +426,29 @@ int BSL_AuthCtx_Init(BSL_AuthCtx_t *hmac_ctx, BSL_Crypto_KeyHandle_t keyhandle, OSSL_PARAM params[2]; { OSSL_PARAM *par = params; - *par++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, digest_name, strlen(digest_name)); - *par++ = OSSL_PARAM_construct_end(); + + *par++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, digest_name, strlen(digest_name)); + *par++ = OSSL_PARAM_construct_end(); } - BSL_LOG_PLAINTEXT_PTR("using key", hmac_ctx, key_info->raw.ptr, key_info->raw.len); - int res = EVP_MAC_init(hmac_ctx->libhandle, key_info->raw.ptr, key_info->raw.len, params); + BSL_LOG_PLAINTEXT_PTR("using key", hmac_ctx, key_view.ptr, key_view.len); + int res = EVP_MAC_init(hmac_ctx->libhandle, key_view.ptr, key_view.len, params); CHK_PROPERTY(res == 1); hmac_ctx->block_size = EVP_MAC_CTX_get_block_size(hmac_ctx->libhandle); + BSL_LOG_DEBUG("MAC block size %zu", hmac_ctx->block_size); + // GCOV_EXCL_START if (hmac_ctx->block_size == 0) { hmac_ctx->block_size = 1024; BSL_LOG_ERR("invalid block size zero, assuming %zu", hmac_ctx->block_size); } + // GCOV_EXCL_STOP res = BSL_Data_InitBuffer(&hmac_ctx->in_buf, hmac_ctx->block_size); CHK_PROPERTY(!res); - pthread_mutex_lock(&key_info->stats_mutex); - key_info->stats.stats[BSL_CRYPTO_KEYSTATS_TIMES_USED]++; - pthread_mutex_unlock(&key_info->stats_mutex); + BSL_KeyStore_State.update_stats(keyhandle, 1, 0); return 0; } @@ -523,10 +465,7 @@ int BSL_AuthCtx_DigestBuffer(BSL_AuthCtx_t *hmac_ctx, const void *data, size_t d BSL_LOG_DEBUG("EVP_MAC_update took %zu bytes, return %d", data_len, res); CHK_PROPERTY(res == 1); - BSL_CryptoKey_t *key_info = BSL_CryptoKeyPtr_ref(hmac_ctx->keyhandle); - pthread_mutex_lock(&key_info->stats_mutex); - key_info->stats.stats[BSL_CRYPTO_KEYSTATS_BYTES_PROCESSED] += data_len; - pthread_mutex_unlock(&key_info->stats_mutex); + BSL_KeyStore_State.update_stats(hmac_ctx->keyhandle, 0, data_len); return 0; } @@ -536,8 +475,6 @@ int BSL_AuthCtx_DigestSeq(BSL_AuthCtx_t *hmac_ctx, BSL_SeqReader_t *reader) ASSERT_ARG_NONNULL(hmac_ctx); ASSERT_ARG_NONNULL(reader); - BSL_CryptoKey_t *key_info = BSL_CryptoKeyPtr_ref(hmac_ctx->keyhandle); - while (true) { // read until there is no more @@ -553,9 +490,7 @@ int BSL_AuthCtx_DigestSeq(BSL_AuthCtx_t *hmac_ctx, BSL_SeqReader_t *reader) BSL_LOG_DEBUG("EVP_MAC_update took %zu bytes, return %d", block_size, res); CHK_PROPERTY(res == 1); - pthread_mutex_lock(&key_info->stats_mutex); - key_info->stats.stats[BSL_CRYPTO_KEYSTATS_BYTES_PROCESSED] += block_size; - pthread_mutex_unlock(&key_info->stats_mutex); + BSL_KeyStore_State.update_stats(hmac_ctx->keyhandle, 0, block_size); } return 0; @@ -586,7 +521,8 @@ void BSL_AuthCtx_Deinit(BSL_AuthCtx_t *hmac_ctx) BSL_Data_Deinit(&hmac_ctx->in_buf); EVP_MAC_CTX_free(hmac_ctx->libhandle); - BSL_CryptoKeyPtr_release(hmac_ctx->keyhandle); + BSL_KeyStore_State.release_key(hmac_ctx->keyhandle); + memset(hmac_ctx, 0, sizeof(BSL_AuthCtx_t)); } @@ -610,9 +546,11 @@ int BSL_Cipher_Init(BSL_Cipher_t *cipher_ctx, BSL_CipherMode_e enc, BSL_Crypto_A memset(cipher_ctx, 0, sizeof(*cipher_ctx)); - cipher_ctx->keyhandle = BSL_CryptoKeyPtr_acquire(keyhandle); + cipher_ctx->keyhandle = BSL_KeyStore_State.acquire_key(keyhandle); + CHK_PRECONDITION(cipher_ctx->keyhandle); - BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(cipher_ctx->keyhandle); + BSL_Data_t key_view; + CHK_PRECONDITION(BSL_SUCCESS == BSL_KeyStore_State.get_keymat(cipher_ctx->keyhandle, &key_view)); cipher_ctx->libhandle = EVP_CIPHER_CTX_new(); cipher_ctx->enc = enc; @@ -633,23 +571,37 @@ int BSL_Cipher_Init(BSL_Cipher_t *cipher_ctx, BSL_CipherMode_e enc, BSL_Crypto_A return BSL_ERR_FAILURE; } - int res = - EVP_CipherInit_ex(cipher_ctx->libhandle, cipher, NULL, NULL, NULL, (cipher_ctx->enc == BSL_CRYPTO_ENCRYPT)); + const int do_encrypt = (cipher_ctx->enc == BSL_CRYPTO_ENCRYPT); + + int res = EVP_CipherInit_ex(cipher_ctx->libhandle, cipher, NULL, NULL, NULL, do_encrypt); CHK_PROPERTY(res == 1); - cipher_ctx->block_size = (size_t)EVP_CIPHER_get_block_size(cipher_ctx->libhandle); + { + const size_t need_len = (size_t)EVP_CIPHER_CTX_get_key_length(cipher_ctx->libhandle); + CHK_PROPERTY(key_view.len == need_len); + } + + cipher_ctx->block_size = (size_t)EVP_CIPHER_CTX_get_block_size(cipher_ctx->libhandle); + if (cipher_ctx->block_size == 1) + { + // Choose a reasonable chunk size + cipher_ctx->block_size = 1024; + } + BSL_LOG_DEBUG("Cipher block size %zu", cipher_ctx->block_size); + // GCOV_EXCL_START if (cipher_ctx->block_size == 0) { cipher_ctx->block_size = 1024; BSL_LOG_ERR("invalid block size zero, assuming %zu", cipher_ctx->block_size); } + // GCOV_EXCL_STOP res = EVP_CIPHER_CTX_ctrl(cipher_ctx->libhandle, EVP_CTRL_GCM_SET_IVLEN, (int)iv_val->len, NULL); CHK_PROPERTY(res == 1); - BSL_LOG_PLAINTEXT_PTR("using key", cipher_ctx, key->raw.ptr, key->raw.len); + BSL_LOG_PLAINTEXT_PTR("using key", cipher_ctx, key_view.ptr, key_view.len); BSL_LOG_PLAINTEXT_PTR("using IV", cipher_ctx, iv_val->ptr, iv_val->len); - res = EVP_CipherInit_ex(cipher_ctx->libhandle, NULL, NULL, key->raw.ptr, iv_val->ptr, -1); + res = EVP_CipherInit_ex(cipher_ctx->libhandle, NULL, NULL, key_view.ptr, iv_val->ptr, -1); CHK_PROPERTY(res == 1); res = BSL_Data_InitBuffer(&cipher_ctx->in_buf, cipher_ctx->block_size); @@ -658,9 +610,7 @@ int BSL_Cipher_Init(BSL_Cipher_t *cipher_ctx, BSL_CipherMode_e enc, BSL_Crypto_A res = BSL_Data_InitBuffer(&cipher_ctx->out_buf, cipher_ctx->block_size); CHK_PROPERTY(!res); - pthread_mutex_lock(&key->stats_mutex); - key->stats.stats[BSL_CRYPTO_KEYSTATS_TIMES_USED]++; - pthread_mutex_unlock(&key->stats_mutex); + BSL_KeyStore_State.update_stats(cipher_ctx->keyhandle, 1, 0); return 0; } @@ -679,10 +629,7 @@ int BSL_Cipher_AddAadBuffer(BSL_Cipher_t *cipher_ctx, const void *aad, size_t aa BSL_LOG_DEBUG("EVP_CipherUpdate took %zu bytes, return %d", aad_len, res); CHK_PROPERTY(res == 1); - BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(cipher_ctx->keyhandle); - pthread_mutex_lock(&key->stats_mutex); - key->stats.stats[BSL_CRYPTO_KEYSTATS_BYTES_PROCESSED] += aad_len; - pthread_mutex_unlock(&key->stats_mutex); + BSL_KeyStore_State.update_stats(cipher_ctx->keyhandle, 0, aad_len); return 0; } @@ -692,8 +639,6 @@ int BSL_Cipher_AddAadSeq(BSL_Cipher_t *cipher_ctx, BSL_SeqReader_t *reader) ASSERT_ARG_NONNULL(cipher_ctx); ASSERT_ARG_NONNULL(reader); - BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(cipher_ctx->keyhandle); - while (true) { // read until there is no more @@ -711,9 +656,7 @@ int BSL_Cipher_AddAadSeq(BSL_Cipher_t *cipher_ctx, BSL_SeqReader_t *reader) EVP_CipherUpdate(cipher_ctx->libhandle, NULL, &block_size_int, cipher_ctx->in_buf.ptr, block_size_int); CHK_PROPERTY(res == 1); - pthread_mutex_lock(&key->stats_mutex); - key->stats.stats[BSL_CRYPTO_KEYSTATS_BYTES_PROCESSED] += block_size_int; - pthread_mutex_unlock(&key->stats_mutex); + BSL_KeyStore_State.update_stats(cipher_ctx->keyhandle, 0, block_size_int); } return 0; @@ -723,9 +666,6 @@ int BSL_Cipher_AddSeq(BSL_Cipher_t *cipher_ctx, BSL_SeqReader_t *reader, BSL_Seq { ASSERT_ARG_NONNULL(cipher_ctx); ASSERT_ARG_NONNULL(reader); - BSL_LOG_DEBUG("block size %zu bytes", cipher_ctx->block_size); - - BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(cipher_ctx->keyhandle); while (limit) { @@ -747,9 +687,7 @@ int BSL_Cipher_AddSeq(BSL_Cipher_t *cipher_ctx, BSL_SeqReader_t *reader, BSL_Seq BSL_LOG_PLAINTEXT_PTR("cipher out", cipher_ctx, cipher_ctx->out_buf.ptr, block_size_int); CHK_PROPERTY(res == 1); - pthread_mutex_lock(&key->stats_mutex); - key->stats.stats[BSL_CRYPTO_KEYSTATS_BYTES_PROCESSED] += block_size_int; - pthread_mutex_unlock(&key->stats_mutex); + BSL_KeyStore_State.update_stats(cipher_ctx->keyhandle, 0, block_size_int); if ((block_size_int > 0) && writer) { @@ -807,11 +745,13 @@ int BSL_Cipher_FinalizeSeq(BSL_Cipher_t *cipher_ctx, BSL_SeqWriter_t *writer) int res = EVP_CipherFinal_ex(cipher_ctx->libhandle, cipher_ctx->out_buf.ptr, &block_size_int); BSL_LOG_DEBUG("EVP_CipherFinal_ex gave %d bytes, return %d", block_size_int, res); + // GCOV_EXCL_START if (res != 1) { BSL_LOG_ERR("EVP_CipherFinal_ex error %s", ERR_error_string(ERR_get_error(), NULL)); return BSL_ERR_FAILURE; } + // GCOV_EXCL_STOP if ((block_size_int > 0) && writer) { @@ -822,189 +762,24 @@ int BSL_Cipher_FinalizeSeq(BSL_Cipher_t *cipher_ctx, BSL_SeqWriter_t *writer) return BSL_SUCCESS; } -int BSL_Cipher_Deinit(BSL_Cipher_t *cipher_ctx) +void BSL_Cipher_Deinit(BSL_Cipher_t *cipher_ctx) { - CHK_ARG_NONNULL(cipher_ctx); + ASSERT_ARG_NONNULL(cipher_ctx); + BSL_Data_Deinit(&cipher_ctx->out_buf); BSL_Data_Deinit(&cipher_ctx->in_buf); EVP_CIPHER_CTX_free(cipher_ctx->libhandle); - BSL_CryptoKeyPtr_release(cipher_ctx->keyhandle); - memset(cipher_ctx, 0, sizeof(*cipher_ctx)); - return BSL_SUCCESS; -} - -int BSL_Crypto_GenKey(size_t key_length, BSL_Crypto_KeyHandle_t *key_out) -{ - CHK_ARG_NONNULL(key_out); - *key_out = NULL; - CHK_ARG_EXPR(key_length > 0); - - BSL_CryptoKeyPtr_t *key_ptr = BSL_CryptoKeyPtr_new(); - // managed struct - BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(key_ptr); - CHK_PROPERTY(key != NULL); - - BSL_Data_Resize(&key->raw, key_length); - if (rand_bytes_generator(key->raw.ptr, (int)key->raw.len) != 1) - { - BSL_CryptoKeyPtr_release(key_ptr); - return BSL_ERR_FAILURE; - } + BSL_KeyStore_State.release_key(cipher_ctx->keyhandle); - *key_out = key_ptr; - return BSL_SUCCESS; -} - -int BSL_Crypto_LoadKey(const uint8_t *secret, size_t secret_len, BSL_Crypto_KeyHandle_t *key_out) -{ - CHK_ARG_NONNULL(key_out); - *key_out = NULL; - CHK_ARG_EXPR(secret_len > 0); - - BSL_CryptoKeyPtr_t *key_ptr = BSL_CryptoKeyPtr_new(); - // managed struct - BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(key_ptr); - CHK_PROPERTY(key != NULL); - - int ecode = 0; - if ((ecode = BSL_Data_CopyFrom(&key->raw, secret_len, secret)) != 0) - { - BSL_LOG_ERR("Failed to copy key"); - BSL_CryptoKeyPtr_release(key_ptr); - return ecode; - } - - *key_out = key_ptr; - return BSL_SUCCESS; + memset(cipher_ctx, 0, sizeof(*cipher_ctx)); } int BSL_Crypto_GenIV(BSL_Data_t *buf) { + ASSERT_PRECONDITION(rand_bytes_generator); CHK_ARG_NONNULL(buf); memset(buf->ptr, 0, buf->len); CHK_PROPERTY(rand_bytes_generator((unsigned char *)(buf->ptr), buf->len) == 1); return BSL_SUCCESS; } - -int BSL_Crypto_AddRegistryKey(const BSL_Data_t *keyid, BSL_Crypto_KeyHandle_t handle) -{ - ASSERT_ARG_NONNULL(keyid); - CHK_ARG_NONNULL(handle); - - BSL_CryptoKeyPtr_t *key_ptr = handle; - - m_bstring_t keyid_str; - m_bstring_init(keyid_str); - m_bstring_push_back_bytes(keyid_str, keyid->len, keyid->ptr); - - pthread_mutex_lock(&StaticCryptoMutex); - BSL_CryptoKeyDict_set_at(StaticKeyRegistry, keyid_str, key_ptr); - pthread_mutex_unlock(&StaticCryptoMutex); - - m_bstring_clear(keyid_str); - return 0; -} - -BSL_IdValPair_t *BSL_Crypto_SetKeyParameter(BSL_Crypto_KeyHandle_t handle, int64_t param_id) -{ - ASSERT_ARG_NONNULL(handle); - BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(handle); - - BSL_IdValPair_t *retval = NULL; - if (key) - { - BSLB_IdValPairPtr_t *param_ptr; - - BSLB_IdValPairPtr_t **found = BSLB_IdValPairPtrMap_get(key->params, param_id); - if (found) - { - param_ptr = *found; - retval = BSLB_IdValPairPtr_ref(param_ptr); - } - else - { - param_ptr = BSLB_IdValPairPtr_new(); - BSLB_IdValPairPtrMap_set_at(key->params, param_id, param_ptr); - retval = BSLB_IdValPairPtr_ref(param_ptr); - // map keeps a reference so this is safe - BSLB_IdValPairPtr_release(param_ptr); - } - } - return retval; -} - -const BSL_IdValPair_t *BSL_Crypto_GetKeyParameter(BSL_Crypto_KeyHandle_t handle, int64_t param_id) -{ - ASSERT_ARG_NONNULL(handle); - BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(handle); - - const BSL_IdValPair_t *retval = NULL; - if (key) - { - BSLB_IdValPairPtr_t **found = BSLB_IdValPairPtrMap_get(key->params, param_id); - if (found) - { - retval = BSLB_IdValPairPtr_ref(*found); - } - } - return retval; -} - -int BSL_Crypto_GetRegistryKey(const BSL_Data_t *keyid, BSL_Crypto_KeyHandle_t *key_handle) -{ - ASSERT_ARG_NONNULL(keyid); - CHK_ARG_NONNULL(key_handle); - - m_bstring_t keyid_str; - m_bstring_init(keyid_str); - m_bstring_push_back_bytes(keyid_str, keyid->len, keyid->ptr); - - int retval = BSL_SUCCESS; - pthread_mutex_lock(&StaticCryptoMutex); - BSL_CryptoKeyPtr_t **found = BSL_CryptoKeyDict_get(StaticKeyRegistry, keyid_str); - if (!found) - { - *key_handle = NULL; - retval = BSL_ERR_NOT_FOUND; - } - else - { - *key_handle = BSL_CryptoKeyPtr_acquire(*found); - } - pthread_mutex_unlock(&StaticCryptoMutex); - - m_bstring_clear(keyid_str); - return retval; -} - -int BSL_Crypto_RemoveRegistryKey(const BSL_Data_t *keyid) -{ - ASSERT_ARG_NONNULL(keyid); - - m_bstring_t keyid_str; - m_bstring_init(keyid_str); - m_bstring_push_back_bytes(keyid_str, keyid->len, keyid->ptr); - - pthread_mutex_lock(&StaticCryptoMutex); - int res = BSL_CryptoKeyDict_erase(StaticKeyRegistry, keyid_str); - pthread_mutex_unlock(&StaticCryptoMutex); - - m_bstring_clear(keyid_str); - return res ? BSL_SUCCESS : -1; -} - -int BSL_Crypto_GetKeyStatistics(BSL_Crypto_KeyHandle_t handle, BSL_Crypto_KeyStats_t *stats) -{ - ASSERT_ARG_NONNULL(handle); - CHK_ARG_NONNULL(stats); - - BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(handle); - - pthread_mutex_lock(&key->stats_mutex); - // copy as POD - *stats = key->stats; - pthread_mutex_unlock(&key->stats_mutex); - - return BSL_SUCCESS; -} diff --git a/src/bsl/crypto/CryptoInterface.h b/src/bsl/crypto/CryptoInterface.h index 510ebb14..3001f947 100644 --- a/src/bsl/crypto/CryptoInterface.h +++ b/src/bsl/crypto/CryptoInterface.h @@ -20,13 +20,15 @@ * subcontract 1700763. */ /** @file - * @ingroup frontend + * @ingroup crypto * Abstract interface for crypto processing. * This file is organized into groups based on topic: key registry, HMAC, cipher, etc. */ #ifndef BSL_FRONTEND_CRYPTO_INTERFACE_H_ #define BSL_FRONTEND_CRYPTO_INTERFACE_H_ +#include "KeyStore.h" + #include "bsl/BPSecLib_Private.h" // TODO replace with Variant.h #include "bsl/BSLConfig.h" #include "bsl/front/Data.h" @@ -39,16 +41,6 @@ extern "C" { #endif -/** Initialize the crypto subsystem. - * This must be called once per process. - */ -void BSL_CryptoInit(void); - -/** Deinitialize the crypto subsystem. - * This should be called at the end of the process. - */ -void BSL_CryptoDeinit(void); - /** * Function pointer def for random bytestring generator * @param buf buffer to fill with random bytes @@ -87,121 +79,6 @@ bool BSL_Crypto_Compare(const void *data1, size_t size1, const void *data2, size */ typedef void *BSL_Crypto_LibHandle_t; -/** @name Key registry interface - * - * There are two forms of managed crypto keys in this interface: - * 1. Identified keys persisted in a long-term, thread-safe registry. - * These keys have byte string names (which can contain UTF8 text) and can - * have additional parameters to restrict their use. - * 2. Anonymous ephemeral keys used for individual operations and then discarded. - * These keys do not have names and are typically key-wrapped or the result of a - * key derivation function (KDF). - */ -///@{ - -typedef enum -{ - BSL_CRYPTO_KEYSTATS_TIMES_USED = 0, - BSL_CRYPTO_KEYSTATS_BYTES_PROCESSED, - /// Not a real index, used to size arrays - BSL_CRYPTO_KEYSTATS_MAX_INDEX -} BSL_Crypto_KeyStatCounterIndex_t; - -/** - * Structure containing statistics for individual keys - */ -typedef struct BSL_Crypto_KeyStats_s -{ - /// Counters for each ::BSL_Crypto_KeyStatCounterIndex_t value - uint64_t stats[BSL_CRYPTO_KEYSTATS_MAX_INDEX]; -} BSL_Crypto_KeyStats_t; - -/** Opaque handle for key objects in the key store. - */ -typedef struct BSL_CryptoKeyPtr_s *BSL_Crypto_KeyHandle_t; - -/** - * Generate a new cryptographic key. - * @param[in] key_length length of new key in bytes. - * @param[out] key_out pointer to pointer for new key handle. - * The handle must be released with BSL_Crypto_ReleaseKeyHandle() when it is done being used. - */ -int BSL_Crypto_GenKey(size_t key_length, BSL_Crypto_KeyHandle_t *key_out); - -/** - * Load a new cryptographic key. - * @param[in] secret raw symmetric key. - * @param secret_len length of @c secret data. - * @param[out] key_out pointer to pointer for new key handle. - * The handle must be released with BSL_Crypto_ReleaseKeyHandle() when it is done being used. - */ -int BSL_Crypto_LoadKey(const uint8_t *secret, size_t secret_len, BSL_Crypto_KeyHandle_t *key_out); - -/** Release a key handle after it is done being used. - * - * @param[in] keyhandle key handle to release. - * If the handle is null this does nothing. - * @post If this is the last use of the handle (including the key registry) the key will be destroyed. - */ -void BSL_Crypto_ReleaseKeyHandle(BSL_Crypto_KeyHandle_t keyhandle); - -/** Compare two keys in a time-invariant way. - * This avoids side channel attacks which depend on comparison time. - * - * @param[in] hdl1 The first key handle. - * @param[in] hdl2 The second key handle. - * @return True if they compare equal. - */ -bool BSL_Crypto_CompareKeys(BSL_Crypto_KeyHandle_t hdl1, BSL_Crypto_KeyHandle_t hdl2); - -/** Get pointers to an existing key, if present. - * - * @param keyid The key to search for. - * @param[in, out] key_handle pointer to pointer for new key handle. - * The handle must be released with BSL_Crypto_ReleaseKeyHandle() when it is done being used. - * @return Zero if the key was present. - */ -int BSL_Crypto_GetRegistryKey(const BSL_Data_t *keyid, BSL_Crypto_KeyHandle_t *key_handle); - -/** Erase key entry from crypto library registry, if present. - * @param[in] keyid key ID of key to remove. - * @return Zero if the key was present. - */ -int BSL_Crypto_RemoveRegistryKey(const BSL_Data_t *keyid); - -/** - * Add a new key to the crypto key registry - * @param[in] keyid key ID that crypto functions will use to access key - * @param[out] handle Key handle to add to the registry. - * Once the key is added it should be treated as read-only for thread-safety purposes. - * When handle is output, the handle must be released with BSL_Crypto_ReleaseKeyHandle() when it is done being used. - * @return Zero upon success. - */ -int BSL_Crypto_AddRegistryKey(const BSL_Data_t *keyid, BSL_Crypto_KeyHandle_t handle); - -/** Add a context-specific parameter to a known key. - * - * @param[in] handle The key ID to update. - * @param[in] param_id The parameter to access. - * If the parameter does not already exist it will be created. - * @return Non-NULL pointer if successful. - */ -BSL_IdValPair_t *BSL_Crypto_SetKeyParameter(BSL_Crypto_KeyHandle_t handle, int64_t param_id); - -/** Get key parameter for read-only access. - * @overload - */ -const BSL_IdValPair_t *BSL_Crypto_GetKeyParameter(BSL_Crypto_KeyHandle_t handle, int64_t param_id); - -/** - * Retrieve statistics related to a crypto key - * @param[in] handle The handle of a key in the crypto registry to retrieve the stats of. - * @param[out] stats struct containing statistics related to the key id - */ -int BSL_Crypto_GetKeyStatistics(BSL_Crypto_KeyHandle_t handle, BSL_Crypto_KeyStats_t *stats); - -///@} key registry - /** @name AES Key Wrap interface */ ///@{ @@ -394,9 +271,8 @@ int BSL_Cipher_FinalizeSeq(BSL_Cipher_t *cipher_ctx, BSL_SeqWriter_t *writer); /** * De-initialize crypto context resources * @param cipher_ctx pointer to context to deinitialize - * @return 0 if successful */ -int BSL_Cipher_Deinit(BSL_Cipher_t *cipher_ctx); +void BSL_Cipher_Deinit(BSL_Cipher_t *cipher_ctx); ///@} cipher diff --git a/src/bsl/crypto/KeyStore.c b/src/bsl/crypto/KeyStore.c new file mode 100644 index 00000000..00b790b4 --- /dev/null +++ b/src/bsl/crypto/KeyStore.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2025-2026 The Johns Hopkins University Applied Physics + * Laboratory LLC. + * + * This file is part of the Bundle Protocol Security Library (BSL). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + * + * This work was performed for the Jet Propulsion Laboratory, California + * Institute of Technology, sponsored by the United States Government under + * the prime contract 80NM0018D0004 between the Caltech and NASA under + * subcontract 1700763. + */ + +/** @file + * @ingroup crypto + * Backend implementation of the crypto API using ::BSL_KeyStore_Descriptors_t callbacks. + */ +#include "KeyStore.h" + +#include "CryptoInterface.h" + +#include +#include + +#define BSL_KeyStore_Descriptors_EMPTY \ + { \ + .new_key = NULL \ + } + +/// Initialized to library default +BSL_KeyStore_Descriptors_t BSL_KeyStore_State = BSL_KeyStore_Descriptors_EMPTY; + +int BSL_KeyStore_Init(BSL_KeyStore_Descriptors_t desc) +{ + // GCOV_EXCL_START + CHK_PRECONDITION(desc.new_key); + CHK_PRECONDITION(desc.acquire_key); + CHK_PRECONDITION(desc.release_key); + CHK_PRECONDITION(desc.find_key); + CHK_PRECONDITION(desc.set_keymat); + CHK_PRECONDITION(desc.get_keymat); + CHK_PRECONDITION(desc.get_parameter); + CHK_PRECONDITION(desc.update_stats); + CHK_PRECONDITION(desc.get_stats); + // GCOV_EXCL_STOP + + BSL_KeyStore_State = desc; + return BSL_SUCCESS; +} + +void BSL_KeyStore_Deinit(void) +{ + BSL_KeyStore_State = (BSL_KeyStore_Descriptors_t)BSL_KeyStore_Descriptors_EMPTY; +} + +void BSL_Crypto_ReleaseKeyHandle(BSL_Crypto_KeyHandle_t keyhandle) +{ + ASSERT_PRECONDITION(BSL_KeyStore_State.release_key); + BSL_KeyStore_State.release_key(keyhandle); +} + +bool BSL_Crypto_CompareKeys(BSL_Crypto_KeyHandle_t hdl1, BSL_Crypto_KeyHandle_t hdl2) +{ + ASSERT_PRECONDITION(BSL_KeyStore_State.get_keymat); + if (!hdl1 || !hdl2) + { + return false; + } + + BSL_Data_t key1_view; + CHK_PRECONDITION(BSL_SUCCESS == BSL_KeyStore_State.get_keymat(hdl1, &key1_view)); + BSL_Data_t key2_view; + CHK_PRECONDITION(BSL_SUCCESS == BSL_KeyStore_State.get_keymat(hdl2, &key2_view)); + + return BSL_Crypto_Compare(key1_view.ptr, key1_view.len, key2_view.ptr, key2_view.len); +} + +int BSL_Crypto_GenKey(size_t key_length, BSL_Crypto_KeyHandle_t *key_out) +{ + CHK_ARG_NONNULL(key_out); + *key_out = NULL; + CHK_ARG_EXPR(key_length > 0); + int retval = BSL_SUCCESS; + + BSL_Data_t keymat; + BSL_Data_InitBuffer(&keymat, key_length); + if (BSL_SUCCESS != BSL_Crypto_GenIV(&keymat)) // FIXME rename for clarity + { + BSL_Data_Deinit(&keymat); + return BSL_ERR_FAILURE; + } + + retval = BSL_Crypto_LoadKey(keymat.ptr, keymat.len, key_out); + BSL_Data_Deinit(&keymat); + return retval; +} + +int BSL_Crypto_LoadKey(const uint8_t *secret, size_t secret_len, BSL_Crypto_KeyHandle_t *key_out) +{ + ASSERT_PRECONDITION(BSL_KeyStore_State.new_key); + ASSERT_PRECONDITION(BSL_KeyStore_State.set_keymat); + CHK_ARG_NONNULL(key_out); + *key_out = NULL; + CHK_ARG_EXPR(secret_len > 0); + + int res = BSL_KeyStore_State.new_key(key_out); + if (BSL_SUCCESS != res) + { + BSL_LOG_ERR("Failed to create new key"); + return BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + } + + BSL_Data_t keymat = BSL_DATA_INIT_VIEW(secret, secret_len); + + res = BSL_KeyStore_State.set_keymat(*key_out, &keymat); + if (BSL_SUCCESS != res) + { + BSL_LOG_ERR("Failed to set new key material"); + return BSL_ERR_SECURITY_CONTEXT_CRYPTO_FAILED; + } + + return BSL_SUCCESS; +} + +const BSL_IdValPair_t *BSL_Crypto_GetKeyParameter(BSL_Crypto_KeyHandle_t handle, int64_t param_id) +{ + ASSERT_PRECONDITION(BSL_KeyStore_State.get_parameter); + return BSL_KeyStore_State.get_parameter(handle, param_id); +} + +int BSL_Crypto_GetRegistryKey(const BSL_Data_t *keyid, BSL_Crypto_KeyHandle_t *handle) +{ + CHK_ARG_NONNULL(keyid); + CHK_ARG_NONNULL(handle); + ASSERT_PRECONDITION(BSL_KeyStore_State.find_key); + return BSL_KeyStore_State.find_key(keyid, handle); +} + +int BSL_Crypto_GetKeyStatistics(BSL_Crypto_KeyHandle_t handle, BSL_Crypto_KeyStats_t *stats) +{ + CHK_ARG_NONNULL(handle); + CHK_ARG_NONNULL(stats); + ASSERT_PRECONDITION(BSL_KeyStore_State.find_key); + return BSL_KeyStore_State.get_stats(handle, stats); +} diff --git a/src/bsl/crypto/KeyStore.h b/src/bsl/crypto/KeyStore.h new file mode 100644 index 00000000..4d6ab9d4 --- /dev/null +++ b/src/bsl/crypto/KeyStore.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2025-2026 The Johns Hopkins University Applied Physics + * Laboratory LLC. + * + * This file is part of the Bundle Protocol Security Library (BSL). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + * + * This work was performed for the Jet Propulsion Laboratory, California + * Institute of Technology, sponsored by the United States Government under + * the prime contract 80NM0018D0004 between the Caltech and NASA under + * subcontract 1700763. + */ +/** @file + * @ingroup crypto + * + * There are two forms of managed crypto keys in this interface: + * 1. Identified keys persisted in a long-term, thread-safe registry. + * These keys have byte string names (which can contain UTF8 text) and can + * have additional parameters to restrict their use. + * 2. Anonymous ephemeral keys used for individual operations and then discarded. + * These keys do not have names and are typically key-wrapped or the result of a + * key derivation function (KDF). + */ +#ifndef BSL_CRYPTO_KEYSTORE_H_ +#define BSL_CRYPTO_KEYSTORE_H_ + +#include "bsl/BPSecLib_Private.h" // TODO replace with Variant.h +#include "bsl/front/Data.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Opaque handle for key objects in the key store. + */ +typedef void *BSL_Crypto_KeyHandle_t; + +/// Indices of telemetry counters in ::BSL_Crypto_KeyStats_t +typedef enum +{ + /// Incremented once per use. + BSL_CRYPTO_KEYSTATS_TIMES_USED = 0, + /** Incremented for each byte processed. + * The specific meaning depends on the algorithm associated with the key. + */ + BSL_CRYPTO_KEYSTATS_BYTES_PROCESSED, + /// Not a real index, used to size arrays + BSL_CRYPTO_KEYSTATS_MAX_INDEX +} BSL_Crypto_KeyStats_CounterIndex_t; + +/** + * Structure containing statistics for individual keys + */ +typedef struct +{ + /// Counters for each ::BSL_Crypto_KeyStats_CounterIndex_t value + uint64_t stats[BSL_CRYPTO_KEYSTATS_MAX_INDEX]; +} BSL_Crypto_KeyStats_t; + +/** The set of callback function pointers which actually implement + * a key store. + * When registering, all of the functions need to be non-NULL. + */ +typedef struct +{ + /** Construct a new default empty key, outside of a key store. + * @param[out] key_out The non-null pointer to set. + * The handle must be released with #release_key when it is done being used. + * @return BSL_SUCCESS if successful. + */ + int (*new_key)(BSL_Crypto_KeyHandle_t *key_out); + + /** Acquire a new copy of a handle. + * @param[in] handle The handle to acquire. + * If NULL handle this is a do-nothing. + * @return The copy, or NULL if failure. + */ + BSL_Crypto_KeyHandle_t (*acquire_key)(BSL_Crypto_KeyHandle_t handle); + + /** Release the use of a handle. + * When all active handles are released the key should be destroyed. + * @param[in] handle The handle to release. + * If NULL handle this is a do-nothing. + */ + void (*release_key)(BSL_Crypto_KeyHandle_t handle); + + /** Find an identified key in the key store. + * Some keys are ephemeral and not registered in the store. + * @param[in] keyid A unique-to-the-store identifier for a key. + * @param[out] handle If found, will be set non-null handle. + * @return BSL_SUCCESS if found. + */ + int (*find_key)(const BSL_Data_t *keyid, BSL_Crypto_KeyHandle_t *handle); + + /** Set the (plaintext) key material for a key. + * @param[in] handle The handle to the key. + * @param[in] data Non-null pointer to key bytes, which will be copied. + * @return BSL_SUCCESS if valid. + */ + int (*set_keymat)(BSL_Crypto_KeyHandle_t handle, const BSL_Data_t *data); + + /** Get the (plaintext) key material for a key. + * @param[in] handle The handle to the key. + * @param[out] data Non-null pointer to output struct, which will be set + * to a view on the data. + * @return BSL_SUCCESS if valid. + */ + int (*get_keymat)(BSL_Crypto_KeyHandle_t handle, BSL_Data_t *view); + + /** Get a specific parameter which may be attached to a key. + * @param[in] handle The handle to the key. + * @param param_id The unique identifier for the parameter. + * The available parameters will be determined by the key source + * (e.g. COSE_Key parameters). + * @return A non-null pointer if the parameter exists. + */ + const BSL_IdValPair_t *(*get_parameter)(BSL_Crypto_KeyHandle_t handle, int64_t param_id); + + /** Update telemetry counters for a key. + */ + void (*update_stats)(BSL_Crypto_KeyHandle_t handle, uint64_t use, uint64_t bytes); + + /** Get full counters for a key. + */ + int (*get_stats)(BSL_Crypto_KeyHandle_t handle, BSL_Crypto_KeyStats_t *stats); + +} BSL_KeyStore_Descriptors_t; + +/** Initialize the key store subsystem. + * This must be called once per process. + * + * @warning This function is not thread safe and should be used before any + * ::BSL_LibCtx_s is initialized or other BSL interfaces used. + * + * @param desc The descriptor to use for future key store access. + * @return Zero if successful, negative on error. + */ +int BSL_KeyStore_Init(BSL_KeyStore_Descriptors_t desc); + +/** Deinitialize the key store subsystem. + * This should be called at the end of the process. + * + * @warning This function is not thread safe and should be used after any + * ::BSL_LibCtx_s is deinitialized. + */ +void BSL_KeyStore_Deinit(void); + +/** + * Generate a new cryptographic key. + * @param[in] key_length length of new key in bytes. + * @param[out] key_out pointer to pointer for new key handle. + * The handle must be released with BSL_Crypto_ReleaseKeyHandle() when it is done being used. + */ +int BSL_Crypto_GenKey(size_t key_length, BSL_Crypto_KeyHandle_t *key_out); + +/** + * Load a new cryptographic key. + * @param[in] secret raw symmetric key. + * @param secret_len length of @c secret data. + * @param[out] key_out pointer to pointer for new key handle. + * The handle must be released with BSL_Crypto_ReleaseKeyHandle() when it is done being used. + */ +int BSL_Crypto_LoadKey(const uint8_t *secret, size_t secret_len, BSL_Crypto_KeyHandle_t *key_out); + +/** Release a key handle after it is done being used. + * + * @param[in] keyhandle key handle to release. + * If the handle is null this does nothing. + * @post If this is the last use of the handle (including the key registry) the key will be destroyed. + */ +void BSL_Crypto_ReleaseKeyHandle(BSL_Crypto_KeyHandle_t keyhandle); + +/** Compare two keys in a time-invariant way. + * This avoids side channel attacks which depend on comparison time. + * + * @param[in] hdl1 The first key handle. + * @param[in] hdl2 The second key handle. + * @return True if they compare equal. + */ +bool BSL_Crypto_CompareKeys(BSL_Crypto_KeyHandle_t hdl1, BSL_Crypto_KeyHandle_t hdl2); + +/** Get pointers to an existing key, if present. + * + * @param keyid The key to search for. + * @param[in, out] handle pointer to pointer for new key handle. + * The handle must be released with BSL_Crypto_ReleaseKeyHandle() when it is done being used. + * @return Zero if the key was present. + */ +int BSL_Crypto_GetRegistryKey(const BSL_Data_t *keyid, BSL_Crypto_KeyHandle_t *handle); + +/** Get key parameter for read-only access. + * @param[in] handle The handle to the key. + * @param param_id The unique identifier for the parameter. + * The available parameters will be determined by the key source + * (e.g. COSE_Key parameters). + * @return A non-null pointer if the parameter exists. + */ +const BSL_IdValPair_t *BSL_Crypto_GetKeyParameter(BSL_Crypto_KeyHandle_t handle, int64_t param_id); + +/** + * Retrieve statistics related to a crypto key + * @param[in] handle The handle of a key in the crypto registry to retrieve the stats of. + * @param[out] stats struct containing statistics related to the key id + */ +int BSL_Crypto_GetKeyStatistics(BSL_Crypto_KeyHandle_t handle, BSL_Crypto_KeyStats_t *stats); + +#ifdef __cplusplus +} // extern C +#endif + +#endif /* BSL_CRYPTO_KEYSTORE_H_ */ diff --git a/src/bsl/mock_bpa/KeyStore.c b/src/bsl/mock_bpa/KeyStore.c new file mode 100644 index 00000000..1ad3abbf --- /dev/null +++ b/src/bsl/mock_bpa/KeyStore.c @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2025-2026 The Johns Hopkins University Applied Physics + * Laboratory LLC. + * + * This file is part of the Bundle Protocol Security Library (BSL). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + * + * This work was performed for the Jet Propulsion Laboratory, California + * Institute of Technology, sponsored by the United States Government under + * the prime contract 80NM0018D0004 between the Caltech and NASA under + * subcontract 1700763. + */ + +/** @file + * @ingroup mock_bpa + * Provider of a key store via the crypto API ::BSL_KeyStore_Descriptors_t. + */ + +#include "KeyStore.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/** + * Struct to hold private key information + */ +typedef struct BSL_CryptoKey_s +{ + /// Pointer to raw key information + BSL_Data_t raw; + /// Additional parameter dictionary + BSLB_IdValPairPtrMap_t params; + /// Statistics related to this key + BSL_Crypto_KeyStats_t stats; + /// Mutex for #stats + pthread_mutex_t stats_mutex; +} BSL_CryptoKey_t; + +static void BSL_CryptoKey_Init(BSL_CryptoKey_t *key) +{ + ASSERT_ARG_NONNULL(key); + + BSL_Data_Init(&(key->raw)); + BSLB_IdValPairPtrMap_init(key->params); + + for (uint64_t i = 0; i < BSL_CRYPTO_KEYSTATS_MAX_INDEX; i++) + { + key->stats.stats[i] = 0; + } + pthread_mutex_init(&key->stats_mutex, NULL); +} + +static void BSL_CryptoKey_Deinit(BSL_CryptoKey_t *key) +{ + ASSERT_ARG_NONNULL(key); + + BSL_Data_Deinit(&(key->raw)); + BSLB_IdValPairPtrMap_clear(key->params); + + pthread_mutex_destroy(&key->stats_mutex); + for (uint64_t i = 0; i < BSL_CRYPTO_KEYSTATS_MAX_INDEX; i++) + { + key->stats.stats[i] = 0; + } +} + +/** M*LIB OPLIST for ::BSL_CryptoKey_t + */ +#define M_OPL_BSL_CryptoKey_t() \ + M_OPEXTEND(M_POD_OPLIST, INIT(API_2(BSL_CryptoKey_Init)), INIT_SET(0), SET(0), CLEAR(API_2(BSL_CryptoKey_Deinit))) + +/** @struct BSL_CryptoKeyPtr_t + * Thread-safe shared pointer to memory-stable ::BSL_CryptoKey_t struct. + */ +/** @struct BSL_CryptoKeyDict_t + * Stable dict of crypto keys (key: key ID | value: BSL_CryptoKeyPtr_t) + */ +/// @cond Doxygen_Suppress +// NOLINTBEGIN +// GCOV_EXCL_START +M_SHARED_PTR_DEF(BSL_CryptoKeyPtr, BSL_CryptoKey_t, M_OPL_BSL_CryptoKey_t()) +#define M_OPL_BSL_CryptoKeyPtr() M_SHARED_PTR_OPLIST(BSL_CryptoKeyPtr, M_OPL_BSL_CryptoKey_t()) +M_DICT_DEF2(BSL_CryptoKeyDict, m_bstring_t, M_BSTRING_OPLIST, BSL_CryptoKeyPtr_t *, M_OPL_BSL_CryptoKeyPtr()) +// GCOV_EXCL_STOP +// NOLINTEND +/// @endcond + +/// Crypto key registry +static BSL_CryptoKeyDict_t StaticKeyRegistry; +static pthread_mutex_t StaticCryptoMutex = PTHREAD_MUTEX_INITIALIZER; + +void MockBPA_KeyStore_Init(void) +{ + pthread_mutex_lock(&StaticCryptoMutex); + BSL_CryptoKeyDict_init(StaticKeyRegistry); + pthread_mutex_unlock(&StaticCryptoMutex); + + BSL_KeyStore_Init(MockBPA_KeyStore_Descriptors()); +} + +void MockBPA_KeyStore_Deinit(void) +{ + BSL_KeyStore_Deinit(); + + pthread_mutex_lock(&StaticCryptoMutex); + BSL_CryptoKeyDict_clear(StaticKeyRegistry); + pthread_mutex_unlock(&StaticCryptoMutex); +} + +int MockBPA_KeyStore_AddKey(const BSL_Data_t *keyid, BSL_Crypto_KeyHandle_t handle) +{ + ASSERT_ARG_NONNULL(keyid); + CHK_ARG_NONNULL(handle); + + BSL_CryptoKeyPtr_t *key_ptr = handle; + + m_bstring_t keyid_str; + m_bstring_init(keyid_str); + m_bstring_push_back_bytes(keyid_str, keyid->len, keyid->ptr); + + pthread_mutex_lock(&StaticCryptoMutex); + BSL_CryptoKeyDict_set_at(StaticKeyRegistry, keyid_str, key_ptr); + pthread_mutex_unlock(&StaticCryptoMutex); + + m_bstring_clear(keyid_str); + return 0; +} + +int MockBPA_KeyStore_RemoveKey(const BSL_Data_t *keyid) +{ + ASSERT_ARG_NONNULL(keyid); + + m_bstring_t keyid_str; + m_bstring_init(keyid_str); + m_bstring_push_back_bytes(keyid_str, keyid->len, keyid->ptr); + + pthread_mutex_lock(&StaticCryptoMutex); + int res = BSL_CryptoKeyDict_erase(StaticKeyRegistry, keyid_str); + pthread_mutex_unlock(&StaticCryptoMutex); + + m_bstring_clear(keyid_str); + return res ? BSL_SUCCESS : -1; +} + +BSL_IdValPair_t *MockBPA_KeyStore_SetKeyParameter(BSL_Crypto_KeyHandle_t handle, int64_t param_id) +{ + ASSERT_ARG_NONNULL(handle); + BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(handle); + + BSL_IdValPair_t *retval = NULL; + if (key) + { + BSLB_IdValPairPtr_t *param_ptr; + + BSLB_IdValPairPtr_t **found = BSLB_IdValPairPtrMap_get(key->params, param_id); + if (found) + { + param_ptr = *found; + retval = BSLB_IdValPairPtr_ref(param_ptr); + } + else + { + param_ptr = BSLB_IdValPairPtr_new(); + BSLB_IdValPairPtrMap_set_at(key->params, param_id, param_ptr); + retval = BSLB_IdValPairPtr_ref(param_ptr); + // map keeps a reference so this is safe + BSLB_IdValPairPtr_release(param_ptr); + } + } + return retval; +} + +static int MockBPA_KeyStore_FindKey(const BSL_Data_t *keyid, BSL_Crypto_KeyHandle_t *handle) +{ + CHK_ARG_NONNULL(keyid); + CHK_ARG_NONNULL(handle); + + m_bstring_t keyid_str; + m_bstring_init(keyid_str); + m_bstring_push_back_bytes(keyid_str, keyid->len, keyid->ptr); + + int retval = BSL_SUCCESS; + pthread_mutex_lock(&StaticCryptoMutex); + BSL_CryptoKeyPtr_t **found = BSL_CryptoKeyDict_get(StaticKeyRegistry, keyid_str); + if (!found) + { + *handle = NULL; + retval = BSL_ERR_NOT_FOUND; + } + else + { + *handle = BSL_CryptoKeyPtr_acquire(*found); + } + pthread_mutex_unlock(&StaticCryptoMutex); + + m_bstring_clear(keyid_str); + return retval; +} + +static const BSL_IdValPair_t *MockBPA_KeyStore_GetKeyParameter(BSL_Crypto_KeyHandle_t handle, int64_t param_id) +{ + if (!handle) + { + return NULL; + } + BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(handle); + + const BSL_IdValPair_t *retval = NULL; + if (key) + { + BSLB_IdValPairPtr_t **found = BSLB_IdValPairPtrMap_get(key->params, param_id); + if (found) + { + retval = BSLB_IdValPairPtr_ref(*found); + } + } + return retval; +} + +static int MockBPA_KeyStore_New(BSL_Crypto_KeyHandle_t *handle) +{ + ASSERT_ARG_NONNULL(handle); + *handle = BSL_CryptoKeyPtr_new(); + return BSL_SUCCESS; +} + +static int MockBPA_KeyStore_SetKeymat(BSL_Crypto_KeyHandle_t handle, const BSL_Data_t *data) +{ + ASSERT_ARG_NONNULL(handle); + ASSERT_ARG_NONNULL(data); + BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(handle); + return BSL_Data_CopyFrom(&key->raw, data->len, data->ptr); +} + +static int MockBPA_KeyStore_GetKeymat(BSL_Crypto_KeyHandle_t handle, BSL_Data_t *data) +{ + ASSERT_ARG_NONNULL(handle); + ASSERT_ARG_NONNULL(data); + const BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(handle); + BSL_Data_InitView(data, key->raw.len, key->raw.ptr); + return BSL_SUCCESS; +} + +static BSL_Crypto_KeyHandle_t MockBPA_KeyStore_Acquire(BSL_Crypto_KeyHandle_t handle) +{ + if (!handle) + { + return NULL; + } + + BSL_CryptoKeyPtr_t *ptr = handle; + return BSL_CryptoKeyPtr_acquire(ptr); +} + +static void MockBPA_KeyStore_Release(BSL_Crypto_KeyHandle_t handle) +{ + if (!handle) + { + return; + } + + BSL_CryptoKeyPtr_t *ptr = handle; + BSL_CryptoKeyPtr_release(ptr); +} + +static void MockBPA_KeyStore_UpdateStats(BSL_Crypto_KeyHandle_t handle, uint64_t use, uint64_t bytes) +{ + if (!handle) + { + return; + } + BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(handle); + + pthread_mutex_lock(&key->stats_mutex); + key->stats.stats[BSL_CRYPTO_KEYSTATS_TIMES_USED] += use; + key->stats.stats[BSL_CRYPTO_KEYSTATS_BYTES_PROCESSED] += bytes; + pthread_mutex_unlock(&key->stats_mutex); +} + +static int MockBPA_KeyStore_GetStats(BSL_Crypto_KeyHandle_t handle, BSL_Crypto_KeyStats_t *stats) +{ + CHK_ARG_NONNULL(handle); + CHK_ARG_NONNULL(stats); + + BSL_CryptoKey_t *key = BSL_CryptoKeyPtr_ref(handle); + + pthread_mutex_lock(&key->stats_mutex); + // copy as POD + *stats = key->stats; + pthread_mutex_unlock(&key->stats_mutex); + + return BSL_SUCCESS; +} + +BSL_KeyStore_Descriptors_t MockBPA_KeyStore_Descriptors(void) +{ + BSL_KeyStore_Descriptors_t desc = { + .new_key = &MockBPA_KeyStore_New, + .set_keymat = &MockBPA_KeyStore_SetKeymat, + .get_keymat = &MockBPA_KeyStore_GetKeymat, + .acquire_key = &MockBPA_KeyStore_Acquire, + .release_key = &MockBPA_KeyStore_Release, + .find_key = &MockBPA_KeyStore_FindKey, + .get_parameter = &MockBPA_KeyStore_GetKeyParameter, + .update_stats = &MockBPA_KeyStore_UpdateStats, + .get_stats = &MockBPA_KeyStore_GetStats, + }; + return desc; +} + +int MockBPA_KeyStore_LoadJwk(int fd) +{ + int retval = BSL_SUCCESS; + + json_error_t err; + + json_t *root = json_loadfd(fd, 0, &err); + if (!root) + { + BSL_LOG_ERR("JSON error: line %d: %s", err.line, err.text); + json_decref(root); + return 1; + } + + const json_t *keys = json_object_get(root, "keys"); + if (!keys || !json_is_array(keys)) + { + BSL_LOG_ERR("Missing \"keys\" "); + json_decref(root); + return 1; + } + + const size_t n = json_array_size(keys); + BSL_LOG_INFO("Found %zu key objects", n); + + for (size_t i = 0; i < n; ++i) + { + const json_t *key_obj = json_array_get(keys, i); + if (!json_is_object(key_obj)) + { + continue; + } + + const json_t *kty = json_object_get(key_obj, "kty"); + if (!kty) + { + BSL_LOG_ERR("Missing \"kty\" "); + continue; + } + + if (0 != strcmp("oct", json_string_value(kty))) + { + BSL_LOG_ERR("Not a symmetric key set"); + continue; + } + + const json_t *kid = json_object_get(key_obj, "kid"); + if (!kid || !json_is_string(kid)) + { + BSL_LOG_ERR("Missing \"kid\" "); + continue; + } + const char *kid_str = json_string_value(kid); + BSL_LOG_DEBUG("kid: %s", kid_str); + + const json_t *k = json_object_get(key_obj, "k"); + if (!k || !json_is_string(k)) + { + BSL_LOG_ERR("Missing \"k\" "); + continue; + } + + BSL_Data_t k_data; + BSL_Data_Init(&k_data); + retval = BSL_TextUtil_Base64_Decode(&k_data, json_string_value(k), json_string_length(k)); + + if (!retval) + { + BSL_Data_t kid_view = BSL_DATA_INIT_VIEW_CSTR(kid_str); + + BSL_Crypto_KeyHandle_t keyhandle; + BSL_Crypto_LoadKey(k_data.ptr, k_data.len, &keyhandle); + retval = MockBPA_KeyStore_AddKey(&kid_view, keyhandle); + BSL_Crypto_ReleaseKeyHandle(keyhandle); + } + BSL_Data_Deinit(&k_data); + + if (retval) + { + BSL_LOG_ERR("JKW register failure"); + break; + } + } + + json_decref(root); + return retval; +} + +/** Decode a @c COSE_KeySet array. + * Matches ::BSL_CBOR_Decode_f signature. + */ +static int mock_bpa_key_registry_cosekey_decode(QCBORDecodeContext *dec, const void *obj _U_) +{ + int retval = BSL_SUCCESS; + + QCBORItem item; + QCBORDecode_EnterArray(dec, NULL); + + // array-of-key-maps + while (QCBOR_SUCCESS == QCBORDecode_PeekNext(dec, &item)) + { + bool has_kty = false; + int64_t kty = 0; + bool has_alg = false; + int64_t alg = 0; + UsefulBufC kid = NULLUsefulBufC; + UsefulBufC baseiv = NULLUsefulBufC; + UsefulBufC k_data = NULLUsefulBufC; + + QCBORDecode_EnterArray(dec, NULL); // using QCBOR_DECODE_MODE_MAP_AS_ARRAY + + while (QCBOR_SUCCESS == QCBORDecode_PeekNext(dec, &item)) + { + int64_t label; + QCBORDecode_GetInt64(dec, &label); + if (QCBOR_SUCCESS != QCBORDecode_GetError(dec)) + { + BSL_LOG_ERR("Unable to get key label"); + break; + } + BSL_LOG_DEBUG("got label %" PRId64, label); + + switch (label) + { + case BSLX_COSEMSG_KEY_PARAM_KTY: + QCBORDecode_GetInt64(dec, &kty); + has_kty = true; + break; + case BSLX_COSEMSG_KEY_PARAM_KID: + QCBORDecode_GetByteString(dec, &kid); + break; + case BSLX_COSEMSG_KEY_PARAM_ALG: + QCBORDecode_GetInt64(dec, &alg); + has_alg = true; + break; + case BSLX_COSEMSG_KEY_PARAM_BASEIV: + QCBORDecode_GetByteString(dec, &baseiv); + break; + case -1: + if (has_kty && (kty == 4)) + { + QCBORDecode_GetByteString(dec, &k_data); + } + break; + default: + // consume but ignore + QCBORDecode_VGetNextConsume(dec, &item); + break; + } + if (QCBOR_SUCCESS != QCBORDecode_GetError(dec)) + { + BSL_LOG_ERR("Unable to get key value"); + break; + } + + if (has_kty && (kty != 4)) + { + BSL_LOG_WARNING("Ignoring non-symmetric key type %" PRId64, kty); + break; + } + } + QCBORDecode_ExitArray(dec); + + // If valid enough to store + if (has_kty && kid.ptr && k_data.ptr) + { + BSL_Data_t kid_view; + BSL_Data_InitView(&kid_view, kid.len, (BSL_DataPtr_t)kid.ptr); + + BSL_Crypto_KeyHandle_t keyhandle; + BSL_Crypto_LoadKey(k_data.ptr, k_data.len, &keyhandle); + + if (has_alg) + { + BSL_IdValPair_SetInt64(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), + BSLX_COSEMSG_KEY_PARAM_ALG, alg); + } + else + { + BSL_LOG_WARNING("COSE Key without an alg parameter"); + } + + if (baseiv.len > 0) + { + BSL_Data_t view; + BSL_Data_InitView(&view, baseiv.len, (BSL_DataPtr_t)baseiv.ptr); + BSL_IdValPair_SetBytestr(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_BASEIV), + BSLX_COSEMSG_KEY_PARAM_BASEIV, view); + } + + retval = MockBPA_KeyStore_AddKey(&kid_view, keyhandle); + BSL_Crypto_ReleaseKeyHandle(keyhandle); + BSL_LOG_DEBUG("Adding key result %d", retval); + if (BSL_SUCCESS != retval) + { + BSL_LOG_ERR("Unable to store key"); + break; + } + } + } + QCBORDecode_ExitArray(dec); + return retval; +} + +int MockBPA_KeyStore_LoadCoseKeySet(int infd) +{ + struct stat sb; + if ((fstat(infd, &sb) < 0) || (sb.st_size == 0)) + { + BSL_LOG_ERR("Error getting file size"); + close(infd); + return BSL_ERR_DECODING; + } + + void *data = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, infd, 0); + if (!data) + { + BSL_LOG_ERR("Error in mmap"); + close(infd); + return BSL_ERR_DECODING; + } + + BSL_Data_t view; + BSL_Data_InitView(&view, sb.st_size, (BSL_DataPtr_t)data); + + int retval = BSL_CBOR_Decode(&view, &mock_bpa_key_registry_cosekey_decode, NULL); + + if (munmap(data, sb.st_size) < 0) + { + BSL_LOG_ERR("Error in munmap"); + } + close(infd); + return retval; +} + +int MockBPA_KeyStore_LoadFile(const char *file_path) +{ + int retval = BSL_SUCCESS; + + int infd = open(file_path, O_RDONLY); + if (infd < 0) + { + BSL_LOG_ERR("Failed to open input file %s", file_path); + return BSL_ERR_DECODING; + } + + BSL_LOG_INFO("Reading keys from %s", file_path); + m_string_t path; + m_string_init_set_cstr(path, file_path); + bool is_json = m_string_end_with_str_p(path, ".json"); + bool is_cbor = m_string_end_with_str_p(path, ".cbor"); + m_string_clear(path); + + if (is_json) + { + retval = MockBPA_KeyStore_LoadJwk(infd); + } + else if (is_cbor) + { + retval = MockBPA_KeyStore_LoadCoseKeySet(infd); + } + else + { + BSL_LOG_ERR("Unhandled key file extension for %s", file_path); + retval = BSL_ERR_ARG_INVALID; + } + + return retval; +} diff --git a/src/bsl/mock_bpa/KeyStore.h b/src/bsl/mock_bpa/KeyStore.h new file mode 100644 index 00000000..f25a3c0e --- /dev/null +++ b/src/bsl/mock_bpa/KeyStore.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025-2026 The Johns Hopkins University Applied Physics + * Laboratory LLC. + * + * This file is part of the Bundle Protocol Security Library (BSL). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + * + * This work was performed for the Jet Propulsion Laboratory, California + * Institute of Technology, sponsored by the United States Government under + * the prime contract 80NM0018D0004 between the Caltech and NASA under + * subcontract 1700763. + */ + +/** @file + * @ingroup mock_bpa + * Declaration of functions to load and manipulate the Mock BPA key store + * separate from the API used by the crypto library. + */ + +#ifndef BSL_MOCKBPA_KEYSTORE_H_ +#define BSL_MOCKBPA_KEYSTORE_H_ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Get key store descriptors for the process. + * + * @return Populated descriptor struct. + */ +BSL_KeyStore_Descriptors_t MockBPA_KeyStore_Descriptors(void); + +/** Initialize the key storage and register it with BSL_KeyStore_Init(). + */ +void MockBPA_KeyStore_Init(void); + +/** De-register with BSL_KeyStore_Deinit() and clear all key storage. + */ +void MockBPA_KeyStore_Deinit(void); + +/** Erase key entry from crypto library registry, if present. + * @param[in] keyid key ID of key to remove. + * @return Zero if the key was present. + */ +int MockBPA_KeyStore_RemoveKey(const BSL_Data_t *keyid); + +/** + * Add a new key to the crypto key registry + * @param[in] keyid key ID that crypto functions will use to access key + * @param[out] handle Key handle to add to the registry. + * Once the key is added it should be treated as read-only for thread-safety purposes. + * When handle is output, the handle must be released with BSL_Crypto_ReleaseKeyHandle() when it is done being used. + * @return Zero upon success. + */ +int MockBPA_KeyStore_AddKey(const BSL_Data_t *keyid, BSL_Crypto_KeyHandle_t handle); + +/** Add a context-specific parameter to a known key. + * + * @param[in] handle The key ID to update. + * @param[in] param_id The parameter to access. + * If the parameter does not already exist it will be created. + * @return Non-NULL pointer if successful. + */ +BSL_IdValPair_t *MockBPA_KeyStore_SetKeyParameter(BSL_Crypto_KeyHandle_t handle, int64_t param_id); + +/** @brief Initialize keys + * @param[in] file_path path to JSON file with JWK Set or CBOR file with @c COSE_KeySet + * @return 0 if successful. + */ +int MockBPA_KeyStore_LoadFile(const char *file_path); + +/** @warning Exposed only for testing. + * @param infd The file descriptor to read from. + */ +int MockBPA_KeyStore_LoadJwk(int infd); + +/** @warning Exposed only for testing. + * @param infd The file descriptor to read from. + */ +int MockBPA_KeyStore_LoadCoseKeySet(int infd); + +#ifdef __cplusplus +} // extern C +#endif + +#endif /* BSL_MOCKBPA_KEYSTORE_H_ */ diff --git a/src/bsl/mock_bpa/MockBPA.h b/src/bsl/mock_bpa/MockBPA.h index 25abad36..fe8b2ae4 100644 --- a/src/bsl/mock_bpa/MockBPA.h +++ b/src/bsl/mock_bpa/MockBPA.h @@ -27,6 +27,7 @@ #include "decode.h" #include "eidpat.h" #include "encode.h" +#include "KeyStore.h" #include "log.h" #endif //_BSL_MockBPA_MockBPA_H_ diff --git a/src/bsl/mock_bpa/agent.c b/src/bsl/mock_bpa/agent.c index 4b59f6a1..ba5771c4 100644 --- a/src/bsl/mock_bpa/agent.c +++ b/src/bsl/mock_bpa/agent.c @@ -21,8 +21,9 @@ */ /** @file - * Definitions for Agent initialization. * @ingroup mock_bpa + * Definitions for Agent initialization and + * provider of host functions via the API ::BSL_HostDescriptors_t. */ #include "agent.h" diff --git a/src/bsl/mock_bpa/agent.h b/src/bsl/mock_bpa/agent.h index e537a0af..bb7bc296 100644 --- a/src/bsl/mock_bpa/agent.h +++ b/src/bsl/mock_bpa/agent.h @@ -144,9 +144,10 @@ typedef struct MockBPA_Agent_s } MockBPA_Agent_t; -/** Get host descriptors without a specific agent. +/** Get host descriptors for a specific agent. * * @param[in] agent The agent to associate as user data. + * @return Populated descriptor struct. */ BSL_HostDescriptors_t MockBPA_Agent_Descriptors(MockBPA_Agent_t *agent); diff --git a/src/bsl/mock_bpa/key_registry.c b/src/bsl/mock_bpa/key_registry.c deleted file mode 100644 index ba5a33c9..00000000 --- a/src/bsl/mock_bpa/key_registry.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c) 2025-2026 The Johns Hopkins University Applied Physics - * Laboratory LLC. - * - * This file is part of the Bundle Protocol Security Library (BSL). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - * - * This work was performed for the Jet Propulsion Laboratory, California - * Institute of Technology, sponsored by the United States Government under - * the prime contract 80NM0018D0004 between the Caltech and NASA under - * subcontract 1700763. - */ - -/** @file - * @ingroup mock_bpa - */ - -#include "key_registry.h" - -#include "bsl/front/TextUtil.h" -#include "bsl/dynamic/CBOR.h" -#include "bsl/cose_sc/CoseMsg.h" - -#include -#include - -#include -#include -#include -#include - -int mock_bpa_key_registry_init_jwk(int fd) -{ - int retval = BSL_SUCCESS; - - json_error_t err; - - json_t *root = json_loadfd(fd, 0, &err); - if (!root) - { - BSL_LOG_ERR("JSON error: line %d: %s", err.line, err.text); - json_decref(root); - return 1; - } - - const json_t *keys = json_object_get(root, "keys"); - if (!keys || !json_is_array(keys)) - { - BSL_LOG_ERR("Missing \"keys\" "); - json_decref(root); - return 1; - } - - const size_t n = json_array_size(keys); - BSL_LOG_INFO("Found %zu key objects", n); - - for (size_t i = 0; i < n; ++i) - { - const json_t *key_obj = json_array_get(keys, i); - if (!json_is_object(key_obj)) - { - continue; - } - - const json_t *kty = json_object_get(key_obj, "kty"); - if (!kty) - { - BSL_LOG_ERR("Missing \"kty\" "); - continue; - } - - if (0 != strcmp("oct", json_string_value(kty))) - { - BSL_LOG_ERR("Not a symmetric key set"); - continue; - } - - const json_t *kid = json_object_get(key_obj, "kid"); - if (!kid || !json_is_string(kid)) - { - BSL_LOG_ERR("Missing \"kid\" "); - continue; - } - const char *kid_str = json_string_value(kid); - BSL_LOG_DEBUG("kid: %s", kid_str); - - const json_t *k = json_object_get(key_obj, "k"); - if (!k || !json_is_string(k)) - { - BSL_LOG_ERR("Missing \"k\" "); - continue; - } - - BSL_Data_t k_data; - BSL_Data_Init(&k_data); - retval = BSL_TextUtil_Base64_Decode(&k_data, json_string_value(k), json_string_length(k)); - - if (!retval) - { - BSL_Data_t kid_view = BSL_DATA_INIT_VIEW_CSTR(kid_str); - - BSL_Crypto_KeyHandle_t keyhandle; - BSL_Crypto_LoadKey(k_data.ptr, k_data.len, &keyhandle); - retval = BSL_Crypto_AddRegistryKey(&kid_view, keyhandle); - BSL_Crypto_ReleaseKeyHandle(keyhandle); - } - BSL_Data_Deinit(&k_data); - - if (retval) - { - BSL_LOG_ERR("JKW register failure"); - break; - } - } - - json_decref(root); - return retval; -} - -/** Decode a @c COSE_KeySet array. - * Matches ::BSL_CBOR_Decode_f signature. - */ -static int mock_bpa_key_registry_cosekey_decode(QCBORDecodeContext *dec, const void *obj _U_) -{ - int retval = BSL_SUCCESS; - - QCBORItem item; - QCBORDecode_EnterArray(dec, NULL); - - // array-of-key-maps - while (QCBOR_SUCCESS == QCBORDecode_PeekNext(dec, &item)) - { - bool has_kty = false; - int64_t kty = 0; - bool has_alg = false; - int64_t alg = 0; - UsefulBufC kid = NULLUsefulBufC; - UsefulBufC baseiv = NULLUsefulBufC; - UsefulBufC k_data = NULLUsefulBufC; - - QCBORDecode_EnterArray(dec, NULL); // using QCBOR_DECODE_MODE_MAP_AS_ARRAY - - while (QCBOR_SUCCESS == QCBORDecode_PeekNext(dec, &item)) - { - int64_t label; - QCBORDecode_GetInt64(dec, &label); - if (QCBOR_SUCCESS != QCBORDecode_GetError(dec)) - { - BSL_LOG_ERR("Unable to get key label"); - break; - } - BSL_LOG_DEBUG("got label %" PRId64, label); - - switch (label) - { - case BSLX_COSEMSG_KEY_PARAM_KTY: - QCBORDecode_GetInt64(dec, &kty); - has_kty = true; - break; - case BSLX_COSEMSG_KEY_PARAM_KID: - QCBORDecode_GetByteString(dec, &kid); - break; - case BSLX_COSEMSG_KEY_PARAM_ALG: - QCBORDecode_GetInt64(dec, &alg); - has_alg = true; - break; - case BSLX_COSEMSG_KEY_PARAM_BASEIV: - QCBORDecode_GetByteString(dec, &baseiv); - break; - case -1: - if (has_kty && (kty == 4)) - { - QCBORDecode_GetByteString(dec, &k_data); - } - break; - default: - // consume but ignore - QCBORDecode_VGetNextConsume(dec, &item); - break; - } - if (QCBOR_SUCCESS != QCBORDecode_GetError(dec)) - { - BSL_LOG_ERR("Unable to get key value"); - break; - } - - if (has_kty && (kty != 4)) - { - BSL_LOG_WARNING("Ignoring non-symmetric key type %" PRId64, kty); - break; - } - } - QCBORDecode_ExitArray(dec); - - // If valid enough to store - if (has_kty && kid.ptr && k_data.ptr) - { - BSL_Data_t kid_view; - BSL_Data_InitView(&kid_view, kid.len, (BSL_DataPtr_t)kid.ptr); - - BSL_Crypto_KeyHandle_t keyhandle; - BSL_Crypto_LoadKey(k_data.ptr, k_data.len, &keyhandle); - - if (has_alg) - { - BSL_IdValPair_SetInt64(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), - BSLX_COSEMSG_KEY_PARAM_ALG, alg); - } - else - { - BSL_LOG_WARNING("COSE Key without an alg parameter"); - } - - if (baseiv.len > 0) - { - BSL_Data_t view; - BSL_Data_InitView(&view, baseiv.len, (BSL_DataPtr_t)baseiv.ptr); - BSL_IdValPair_SetBytestr(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_BASEIV), - BSLX_COSEMSG_KEY_PARAM_BASEIV, view); - } - - retval = BSL_Crypto_AddRegistryKey(&kid_view, keyhandle); - BSL_Crypto_ReleaseKeyHandle(keyhandle); - BSL_LOG_DEBUG("Adding key result %d", retval); - if (BSL_SUCCESS != retval) - { - BSL_LOG_ERR("Unable to store key"); - break; - } - } - } - QCBORDecode_ExitArray(dec); - return retval; -} - -int mock_bpa_key_registry_init_cosekey(int infd) -{ - struct stat sb; - if ((fstat(infd, &sb) < 0) || (sb.st_size == 0)) - { - BSL_LOG_ERR("Error getting file size"); - close(infd); - return BSL_ERR_DECODING; - } - - void *data = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, infd, 0); - if (!data) - { - BSL_LOG_ERR("Error in mmap"); - close(infd); - return BSL_ERR_DECODING; - } - - BSL_Data_t view; - BSL_Data_InitView(&view, sb.st_size, (BSL_DataPtr_t)data); - - int retval = BSL_CBOR_Decode(&view, &mock_bpa_key_registry_cosekey_decode, NULL); - - if (munmap(data, sb.st_size) < 0) - { - BSL_LOG_ERR("Error in munmap"); - } - close(infd); - return retval; -} - -int mock_bpa_key_registry_init(const char *file_path) -{ - int retval = BSL_SUCCESS; - - int infd = open(file_path, O_RDONLY); - if (infd < 0) - { - BSL_LOG_ERR("Failed to open input file %s", file_path); - return BSL_ERR_DECODING; - } - - BSL_LOG_INFO("Reading keys from %s", file_path); - m_string_t path; - m_string_init_set_cstr(path, file_path); - bool is_json = m_string_end_with_str_p(path, ".json"); - bool is_cbor = m_string_end_with_str_p(path, ".cbor"); - m_string_clear(path); - - if (is_json) - { - retval = mock_bpa_key_registry_init_jwk(infd); - } - else if (is_cbor) - { - retval = mock_bpa_key_registry_init_cosekey(infd); - } - else - { - BSL_LOG_ERR("Unhandled key file extension for %s", file_path); - retval = BSL_ERR_ARG_INVALID; - } - - return retval; -} - -int mock_bpa_rfc9173_bcb_cek(unsigned char *buf, int len) -{ - if (len == 12) // IV - { - uint8_t iv[] = { 0x54, 0x77, 0x65, 0x6c, 0x76, 0x65, 0x31, 0x32, 0x31, 0x32, 0x31, 0x32 }; - memcpy(buf, iv, 12); - } - else // A3 KEY - { - uint8_t rfc9173A3_key[] = { 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, - 0x6f, 0x70, 0x61, 0x73, 0x64, 0x66, 0x67, 0x68 }; - memcpy(buf, rfc9173A3_key, len); - } - return 1; -} diff --git a/src/bsl/mock_bpa/key_registry.h b/src/bsl/mock_bpa/key_registry.h deleted file mode 100644 index 2c80375f..00000000 --- a/src/bsl/mock_bpa/key_registry.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2025-2026 The Johns Hopkins University Applied Physics - * Laboratory LLC. - * - * This file is part of the Bundle Protocol Security Library (BSL). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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. - * - * This work was performed for the Jet Propulsion Laboratory, California - * Institute of Technology, sponsored by the United States Government under - * the prime contract 80NM0018D0004 between the Caltech and NASA under - * subcontract 1700763. - */ - -/** @file - * @ingroup mock_bpa - */ - -#ifndef BSL_MOCK_BPA_KEY_REGISTRY_H_ -#define BSL_MOCK_BPA_KEY_REGISTRY_H_ - -#include "bsl/crypto/CryptoInterface.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @brief Initialize keys - * @param[in] file_path path to JSON file with JWKs or CBOR file with @c COSE_KeySet - * @return 0 if successful. - */ -int mock_bpa_key_registry_init(const char *file_path); - -/** @warning Exposed only for testing. - * @param infd The file descriptor to read from. - */ -int mock_bpa_key_registry_init_jwk(int infd); - -/** @warning Exposed only for testing. - * @param infd The file descriptor to read from. - */ -int mock_bpa_key_registry_init_cosekey(int infd); - -/** - * Custom RNG function for BCB testing - */ -int mock_bpa_rfc9173_bcb_cek(unsigned char *buf, int len); - -#ifdef __cplusplus -} // extern C -#endif - -#endif diff --git a/src/bsl/mock_bpa/mock_bpa.c b/src/bsl/mock_bpa/mock_bpa.c index c761d53d..5aec854b 100644 --- a/src/bsl/mock_bpa/mock_bpa.c +++ b/src/bsl/mock_bpa/mock_bpa.c @@ -25,7 +25,7 @@ * unix domain sockets. */ #include "agent.h" -#include "key_registry.h" +#include "KeyStore.h" #include "log.h" #include "bsl/BPSecLib_Private.h" @@ -118,6 +118,25 @@ static void show_usage(const char *argv0) BSL_VERSION, argv0); } +/** + * Custom RNG function for BCB testing + */ +static int mock_bpa_rfc9173_bcb_cek(unsigned char *buf, int len) +{ + if (len == 12) // IV + { + uint8_t iv[] = { 0x54, 0x77, 0x65, 0x6c, 0x76, 0x65, 0x31, 0x32, 0x31, 0x32, 0x31, 0x32 }; + memcpy(buf, iv, 12); + } + else // A3 KEY + { + uint8_t rfc9173A3_key[] = { 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, + 0x6f, 0x70, 0x61, 0x73, 0x64, 0x66, 0x67, 0x68 }; + memcpy(buf, rfc9173A3_key, len); + } + return 1; +} + int main(int argc, char **argv) { int retval = 0; @@ -128,7 +147,7 @@ int main(int argc, char **argv) return 2; } mock_bpa_LogOpen(); - BSL_CryptoInit(); + MockBPA_KeyStore_Init(); if ((res = MockBPA_Agent_Init(&agent, &policy))) { BSL_LOG_ERR("Failed to initialize mock BPA, error %d", res); @@ -191,7 +210,7 @@ int main(int argc, char **argv) break; } case 'k': - if (mock_bpa_key_registry_init(optarg)) + if (MockBPA_KeyStore_LoadFile(optarg)) { retval = 1; } @@ -252,7 +271,7 @@ int main(int argc, char **argv) BSL_HostEID_Deinit(&sec_eid); BSL_HostEID_Deinit(&app_eid); - BSL_CryptoDeinit(); + MockBPA_KeyStore_Deinit(); mock_bpa_LogClose(); BSL_HostDescriptors_Clear(); return retval; diff --git a/test/DefaultScUtils.h b/test/DefaultScUtils.h index 48306bf9..2a5abd71 100644 --- a/test/DefaultScUtils.h +++ b/test/DefaultScUtils.h @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -55,7 +56,7 @@ static inline int BSL_Crypto_AddRegistryKeyName(const char *name, const uint8_t BSL_Crypto_KeyHandle_t keyhandle; BSL_Crypto_LoadKey(ptr, len, &keyhandle); BSL_Data_t key_id = BSL_DATA_INIT_VIEW_CSTR(name); - int res = BSL_Crypto_AddRegistryKey(&key_id, keyhandle); + int res = MockBPA_KeyStore_AddKey(&key_id, keyhandle); BSL_Crypto_ReleaseKeyHandle(keyhandle); return res; } @@ -68,10 +69,10 @@ static inline int BSL_Crypto_GetRegistryKeyName(const char *name, BSL_Crypto_Key } /// Test helper function -static inline int BSL_Crypto_RemoveRegistryKeyName(const char *name) +static inline int MockBPA_KeyStore_RemoveKeyName(const char *name) { BSL_Data_t key_id = BSL_DATA_INIT_VIEW_CSTR(name); - return BSL_Crypto_RemoveRegistryKey(&key_id); + return MockBPA_KeyStore_RemoveKey(&key_id); } /// @brief Sample policy provider ID diff --git a/test/fuzz_mock_bpa_keyregistry_cosekey.cpp b/test/fuzz_mock_bpa_keyregistry_cosekey.cpp index e5ff486d..73b2238a 100644 --- a/test/fuzz_mock_bpa_keyregistry_cosekey.cpp +++ b/test/fuzz_mock_bpa_keyregistry_cosekey.cpp @@ -26,7 +26,7 @@ #include "TestUtils.h" #include -#include +#include #include #include @@ -51,7 +51,7 @@ extern "C" int LLVMFuzzerInitialize(int *argc _U_, char ***argv _U_) extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { int retval = 0; - BSL_CryptoInit(); + MockBPA_KeyStore_Init(); FILE *tmp = tmpfile(); size_t got = fwrite(data, size, 1, tmp); @@ -65,13 +65,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) if (!retval) { int infd = fileno(tmp); - if (mock_bpa_key_registry_init_cosekey(infd)) + if (MockBPA_KeyStore_LoadCoseKeySet(infd)) { retval = -1; } } fclose(tmp); - BSL_CryptoDeinit(); + MockBPA_KeyStore_Deinit(); return retval; } diff --git a/test/fuzz_mock_bpa_keyregistry_jwk.cpp b/test/fuzz_mock_bpa_keyregistry_jwk.cpp index 8fb5d6e5..46d9549a 100644 --- a/test/fuzz_mock_bpa_keyregistry_jwk.cpp +++ b/test/fuzz_mock_bpa_keyregistry_jwk.cpp @@ -26,7 +26,7 @@ #include "TestUtils.h" #include -#include +#include #include #include @@ -51,7 +51,7 @@ extern "C" int LLVMFuzzerInitialize(int *argc _U_, char ***argv _U_) extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { int retval = 0; - BSL_CryptoInit(); + MockBPA_KeyStore_Init(); FILE *tmp = tmpfile(); size_t got = fwrite(data, size, 1, tmp); @@ -65,13 +65,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) if (!retval) { int infd = fileno(tmp); - if (mock_bpa_key_registry_init_jwk(infd)) + if (MockBPA_KeyStore_LoadJwk(infd)) { retval = -1; } } fclose(tmp); - BSL_CryptoDeinit(); + MockBPA_KeyStore_Deinit(); return retval; } diff --git a/test/test_BackendSecurityContext.c b/test/test_BackendSecurityContext.c index 21ea2bc1..591ac0b8 100644 --- a/test/test_BackendSecurityContext.c +++ b/test/test_BackendSecurityContext.c @@ -82,7 +82,7 @@ int suiteTearDown(int failures) void setUp(void) { - BSL_CryptoInit(); + MockBPA_KeyStore_Init(); setenv("BSL_TEST_LOCAL_IPN_EID", "ipn:2.1", 1); TEST_ASSERT_EQUAL(0, BSL_TestContext_Init(&LocalTestCtx)); BSL_TestUtils_SetupDefaultSecurityContext(&LocalTestCtx.bsl); @@ -90,7 +90,7 @@ void setUp(void) void tearDown(void) { - BSL_CryptoDeinit(); + MockBPA_KeyStore_Deinit(); TEST_ASSERT_EQUAL(0, BSL_TestContext_Deinit(&LocalTestCtx)); } diff --git a/test/test_CoseContext.c b/test/test_CoseContext.c index e452b18c..aaad40f7 100644 --- a/test/test_CoseContext.c +++ b/test/test_CoseContext.c @@ -60,13 +60,13 @@ int suiteTearDown(int failures) void setUp(void) { - BSL_CryptoInit(); + MockBPA_KeyStore_Init(); TEST_ASSERT_EQUAL(0, BSL_TestContext_Init(&LocalTestCtx)); } void tearDown(void) { - BSL_CryptoDeinit(); + MockBPA_KeyStore_Deinit(); TEST_ASSERT_EQUAL(0, BSL_TestContext_Deinit(&LocalTestCtx)); } @@ -284,11 +284,11 @@ void test_AppendixA_Example1_BIB_Source(void) TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_LoadKey(keymat.ptr, keymat.len, &keyhandle)); BSL_Data_Deinit(&keymat); - BSL_IdValPair_SetInt64(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), + BSL_IdValPair_SetInt64(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), BSLX_COSEMSG_KEY_PARAM_ALG, BSLX_COSEMSG_ALG_HMAC_SHA_384_384); BSL_Data_t keyid = BSL_DATA_INIT_VIEW_CSTR(exA_1_kid); - TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_AddRegistryKey(&keyid, keyhandle)); + TEST_ASSERT_EQUAL_INT(0, MockBPA_KeyStore_AddKey(&keyid, keyhandle)); } TEST_ASSERT_EQUAL(0, BSL_TestUtils_LoadBundleFromCBOR(&LocalTestCtx, exA_nosec)); @@ -402,11 +402,11 @@ void test_AppendixA_Example1_BIB_VerifyAccept(BSL_SecRole_e role, int mismatch) TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_LoadKey(keymat.ptr, keymat.len, &keyhandle)); BSL_Data_Deinit(&keymat); - BSL_IdValPair_SetInt64(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), + BSL_IdValPair_SetInt64(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), BSLX_COSEMSG_KEY_PARAM_ALG, BSLX_COSEMSG_ALG_HMAC_SHA_384_384); BSL_Data_t keyid = BSL_DATA_INIT_VIEW_CSTR(exA_1_kid); - TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_AddRegistryKey(&keyid, keyhandle)); + TEST_ASSERT_EQUAL_INT(0, MockBPA_KeyStore_AddKey(&keyid, keyhandle)); } TEST_ASSERT_EQUAL(0, BSL_TestUtils_LoadBundleFromCBOR(&LocalTestCtx, exA_1_mac0)); @@ -568,11 +568,11 @@ void test_CCSDS_Example_Mac_Source(void) TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_LoadKey(keymat.ptr, keymat.len, &keyhandle)); BSL_Data_Deinit(&keymat); - BSL_IdValPair_SetInt64(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), + BSL_IdValPair_SetInt64(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), BSLX_COSEMSG_KEY_PARAM_ALG, BSLX_COSEMSG_ALG_AES_KW_256); BSL_Data_t keyid = BSL_DATA_INIT_VIEW_CSTR(ccsds_mac_kid); - TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_AddRegistryKey(&keyid, keyhandle)); + TEST_ASSERT_EQUAL_INT(0, MockBPA_KeyStore_AddKey(&keyid, keyhandle)); } TEST_ASSERT_EQUAL(0, BSL_TestUtils_LoadBundleFromCBOR(&LocalTestCtx, ccsds_mac_nosec)); @@ -675,11 +675,11 @@ void test_CCSDS_Example_Mac_VerifyAccept(BSL_SecRole_e role, int mismatch) TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_LoadKey(keymat.ptr, keymat.len, &keyhandle)); BSL_Data_Deinit(&keymat); - BSL_IdValPair_SetInt64(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), + BSL_IdValPair_SetInt64(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), BSLX_COSEMSG_KEY_PARAM_ALG, BSLX_COSEMSG_ALG_AES_KW_256); BSL_Data_t keyid = BSL_DATA_INIT_VIEW_CSTR(ccsds_mac_kid); - TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_AddRegistryKey(&keyid, keyhandle)); + TEST_ASSERT_EQUAL_INT(0, MockBPA_KeyStore_AddKey(&keyid, keyhandle)); } TEST_ASSERT_EQUAL(0, BSL_TestUtils_LoadBundleFromCBOR(&LocalTestCtx, ccsds_mac_bib)); @@ -822,19 +822,19 @@ void test_AppendixA_Example4_BCB_Source(void) TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_LoadKey(keymat.ptr, keymat.len, &keyhandle)); BSL_Data_Deinit(&keymat); } - BSL_IdValPair_SetInt64(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), + BSL_IdValPair_SetInt64(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), BSLX_COSEMSG_KEY_PARAM_ALG, BSLX_COSEMSG_ALG_AES_GCM_256); { BSL_Data_t buf; BSL_Data_Init(&buf); TEST_ASSERT_EQUAL(0, BSL_TestUtils_DecodeBase16_cstr(&buf, exA_4_biv)); - BSL_IdValPair_SetBytestr(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_BASEIV), + BSL_IdValPair_SetBytestr(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_BASEIV), BSLX_COSEMSG_KEY_PARAM_BASEIV, buf); BSL_Data_Deinit(&buf); } BSL_Data_t keyid = BSL_DATA_INIT_VIEW_CSTR(exA_4_kid); - TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_AddRegistryKey(&keyid, keyhandle)); + TEST_ASSERT_EQUAL_INT(0, MockBPA_KeyStore_AddKey(&keyid, keyhandle)); } TEST_ASSERT_EQUAL(0, BSL_TestUtils_LoadBundleFromCBOR(&LocalTestCtx, exA_nosec)); @@ -946,19 +946,19 @@ void test_AppendixA_Example4_BCB_VerifyAccept(BSL_SecRole_e role, int mismatch) TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_LoadKey(keymat.ptr, keymat.len, &keyhandle)); BSL_Data_Deinit(&keymat); - BSL_IdValPair_SetInt64(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), + BSL_IdValPair_SetInt64(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), BSLX_COSEMSG_KEY_PARAM_ALG, BSLX_COSEMSG_ALG_AES_GCM_256); { BSL_Data_t buf; BSL_Data_Init(&buf); TEST_ASSERT_EQUAL(0, BSL_TestUtils_DecodeBase16_cstr(&buf, exA_4_biv)); - BSL_IdValPair_SetBytestr(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_BASEIV), + BSL_IdValPair_SetBytestr(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_BASEIV), BSLX_COSEMSG_KEY_PARAM_BASEIV, buf); BSL_Data_Deinit(&buf); } BSL_Data_t keyid = BSL_DATA_INIT_VIEW_CSTR(exA_4_kid); - TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_AddRegistryKey(&keyid, keyhandle)); + TEST_ASSERT_EQUAL_INT(0, MockBPA_KeyStore_AddKey(&keyid, keyhandle)); } TEST_ASSERT_EQUAL(0, BSL_TestUtils_LoadBundleFromCBOR(&LocalTestCtx, exA_4_enc0)); @@ -1125,11 +1125,11 @@ void test_AppendixA_Example5_BCB_Source(void) TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_LoadKey(keymat.ptr, keymat.len, &keyhandle)); BSL_Data_Deinit(&keymat); } - BSL_IdValPair_SetInt64(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), + BSL_IdValPair_SetInt64(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), BSLX_COSEMSG_KEY_PARAM_ALG, BSLX_COSEMSG_ALG_AES_KW_256); BSL_Data_t keyid = BSL_DATA_INIT_VIEW_CSTR(exA_5_kid); - TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_AddRegistryKey(&keyid, keyhandle)); + TEST_ASSERT_EQUAL_INT(0, MockBPA_KeyStore_AddKey(&keyid, keyhandle)); } TEST_ASSERT_EQUAL(0, BSL_TestUtils_LoadBundleFromCBOR(&LocalTestCtx, exA_nosec)); @@ -1232,11 +1232,11 @@ void test_AppendixA_Example5_BCB_VerifyAccept(BSL_SecRole_e role, int mismatch) TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_LoadKey(keymat.ptr, keymat.len, &keyhandle)); BSL_Data_Deinit(&keymat); - BSL_IdValPair_SetInt64(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), + BSL_IdValPair_SetInt64(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), BSLX_COSEMSG_KEY_PARAM_ALG, BSLX_COSEMSG_ALG_AES_KW_256); BSL_Data_t keyid = BSL_DATA_INIT_VIEW_CSTR(exA_5_kid); - TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_AddRegistryKey(&keyid, keyhandle)); + TEST_ASSERT_EQUAL_INT(0, MockBPA_KeyStore_AddKey(&keyid, keyhandle)); } TEST_ASSERT_EQUAL(0, BSL_TestUtils_LoadBundleFromCBOR(&LocalTestCtx, exA_5_enc)); @@ -1401,11 +1401,11 @@ void test_AppendixA_Example6_BCB_Source(void) TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_LoadKey(keymat.ptr, keymat.len, &keyhandle)); BSL_Data_Deinit(&keymat); } - BSL_IdValPair_SetInt64(BSL_Crypto_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), + BSL_IdValPair_SetInt64(MockBPA_KeyStore_SetKeyParameter(keyhandle, BSLX_COSEMSG_KEY_PARAM_ALG), BSLX_COSEMSG_KEY_PARAM_ALG, BSLX_COSEMSG_ALG_DIRECT_HKDF_SHA_512); BSL_Data_t keyid = BSL_DATA_INIT_VIEW_CSTR(exA_6_kid); - BSL_Crypto_AddRegistryKey(&keyid, keyhandle); + MockBPA_KeyStore_AddKey(&keyid, keyhandle); } TEST_ASSERT_EQUAL(0, BSL_TestUtils_LoadBundleFromCBOR(&LocalTestCtx, exA_nosec)); diff --git a/test/test_CryptoInterface.c b/test/test_CryptoInterface.c index 18b24f32..25491605 100644 --- a/test/test_CryptoInterface.c +++ b/test/test_CryptoInterface.c @@ -212,7 +212,7 @@ void setUp(void) { TEST_ASSERT_EQUAL(0, BSL_API_InitLib(&bsl)); - BSL_CryptoInit(); + MockBPA_KeyStore_Init(); // static keys uint8_t test1[20] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, @@ -237,7 +237,7 @@ void setUp(void) void tearDown(void) { - BSL_CryptoDeinit(); + MockBPA_KeyStore_Deinit(); TEST_ASSERT_EQUAL(0, BSL_API_DeinitLib(&bsl)); } @@ -456,8 +456,7 @@ void test_encrypt(const char *plaintext_in, const char *keyid) BSL_SeqReader_Destroy(reader); - res = BSL_Cipher_Deinit(&ctx); - TEST_ASSERT_EQUAL(0, res); + BSL_Cipher_Deinit(&ctx); BSL_Crypto_ReleaseKeyHandle(ekey); BSL_Data_Deinit(&iv); @@ -529,7 +528,7 @@ void test_decrypt(const char *plaintext_in, const char *keyid) TEST_ASSERT_EQUAL_MEMORY(plaintext_in, plaintext, pt_size); } - TEST_ASSERT_EQUAL(0, BSL_Cipher_Deinit(&ctx)); + BSL_Cipher_Deinit(&ctx); BSL_Crypto_ReleaseKeyHandle(ckey); BSL_Data_Deinit(&iv); @@ -600,8 +599,8 @@ void test_key_wrap(const char *kek, const char *cek, const char *expected) BSL_Data_Deinit(&kek_data); BSL_Data_Deinit(&cek_data); BSL_Data_Deinit(&wrapped_key); - BSL_Crypto_RemoveRegistryKeyName("kek"); - BSL_Crypto_RemoveRegistryKeyName("cek"); + MockBPA_KeyStore_RemoveKeyName("kek"); + MockBPA_KeyStore_RemoveKeyName("cek"); } // rfc3394 test vectors @@ -659,8 +658,8 @@ void test_key_unwrap(const char *kek, const char *expected_cek, const char *wrap BSL_Crypto_ReleaseKeyHandle(cek_handle); BSL_Crypto_ReleaseKeyHandle(expect_handle); BSL_Crypto_ReleaseKeyHandle(kek_handle); - BSL_Crypto_RemoveRegistryKeyName("kek"); - BSL_Crypto_RemoveRegistryKeyName("cek"); + MockBPA_KeyStore_RemoveKeyName("kek"); + MockBPA_KeyStore_RemoveKeyName("cek"); } // RFC 5869 test vectors @@ -831,7 +830,7 @@ void test_key_stats(void) BSL_Crypto_KeyHandle_t handle; BSL_Crypto_LoadKey(test_128, sizeof(test_128), &handle); TEST_ASSERT_NOT_NULL(handle); - TEST_ASSERT_EQUAL_INT(0, BSL_Crypto_AddRegistryKey(&key_id, handle)); + TEST_ASSERT_EQUAL_INT(0, MockBPA_KeyStore_AddKey(&key_id, handle)); test_encrypt("hello world!", "testkeystats"); diff --git a/test/test_DefaultSecurityContext.c b/test/test_DefaultSecurityContext.c index ef47bc92..78928a57 100644 --- a/test/test_DefaultSecurityContext.c +++ b/test/test_DefaultSecurityContext.c @@ -65,7 +65,7 @@ int suiteTearDown(int failures) void setUp(void) { - BSL_CryptoInit(); + MockBPA_KeyStore_Init(); setenv("BSL_TEST_LOCAL_IPN_EID", "ipn:2.1", 1); TEST_ASSERT_EQUAL(0, BSL_TestContext_Init(&LocalTestCtx)); BSL_TestUtils_SetupDefaultSecurityContext(&LocalTestCtx.bsl); @@ -73,7 +73,7 @@ void setUp(void) void tearDown(void) { - BSL_CryptoDeinit(); + MockBPA_KeyStore_Deinit(); TEST_ASSERT_EQUAL(0, BSL_TestContext_Deinit(&LocalTestCtx)); } diff --git a/test/test_DynamicMemCbs.c b/test/test_DynamicMemCbs.c index 80350278..36c14f86 100644 --- a/test/test_DynamicMemCbs.c +++ b/test/test_DynamicMemCbs.c @@ -94,7 +94,7 @@ int suiteTearDown(int failures) void _setUp(void) { setenv("BSL_TEST_LOCAL_IPN_EID", "ipn:2.1", 1); - BSL_CryptoInit(); + MockBPA_KeyStore_Init(); TEST_ASSERT_EQUAL(0, BSL_TestContext_Init(&LocalTestCtx)); BSL_TestUtils_SetupDefaultSecurityContext(&LocalTestCtx.bsl); @@ -149,7 +149,7 @@ void _tearDown(void) { BSL_SecurityActionSet_Deinit(&action_set); BSLP_PolicyProvider_Destroy(policy_provider); - BSL_CryptoDeinit(); + MockBPA_KeyStore_Deinit(); TEST_ASSERT_EQUAL(0, BSL_TestContext_Deinit(&LocalTestCtx)); BSL_IdValPair_Deinit(¶m_aes_variant_128); diff --git a/test/test_PublicInterfaceImpl.c b/test/test_PublicInterfaceImpl.c index ebc4a7bf..092c3454 100644 --- a/test/test_PublicInterfaceImpl.c +++ b/test/test_PublicInterfaceImpl.c @@ -118,7 +118,7 @@ void PublicInterfaceTestCtx_deinit(BSL_TestPublInterfaceCtx_t *ctx) void setUp(void) { setenv("BSL_TEST_LOCAL_IPN_EID", "ipn:2.1", 1); - BSL_CryptoInit(); + MockBPA_KeyStore_Init(); TEST_ASSERT_EQUAL(0, BSL_TestContext_Init(&LocalTestCtx)); BSL_TestUtils_SetupDefaultSecurityContext(&LocalTestCtx.bsl); BSL_SecurityActionSet_Init(&action_set); @@ -506,7 +506,7 @@ void setUp(void) void tearDown(void) { BSLP_PolicyProvider_Destroy(policy_provider); - BSL_CryptoDeinit(); + MockBPA_KeyStore_Deinit(); TEST_ASSERT_EQUAL(0, BSL_TestContext_Deinit(&LocalTestCtx)); BSL_SecurityActionSet_Deinit(&action_set); PublicInterfaceTestCtx_deinit(&ctx);