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