Skip to content

Commit 23a9d07

Browse files
committed
Add tests for client certificate edge cases
- client_cert_no_cn: Tests certificate without Common Name field, covering the cn_size == 0 branch in get_client_cert_cn() - client_cert_untrusted: Tests certificate not in trust store, covering the status != 0 branch in is_client_cert_verified() Also adds the new test certificate files to configure.ac.
1 parent c47da0e commit 23a9d07

File tree

6 files changed

+179
-0
lines changed

6 files changed

+179
-0
lines changed

configure.ac

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ AC_CONFIG_FILES([test/key.pem:test/key.pem])
302302
AC_CONFIG_FILES([test/test_root_ca.pem:test/test_root_ca.pem])
303303
AC_CONFIG_FILES([test/client_cert.pem:test/client_cert.pem])
304304
AC_CONFIG_FILES([test/client_key.pem:test/client_key.pem])
305+
AC_CONFIG_FILES([test/client_cert_no_cn.pem:test/client_cert_no_cn.pem])
306+
AC_CONFIG_FILES([test/client_key_no_cn.pem:test/client_key_no_cn.pem])
307+
AC_CONFIG_FILES([test/client_cert_untrusted.pem:test/client_cert_untrusted.pem])
308+
AC_CONFIG_FILES([test/client_key_untrusted.pem:test/client_key_untrusted.pem])
305309
AC_CONFIG_FILES([test/libhttpserver.supp:test/libhttpserver.supp])
306310
AC_CONFIG_FILES([examples/cert.pem:examples/cert.pem])
307311
AC_CONFIG_FILES([examples/key.pem:examples/key.pem])

test/client_cert_no_cn.pem

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDHTCCAgWgAwIBAgIUZxrdiFzIPZz71PW6KGhQgzUJYY0wDQYJKoZIhvcNAQEL
3+
BQAwHjEcMBoGA1UECgwTVGVzdCBPcmcgV2l0aG91dCBDTjAeFw0yNjAyMDUwMDAy
4+
NTFaFw0zNjAyMDMwMDAyNTFaMB4xHDAaBgNVBAoME1Rlc3QgT3JnIFdpdGhvdXQg
5+
Q04wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQClSmDXcECe5ID3F/yb
6+
PB7XrT2jGZq51MLnfv+WSRrj4ORuae03VhrCUw1oqodxZgwU89xtjkfLX8iItH3E
7+
20RfhVj/GBZuHw+7iGyNP5dHiSiYq5bfNFbpNI/yO3/NEKflALQ0DZDjeGaZhv08
8+
wWDRkea//oFJfGeJM6IRcmXv0MG7woZohkQfobfvnj8plMl0PAkHGEcnZFhauvjB
9+
d4d/TcmZhuDfRychP2HRy4UhqKuisa0wvLvE7KN4OZsegRYIIVKMDWl6odquzyD7
10+
KE6POT+BTv7WoCP3UWlYJtX27kx8iJMFNWGUv2DGllBY4Q9o1rhJr5pFBtd873Xh
11+
wE29AgMBAAGjUzBRMB0GA1UdDgQWBBQdtRld75yAChAw/rcfqtTB0Prq/TAfBgNV
12+
HSMEGDAWgBQdtRld75yAChAw/rcfqtTB0Prq/TAPBgNVHRMBAf8EBTADAQH/MA0G
13+
CSqGSIb3DQEBCwUAA4IBAQB9ynRcMBZp2jkekBsvtyyydp4OKWBwXhiLX5jJWMKL
14+
GqEm9quqM7iH+W7trxRz1GHrqkHRz37TUp8jU9mnDZ7aaXIbhBu4RMnao36O3R6d
15+
lA43mN+4ZTUecsJAY9hR4X3+oLLndrLlmte8NkpwKNIuo32XEfu97wXUuEP5W17s
16+
GJh3EGh7lrz8TS4GO4Oek/qK+6dgDhHLQcmqoRUnBj1mb+0ffcsWTyWFRD9W2oyW
17+
L1S1t/Q6L4sJEIzvU1qUtO5kiWBsd3uq5oZibKYdU1nYs9nucFE8Fers+qafqbKR
18+
wHHH4vsiZVIU1n7yqG4kLi5uL4KO5XcYJmjANB0lEM8r
19+
-----END CERTIFICATE-----

