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