minifi_main/Fips.cpp (111 lines of code) (raw):

/** * 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 { #ifdef WIN32 constexpr std::string_view FIPS_LIB = "fips.dll"; #elif defined(__APPLE__) constexpr std::string_view FIPS_LIB = "fips.dylib"; #else constexpr std::string_view FIPS_LIB = "fips.so"; #endif 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; } bool generateFipsModuleConfig(const std::filesystem::path& minifi_home, const std::shared_ptr<core::logging::Logger>& logger) { std::filesystem::path output_file(minifi_home / "fips" / "fipsmodule.cnf"); logger->log_info("fipsmodule.cnf was not found, trying to run fipsinstall command to generate the file"); #ifdef WIN32 std::string command = "\"\"" + (minifi_home / "fips" / "openssl.exe").string() + "\" fipsinstall -out \"" + output_file.string() + "\" -module \"" + (minifi_home / "fips" / FIPS_LIB).string() + "\"\""; #else std::string command = "\"" + (minifi_home / "fips" / "openssl").string() + "\" fipsinstall -out \"" + output_file.string() + "\" -module \"" + (minifi_home / "fips" / FIPS_LIB).string() + "\""; #endif auto ret = std::system(command.c_str()); if (ret != 0) { logger->log_error("Failed to generate fipsmodule.cnf file"); return false; } logger->log_info("Successfully generated fipsmodule.cnf file"); 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)) { logger->log_info("FIPS mode is disabled. FIPS configs and modules will NOT be loaded."); return; } 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") && !generateFipsModuleConfig(minifi_home, logger)) { logger->log_error("FIPS mode is enabled, but fipsmodule.cnf is not available in $MINIFI_HOME/fips directory, and minifi couldn't generate it automatically. " "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