test/client_cert_untrusted.pem

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDRzCCAi+gAwIBAgIUGKzbXdmC0G8pSeYuFwMoWQCHYuEwDQYJKoZIhvcNAQEL
3+
BQAwMzEZMBcGA1UEAwwQVW50cnVzdGVkIENsaWVudDEWMBQGA1UECgwNVW50cnVz
4+
dGVkIE9yZzAeFw0yNjAyMDUwMDAyNTdaFw0zNjAyMDMwMDAyNTdaMDMxGTAXBgNV
5+
BAMMEFVudHJ1c3RlZCBDbGllbnQxFjAUBgNVBAoMDVVudHJ1c3RlZCBPcmcwggEi
6+
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCT9JwyKk5xPhz5aHlYkN1u4jCm
7+
SeIavIicQCbYgcmCwFgdH0i+fP1s2MrcZgeEoiqN4VK8zmxtpj1QME0KGAImwn9k
8+
ffROftIQ0pdebIvImD/QWmR+bNCXQYWmyX6c52ESKPrCSVPstHj1r2pOCHA0j/s0
9+
4V1gMNI/snv4CxZ+H+JGBikE+ycvZYTgZa3HiAjm9rtQu1zU5blwuZ2NhUumkdfB
10+
cc/oC+6yxUiPaD84poLefmF9vdqmGKEIWxWQB+Ijvll1iieEf47lOqxokLWWWsxH
11+
bfWOGagzdQJKHzeDj76KjfTbSTsMsIyCxAbJU2K53ccCLlQYYHzn1h1zaQntAgMB
12+
AAGjUzBRMB0GA1UdDgQWBBS3oS6d4JFK/ZrF4uDyAxqP8BDJCDAfBgNVHSMEGDAW
13+
gBS3oS6d4JFK/ZrF4uDyAxqP8BDJCDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
14+
DQEBCwUAA4IBAQBrltJfDg26jzDEsWoqJM7/xuYM5EVebbIiFUQgM7AWPtFGewbM
15+
cb9TPPHRMx3izv2E95JWaQ0YXSuxkGISkJQEisTPzssIDQfrpcAyZdMgR5XSWKVC
16+
t8ychNwE7rKdJfRGMoXrqAD4R1h0NQpl0V86rwieA23voBOK/5xE6ja0JIsso8YG
17+
mQpqxPROxtpJ4J59BnwQnhhZ66GQ+HpqTN1cc8Pl0kqVzBvwnkeiz6/6h4qX6dVQ
18+
eI0OA9LARB1uYqK9sTdZ2KA45rJLXDsOeWB/WAs0ZOSMQSO5qkFYA1FkPpwc+mcR
19+
ckU7IZOyPFf4Xr98Jbaf+LFcq8WsCA10xzJ2
20+
-----END CERTIFICATE-----

