diff options
author | Ed Tanous <edtanous@google.com> | 2022-02-21 23:11:14 +0300 |
---|---|---|
committer | Ed Tanous <ed@tanous.net> | 2023-01-12 02:44:24 +0300 |
commit | 7c8e064d33a1b9136b10f224d9ae9e9b066be012 (patch) | |
tree | 5f371962698da003ebffedb311245afbbf26ba45 /http/mutual_tls.hpp | |
parent | 218295dc3aa54e68a097f9ab305b9292e70793f7 (diff) | |
download | bmcweb-7c8e064d33a1b9136b10f224d9ae9e9b066be012.tar.xz |
Refactor mtls callbacks into their own file
Mutual TLS is non-trivial enough that it definitely shouldn't be done in
an inline lambda method. This commit moves the code.
Tested: WIP. This is a pretty negligible code move; Minimal touch
testing should be good.
Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I7a15a6bc66f4d8fb090411509549628f6d1045a5
Diffstat (limited to 'http/mutual_tls.hpp')
-rw-r--r-- | http/mutual_tls.hpp | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/http/mutual_tls.hpp b/http/mutual_tls.hpp new file mode 100644 index 0000000000..aee85c265e --- /dev/null +++ b/http/mutual_tls.hpp @@ -0,0 +1,154 @@ +#pragma once + +#include "logging.hpp" +#include "persistent_data.hpp" + +#include <openssl/crypto.h> +#include <openssl/ssl.h> + +#include <boost/asio/ip/address.hpp> +#include <boost/asio/ssl/verify_context.hpp> + +#include <memory> + +inline std::shared_ptr<persistent_data::UserSession> + verifyMtlsUser(const boost::asio::ip::address& clientIp, + boost::asio::ssl::verify_context& ctx) +{ + // do nothing if TLS is disabled + if (!persistent_data::SessionStore::getInstance() + .getAuthMethodsConfig() + .tls) + { + BMCWEB_LOG_DEBUG << "TLS auth_config is disabled"; + return nullptr; + } + + X509_STORE_CTX* cts = ctx.native_handle(); + if (cts == nullptr) + { + BMCWEB_LOG_DEBUG << "Cannot get native TLS handle."; + return nullptr; + } + + // Get certificate + X509* peerCert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); + if (peerCert == nullptr) + { + BMCWEB_LOG_DEBUG << "Cannot get current TLS certificate."; + return nullptr; + } + + // Check if certificate is OK + int ctxError = X509_STORE_CTX_get_error(cts); + if (ctxError != X509_V_OK) + { + BMCWEB_LOG_INFO << "Last TLS error is: " << ctxError; + return nullptr; + } + // Check that we have reached final certificate in chain + int32_t depth = X509_STORE_CTX_get_error_depth(cts); + if (depth != 0) + + { + BMCWEB_LOG_DEBUG << "Certificate verification in progress (depth " + << depth << "), waiting to reach final depth"; + return nullptr; + } + + BMCWEB_LOG_DEBUG << "Certificate verification of final depth"; + + // Verify KeyUsage + bool isKeyUsageDigitalSignature = false; + bool isKeyUsageKeyAgreement = false; + + ASN1_BIT_STRING* usage = static_cast<ASN1_BIT_STRING*>( + X509_get_ext_d2i(peerCert, NID_key_usage, nullptr, nullptr)); + + if (usage == nullptr) + { + BMCWEB_LOG_DEBUG << "TLS usage is null"; + return nullptr; + } + + for (int i = 0; i < usage->length; i++) + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + unsigned char usageChar = usage->data[i]; + if (KU_DIGITAL_SIGNATURE & usageChar) + { + isKeyUsageDigitalSignature = true; + } + if (KU_KEY_AGREEMENT & usageChar) + { + isKeyUsageKeyAgreement = true; + } + } + ASN1_BIT_STRING_free(usage); + + if (!isKeyUsageDigitalSignature || !isKeyUsageKeyAgreement) + { + BMCWEB_LOG_DEBUG << "Certificate ExtendedKeyUsage does " + "not allow provided certificate to " + "be used for user authentication"; + return nullptr; + } + + // Determine that ExtendedKeyUsage includes Client Auth + + stack_st_ASN1_OBJECT* extUsage = static_cast<stack_st_ASN1_OBJECT*>( + X509_get_ext_d2i(peerCert, NID_ext_key_usage, nullptr, nullptr)); + + if (extUsage == nullptr) + { + BMCWEB_LOG_DEBUG << "TLS extUsage is null"; + return nullptr; + } + + bool isExKeyUsageClientAuth = false; + for (int i = 0; i < sk_ASN1_OBJECT_num(extUsage); i++) + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) + int nid = OBJ_obj2nid(sk_ASN1_OBJECT_value(extUsage, i)); + if (NID_client_auth == nid) + { + isExKeyUsageClientAuth = true; + break; + } + } + sk_ASN1_OBJECT_free(extUsage); + + // Certificate has to have proper key usages set + if (!isExKeyUsageClientAuth) + { + BMCWEB_LOG_DEBUG << "Certificate ExtendedKeyUsage does " + "not allow provided certificate to " + "be used for user authentication"; + return nullptr; + } + std::string sslUser; + // Extract username contained in CommonName + sslUser.resize(256, '\0'); + + int status = X509_NAME_get_text_by_NID(X509_get_subject_name(peerCert), + NID_commonName, sslUser.data(), + static_cast<int>(sslUser.size())); + + if (status == -1) + { + BMCWEB_LOG_DEBUG << "TLS cannot get username to create session"; + return nullptr; + } + + size_t lastChar = sslUser.find('\0'); + if (lastChar == std::string::npos || lastChar == 0) + { + BMCWEB_LOG_DEBUG << "Invalid TLS user name"; + return nullptr; + } + sslUser.resize(lastChar); + std::string unsupportedClientId; + return persistent_data::SessionStore::getInstance().generateUserSession( + sslUser, clientIp, unsupportedClientId, + persistent_data::PersistenceType::TIMEOUT); +} |