Path: blob/main/crypto/openssl/providers/fips/self_test.c
48261 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) {142init();143}144145/* Method automatically called by the NonStop OS prior to unloading the DLL */146void __TERM__cleanup(void) {147cleanup();148}149150#else151/*152* This build does not support any kind of DEP.153* We force the self-tests to run as part of the FIPS provider initialisation154* rather than being triggered by the DEP.155*/156# undef DEP_INIT_ATTRIBUTE157# undef DEP_FINI_ATTRIBUTE158# undef DEP_INITIAL_STATE159# define DEP_INITIAL_STATE FIPS_STATE_SELFTEST160#endif161162static TSAN_QUALIFIER int FIPS_state = DEP_INITIAL_STATE;163164#if defined(DEP_INIT_ATTRIBUTE)165DEP_INIT_ATTRIBUTE void init(void)166{167tsan_store(&FIPS_state, FIPS_STATE_SELFTEST);168}169#endif170171#if defined(DEP_FINI_ATTRIBUTE)172DEP_FINI_ATTRIBUTE void cleanup(void)173{174CRYPTO_THREAD_lock_free(self_test_lock);175}176#endif177178#if !defined(OPENSSL_NO_FIPS_POST)179/*180* We need an explicit HMAC-SHA-256 KAT even though it is also181* checked as part of the KDF KATs. Refer IG 10.3.182*/183static const unsigned char hmac_kat_pt[] = {1840xdd, 0x0c, 0x30, 0x33, 0x35, 0xf9, 0xe4, 0x2e,1850xc2, 0xef, 0xcc, 0xbf, 0x07, 0x95, 0xee, 0xa2186};187static const unsigned char hmac_kat_key[] = {1880xf4, 0x55, 0x66, 0x50, 0xac, 0x31, 0xd3, 0x54,1890x61, 0x61, 0x0b, 0xac, 0x4e, 0xd8, 0x1b, 0x1a,1900x18, 0x1b, 0x2d, 0x8a, 0x43, 0xea, 0x28, 0x54,1910xcb, 0xae, 0x22, 0xca, 0x74, 0x56, 0x08, 0x13192};193static const unsigned char hmac_kat_digest[] = {1940xf5, 0xf5, 0xe5, 0xf2, 0x66, 0x49, 0xe2, 0x40,1950xfc, 0x9e, 0x85, 0x7f, 0x2b, 0x9a, 0xbe, 0x28,1960x20, 0x12, 0x00, 0x92, 0x82, 0x21, 0x3e, 0x51,1970x44, 0x5d, 0xe3, 0x31, 0x04, 0x01, 0x72, 0x6b198};199200static int integrity_self_test(OSSL_SELF_TEST *ev, OSSL_LIB_CTX *libctx)201{202int ok = 0;203unsigned char out[EVP_MAX_MD_SIZE];204size_t out_len = 0;205206OSSL_PARAM params[2];207EVP_MAC *mac = EVP_MAC_fetch(libctx, MAC_NAME, NULL);208EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(mac);209210OSSL_SELF_TEST_onbegin(ev, OSSL_SELF_TEST_TYPE_KAT_INTEGRITY,211OSSL_SELF_TEST_DESC_INTEGRITY_HMAC);212213params[0] = OSSL_PARAM_construct_utf8_string("digest", DIGEST_NAME, 0);214params[1] = OSSL_PARAM_construct_end();215216if (ctx == NULL217|| mac == NULL218|| !EVP_MAC_init(ctx, hmac_kat_key, sizeof(hmac_kat_key), params)219|| !EVP_MAC_update(ctx, hmac_kat_pt, sizeof(hmac_kat_pt))220|| !EVP_MAC_final(ctx, out, &out_len, MAX_MD_SIZE))221goto err;222223/* Optional corruption */224OSSL_SELF_TEST_oncorrupt_byte(ev, out);225226if (out_len != sizeof(hmac_kat_digest)227|| memcmp(out, hmac_kat_digest, out_len) != 0)228goto err;229ok = 1;230err:231OSSL_SELF_TEST_onend(ev, ok);232EVP_MAC_free(mac);233EVP_MAC_CTX_free(ctx);234return ok;235}236237/*238* Calculate the HMAC SHA256 of data read using a BIO and read_cb, and verify239* the result matches the expected value.240* Return 1 if verified, or 0 if it fails.241*/242static int verify_integrity(OSSL_CORE_BIO *bio, OSSL_FUNC_BIO_read_ex_fn read_ex_cb,243unsigned char *expected, size_t expected_len,244OSSL_LIB_CTX *libctx, OSSL_SELF_TEST *ev,245const char *event_type)246{247int ret = 0, status;248unsigned char out[MAX_MD_SIZE];249unsigned char buf[INTEGRITY_BUF_SIZE];250size_t bytes_read = 0, out_len = 0;251EVP_MAC *mac = NULL;252EVP_MAC_CTX *ctx = NULL;253OSSL_PARAM params[2], *p = params;254255if (!integrity_self_test(ev, libctx))256goto err;257258OSSL_SELF_TEST_onbegin(ev, event_type, OSSL_SELF_TEST_DESC_INTEGRITY_HMAC);259260mac = EVP_MAC_fetch(libctx, MAC_NAME, NULL);261if (mac == NULL)262goto err;263ctx = EVP_MAC_CTX_new(mac);264if (ctx == NULL)265goto err;266267*p++ = OSSL_PARAM_construct_utf8_string("digest", DIGEST_NAME, 0);268*p = OSSL_PARAM_construct_end();269270if (!EVP_MAC_init(ctx, fixed_key, sizeof(fixed_key), params))271goto err;272273while (1) {274status = read_ex_cb(bio, buf, sizeof(buf), &bytes_read);275if (status != 1)276break;277if (!EVP_MAC_update(ctx, buf, bytes_read))278goto err;279}280if (!EVP_MAC_final(ctx, out, &out_len, sizeof(out)))281goto err;282283OSSL_SELF_TEST_oncorrupt_byte(ev, out);284if (expected_len != out_len285|| memcmp(expected, out, out_len) != 0)286goto err;287ret = 1;288err:289OSSL_SELF_TEST_onend(ev, ret);290EVP_MAC_CTX_free(ctx);291EVP_MAC_free(mac);292# ifdef OPENSSL_PEDANTIC_ZEROIZATION293OPENSSL_cleanse(out, sizeof(out));294# endif295return ret;296}297#endif /* OPENSSL_NO_FIPS_POST */298299static void set_fips_state(int state)300{301tsan_store(&FIPS_state, state);302}303304/* Return 1 if the FIPS self tests are running and 0 otherwise */305int ossl_fips_self_testing(void)306{307return tsan_load(&FIPS_state) == FIPS_STATE_SELFTEST;308}309310/* This API is triggered either on loading of the FIPS module or on demand */311int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test)312{313int loclstate;314#if !defined(OPENSSL_NO_FIPS_POST)315int ok = 0;316long checksum_len;317OSSL_CORE_BIO *bio_module = NULL;318unsigned char *module_checksum = NULL;319OSSL_SELF_TEST *ev = NULL;320EVP_RAND *testrand = NULL;321EVP_RAND_CTX *rng;322#endif323324if (!RUN_ONCE(&fips_self_test_init, do_fips_self_test_init))325return 0;326327loclstate = tsan_load(&FIPS_state);328329if (loclstate == FIPS_STATE_RUNNING) {330if (!on_demand_test)331return 1;332} else if (loclstate != FIPS_STATE_SELFTEST) {333ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_STATE);334return 0;335}336337if (!CRYPTO_THREAD_write_lock(self_test_lock))338return 0;339340#if !defined(OPENSSL_NO_FIPS_POST)341loclstate = tsan_load(&FIPS_state);342if (loclstate == FIPS_STATE_RUNNING) {343if (!on_demand_test) {344CRYPTO_THREAD_unlock(self_test_lock);345return 1;346}347set_fips_state(FIPS_STATE_SELFTEST);348} else if (loclstate != FIPS_STATE_SELFTEST) {349CRYPTO_THREAD_unlock(self_test_lock);350ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_STATE);351return 0;352}353354if (st == NULL355|| st->module_checksum_data == NULL) {356ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CONFIG_DATA);357goto end;358}359360ev = OSSL_SELF_TEST_new(st->cb, st->cb_arg);361if (ev == NULL)362goto end;363364module_checksum = OPENSSL_hexstr2buf(st->module_checksum_data,365&checksum_len);366if (module_checksum == NULL) {367ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CONFIG_DATA);368goto end;369}370bio_module = (*st->bio_new_file_cb)(st->module_filename, "rb");371372/* Always check the integrity of the fips module */373if (bio_module == NULL374|| !verify_integrity(bio_module, st->bio_read_ex_cb,375module_checksum, checksum_len, st->libctx,376ev, OSSL_SELF_TEST_TYPE_MODULE_INTEGRITY)) {377ERR_raise(ERR_LIB_PROV, PROV_R_MODULE_INTEGRITY_FAILURE);378goto end;379}380381if (!SELF_TEST_kats(ev, st->libctx)) {382ERR_raise(ERR_LIB_PROV, PROV_R_SELF_TEST_KAT_FAILURE);383goto end;384}385386/* Verify that the RNG has been restored properly */387rng = ossl_rand_get0_private_noncreating(st->libctx);388if (rng != NULL)389if ((testrand = EVP_RAND_fetch(st->libctx, "TEST-RAND", NULL)) == NULL390|| strcmp(EVP_RAND_get0_name(EVP_RAND_CTX_get0_rand(rng)),391EVP_RAND_get0_name(testrand)) == 0) {392ERR_raise(ERR_LIB_PROV, PROV_R_SELF_TEST_KAT_FAILURE);393goto end;394}395396ok = 1;397end:398EVP_RAND_free(testrand);399OSSL_SELF_TEST_free(ev);400OPENSSL_free(module_checksum);401402if (st != NULL)403(*st->bio_free_cb)(bio_module);404405if (ok)406set_fips_state(FIPS_STATE_RUNNING);407else408ossl_set_error_state(OSSL_SELF_TEST_TYPE_NONE);409CRYPTO_THREAD_unlock(self_test_lock);410411return ok;412#else413set_fips_state(FIPS_STATE_RUNNING);414CRYPTO_THREAD_unlock(self_test_lock);415return 1;416#endif /* !defined(OPENSSL_NO_FIPS_POST) */417}418419void SELF_TEST_disable_conditional_error_state(void)420{421FIPS_conditional_error_check = 0;422}423424void ossl_set_error_state(const char *type)425{426int cond_test = 0;427int import_pct = 0;428429if (type != NULL) {430cond_test = strcmp(type, OSSL_SELF_TEST_TYPE_PCT) == 0;431import_pct = strcmp(type, OSSL_SELF_TEST_TYPE_PCT_IMPORT) == 0;432}433434if (import_pct) {435/* Failure to import is transient to avoid a DoS attack */436ERR_raise(ERR_LIB_PROV, PROV_R_FIPS_MODULE_IMPORT_PCT_ERROR);437} else if (!cond_test || (FIPS_conditional_error_check == 1)) {438set_fips_state(FIPS_STATE_ERROR);439ERR_raise(ERR_LIB_PROV, PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE);440} else {441ERR_raise(ERR_LIB_PROV, PROV_R_FIPS_MODULE_CONDITIONAL_ERROR);442}443}444445int ossl_prov_is_running(void)446{447int res, loclstate;448static TSAN_QUALIFIER unsigned int rate_limit = 0;449450loclstate = tsan_load(&FIPS_state);451res = loclstate == FIPS_STATE_RUNNING || loclstate == FIPS_STATE_SELFTEST;452if (loclstate == FIPS_STATE_ERROR)453if (tsan_counter(&rate_limit) < FIPS_ERROR_REPORTING_RATE_LIMIT)454ERR_raise(ERR_LIB_PROV, PROV_R_FIPS_MODULE_IN_ERROR_STATE);455return res;456}457458459