test/client_key_no_cn.pem

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQClSmDXcECe5ID3
3+
F/ybPB7XrT2jGZq51MLnfv+WSRrj4ORuae03VhrCUw1oqodxZgwU89xtjkfLX8iI
4+
tH3E20RfhVj/GBZuHw+7iGyNP5dHiSiYq5bfNFbpNI/yO3/NEKflALQ0DZDjeGaZ
5+
hv08wWDRkea//oFJfGeJM6IRcmXv0MG7woZohkQfobfvnj8plMl0PAkHGEcnZFha
6+
uvjBd4d/TcmZhuDfRychP2HRy4UhqKuisa0wvLvE7KN4OZsegRYIIVKMDWl6odqu
7+
zyD7KE6POT+BTv7WoCP3UWlYJtX27kx8iJMFNWGUv2DGllBY4Q9o1rhJr5pFBtd8
8+
73XhwE29AgMBAAECggEAGBo28eNkAOd4KM/eHXLQWongDYr7xXJRc3lQ4sTJP4Z5
9+
OOKIXUPYhhKfR25qbq4/P8TplS4kqPLQJqMPHegNWdJzjksgZjFwVVvI3HXz5NIK
10+
0exfhS+4Jqxr+xoTAj+WA+4s2NRLluflKikFf1kBeb3JRKDjkGgsHtUhImMomyX9
11+
Q9GaElwM6AQTKRxChlmglxnErgYip59l/ECaGiU/sSMK5vmqiOLeBk7r++xjOFcH
12+
9JbBDVKJT+0urwYn8Istwe7UnoYStPUwIVjBlcvI1d+5k3OuLsJ0QJ8ThXBIN9Pn
13+
wMBHsR/vkC06I1eS4htaJEdrCS/R+MQUXHaP9f6o3wKBgQDPE6kh4fBj44L7SAi+
14+
ooKwJrNOE20IVR7LSPQ1ZfWoQVSkqv/hpZyN+zlFOpLepLNVpzR3/XXAUg1LRJSU
15+
lvN+fRSjGQO2uNgt/APs5+wsZvwtuQHfPgh4zcNtr5GqxLVhH7V5YgEZ02SWSlmx
16+
c9x+ETQ6zhV05sRfYh44DZKK1wKBgQDMV2rKhbK7oI/3HVU/TyWFkvWJK/t79Uuu
17+
wFoPpKf0oqnImzOGb8EMi/ecjEgktRKUnBB/hY3tQIZCB3LaOujIp/OVY3Saa1Gb
18+
s1G1QlTvhgWbLHEHeZvA4qolmEYnNxgupmWounrICk3bd5Hr0zX8K2fzKPAlDs4O
19+
65r/bK4NiwKBgQC0vNNFWH/Jn3zmN8QyJ4NrnguoHLpwqGK9SYqkxL46QfNP2lSG
20+
LVdMcTZWXz5rh1NjchIQnK/W0Yb65/vLCUmzYBbQF/gu1n0Q/cKrVu3C/4whmDWz
21+
FOCuF+H37WJ1q0UoZVWugUS2ttQ3fON2R8ruWbO9k7wUkYpaOjhn8iiydwKBgGSw
22+
9tiRBT/boNVeSPGHaK/neMJ9P9EXUJHuCvMGahTsSsmlYMBwNSqflgY4QhyEdYFx
23+
XdfY0dUFJKNI1FmhCbBGworslTq6g148AJlW9E+LNRv/zDqovA1SJBGedYNBbNMf
24+
/5wjN/l2ymLJCsiwLTvzj6eMlrlMEFHd22TeAu59AoGAVWK/s5loFUk0XUrkRC6m
25+
Ys28G2jTHsgwPvfIBRIsoiN1j4w2rrMw/79tpBscCQK6v5Z7jCiahOz1Xe8fNkId
26+
Z8oiErDKKOiUY86umg421mhuwzBU+gXsiHuBYrdH3e3aw+fGYyMNpbFdRvJVy2lv
27+
pm+6ev0dkUX/fjUl3UNydW8=
28+
-----END PRIVATE KEY-----

