isaacpittman-hitachi / rpms / openssl

Forked from rpms/openssl 2 years ago
Clone
727bdf
From e3d6fca1af033d00c47bcd8f9ba28fcf1aa476aa Mon Sep 17 00:00:00 2001
727bdf
From: Clemens Lang <cllang@redhat.com>
727bdf
Date: Tue, 7 Jun 2022 12:02:49 +0200
727bdf
Subject: [PATCH] fips: Expose a FIPS indicator
727bdf
727bdf
FIPS 140-3 requires us to indicate whether an operation was using
727bdf
approved services or not. The FIPS 140-3 implementation guidelines
727bdf
provide two basic approaches to doing this: implicit indicators, and
727bdf
explicit indicators.
727bdf
727bdf
Implicit indicators are basically the concept of "if the operation
727bdf
passes, it was approved". We were originally aiming for implicit
727bdf
indicators in our copy of OpenSSL. However, this proved to be a problem,
727bdf
because we wanted to certify a signature service, and FIPS 140-3
727bdf
requires that a signature service computes the digest to be signed
727bdf
within the boundaries of the FIPS module. Since we were planning to
727bdf
certify fips.so only, this means that EVP_PKEY_sign/EVP_PKEY_verify
727bdf
would have to be blocked. Unfortunately, EVP_SignFinal uses
727bdf
EVP_PKEY_sign internally, but outside of fips.so and thus outside of the
727bdf
FIPS module boundary. This means that using implicit indicators in
727bdf
combination with certifying only fips.so would require us to block both
727bdf
EVP_PKEY_sign and EVP_SignFinal, which are the two APIs currently used
727bdf
by most users of OpenSSL for signatures.
727bdf
727bdf
EVP_DigestSign would be acceptable, but has only been added in 3.0 and
727bdf
is thus not yet widely used.
727bdf
727bdf
As a consequence, we've decided to introduce explicit indicators so that
727bdf
EVP_PKEY_sign and EVP_SignFinal can continue to work for now, but
727bdf
FIPS-aware applications can query the explicit indicator to check
727bdf
whether the operation was approved.
727bdf
727bdf
To avoid affecting the ABI and public API too much, this is implemented
727bdf
as an exported symbol in fips.so and a private header, so applications
727bdf
that wish to use this will have to dlopen(3) fips.so, locate the
727bdf
function using dlsym(3), and then call it. These applications will have
727bdf
to build against the private header in order to use the returned
727bdf
pointer.
727bdf
727bdf
Modify util/mkdef.pl to support exposing a symbol only for a specific
727bdf
provider identified by its name and path.
727bdf
727bdf
Signed-off-by: Clemens Lang <cllang@redhat.com>
727bdf
---
727bdf
 doc/build.info                      |   6 ++
727bdf
 doc/man7/fips_module_indicators.pod | 154 ++++++++++++++++++++++++++++
727bdf
 providers/fips/fipsprov.c           |  71 +++++++++++++
727bdf
 providers/fips/indicator.h          |  66 ++++++++++++
727bdf
 util/mkdef.pl                       |  25 ++++-
727bdf
 util/providers.num                  |   1 +
727bdf
 6 files changed, 322 insertions(+), 1 deletion(-)
727bdf
 create mode 100644 doc/man7/fips_module_indicators.pod
727bdf
 create mode 100644 providers/fips/indicator.h
727bdf
727bdf
diff --git a/doc/build.info b/doc/build.info
727bdf
index b0aa4297a4..af235113bb 100644
727bdf
--- a/doc/build.info
727bdf
+++ b/doc/build.info
727bdf
@@ -4389,6 +4389,10 @@ DEPEND[html/man7/fips_module.html]=man7/fips_module.pod
727bdf
 GENERATE[html/man7/fips_module.html]=man7/fips_module.pod
727bdf
 DEPEND[man/man7/fips_module.7]=man7/fips_module.pod
727bdf
 GENERATE[man/man7/fips_module.7]=man7/fips_module.pod
