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
getUsernameFromCommonName(std::string_view commonName)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>
verifyMtlsUser(const boost::asio::ip::address & clientIp,boost::asio::ssl::verify_context & ctx)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