test/client_key_untrusted.pem

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCT9JwyKk5xPhz5
3+
aHlYkN1u4jCmSeIavIicQCbYgcmCwFgdH0i+fP1s2MrcZgeEoiqN4VK8zmxtpj1Q
4+
ME0KGAImwn9kffROftIQ0pdebIvImD/QWmR+bNCXQYWmyX6c52ESKPrCSVPstHj1
5+
r2pOCHA0j/s04V1gMNI/snv4CxZ+H+JGBikE+ycvZYTgZa3HiAjm9rtQu1zU5blw
6+
uZ2NhUumkdfBcc/oC+6yxUiPaD84poLefmF9vdqmGKEIWxWQB+Ijvll1iieEf47l
7+
OqxokLWWWsxHbfWOGagzdQJKHzeDj76KjfTbSTsMsIyCxAbJU2K53ccCLlQYYHzn
8+
1h1zaQntAgMBAAECggEACwdw8qG0tzxUwe1yc5JY71XCdU2MopxAkrqK1W4srKfU
9+
lFcrVQfRhwuiE6EyGPD9uxXQ1ReOKEj8HmjQqq/0zm7b5Yx+FFvfzOE7PLlasi6n
10+
Pct/MkK/nzGDL6uq2dy69QpDpw1QSZTVGiYOsUJvxXtLfpBOJZ1+DsF/UZOCBGS+
11+
9/xC7gU3bGDhjAgzgPBhyO+WVPLORvV6/mRVQalB7MiH/kgZDKZi0dZ50qgCyc95
12+
CUnrf7Mck0c782SN7rN3W4ZAKWb8YaWCtGUGYpwk7E/eIw23eCNQZjeLB21w4uge
13+
7rCSRzEFy1DeLgWWSPnNfHO59fJ3ii31aHQWRu1YAQKBgQDQ7JJ/S+FWMEkso7A1
14+
qNraAzyyFYXMeV79/VSbFWO1dT0+mxfG9LekAGzF7BLOwW7mKM+iJqWaSg1Up9GU
15+
FDINV8R4s1+0syKdBLNrd02qGYkqaSs1A75q2n2ExvJsBwNXcUtHjcUIL3ui56aH
16+
RpMX3GomYCC6ormw4nFENWTlJQKBgQC1SytEA5LS3okrZzzCilnBr2SOBjBdQrxK
17+
D2CgVqwE0/8blmqy5w/ZE/Rn44RirQmhAG1g7qS+WQy8cvTBUCnqXov9kAtnL7oP
18+
0iZFA5Mjo2o80wT+1haZolUMqHXchC5nBXGUBcwulZdZdFmjo3H64vpHQLQE9D7a
19+
f06OmpzLKQKBgCpv41H4F81qAXMPzLsZkVq3TZzewk7GWIU+7/CQZ7B0H/yXhDzl
20+
eGfXrkCFs0xL/jrCD2rgbsLoR8zqSafKcmBDc6UQyl/qAx3h1o/9q8jhZvs2YZBj
21+
MkqCFvzhbFyFECiy2peuNFd1TafJZgoUS8yM+QLSg9NlOlKzrE4uilABAoGAOTv7
22+
8sL2DWB4CZ3UDs7Cu2T15+iISEkTTIZCSRxTvkp3VWxNTyGnXS7xkALB/q0GRy/t
23+
WBa/J+DRJoVcQ9NdCELFC034a6Ejqm776fnQ8AVdOsqb3yATjnkzRIXCf9WzGI8d
24+
Zk/WQDa1y2XyDrlA+KXDwc7phk7dsPlUAa1KJtECgYBW8MlkBt76OEg+J0ZMgBVU
25+
ze4fuCAEtFbetd7DjsId4rSqsawWaJZX0ZRo8gZsLUrNM3hcZfZTELF2uL5eNhMu
26+
t/ig52WfLVHwmtVAdIIbDdyKFO/4mY84IbWjAmYI08SvBb+Mk5KTJR80B8idVM3D
27+
Yge1bloM2atDhO63yM1LwA==
28+
-----END PRIVATE KEY-----

test/integ/ws_start_stop.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,86 @@ LT_BEGIN_AUTO_TEST(ws_start_stop_suite, client_cert_fingerprint)
11341134
ws.stop();
11351135
LT_END_AUTO_TEST(client_cert_fingerprint)
11361136

