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