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