blob: be8b65102fff457ff5b2c417d1d6376e2fc4ea07 [file] [log] [blame]
Ed Tanouse7923992023-12-03 14:14:02 -08001#include "mutual_tls.hpp"
2
Ed Tanousf0b59af2024-03-20 13:38:04 -07003#include "sessions.hpp"
4
5#include <openssl/asn1.h>
6#include <openssl/ec.h>
7#include <openssl/evp.h>
8#include <openssl/obj_mac.h>
9#include <openssl/types.h>
10#include <openssl/x509.h>
11#include <openssl/x509_vfy.h>
12#include <openssl/x509v3.h>
13
Ed Tanouse7923992023-12-03 14:14:02 -080014#include <boost/asio/ip/address.hpp>
15#include <boost/asio/ssl/verify_context.hpp>
16
Ed Tanousf0b59af2024-03-20 13:38:04 -070017#include <array>
Ed Tanouse7923992023-12-03 14:14:02 -080018#include <memory>
19
20#include <gmock/gmock.h>
21#include <gtest/gtest.h> // IWYU pragma: keep
22
23using ::testing::IsNull;
24using ::testing::NotNull;
25
26namespace
27{
28class OSSLX509
29{
30 X509* ptr = X509_new();
31
32 public:
33 OSSLX509& operator=(const OSSLX509&) = delete;
34 OSSLX509& operator=(OSSLX509&&) = delete;
35
36 OSSLX509(const OSSLX509&) = delete;
37 OSSLX509(OSSLX509&&) = delete;
38
39 OSSLX509() = default;
Ed Tanous23f1c962023-12-05 15:57:46 -080040
41 void setSubjectName()
42 {
43 X509_NAME* name = X509_get_subject_name(ptr);
44 std::array<unsigned char, 5> user = {'u', 's', 'e', 'r', '\0'};
45 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, user.data(), -1,
46 -1, 0);
47 }
48 void sign()
49 {
50 // Generate test key
51 EVP_PKEY* pkey = nullptr;
52 EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr);
53 ASSERT_EQ(EVP_PKEY_keygen_init(pctx), 1);
54 ASSERT_EQ(
55 EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1),
56 1);
57 ASSERT_EQ(EVP_PKEY_keygen(pctx, &pkey), 1);
58 EVP_PKEY_CTX_free(pctx);
59
60 // Sign cert with key
61 ASSERT_EQ(X509_set_pubkey(ptr, pkey), 1);
62 ASSERT_GT(X509_sign(ptr, pkey, EVP_sha256()), 0);
63 EVP_PKEY_free(pkey);
64 }
65
Ed Tanouse7923992023-12-03 14:14:02 -080066 X509* get()
67 {
68 return ptr;
69 }
70 ~OSSLX509()
71 {
72 X509_free(ptr);
73 }
74};
75
76class OSSLX509StoreCTX
77{
78 X509_STORE_CTX* ptr = X509_STORE_CTX_new();
79
80 public:
81 OSSLX509StoreCTX& operator=(const OSSLX509StoreCTX&) = delete;
82 OSSLX509StoreCTX& operator=(OSSLX509StoreCTX&&) = delete;
83
84 OSSLX509StoreCTX(const OSSLX509StoreCTX&) = delete;
85 OSSLX509StoreCTX(OSSLX509StoreCTX&&) = delete;
86
87 OSSLX509StoreCTX() = default;
88 X509_STORE_CTX* get()
89 {
90 return ptr;
91 }
92 ~OSSLX509StoreCTX()
93 {
94 X509_STORE_CTX_free(ptr);
95 }
96};
97
98TEST(MutualTLS, GoodCert)
99{
100 OSSLX509 x509;
101
Ed Tanous23f1c962023-12-05 15:57:46 -0800102 x509.setSubjectName();
Ed Tanouse7923992023-12-03 14:14:02 -0800103 X509_EXTENSION* ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_key_usage,
104 "digitalSignature, keyAgreement");
105 ASSERT_THAT(ex, NotNull());
106 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
107 X509_EXTENSION_free(ex);
108 ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_ext_key_usage, "clientAuth");
109 ASSERT_THAT(ex, NotNull());
110 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
111 X509_EXTENSION_free(ex);
112
Ed Tanous23f1c962023-12-05 15:57:46 -0800113 x509.sign();
114
Ed Tanouse7923992023-12-03 14:14:02 -0800115 OSSLX509StoreCTX x509Store;
116 X509_STORE_CTX_set_current_cert(x509Store.get(), x509.get());
117
118 boost::asio::ip::address ip;
119 boost::asio::ssl::verify_context ctx(x509Store.get());
120 std::shared_ptr<persistent_data::UserSession> session = verifyMtlsUser(ip,
121 ctx);
122 ASSERT_THAT(session, NotNull());
123 EXPECT_THAT(session->username, "user");
124}
125
Ed Tanouse7923992023-12-03 14:14:02 -0800126TEST(MutualTLS, MissingKeyUsage)
127{
Ed Tanous23f1c962023-12-05 15:57:46 -0800128 for (const char* usageString :
129 {"digitalSignature", "keyAgreement", "digitalSignature, keyAgreement"})
Ed Tanouse7923992023-12-03 14:14:02 -0800130 {
131 OSSLX509 x509;
Ed Tanous23f1c962023-12-05 15:57:46 -0800132 x509.setSubjectName();
Ed Tanouse7923992023-12-03 14:14:02 -0800133
134 X509_EXTENSION* ex = X509V3_EXT_conf_nid(nullptr, nullptr,
135 NID_key_usage, usageString);
136
137 ASSERT_THAT(ex, NotNull());
138 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
139 X509_EXTENSION_free(ex);
140 ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_ext_key_usage,
141 "clientAuth");
142 ASSERT_THAT(ex, NotNull());
143 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
144 X509_EXTENSION_free(ex);
Ed Tanous23f1c962023-12-05 15:57:46 -0800145 x509.sign();
Ed Tanouse7923992023-12-03 14:14:02 -0800146
147 OSSLX509StoreCTX x509Store;
148 X509_STORE_CTX_set_current_cert(x509Store.get(), x509.get());
149
150 boost::asio::ip::address ip;
151 boost::asio::ssl::verify_context ctx(x509Store.get());
152 std::shared_ptr<persistent_data::UserSession> session =
153 verifyMtlsUser(ip, ctx);
Ed Tanous23f1c962023-12-05 15:57:46 -0800154 ASSERT_THAT(session, NotNull());
Ed Tanouse7923992023-12-03 14:14:02 -0800155 }
156}
157
Ed Tanouse7923992023-12-03 14:14:02 -0800158TEST(MutualTLS, MissingCert)
159{
160 OSSLX509StoreCTX x509Store;
161
162 boost::asio::ip::address ip;
163 boost::asio::ssl::verify_context ctx(x509Store.get());
164 std::shared_ptr<persistent_data::UserSession> session = verifyMtlsUser(ip,
165 ctx);
166 ASSERT_THAT(session, IsNull());
167}
168} // namespace