1 #pragma once 2 3 #include "logging.hpp" 4 #include "mutual_tls_meta.hpp" 5 #include "persistent_data.hpp" 6 7 extern "C" 8 { 9 #include <openssl/crypto.h> 10 #include <openssl/ssl.h> 11 } 12 13 #include <boost/asio/ip/address.hpp> 14 #include <boost/asio/ssl/verify_context.hpp> 15 16 #include <memory> 17 #include <span> 18 19 inline std::string getUsernameFromCommonName(std::string_view commonName) 20 { 21 const persistent_data::AuthConfigMethods& authMethodsConfig = 22 persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 23 switch (authMethodsConfig.mTLSCommonNameParsingMode) 24 { 25 case persistent_data::MTLSCommonNameParseMode::Invalid: 26 case persistent_data::MTLSCommonNameParseMode::Whole: 27 case persistent_data::MTLSCommonNameParseMode::UserPrincipalName: 28 { 29 // Not yet supported 30 return ""; 31 } 32 case persistent_data::MTLSCommonNameParseMode::CommonName: 33 { 34 return std::string{commonName}; 35 } 36 case persistent_data::MTLSCommonNameParseMode::Meta: 37 { 38 // Meta Inc. CommonName parsing 39 std::optional<std::string_view> sslUserMeta = 40 mtlsMetaParseSslUser(commonName); 41 if (!sslUserMeta) 42 { 43 return ""; 44 } 45 return std::string{*sslUserMeta}; 46 } 47 } 48 return ""; 49 } 50 51 inline std::shared_ptr<persistent_data::UserSession> 52 verifyMtlsUser(const boost::asio::ip::address& clientIp, 53 boost::asio::ssl::verify_context& ctx) 54 { 55 // do nothing if TLS is disabled 56 if (!persistent_data::SessionStore::getInstance() 57 .getAuthMethodsConfig() 58 .tls) 59 { 60 BMCWEB_LOG_DEBUG("TLS auth_config is disabled"); 61 return nullptr; 62 } 63 64 X509_STORE_CTX* cts = ctx.native_handle(); 65 if (cts == nullptr) 66 { 67 BMCWEB_LOG_DEBUG("Cannot get native TLS handle."); 68 return nullptr; 69 } 70 71 // Get certificate 72 X509* peerCert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); 73 if (peerCert == nullptr) 74 { 75 BMCWEB_LOG_DEBUG("Cannot get current TLS certificate."); 76 return nullptr; 77 } 78 79 // Check if certificate is OK 80 int ctxError = X509_STORE_CTX_get_error(cts); 81 if (ctxError != X509_V_OK) 82 { 83 BMCWEB_LOG_INFO("Last TLS error is: {}", ctxError); 84 return nullptr; 85 } 86 87 // Check that we have reached final certificate in chain 88 int32_t depth = X509_STORE_CTX_get_error_depth(cts); 89 if (depth != 0) 90 { 91 BMCWEB_LOG_DEBUG( 92 "Certificate verification in progress (depth {}), waiting to reach final depth", 93 depth); 94 return nullptr; 95 } 96 97 BMCWEB_LOG_DEBUG("Certificate verification of final depth"); 98 99 if (X509_check_purpose(peerCert, X509_PURPOSE_SSL_CLIENT, 0) != 1) 100 { 101 BMCWEB_LOG_DEBUG( 102 "Chain does not allow certificate to be used for SSL client authentication"); 103 return nullptr; 104 } 105 106 std::string commonName; 107 // Extract username contained in CommonName 108 commonName.resize(256, '\0'); 109 110 int length = X509_NAME_get_text_by_NID(X509_get_subject_name(peerCert), 111 NID_commonName, commonName.data(), 112 static_cast<int>(commonName.size())); 113 if (length <= 0) 114 { 115 BMCWEB_LOG_DEBUG("TLS cannot get common name to create session"); 116 return nullptr; 117 } 118 119 commonName.resize(static_cast<size_t>(length)); 120 std::string sslUser = getUsernameFromCommonName(commonName); 121 if (sslUser.empty()) 122 { 123 BMCWEB_LOG_WARNING("Failed to get user from common name {}", 124 commonName); 125 return nullptr; 126 } 127 128 std::string unsupportedClientId; 129 return persistent_data::SessionStore::getInstance().generateUserSession( 130 sslUser, clientIp, unsupportedClientId, 131 persistent_data::SessionType::MutualTLS); 132 } 133