blob: bb3cbbfbad83b6e44620cc3a8763616047718457 [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
Ed Tanous6dbe9be2024-04-14 10:24:20 -07005extern "C"
6{
Ed Tanousf0b59af2024-03-20 13:38:04 -07007#include <openssl/asn1.h>
8#include <openssl/ec.h>
9#include <openssl/evp.h>
10#include <openssl/obj_mac.h>
11#include <openssl/types.h>
12#include <openssl/x509.h>
13#include <openssl/x509_vfy.h>
14#include <openssl/x509v3.h>
Ed Tanous6dbe9be2024-04-14 10:24:20 -070015}
Ed Tanousf0b59af2024-03-20 13:38:04 -070016
Ed Tanouse7923992023-12-03 14:14:02 -080017#include <boost/asio/ip/address.hpp>
18#include <boost/asio/ssl/verify_context.hpp>
19
Ed Tanousf0b59af2024-03-20 13:38:04 -070020#include <array>
Ed Tanouse7923992023-12-03 14:14:02 -080021#include <memory>
22
23#include <gmock/gmock.h>
Ed Tanous478b7ad2024-07-15 19:11:54 -070024#include <gtest/gtest.h>
Ed Tanouse7923992023-12-03 14:14:02 -080025
26using ::testing::IsNull;
27using ::testing::NotNull;
28
29namespace
30{
31class OSSLX509
32{
33 X509* ptr = X509_new();
34
35 public:
36 OSSLX509& operator=(const OSSLX509&) = delete;
37 OSSLX509& operator=(OSSLX509&&) = delete;
38
39 OSSLX509(const OSSLX509&) = delete;
40 OSSLX509(OSSLX509&&) = delete;
41
42 OSSLX509() = default;
Ed Tanous23f1c962023-12-05 15:57:46 -080043
44 void setSubjectName()
45 {
46 X509_NAME* name = X509_get_subject_name(ptr);
47 std::array<unsigned char, 5> user = {'u', 's', 'e', 'r', '\0'};
48 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, user.data(), -1,
49 -1, 0);
50 }
51 void sign()
52 {
53 // Generate test key
54 EVP_PKEY* pkey = nullptr;
55 EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr);
56 ASSERT_EQ(EVP_PKEY_keygen_init(pctx), 1);
57 ASSERT_EQ(
58 EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1),
59 1);
60 ASSERT_EQ(EVP_PKEY_keygen(pctx, &pkey), 1);
61 EVP_PKEY_CTX_free(pctx);
62
63 // Sign cert with key
64 ASSERT_EQ(X509_set_pubkey(ptr, pkey), 1);
65 ASSERT_GT(X509_sign(ptr, pkey, EVP_sha256()), 0);
66 EVP_PKEY_free(pkey);
67 }
68
Ed Tanouse7923992023-12-03 14:14:02 -080069 X509* get()
70 {
71 return ptr;
72 }
73 ~OSSLX509()
74 {
75 X509_free(ptr);
76 }
77};
78
79class OSSLX509StoreCTX
80{
81 X509_STORE_CTX* ptr = X509_STORE_CTX_new();
82
83 public:
84 OSSLX509StoreCTX& operator=(const OSSLX509StoreCTX&) = delete;
85 OSSLX509StoreCTX& operator=(OSSLX509StoreCTX&&) = delete;
86
87 OSSLX509StoreCTX(const OSSLX509StoreCTX&) = delete;
88 OSSLX509StoreCTX(OSSLX509StoreCTX&&) = delete;
89
90 OSSLX509StoreCTX() = default;
91 X509_STORE_CTX* get()
92 {
93 return ptr;
94 }
95 ~OSSLX509StoreCTX()
96 {
97 X509_STORE_CTX_free(ptr);
98 }
99};
100
101TEST(MutualTLS, GoodCert)
102{
103 OSSLX509 x509;
104
Ed Tanous23f1c962023-12-05 15:57:46 -0800105 x509.setSubjectName();
Ed Tanouse7923992023-12-03 14:14:02 -0800106 X509_EXTENSION* ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_key_usage,
107 "digitalSignature, keyAgreement");
108 ASSERT_THAT(ex, NotNull());
109 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
110 X509_EXTENSION_free(ex);
111 ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_ext_key_usage, "clientAuth");
112 ASSERT_THAT(ex, NotNull());
113 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
114 X509_EXTENSION_free(ex);
115
Ed Tanous23f1c962023-12-05 15:57:46 -0800116 x509.sign();
117
Ed Tanouse7923992023-12-03 14:14:02 -0800118 OSSLX509StoreCTX x509Store;
119 X509_STORE_CTX_set_current_cert(x509Store.get(), x509.get());
120
121 boost::asio::ip::address ip;
122 boost::asio::ssl::verify_context ctx(x509Store.get());
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400123 std::shared_ptr<persistent_data::UserSession> session =
124 verifyMtlsUser(ip, ctx);
Ed Tanouse7923992023-12-03 14:14:02 -0800125 ASSERT_THAT(session, NotNull());
126 EXPECT_THAT(session->username, "user");
127}
128
Ed Tanouse7923992023-12-03 14:14:02 -0800129TEST(MutualTLS, MissingKeyUsage)
130{
Ed Tanous23f1c962023-12-05 15:57:46 -0800131 for (const char* usageString :
132 {"digitalSignature", "keyAgreement", "digitalSignature, keyAgreement"})
Ed Tanouse7923992023-12-03 14:14:02 -0800133 {
134 OSSLX509 x509;
Ed Tanous23f1c962023-12-05 15:57:46 -0800135 x509.setSubjectName();
Ed Tanouse7923992023-12-03 14:14:02 -0800136
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400137 X509_EXTENSION* ex =
138 X509V3_EXT_conf_nid(nullptr, nullptr, NID_key_usage, usageString);
Ed Tanouse7923992023-12-03 14:14:02 -0800139
140 ASSERT_THAT(ex, NotNull());
141 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
142 X509_EXTENSION_free(ex);
143 ex = X509V3_EXT_conf_nid(nullptr, nullptr, NID_ext_key_usage,
144 "clientAuth");
145 ASSERT_THAT(ex, NotNull());
146 ASSERT_EQ(X509_add_ext(x509.get(), ex, -1), 1);
147 X509_EXTENSION_free(ex);
Ed Tanous23f1c962023-12-05 15:57:46 -0800148 x509.sign();
Ed Tanouse7923992023-12-03 14:14:02 -0800149
150 OSSLX509StoreCTX x509Store;
151 X509_STORE_CTX_set_current_cert(x509Store.get(), x509.get());
152
153 boost::asio::ip::address ip;
154 boost::asio::ssl::verify_context ctx(x509Store.get());
155 std::shared_ptr<persistent_data::UserSession> session =
156 verifyMtlsUser(ip, ctx);
Ed Tanous23f1c962023-12-05 15:57:46 -0800157 ASSERT_THAT(session, NotNull());
Ed Tanouse7923992023-12-03 14:14:02 -0800158 }
159}
160
Ed Tanouse7923992023-12-03 14:14:02 -0800161TEST(MutualTLS, MissingCert)
162{
163 OSSLX509StoreCTX x509Store;
164
165 boost::asio::ip::address ip;
166 boost::asio::ssl::verify_context ctx(x509Store.get());
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400167 std::shared_ptr<persistent_data::UserSession> session =
168 verifyMtlsUser(ip, ctx);
Ed Tanouse7923992023-12-03 14:14:02 -0800169 ASSERT_THAT(session, IsNull());
170}
171} // namespace