blob: eb26b5a4dfa1d08e22d16f3496357bfc5556348c [file] [log] [blame]
Ed Tanous7c8e0642022-02-21 12:11:14 -08001#pragma once
2
3#include "logging.hpp"
Marco Kawajiri0e373b52023-10-31 13:36:58 -07004#include "mutual_tls_meta.hpp"
Ed Tanous7c8e0642022-02-21 12:11:14 -08005#include "persistent_data.hpp"
6
Ed Tanous6dbe9be2024-04-14 10:24:20 -07007extern "C"
8{
Ed Tanous7c8e0642022-02-21 12:11:14 -08009#include <openssl/crypto.h>
10#include <openssl/ssl.h>
Ed Tanous6dbe9be2024-04-14 10:24:20 -070011}
Ed Tanous7c8e0642022-02-21 12:11:14 -080012
13#include <boost/asio/ip/address.hpp>
14#include <boost/asio/ssl/verify_context.hpp>
15
16#include <memory>
Patrick Williams3d7fc712023-05-10 20:03:19 -050017#include <span>
Ed Tanous7c8e0642022-02-21 12:11:14 -080018
Ed Tanous3ce36882024-06-09 10:58:16 -070019inline std::string getUsernameFromCommonName(std::string_view commonName)
20{
21 const persistent_data::AuthConfigMethods& authMethodsConfig =
22 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
23 switch (authMethodsConfig.mTLSCommonNameParsingMode)
24 {
25 case persistent_data::MTLSCommonNameParseMode::Invalid:
26 case persistent_data::MTLSCommonNameParseMode::Whole:
27 case persistent_data::MTLSCommonNameParseMode::UserPrincipalName:
28 {
29 // Not yet supported
30 return "";
31 }
32 case persistent_data::MTLSCommonNameParseMode::CommonName:
33 {
34 return std::string{commonName};
35 }
36 case persistent_data::MTLSCommonNameParseMode::Meta:
37 {
38 // Meta Inc. CommonName parsing
39 std::optional<std::string_view> sslUserMeta =
40 mtlsMetaParseSslUser(commonName);
41 if (!sslUserMeta)
42 {
43 return "";
44 }
45 return std::string{*sslUserMeta};
46 }
47 }
48 return "";
49}
50
Ed Tanous7c8e0642022-02-21 12:11:14 -080051inline std::shared_ptr<persistent_data::UserSession>
52 verifyMtlsUser(const boost::asio::ip::address& clientIp,
53 boost::asio::ssl::verify_context& ctx)
54{
55 // do nothing if TLS is disabled
56 if (!persistent_data::SessionStore::getInstance()
57 .getAuthMethodsConfig()
58 .tls)
59 {
Ed Tanous62598e32023-07-17 17:06:25 -070060 BMCWEB_LOG_DEBUG("TLS auth_config is disabled");
Ed Tanous7c8e0642022-02-21 12:11:14 -080061 return nullptr;
62 }
63
64 X509_STORE_CTX* cts = ctx.native_handle();
65 if (cts == nullptr)
66 {
Ed Tanous62598e32023-07-17 17:06:25 -070067 BMCWEB_LOG_DEBUG("Cannot get native TLS handle.");
Ed Tanous7c8e0642022-02-21 12:11:14 -080068 return nullptr;
69 }
70
71 // Get certificate
72 X509* peerCert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
73 if (peerCert == nullptr)
74 {
Ed Tanous62598e32023-07-17 17:06:25 -070075 BMCWEB_LOG_DEBUG("Cannot get current TLS certificate.");
Ed Tanous7c8e0642022-02-21 12:11:14 -080076 return nullptr;
77 }
78
79 // Check if certificate is OK
80 int ctxError = X509_STORE_CTX_get_error(cts);
81 if (ctxError != X509_V_OK)
82 {
Ed Tanous62598e32023-07-17 17:06:25 -070083 BMCWEB_LOG_INFO("Last TLS error is: {}", ctxError);
Ed Tanous7c8e0642022-02-21 12:11:14 -080084 return nullptr;
85 }
Ed Tanous23f1c962023-12-05 15:57:46 -080086
Ed Tanous7c8e0642022-02-21 12:11:14 -080087 // Check that we have reached final certificate in chain
88 int32_t depth = X509_STORE_CTX_get_error_depth(cts);
89 if (depth != 0)
Ed Tanous7c8e0642022-02-21 12:11:14 -080090 {
Ed Tanous62598e32023-07-17 17:06:25 -070091 BMCWEB_LOG_DEBUG(
92 "Certificate verification in progress (depth {}), waiting to reach final depth",
93 depth);
Ed Tanous7c8e0642022-02-21 12:11:14 -080094 return nullptr;
95 }
96
Ed Tanous62598e32023-07-17 17:06:25 -070097 BMCWEB_LOG_DEBUG("Certificate verification of final depth");
Ed Tanous7c8e0642022-02-21 12:11:14 -080098
Ed Tanous23f1c962023-12-05 15:57:46 -080099 if (X509_check_purpose(peerCert, X509_PURPOSE_SSL_CLIENT, 0) != 1)
Ed Tanous7c8e0642022-02-21 12:11:14 -0800100 {
Ed Tanous23f1c962023-12-05 15:57:46 -0800101 BMCWEB_LOG_DEBUG(
102 "Chain does not allow certificate to be used for SSL client authentication");
Ed Tanous7c8e0642022-02-21 12:11:14 -0800103 return nullptr;
104 }
105
Ed Tanous3ce36882024-06-09 10:58:16 -0700106 std::string commonName;
Ed Tanous7c8e0642022-02-21 12:11:14 -0800107 // Extract username contained in CommonName
Ed Tanous3ce36882024-06-09 10:58:16 -0700108 commonName.resize(256, '\0');
Ed Tanous7c8e0642022-02-21 12:11:14 -0800109
Ed Tanous3ce36882024-06-09 10:58:16 -0700110 int length = X509_NAME_get_text_by_NID(X509_get_subject_name(peerCert),
111 NID_commonName, commonName.data(),
112 static_cast<int>(commonName.size()));
113 if (length <= 0)
Ed Tanous7c8e0642022-02-21 12:11:14 -0800114 {
Ed Tanous3ce36882024-06-09 10:58:16 -0700115 BMCWEB_LOG_DEBUG("TLS cannot get common name to create session");
Ed Tanous7c8e0642022-02-21 12:11:14 -0800116 return nullptr;
117 }
118
Ed Tanous3ce36882024-06-09 10:58:16 -0700119 commonName.resize(static_cast<size_t>(length));
120 std::string sslUser = getUsernameFromCommonName(commonName);
121 if (sslUser.empty())
Ed Tanous7c8e0642022-02-21 12:11:14 -0800122 {
Ed Tanous3ce36882024-06-09 10:58:16 -0700123 BMCWEB_LOG_WARNING("Failed to get user from common name {}",
124 commonName);
Ed Tanous7c8e0642022-02-21 12:11:14 -0800125 return nullptr;
126 }
Marco Kawajiri0e373b52023-10-31 13:36:58 -0700127
Ed Tanous7c8e0642022-02-21 12:11:14 -0800128 std::string unsupportedClientId;
129 return persistent_data::SessionStore::getInstance().generateUserSession(
130 sslUser, clientIp, unsupportedClientId,
Ed Tanous89cda632024-04-16 08:45:54 -0700131 persistent_data::SessionType::MutualTLS);
Ed Tanous7c8e0642022-02-21 12:11:14 -0800132}