1137+
// Test client certificate without CN field (covers cn_size == 0 branch)
1138+
LT_BEGIN_AUTO_TEST(ws_start_stop_suite, client_cert_no_cn)
1139+
int port = PORT + 51;
1140+
httpserver::webserver ws = httpserver::create_webserver(port)
1141+
.use_ssl()
1142+
.https_mem_key(ROOT "/key.pem")
1143+
.https_mem_cert(ROOT "/cert.pem")
1144+
.https_mem_trust(ROOT "/client_cert_no_cn.pem");
1145+
client_cert_info_resource cert_info;
1146+
LT_ASSERT_EQ(true, ws.register_resource("cert_info", &cert_info));
1147+
try {
1148+
ws.start(false);
1149+
} catch (const std::exception& e) {
1150+
LT_CHECK_EQ(1, 1);
1151+
return;
1152+
}
1153+
curl_global_init(CURL_GLOBAL_ALL);
1154+
std::string s;
1155+
CURL *curl = curl_easy_init();
1156+
CURLcode res;
1157+
std::string url = "https://localhost:" + std::to_string(port) + "/cert_info";
1158+
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
1159+
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
1160+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
1161+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
1162+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
1163+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
1164+
curl_easy_setopt(curl, CURLOPT_SSLCERT, ROOT "/client_cert_no_cn.pem");
1165+
curl_easy_setopt(curl, CURLOPT_SSLKEY, ROOT "/client_key_no_cn.pem");
1166+
res = curl_easy_perform(curl);
1167+
LT_ASSERT_EQ(res, 0);
1168+
// Certificate has no CN, so CN should be empty but other fields should work
1169+
LT_CHECK_NEQ(s.find("HAS_CLIENT_CERT"), std::string::npos);
1170+
LT_CHECK_NEQ(s.find("CN:"), std::string::npos); // CN field present but empty
1171+
// DN should contain "O=Test Org Without CN"
1172+
LT_CHECK_NEQ(s.find("Test Org Without CN"), std::string::npos);
1173+
curl_easy_cleanup(curl);
1174+
ws.stop();
1175+
LT_END_AUTO_TEST(client_cert_no_cn)
1176+
1177+
// Test client certificate that fails verification (covers status != 0 branch)
1178+
LT_BEGIN_AUTO_TEST(ws_start_stop_suite, client_cert_untrusted)
1179+
int port = PORT + 52;
1180+
// Don't add untrusted cert to trust store - verification should fail
1181+
httpserver::webserver ws = httpserver::create_webserver(port)
1182+
.use_ssl()
1183+
.https_mem_key(ROOT "/key.pem")
1184+
.https_mem_cert(ROOT "/cert.pem")
1185+
.https_mem_trust(ROOT "/client_cert.pem"); // Only trust the original client cert
1186+
client_cert_info_resource cert_info;
1187+
LT_ASSERT_EQ(true, ws.register_resource("cert_info", &cert_info));
1188+
try {
1189+
ws.start(false);
1190+
} catch (const std::exception& e) {
1191+
LT_CHECK_EQ(1, 1);
1192+
return;
1193+
}
1194+
curl_global_init(CURL_GLOBAL_ALL);
1195+
std::string s;
1196+
CURL *curl = curl_easy_init();
1197+
CURLcode res;
1198+
std::string url = "https://localhost:" + std::to_string(port) + "/cert_info";
1199+
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
1200+
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
1201+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
1202+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
1203+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
1204+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
1205+
// Use the untrusted certificate
1206+
curl_easy_setopt(curl, CURLOPT_SSLCERT, ROOT "/client_cert_untrusted.pem");
1207+
curl_easy_setopt(curl, CURLOPT_SSLKEY, ROOT "/client_key_untrusted.pem");
1208+
res = curl_easy_perform(curl);
1209+
LT_ASSERT_EQ(res, 0);
1210+
// Certificate is present but should NOT be verified (untrusted)
1211+
LT_CHECK_NEQ(s.find("HAS_CLIENT_CERT"), std::string::npos);
1212+
LT_CHECK_NEQ(s.find("VERIFIED:no"), std::string::npos);
1213+
curl_easy_cleanup(curl);
1214+
ws.stop();
1215+
LT_END_AUTO_TEST(client_cert_untrusted)
1216+
11371217
// Test SNI callback configuration
11381218
LT_BEGIN_AUTO_TEST(ws_start_stop_suite, sni_callback_setup)
11391219
int port = PORT + 50;

0 commit comments

Comments
 (0)