]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add FIPS indicator helpers
authorslontis <shane.lontis@oracle.com>
Mon, 1 Jul 2024 01:27:58 +0000 (11:27 +1000)
committerPauli <ppzgs1@gmail.com>
Wed, 10 Jul 2024 22:29:43 +0000 (08:29 +1000)
Each provider algorithm context can use these helpers to add indicator
support.

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/24623)

providers/common/include/prov/fipsindicator.h [new file with mode: 0644]
providers/fips/build.info
providers/fips/fipsindicator.c [new file with mode: 0644]

diff --git a/providers/common/include/prov/fipsindicator.h b/providers/common/include/prov/fipsindicator.h
new file mode 100644 (file)
index 0000000..fbfa7e0
--- /dev/null
@@ -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 <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
index 2bfc58501e941b429d1dd9ae153c5f0e5f2d1b69..9756ad3f792d16861d0cab09609d124d820bb1d8 100644 (file)
@@ -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 (file)
index 0000000..9956c19
--- /dev/null
@@ -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 <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);
+}