Skip to content

Commit

Permalink
MINIFICPP-1070 - Fixed handling of PKCS12 certificates
Browse files Browse the repository at this point in the history
There are two issues fixed in this commit:

* SSLContextService was ignoring additional certs in the P12
  file, which was preventing the server to establish trust of
  the client certificate when it was signed by an intermediate
  CA.
* TLSSocket only supported PEM certificates. It has been changed
  to delegate the handling of cert files to the SSLContextService.
  • Loading branch information
asdaraujo committed Oct 22, 2019
1 parent 77b579b commit 6781bff
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 56 deletions.
90 changes: 56 additions & 34 deletions libminifi/src/controllers/SSLContextService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ bool SSLContextService::configure_ssl_context(SSL_CTX *ctx) {
}
EVP_PKEY* pkey = nullptr;
X509* cert = nullptr;
if (!PKCS12_parse(p12, passphrase_.c_str(), &pkey, &cert, nullptr /*ca*/)) {
stack_st_X509* ca = nullptr;
if (!PKCS12_parse(p12, passphrase_.c_str(), &pkey, &cert, &ca)) {
//if (!PKCS12_parse(p12, passphrase_.c_str(), &pkey, &cert, nullptr /*ca*/)) {
logging::LOG_ERROR(logger_) << "Failed to parse certificate file " << certificate << " as PKCS#12, " << getLatestOpenSSLErrorString();
PKCS12_free(p12);
return false;
Expand All @@ -80,7 +82,16 @@ bool SSLContextService::configure_ssl_context(SSL_CTX *ctx) {
X509_free(cert);
return false;
}
if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) {
while (ca != nullptr && sk_X509_num(ca)) {
X509 * cacert = sk_X509_pop(ca);
if (SSL_CTX_add_extra_chain_cert(ctx, cacert) != 1) {
logging::LOG_ERROR(logger_) << "Failed to set additional certificate from " << certificate << ", " << getLatestOpenSSLErrorString();
EVP_PKEY_free(pkey);
X509_free(cacert);
return false;
}
}
if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) {
logging::LOG_ERROR(logger_) << "Failed to set private key from " << certificate << ", " << getLatestOpenSSLErrorString();
EVP_PKEY_free(pkey);
X509_free(cert);
Expand Down Expand Up @@ -192,38 +203,49 @@ void SSLContextService::onEnable() {

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(property.getName(), certificate)) {
std::ifstream cert_file(certificate);
if (!cert_file.good()) {
logger_->log_warn("Cannot open certificate file %s", 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_info("Using certificate file %s", certificate);
}
else {
logger_->log_error("Cannot open certificate file %s", test_cert);
valid_ = false;
}
cert_file_test.close();
}
cert_file.close();
}
else {
logger_->log_debug("Certificate empty");
}
if (getProperty(property.getName(), certificate) && !isFileTypeP12(certificate)) {
if (getProperty(privKey.getName(), private_key_)) {
std::ifstream priv_file(private_key_);
if (!priv_file.good()) {
logger_->log_warn("Cannot open private key file %s", private_key_);
std::string test_priv = default_dir + private_key_;
std::ifstream private_file_test(test_priv);
if (private_file_test.good()) {
private_key_ = test_priv;
logger_->log_info("Using private key file %s", private_key_);
}
else {
logger_->log_error("Cannot open private key file %s", test_priv);
valid_ = false;
}
private_file_test.close();
}
priv_file.close();
}
else {
logger_->log_debug("Private key empty");
}
}
if (!getProperty(passphrase_prop.getName(), passphrase_)) {
logger_->log_debug("No pass phrase for %s", certificate);
Expand Down
39 changes: 17 additions & 22 deletions libminifi/src/io/tls/TLSSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,40 +80,35 @@ int16_t TLSContext::initialize(bool server_method) {
std::string caCertificate;

if (ssl_service_ != nullptr) {
certificate = ssl_service_->getCertificateFile();
privatekey = ssl_service_->getPrivateKeyFile();
caCertificate = ssl_service_->getCACertificate();
passphrase = ssl_service_->getPassphrase();
} else {
if (!(configure_->get(Configure::nifi_security_client_certificate, certificate) && configure_->get(Configure::nifi_security_client_private_key, privatekey))) {
if (!ssl_service_->configure_ssl_context(ctx)) {
error_value = TLS_ERROR_CERT_ERROR;
return error_value;
}
return 0;
}

if (!(configure_->get(Configure::nifi_security_client_certificate, certificate) && configure_->get(Configure::nifi_security_client_private_key, privatekey))) {
logger_->log_error("Certificate and Private Key PEM file not configured, error: %s.", std::strerror(errno));
error_value = TLS_ERROR_PEM_MISSING;
return error_value;
}
}
// load certificates and private key in PEM format
if (SSL_CTX_use_certificate_chain_file(ctx, certificate.c_str()) <= 0) {
logger_->log_error("Could not load certificate %s, for %X and %X error : %s", certificate, this, ctx, std::strerror(errno));
error_value = TLS_ERROR_CERT_MISSING;
return error_value;
}
if (ssl_service_ != nullptr) {
// if the private key has passphase
if (configure_->get(Configure::nifi_security_client_pass_phrase, passphrase)) {
std::ifstream file(passphrase.c_str(), std::ifstream::in);
if (file.good()) {
// if we have been given a file copy that, otherwise treat the passphrase as a password
std::string password;
password.assign((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
passphrase = password;
}
SSL_CTX_set_default_passwd_cb(ctx, io::tls::pemPassWordCb);
SSL_CTX_set_default_passwd_cb_userdata(ctx, &passphrase);
} else {
if (configure_->get(Configure::nifi_security_client_pass_phrase, passphrase)) {
std::ifstream file(passphrase.c_str(), std::ifstream::in);
if (file.good()) {
// if we have been given a file copy that, otherwise treat the passphrase as a password
std::string password;
password.assign((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
passphrase = password;
}
SSL_CTX_set_default_passwd_cb(ctx, io::tls::pemPassWordCb);
SSL_CTX_set_default_passwd_cb_userdata(ctx, &passphrase);
}
}

int retp = SSL_CTX_use_PrivateKey_file(ctx, privatekey.c_str(), SSL_FILETYPE_PEM);
Expand Down

0 comments on commit 6781bff

Please sign in to comment.