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