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