blob: 9cd4cde01cbd0448966201cf47fe3c67e4594cf8 [file] [log] [blame]
Ed Tanous7c8e0642022-02-21 12:11:14 -08001#pragma once
2
3#include "logging.hpp"
4#include "persistent_data.hpp"
5
6#include <openssl/crypto.h>
7#include <openssl/ssl.h>
8
9#include <boost/asio/ip/address.hpp>
10#include <boost/asio/ssl/verify_context.hpp>
11
12#include <memory>
Patrick Williams3d7fc712023-05-10 20:03:19 -050013#include <span>
Ed Tanous7c8e0642022-02-21 12:11:14 -080014
15inline std::shared_ptr<persistent_data::UserSession>
16 verifyMtlsUser(const boost::asio::ip::address& clientIp,
17 boost::asio::ssl::verify_context& ctx)
18{
19 // do nothing if TLS is disabled
20 if (!persistent_data::SessionStore::getInstance()
21 .getAuthMethodsConfig()
22 .tls)
23 {
Ed Tanous62598e32023-07-17 17:06:25 -070024 BMCWEB_LOG_DEBUG("TLS auth_config is disabled");
Ed Tanous7c8e0642022-02-21 12:11:14 -080025 return nullptr;
26 }
27
28 X509_STORE_CTX* cts = ctx.native_handle();
29 if (cts == nullptr)
30 {
Ed Tanous62598e32023-07-17 17:06:25 -070031 BMCWEB_LOG_DEBUG("Cannot get native TLS handle.");
Ed Tanous7c8e0642022-02-21 12:11:14 -080032 return nullptr;
33 }
34
35 // Get certificate
36 X509* peerCert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
37 if (peerCert == nullptr)
38 {
Ed Tanous62598e32023-07-17 17:06:25 -070039 BMCWEB_LOG_DEBUG("Cannot get current TLS certificate.");
Ed Tanous7c8e0642022-02-21 12:11:14 -080040 return nullptr;
41 }
42
43 // Check if certificate is OK
44 int ctxError = X509_STORE_CTX_get_error(cts);
45 if (ctxError != X509_V_OK)
46 {
Ed Tanous62598e32023-07-17 17:06:25 -070047 BMCWEB_LOG_INFO("Last TLS error is: {}", ctxError);
Ed Tanous7c8e0642022-02-21 12:11:14 -080048 return nullptr;
49 }
50 // Check that we have reached final certificate in chain
51 int32_t depth = X509_STORE_CTX_get_error_depth(cts);
52 if (depth != 0)
53
54 {
Ed Tanous62598e32023-07-17 17:06:25 -070055 BMCWEB_LOG_DEBUG(
56 "Certificate verification in progress (depth {}), waiting to reach final depth",
57 depth);
Ed Tanous7c8e0642022-02-21 12:11:14 -080058 return nullptr;
59 }
60
Ed Tanous62598e32023-07-17 17:06:25 -070061 BMCWEB_LOG_DEBUG("Certificate verification of final depth");
Ed Tanous7c8e0642022-02-21 12:11:14 -080062
63 // Verify KeyUsage
64 bool isKeyUsageDigitalSignature = false;
65 bool isKeyUsageKeyAgreement = false;
66
67 ASN1_BIT_STRING* usage = static_cast<ASN1_BIT_STRING*>(
68 X509_get_ext_d2i(peerCert, NID_key_usage, nullptr, nullptr));
69
Patrick Williams3d7fc712023-05-10 20:03:19 -050070 if ((usage == nullptr) || (usage->data == nullptr))
Ed Tanous7c8e0642022-02-21 12:11:14 -080071 {
Ed Tanous62598e32023-07-17 17:06:25 -070072 BMCWEB_LOG_DEBUG("TLS usage is null");
Ed Tanous7c8e0642022-02-21 12:11:14 -080073 return nullptr;
74 }
75
Patrick Williams3d7fc712023-05-10 20:03:19 -050076 for (auto usageChar :
77 std::span(usage->data, static_cast<size_t>(usage->length)))
Ed Tanous7c8e0642022-02-21 12:11:14 -080078 {
Ed Tanous7c8e0642022-02-21 12:11:14 -080079 if (KU_DIGITAL_SIGNATURE & usageChar)
80 {
81 isKeyUsageDigitalSignature = true;
82 }
83 if (KU_KEY_AGREEMENT & usageChar)
84 {
85 isKeyUsageKeyAgreement = true;
86 }
87 }
88 ASN1_BIT_STRING_free(usage);
89
90 if (!isKeyUsageDigitalSignature || !isKeyUsageKeyAgreement)
91 {
Ed Tanous62598e32023-07-17 17:06:25 -070092 BMCWEB_LOG_DEBUG("Certificate ExtendedKeyUsage does "
93 "not allow provided certificate to "
94 "be used for user authentication");
Ed Tanous7c8e0642022-02-21 12:11:14 -080095 return nullptr;
96 }
97
98 // Determine that ExtendedKeyUsage includes Client Auth
99
100 stack_st_ASN1_OBJECT* extUsage = static_cast<stack_st_ASN1_OBJECT*>(
101 X509_get_ext_d2i(peerCert, NID_ext_key_usage, nullptr, nullptr));
102
103 if (extUsage == nullptr)
104 {
Ed Tanous62598e32023-07-17 17:06:25 -0700105 BMCWEB_LOG_DEBUG("TLS extUsage is null");
Ed Tanous7c8e0642022-02-21 12:11:14 -0800106 return nullptr;
107 }
108
109 bool isExKeyUsageClientAuth = false;
110 for (int i = 0; i < sk_ASN1_OBJECT_num(extUsage); i++)
111 {
112 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
113 int nid = OBJ_obj2nid(sk_ASN1_OBJECT_value(extUsage, i));
114 if (NID_client_auth == nid)
115 {
116 isExKeyUsageClientAuth = true;
117 break;
118 }
119 }
120 sk_ASN1_OBJECT_free(extUsage);
121
122 // Certificate has to have proper key usages set
123 if (!isExKeyUsageClientAuth)
124 {
Ed Tanous62598e32023-07-17 17:06:25 -0700125 BMCWEB_LOG_DEBUG("Certificate ExtendedKeyUsage does "
126 "not allow provided certificate to "
127 "be used for user authentication");
Ed Tanous7c8e0642022-02-21 12:11:14 -0800128 return nullptr;
129 }
130 std::string sslUser;
131 // Extract username contained in CommonName
132 sslUser.resize(256, '\0');
133
134 int status = X509_NAME_get_text_by_NID(X509_get_subject_name(peerCert),
135 NID_commonName, sslUser.data(),
136 static_cast<int>(sslUser.size()));
137
138 if (status == -1)
139 {
Ed Tanous62598e32023-07-17 17:06:25 -0700140 BMCWEB_LOG_DEBUG("TLS cannot get username to create session");
Ed Tanous7c8e0642022-02-21 12:11:14 -0800141 return nullptr;
142 }
143
144 size_t lastChar = sslUser.find('\0');
145 if (lastChar == std::string::npos || lastChar == 0)
146 {
Ed Tanous62598e32023-07-17 17:06:25 -0700147 BMCWEB_LOG_DEBUG("Invalid TLS user name");
Ed Tanous7c8e0642022-02-21 12:11:14 -0800148 return nullptr;
149 }
150 sslUser.resize(lastChar);
151 std::string unsupportedClientId;
152 return persistent_data::SessionStore::getInstance().generateUserSession(
153 sslUser, clientIp, unsupportedClientId,
154 persistent_data::PersistenceType::TIMEOUT);
155}