xref: /openbmc/bmcweb/http/mutual_tls.cpp (revision 724985ff)
1 #include "mutual_tls.hpp"
2 
3 extern "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 
18 std::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         }
46     }
47     return "";
48 }
49 
50 std::shared_ptr<persistent_data::UserSession>
51     verifyMtlsUser(const boost::asio::ip::address& clientIp,
52                    boost::asio::ssl::verify_context& ctx)
53 {
54     // do nothing if TLS is disabled
55     if (!persistent_data::SessionStore::getInstance()
56              .getAuthMethodsConfig()
57              .tls)
58     {
59         BMCWEB_LOG_DEBUG("TLS auth_config is disabled");
60         return nullptr;
61     }
62 
63     X509_STORE_CTX* cts = ctx.native_handle();
64     if (cts == nullptr)
65     {
66         BMCWEB_LOG_DEBUG("Cannot get native TLS handle.");
67         return nullptr;
68     }
69 
70     // Get certificate
71     X509* peerCert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
72     if (peerCert == nullptr)
73     {
74         BMCWEB_LOG_DEBUG("Cannot get current TLS certificate.");
75         return nullptr;
76     }
77 
78     // Check if certificate is OK
79     int ctxError = X509_STORE_CTX_get_error(cts);
80     if (ctxError != X509_V_OK)
81     {
82         BMCWEB_LOG_INFO("Last TLS error is: {}", ctxError);
83         return nullptr;
84     }
85 
86     // Check that we have reached final certificate in chain
87     int32_t depth = X509_STORE_CTX_get_error_depth(cts);
88     if (depth != 0)
89     {
90         BMCWEB_LOG_DEBUG(
91             "Certificate verification in progress (depth {}), waiting to reach final depth",
92             depth);
93         return nullptr;
94     }
95 
96     BMCWEB_LOG_DEBUG("Certificate verification of final depth");
97 
98     if (X509_check_purpose(peerCert, X509_PURPOSE_SSL_CLIENT, 0) != 1)
99     {
100         BMCWEB_LOG_DEBUG(
101             "Chain does not allow certificate to be used for SSL client authentication");
102         return nullptr;
103     }
104 
105     std::string commonName;
106     // Extract username contained in CommonName
107     commonName.resize(256, '\0');
108 
109     int length = X509_NAME_get_text_by_NID(X509_get_subject_name(peerCert),
110                                            NID_commonName, commonName.data(),
111                                            static_cast<int>(commonName.size()));
112     if (length <= 0)
113     {
114         BMCWEB_LOG_DEBUG("TLS cannot get common name to create session");
115         return nullptr;
116     }
117 
118     commonName.resize(static_cast<size_t>(length));
119     std::string sslUser = getUsernameFromCommonName(commonName);
120     if (sslUser.empty())
121     {
122         BMCWEB_LOG_WARNING("Failed to get user from common name {}",
123                            commonName);
124         return nullptr;
125     }
126 
127     std::string unsupportedClientId;
128     return persistent_data::SessionStore::getInstance().generateUserSession(
129         sslUser, clientIp, unsupportedClientId,
130         persistent_data::SessionType::MutualTLS);
131 }
132