summaryrefslogtreecommitdiff
path: root/http/mutual_tls.hpp
blob: 5392549b169bf60e8ba2473de12165f38c8efef0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#pragma once

#include "logging.hpp"
#include "mutual_tls_meta.hpp"
#include "persistent_data.hpp"

extern "C"
{
#include <openssl/crypto.h>
#include <openssl/ssl.h>
}

#include <boost/asio/ip/address.hpp>
#include <boost/asio/ssl/verify_context.hpp>

#include <memory>
#include <span>

inline std::shared_ptr<persistent_data::UserSession>
    verifyMtlsUser(const boost::asio::ip::address& clientIp,
                   boost::asio::ssl::verify_context& ctx)
{
    // do nothing if TLS is disabled
    if (!persistent_data::SessionStore::getInstance()
             .getAuthMethodsConfig()
             .tls)
    {
        BMCWEB_LOG_DEBUG("TLS auth_config is disabled");
        return nullptr;
    }

    X509_STORE_CTX* cts = ctx.native_handle();
    if (cts == nullptr)
    {
        BMCWEB_LOG_DEBUG("Cannot get native TLS handle.");
        return nullptr;
    }

    // Get certificate
    X509* peerCert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
    if (peerCert == nullptr)
    {
        BMCWEB_LOG_DEBUG("Cannot get current TLS certificate.");
        return nullptr;
    }

    // Check if certificate is OK
    int ctxError = X509_STORE_CTX_get_error(cts);
    if (ctxError != X509_V_OK)
    {
        BMCWEB_LOG_INFO("Last TLS error is: {}", ctxError);
        return nullptr;
    }

    // Check that we have reached final certificate in chain
    int32_t depth = X509_STORE_CTX_get_error_depth(cts);
    if (depth != 0)
    {
        BMCWEB_LOG_DEBUG(
            "Certificate verification in progress (depth {}), waiting to reach final depth",
            depth);
        return nullptr;
    }

    BMCWEB_LOG_DEBUG("Certificate verification of final depth");

    if (X509_check_purpose(peerCert, X509_PURPOSE_SSL_CLIENT, 0) != 1)
    {
        BMCWEB_LOG_DEBUG(
            "Chain does not allow certificate to be used for SSL client authentication");
        return nullptr;
    }

    std::string sslUser;
    // Extract username contained in CommonName
    sslUser.resize(256, '\0');

    int status = X509_NAME_get_text_by_NID(X509_get_subject_name(peerCert),
                                           NID_commonName, sslUser.data(),
                                           static_cast<int>(sslUser.size()));

    if (status == -1)
    {
        BMCWEB_LOG_DEBUG("TLS cannot get username to create session");
        return nullptr;
    }

    size_t lastChar = sslUser.find('\0');
    if (lastChar == std::string::npos || lastChar == 0)
    {
        BMCWEB_LOG_DEBUG("Invalid TLS user name");
        return nullptr;
    }
    sslUser.resize(lastChar);

    // Meta Inc. CommonName parsing
    if constexpr (BMCWEB_MUTUAL_TLS_COMMON_NAME_PARSING == "meta")
    {
        std::optional<std::string_view> sslUserMeta =
            mtlsMetaParseSslUser(sslUser);
        if (!sslUserMeta)
        {
            return nullptr;
        }
        sslUser = *sslUserMeta;
    }

    std::string unsupportedClientId;
    return persistent_data::SessionStore::getInstance().generateUserSession(
        sslUser, clientIp, unsupportedClientId,
        persistent_data::PersistenceType::TIMEOUT);
}