blob: 1620054e1c8a41b69467a0ad80fc83a3a313c4f9 [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
7#include <openssl/crypto.h>
8#include <openssl/ssl.h>
9
10#include <boost/asio/ip/address.hpp>
11#include <boost/asio/ssl/verify_context.hpp>
12
13#include <memory>
Patrick Williams3d7fc712023-05-10 20:03:19 -050014#include <span>
Ed Tanous7c8e0642022-02-21 12:11:14 -080015
16inline std::shared_ptr<persistent_data::UserSession>
17 verifyMtlsUser(const boost::asio::ip::address& clientIp,
18 boost::asio::ssl::verify_context& ctx)
19{
20 // do nothing if TLS is disabled
21 if (!persistent_data::SessionStore::getInstance()
22 .getAuthMethodsConfig()
23 .tls)
24 {
Ed Tanous62598e32023-07-17 17:06:25 -070025 BMCWEB_LOG_DEBUG("TLS auth_config is disabled");
Ed Tanous7c8e0642022-02-21 12:11:14 -080026 return nullptr;
27 }
28
29 X509_STORE_CTX* cts = ctx.native_handle();
30 if (cts == nullptr)
31 {
Ed Tanous62598e32023-07-17 17:06:25 -070032 BMCWEB_LOG_DEBUG("Cannot get native TLS handle.");
Ed Tanous7c8e0642022-02-21 12:11:14 -080033 return nullptr;
34 }
35
36 // Get certificate
37 X509* peerCert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
38 if (peerCert == nullptr)
39 {
Ed Tanous62598e32023-07-17 17:06:25 -070040 BMCWEB_LOG_DEBUG("Cannot get current TLS certificate.");
Ed Tanous7c8e0642022-02-21 12:11:14 -080041 return nullptr;
42 }
43
44 // Check if certificate is OK
45 int ctxError = X509_STORE_CTX_get_error(cts);
46 if (ctxError != X509_V_OK)
47 {
Ed Tanous62598e32023-07-17 17:06:25 -070048 BMCWEB_LOG_INFO("Last TLS error is: {}", ctxError);
Ed Tanous7c8e0642022-02-21 12:11:14 -080049 return nullptr;
50 }
Ed Tanous23f1c962023-12-05 15:57:46 -080051
Ed Tanous7c8e0642022-02-21 12:11:14 -080052 // Check that we have reached final certificate in chain
53 int32_t depth = X509_STORE_CTX_get_error_depth(cts);
54 if (depth != 0)
Ed Tanous7c8e0642022-02-21 12:11:14 -080055 {
Ed Tanous62598e32023-07-17 17:06:25 -070056 BMCWEB_LOG_DEBUG(
57 "Certificate verification in progress (depth {}), waiting to reach final depth",
58 depth);
Ed Tanous7c8e0642022-02-21 12:11:14 -080059 return nullptr;
60 }
61
Ed Tanous62598e32023-07-17 17:06:25 -070062 BMCWEB_LOG_DEBUG("Certificate verification of final depth");
Ed Tanous7c8e0642022-02-21 12:11:14 -080063
Ed Tanous23f1c962023-12-05 15:57:46 -080064 if (X509_check_purpose(peerCert, X509_PURPOSE_SSL_CLIENT, 0) != 1)
Ed Tanous7c8e0642022-02-21 12:11:14 -080065 {
Ed Tanous23f1c962023-12-05 15:57:46 -080066 BMCWEB_LOG_DEBUG(
67 "Chain does not allow certificate to be used for SSL client authentication");
Ed Tanous7c8e0642022-02-21 12:11:14 -080068 return nullptr;
69 }
70
Ed Tanous7c8e0642022-02-21 12:11:14 -080071 std::string sslUser;
72 // Extract username contained in CommonName
73 sslUser.resize(256, '\0');
74
75 int status = X509_NAME_get_text_by_NID(X509_get_subject_name(peerCert),
76 NID_commonName, sslUser.data(),
77 static_cast<int>(sslUser.size()));
78
79 if (status == -1)
80 {
Ed Tanous62598e32023-07-17 17:06:25 -070081 BMCWEB_LOG_DEBUG("TLS cannot get username to create session");
Ed Tanous7c8e0642022-02-21 12:11:14 -080082 return nullptr;
83 }
84
85 size_t lastChar = sslUser.find('\0');
86 if (lastChar == std::string::npos || lastChar == 0)
87 {
Ed Tanous62598e32023-07-17 17:06:25 -070088 BMCWEB_LOG_DEBUG("Invalid TLS user name");
Ed Tanous7c8e0642022-02-21 12:11:14 -080089 return nullptr;
90 }
91 sslUser.resize(lastChar);
Marco Kawajiri0e373b52023-10-31 13:36:58 -070092
93 // Meta Inc. CommonName parsing
94 if (bmcwebMTLSCommonNameParsingMeta)
95 {
96 std::optional<std::string_view> sslUserMeta =
97 mtlsMetaParseSslUser(sslUser);
98 if (!sslUserMeta)
99 {
100 return nullptr;
101 }
102 sslUser = *sslUserMeta;
103 }
104
Ed Tanous7c8e0642022-02-21 12:11:14 -0800105 std::string unsupportedClientId;
106 return persistent_data::SessionStore::getInstance().generateUserSession(
107 sslUser, clientIp, unsupportedClientId,
108 persistent_data::PersistenceType::TIMEOUT);
109}