Path: blob/main/crypto/openssl/providers/fips/self_test.c
105194 views
/*1* Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#include <string.h>10#include <openssl/evp.h>11#include <openssl/params.h>12#include <openssl/crypto.h>13#include "internal/cryptlib.h"14#include <openssl/fipskey.h>15#include <openssl/err.h>16#include <openssl/proverr.h>17#include <openssl/rand.h>18#include "internal/e_os.h"19#include "internal/fips.h"20#include "internal/tsan_assist.h"21#include "prov/providercommon.h"22#include "crypto/rand.h"2324/*25* We're cheating here. Normally we don't allow RUN_ONCE usage inside the FIPS26* module because all such initialisation should be associated with an27* individual OSSL_LIB_CTX. That doesn't work with the self test though because28* it should be run once regardless of the number of OSSL_LIB_CTXs we have.29*/30#define ALLOW_RUN_ONCE_IN_FIPS31#include "internal/thread_once.h"32#include "self_test.h"3334#define FIPS_STATE_INIT 035#define FIPS_STATE_SELFTEST 136#define FIPS_STATE_RUNNING 237#define FIPS_STATE_ERROR 33839/*40* The number of times the module will report it is in the error state41* before going quiet.42*/43#define FIPS_ERROR_REPORTING_RATE_LIMIT 104445/* The size of a temp buffer used to read in data */46#define INTEGRITY_BUF_SIZE (4096)47#define MAX_MD_SIZE 6448#define MAC_NAME "HMAC"49#define DIGEST_NAME "SHA256"5051static int FIPS_conditional_error_check = 1;52static CRYPTO_RWLOCK *self_test_lock = NULL;5354static CRYPTO_ONCE fips_self_test_init = CRYPTO_ONCE_STATIC_INIT;55#if !defined(OPENSSL_NO_FIPS_POST)56static unsigned char fixed_key[32] = { FIPS_KEY_ELEMENTS };57#endif5859DEFINE_RUN_ONCE_STATIC(do_fips_self_test_init)60{61/*62* These locks get freed in platform specific ways that may occur after we63* do mem leak checking. If we don't know how to free it for a particular64* platform then we just leak it deliberately.65*/66self_test_lock = CRYPTO_THREAD_lock_new();67return self_test_lock != NULL;68}6970/*71* Declarations for the DEP entry/exit points.72* Ones not required or incorrect need to be undefined or redefined respectively.73*/74#define DEP_INITIAL_STATE FIPS_STATE_INIT75#define DEP_INIT_ATTRIBUTE static76#define DEP_FINI_ATTRIBUTE static7778static void init(void);79static void cleanup(void);8081/*82* This is the Default Entry Point (DEP) code.83* See FIPS 140-2 IG 9.1084*/85#if defined(_WIN32) || defined(__CYGWIN__)86#ifdef __CYGWIN__87/* pick DLL_[PROCESS|THREAD]_[ATTACH|DETACH] definitions */88#include <windows.h>89/*90* this has side-effect of _WIN32 getting defined, which otherwise is91* mutually exclusive with __CYGWIN__...92*/93#endif9495BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);96BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)97{98switch (fdwReason) {99case DLL_PROCESS_ATTACH:100init();101break;102case DLL_PROCESS_DETACH:103cleanup();104break;105default:106break;107}108return TRUE;109}110111#elif defined(__GNUC__) && !defined(_AIX)112#undef DEP_INIT_ATTRIBUTE113#undef DEP_FINI_ATTRIBUTE114#define DEP_INIT_ATTRIBUTE static __attribute__((constructor))115#define DEP_FINI_ATTRIBUTE static __attribute__((destructor))116117#elif defined(__sun)118#pragma init(init)119#pragma fini(cleanup)120121#elif defined(_AIX) && !defined(__GNUC__)122void _init(void);123void _cleanup(void);124#pragma init(_init)125#pragma fini(_cleanup)126void _init(void)127{128init();129}130void _cleanup(void)131{132cleanup();133}134135#elif defined(__hpux)136#pragma init "init"137#pragma fini "cleanup"138139#elif defined(__TANDEM)140/* Method automatically called by the NonStop OS when the DLL loads */141void __INIT__init(void)142{143init();144}145146/* Method automatically called by the NonStop OS prior to unloading the DLL */147void __TERM__cleanup(void)148{149cleanup();150}151152#else153/*154* This build does not support any kind of DEP.155* We force the self-tests to run as part of the FIPS provider initialisation156* rather than being triggered by the DEP.157*/158#undef DEP_INIT_ATTRIBUTE159#undef DEP_FINI_ATTRIBUTE160#undef DEP_INITIAL_STATE161#define DEP_INITIAL_STATE FIPS_STATE_SELFTEST162#endif163164static TSAN_QUALIFIER int FIPS_state = DEP_INITIAL_STATE;165166#if defined(DEP_INIT_ATTRIBUTE)167DEP_INIT_ATTRIBUTE void init(void)168{169tsan_store(&FIPS_state, FIPS_STATE_SELFTEST);170}171#endif172173#if defined(DEP_FINI_ATTRIBUTE)174DEP_FINI_ATTRIBUTE void cleanup(void)175{176CRYPTO_THREAD_lock_free(self_test_lock);177}178#endif179180#if !defined(OPENSSL_NO_FIPS_POST)181/*182* We need an explicit HMAC-SHA-256 KAT even though it is also183* checked as part of the KDF KATs. Refer IG 10.3.184*/185static const unsigned char hmac_kat_pt[] = {1860xdd, 0x0c, 0x30, 0x33, 0x35, 0xf9, 0xe4, 0x2e,1870xc2, 0xef, 0xcc, 0xbf, 0x07, 0x95, 0xee, 0xa2188};189static const unsigned char hmac_kat_key[] = {1900xf4, 0x55, 0x66, 0x50, 0xac, 0x31, 0xd3, 0x54,1910x61, 0x61, 0x0b, 0xac, 0x4e, 0xd8, 0x1b, 0x1a,1920x18, 0x1b, 0x2d, 0x8a, 0x43, 0xea, 0x28, 0x54,1930xcb, 0xae, 0x22, 0xca, 0x74, 0x56, 0x08, 0x13194};195static const unsigned char hmac_kat_digest[] = {1960xf5, 0xf5, 0xe5, 0xf2, 0x66, 0x49, 0xe2, 0x40,1970xfc, 0x9e, 0x85, 0x7f, 0x2b, 0x9a, 0xbe, 0x28,1980x20, 0x12, 0x00, 0x92, 0x82, 0x21, 0x3e, 0x51,1990x44, 0x5d, 0xe3, 0x31, 0x04, 0x01, 0x72, 0x6b200};201202static int integrity_self_test(OSSL_SELF_TEST *ev, OSSL_LIB_CTX *libctx)203{204int ok = 0;205unsigned char out[EVP_MAX_MD_SIZE];206size_t out_len = 0;207208OSSL_PARAM params[2];209EVP_MAC *mac = EVP_MAC_fetch(libctx, MAC_NAME, NULL);210EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(mac);211212OSSL_SELF_TEST_onbegin(ev, OSSL_SELF_TEST_TYPE_KAT_INTEGRITY,213OSSL_SELF_TEST_DESC_INTEGRITY_HMAC);214215params[0] = OSSL_PARAM_construct_utf8_string("digest", DIGEST_NAME, 0);216params[1] = OSSL_PARAM_construct_end();217218if (ctx == NULL219|| mac == NULL220|| !EVP_MAC_init(ctx, hmac_kat_key, sizeof(hmac_kat_key), params)221|| !EVP_MAC_update(ctx, hmac_kat_pt, sizeof(hmac_kat_pt))222|| !EVP_MAC_final(ctx, out, &out_len, MAX_MD_SIZE))223goto err;224225/* Optional corruption */226OSSL_SELF_TEST_oncorrupt_byte(ev, out);227228if (out_len != sizeof(hmac_kat_digest)229|| memcmp(out, hmac_kat_digest, out_len) != 0)230goto err;231ok = 1;232err:233OSSL_SELF_TEST_onend(ev, ok);234EVP_MAC_free(mac);235EVP_MAC_CTX_free(ctx);236return ok;237}238239/*240* Calculate the HMAC SHA256 of data read using a BIO and read_cb, and verify241* the result matches the expected value.242* Return 1 if verified, or 0 if it fails.243*/244static int verify_integrity(OSSL_CORE_BIO *bio, OSSL_FUNC_BIO_read_ex_fn read_ex_cb,245unsigned char *expected, size_t expected_len,246OSSL_LIB_CTX *libctx, OSSL_SELF_TEST *ev,247const char *event_type)248{249int ret = 0, status;250unsigned char out[MAX_MD_SIZE];251unsigned char buf[INTEGRITY_BUF_SIZE];252size_t bytes_read = 0, out_len = 0;253EVP_MAC *mac = NULL;254EVP_MAC_CTX *ctx = NULL;255OSSL_PARAM params[2], *p = params;256257if (!integrity_self_test(ev, libctx))258goto err;259260OSSL_SELF_TEST_onbegin(ev, event_type, OSSL_SELF_TEST_DESC_INTEGRITY_HMAC);261262mac = EVP_MAC_fetch(libctx, MAC_NAME, NULL);263if (mac == NULL)264goto err;265ctx = EVP_MAC_CTX_new(mac);266if (ctx == NULL)267goto err;268269*p++ = OSSL_PARAM_construct_utf8_string("digest", DIGEST_NAME, 0);270*p = OSSL_PARAM_construct_end();271272if (!EVP_MAC_init(ctx, fixed_key, sizeof(fixed_key), params))273goto err;274275while (1) {276status = read_ex_cb(bio, buf, sizeof(buf), &bytes_read);277if (status != 1)278break;279if (!EVP_MAC_update(ctx, buf, bytes_read))280goto err;281}282if (!EVP_MAC_final(ctx, out, &out_len, sizeof(out)))283goto err;284285OSSL_SELF_TEST_oncorrupt_byte(ev, out);286if (expected_len != out_len287|| memcmp(expected, out, out_len) != 0)288goto err;289ret = 1;290err:291OSSL_SELF_TEST_onend(ev, ret);292EVP_MAC_CTX_free(ctx);293EVP_MAC_free(mac);294#ifdef OPENSSL_PEDANTIC_ZEROIZATION295OPENSSL_cleanse(out, sizeof(out));296#endif297return ret;298}299#endif /* OPENSSL_NO_FIPS_POST */300301static void set_fips_state(int state)302{303tsan_store(&FIPS_state, state);304}305306/* Return 1 if the FIPS self tests are running and 0 otherwise */307int ossl_fips_self_testing(void)308{309return tsan_load(&FIPS_state) == FIPS_STATE_SELFTEST;310}311312/* This API is triggered either on loading of the FIPS module or on demand */313int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test)314{315int loclstate;316#if !defined(OPENSSL_NO_FIPS_POST)317int ok = 0;318long checksum_len;319OSSL_CORE_BIO *bio_module = NULL;320unsigned char *module_checksum = NULL;321OSSL_SELF_TEST *ev = NULL;322EVP_RAND *testrand = NULL;323EVP_RAND_CTX *rng;324#endif325326if (!RUN_ONCE(&fips_self_test_init, do_fips_self_test_init))327return 0;328329loclstate = tsan_load(&FIPS_state);330331if (loclstate == FIPS_STATE_RUNNING) {332if (!on_demand_test)333return 1;334} else if (loclstate != FIPS_STATE_SELFTEST) {335ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_STATE);336return 0;337}338339if (!CRYPTO_THREAD_write_lock(self_test_lock))340return 0;341342#if !defined(OPENSSL_NO_FIPS_POST)343loclstate = tsan_load(&FIPS_state);344if (loclstate == FIPS_STATE_RUNNING) {345if (!on_demand_test) {346CRYPTO_THREAD_unlock(self_test_lock);347return 1;348}349set_fips_state(FIPS_STATE_SELFTEST);350} else if (loclstate != FIPS_STATE_SELFTEST) {351CRYPTO_THREAD_unlock(self_test_lock);352ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_STATE);353return 0;354}355356if (st == NULL357|| st->module_checksum_data == NULL) {358ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CONFIG_DATA);359goto end;360}361362ev = OSSL_SELF_TEST_new(st->cb, st->cb_arg);363if (ev == NULL)364goto end;365366module_checksum = OPENSSL_hexstr2buf(st->module_checksum_data,367&checksum_len);368if (module_checksum == NULL) {369ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CONFIG_DATA);370goto end;371}372bio_module = (*st->bio_new_file_cb)(st->module_filename, "rb");373374/* Always check the integrity of the fips module */375if (bio_module == NULL376|| !verify_integrity(bio_module, st->bio_read_ex_cb,377module_checksum, checksum_len, st->libctx,378ev, OSSL_SELF_TEST_TYPE_MODULE_INTEGRITY)) {379ERR_raise(ERR_LIB_PROV, PROV_R_MODULE_INTEGRITY_FAILURE);380goto end;381}382383if (!SELF_TEST_kats(ev, st->libctx)) {384ERR_raise(ERR_LIB_PROV, PROV_R_SELF_TEST_KAT_FAILURE);385goto end;386}387388/* Verify that the RNG has been restored properly */389rng = ossl_rand_get0_private_noncreating(st->libctx);390if (rng != NULL)391if ((testrand = EVP_RAND_fetch(st->libctx, "TEST-RAND", NULL)) == NULL392|| strcmp(EVP_RAND_get0_name(EVP_RAND_CTX_get0_rand(rng)),393EVP_RAND_get0_name(testrand))394== 0) {395ERR_raise(ERR_LIB_PROV, PROV_R_SELF_TEST_KAT_FAILURE);396goto end;397}398399ok = 1;400end:401EVP_RAND_free(testrand);402OSSL_SELF_TEST_free(ev);403OPENSSL_free(module_checksum);404405if (st != NULL)406(*st->bio_free_cb)(bio_module);407408if (ok)409set_fips_state(FIPS_STATE_RUNNING);410else411ossl_set_error_state(OSSL_SELF_TEST_TYPE_NONE);412CRYPTO_THREAD_unlock(self_test_lock);413414return ok;415#else416set_fips_state(FIPS_STATE_RUNNING);417CRYPTO_THREAD_unlock(self_test_lock);418return 1;419#endif /* !defined(OPENSSL_NO_FIPS_POST) */420}421422void SELF_TEST_disable_conditional_error_state(void)423{424FIPS_conditional_error_check = 0;425}426427void ossl_set_error_state(const char *type)428{429int cond_test = 0;430int import_pct = 0;431432if (type != NULL) {433cond_test = strcmp(type, OSSL_SELF_TEST_TYPE_PCT) == 0;434import_pct = strcmp(type, OSSL_SELF_TEST_TYPE_PCT_IMPORT) == 0;435}436437if (import_pct) {438/* Failure to import is transient to avoid a DoS attack */439ERR_raise(ERR_LIB_PROV, PROV_R_FIPS_MODULE_IMPORT_PCT_ERROR);440} else if (!cond_test || (FIPS_conditional_error_check == 1)) {441set_fips_state(FIPS_STATE_ERROR);442ERR_raise(ERR_LIB_PROV, PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE);443} else {444ERR_raise(ERR_LIB_PROV, PROV_R_FIPS_MODULE_CONDITIONAL_ERROR);445}446}447448int ossl_prov_is_running(void)449{450int res, loclstate;451static TSAN_QUALIFIER unsigned int rate_limit = 0;452453loclstate = tsan_load(&FIPS_state);454res = loclstate == FIPS_STATE_RUNNING || loclstate == FIPS_STATE_SELFTEST;455if (loclstate == FIPS_STATE_ERROR)456if (tsan_counter(&rate_limit) < FIPS_ERROR_REPORTING_RATE_LIMIT)457ERR_raise(ERR_LIB_PROV, PROV_R_FIPS_MODULE_IN_ERROR_STATE);458return res;459}460461462