blob: b1b7878586910ed9b7f50d14cb1cd494ade48951 [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;
28 X509* get()
29 {
30 return ptr;
31 }
32 ~OSSLX509()
33 {
34 X509_free(ptr);
35 }
36};
37
38class OSSLX509StoreCTX
39{
40 X509_STORE_CTX* ptr = X509_STORE_CTX_new();
41
42 public:
43 OSSLX509StoreCTX& operator=(const OSSLX509StoreCTX&) = delete;
44 OSSLX509StoreCTX& operator=(OSSLX509StoreCTX&&) = delete;
45
46 OSSLX509StoreCTX(const OSSLX509StoreCTX&) = delete;
47 OSSLX509StoreCTX(OSSLX509StoreCTX&&) = delete;
48
49 OSSLX509StoreCTX() = default;
50 X509_STORE_CTX* get()
51 {
52 return ptr;
53 }
54 ~OSSLX509StoreCTX()
55 {
56 X509_STORE_CTX_free(ptr);
57 }
58};
59
60TEST(MutualTLS, GoodCert)
61{
62 OSSLX509 x509;
63
64 X509_NAME* name = X509_get_subject_name(x509.get());
65 std::array<unsigned char, 5> user = {'u', 's', 'e', 'r', '\0'};
66 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, user.data(), -1, -1,
67 0);
68
69 X509_EXTENSION* ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_key_usage,
70 "digitalSignature, keyAgreement");
71 ASSERT_THAT(ex, NotNull());
72 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
73 X509_EXTENSION_free(ex);
74 ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_ext_key_usage, "clientAuth");
75 ASSERT_THAT(ex, NotNull());
76 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
77 X509_EXTENSION_free(ex);
78
79 OSSLX509StoreCTX x509Store;
80 X509_STORE_CTX_set_current_cert(x509Store.get(), x509.get());
81
82 boost::asio::ip::address ip;
83 boost::asio::ssl::verify_context ctx(x509Store.get());
84 std::shared_ptr<persistent_data::UserSession> session = verifyMtlsUser(ip,
85 ctx);
86 ASSERT_THAT(session, NotNull());
87 EXPECT_THAT(session->username, "user");
88}
89
90TEST(MutualTLS, MissingSubject)
91{
92 OSSLX509 x509;
93
94 X509_EXTENSION* ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_key_usage,
95 "digitalSignature, keyAgreement");
96 ASSERT_THAT(ex, NotNull());
97 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
98 X509_EXTENSION_free(ex);
99 ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_ext_key_usage, "clientAuth");
100 ASSERT_THAT(ex, NotNull());
101 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
102 X509_EXTENSION_free(ex);
103
104 OSSLX509StoreCTX x509Store;
105 X509_STORE_CTX_set_current_cert(x509Store.get(), x509.get());
106
107 boost::asio::ip::address ip;
108 boost::asio::ssl::verify_context ctx(x509Store.get());
109 std::shared_ptr<persistent_data::UserSession> session = verifyMtlsUser(ip,
110 ctx);
111 ASSERT_THAT(session, IsNull());
112}
113
114TEST(MutualTLS, MissingKeyUsage)
115{
116 for (const char* usageString : {"digitalSignature", "keyAgreement"})
117 {
118 OSSLX509 x509;
119
120 X509_EXTENSION* ex = X509V3_EXT_conf_nid(nullptr, nullptr,
121 NID_key_usage, usageString);
122
123 ASSERT_THAT(ex, NotNull());
124 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
125 X509_EXTENSION_free(ex);
126 ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_ext_key_usage,
127 "clientAuth");
128 ASSERT_THAT(ex, NotNull());
129 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
130 X509_EXTENSION_free(ex);
131
132 OSSLX509StoreCTX x509Store;
133 X509_STORE_CTX_set_current_cert(x509Store.get(), x509.get());
134
135 boost::asio::ip::address ip;
136 boost::asio::ssl::verify_context ctx(x509Store.get());
137 std::shared_ptr<persistent_data::UserSession> session =
138 verifyMtlsUser(ip, ctx);
139 ASSERT_THAT(session, IsNull());
140 }
141}
142
143TEST(MutualTLS, MissingExtKeyUsage)
144{
145 OSSLX509 x509;
146
147 X509_EXTENSION* ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_key_usage,
148 "digitalSignature, keyAgreement");
149
150 ASSERT_THAT(ex, NotNull());
151 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
152 X509_EXTENSION_free(ex);
153
154 OSSLX509StoreCTX x509Store;
155 X509_STORE_CTX_set_current_cert(x509Store.get(), x509.get());
156
157 boost::asio::ip::address ip;
158 boost::asio::ssl::verify_context ctx(x509Store.get());
159 std::shared_ptr<persistent_data::UserSession> session = verifyMtlsUser(ip,
160 ctx);
161 ASSERT_THAT(session, IsNull());
162}
163
164TEST(MutualTLS, MissingCert)
165{
166 OSSLX509StoreCTX x509Store;
167
168 boost::asio::ip::address ip;
169 boost::asio::ssl::verify_context ctx(x509Store.get());
170 std::shared_ptr<persistent_data::UserSession> session = verifyMtlsUser(ip,
171 ctx);
172 ASSERT_THAT(session, IsNull());
173}
174} // namespace