727bdf
+DEPEND[html/man7/fips_module_indicators.html]=man7/fips_module_indicators.pod
727bdf
+GENERATE[html/man7/fips_module_indicators.html]=man7/fips_module_indicators.pod
727bdf
+DEPEND[man/man7/fips_module_indicators.7]=man7/fips_module_indicators.pod
727bdf
+GENERATE[man/man7/fips_module_indicators.7]=man7/fips_module_indicators.pod
727bdf
 DEPEND[html/man7/life_cycle-cipher.html]=man7/life_cycle-cipher.pod
727bdf
 GENERATE[html/man7/life_cycle-cipher.html]=man7/life_cycle-cipher.pod
727bdf
 DEPEND[man/man7/life_cycle-cipher.7]=man7/life_cycle-cipher.pod
727bdf
@@ -4631,6 +4635,7 @@ html/man7/ct.html \
727bdf
 html/man7/des_modes.html \
727bdf
 html/man7/evp.html \
727bdf
 html/man7/fips_module.html \
727bdf
+html/man7/fips_module_indicators.html \
727bdf
 html/man7/life_cycle-cipher.html \
727bdf
 html/man7/life_cycle-digest.html \
727bdf
 html/man7/life_cycle-kdf.html \
727bdf
@@ -4754,6 +4759,7 @@ man/man7/ct.7 \
727bdf
 man/man7/des_modes.7 \
727bdf
 man/man7/evp.7 \
727bdf
 man/man7/fips_module.7 \
727bdf
+man/man7/fips_module_indicators.7 \
727bdf
 man/man7/life_cycle-cipher.7 \
727bdf
 man/man7/life_cycle-digest.7 \
727bdf
 man/man7/life_cycle-kdf.7 \
