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 default: 47 { 48 return ""; 49 } 50 } 51 } 52 53 std::shared_ptr<persistent_data::UserSession> 54 verifyMtlsUser(const boost::asio::ip::address& clientIp, 55 boost::asio::ssl::verify_context& ctx) 56 { 57 // do nothing if TLS is disabled 58 if (!persistent_data::SessionStore::getInstance() 59 .getAuthMethodsConfig() 60 .tls) 61 { 62 BMCWEB_LOG_DEBUG("TLS auth_config is disabled"); 63 return nullptr; 64 } 65 66 X509_STORE_CTX* cts = ctx.native_handle(); 67 if (cts == nullptr) 68 { 69 BMCWEB_LOG_DEBUG("Cannot get native TLS handle."); 70 return nullptr; 71 } 72 73 // Get certificate 74 X509* peerCert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); 75 if (peerCert == nullptr) 76 { 77 BMCWEB_LOG_DEBUG("Cannot get current TLS certificate."); 78 return nullptr; 79 } 80 81 // Check if certificate is OK 82 int ctxError = X509_STORE_CTX_get_error(cts); 83 if (ctxError != X509_V_OK) 84 { 85 BMCWEB_LOG_INFO("Last TLS error is: {}", ctxError); 86 return nullptr; 87 } 88 89 // Check that we have reached final certificate in chain 90 int32_t depth = X509_STORE_CTX_get_error_depth(cts); 91 if (depth != 0) 92 { 93 BMCWEB_LOG_DEBUG( 94 "Certificate verification in progress (depth {}), waiting to reach final depth", 95 depth); 96 return nullptr; 97 } 98 99 BMCWEB_LOG_DEBUG("Certificate verification of final depth"); 100 101 if (X509_check_purpose(peerCert, X509_PURPOSE_SSL_CLIENT, 0) != 1) 102 { 103 BMCWEB_LOG_DEBUG( 104 "Chain does not allow certificate to be used for SSL client authentication"); 105 return nullptr; 106 } 107 108 std::string commonName; 109 // Extract username contained in CommonName 110 commonName.resize(256, '\0'); 111 112 int length = X509_NAME_get_text_by_NID( 113 X509_get_subject_name(peerCert), NID_commonName, commonName.data(), 114 static_cast<int>(commonName.size())); 115 if (length <= 0) 116 { 117 BMCWEB_LOG_DEBUG("TLS cannot get common name to create session"); 118 return nullptr; 119 } 120 121 commonName.resize(static_cast<size_t>(length)); 122 std::string sslUser = getUsernameFromCommonName(commonName); 123 if (sslUser.empty()) 124 { 125 BMCWEB_LOG_WARNING("Failed to get user from common name {}", 126 commonName); 127 return nullptr; 128 } 129 130 std::string unsupportedClientId; 131 return persistent_data::SessionStore::getInstance().generateUserSession( 132 sslUser, clientIp, unsupportedClientId, 133 persistent_data::SessionType::MutualTLS); 134 } 135