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::shared_ptr<persistent_data::UserSession> 20 verifyMtlsUser(const boost::asio::ip::address& clientIp, 21 boost::asio::ssl::verify_context& ctx) 22 { 23 // do nothing if TLS is disabled 24 if (!persistent_data::SessionStore::getInstance() 25 .getAuthMethodsConfig() 26 .tls) 27 { 28 BMCWEB_LOG_DEBUG("TLS auth_config is disabled"); 29 return nullptr; 30 } 31 32 X509_STORE_CTX* cts = ctx.native_handle(); 33 if (cts == nullptr) 34 { 35 BMCWEB_LOG_DEBUG("Cannot get native TLS handle."); 36 return nullptr; 37 } 38 39 // Get certificate 40 X509* peerCert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); 41 if (peerCert == nullptr) 42 { 43 BMCWEB_LOG_DEBUG("Cannot get current TLS certificate."); 44 return nullptr; 45 } 46 47 // Check if certificate is OK 48 int ctxError = X509_STORE_CTX_get_error(cts); 49 if (ctxError != X509_V_OK) 50 { 51 BMCWEB_LOG_INFO("Last TLS error is: {}", ctxError); 52 return nullptr; 53 } 54 55 // Check that we have reached final certificate in chain 56 int32_t depth = X509_STORE_CTX_get_error_depth(cts); 57 if (depth != 0) 58 { 59 BMCWEB_LOG_DEBUG( 60 "Certificate verification in progress (depth {}), waiting to reach final depth", 61 depth); 62 return nullptr; 63 } 64 65 BMCWEB_LOG_DEBUG("Certificate verification of final depth"); 66 67 if (X509_check_purpose(peerCert, X509_PURPOSE_SSL_CLIENT, 0) != 1) 68 { 69 BMCWEB_LOG_DEBUG( 70 "Chain does not allow certificate to be used for SSL client authentication"); 71 return nullptr; 72 } 73 74 std::string sslUser; 75 // Extract username contained in CommonName 76 sslUser.resize(256, '\0'); 77 78 int status = X509_NAME_get_text_by_NID(X509_get_subject_name(peerCert), 79 NID_commonName, sslUser.data(), 80 static_cast<int>(sslUser.size())); 81 82 if (status == -1) 83 { 84 BMCWEB_LOG_DEBUG("TLS cannot get username to create session"); 85 return nullptr; 86 } 87 88 size_t lastChar = sslUser.find('\0'); 89 if (lastChar == std::string::npos || lastChar == 0) 90 { 91 BMCWEB_LOG_DEBUG("Invalid TLS user name"); 92 return nullptr; 93 } 94 sslUser.resize(lastChar); 95 96 // Meta Inc. CommonName parsing 97 if constexpr (BMCWEB_MUTUAL_TLS_COMMON_NAME_PARSING == "meta") 98 { 99 std::optional<std::string_view> sslUserMeta = 100 mtlsMetaParseSslUser(sslUser); 101 if (!sslUserMeta) 102 { 103 return nullptr; 104 } 105 sslUser = *sslUserMeta; 106 } 107 108 std::string unsupportedClientId; 109 return persistent_data::SessionStore::getInstance().generateUserSession( 110 sslUser, clientIp, unsupportedClientId, 111 persistent_data::PersistenceType::TIMEOUT); 112 } 113