blob: 7b5cb25acd06994438db6cdbc65ad50930173f72 [file] [log] [blame]
Ed Tanouse7923992023-12-03 14:14:02 -08001#include "mutual_tls.hpp"
2
3#include <boost/asio/ip/address.hpp>
4#include <boost/asio/ssl/verify_context.hpp>
5
6#include <memory>
7
8#include <gmock/gmock.h>
9#include <gtest/gtest.h> // IWYU pragma: keep
10
11using ::testing::IsNull;
12using ::testing::NotNull;
13
14namespace
15{
16class OSSLX509
17{
18 X509* ptr = X509_new();
19
20 public:
21 OSSLX509& operator=(const OSSLX509&) = delete;
22 OSSLX509& operator=(OSSLX509&&) = delete;
23
24 OSSLX509(const OSSLX509&) = delete;
25 OSSLX509(OSSLX509&&) = delete;
26
27 OSSLX509() = default;
Ed Tanous23f1c962023-12-05 15:57:46 -080028
29 void setSubjectName()
30 {
31 X509_NAME* name = X509_get_subject_name(ptr);
32 std::array<unsigned char, 5> user = {'u', 's', 'e', 'r', '\0'};
33 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, user.data(), -1,
34 -1, 0);
35 }
36 void sign()
37 {
38 // Generate test key
39 EVP_PKEY* pkey = nullptr;
40 EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr);
41 ASSERT_EQ(EVP_PKEY_keygen_init(pctx), 1);
42 ASSERT_EQ(
43 EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1),
44 1);
45 ASSERT_EQ(EVP_PKEY_keygen(pctx, &pkey), 1);
46 EVP_PKEY_CTX_free(pctx);
47
48 // Sign cert with key
49 ASSERT_EQ(X509_set_pubkey(ptr, pkey), 1);
50 ASSERT_GT(X509_sign(ptr, pkey, EVP_sha256()), 0);
51 EVP_PKEY_free(pkey);
52 }
53
Ed Tanouse7923992023-12-03 14:14:02 -080054 X509* get()
55 {
56 return ptr;
57 }
58 ~OSSLX509()
59 {
60 X509_free(ptr);
61 }
62};
63
64class OSSLX509StoreCTX
65{
66 X509_STORE_CTX* ptr = X509_STORE_CTX_new();
67
68 public:
69 OSSLX509StoreCTX& operator=(const OSSLX509StoreCTX&) = delete;
70 OSSLX509StoreCTX& operator=(OSSLX509StoreCTX&&) = delete;
71
72 OSSLX509StoreCTX(const OSSLX509StoreCTX&) = delete;
73 OSSLX509StoreCTX(OSSLX509StoreCTX&&) = delete;
74
75 OSSLX509StoreCTX() = default;
76 X509_STORE_CTX* get()
77 {
78 return ptr;
79 }
80 ~OSSLX509StoreCTX()
81 {
82 X509_STORE_CTX_free(ptr);
83 }
84};
85
86TEST(MutualTLS, GoodCert)
87{
88 OSSLX509 x509;
89
Ed Tanous23f1c962023-12-05 15:57:46 -080090 x509.setSubjectName();
Ed Tanouse7923992023-12-03 14:14:02 -080091 X509_EXTENSION* ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_key_usage,
92 "digitalSignature, keyAgreement");
93 ASSERT_THAT(ex, NotNull());
94 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
95 X509_EXTENSION_free(ex);
96 ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_ext_key_usage, "clientAuth");
97 ASSERT_THAT(ex, NotNull());
98 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
99 X509_EXTENSION_free(ex);
100
Ed Tanous23f1c962023-12-05 15:57:46 -0800101 x509.sign();
102
Ed Tanouse7923992023-12-03 14:14:02 -0800103 OSSLX509StoreCTX x509Store;
104 X509_STORE_CTX_set_current_cert(x509Store.get(), x509.get());
105
106 boost::asio::ip::address ip;
107 boost::asio::ssl::verify_context ctx(x509Store.get());
108 std::shared_ptr<persistent_data::UserSession> session = verifyMtlsUser(ip,
109 ctx);
110 ASSERT_THAT(session, NotNull());
111 EXPECT_THAT(session->username, "user");
112}
113
Ed Tanouse7923992023-12-03 14:14:02 -0800114TEST(MutualTLS, MissingKeyUsage)
115{
Ed Tanous23f1c962023-12-05 15:57:46 -0800116 for (const char* usageString :
117 {"digitalSignature", "keyAgreement", "digitalSignature, keyAgreement"})
Ed Tanouse7923992023-12-03 14:14:02 -0800118 {
119 OSSLX509 x509;
Ed Tanous23f1c962023-12-05 15:57:46 -0800120 x509.setSubjectName();
Ed Tanouse7923992023-12-03 14:14:02 -0800121
122 X509_EXTENSION* ex = X509V3_EXT_conf_nid(nullptr, nullptr,
123 NID_key_usage, usageString);
124
125 ASSERT_THAT(ex, NotNull());
126 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
127 X509_EXTENSION_free(ex);
128 ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_ext_key_usage,
129 "clientAuth");
130 ASSERT_THAT(ex, NotNull());
131 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
132 X509_EXTENSION_free(ex);
Ed Tanous23f1c962023-12-05 15:57:46 -0800133 x509.sign();
Ed Tanouse7923992023-12-03 14:14:02 -0800134
135 OSSLX509StoreCTX x509Store;
136 X509_STORE_CTX_set_current_cert(x509Store.get(), x509.get());
137
138 boost::asio::ip::address ip;
139 boost::asio::ssl::verify_context ctx(x509Store.get());
140 std::shared_ptr<persistent_data::UserSession> session =
141 verifyMtlsUser(ip, ctx);
Ed Tanous23f1c962023-12-05 15:57:46 -0800142 ASSERT_THAT(session, NotNull());
Ed Tanouse7923992023-12-03 14:14:02 -0800143 }
144}
145
Ed Tanouse7923992023-12-03 14:14:02 -0800146TEST(MutualTLS, MissingCert)
147{
148 OSSLX509StoreCTX x509Store;
149
150 boost::asio::ip::address ip;
151 boost::asio::ssl::verify_context ctx(x509Store.get());
152 std::shared_ptr<persistent_data::UserSession> session = verifyMtlsUser(ip,
153 ctx);
154 ASSERT_THAT(session, IsNull());
155}
156} // namespace