blob: 5392549b169bf60e8ba2473de12165f38c8efef0 [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
19inline std::shared_ptr<persistent_data::UserSession>
20 verifyMtlsUser(const boost::asio::ip::address& clientIp,
21 boost::asio::ssl::verify_context& ctx)
22{
23 // do nothing if TLS is disabled
24 if (!persistent_data::SessionStore::getInstance()
25 .getAuthMethodsConfig()
26 .tls)
27 {
Ed Tanous62598e32023-07-17 17:06:25 -070028 BMCWEB_LOG_DEBUG("TLS auth_config is disabled");
Ed Tanous7c8e0642022-02-21 12:11:14 -080029 return nullptr;
30 }
31
32 X509_STORE_CTX* cts = ctx.native_handle();
33 if (cts == nullptr)
34 {
Ed Tanous62598e32023-07-17 17:06:25 -070035 BMCWEB_LOG_DEBUG("Cannot get native TLS handle.");
Ed Tanous7c8e0642022-02-21 12:11:14 -080036 return nullptr;
37 }
38
39 // Get certificate
40 X509* peerCert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
41 if (peerCert == nullptr)
42 {
Ed Tanous62598e32023-07-17 17:06:25 -070043 BMCWEB_LOG_DEBUG("Cannot get current TLS certificate.");
Ed Tanous7c8e0642022-02-21 12:11:14 -080044 return nullptr;
45 }
46
47 // Check if certificate is OK
48 int ctxError = X509_STORE_CTX_get_error(cts);
49 if (ctxError != X509_V_OK)
50 {
Ed Tanous62598e32023-07-17 17:06:25 -070051 BMCWEB_LOG_INFO("Last TLS error is: {}", ctxError);
Ed Tanous7c8e0642022-02-21 12:11:14 -080052 return nullptr;
53 }
Ed Tanous23f1c962023-12-05 15:57:46 -080054
Ed Tanous7c8e0642022-02-21 12:11:14 -080055 // Check that we have reached final certificate in chain
56 int32_t depth = X509_STORE_CTX_get_error_depth(cts);
57 if (depth != 0)
Ed Tanous7c8e0642022-02-21 12:11:14 -080058 {
Ed Tanous62598e32023-07-17 17:06:25 -070059 BMCWEB_LOG_DEBUG(
60 "Certificate verification in progress (depth {}), waiting to reach final depth",
61 depth);
Ed Tanous7c8e0642022-02-21 12:11:14 -080062 return nullptr;
63 }
64
Ed Tanous62598e32023-07-17 17:06:25 -070065 BMCWEB_LOG_DEBUG("Certificate verification of final depth");
Ed Tanous7c8e0642022-02-21 12:11:14 -080066
Ed Tanous23f1c962023-12-05 15:57:46 -080067 if (X509_check_purpose(peerCert, X509_PURPOSE_SSL_CLIENT, 0) != 1)
Ed Tanous7c8e0642022-02-21 12:11:14 -080068 {
Ed Tanous23f1c962023-12-05 15:57:46 -080069 BMCWEB_LOG_DEBUG(
70 "Chain does not allow certificate to be used for SSL client authentication");
Ed Tanous7c8e0642022-02-21 12:11:14 -080071 return nullptr;
72 }
73
Ed Tanous7c8e0642022-02-21 12:11:14 -080074 std::string sslUser;
75 // Extract username contained in CommonName
76 sslUser.resize(256, '\0');
77
78 int status = X509_NAME_get_text_by_NID(X509_get_subject_name(peerCert),
79 NID_commonName, sslUser.data(),
80 static_cast<int>(sslUser.size()));
81
82 if (status == -1)
83 {
Ed Tanous62598e32023-07-17 17:06:25 -070084 BMCWEB_LOG_DEBUG("TLS cannot get username to create session");
Ed Tanous7c8e0642022-02-21 12:11:14 -080085 return nullptr;
86 }
87
88 size_t lastChar = sslUser.find('\0');
89 if (lastChar == std::string::npos || lastChar == 0)
90 {
Ed Tanous62598e32023-07-17 17:06:25 -070091 BMCWEB_LOG_DEBUG("Invalid TLS user name");
Ed Tanous7c8e0642022-02-21 12:11:14 -080092 return nullptr;
93 }
94 sslUser.resize(lastChar);
Marco Kawajiri0e373b52023-10-31 13:36:58 -070095
96 // Meta Inc. CommonName parsing
Ed Tanous25b54db2024-04-17 15:40:31 -070097 if constexpr (BMCWEB_MUTUAL_TLS_COMMON_NAME_PARSING == "meta")
Marco Kawajiri0e373b52023-10-31 13:36:58 -070098 {
99 std::optional<std::string_view> sslUserMeta =
100 mtlsMetaParseSslUser(sslUser);
101 if (!sslUserMeta)
102 {
103 return nullptr;
104 }
105 sslUser = *sslUserMeta;
106 }
107
Ed Tanous7c8e0642022-02-21 12:11:14 -0800108 std::string unsupportedClientId;
109 return persistent_data::SessionStore::getInstance().generateUserSession(
110 sslUser, clientIp, unsupportedClientId,
111 persistent_data::PersistenceType::TIMEOUT);
112}