--- /dev/null
+/*
+ * 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 <openssl/core.h> /* OSSL_CALLBACK, OSSL_LIB_CTX */
+# include <openssl/indicator.h>
+# include "crypto/types.h"
+# include <openssl/ec.h>
+
+/*
+ * 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
--- /dev/null
+/*
+ * 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 <openssl/indicator.h>
+#include <openssl/params.h>
+#include <openssl/core_names.h>
+#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);
+}