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