| /** |
| * |
| * 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 "controllers/SSLContextService.h" |
| #include <openssl/err.h> |
| #include <openssl/ssl.h> |
| #include <string> |
| #include <memory> |
| #include <set> |
| #include "core/Property.h" |
| #include "io/validation.h" |
| #include "properties/Configure.h" |
| namespace org { |
| namespace apache { |
| namespace nifi { |
| namespace minifi { |
| namespace controllers { |
| |
| void SSLContextService::initialize() { |
| if (initialized_) |
| return; |
| |
| std::lock_guard<std::mutex> lock(initialization_mutex_); |
| |
| ControllerService::initialize(); |
| |
| initializeTLS(); |
| |
| initialized_ = true; |
| } |
| |
| std::unique_ptr<SSLContext> SSLContextService::createSSLContext() { |
| SSL_library_init(); |
| const SSL_METHOD *method; |
| |
| OpenSSL_add_all_algorithms(); |
| SSL_load_error_strings(); |
| method = TLSv1_2_client_method(); |
| SSL_CTX *ctx = SSL_CTX_new(method); |
| |
| if (!IsNullOrEmpty(certificate)) { |
| if (SSL_CTX_use_certificate_file(ctx, certificate.c_str(), SSL_FILETYPE_PEM) <= 0) { |
| logger_->log_error("Could not create load certificate, error : %s", std::strerror(errno)); |
| return nullptr; |
| } |
| if (!IsNullOrEmpty(passphrase_)) { |
| SSL_CTX_set_default_passwd_cb_userdata(ctx, &passphrase_); |
| SSL_CTX_set_default_passwd_cb(ctx, pemPassWordCb); |
| } |
| } |
| |
| if (!IsNullOrEmpty(private_key_)) { |
| int retp = SSL_CTX_use_PrivateKey_file(ctx, private_key_.c_str(), SSL_FILETYPE_PEM); |
| if (retp != 1) { |
| logger_->log_error("Could not create load private key,%i on %s error : %s", retp, private_key_, std::strerror(errno)); |
| return nullptr; |
| } |
| |
| if (!SSL_CTX_check_private_key(ctx)) { |
| logger_->log_error("Private key does not match the public certificate, error : %s", std::strerror(errno)); |
| return nullptr; |
| } |
| } |
| |
| int retp = SSL_CTX_load_verify_locations(ctx, ca_certificate_.c_str(), 0); |
| if (retp == 0) { |
| logger_->log_error("Can not load CA certificate %s, Exiting, error : %s", ca_certificate_, std::strerror(errno)); |
| } |
| return std::unique_ptr<SSLContext>(new SSLContext(ctx)); |
| } |
| |
| const std::string &SSLContextService::getCertificateFile() { |
| std::lock_guard<std::mutex> lock(initialization_mutex_); |
| return certificate; |
| } |
| |
| const std::string &SSLContextService::getPassphrase() { |
| std::lock_guard<std::mutex> lock(initialization_mutex_); |
| return passphrase_; |
| } |
| |
| const std::string &SSLContextService::getPassphraseFile() { |
| std::lock_guard<std::mutex> lock(initialization_mutex_); |
| return passphrase_file_; |
| } |
| |
| const std::string &SSLContextService::getPrivateKeyFile() { |
| std::lock_guard<std::mutex> lock(initialization_mutex_); |
| return private_key_; |
| } |
| |
| const std::string &SSLContextService::getCACertificate() { |
| std::lock_guard<std::mutex> lock(initialization_mutex_); |
| return ca_certificate_; |
| } |
| |
| void SSLContextService::onEnable() { |
| valid_ = true; |
| core::Property property("Client Certificate", "Client Certificate"); |
| core::Property privKey("Private Key", "Private Key file"); |
| core::Property passphrase_prop("Passphrase", "Client passphrase. Either a file or unencrypted text"); |
| core::Property caCert("CA Certificate", "CA certificate file"); |
| std::string default_dir; |
| if (nullptr != configuration_) |
| configuration_->get(Configure::nifi_default_directory, default_dir); |
| |
| logger_->log_trace("onEnable()"); |
| |
| if (getProperty(property.getName(), certificate) && getProperty(privKey.getName(), private_key_)) { |
| std::ifstream cert_file(certificate); |
| std::ifstream priv_file(private_key_); |
| if (!cert_file.good()) { |
| logger_->log_info("%s not good", certificate); |
| std::string test_cert = default_dir + certificate; |
| std::ifstream cert_file_test(test_cert); |
| if (cert_file_test.good()) { |
| certificate = test_cert; |
| logger_->log_debug("%s now good", certificate); |
| } else { |
| logger_->log_warn("%s still not good", test_cert); |
| valid_ = false; |
| } |
| cert_file_test.close(); |
| } |
| |
| if (!priv_file.good()) { |
| std::string test_priv = default_dir + private_key_; |
| std::ifstream private_file_test(test_priv); |
| if (private_file_test.good()) { |
| private_key_ = test_priv; |
| } else { |
| valid_ = false; |
| } |
| private_file_test.close(); |
| } |
| cert_file.close(); |
| priv_file.close(); |
| |
| } else { |
| logger_->log_debug("Certificate empty"); |
| } |
| if (!getProperty(passphrase_prop.getName(), passphrase_)) { |
| logger_->log_debug("No pass phrase for %s", certificate); |
| } else { |
| std::ifstream passphrase_file(passphrase_); |
| if (passphrase_file.good()) { |
| passphrase_file_ = passphrase_; |
| // we should read it from the file |
| passphrase_.assign((std::istreambuf_iterator<char>(passphrase_file)), std::istreambuf_iterator<char>()); |
| } else { |
| std::string test_passphrase = default_dir + passphrase_; |
| std::ifstream passphrase_file_test(test_passphrase); |
| if (passphrase_file_test.good()) { |
| passphrase_ = test_passphrase; |
| passphrase_file_ = test_passphrase; |
| passphrase_.assign((std::istreambuf_iterator<char>(passphrase_file_test)), std::istreambuf_iterator<char>()); |
| } else { |
| valid_ = false; |
| } |
| passphrase_file_test.close(); |
| } |
| passphrase_file.close(); |
| } |
| // load CA certificates |
| if (!getProperty(caCert.getName(), ca_certificate_)) { |
| logger_->log_error("Can not load CA certificate."); |
| } else { |
| std::ifstream cert_file(ca_certificate_); |
| if (!cert_file.good()) { |
| std::string test_ca_cert = default_dir + ca_certificate_; |
| std::ifstream ca_cert_file_file_test(test_ca_cert); |
| if (ca_cert_file_file_test.good()) { |
| ca_certificate_ = test_ca_cert; |
| } else { |
| valid_ = false; |
| } |
| ca_cert_file_file_test.close(); |
| } |
| cert_file.close(); |
| } |
| } |
| |
| void SSLContextService::initializeTLS() { |
| core::Property property("Client Certificate", "Client Certificate"); |
| core::Property privKey("Private Key", "Private Key file"); |
| core::Property passphrase_prop("Passphrase", "Client passphrase. Either a file or unencrypted text"); |
| core::Property caCert("CA Certificate", "CA certificate file"); |
| std::set<core::Property> supportedProperties; |
| supportedProperties.insert(property); |
| supportedProperties.insert(privKey); |
| supportedProperties.insert(passphrase_prop); |
| supportedProperties.insert(caCert); |
| setSupportedProperties(supportedProperties); |
| } |
| |
| } /* namespace controllers */ |
| } /* namespace minifi */ |
| } /* namespace nifi */ |
| } /* namespace apache */ |
| } /* namespace org */ |