This is an automated email from the ASF dual-hosted git repository.

szaszm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git

commit 22013fa9337d6ce67e3438e6f4b2b75a9e3e552c
Author: Gabor Gyimesi <[email protected]>
AuthorDate: Wed Mar 12 22:12:48 2025 +0100

    MINIFICPP-2524 Add FIPS compliancy support
    
    This change adds the option to enable FIPS mode in the OpenSSL library for 
cryptographic functions used by MiNiFi C++. This includes the following:
    - Introduces the `nifi.openssl.fips.support.enable` option in 
`minifi.properties` to enable this option, if the option is enabled MiNiFi C++ 
will try to load the `openssl.cnf` that loads the FIPS provider and then 
enables FIPS mode in OpenSSL.
    - Adds compilation of the FIPS provider library from OpenSSL 3.0.9 which is 
the latest FIPS validated OpenSSL version as listed here: 
https://openssl-library.org/source/
    - Adds the FIPS provider library and the required `openssl.cnf` files to 
the install package under the $MINIFI_HOME/fips directory
    - Adds the `openssl` binary to the install package under the 
$MINIFI_HOME/fips directory for running the module tests and generating the 
fipsmodule.cnf file on the target platform as required for the FIPS compliancy, 
referenced in these sources: 
https://github.com/openssl/openssl/discussions/25036, 
https://openssl-library.org/source/fips-doc/openssl-3.0.9-security-policy-2024-01-12.pdf
 Appendix A
    - Updated paho-mqtt, librdkafka libraries and added `no-engine` flag for 
OpenSSL compilation to remove legacy API usage required for FIPS compliancy as 
referenced here: https://docs.openssl.org/master/man7/fips_module/#description
    
    OpenSSL discussion about this issue: 
https://github.com/openssl/openssl/discussions/26378
    
    Closes #1925
    
    Signed-off-by: Marton Szasz <[email protected]>
---
 CMakeLists.txt                                     |   5 +
 CONFIGURE.md                                       |  17 +++
 cmake/BundledOpenSSL.cmake                         |  95 +++++++++++++--
 cmake/Fetchlibrdkafka.cmake                        |   4 +-
 cmake/PahoMqttC.cmake                              |   4 +-
 cmake/ssl/FindOpenSSL.cmake                        |   2 +-
 conf/minifi.properties                             |   3 +
 docker/test/integration/cluster/ContainerStore.py  |   3 +
 .../test/integration/cluster/DockerTestCluster.py  |   3 +
 .../cluster/containers/MinifiContainer.py          |  11 ++
 .../features/MiNiFi_integration_test_driver.py     |   3 +
 docker/test/integration/features/https.feature     |   3 +-
 docker/test/integration/features/kafka.feature     |  18 ++-
 .../integration/features/minifi_c2_server.feature  |   6 +-
 .../test/integration/features/opensearch.feature   |   9 +-
 .../test/integration/features/prometheus.feature   |   3 +-
 docker/test/integration/features/s2s.feature       |  12 +-
 docker/test/integration/features/splunk.feature    |   3 +-
 docker/test/integration/features/steps/steps.py    |   5 +
 encrypt-config/tests/ConfigFileEncryptorTests.cpp  |   2 +-
 encrypt-config/tests/ConfigFileTests.cpp           |   8 +-
 encrypt-config/tests/resources/minifi.properties   |   3 +
 ...th-additional-sensitive-props.minifi.properties |   3 +
 .../mqtt/processors/AbstractMQTTProcessor.cpp      |   2 +-
 fips/openssl.cnf                                   |  13 ++
 libminifi/src/Configuration.cpp                    |   3 +-
 .../test/resources/encrypted.minifi.properties     |   3 +
 .../include/minifi-cpp/properties/Configuration.h  |   2 +
 minifi_main/CMakeLists.txt                         |   2 +-
 minifi_main/Fips.cpp                               | 131 +++++++++++++++++++++
 minifi_main/Fips.h                                 |  28 +++++
 minifi_main/MiNiFiMain.cpp                         |   3 +
 msi/WixWin.wsi.in                                  |   7 ++
 thirdparty/paho-mqtt/cmake-openssl.patch           |  90 +++++++-------
 34 files changed, 425 insertions(+), 84 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9a01eccc3..bed297c48 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -431,6 +431,7 @@ if(WIN32)
     set(CPACK_WIX_UI_DIALOG "${CMAKE_CURRENT_SOURCE_DIR}/msi/bgr.png")
 
     file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/conf/" DESTINATION 
"${CMAKE_CURRENT_BINARY_DIR}/conf/")
+    file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/fips/" DESTINATION 
"${CMAKE_CURRENT_BINARY_DIR}/fips/")
     file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" DESTINATION 
"${CMAKE_CURRENT_BINARY_DIR}")
     file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/NOTICE" DESTINATION 
"${CMAKE_CURRENT_BINARY_DIR}")
     file(GLOB markdown_docs "${CMAKE_CURRENT_SOURCE_DIR}/*.md")
@@ -552,6 +553,10 @@ if (NOT WIN32)
         DESTINATION conf
         COMPONENT bin)
 
+    install(FILES fips/openssl.cnf
+        DESTINATION fips
+        COMPONENT bin)
+
     install(DIRECTORY extensions/python/pythonprocessors/
         DESTINATION minifi-python
         COMPONENT bin)
