[GitHub] [nifi-minifi-cpp] szaszm commented on a change in pull request #947: MINIFICPP-1401 Read certificates from the Windows system store

2020-12-08 Thread GitBox


szaszm commented on a change in pull request #947:
URL: https://github.com/apache/nifi-minifi-cpp/pull/947#discussion_r538647760



##
File path: libminifi/src/utils/tls/ExtendedKeyUsage.cpp
##
@@ -0,0 +1,104 @@
+/**
+ * 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.
+ */
+#ifdef OPENSSL_SUPPORT
+
+#include "utils/tls/ExtendedKeyUsage.h"
+
+#include 
+
+#include 
+#include 
+#include 
+
+#include "core/logging/LoggerConfiguration.h"
+#include "utils/StringUtils.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace utils {
+namespace tls {
+
+namespace {
+
+struct KeyValuePair {
+  const char* key;
+  uint8_t value;
+};
+constexpr std::array EXT_KEY_USAGE_NAME_TO_BIT_POS{{
+KeyValuePair{"Server Authentication", 1},
+KeyValuePair{"Client Authentication", 2},
+KeyValuePair{"Code Signing", 3},
+KeyValuePair{"Secure Email", 4},
+KeyValuePair{"Time Stamping", 8},
+KeyValuePair{"OCSP Signing", 9}
+}};
+
+}  // namespace
+
+void EXTENDED_KEY_USAGE_deleter::operator()(EXTENDED_KEY_USAGE* key_usage) 
const { EXTENDED_KEY_USAGE_free(key_usage); }
+
+ExtendedKeyUsage::ExtendedKeyUsage() : 
logger_(core::logging::LoggerFactory::getLogger()) {}
+
+ExtendedKeyUsage::ExtendedKeyUsage(const EXTENDED_KEY_USAGE& key_usage_asn1) : 
ExtendedKeyUsage{} {
+  const int num_oids = sk_ASN1_OBJECT_num(_usage_asn1);
+  for (int i = 0; i < num_oids; ++i) {
+const ASN1_OBJECT* const oid = sk_ASN1_OBJECT_value(_usage_asn1, i);
+assert(oid && oid->length > 0);
+const unsigned char bit_pos = oid->data[oid->length - 1];

Review comment:
   Ah, I see. I had some trouble reading ASN, but I think I see what you 
mean now: id-kp is the same and the last element (byte?) is different.





This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org




[GitHub] [nifi-minifi-cpp] szaszm commented on a change in pull request #947: MINIFICPP-1401 Read certificates from the Windows system store

2020-12-08 Thread GitBox


szaszm commented on a change in pull request #947:
URL: https://github.com/apache/nifi-minifi-cpp/pull/947#discussion_r538636172



##
File path: libminifi/src/controllers/SSLContextService.cpp
##
@@ -128,16 +149,239 @@ bool SSLContextService::configure_ssl_context(SSL_CTX 
*ctx) {
   }
 
   SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, nullptr);
-  int retp = SSL_CTX_load_verify_locations(ctx, ca_certificate_.c_str(), 0);
 
-  if (retp == 0) {
-logging::LOG_ERROR(logger_) << "Can not load CA certificate, Exiting, " << 
getLatestOpenSSLErrorString();
+  if (!IsNullOrEmpty(ca_certificate_)) {
+if (SSL_CTX_load_verify_locations(ctx, ca_certificate_.c_str(), 0) == 0) {
+  logging::LOG_ERROR(logger_) << "Cannot load CA certificate, exiting, " 
<< getLatestOpenSSLErrorString();
+  return false;
+}
+  }
+
+  if (use_system_cert_store_ && IsNullOrEmpty(certificate_)) {
+if (!addClientCertificateFromSystemStoreToSSLContext(ctx)) {
+  return false;
+}
+  }
+
+  if (use_system_cert_store_ && IsNullOrEmpty(ca_certificate_)) {
+if (!addServerCertificatesFromSystemStoreToSSLContext(ctx)) {
+  return false;
+}
+  }
+
+  return true;
+}
+
+bool SSLContextService::addP12CertificateToSSLContext(SSL_CTX* ctx) const {
+  const auto fp_deleter = [](BIO* ptr) { BIO_free(ptr); };
+  std::unique_ptr fp(BIO_new(BIO_s_file()), 
fp_deleter);
+  if (fp == nullptr) {
+logging::LOG_ERROR(logger_) << "Failed create new file BIO, " << 
getLatestOpenSSLErrorString();
+return false;
+  }
+  if (BIO_read_filename(fp.get(), certificate_.c_str()) <= 0) {
+logging::LOG_ERROR(logger_) << "Failed to read certificate file " << 
certificate_ << ", " << getLatestOpenSSLErrorString();
+return false;
+  }
+  const auto p12_deleter = [](PKCS12* ptr) { PKCS12_free(ptr); };
+  std::unique_ptr p12(d2i_PKCS12_bio(fp.get(), 
nullptr), p12_deleter);
+  if (p12 == nullptr) {
+logging::LOG_ERROR(logger_) << "Failed to DER decode certificate file " << 
certificate_ << ", " << getLatestOpenSSLErrorString();
+return false;
+  }
+
+  EVP_PKEY* pkey = nullptr;
+  X509* cert = nullptr;
+  STACK_OF(X509)* ca = nullptr;
+  if (!PKCS12_parse(p12.get(), passphrase_.c_str(), , , )) {
+logging::LOG_ERROR(logger_) << "Failed to parse certificate file " << 
certificate_ << " as PKCS#12, " << getLatestOpenSSLErrorString();
+return false;
+  }
+  utils::tls::EVP_PKEY_unique_ptr pkey_ptr{pkey};
+  utils::tls::X509_unique_ptr cert_ptr{cert};
+  const auto ca_deleter = gsl::finally([ca] { sk_X509_pop_free(ca, X509_free); 
});
+
+  if (SSL_CTX_use_certificate(ctx, cert) != 1) {
+logging::LOG_ERROR(logger_) << "Failed to set certificate from " << 
certificate_ << ", " << getLatestOpenSSLErrorString();
+return false;
+  }
+  while (ca != nullptr && sk_X509_num(ca) > 0) {
+utils::tls::X509_unique_ptr cacert{sk_X509_pop(ca)};
+if (SSL_CTX_add_extra_chain_cert(ctx, cacert.get()) != 1) {
+  logging::LOG_ERROR(logger_) << "Failed to set additional certificate 
from " << certificate_ << ", " << getLatestOpenSSLErrorString();
+  return false;
+}
+cacert.release();  // a successful SSL_CTX_add_extra_chain_cert() takes 
ownership of cacert
+  }
+  if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) {
+logging::LOG_ERROR(logger_) << "Failed to set private key from " << 
certificate_ << ", " << getLatestOpenSSLErrorString();
 return false;
   }
 
   return true;
 }
-#endif
+
+bool SSLContextService::addPemCertificateToSSLContext(SSL_CTX* ctx) const {
+  if (SSL_CTX_use_certificate_chain_file(ctx, certificate_.c_str()) <= 0) {
+logging::LOG_ERROR(logger_) << "Could not load client certificate " << 
certificate_ << ", " << getLatestOpenSSLErrorString();
+return false;
+  }
+
+  if (!IsNullOrEmpty(passphrase_)) {
+void* passphrase = const_cast(_);
+SSL_CTX_set_default_passwd_cb_userdata(ctx, passphrase);
+SSL_CTX_set_default_passwd_cb(ctx, minifi::utils::tls::pemPassWordCb);
+  }
+
+  if (!IsNullOrEmpty(private_key_)) {
+int retp = SSL_CTX_use_PrivateKey_file(ctx, private_key_.c_str(), 
SSL_FILETYPE_PEM);
+if (retp != 1) {
+  logging::LOG_ERROR(logger_) << "Could not load private key, " << retp << 
" on " << private_key_ << ", " << getLatestOpenSSLErrorString();
+  return false;
+}
+  }
+
+  return true;
+}
+
+bool 
SSLContextService::addClientCertificateFromSystemStoreToSSLContext(SSL_CTX* 
ctx) const {
+#ifdef WIN32
+  utils::tls::WindowsCertStoreLocation store_location{cert_store_location_};
+  HCERTSTORE hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, NULL,
+CERT_STORE_OPEN_EXISTING_FLAG | 
CERT_STORE_READONLY_FLAG | store_location.getBitfieldValue(),
+client_cert_store_.data());
+  if (!hCertStore) {
+logger_->log_error("Could not open system certificate store %s/%s (client 
certificates)", cert_store_location_, client_cert_store_);
+

[GitHub] [nifi-minifi-cpp] szaszm commented on a change in pull request #947: MINIFICPP-1401 Read certificates from the Windows system store

2020-12-08 Thread GitBox


szaszm commented on a change in pull request #947:
URL: https://github.com/apache/nifi-minifi-cpp/pull/947#discussion_r538632918



##
File path: libminifi/src/utils/tls/ExtendedKeyUsage.cpp
##
@@ -0,0 +1,104 @@
+/**
+ * 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.
+ */
+#ifdef OPENSSL_SUPPORT
+
+#include "utils/tls/ExtendedKeyUsage.h"
+
+#include 
+
+#include 
+#include 
+#include 
+
+#include "core/logging/LoggerConfiguration.h"
+#include "utils/StringUtils.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace utils {
+namespace tls {
+
+namespace {
+
+struct KeyValuePair {
+  const char* key;
+  uint8_t value;
+};
+constexpr std::array EXT_KEY_USAGE_NAME_TO_BIT_POS{{
+KeyValuePair{"Server Authentication", 1},
+KeyValuePair{"Client Authentication", 2},
+KeyValuePair{"Code Signing", 3},
+KeyValuePair{"Secure Email", 4},
+KeyValuePair{"Time Stamping", 8},
+KeyValuePair{"OCSP Signing", 9}
+}};
+
+}  // namespace
+
+void EXTENDED_KEY_USAGE_deleter::operator()(EXTENDED_KEY_USAGE* key_usage) 
const { EXTENDED_KEY_USAGE_free(key_usage); }
+
+ExtendedKeyUsage::ExtendedKeyUsage() : 
logger_(core::logging::LoggerFactory::getLogger()) {}
+
+ExtendedKeyUsage::ExtendedKeyUsage(const EXTENDED_KEY_USAGE& key_usage_asn1) : 
ExtendedKeyUsage{} {
+  const int num_oids = sk_ASN1_OBJECT_num(_usage_asn1);
+  for (int i = 0; i < num_oids; ++i) {
+const ASN1_OBJECT* const oid = sk_ASN1_OBJECT_value(_usage_asn1, i);
+assert(oid && oid->length > 0);
+const unsigned char bit_pos = oid->data[oid->length - 1];

Review comment:
   My problem is that I couldn't find a source that describes the structure 
of extended key usage asn1 objects in detail. I don't understand why we index 
to the last element (byte?) of the object and why it contains the bit position 
that we use below.





This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org




[GitHub] [nifi-minifi-cpp] szaszm commented on a change in pull request #947: MINIFICPP-1401 Read certificates from the Windows system store

2020-12-08 Thread GitBox


szaszm commented on a change in pull request #947:
URL: https://github.com/apache/nifi-minifi-cpp/pull/947#discussion_r538274424



##
File path: libminifi/src/utils/tls/ExtendedKeyUsage.cpp
##
@@ -0,0 +1,104 @@
+/**
+ * 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.
+ */
+#ifdef OPENSSL_SUPPORT
+
+#include "utils/tls/ExtendedKeyUsage.h"
+
+#include 
+
+#include 
+#include 
+#include 
+
+#include "core/logging/LoggerConfiguration.h"
+#include "utils/StringUtils.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace utils {
+namespace tls {
+
+namespace {
+
+struct KeyValuePair {
+  const char* key;
+  uint8_t value;
+};
+constexpr std::array EXT_KEY_USAGE_NAME_TO_BIT_POS{{
+KeyValuePair{"Server Authentication", 1},
+KeyValuePair{"Client Authentication", 2},
+KeyValuePair{"Code Signing", 3},
+KeyValuePair{"Secure Email", 4},
+KeyValuePair{"Time Stamping", 8},
+KeyValuePair{"OCSP Signing", 9}
+}};

Review comment:
   A source for these constants would be nice. I've found them in RFC3280 
on page 109.

##
File path: libminifi/src/utils/tls/ExtendedKeyUsage.cpp
##
@@ -0,0 +1,104 @@
+/**
+ * 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.
+ */
+#ifdef OPENSSL_SUPPORT
+
+#include "utils/tls/ExtendedKeyUsage.h"
+
+#include 
+
+#include 
+#include 
+#include 
+
+#include "core/logging/LoggerConfiguration.h"
+#include "utils/StringUtils.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace utils {
+namespace tls {
+
+namespace {
+
+struct KeyValuePair {
+  const char* key;
+  uint8_t value;
+};
+constexpr std::array EXT_KEY_USAGE_NAME_TO_BIT_POS{{
+KeyValuePair{"Server Authentication", 1},
+KeyValuePair{"Client Authentication", 2},
+KeyValuePair{"Code Signing", 3},
+KeyValuePair{"Secure Email", 4},
+KeyValuePair{"Time Stamping", 8},
+KeyValuePair{"OCSP Signing", 9}
+}};
+
+}  // namespace
+
+void EXTENDED_KEY_USAGE_deleter::operator()(EXTENDED_KEY_USAGE* key_usage) 
const { EXTENDED_KEY_USAGE_free(key_usage); }
+
+ExtendedKeyUsage::ExtendedKeyUsage() : 
logger_(core::logging::LoggerFactory::getLogger()) {}
+
+ExtendedKeyUsage::ExtendedKeyUsage(const EXTENDED_KEY_USAGE& key_usage_asn1) : 
ExtendedKeyUsage{} {
+  const int num_oids = sk_ASN1_OBJECT_num(_usage_asn1);
+  for (int i = 0; i < num_oids; ++i) {
+const ASN1_OBJECT* const oid = sk_ASN1_OBJECT_value(_usage_asn1, i);
+assert(oid && oid->length > 0);
+const unsigned char bit_pos = oid->data[oid->length - 1];

Review comment:
   Could you provide some structure references for mortals like myself to 
be able to see what makes e.g. `oid->data[oid->length - 1]` be the bit to be 
set in the extended key usage bitset?

##
File path: libminifi/src/controllers/SSLContextService.cpp
##
@@ -128,16 +149,239 @@ bool SSLContextService::configure_ssl_context(SSL_CTX 
*ctx) {
   }
 
   SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, nullptr);
-  int retp = SSL_CTX_load_verify_locations(ctx, ca_certificate_.c_str(), 0);
 
-  if (retp == 0) {
-logging::LOG_ERROR(logger_) << "Can not load CA certificate, Exiting, " << 
getLatestOpenSSLErrorString();
+  if (!IsNullOrEmpty(ca_certificate_)) {
+if (SSL_CTX_load_verify_locations(ctx, ca_certificate_.c_str(), 0) == 0) {
+  logging::LOG_ERROR(logger_) << "Cannot load CA certificate, exiting, " 
<< getLatestOpenSSLErrorString();
+  return false;
+}

[GitHub] [nifi-minifi-cpp] szaszm commented on a change in pull request #947: MINIFICPP-1401 Read certificates from the Windows system store

2020-12-05 Thread GitBox


szaszm commented on a change in pull request #947:
URL: https://github.com/apache/nifi-minifi-cpp/pull/947#discussion_r536913865



##
File path: libminifi/src/utils/tls/DistinguishedName.cpp
##
@@ -0,0 +1,64 @@
+/**
+ * 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 "utils/tls/DistinguishedName.h"
+
+#include 
+
+#include "utils/StringUtils.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace utils {
+namespace tls {
+
+DistinguishedName::DistinguishedName(const std::vector& 
components) {
+  std::transform(components.begin(), components.end(), 
std::back_inserter(components_),
+  [](const std::string& component) { return 
utils::StringUtils::trim(component); });
+  std::sort(components_.begin(), components_.end());
+}
+
+DistinguishedName DistinguishedName::fromCommaSeparated(const std::string& 
comma_separated_components) {
+  return 
DistinguishedName{utils::StringUtils::split(comma_separated_components, ",")};
+}
+
+DistinguishedName DistinguishedName::fromSlashSeparated(const std::string 
_separated_components) {
+  return 
DistinguishedName{utils::StringUtils::split(slash_separated_components, "/")};

Review comment:
   That's a great idea, I'm fine with leaving it as is in the meantime. I 
think deployments with the most frequent heartbeat intervals are around 1/sec, 
so it should be fine in either case.





This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org




[GitHub] [nifi-minifi-cpp] szaszm commented on a change in pull request #947: MINIFICPP-1401 Read certificates from the Windows system store

2020-12-05 Thread GitBox


szaszm commented on a change in pull request #947:
URL: https://github.com/apache/nifi-minifi-cpp/pull/947#discussion_r536913327



##
File path: libminifi/src/utils/tls/DistinguishedName.cpp
##
@@ -0,0 +1,64 @@
+/**
+ * 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 "utils/tls/DistinguishedName.h"
+
+#include 
+
+#include "utils/StringUtils.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace utils {
+namespace tls {
+
+DistinguishedName::DistinguishedName(const std::vector& 
components) {
+  std::transform(components.begin(), components.end(), 
std::back_inserter(components_),
+  [](const std::string& component) { return 
utils::StringUtils::trim(component); });
+  std::sort(components_.begin(), components_.end());
+}
+
+DistinguishedName DistinguishedName::fromCommaSeparated(const std::string& 
comma_separated_components) {
+  return 
DistinguishedName{utils::StringUtils::split(comma_separated_components, ",")};
+}
+
+DistinguishedName DistinguishedName::fromSlashSeparated(const std::string 
_separated_components) {
+  return 
DistinguishedName{utils::StringUtils::split(slash_separated_components, "/")};
+}
+
+utils::optional DistinguishedName::getCN() const {
+  const auto it = std::find_if(components_.begin(), components_.end(),
+  [](const std::string& component) { return component.substr(0, 3) == 
"CN="; });

Review comment:
   Adam, you're right, I didn't think about SSO. From a readability 
standpoint, both are good IMO, so I'm fine with either. Thanks.





This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org




[GitHub] [nifi-minifi-cpp] szaszm commented on a change in pull request #947: MINIFICPP-1401 Read certificates from the Windows system store

2020-12-03 Thread GitBox


szaszm commented on a change in pull request #947:
URL: https://github.com/apache/nifi-minifi-cpp/pull/947#discussion_r535539954



##
File path: libminifi/src/utils/tls/DistinguishedName.cpp
##
@@ -0,0 +1,64 @@
+/**
+ * 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 "utils/tls/DistinguishedName.h"
+
+#include 
+
+#include "utils/StringUtils.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace utils {
+namespace tls {
+
+DistinguishedName::DistinguishedName(const std::vector& 
components) {
+  std::transform(components.begin(), components.end(), 
std::back_inserter(components_),
+  [](const std::string& component) { return 
utils::StringUtils::trim(component); });
+  std::sort(components_.begin(), components_.end());
+}
+
+DistinguishedName DistinguishedName::fromCommaSeparated(const std::string& 
comma_separated_components) {
+  return 
DistinguishedName{utils::StringUtils::split(comma_separated_components, ",")};
+}
+
+DistinguishedName DistinguishedName::fromSlashSeparated(const std::string 
_separated_components) {
+  return 
DistinguishedName{utils::StringUtils::split(slash_separated_components, "/")};
+}
+
+utils::optional DistinguishedName::getCN() const {
+  const auto it = std::find_if(components_.begin(), components_.end(),
+  [](const std::string& component) { return component.substr(0, 3) == 
"CN="; });

Review comment:
   Not sure how often this would be called but this is a way to do the same 
without a temporary allocation/deallocation:
   ```suggestion
 [](const std::string& component) { return component.compare(0, 3, 
"CN="); });
   ```

##
File path: libminifi/src/utils/tls/ExtendedKeyUsage.cpp
##
@@ -0,0 +1,104 @@
+/**
+ * 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.
+ */
+#ifdef OPENSSL_SUPPORT
+
+#include "utils/tls/ExtendedKeyUsage.h"
+
+#include 
+
+#include 
+#include 
+#include 
+
+#include "core/logging/LoggerConfiguration.h"
+#include "utils/StringUtils.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace utils {
+namespace tls {
+
+namespace {
+
+struct KeyValuePair {
+  const char* key;
+  uint8_t value;
+};
+constexpr std::array EXT_KEY_USAGE_NAME_TO_BIT_POS{{
+KeyValuePair{"Server Authentication", 1},
+KeyValuePair{"Client Authentication", 2},
+KeyValuePair{"Code Signing", 3},
+KeyValuePair{"Secure Email", 4},
+KeyValuePair{"Time Stamping", 8},
+KeyValuePair{"OCSP Signing", 9}
+}};
+
+}  // namespace
+
+void EXTENDED_KEY_USAGE_deleter::operator()(EXTENDED_KEY_USAGE* key_usage) 
const { EXTENDED_KEY_USAGE_free(key_usage); }
+
+ExtendedKeyUsage::ExtendedKeyUsage() : 
logger_(core::logging::LoggerFactory::getLogger()) {}
+
+ExtendedKeyUsage::ExtendedKeyUsage(const EXTENDED_KEY_USAGE& key_usage_asn1) : 
ExtendedKeyUsage{} {
+  const int num_oids = sk_ASN1_OBJECT_num(_usage_asn1);
+  for (int i = 0; i < num_oids; ++i) {
+const ASN1_OBJECT* const oid = sk_ASN1_OBJECT_value(_usage_asn1, i);
+assert(oid && oid->length > 0);
+const unsigned char bit_pos = oid->data[oid->length - 1];
+if (bit_pos < CHAR_BIT * sizeof(bits_)) {
+  bits_ |= (1 << bit_pos);
+}
+  }
+}
+
+ExtendedKeyUsage::ExtendedKeyUsage(const std::string& key_usage_str) : 
ExtendedKeyUsage{} {
+  const std::vector key_usages = 
utils::StringUtils::split(key_usage_str, ",");
+  for (const auto& key_usage : key_usages) {
+const