727bdf
diff --git a/doc/man7/fips_module_indicators.pod b/doc/man7/fips_module_indicators.pod
727bdf
new file mode 100644
727bdf
index 0000000000..23db2b395c
727bdf
--- /dev/null
727bdf
+++ b/doc/man7/fips_module_indicators.pod
727bdf
@@ -0,0 +1,154 @@
727bdf
+=pod
727bdf
+
727bdf
+=head1 NAME
727bdf
+
727bdf
+fips_module_indicators - Red Hat OpenSSL FIPS module indicators guide
727bdf
+
727bdf
+=head1 DESCRIPTION
727bdf
+
727bdf
+This guide documents how the Red Hat Enterprise Linux 9 OpenSSL FIPS provider
727bdf
+implements Approved Security Service Indicators according to the FIPS 140-3
727bdf
+Implementation Guidelines, section 2.4.C. See
727bdf
+L<https://csrc.nist.gov/CSRC/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf>
727bdf
+for the FIPS 140-3 Implementation Guidelines.
727bdf
+
727bdf
+For all approved services except signatures, the Red Hat OpenSSL FIPS provider
727bdf
+uses the return code as the indicator as understood by FIPS 140-3. That means
727bdf
+that every operation that succeeds denotes use of an approved security service.
727bdf
+Operations that do not succeed may not have been approved security services, or
727bdf
+may have been used incorrectly.
727bdf
+
727bdf
+For signatures, an explicit indicator API is available to determine whether
727bdf
+a selected operation is an approved security service, in combination with the
727bdf
+return code of the operation. For a signature operation to be approved, the
727bdf
+explicit indicator must claim it as approved, and it must succeed.
727bdf
+
727bdf
+=head2 Querying the explicit indicator
727bdf
+
727bdf
+The Red Hat OpenSSL FIPS provider exports a symbol named
727bdf
+I<redhat_ossl_query_fipsindicator> that provides information on which signature
727bdf
+operations are approved security functions. To use this function, either link
727bdf
+against I<fips.so> directly, or load it at runtime using dlopen(3) and
727bdf
+dlsym(3).
727bdf
+
727bdf
+    #include <openssl/core_dispatch.h>
727bdf
+    #include "providers/fips/indicator.h"
727bdf
+
727bdf
+    void *provider = dlopen("/usr/lib64/ossl-modules/fips.so", RTLD_LAZY);
727bdf
+    if (provider == NULL) {
727bdf
+        fprintf(stderr, "%s\n", dlerror());
727bdf
+        // handle error
727bdf
+    }
727bdf
+
727bdf
+    const OSSL_RH_FIPSINDICATOR_ALORITHM *(*redhat_ossl_query_fipsindicator)(int) \
727bdf
+        = dlsym(provider, "redhat_ossl_query_fipsindicator");
727bdf
+    if (redhat_ossl_query_fipsindicator == NULL) {
727bdf
+        fprintf(stderr, "%s\n", dlerror());
727bdf
+        fprintf(stderr, "Does your copy of fips.so have the required Red Hat"
727bdf
+                        " patches?\n");
727bdf
+        // handle error
727bdf
+    }
727bdf
+
727bdf
+Note that this uses the I<providers/fips/indicator.h> header, which is not
727bdf
+public. Install the I<openssl-debugsource> package from the I<BaseOS-debuginfo>
727bdf
+repository using I<dnf debuginfo-install openssl> and include
727bdf
+I</usr/src/debug/openssl-3.*/> in the compiler's include path.
727bdf
+
727bdf
+I<redhat_ossl_query_fipsindicator> expects an operation ID as its only
727bdf
+argument. Currently, the only supported operation ID is I<OSSL_OP_SIGNATURE> to
727bdf
+obtain the indicators for signature operations. On success, the return value is
727bdf
+a pointer to an array of I<OSSL_RH_FIPSINDICATOR_STRUCT>s. On failure, NULL is
727bdf
+returned. The last entry in the array is indicated by I<algorithm_names> being
727bdf
+NULL.
727bdf
+
727bdf
+    typedef struct ossl_rh_fipsindicator_algorithm_st {
727bdf
+        const char *algorithm_names;     /* key */
727bdf
+        const char *property_definition; /* key */
727bdf
+        const OSSL_RH_FIPSINDICATOR_DISPATCH *indicators;
727bdf
+    } OSSL_RH_FIPSINDICATOR_ALGORITHM;
727bdf
+
727bdf
+    typedef struct ossl_rh_fipsindicator_dispatch_st {
727bdf
+        int function_id;
727bdf
+        int approved;
727bdf
+    } OSSL_RH_FIPSINDICATOR_DISPATCH;
727bdf
+
727bdf
+The I<algorithm_names> field is a colon-separated list of algorithm names from
727bdf
+one of the I<PROV_NAMES_...> constants, e.g., I<PROV_NAMES_RSA>. strtok(3) can
727bdf
+be used to locate the appropriate entry. See the example below, where
727bdf
+I<algorithm> contains the algorithm name to search for:
727bdf
+
727bdf
+    const OSSL_RH_FIPSINDICATOR_DISPATCH *indicator_dispatch = NULL;
727bdf
+    const OSSL_RH_FIPSINDICATOR_ALGORITHM *indicator =
727bdf
+        redhat_ossl_query_fipsindicator(operation_id);
727bdf
+    if (indicator == NULL) {
727bdf
+        fprintf(stderr, "No indicator for operation, probably using implicit"
727bdf
+                        " indicators.\n");
727bdf
+        // handle error
727bdf
+    }
727bdf
+
727bdf
+    for (; indicator->algorithm_names != NULL; ++indicator) {
727bdf
+        char *algorithm_names = strdup(indicator->algorithm_names);
727bdf
+        if (algorithm_names == NULL) {
727bdf
+            perror("strdup(3)");
727bdf
+            // handle error
727bdf
+        }
727bdf
+
727bdf
+        const char *algorithm_name = strtok(algorithm_names, ":");
727bdf
+        for (; algorithm_name != NULL; algorithm_name = strtok(NULL, ":")) {
727bdf
+            if (strcasecmp(algorithm_name, algorithm) == 0) {
727bdf
+                indicator_dispatch = indicator->indicators;
727bdf
+                free(algorithm_names);
727bdf
+                algorithm_names = NULL;
727bdf
+                break;
727bdf
+            }
727bdf
+        }
727bdf
+        free(algorithm_names);
727bdf
+    }
727bdf
+    if (indicator_dispatch == NULL) {
727bdf
+        fprintf(stderr, "No indicator for algorithm %s.\n", algorithm);
727bdf
+        // handle error
727bdf
+    }
727bdf
+
727bdf
+If an appropriate I<OSSL_RH_FIPSINDICATOR_DISPATCH> array is available for the
727bdf
+given algorithm name, it maps function IDs to their approval status. The last
727bdf
+entry is indicated by a zero I<function_id>. I<approved> is
727bdf
+I<OSSL_RH_FIPSINDICATOR_APPROVED> if the operation is an approved security
727bdf
+service, or part of an approved security service, or
727bdf
+I<OSSL_RH_FIPSINDICATOR_UNAPPROVED> otherwise. Any other value is invalid.
727bdf
+Function IDs are I<OSSL_FUNC_*> constants from I<openssl/core_dispatch.h>,
727bdf
+e.g., I<OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE> or I<OSSL_FUNC_SIGNATURE_SIGN>.
727bdf
+
727bdf
+Assuming I<function_id> is the function in question, the following code can be
727bdf
+used to query the approval status:
727bdf
+
727bdf
+    for (; indicator_dispatch->function_id != 0; ++indicator_dispatch) {
727bdf
+        if (indicator_dispatch->function_id == function_id) {
727bdf
+            switch (indicator_dispatch->approved) {
727bdf
+                case OSSL_RH_FIPSINDICATOR_APPROVED:
727bdf
+                    // approved security service
727bdf
+                    break;
727bdf
+                case OSSL_RH_FIPSINDICATOR_UNAPPROVED:
727bdf
+                    // unapproved security service
727bdf
+                    break;
727bdf
+                default:
727bdf
+                    // invalid result
727bdf
+                    break;
727bdf
+            }
727bdf
+            break;
727bdf
+        }
727bdf
+    }
727bdf
+
727bdf
+=head1 SEE ALSO
727bdf
+
727bdf
+L<fips_module(7)>, L<provider(7)>
727bdf
+
727bdf
+=head1 COPYRIGHT
727bdf
+
727bdf
+Copyright 2022 Red Hat, Inc. All Rights Reserved.
727bdf
+
727bdf
+Licensed under the Apache License 2.0 (the "License").  You may not use
727bdf
+this file except in compliance with the License.  You can obtain a copy
727bdf
+in the file LICENSE in the source distribution or at
727bdf
+L<https://www.openssl.org/source/license.html>.
727bdf
+
727bdf
+=cut
727bdf
diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c
727bdf
index de391ce067..1cfd71c5cf 100644
727bdf
--- a/providers/fips/fipsprov.c
727bdf
+++ b/providers/fips/fipsprov.c
727bdf
@@ -23,6 +23,7 @@
727bdf
 #include "prov/seeding.h"