diff --git a/CONFIGURE.md b/CONFIGURE.md
index 0b9ec9b66..b84c9e6bc 100644
--- a/CONFIGURE.md
+++ b/CONFIGURE.md
@@ -931,6 +931,23 @@ To notify the agent which extensions it should load see 
[Loading extensions](Ext
 ### Python processors
 Please see the [Python Processors Readme](extensions/python/PYTHON.md).
 
+### Enabling FIPS support
+
+To enable FIPS support, and use MiNiFi C++ in FIPS compliant mode, there are a 
few steps that need to be taken before the application startup. First the 
following property needs to be set in the minifi.properties file:
+
+    # in minifi.properties
+    nifi.openssl.fips.support.enable=true
+
+Before first starting the application, the fipsmodule.cnf needs to be 
generated. To do this run the following command with the openssl binary 
(openssl on Unix and openssl.exe on windows) with the following parameters 
provided in the $MINIFI_HOME/fips directory:
+
+    # on Unix platform
+    ./openssl fipsinstall -out fipsmodule.cnf -module $MINIFI_HOME/fips/fips.so
+
+    # on Windows platform
+    openssl.exe fipsinstall -out fipsmodule.cnf -module 
$MINIFI_HOME\fips\fips.dll
+
+If the command finishes successfully, the fipsmodule.cnf file will be 
generated in the $MINIFI_HOME/fips directory. After this the application can be 
started and it will configure OpenSSL to start in FIPS mode.
+
 ## Log configuration
 By default the application logs for Apache MiNiFi C++ can be found in the 
${MINIFI_HOME}/logs/minifi-app.log file with default INFO level logging. The 
logger can be reconfigured in the ${MINIFI_HOME}/conf/minifi-log.properties 
file to use different output streams, log level, and output format.
 
diff --git a/cmake/BundledOpenSSL.cmake b/cmake/BundledOpenSSL.cmake
index 0b9ed6f2e..920bd949a 100644
--- a/cmake/BundledOpenSSL.cmake
+++ b/cmake/BundledOpenSSL.cmake
@@ -38,6 +38,12 @@ function(use_openssl SOURCE_DIR BINARY_DIR)
         set(BYPRODUCT_SUFFIX ".a" CACHE STRING "" FORCE)
     endif()
 
+    if (WIN32)
+        set(EXECUTABLE_SUFFIX ".exe" CACHE STRING "" FORCE)
+    else()
+        set(EXECUTABLE_SUFFIX "" CACHE STRING "" FORCE)
+    endif()
+
     set(BYPRODUCTS
             "${LIBDIR}/${BYPRODUCT_PREFIX}ssl${BYPRODUCT_SUFFIX}"
             "${LIBDIR}/${BYPRODUCT_PREFIX}crypto${BYPRODUCT_SUFFIX}"
@@ -51,15 +57,12 @@ function(use_openssl SOURCE_DIR BINARY_DIR)
 
     set(OPENSSL_EXTRA_FLAGS
             no-tests            # Disable tests
-            no-apps             # disable executables
             no-capieng          # disable CAPI engine (legacy)
-            no-dso              # disable dynamic libraries
             no-docs             # disable docs and manpages
             no-legacy           # disable legacy modules
-            no-module           # disable dynamically loadable engines
-            no-pinshared        # don't pin shared libraries in the process 
memory
             enable-tfo          # Enable TCP Fast Open
-            no-ssl)             # disable SSLv3
+            no-ssl              # disable SSLv3
+            no-engine)          # disable Engine API as it is deprecated since 
OpenSSL 3.0 and not FIPS compatible
 
     set(OPENSSL_BIN_DIR "${BINARY_DIR}/thirdparty/openssl-install" CACHE 
STRING "" FORCE)
 
@@ -99,8 +102,8 @@ function(use_openssl SOURCE_DIR BINARY_DIR)
         endif()
         ExternalProject_Add(
                 openssl-external
-                URL 
https://github.com/openssl/openssl/releases/download/openssl-3.3.2/openssl-3.3.2.tar.gz
-                URL_HASH 
"SHA256=2e8a40b01979afe8be0bbfb3de5dc1c6709fedb46d6c89c10da114ab5fc3d281"
+                URL 
https://github.com/openssl/openssl/releases/download/openssl-3.3.3/openssl-3.3.3.tar.gz
+                URL_HASH 
"SHA256=712590fd20aaa60ec75d778fe5b810d6b829ca7fb1e530577917a131f9105539"
                 SOURCE_DIR "${BINARY_DIR}/thirdparty/openssl-src"
                 BUILD_IN_SOURCE true
                 CONFIGURE_COMMAND perl Configure 
"CFLAGS=${PASSTHROUGH_CMAKE_C_FLAGS} ${OPENSSL_WINDOWS_COMPILE_FLAGS}" 
"CXXFLAGS=${PASSTHROUGH_CMAKE_CXX_FLAGS} ${OPENSSL_WINDOWS_COMPILE_FLAGS}" 
${OPENSSL_SHARED_FLAG} ${OPENSSL_EXTRA_FLAGS} "--prefix=${OPENSSL_BIN_DIR}" 
"--openssldir=${OPENSSL_BIN_DIR}"
@@ -114,8 +117,8 @@ function(use_openssl SOURCE_DIR BINARY_DIR)
     else()
         ExternalProject_Add(
                 openssl-external
-                URL 
https://github.com/openssl/openssl/releases/download/openssl-3.3.2/openssl-3.3.2.tar.gz
-                URL_HASH 
"SHA256=2e8a40b01979afe8be0bbfb3de5dc1c6709fedb46d6c89c10da114ab5fc3d281"
+                URL 
https://github.com/openssl/openssl/releases/download/openssl-3.3.3/openssl-3.3.3.tar.gz
+                URL_HASH 
"SHA256=712590fd20aaa60ec75d778fe5b810d6b829ca7fb1e530577917a131f9105539"
                 SOURCE_DIR "${BINARY_DIR}/thirdparty/openssl-src"
                 BUILD_IN_SOURCE true
                 CONFIGURE_COMMAND ./Configure 
"CFLAGS=${PASSTHROUGH_CMAKE_C_FLAGS} -fPIC" 
"CXXFLAGS=${PASSTHROUGH_CMAKE_CXX_FLAGS} -fPIC" ${OPENSSL_SHARED_FLAG} 
${OPENSSL_EXTRA_FLAGS} "--prefix=${OPENSSL_BIN_DIR}" 
"--openssldir=${OPENSSL_BIN_DIR}"
@@ -132,6 +135,7 @@ function(use_openssl SOURCE_DIR BINARY_DIR)
     set(OPENSSL_LIBRARIES "${OPENSSL_LIBRARIES_LIST};${CMAKE_DL_LIBS}"  CACHE 
STRING "" FORCE)
     set(OPENSSL_CRYPTO_LIBRARY 
"${OPENSSL_BIN_DIR}/${LIBDIR}/${BYPRODUCT_PREFIX}crypto${BYPRODUCT_SUFFIX}" 
CACHE STRING "" FORCE)
     set(OPENSSL_SSL_LIBRARY 
"${OPENSSL_BIN_DIR}/${LIBDIR}/${BYPRODUCT_PREFIX}ssl${BYPRODUCT_SUFFIX}" CACHE 
STRING "" FORCE)
+    set(OPENSSL_VERSION "3.3.3" CACHE STRING "" FORCE)
 
     # Set exported variables for FindPackage.cmake
     set(PASSTHROUGH_VARIABLES ${PASSTHROUGH_VARIABLES} 
"-DEXPORTED_OPENSSL_INCLUDE_DIR=${OPENSSL_INCLUDE_DIR}" CACHE STRING "" FORCE)
@@ -165,4 +169,77 @@ function(use_openssl SOURCE_DIR BINARY_DIR)
         set_property(TARGET OpenSSL::SSL APPEND PROPERTY 
INTERFACE_LINK_LIBRARIES crypt32.lib)
     endif()
 
+    if (WIN32)
+        set(BYPRODUCT_DYN_SUFFIX ".dll" CACHE STRING "" FORCE)
+    elseif(APPLE)
+        set(BYPRODUCT_DYN_SUFFIX ".dylib" CACHE STRING "" FORCE)
+    else()
+        set(BYPRODUCT_DYN_SUFFIX ".so" CACHE STRING "" FORCE)
+    endif()
+
+    set(FIPS_BYPRODUCTS
+            "${LIBDIR}/ossl-modules/fips${BYPRODUCT_DYN_SUFFIX}"
+            )
+
+    set(OPENSSL_FIPS_BIN_DIR "${BINARY_DIR}/thirdparty/openssl-fips-install" 
CACHE STRING "" FORCE)
+
+    FOREACH(BYPRODUCT ${FIPS_BYPRODUCTS})
+        LIST(APPEND OPENSSL_FIPS_FILE_LIST 
"${OPENSSL_FIPS_BIN_DIR}/${BYPRODUCT}")
+    ENDFOREACH(BYPRODUCT)
+
+    install(FILES ${OPENSSL_FIPS_FILE_LIST} DESTINATION fips COMPONENT bin)
+    install(FILES "${OPENSSL_BIN_DIR}/bin/openssl${EXECUTABLE_SUFFIX}" 
DESTINATION fips COMPONENT bin
+            PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE 
GROUP_READ WORLD_READ WORLD_EXECUTE)
+
+    set(OPENSSL_FIPS_EXTRA_FLAGS
+            no-tests            # Disable tests
+            no-capieng          # disable CAPI engine (legacy)
+            no-legacy           # disable legacy modules
+            no-ssl              # disable SSLv3
+            no-engine           # disable Engine API as it is deprecated since 
OpenSSL 3.0 and not FIPS compatible
+            enable-fips)        # enable FIPS module
+
+    if (WIN32)
+        find_program(JOM_EXECUTABLE_PATH
+            NAMES jom.exe
+            PATHS ENV PATH
+            NO_DEFAULT_PATH)
+        if(JOM_EXECUTABLE_PATH)
+            include(ProcessorCount)
+            processorcount(jobs)
+            set(OPENSSL_BUILD_COMMAND ${JOM_EXECUTABLE_PATH} -j${jobs})
+            set(OPENSSL_WINDOWS_COMPILE_FLAGS /FS)
+        else()
+            message("Using nmake for OpenSSL build")
+            set(OPENSSL_BUILD_COMMAND nmake)
+            set(OPENSSL_WINDOWS_COMPILE_FLAGS "")
+        endif()
+        ExternalProject_Add(
+                openssl-fips-external
+                URL 
https://github.com/openssl/openssl/releases/download/openssl-3.0.9/openssl-3.0.9.tar.gz
+                URL_HASH 
"SHA256=eb1ab04781474360f77c318ab89d8c5a03abc38e63d65a603cabbf1b00a1dc90"
+                SOURCE_DIR "${BINARY_DIR}/thirdparty/openssl-fips-src"
+                BUILD_IN_SOURCE true
+                CONFIGURE_COMMAND perl Configure 
"CFLAGS=${PASSTHROUGH_CMAKE_C_FLAGS} ${OPENSSL_WINDOWS_COMPILE_FLAGS}" 
"CXXFLAGS=${PASSTHROUGH_CMAKE_CXX_FLAGS} ${OPENSSL_WINDOWS_COMPILE_FLAGS}" 
${OPENSSL_SHARED_FLAG} ${OPENSSL_FIPS_EXTRA_FLAGS} enable-fips 
"--prefix=${OPENSSL_FIPS_BIN_DIR}" "--openssldir=${OPENSSL_FIPS_BIN_DIR}"
+                BUILD_BYPRODUCTS ${OPENSSL_FIPS_FILE_LIST}
+                EXCLUDE_FROM_ALL TRUE
+                BUILD_COMMAND ${OPENSSL_BUILD_COMMAND}
+                INSTALL_COMMAND nmake install_fips
+            )
+    else()
+        ExternalProject_Add(
+            openssl-fips-external
+                URL 
https://github.com/openssl/openssl/releases/download/openssl-3.0.9/openssl-3.0.9.tar.gz
+                URL_HASH 
"SHA256=eb1ab04781474360f77c318ab89d8c5a03abc38e63d65a603cabbf1b00a1dc90"
+                SOURCE_DIR "${BINARY_DIR}/thirdparty/openssl-fips-src"
+                BUILD_IN_SOURCE true
+                CONFIGURE_COMMAND ./Configure 
"CFLAGS=${PASSTHROUGH_CMAKE_C_FLAGS} -fPIC" 
"CXXFLAGS=${PASSTHROUGH_CMAKE_CXX_FLAGS} -fPIC" ${OPENSSL_SHARED_FLAG} 
${OPENSSL_FIPS_EXTRA_FLAGS}  "--prefix=${OPENSSL_FIPS_BIN_DIR}" 
"--openssldir=${OPENSSL_FIPS_BIN_DIR}"
+                BUILD_BYPRODUCTS ${OPENSSL_FIPS_FILE_LIST}
+                EXCLUDE_FROM_ALL TRUE
+                INSTALL_COMMAND make install_fips
+        )
+    endif()
+
+    add_dependencies(OpenSSL::Crypto openssl-fips-external)
+
 endfunction(use_openssl)
diff --git a/cmake/Fetchlibrdkafka.cmake b/cmake/Fetchlibrdkafka.cmake
index 49b600b59..021334c1d 100644
--- a/cmake/Fetchlibrdkafka.cmake
+++ b/cmake/Fetchlibrdkafka.cmake
@@ -34,8 +34,8 @@ set(PATCH_FILE 
"${CMAKE_SOURCE_DIR}/thirdparty/librdkafka/0001-remove-findLZ4-an
 set(PC "${Patch_EXECUTABLE}" -p1 -i "${PATCH_FILE}")
 
 FetchContent_Declare(libkafka
-        URL 
https://github.com/confluentinc/librdkafka/archive/refs/tags/v2.6.0.tar.gz
-        URL_HASH 
SHA256=abe0212ecd3e7ed3c4818a4f2baf7bf916e845e902bb15ae48834ca2d36ac745
+        URL 
https://github.com/confluentinc/librdkafka/archive/refs/tags/v2.8.0.tar.gz
+        URL_HASH 
SHA256=5bd1c46f63265f31c6bfcedcde78703f77d28238eadf23821c2b43fc30be3e25
         PATCH_COMMAND "${PC}"
 )
 
diff --git a/cmake/PahoMqttC.cmake b/cmake/PahoMqttC.cmake
index 5ae355fa8..0209edf94 100644
--- a/cmake/PahoMqttC.cmake
+++ b/cmake/PahoMqttC.cmake
@@ -29,8 +29,8 @@ set(PC ${Bash_EXECUTABLE}  -c "set -x &&\
 
 FetchContent_Declare(
     paho.mqtt.c-external
-    URL 
"https://github.com/eclipse/paho.mqtt.c/archive/refs/tags/v1.3.9.tar.gz";
-    URL_HASH 
"SHA256=386c9b5fa1cf6d0d516db12d57fd8f6a410dd0fdc5e9a2da870aae437a2535ed"
+    URL 
"https://github.com/eclipse/paho.mqtt.c/archive/refs/tags/v1.3.14.tar.gz";
+    URL_HASH 
"SHA256=7af7d906e60a696a80f1b7c2bd7d6eb164aaad908ff4c40c3332ac2006d07346"
     PATCH_COMMAND "${PC}"
 )
 
diff --git a/cmake/ssl/FindOpenSSL.cmake b/cmake/ssl/FindOpenSSL.cmake
index 3b6adc46f..0111b855f 100644
--- a/cmake/ssl/FindOpenSSL.cmake
+++ b/cmake/ssl/FindOpenSSL.cmake
@@ -23,7 +23,7 @@ if(NOT OPENSSL_FOUND)
     set(OPENSSL_CRYPTO_LIBRARY "${EXPORTED_OPENSSL_CRYPTO_LIBRARY}" CACHE 
STRING "" FORCE)
     set(OPENSSL_SSL_LIBRARY "${EXPORTED_OPENSSL_SSL_LIBRARY}" CACHE STRING "" 
FORCE)
     set(OPENSSL_LIBRARIES "${EXPORTED_OPENSSL_LIBRARIES}" CACHE STRING "" 
FORCE)
-    set(OPENSSL_VERSION "3.1.0" CACHE STRING "" FORCE)
+    set(OPENSSL_VERSION "3.3.2" CACHE STRING "" FORCE)
 endif()
 
 if(NOT TARGET OpenSSL::Crypto)
diff --git a/conf/minifi.properties b/conf/minifi.properties
index 1a18fb076..f681e9a28 100644
--- a/conf/minifi.properties
+++ b/conf/minifi.properties
@@ -142,3 +142,6 @@ nifi.python.processor.dir=${MINIFI_HOME}/minifi-python/
 nifi.python.virtualenv.directory=${MINIFI_HOME}/minifi-python-env
 nifi.python.install.packages.automatically=true
 # nifi.python.env.setup.binary=python3
+
+# FIPS
+# nifi.openssl.fips.support.enable=false
diff --git a/docker/test/integration/cluster/ContainerStore.py 
b/docker/test/integration/cluster/ContainerStore.py
index 9c8527458..baa5e9907 100644
--- a/docker/test/integration/cluster/ContainerStore.py
+++ b/docker/test/integration/cluster/ContainerStore.py
@@ -397,6 +397,9 @@ class ContainerStore:
     def enable_example_minifi_python_processors(self):
         self.minifi_options.enable_example_minifi_python_processors = True
 
+    def enable_openssl_fips_mode_in_minifi(self):
+        self.minifi_options.enable_openssl_fips_mode = True
+
     def get_startup_finished_log_entry(self, container_name):
         container_name = self.get_container_name_with_postfix(container_name)
         return self.containers[container_name].get_startup_finished_log_entry()
diff --git a/docker/test/integration/cluster/DockerTestCluster.py 
b/docker/test/integration/cluster/DockerTestCluster.py
index e161d5da4..a758b873f 100644
--- a/docker/test/integration/cluster/DockerTestCluster.py
+++ b/docker/test/integration/cluster/DockerTestCluster.py
@@ -138,6 +138,9 @@ class DockerTestCluster:
     def enable_example_minifi_python_processors(self):
         self.container_store.enable_example_minifi_python_processors()
 
+    def enable_openssl_fips_mode_in_minifi(self):
+        self.container_store.enable_openssl_fips_mode_in_minifi()
+
     def get_app_log(self, container_name):
         container_name = 
self.container_store.get_container_name_with_postfix(container_name)
         log_source = self.container_store.log_source(container_name)
diff --git a/docker/test/integration/cluster/containers/MinifiContainer.py 
b/docker/test/integration/cluster/containers/MinifiContainer.py
index 8d0894446..75f698faf 100644
--- a/docker/test/integration/cluster/containers/MinifiContainer.py
+++ b/docker/test/integration/cluster/containers/MinifiContainer.py
@@ -43,6 +43,7 @@ class MinifiOptions:
         self.enable_controller_socket = False
         self.enable_log_metrics_publisher = False
         self.enable_example_minifi_python_processors = False
+        self.enable_openssl_fips_mode = False
 
 
 class MinifiContainer(FlowContainer):
@@ -52,6 +53,13 @@ class MinifiContainer(FlowContainer):
 
     def __init__(self, feature_context, config_dir, options, name, vols, 
network, image_store, command=None):
         self.options = options
+        if options.enable_openssl_fips_mode:
+            if command is not None:
+                command = ["/bin/sh", "-c", MinifiContainer.MINIFI_ROOT + 
"/fips/openssl fipsinstall -out " + MinifiContainer.MINIFI_ROOT + 
"/fips/fipsmodule.cnf -module "
+                           + MinifiContainer.MINIFI_ROOT + "/fips/fips.so && " 
+ command]
+            else:
+                command = ["/bin/sh", "-c", MinifiContainer.MINIFI_ROOT + 
"/fips/openssl fipsinstall -out " + MinifiContainer.MINIFI_ROOT + 
"/fips/fipsmodule.cnf -module "
+                           + MinifiContainer.MINIFI_ROOT + "/fips/fips.so && " 
+ MinifiContainer.MINIFI_ROOT + "/bin/minifi.sh run"]
 
         super().__init__(feature_context=feature_context,
                          config_dir=config_dir,
@@ -159,6 +167,9 @@ class MinifiContainer(FlowContainer):
             if self.options.use_nifi_python_processors_with_virtualenv or 
self.options.remove_python_requirements_txt:
                 f.write("nifi.python.install.packages.automatically=true\n")
 
+            if self.options.enable_openssl_fips_mode:
+                f.write("nifi.openssl.fips.support.enable=true\n")
+
     def _setup_config(self):
         self._create_properties()
         if not self.options.use_flow_config_from_url:
diff --git a/docker/test/integration/features/MiNiFi_integration_test_driver.py 
b/docker/test/integration/features/MiNiFi_integration_test_driver.py
index 57526342d..e7171865e 100644
--- a/docker/test/integration/features/MiNiFi_integration_test_driver.py
+++ b/docker/test/integration/features/MiNiFi_integration_test_driver.py
@@ -437,6 +437,9 @@ class MiNiFi_integration_test:
     def enable_example_minifi_python_processors(self):
         self.cluster.enable_example_minifi_python_processors()
 
+    def enable_openssl_fips_mode_in_minifi(self):
+        self.cluster.enable_openssl_fips_mode_in_minifi()
+
     def debug_bundle_can_be_retrieved_through_minifi_controller(self, 
container_name: str):
         assert 
self.cluster.debug_bundle_can_be_retrieved_through_minifi_controller(container_name)
 or self.cluster.log_app_output()
 
diff --git a/docker/test/integration/features/https.feature 
b/docker/test/integration/features/https.feature
index f4ff9d246..6c6f459db 100644
--- a/docker/test/integration/features/https.feature
+++ b/docker/test/integration/features/https.feature
@@ -131,7 +131,8 @@ Feature: Transfer data from and to MiNiFi using HTTPS
 
 
   Scenario: InvokeHTTP to ListenHTTP with mutual TLS, using the system 
certificate store, requires a server cert signed by a CA
-    Given a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
     And the "Unique FlowFiles" property of the GenerateFlowFile processor is 
set to "false"
     And the "Custom Text" property of the GenerateFlowFile processor is set to 
"Duis aute irure dolor in reprehenderit in voluptate"
     And a InvokeHTTP processor with the "Remote URL" property set to 
"https://server-${feature_id}:4430/contentListener";
diff --git a/docker/test/integration/features/kafka.feature 
b/docker/test/integration/features/kafka.feature
index e7dedc2b2..84353f712 100644
--- a/docker/test/integration/features/kafka.feature
+++ b/docker/test/integration/features/kafka.feature
@@ -83,7 +83,8 @@ Feature: Sending data to using Kafka streaming platform using 
PublishKafka
     Then a flowfile with the content "no broker" is placed in the monitored 
directory in less than 60 seconds
 
   Scenario: PublishKafka sends can use SSL connect with security properties
-    Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And a file with the content "test" is present in "/tmp/input"
     And a PublishKafka processor set up to communicate with a kafka broker 
instance
     And these processor properties are set:
@@ -139,7 +140,8 @@ Feature: Sending data to using Kafka streaming platform 
using PublishKafka
     Then a flowfile with the content "test" is placed in the monitored 
directory in less than 60 seconds
 
   Scenario: PublishKafka sends can use SASL SSL connect with security 
properties
-    Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And a file with the content "test" is present in "/tmp/input"
     And a PublishKafka processor set up to communicate with a kafka broker 
instance
     And these processor properties are set:
@@ -170,7 +172,8 @@ Feature: Sending data to using Kafka streaming platform 
using PublishKafka
     Then a flowfile with the content "test" is placed in the monitored 
directory in less than 60 seconds
 
   Scenario: PublishKafka sends can use SASL SSL connect with SSL Context
-    Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And a file with the content "test" is present in "/tmp/input"
     And a PublishKafka processor set up to communicate with a kafka broker 
instance
     And these processor properties are set:
@@ -199,7 +202,8 @@ Feature: Sending data to using Kafka streaming platform 
using PublishKafka
     Then a flowfile with the content "test" is placed in the monitored 
directory in less than 60 seconds
 
   Scenario: PublishKafka sends can use SSL connect with SSL Context Service
-    Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And a file with the content "test" is present in "/tmp/input"
     And a PublishKafka processor set up to communicate with a kafka broker 
instance
     And these processor properties are set:
@@ -423,7 +427,8 @@ Feature: Sending data to using Kafka streaming platform 
using PublishKafka
       | Shogun           | James Clavell  | Message Header Encoding | UTF-32   
      |
 
   Scenario: ConsumeKafka receives data via SSL
-    Given a ConsumeKafka processor set up in a "kafka-consumer-flow" flow
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a ConsumeKafka processor set up in a "kafka-consumer-flow" flow
     And these processor properties are set:
       | processor name | property name     | property value                  |
       | ConsumeKafka   | Kafka Brokers     | kafka-broker-${feature_id}:9093 |
@@ -441,7 +446,8 @@ Feature: Sending data to using Kafka streaming platform 
using PublishKafka
     Then two flowfiles with the contents "Alice's Adventures in Wonderland" 
and "Lewis Carroll" are placed in the monitored directory in less than 60 
seconds
 
   Scenario: ConsumeKafka receives data via SASL SSL
-    Given a ConsumeKafka processor set up in a "kafka-consumer-flow" flow
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a ConsumeKafka processor set up in a "kafka-consumer-flow" flow
     And these processor properties are set:
       | processor name | property name     | property value                  |
       | ConsumeKafka   | Kafka Brokers     | kafka-broker-${feature_id}:9095 |
diff --git a/docker/test/integration/features/minifi_c2_server.feature 
b/docker/test/integration/features/minifi_c2_server.feature
index ff6640deb..b11e63d66 100644
--- a/docker/test/integration/features/minifi_c2_server.feature
+++ b/docker/test/integration/features/minifi_c2_server.feature
@@ -30,7 +30,8 @@ Feature: MiNiFi can communicate with Apache NiFi MiNiFi C2 
server
     And the Minifi logs do not contain the following message: "Failed to parse 
json response: The document is empty. at 0" after 0 seconds
 
   Scenario: MiNiFi flow config is updated from MiNiFi C2 server through SSL 
with SSL controller service
-    Given a file with the content "test" is present in "/tmp/input"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a file with the content "test" is present in "/tmp/input"
     And a ssl context service is set up for MiNiFi C2 server
     And a MiNiFi C2 server is set up with SSL
     When all instances start up
@@ -47,7 +48,8 @@ Feature: MiNiFi can communicate with Apache NiFi MiNiFi C2 
server
     And a flowfile with the content "test" is placed in the monitored 
directory in less than 10 seconds
 
   Scenario: MiNiFi flow config is updated from MiNiFi C2 server through SSL 
with SSL properties
-    Given a file with the content "test" is present in "/tmp/input"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a file with the content "test" is present in "/tmp/input"
     And a GenerateFlowFile processor
     And ssl properties are set up for MiNiFi C2 server
     And a MiNiFi C2 server is set up with SSL
diff --git a/docker/test/integration/features/opensearch.feature 
b/docker/test/integration/features/opensearch.feature
index f4e2fabb8..5a6877f49 100644
--- a/docker/test/integration/features/opensearch.feature
+++ b/docker/test/integration/features/opensearch.feature
@@ -20,7 +20,8 @@ Feature: PostElasticsearch works on Opensearch (Opensearch 
doesnt support API Ke
     Given the content of "/tmp/output" is monitored
 
   Scenario Outline: MiNiFi instance creates a document on Opensearch using 
Basic Authentication
-    Given an Opensearch server is set up and running
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And an Opensearch server is set up and running
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And a file with the content "{ "field1" : "value1" }" is present in 
"/tmp/input"
     And a PostElasticsearch processor
@@ -44,7 +45,8 @@ Feature: PostElasticsearch works on Opensearch (Opensearch 
doesnt support API Ke
       | "create" |
 
   Scenario: MiNiFi instance deletes a document from Opensearch using Basic 
Authentication
-    Given an Opensearch server is set up and a single document is present with 
"preloaded_id" in "my_index"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And an Opensearch server is set up and a single document is present with 
"preloaded_id" in "my_index"
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And a file with the content "hello world" is present in "/tmp/input"
     And a PostElasticsearch processor
@@ -63,7 +65,8 @@ Feature: PostElasticsearch works on Opensearch (Opensearch 
doesnt support API Ke
     And Opensearch is empty
 
   Scenario: MiNiFi instance partially updates a document in Opensearch using 
Basic Authentication
-    Given an Opensearch server is set up and a single document is present with 
"preloaded_id" in "my_index" with "value1" in "field1"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And an Opensearch server is set up and a single document is present with 
"preloaded_id" in "my_index" with "value1" in "field1"
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And a file with the content "{ "field2" : "value2" }" is present in 
"/tmp/input"
     And a PostElasticsearch processor
diff --git a/docker/test/integration/features/prometheus.feature 
b/docker/test/integration/features/prometheus.feature
index f336990b5..33a3ea2e7 100644
--- a/docker/test/integration/features/prometheus.feature
+++ b/docker/test/integration/features/prometheus.feature
@@ -37,7 +37,8 @@ Feature: MiNiFi can publish metrics to Prometheus server
     And all Prometheus metric types are only defined once
 
   Scenario: Published metrics are scraped by Prometheus server through SSL 
connection
-    Given a GetFile processor with the name "GetFile1" and the "Input 
Directory" property set to "/tmp/input"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a GetFile processor with the name "GetFile1" and the "Input Directory" 
property set to "/tmp/input"
     And a file with the content "test" is present in "/tmp/input"
     And a PutFile processor with the "Directory" property set to "/tmp/output"
     And the "success" relationship of the GetFile1 processor is connected to 
the PutFile
diff --git a/docker/test/integration/features/s2s.feature 
b/docker/test/integration/features/s2s.feature
index 80a8eb648..f279a4058 100644
--- a/docker/test/integration/features/s2s.feature
+++ b/docker/test/integration/features/s2s.feature
@@ -79,7 +79,8 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
     Then no files are placed in the monitored directory in 50 seconds of 
running time
 
   Scenario: A MiNiFi instance produces and transfers data to a NiFi instance 
via s2s using SSL
-    Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And the "Keep Source File" property of the GetFile processor is set to 
"true"
     And a file with the content "test" is present in "/tmp/input"
     And a RemoteProcessGroup node opened on 
"https://nifi-${feature_id}:8443/nifi";
@@ -96,7 +97,8 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
     And the Minifi logs do not contain the following message: "ProcessSession 
rollback" after 1 seconds
 
   Scenario: A MiNiFi instance produces and transfers data to a NiFi instance 
via s2s using SSL with YAML config
-    Given a MiNiFi CPP server with yaml config
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a MiNiFi CPP server with yaml config
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And the "Keep Source File" property of the GetFile processor is set to 
"true"
     And a file with the content "test" is present in "/tmp/input"
@@ -114,7 +116,8 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
     And the Minifi logs do not contain the following message: "ProcessSession 
rollback" after 1 seconds
 
   Scenario: A MiNiFi instance produces and transfers data to a NiFi instance 
via s2s using SSL config defined in minifi.properties
-    Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And the "Keep Source File" property of the GetFile processor is set to 
"true"
     And a file with the content "test" is present in "/tmp/input"
     And a RemoteProcessGroup node opened on 
"https://nifi-${feature_id}:8443/nifi";
@@ -131,7 +134,8 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
     And the Minifi logs do not contain the following message: "ProcessSession 
rollback" after 1 seconds
 
   Scenario: A MiNiFi instance produces and transfers data to a NiFi instance 
via s2s using YAML config and SSL config defined in minifi.properties
-    Given a MiNiFi CPP server with yaml config
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a MiNiFi CPP server with yaml config
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And the "Keep Source File" property of the GetFile processor is set to 
"true"
     And a file with the content "test" is present in "/tmp/input"
diff --git a/docker/test/integration/features/splunk.feature 
b/docker/test/integration/features/splunk.feature
index a6f99285e..3c18654d6 100644
--- a/docker/test/integration/features/splunk.feature
+++ b/docker/test/integration/features/splunk.feature
@@ -44,7 +44,8 @@ Feature: Sending data to Splunk HEC using PutSplunkHTTP
 
 
   Scenario: A MiNiFi instance transfers data to a Splunk HEC with SSL enabled
-    Given a Splunk HEC is set up and running
+    Given OpenSSL FIPS mode is enabled in MiNiFi
+    And a Splunk HEC is set up and running
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And a file with the content "foobar" is present in "/tmp/input"
     And a PutSplunkHTTP processor set up to communicate with the Splunk HEC 
instance
diff --git a/docker/test/integration/features/steps/steps.py 
b/docker/test/integration/features/steps/steps.py
index e65ca2f29..5d8a7c556 100644
--- a/docker/test/integration/features/steps/steps.py
+++ b/docker/test/integration/features/steps/steps.py
@@ -372,6 +372,11 @@ def step_impl(context):
     context.test.enable_prometheus_with_ssl_in_minifi()
 
 
+@given("OpenSSL FIPS mode is enabled in MiNiFi")
+def step_impl(context):
+    context.test.enable_openssl_fips_mode_in_minifi()
+
+
 # HTTP proxy setup
 @given("the http proxy server is set up")
 @given("a http proxy server is set up accordingly")
diff --git a/encrypt-config/tests/ConfigFileEncryptorTests.cpp 
b/encrypt-config/tests/ConfigFileEncryptorTests.cpp
index ab7a9d2f8..dd326c5b9 100644
--- a/encrypt-config/tests/ConfigFileEncryptorTests.cpp
+++ b/encrypt-config/tests/ConfigFileEncryptorTests.cpp
@@ -77,7 +77,7 @@ TEST_CASE("ConfigFileEncryptor can encrypt the sensitive 
properties", "[encrypt-
     uint32_t num_properties_encrypted = 
encryptSensitivePropertiesInFile(test_file, KEY);
 
     REQUIRE(num_properties_encrypted == 1);
-    REQUIRE(test_file.size() == 101);
+    REQUIRE(test_file.size() == 104);
     REQUIRE(check_encryption(test_file, Configuration::nifi_rest_api_password, 
original_password.length()));
 
     SECTION("calling encryptSensitiveValuesInMinifiProperties a second time 
does nothing") {
diff --git a/encrypt-config/tests/ConfigFileTests.cpp 
b/encrypt-config/tests/ConfigFileTests.cpp
index cd45ac3cb..cd998ff72 100644
--- a/encrypt-config/tests/ConfigFileTests.cpp
+++ b/encrypt-config/tests/ConfigFileTests.cpp
@@ -90,7 +90,7 @@ TEST_CASE("ConfigFile creates an empty object from a 
nonexistent file", "[encryp
 
 TEST_CASE("ConfigFile can parse a simple config file", 
"[encrypt-config][constructor]") {
   ConfigFile test_file{std::ifstream{"resources/minifi.properties"}};
-  REQUIRE(test_file.size() == 100);
+  REQUIRE(test_file.size() == 103);
 }
 
 TEST_CASE("ConfigFile can test whether a key is present", 
"[encrypt-config][hasValue]") {
@@ -102,7 +102,7 @@ TEST_CASE("ConfigFile can test whether a key is present", 
"[encrypt-config][hasV
 
 TEST_CASE("ConfigFile can read empty properties correctly", 
"[encrypt-config][constructor]") {
   ConfigFile 
test_file{std::ifstream{"resources/with-additional-sensitive-props.minifi.properties"}};
-  REQUIRE(test_file.size() == 102);
+  REQUIRE(test_file.size() == 105);
 
   auto empty_property = 
test_file.getValue(Configuration::nifi_security_need_ClientAuth);
   REQUIRE(empty_property);
@@ -143,7 +143,7 @@ TEST_CASE("ConfigFile can add a new setting after an 
existing setting", "[encryp
 
   SECTION("valid key") {
     test_file.insertAfter(Configuration::nifi_rest_api_password, 
"nifi.rest.api.password.protected", "my-cipher-name");
-    REQUIRE(test_file.size() == 101);
+    REQUIRE(test_file.size() == 104);
     REQUIRE(test_file.getValue("nifi.rest.api.password.protected") == 
"my-cipher-name");
   }
 
@@ -158,7 +158,7 @@ TEST_CASE("ConfigFile can add a new setting at the end", 
"[encrypt-config][appen
   const std::string KEY = "nifi.bootstrap.sensitive.key";
   const std::string VALUE = 
"aa411f289c91685ef9d5a9e5a4fad9393ff4c7a78ab978484323488caed7a9ab";
   test_file.append(KEY, VALUE);
-  REQUIRE(test_file.size() == 101);
+  REQUIRE(test_file.size() == 104);
   REQUIRE(test_file.getValue(KEY) == std::make_optional(VALUE));
 }
 
diff --git a/encrypt-config/tests/resources/minifi.properties 
b/encrypt-config/tests/resources/minifi.properties
index 2f2db68bb..6bb6566df 100644
--- a/encrypt-config/tests/resources/minifi.properties
+++ b/encrypt-config/tests/resources/minifi.properties
@@ -98,3 +98,6 @@ nifi.python.processor.dir=${MINIFI_HOME}/minifi-python/
 nifi.python.virtualenv.directory=${MINIFI_HOME}/minifi-python-env
 nifi.python.install.packages.automatically=true
 # nifi.python.env.setup.binary=python3
+
+# FIPS
+# nifi.openssl.fips.support.enable=false
diff --git 
a/encrypt-config/tests/resources/with-additional-sensitive-props.minifi.properties
 
b/encrypt-config/tests/resources/with-additional-sensitive-props.minifi.properties
index d2702c34d..8f468b2c8 100644
--- 
a/encrypt-config/tests/resources/with-additional-sensitive-props.minifi.properties
+++ 
b/encrypt-config/tests/resources/with-additional-sensitive-props.minifi.properties
@@ -100,3 +100,6 @@ nifi.python.processor.dir=${MINIFI_HOME}/minifi-python/
 nifi.python.virtualenv.directory=${MINIFI_HOME}/minifi-python-env
 nifi.python.install.packages.automatically=true
 # nifi.python.env.setup.binary=python3
+
+# FIPS
+# nifi.openssl.fips.support.enable=false
diff --git a/extensions/mqtt/processors/AbstractMQTTProcessor.cpp 
b/extensions/mqtt/processors/AbstractMQTTProcessor.cpp
index 3c73ae586..c7dc5dd82 100644
--- a/extensions/mqtt/processors/AbstractMQTTProcessor.cpp
+++ b/extensions/mqtt/processors/AbstractMQTTProcessor.cpp
@@ -318,7 +318,7 @@ void AbstractMQTTProcessor::disconnect() {
 
 void AbstractMQTTProcessor::setBrokerLimits(MQTTAsync_successData5* response) {
   auto readProperty = [response] (MQTTPropertyCodes property_code, auto& 
out_var) {
-    const int value = MQTTProperties_getNumericValue(&response->properties, 
property_code);
+    const auto value = MQTTProperties_getNumericValue(&response->properties, 
property_code);
     if (value != PAHO_MQTT_C_FAILURE_CODE) {
       if constexpr (std::is_same_v<decltype(out_var), 
std::optional<std::chrono::seconds>&>) {
         out_var = std::chrono::seconds(value);
diff --git a/fips/openssl.cnf b/fips/openssl.cnf
new file mode 100644
index 000000000..ab83ba2be
--- /dev/null
+++ b/fips/openssl.cnf
@@ -0,0 +1,13 @@
+openssl_conf = openssl_init
+
+.include ${MINIFI_HOME}/fips/fipsmodule.cnf
+
+[openssl_init]
+providers = prov
+
+[prov]
+fips = fips_sect
+base = base_sect
+
+[base_sect]
+activate = 1
diff --git a/libminifi/src/Configuration.cpp b/libminifi/src/Configuration.cpp
index df50a7d72..8acabcdb2 100644
--- a/libminifi/src/Configuration.cpp
+++ b/libminifi/src/Configuration.cpp
@@ -154,7 +154,8 @@ const std::unordered_map<std::string_view, 
gsl::not_null<const core::PropertyVal
   {Configuration::nifi_flow_file_repository_check_health, 
gsl::make_not_null(&core::StandardPropertyTypes::BOOLEAN_TYPE)},
   {Configuration::nifi_python_virtualenv_directory, 
gsl::make_not_null(&core::StandardPropertyTypes::VALID_TYPE)},
   {Configuration::nifi_python_env_setup_binary, 
gsl::make_not_null(&core::StandardPropertyTypes::VALID_TYPE)},
-  {Configuration::nifi_python_install_packages_automatically, 
gsl::make_not_null(&core::StandardPropertyTypes::BOOLEAN_TYPE)}
+  {Configuration::nifi_python_install_packages_automatically, 
gsl::make_not_null(&core::StandardPropertyTypes::BOOLEAN_TYPE)},
+  {Configuration::nifi_openssl_fips_support_enable, 
gsl::make_not_null(&core::StandardPropertyTypes::BOOLEAN_TYPE)}
 };
 
 const std::array<const char*, 2> Configuration::DEFAULT_SENSITIVE_PROPERTIES = 
{Configuration::nifi_security_client_pass_phrase,
diff --git a/libminifi/test/resources/encrypted.minifi.properties 
b/libminifi/test/resources/encrypted.minifi.properties
index f19422e43..dc1bf5272 100644
--- a/libminifi/test/resources/encrypted.minifi.properties
+++ b/libminifi/test/resources/encrypted.minifi.properties
@@ -104,3 +104,6 @@ nifi.python.processor.dir=${MINIFI_HOME}/minifi-python/
 nifi.python.virtualenv.directory=${MINIFI_HOME}/minifi-python-env
 nifi.python.install.packages.automatically=true
 # nifi.python.env.setup.binary=python3
+
+# FIPS
+# nifi.openssl.fips.support.enable=false
diff --git a/minifi-api/include/minifi-cpp/properties/Configuration.h 
b/minifi-api/include/minifi-cpp/properties/Configuration.h
index 280771ca5..2009e746f 100644
--- a/minifi-api/include/minifi-cpp/properties/Configuration.h
+++ b/minifi-api/include/minifi-cpp/properties/Configuration.h
@@ -200,6 +200,8 @@ class Configuration : public virtual Properties {
   static constexpr const char *nifi_python_env_setup_binary = 
"nifi.python.env.setup.binary";
   static constexpr const char *nifi_python_install_packages_automatically = 
"nifi.python.install.packages.automatically";
 
+  static constexpr const char *nifi_openssl_fips_support_enable = 
"nifi.openssl.fips.support.enable";
+
   MINIFIAPI static const std::unordered_map<std::string_view, 
gsl::not_null<const core::PropertyValidator*>> CONFIGURATION_PROPERTIES;
   MINIFIAPI static const std::array<const char*, 2> 
DEFAULT_SENSITIVE_PROPERTIES;
 
diff --git a/minifi_main/CMakeLists.txt b/minifi_main/CMakeLists.txt
index 47a4ab669..cddaf8873 100644
--- a/minifi_main/CMakeLists.txt
+++ b/minifi_main/CMakeLists.txt
@@ -33,7 +33,7 @@ endif()
 include(CppVersion)
 set_cpp_version()
 
-set(MINIFIEXE_SOURCES MiNiFiMain.cpp MainHelper.cpp MiNiFiWindowsService.cpp 
AgentDocs.cpp TableFormatter.cpp)
+set(MINIFIEXE_SOURCES MiNiFiMain.cpp MainHelper.cpp MiNiFiWindowsService.cpp 
AgentDocs.cpp TableFormatter.cpp Fips.cpp)
 if(WIN32)
     
set_source_files_properties("${CMAKE_BINARY_DIR}/libminifi/src/core/logging/WindowsMessageTextFile.rc"
 PROPERTIES GENERATED TRUE)
     list(APPEND MINIFIEXE_SOURCES 
"${CMAKE_BINARY_DIR}/libminifi/src/core/logging/WindowsMessageTextFile.rc")
diff --git a/minifi_main/Fips.cpp b/minifi_main/Fips.cpp
new file mode 100644
index 000000000..4a305a104
--- /dev/null
+++ b/minifi_main/Fips.cpp
@@ -0,0 +1,131 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "Fips.h"
+
+#include <fstream>
+#include <algorithm>
+#include <string>
+#include <openssl/provider.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include "utils/Environment.h"
+#include "utils/StringUtils.h"
+#include "utils/OptionalUtils.h"
+
+namespace org::apache::nifi::minifi::fips {
+
+namespace {
+bool replaceMinifiHomeVariable(const std::filesystem::path& file_path, const 
std::filesystem::path& minifi_home_path, const 
std::shared_ptr<core::logging::Logger>& logger) {
+  std::ifstream input_file(file_path);
+  if (!input_file) {
+    logger->log_error("Failed to open file: {}", file_path.string());
+    return false;
+  }
+
+  std::ostringstream buffer;
+  buffer << input_file.rdbuf();
+  std::string content = buffer.str();
+  input_file.close();
+
+  const std::string placeholder = "${MINIFI_HOME}";
+  size_t pos = content.find(placeholder, 0);
+  if (pos == std::string::npos) {
+    return true;
+  }
+
+  auto minifi_home_path_str = minifi_home_path.generic_string();
+  do {
+    content.replace(pos, placeholder.length(), minifi_home_path_str);
+    pos += minifi_home_path_str.length();
+  } while((pos = content.find(placeholder, pos)) != std::string::npos);
+
+  std::ofstream output_file(file_path);
+  if (!output_file) {
+    logger->log_error("Failed to open file for writing: {}", 
file_path.string());
+    return false;
+  }
+
+  output_file << content;
+  output_file.close();
+  return true;
+}
+}  // namespace
+
+void initializeFipsMode(const std::shared_ptr<minifi::Configure>& configure, 
const std::filesystem::path& minifi_home, const 
std::shared_ptr<core::logging::Logger>& logger) {
+  if (!(configure->get(minifi::Configure::nifi_openssl_fips_support_enable) | 
utils::andThen(utils::string::toBool)).value_or(false)) {
+    return;
+  }
+
+#ifdef WIN32
+  static constexpr std::string_view FIPS_LIB = "fips.dll";
+#elif defined(__APPLE__)
+  static constexpr std::string_view FIPS_LIB = "fips.dylib";
+#else
+  static constexpr std::string_view FIPS_LIB = "fips.so";
+#endif
+
+  if (!std::filesystem::exists(minifi_home / "fips" / FIPS_LIB)) {
+    logger->log_error("FIPS mode is enabled, but {} is not available in 
MINIFI_HOME/fips directory", FIPS_LIB);
+    std::exit(1);
+  }
+
+  if (!std::filesystem::exists(minifi_home / "fips" / "fipsmodule.cnf")) {
+    logger->log_error("FIPS mode is enabled, but fipsmodule.cnf is not 
available in MINIFI_HOME/fips directory. "
+      "Run MINIFI_HOME/fips/openssl fipsinstall -out fipsmodule.cnf -module 
MINIFI_HOME/fips/{} command to generate the configuration file", FIPS_LIB);
+    std::exit(1);
+  }
+
+  if (!std::filesystem::exists(minifi_home / "fips" / "openssl.cnf")) {
+    logger->log_error("FIPS mode is enabled, but openssl.cnf is not available 
in MINIFI_HOME/fips directory");
+    std::exit(1);
+  }
+
+  if (!replaceMinifiHomeVariable(minifi_home / "fips" / "openssl.cnf", 
minifi_home, logger)) {
+    logger->log_error("Failed to replace MINIFI_HOME variable in openssl.cnf");
+    std::exit(1);
+  }
+
+  utils::Environment::setEnvironmentVariable("OPENSSL_CONF", (minifi_home / 
"fips" / "openssl.cnf").string().c_str(), true);
+
+  if (!OSSL_PROVIDER_set_default_search_path(nullptr, (minifi_home / 
"fips").string().c_str())) {
+    logger->log_error("Failed to set FIPS module path: {}", (minifi_home / 
"fips").string());
+    ERR_print_errors_fp(stderr);
+    std::exit(1);
+  }
+
+  if (OSSL_PROVIDER_available(nullptr, "fips") != 1) {
+    logger->log_error("FIPS provider not available in default search path");
+    ERR_print_errors_fp(stderr);
+    std::exit(1);
+  }
+
+  if (!EVP_default_properties_enable_fips(nullptr, 1)) {
+    logger->log_error("Failed to enable FIPS mode");
+    ERR_print_errors_fp(stderr);
+    std::exit(1);
+  }
+
+  if (!EVP_default_properties_is_fips_enabled(nullptr)) {
+    logger->log_error("FIPS mode is not enabled");
+    ERR_print_errors_fp(stderr);
+    std::exit(1);
+  }
+
+  logger->log_info("FIPS mode enabled in MiNiFi C++");
+}
+
+}  // namespace org::apache::nifi::minifi::fips
diff --git a/minifi_main/Fips.h b/minifi_main/Fips.h
new file mode 100644
index 000000000..ab3261b0e
--- /dev/null
+++ b/minifi_main/Fips.h
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <filesystem>
+#include <memory>
+#include "core/logging/Logger.h"
+#include "minifi-cpp/properties/Configure.h"
+
+namespace org::apache::nifi::minifi::fips {
+
+void initializeFipsMode(const std::shared_ptr<Configure>& configure, const 
std::filesystem::path& minifi_home, const 
std::shared_ptr<core::logging::Logger>& logger);
+
+}  // namespace org::apache::nifi::minifi::utils::fips
diff --git a/minifi_main/MiNiFiMain.cpp b/minifi_main/MiNiFiMain.cpp
index 2297048f8..849ab2672 100644
--- a/minifi_main/MiNiFiMain.cpp
+++ b/minifi_main/MiNiFiMain.cpp
@@ -69,6 +69,7 @@
 #include "core/state/MetricsPublisherStore.h"
 #include "argparse/argparse.hpp"
 #include "agent/agent_version.h"
+#include "Fips.h"
 
 namespace minifi = org::apache::nifi::minifi;
 namespace core = minifi::core;
@@ -333,6 +334,8 @@ int main(int argc, char **argv) {
     configure->loadConfigureFile(DEFAULT_NIFI_PROPERTIES_FILE);
     overridePropertiesFromCommandLine(argument_parser, configure);
 
+    minifi::fips::initializeFipsMode(configure, minifiHome, logger);
+
     minifi::core::extension::ExtensionManagerImpl::get().initialize(configure);
 
     dumpDocsIfRequested(argument_parser, configure);
diff --git a/msi/WixWin.wsi.in b/msi/WixWin.wsi.in
index d39c5daed..3e4ccb5b3 100644
--- a/msi/WixWin.wsi.in
+++ b/msi/WixWin.wsi.in
@@ -59,6 +59,7 @@ ${WIX_EXTRA_FEATURES}
       <ComponentRef Id="LOGPROP"/>
       <ComponentRef Id="UIDPROP"/>
       <ComponentRef Id="CONFIGFILE"/>
+      <ComponentRef Id="OPENSSLCONFCOMP"/>
       <ComponentRef Id="UpdateConfig"/>
       <ComponentRef Id="UpdateConfigNotExist"/>
     </Feature>
@@ -326,6 +327,12 @@ ${WIX_EXTRA_FEATURES}
               </Component>
             </Directory>
 
+            <Directory Id="FIPSDIR" Name="fips">
+              <Component Id="OPENSSLCONFCOMP" 
Guid="77845aec-87fb-46e3-b0c8-b86b57256aec">
+                <File Id="OPENSSLCONF" Source="fips\openssl.cnf" 
KeyPath="yes"/>
+              </Component>
+            </Directory>
+
             <Directory Id="INSTALLBINDIR" Name="bin">
               <Component Id="minifiService" 
Guid="87658309-0339-425c-8633-f54ffaaa4921">
                 <File Id="MiNiFiExe" Name="minifi.exe" KeyPath="yes" 
Source="minifi_main\minifi.exe"/>
diff --git a/thirdparty/paho-mqtt/cmake-openssl.patch 
b/thirdparty/paho-mqtt/cmake-openssl.patch
index 4f94b89e0..b62f72fda 100644
--- a/thirdparty/paho-mqtt/cmake-openssl.patch
+++ b/thirdparty/paho-mqtt/cmake-openssl.patch
@@ -1,56 +1,58 @@
 diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 7bfee10..5debc1f 100644
+index ef145cd..a069f83 100644
 --- a/CMakeLists.txt
 +++ b/CMakeLists.txt
-@@ -23,7 +23,7 @@ MESSAGE(STATUS "CMake version: " ${CMAKE_VERSION})
- MESSAGE(STATUS "CMake system name: " ${CMAKE_SYSTEM_NAME})
+@@ -26,7 +26,7 @@ message(STATUS "CMake version: " ${CMAKE_VERSION})
+ message(STATUS "CMake system name: " ${CMAKE_SYSTEM_NAME})
  
- SET(CMAKE_SCRIPTS "${CMAKE_SOURCE_DIR}/cmake")
--SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
-+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
+ set(CMAKE_SCRIPTS "${PROJECT_SOURCE_DIR}/cmake")
+-set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules")
++list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules")
  
- ## build settings
- file(READ version.major PAHO_VERSION_MAJOR)
+ ## Project Version
+ ## Previously we read in the version from these files, but now we use the 
 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
-index 0bc7194..d2f8e6d 100644
+index 16382c1..c56d703 100644
 --- a/src/CMakeLists.txt
 +++ b/src/CMakeLists.txt
-@@ -316,20 +316,22 @@ INSTALL(FILES
-     "${CMAKE_CURRENT_BINARY_DIR}/eclipse-paho-mqtt-cConfigVersion.cmake"
-     DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/eclipse-paho-mqtt-c)
+@@ -412,22 +412,24 @@ install(
+     ${CMAKE_INSTALL_LIBDIR}/cmake/eclipse-paho-mqtt-c
+ )
  
 -# Base64 test
--ADD_EXECUTABLE( Base64Test EXCLUDE_FROM_ALL Base64.c Base64.h )
--TARGET_COMPILE_DEFINITIONS( Base64Test PUBLIC "-DBASE64_TEST" )
--IF (PAHO_WITH_SSL)
--      ADD_EXECUTABLE( Base64TestOpenSSL EXCLUDE_FROM_ALL Base64.c Base64.h )
--      TARGET_LINK_LIBRARIES( Base64TestOpenSSL OpenSSL::SSL OpenSSL::Crypto)
--      TARGET_COMPILE_DEFINITIONS( Base64TestOpenSSL PUBLIC "-DBASE64_TEST 
-DOPENSSL=1" )
--ENDIF (PAHO_WITH_SSL)
-+IF(PAHO_ENABLE_TESTING)
-+      # Base64 test
-+      ADD_EXECUTABLE( Base64Test EXCLUDE_FROM_ALL Base64.c Base64.h )
-+      TARGET_COMPILE_DEFINITIONS( Base64Test PUBLIC "-DBASE64_TEST" )
-+      IF (PAHO_WITH_SSL)
-+              ADD_EXECUTABLE( Base64TestOpenSSL EXCLUDE_FROM_ALL Base64.c 
Base64.h )
-+              TARGET_LINK_LIBRARIES( Base64TestOpenSSL OpenSSL::SSL 
OpenSSL::Crypto)
-+              TARGET_COMPILE_DEFINITIONS( Base64TestOpenSSL PUBLIC 
"-DBASE64_TEST -DOPENSSL=1" )
-+      ENDIF (PAHO_WITH_SSL)
+-add_executable(Base64Test EXCLUDE_FROM_ALL Base64.c Base64.h)
+-target_compile_definitions(Base64Test PUBLIC BASE64_TEST)
+-
+-if(PAHO_WITH_SSL OR PAHO_WITH_LIBRESSL)
+-  add_executable(Base64TestOpenSSL EXCLUDE_FROM_ALL Base64.c Base64.h )
+-  target_link_libraries(Base64TestOpenSSL ${SSL_LIBRARY_NAME}::SSL 
${SSL_LIBRARY_NAME}::Crypto)
+-  target_compile_definitions(Base64TestOpenSSL PUBLIC BASE64_TEST OPENSSL=1)
+-endif()
++if(PAHO_ENABLE_TESTING)
++  # Base64 test
++  add_executable(Base64Test EXCLUDE_FROM_ALL Base64.c Base64.h)
++  target_compile_definitions(Base64Test PUBLIC BASE64_TEST)
++
++  if(PAHO_WITH_SSL OR PAHO_WITH_LIBRESSL)
++    add_executable(Base64TestOpenSSL EXCLUDE_FROM_ALL Base64.c Base64.h )
++    target_link_libraries(Base64TestOpenSSL ${SSL_LIBRARY_NAME}::SSL 
${SSL_LIBRARY_NAME}::Crypto)
++    target_compile_definitions(Base64TestOpenSSL PUBLIC BASE64_TEST OPENSSL=1)
++  endif()
  
 -# SHA1 test
--ADD_EXECUTABLE( Sha1Test EXCLUDE_FROM_ALL SHA1.c SHA1.h )
--TARGET_COMPILE_DEFINITIONS( Sha1Test PUBLIC "-DSHA1_TEST" )
--IF (PAHO_WITH_SSL)
--      ADD_EXECUTABLE( Sha1TestOpenSSL EXCLUDE_FROM_ALL SHA1.c SHA1.h )
--      TARGET_LINK_LIBRARIES( Sha1TestOpenSSL OpenSSL::SSL OpenSSL::Crypto)
--      TARGET_COMPILE_DEFINITIONS( Sha1TestOpenSSL PUBLIC "-DSHA1_TEST 
-DOPENSSL=1" )
--ENDIF (PAHO_WITH_SSL)
-+      # SHA1 test
-+      ADD_EXECUTABLE( Sha1Test EXCLUDE_FROM_ALL SHA1.c SHA1.h )
-+      TARGET_COMPILE_DEFINITIONS( Sha1Test PUBLIC "-DSHA1_TEST" )
-+      IF (PAHO_WITH_SSL)
-+              ADD_EXECUTABLE( Sha1TestOpenSSL EXCLUDE_FROM_ALL SHA1.c SHA1.h )
-+              TARGET_LINK_LIBRARIES( Sha1TestOpenSSL OpenSSL::SSL 
OpenSSL::Crypto)
-+              TARGET_COMPILE_DEFINITIONS( Sha1TestOpenSSL PUBLIC "-DSHA1_TEST 
-DOPENSSL=1" )
-+      ENDIF (PAHO_WITH_SSL)
-+ENDIF()
+-add_executable(Sha1Test EXCLUDE_FROM_ALL SHA1.c SHA1.h)
+-target_compile_definitions(Sha1Test PUBLIC SHA1_TEST)
++  # SHA1 test
++  add_executable(Sha1Test EXCLUDE_FROM_ALL SHA1.c SHA1.h)
++  target_compile_definitions(Sha1Test PUBLIC SHA1_TEST)
+ 
+-if(PAHO_WITH_SSL OR PAHO_WITH_LIBRESSL)
+-      add_executable(Sha1TestOpenSSL EXCLUDE_FROM_ALL SHA1.c SHA1.h)
+-      target_link_libraries(Sha1TestOpenSSL ${SSL_LIBRARY_NAME}::SSL 
${SSL_LIBRARY_NAME}::Crypto)
+-      target_compile_definitions(Sha1TestOpenSSL PUBLIC SHA1_TEST OPENSSL=1)
++  if(PAHO_WITH_SSL OR PAHO_WITH_LIBRESSL)
++    add_executable(Sha1TestOpenSSL EXCLUDE_FROM_ALL SHA1.c SHA1.h)
++    target_link_libraries(Sha1TestOpenSSL ${SSL_LIBRARY_NAME}::SSL 
${SSL_LIBRARY_NAME}::Crypto)
++    target_compile_definitions(Sha1TestOpenSSL PUBLIC SHA1_TEST OPENSSL=1)
++  endif()
+ endif()

Reply via email to