xref: /openbmc/bmcweb/http/mutual_tls.cpp (revision bd79bce8)
1724985ffSEd Tanous #include "mutual_tls.hpp"
2724985ffSEd Tanous 
3724985ffSEd Tanous extern "C"
4724985ffSEd Tanous {
5724985ffSEd Tanous #include <openssl/x509_vfy.h>
6724985ffSEd Tanous }
7724985ffSEd Tanous 
8724985ffSEd Tanous #include "logging.hpp"
9724985ffSEd Tanous #include "mutual_tls_meta.hpp"
10724985ffSEd Tanous #include "persistent_data.hpp"
11724985ffSEd Tanous 
12724985ffSEd Tanous #include <boost/asio/ip/address.hpp>
13724985ffSEd Tanous #include <boost/asio/ssl/verify_context.hpp>
14724985ffSEd Tanous 
15724985ffSEd Tanous #include <memory>
16724985ffSEd Tanous #include <string_view>
17724985ffSEd Tanous 
18724985ffSEd Tanous std::string getUsernameFromCommonName(std::string_view commonName)
19724985ffSEd Tanous {
20724985ffSEd Tanous     const persistent_data::AuthConfigMethods& authMethodsConfig =
21724985ffSEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
22724985ffSEd Tanous     switch (authMethodsConfig.mTLSCommonNameParsingMode)
23724985ffSEd Tanous     {
24724985ffSEd Tanous         case persistent_data::MTLSCommonNameParseMode::Invalid:
25724985ffSEd Tanous         case persistent_data::MTLSCommonNameParseMode::Whole:
26724985ffSEd Tanous         case persistent_data::MTLSCommonNameParseMode::UserPrincipalName:
27724985ffSEd Tanous         {
28724985ffSEd Tanous             // Not yet supported
29724985ffSEd Tanous             return "";
30724985ffSEd Tanous         }
31724985ffSEd Tanous         case persistent_data::MTLSCommonNameParseMode::CommonName:
32724985ffSEd Tanous         {
33724985ffSEd Tanous             return std::string{commonName};
34724985ffSEd Tanous         }
35724985ffSEd Tanous         case persistent_data::MTLSCommonNameParseMode::Meta:
36724985ffSEd Tanous         {
37724985ffSEd Tanous             // Meta Inc. CommonName parsing
38724985ffSEd Tanous             std::optional<std::string_view> sslUserMeta =
39724985ffSEd Tanous                 mtlsMetaParseSslUser(commonName);
40724985ffSEd Tanous             if (!sslUserMeta)
41724985ffSEd Tanous             {
42724985ffSEd Tanous                 return "";
43724985ffSEd Tanous             }
44724985ffSEd Tanous             return std::string{*sslUserMeta};
45724985ffSEd Tanous         }
464f467963SEd Tanous         default:
474f467963SEd Tanous         {
48724985ffSEd Tanous             return "";
49724985ffSEd Tanous         }
504f467963SEd Tanous     }
514f467963SEd Tanous }
52724985ffSEd Tanous 
53724985ffSEd Tanous std::shared_ptr<persistent_data::UserSession>
54724985ffSEd Tanous     verifyMtlsUser(const boost::asio::ip::address& clientIp,
55724985ffSEd Tanous                    boost::asio::ssl::verify_context& ctx)
56724985ffSEd Tanous {
57724985ffSEd Tanous     // do nothing if TLS is disabled
58724985ffSEd Tanous     if (!persistent_data::SessionStore::getInstance()
59724985ffSEd Tanous              .getAuthMethodsConfig()
60724985ffSEd Tanous              .tls)
61724985ffSEd Tanous     {
62724985ffSEd Tanous         BMCWEB_LOG_DEBUG("TLS auth_config is disabled");
63724985ffSEd Tanous         return nullptr;
64724985ffSEd Tanous     }
65724985ffSEd Tanous 
66724985ffSEd Tanous     X509_STORE_CTX* cts = ctx.native_handle();
67724985ffSEd Tanous     if (cts == nullptr)
68724985ffSEd Tanous     {
69724985ffSEd Tanous         BMCWEB_LOG_DEBUG("Cannot get native TLS handle.");
70724985ffSEd Tanous         return nullptr;
71724985ffSEd Tanous     }
72724985ffSEd Tanous 
73724985ffSEd Tanous     // Get certificate
74724985ffSEd Tanous     X509* peerCert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
75724985ffSEd Tanous     if (peerCert == nullptr)
76724985ffSEd Tanous     {
77724985ffSEd Tanous         BMCWEB_LOG_DEBUG("Cannot get current TLS certificate.");
78724985ffSEd Tanous         return nullptr;
79724985ffSEd Tanous     }
80724985ffSEd Tanous 
81724985ffSEd Tanous     // Check if certificate is OK
82724985ffSEd Tanous     int ctxError = X509_STORE_CTX_get_error(cts);
83724985ffSEd Tanous     if (ctxError != X509_V_OK)
84724985ffSEd Tanous     {
85724985ffSEd Tanous         BMCWEB_LOG_INFO("Last TLS error is: {}", ctxError);
86724985ffSEd Tanous         return nullptr;
87724985ffSEd Tanous     }
88724985ffSEd Tanous 
89724985ffSEd Tanous     // Check that we have reached final certificate in chain
90724985ffSEd Tanous     int32_t depth = X509_STORE_CTX_get_error_depth(cts);
91724985ffSEd Tanous     if (depth != 0)
92724985ffSEd Tanous     {
93724985ffSEd Tanous         BMCWEB_LOG_DEBUG(
94724985ffSEd Tanous             "Certificate verification in progress (depth {}), waiting to reach final depth",
95724985ffSEd Tanous             depth);
96724985ffSEd Tanous         return nullptr;
97724985ffSEd Tanous     }
98724985ffSEd Tanous 
99724985ffSEd Tanous     BMCWEB_LOG_DEBUG("Certificate verification of final depth");
100724985ffSEd Tanous 
101724985ffSEd Tanous     if (X509_check_purpose(peerCert, X509_PURPOSE_SSL_CLIENT, 0) != 1)
102724985ffSEd Tanous     {
103724985ffSEd Tanous         BMCWEB_LOG_DEBUG(
104724985ffSEd Tanous             "Chain does not allow certificate to be used for SSL client authentication");
105724985ffSEd Tanous         return nullptr;
106724985ffSEd Tanous     }
107724985ffSEd Tanous 
108724985ffSEd Tanous     std::string commonName;
109724985ffSEd Tanous     // Extract username contained in CommonName
110724985ffSEd Tanous     commonName.resize(256, '\0');
111724985ffSEd Tanous 
112*bd79bce8SPatrick Williams     int length = X509_NAME_get_text_by_NID(
113*bd79bce8SPatrick Williams         X509_get_subject_name(peerCert), NID_commonName, commonName.data(),
114724985ffSEd Tanous         static_cast<int>(commonName.size()));
115724985ffSEd Tanous     if (length <= 0)
116724985ffSEd Tanous     {
117724985ffSEd Tanous         BMCWEB_LOG_DEBUG("TLS cannot get common name to create session");
118724985ffSEd Tanous         return nullptr;
119724985ffSEd Tanous     }
120724985ffSEd Tanous 
121724985ffSEd Tanous     commonName.resize(static_cast<size_t>(length));
122724985ffSEd Tanous     std::string sslUser = getUsernameFromCommonName(commonName);
123724985ffSEd Tanous     if (sslUser.empty())
124724985ffSEd Tanous     {
125724985ffSEd Tanous         BMCWEB_LOG_WARNING("Failed to get user from common name {}",
126724985ffSEd Tanous                            commonName);
127724985ffSEd Tanous         return nullptr;
128724985ffSEd Tanous     }
129724985ffSEd Tanous 
130724985ffSEd Tanous     std::string unsupportedClientId;
131724985ffSEd Tanous     return persistent_data::SessionStore::getInstance().generateUserSession(
132724985ffSEd Tanous         sslUser, clientIp, unsupportedClientId,
133724985ffSEd Tanous         persistent_data::SessionType::MutualTLS);
134724985ffSEd Tanous }
135