727bdf
 #include "self_test.h"
727bdf
 #include "internal/core.h"
727bdf
+#include "indicator.h"
727bdf
 
727bdf
 static const char FIPS_DEFAULT_PROPERTIES[] = "provider=fips,fips=yes";
727bdf
 static const char FIPS_UNAPPROVED_PROPERTIES[] = "provider=fips,fips=no";
727bdf
@@ -425,6 +426,68 @@ static const OSSL_ALGORITHM fips_signature[] = {
727bdf
     { NULL, NULL, NULL }
727bdf
 };
727bdf
 
727bdf
+static const OSSL_RH_FIPSINDICATOR_DISPATCH redhat_rsa_signature_indicators[] = {
727bdf
+    { OSSL_FUNC_SIGNATURE_NEWCTX, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SIGN_INIT, OSSL_RH_FIPSINDICATOR_UNAPPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SIGN, OSSL_RH_FIPSINDICATOR_UNAPPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_VERIFY_INIT, OSSL_RH_FIPSINDICATOR_UNAPPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_VERIFY, OSSL_RH_FIPSINDICATOR_UNAPPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT, OSSL_RH_FIPSINDICATOR_UNAPPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_VERIFY_RECOVER, OSSL_RH_FIPSINDICATOR_UNAPPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_FREECTX, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DUPCTX, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { 0, OSSL_RH_FIPSINDICATOR_UNAPPROVED }
727bdf
+};
727bdf
+
727bdf
+static const OSSL_RH_FIPSINDICATOR_DISPATCH redhat_ecdsa_signature_indicators[] = {
727bdf
+    { OSSL_FUNC_SIGNATURE_NEWCTX, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SIGN_INIT, OSSL_RH_FIPSINDICATOR_UNAPPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SIGN, OSSL_RH_FIPSINDICATOR_UNAPPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_VERIFY_INIT, OSSL_RH_FIPSINDICATOR_UNAPPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_VERIFY, OSSL_RH_FIPSINDICATOR_UNAPPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_FREECTX, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_DUPCTX, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS, OSSL_RH_FIPSINDICATOR_APPROVED },
727bdf
+    { 0, OSSL_RH_FIPSINDICATOR_UNAPPROVED }
727bdf
+};
727bdf
+
727bdf
+static const OSSL_RH_FIPSINDICATOR_ALGORITHM redhat_indicator_fips_signature[] = {
727bdf
+    { PROV_NAMES_RSA, FIPS_DEFAULT_PROPERTIES,
727bdf
+        redhat_rsa_signature_indicators },
727bdf
+#ifndef OPENSSL_NO_EC
727bdf
+    { PROV_NAMES_ECDSA, FIPS_DEFAULT_PROPERTIES,
727bdf
+        redhat_ecdsa_signature_indicators },
727bdf
+#endif
727bdf
+    { NULL, NULL, NULL }
727bdf
+};
727bdf
+
727bdf
 static const OSSL_ALGORITHM fips_asym_cipher[] = {
727bdf
     { PROV_NAMES_RSA, FIPS_DEFAULT_PROPERTIES, ossl_rsa_asym_cipher_functions },
727bdf
     { NULL, NULL, NULL }
727bdf
@@ -527,6 +590,14 @@ static void fips_deinit_casecmp(void) {
727bdf
     freelocale(loc);
727bdf
 }
727bdf
 
727bdf
+const OSSL_RH_FIPSINDICATOR_ALGORITHM *redhat_ossl_query_fipsindicator(int operation_id) {
727bdf
+    switch (operation_id) {
727bdf
+    case OSSL_OP_SIGNATURE:
727bdf
+        return redhat_indicator_fips_signature;
727bdf
+    }
727bdf
+    return NULL;
727bdf
+}
727bdf
+
727bdf
 static void fips_teardown(void *provctx)
727bdf
 {
727bdf
     OSSL_LIB_CTX_free(PROV_LIBCTX_OF(provctx));
727bdf
diff --git a/providers/fips/indicator.h b/providers/fips/indicator.h
727bdf
new file mode 100644
727bdf
index 0000000000..b323efe44c
727bdf
--- /dev/null
727bdf
+++ b/providers/fips/indicator.h
727bdf
@@ -0,0 +1,66 @@
727bdf
+/*
727bdf
+ * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
727bdf
+ *
727bdf
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
727bdf
+ * this file except in compliance with the License.  You can obtain a copy
727bdf
+ * in the file LICENSE in the source distribution or at
727bdf
+ * https://www.openssl.org/source/license.html
727bdf
+ */
727bdf
+
727bdf
+#ifndef OPENSSL_FIPS_INDICATOR_H
727bdf
+# define OPENSSL_FIPS_INDICATOR_H
727bdf
+# pragma once
727bdf
+
727bdf
+# ifdef __cplusplus
727bdf
+extern "C" {
727bdf
+# endif
727bdf
+
727bdf
+# define OSSL_RH_FIPSINDICATOR_UNAPPROVED (0)
727bdf
+# define OSSL_RH_FIPSINDICATOR_APPROVED (1)
727bdf
+
727bdf
+/*
727bdf
+ * FIPS indicator dispatch table element.  function_id numbers and the
727bdf
+ * functions are defined in core_dispatch.h, see macros with
727bdf
+ * 'OSSL_CORE_MAKE_FUNC' in their names.
727bdf
+ *
727bdf
+ * An array of these is always terminated by function_id == 0
727bdf
+ */
727bdf
+typedef struct ossl_rh_fipsindicator_dispatch_st {
727bdf
+    int function_id;
727bdf
+    int approved;
727bdf
+} OSSL_RH_FIPSINDICATOR_DISPATCH;
727bdf
+
727bdf
+/*
727bdf
+ * Type to tie together algorithm names, property definition string and the
727bdf
+ * algorithm implementation's FIPS indicator status in the form of a FIPS
727bdf
+ * indicator dispatch table.
727bdf
+ *
727bdf
+ * An array of these is always terminated by algorithm_names == NULL
727bdf
+ */
727bdf
+typedef struct ossl_rh_fipsindicator_algorithm_st {
727bdf
+    const char *algorithm_names;     /* key */
727bdf
+    const char *property_definition; /* key */
727bdf
+    const OSSL_RH_FIPSINDICATOR_DISPATCH *indicators;
727bdf
+} OSSL_RH_FIPSINDICATOR_ALGORITHM;
727bdf
+
727bdf
+/**
727bdf
+ * Query FIPS indicator status for the given operation.  Possible values for
727bdf
+ * 'operation_id' are currently only OSSL_OP_SIGNATURE, as all other algorithms
727bdf
+ * use implicit indicators.  The return value is an array of
727bdf
+ * OSSL_RH_FIPSINDICATOR_ALGORITHMs, terminated by an entry with
727bdf
+ * algorithm_names == NULL.  'algorithm_names' is a colon-separated list of
727bdf
+ * algorithm names, 'property_definition' a comma-separated list of properties,
727bdf
+ * and 'indicators' is a list of OSSL_RH_FIPSINDICATOR_DISPATCH structs.  This
727bdf
+ * list is terminated by function_id == 0.  'function_id' is one of the
727bdf
+ * OSSL_FUNC_* constants, e.g., OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL.
727bdf
+ *
727bdf
+ * If there is no entry in the returned struct for the given operation_id,
727bdf
+ * algorithm name, or function_id, the algorithm is unapproved.
727bdf
+ */
727bdf
+const OSSL_RH_FIPSINDICATOR_ALGORITHM *redhat_ossl_query_fipsindicator(int operation_id);
727bdf
+
727bdf
+# ifdef __cplusplus
727bdf
+}
727bdf
+# endif
727bdf
+
727bdf
+#endif
727bdf
diff --git a/util/mkdef.pl b/util/mkdef.pl
727bdf
index a1c76f7c97..eda39b71ee 100755
727bdf
--- a/util/mkdef.pl
727bdf
+++ b/util/mkdef.pl
727bdf
@@ -149,7 +149,8 @@ $ordinal_opts{filter} =
727bdf
         return
727bdf
             $item->exists()
727bdf
             && platform_filter($item)
727bdf
-            && feature_filter($item);
727bdf
+            && feature_filter($item)
727bdf
+            && fips_filter($item, $name);
727bdf
     };
727bdf
 my $ordinals = OpenSSL::Ordinals->new(from => $ordinals_file);
727bdf
 
727bdf
@@ -205,6 +206,28 @@ sub feature_filter {
727bdf
     return $verdict;
727bdf
 }
727bdf
 
727bdf
+sub fips_filter {
727bdf
+    my $item = shift;
727bdf
+    my $name = uc(shift);
727bdf
+    my @features = ( $item->features() );
727bdf
+
727bdf
+    # True if no features are defined
727bdf
+    return 1 if scalar @features == 0;
727bdf
+
727bdf
+    my @matches = grep(/^ONLY_.*$/, @features);
727bdf
+    if (@matches) {
727bdf
+        # There is at least one only_* flag on this symbol, check if any of
727bdf
+        # them match the name
727bdf
+        for (@matches) {
727bdf
+            if ($_ eq "ONLY_${name}") {
727bdf
+                return 1;
727bdf
+            }
727bdf
+        }
727bdf
+        return 0;
727bdf
+    }
727bdf
+    return 1;
727bdf
+}
727bdf
+
727bdf
 sub sorter_unix {
727bdf
     my $by_name = OpenSSL::Ordinals::by_name();
727bdf
     my %weight = (
727bdf
diff --git a/util/providers.num b/util/providers.num
727bdf
index 4e2fa81b98..77879d0e5f 100644
727bdf
--- a/util/providers.num
727bdf
+++ b/util/providers.num
727bdf
@@ -1 +1,2 @@
727bdf
 OSSL_provider_init                     1	*	EXIST::FUNCTION:
727bdf
+redhat_ossl_query_fipsindicator        1	*	EXIST::FUNCTION:ONLY_PROVIDERS/FIPS
727bdf
-- 
727bdf
2.35.3
727bdf