blob: ec00de29241b4ad67df8d6c0487888a39983d5a6 [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 }
Ed Tanous4f467962024-08-06 10:14:26 -070046 default:
47 {
48 return "";
49 }
Ed Tanous724985f2024-06-05 09:19:06 -070050 }
Ed Tanous724985f2024-06-05 09:19:06 -070051}
52
53std::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
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400112 int length = X509_NAME_get_text_by_NID(
113 X509_get_subject_name(peerCert), NID_commonName, commonName.data(),
114 static_cast<int>(commonName.size()));
Ed Tanous724985f2024-06-05 09:19:06 -0700115 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}