blob: f579089ed824974a1d1679c22117ecb9435fec37 [file] [log] [blame]
Ed Tanous724985f2024-06-05 09:19:06 -07001#include "mutual_tls.hpp"
2
3extern "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
18std::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
50std::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}