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