From: slontis Date: Mon, 1 Jul 2024 01:27:58 +0000 (+1000) Subject: Add FIPS indicator helpers X-Git-Tag: openssl-3.4.0-alpha1~362 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d4848934a61a668d16078f3118786c9a741b7efd;p=thirdparty%2Fopenssl.git Add FIPS indicator helpers Each provider algorithm context can use these helpers to add indicator support. Reviewed-by: Neil Horman Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24623) --- diff --git a/providers/common/include/prov/fipsindicator.h b/providers/common/include/prov/fipsindicator.h new file mode 100644 index 00000000000..fbfa7e0790d --- /dev/null +++ b/providers/common/include/prov/fipsindicator.h @@ -0,0 +1,130 @@ +/* + * Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifdef FIPS_MODULE + +# include /* OSSL_CALLBACK, OSSL_LIB_CTX */ +# include +# include "crypto/types.h" +# include + +/* + * There may be multiple settables associated with an algorithm that allow + * overriding the default status. + * We associate an id with each of these. + */ +# define OSSL_FIPS_IND_SETTABLE0 0 +# define OSSL_FIPS_IND_SETTABLE1 1 +# define OSSL_FIPS_IND_SETTABLE2 2 +# define OSSL_FIPS_IND_SETTABLE3 2 +# define OSSL_FIPS_IND_SETTABLE4 2 +# define OSSL_FIPS_IND_SETTABLE5 2 +# define OSSL_FIPS_IND_SETTABLE6 2 +# define OSSL_FIPS_IND_SETTABLE7 2 +# define OSSL_FIPS_IND_SETTABLE_MAX (1 + OSSL_FIPS_IND_SETTABLE7) + +/* Each settable is in one of 3 states */ +#define OSSL_FIPS_IND_STATE_UNKNOWN -1 /* Initial unknown state */ +#define OSSL_FIPS_IND_STATE_STRICT 1 /* Strict enforcement */ +#define OSSL_FIPS_IND_STATE_TOLERANT 0 /* Relaxation of rules */ + +/* + * For each algorithm context there may be multiple checks that determine if + * the algorithm is approved or not. These checks may be in different stages. + * To keep it simple it is assumed that the algorithm is initially approved, + * and may be unapproved when each check happens. Once unapproved the operation + * will remain unapproved (otherwise we need to maintain state for each check). + * The approved state should only be queried after the operation has completed + * e.g. A digest final, or a KDF derive. + * + * If a FIPS approved check fails then we must decide what to do in this case. + * In strict mode we would just return an error. + * To override strict mode we either need to have a settable variable or have a + * fips config flag that overrides strict mode. + * If there are multiple checks, each one could possible have a different + * configurable item. Each configurable item can be overriden by a different + * settable. + */ +typedef struct ossl_fips_ind_st { + unsigned int approved; + int settable[OSSL_FIPS_IND_SETTABLE_MAX]; /* See OSSL_FIPS_IND_STATE */ +} OSSL_FIPS_IND; + +typedef int (OSSL_FIPS_IND_CHECK_CB)(OSSL_LIB_CTX *libctx); + +int ossl_FIPS_IND_callback(OSSL_LIB_CTX *libctx, const char *type, + const char *desc); + +void ossl_FIPS_IND_init(OSSL_FIPS_IND *ind); +void ossl_FIPS_IND_set_approved(OSSL_FIPS_IND *ind); +void ossl_FIPS_IND_set_settable(OSSL_FIPS_IND *ind, int id, int enable); +int ossl_FIPS_IND_get_settable(const OSSL_FIPS_IND *ind, int id); +int ossl_FIPS_IND_on_unapproved(OSSL_FIPS_IND *ind, int id, OSSL_LIB_CTX *libctx, + const char *algname, const char *opname, + OSSL_FIPS_IND_CHECK_CB *config_check_fn); +int ossl_FIPS_IND_set_ctx_param(OSSL_FIPS_IND *ind, int id, + const OSSL_PARAM params[], const char *name); +int ossl_FIPS_IND_get_ctx_param(const OSSL_FIPS_IND *ind, + OSSL_PARAM params[]); +void ossl_FIPS_IND_copy(OSSL_FIPS_IND *dst, const OSSL_FIPS_IND *src); + +/* Place this in the algorithm ctx structure */ +# define OSSL_FIPS_IND_DECLARE OSSL_FIPS_IND indicator; +/* Call this to initialize the indicator */ +# define OSSL_FIPS_IND_INIT(ctx) ossl_FIPS_IND_init(&ctx->indicator); +/* + * Use the copy if an algorithm has a dup function that does not copy the src to + * the dst. + */ +# define OSSL_FIPS_IND_COPY(dst, src) ossl_FIPS_IND_copy(&dst->indicator, &src->indicator); + +/* + * Required for reset - since once something becomes unapproved it will remain + * unapproved unless this is used. This should be used in the init before + * params are set into the ctx & before any FIPS checks are done. + */ +# define OSSL_FIPS_IND_SET_APPROVED(ctx) ossl_FIPS_IND_set_approved(&ctx->indicator); +/* + * This should be called if a FIPS check fails, to indicate the operation is not approved + * If there is more than 1 strict check flag per algorithm ctx, the id represents + * the index. + */ +# define OSSL_FIPS_IND_ON_UNAPPROVED(ctx, id, libctx, algname, opname, config_check_fn) \ + ossl_FIPS_IND_on_unapproved(&ctx->indicator, id, libctx, algname, opname, config_check_fn) + +# define OSSL_FIPS_IND_SETTABLE_CTX_PARAM(name) \ + OSSL_PARAM_int(name, NULL), + +/* + * The id here must match the one used by OSSL_FIPS_IND_ON_UNAPPROVED + * The name must match the param used by OSSL_FIPS_IND_SETTABLE_CTX_PARAM + */ +# define OSSL_FIPS_IND_SET_CTX_PARAM(ctx, id, params, name) \ + ossl_FIPS_IND_set_ctx_param(&((ctx)->indicator), id, params, name) + +# define OSSL_FIPS_IND_GETTABLE_CTX_PARAM() \ + OSSL_PARAM_int(OSSL_ALG_PARAM_FIPS_APPROVED_INDICATOR, NULL), + +# define OSSL_FIPS_IND_GET_CTX_PARAM(ctx, prms) \ + ossl_FIPS_IND_get_ctx_param(&((ctx)->indicator), prms) + +#define OSSL_FIPS_IND_GET(ctx) &((ctx)->indicator) + +#else +# define OSSL_FIPS_IND_DECLARE +# define OSSL_FIPS_IND_INIT(ctx) +# define OSSL_FIPS_IND_SET_APPROVED(ctx) +# define OSSL_FIPS_IND_ON_UNAPPROVED(ctx, id, libctx, algname, opname, configopt_fn) +# define OSSL_FIPS_IND_SETTABLE_CTX_PARAM(name) +# define OSSL_FIPS_IND_SET_CTX_PARAM(ctx, id, params, name) 1 +# define OSSL_FIPS_IND_GETTABLE_CTX_PARAM() +# define OSSL_FIPS_IND_GET_CTX_PARAM(ctx, params) 1 +# define OSSL_FIPS_IND_COPY(dst, src) + +#endif diff --git a/providers/fips/build.info b/providers/fips/build.info index 2bfc58501e9..9756ad3f792 100644 --- a/providers/fips/build.info +++ b/providers/fips/build.info @@ -1,6 +1,6 @@ # We include the provider implementation into ../libfips.a, so that all # platforms can resolve symbols in other members of that library. -SOURCE[../libfips.a]=fipsprov.c self_test.c self_test_kats.c +SOURCE[../libfips.a]=fipsprov.c self_test.c self_test_kats.c fipsindicator.c # It is necessary to have an explicit entry point SOURCE[../fips]=fips_entry.c diff --git a/providers/fips/fipsindicator.c b/providers/fips/fipsindicator.c new file mode 100644 index 00000000000..9956c19884b --- /dev/null +++ b/providers/fips/fipsindicator.c @@ -0,0 +1,113 @@ +/* + * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include "prov/fipsindicator.h" +#include "internal/common.h" /* for ossl_assert() */ + +void ossl_FIPS_IND_init(OSSL_FIPS_IND *ind) +{ + ossl_FIPS_IND_set_approved(ind); /* Assume we are approved by default */ + memset(ind->settable, OSSL_FIPS_IND_STATE_UNKNOWN, sizeof(ind->settable)); +} + +void ossl_FIPS_IND_set_approved(OSSL_FIPS_IND *ind) +{ + ind->approved = 1; +} + +void ossl_FIPS_IND_copy(OSSL_FIPS_IND *dst, const OSSL_FIPS_IND *src) +{ + *dst = *src; +} + +void ossl_FIPS_IND_set_settable(OSSL_FIPS_IND *ind, int id, int state) +{ + if (!ossl_assert(id < OSSL_FIPS_IND_SETTABLE_MAX)) + return; + if (!ossl_assert(state == OSSL_FIPS_IND_STATE_STRICT + || state == OSSL_FIPS_IND_STATE_TOLERANT)) + return; + ind->settable[id] = state; +} + +int ossl_FIPS_IND_get_settable(const OSSL_FIPS_IND *ind, int id) +{ + if (!ossl_assert(id < OSSL_FIPS_IND_SETTABLE_MAX)) + return OSSL_FIPS_IND_STATE_UNKNOWN; + return ind->settable[id]; +} + +/* + * This should only be called when a strict FIPS algorithm check fails. + * It assumes that we are in strict mode by default. + * If the logic here is not sufficient for all cases, then additional + * ossl_FIPS_IND_on_unapproved() functions may be required. + */ +int ossl_FIPS_IND_on_unapproved(OSSL_FIPS_IND *ind, int id, + OSSL_LIB_CTX *libctx, + const char *algname, const char *opname, + OSSL_FIPS_IND_CHECK_CB *config_check_fn) +{ + /* Set to unapproved. Once unapproved mode is set this will not be reset */ + ind->approved = 0; + + /* + * We only trigger the indicator callback if the ctx variable is cleared OR + * the configurable item is cleared. If the values are unknown they are + * assumed to be strict. + */ + if (ossl_FIPS_IND_get_settable(ind, id) == OSSL_FIPS_IND_STATE_TOLERANT + || (config_check_fn != NULL + && config_check_fn(libctx) == OSSL_FIPS_IND_STATE_TOLERANT)) { + return ossl_FIPS_IND_callback(libctx, algname, opname); + } + /* Strict mode gets here: This returns an error */ + return 0; +} + +int ossl_FIPS_IND_set_ctx_param(OSSL_FIPS_IND *ind, int id, + const OSSL_PARAM params[], const char *name) +{ + int in = 0; + const OSSL_PARAM *p = OSSL_PARAM_locate_const(params, name); + + if (p != NULL) { + if (!OSSL_PARAM_get_int(p, &in)) + return 0; + ossl_FIPS_IND_set_settable(ind, id, in); + } + return 1; +} + +int ossl_FIPS_IND_get_ctx_param(const OSSL_FIPS_IND *ind, OSSL_PARAM params[]) +{ + OSSL_PARAM *p = OSSL_PARAM_locate(params, OSSL_ALG_PARAM_FIPS_APPROVED_INDICATOR); + + return p == NULL || OSSL_PARAM_set_int(p, ind->approved); +} + +/* + * Can be used during application testing to log that an indicator was + * triggered. The callback will return 1 if the application wants an error + * to occur based on the indicator type and description. + */ +int ossl_FIPS_IND_callback(OSSL_LIB_CTX *libctx, const char *type, + const char *desc) +{ + OSSL_INDICATOR_CALLBACK *cb = NULL; + + OSSL_INDICATOR_get_callback(libctx, &cb); + if (cb == NULL) + return 1; + + return cb(type, desc, NULL); +}