verifytest.c revision 1.8
1/* $OpenBSD: verifytest.c,v 1.8 2023/05/28 09:02:01 beck Exp $ */ 2/* 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <err.h> 19#include <stdio.h> 20#include <stdlib.h> 21 22#include <openssl/x509v3.h> 23#include <tls.h> 24 25extern int tls_check_name(struct tls *ctx, X509 *cert, const char *name, 26 int *match); 27 28struct alt_name { 29 const char name[128]; 30 int name_len; 31 int name_type; 32}; 33 34struct verify_test { 35 const char common_name[128]; 36 int common_name_len; 37 struct alt_name alt_name1; 38 struct alt_name alt_name2; 39 struct alt_name alt_name3; 40 const char name[128]; 41 int want_return; 42 int want_match; 43 int name_type; 44}; 45 46struct verify_test verify_tests[] = { 47 { 48 /* CN without SANs - matching. */ 49 .common_name = "www.openbsd.org", 50 .common_name_len = -1, 51 .name = "www.openbsd.org", 52 .want_return = 0, 53 .want_match = 1, 54 }, 55 { 56 /* Zero length name - non-matching. */ 57 .common_name = "www.openbsd.org", 58 .common_name_len = -1, 59 .name = "", 60 .want_return = 0, 61 .want_match = 0, 62 }, 63 { 64 /* CN wildcard without SANs - matching. */ 65 .common_name = "*.openbsd.org", 66 .common_name_len = -1, 67 .name = "www.openbsd.org", 68 .want_return = 0, 69 .want_match = 1, 70 }, 71 { 72 /* CN without SANs - non-matching. */ 73 .common_name = "www.openbsdfoundation.org", 74 .common_name_len = -1, 75 .name = "www.openbsd.org", 76 .want_return = 0, 77 .want_match = 0, 78 }, 79 { 80 /* CN wildcard without SANs - invalid CN wildcard. */ 81 .common_name = "w*.openbsd.org", 82 .common_name_len = -1, 83 .name = "www.openbsd.org", 84 .want_return = 0, 85 .want_match = 0, 86 }, 87 { 88 /* CN wildcard without SANs - invalid CN wildcard. */ 89 .common_name = "www.*.org", 90 .common_name_len = -1, 91 .name = "www.openbsd.org", 92 .want_return = 0, 93 .want_match = 0, 94 }, 95 { 96 /* CN wildcard without SANs - invalid CN wildcard. */ 97 .common_name = "www.openbsd.*", 98 .common_name_len = -1, 99 .name = "www.openbsd.org", 100 .want_return = 0, 101 .want_match = 0, 102 }, 103 { 104 /* CN wildcard without SANs - invalid CN wildcard. */ 105 .common_name = "*", 106 .common_name_len = -1, 107 .name = "www.openbsd.org", 108 .want_return = 0, 109 .want_match = 0, 110 }, 111 { 112 /* CN wildcard without SANs - invalid CN wildcard. */ 113 .common_name = "*.org", 114 .common_name_len = -1, 115 .name = "www.openbsd.org", 116 .want_return = 0, 117 .want_match = 0, 118 }, 119 { 120 /* CN wildcard without SANs - invalid CN wildcard. */ 121 .common_name = "*.org", 122 .common_name_len = -1, 123 .name = "openbsd.org", 124 .want_return = 0, 125 .want_match = 0, 126 }, 127 { 128 /* CN IPv4 without SANs - matching. */ 129 .common_name = "1.2.3.4", 130 .common_name_len = -1, 131 .name = "1.2.3.4", 132 .want_return = 0, 133 .want_match = 1, 134 }, 135 { 136 /* CN IPv4 wildcard without SANS - invalid IP wildcard. */ 137 .common_name = "*.2.3.4", 138 .common_name_len = -1, 139 .name = "1.2.3.4", 140 .want_return = 0, 141 .want_match = 0, 142 }, 143 { 144 /* CN IPv6 without SANs - matching. */ 145 .common_name = "cafe::beef", 146 .common_name_len = -1, 147 .name = "cafe::beef", 148 .want_return = 0, 149 .want_match = 1, 150 }, 151 { 152 /* CN without SANs - error due to embedded NUL in CN. */ 153 .common_name = { 154 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 155 0x62, 0x73, 0x64, 0x2e, 0x6f, 0x72, 0x67, 0x00, 156 0x6e, 0x61, 0x73, 0x74, 0x79, 0x2e, 0x6f, 0x72, 157 0x67, 158 }, 159 .common_name_len = 25, 160 .name = "www.openbsd.org", 161 .want_return = -1, 162 .want_match = 0, 163 }, 164 { 165 /* CN wildcard without SANs - invalid non-matching name. */ 166 .common_name = "*.openbsd.org", 167 .common_name_len = -1, 168 .name = ".openbsd.org", 169 .want_return = 0, 170 .want_match = 0, 171 }, 172 { 173 /* CN with SANs - matching on first SAN. */ 174 .common_name = "www.openbsd.org", 175 .common_name_len = -1, 176 .alt_name1 = { 177 .name = "www.openbsd.org", 178 .name_len = -1, 179 .name_type = GEN_DNS, 180 }, 181 .alt_name2 = { 182 .name = "ftp.openbsd.org", 183 .name_len = -1, 184 .name_type = GEN_DNS, 185 }, 186 .name = "www.openbsd.org", 187 .want_return = 0, 188 .want_match = 1, 189 }, 190 { 191 /* SANs only - matching on first SAN. */ 192 .common_name_len = 0, 193 .alt_name1 = { 194 .name = "www.openbsd.org", 195 .name_len = -1, 196 .name_type = GEN_DNS, 197 }, 198 .alt_name2 = { 199 .name = "ftp.openbsd.org", 200 .name_len = -1, 201 .name_type = GEN_DNS, 202 }, 203 .name = "www.openbsd.org", 204 .want_return = 0, 205 .want_match = 1, 206 }, 207 { 208 /* SANs only - matching on second SAN. */ 209 .common_name_len = 0, 210 .alt_name1 = { 211 .name = "www.openbsd.org", 212 .name_len = -1, 213 .name_type = GEN_DNS, 214 }, 215 .alt_name2 = { 216 .name = "ftp.openbsd.org", 217 .name_len = -1, 218 .name_type = GEN_DNS, 219 }, 220 .name = "ftp.openbsd.org", 221 .want_return = 0, 222 .want_match = 1, 223 }, 224 { 225 /* SANs only - non-matching. */ 226 .common_name_len = 0, 227 .alt_name1 = { 228 .name = "www.openbsd.org", 229 .name_len = -1, 230 .name_type = GEN_DNS, 231 }, 232 .alt_name2 = { 233 .name = "ftp.openbsd.org", 234 .name_len = -1, 235 .name_type = GEN_DNS, 236 }, 237 .name = "mail.openbsd.org", 238 .want_return = 0, 239 .want_match = 0, 240 }, 241 { 242 /* CN with SANs - matching on second SAN. */ 243 .common_name = "www.openbsd.org", 244 .common_name_len = -1, 245 .alt_name1 = { 246 .name = "www.openbsd.org", 247 .name_len = -1, 248 .name_type = GEN_DNS, 249 }, 250 .alt_name2 = { 251 .name = "ftp.openbsd.org", 252 .name_len = -1, 253 .name_type = GEN_DNS, 254 }, 255 .name = "ftp.openbsd.org", 256 .want_return = 0, 257 .want_match = 1, 258 }, 259 { 260 /* CN with SANs - matching on wildcard second SAN. */ 261 .common_name = "www.openbsdfoundation.org", 262 .common_name_len = -1, 263 .alt_name1 = { 264 .name = "www.openbsdfoundation.org", 265 .name_len = -1, 266 .name_type = GEN_DNS, 267 }, 268 .alt_name2 = { 269 .name = "*.openbsd.org", 270 .name_len = -1, 271 .name_type = GEN_DNS, 272 }, 273 .name = "www.openbsd.org", 274 .want_return = 0, 275 .want_match = 1, 276 }, 277 { 278 /* CN with SANs - non-matching invalid wildcard. */ 279 .common_name = "www.openbsdfoundation.org", 280 .common_name_len = -1, 281 .alt_name1 = { 282 .name = "www.openbsdfoundation.org", 283 .name_len = -1, 284 .name_type = GEN_DNS, 285 }, 286 .alt_name2 = { 287 .name = "*.org", 288 .name_len = -1, 289 .name_type = GEN_DNS, 290 }, 291 .name = "www.openbsd.org", 292 .want_return = 0, 293 .want_match = 0, 294 }, 295 { 296 /* CN with SANs - non-matching IPv4 due to GEN_DNS SAN. */ 297 .common_name = "www.openbsd.org", 298 .common_name_len = -1, 299 .alt_name1 = { 300 .name = "www.openbsd.org", 301 .name_len = -1, 302 .name_type = GEN_DNS, 303 }, 304 .alt_name2 = { 305 .name = "1.2.3.4", 306 .name_len = -1, 307 .name_type = GEN_DNS, 308 }, 309 .name = "1.2.3.4", 310 .want_return = 0, 311 .want_match = 0, 312 }, 313 { 314 /* CN with SANs - matching IPv4 on GEN_IPADD SAN. */ 315 .common_name = "www.openbsd.org", 316 .common_name_len = -1, 317 .alt_name1 = { 318 .name = "www.openbsd.org", 319 .name_len = -1, 320 .name_type = GEN_DNS, 321 }, 322 .alt_name2 = { 323 .name = {0x01, 0x02, 0x03, 0x04}, 324 .name_len = 4, 325 .name_type = GEN_IPADD, 326 }, 327 .name = "1.2.3.4", 328 .want_return = 0, 329 .want_match = 1, 330 }, 331 { 332 /* CN with SANs - matching IPv6 on GEN_IPADD SAN. */ 333 .common_name = "www.openbsd.org", 334 .common_name_len = -1, 335 .alt_name1 = { 336 .name = "www.openbsd.org", 337 .name_len = -1, 338 .name_type = GEN_DNS, 339 }, 340 .alt_name2 = { 341 .name = { 342 0xca, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xef, 344 }, 345 .name_len = 16, 346 .name_type = GEN_IPADD, 347 }, 348 .name = "cafe::beef", 349 .want_return = 0, 350 .want_match = 1, 351 }, 352 { 353 /* CN with SANs - error due to embedded NUL in GEN_DNS. */ 354 .common_name = "www.openbsd.org.nasty.org", 355 .common_name_len = -1, 356 .alt_name1 = { 357 .name = "www.openbsd.org.nasty.org", 358 .name_len = -1, 359 .name_type = GEN_DNS, 360 }, 361 .alt_name2 = { 362 .name = { 363 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 364 0x62, 0x73, 0x64, 0x2e, 0x6f, 0x72, 0x67, 0x00, 365 0x6e, 0x61, 0x73, 0x74, 0x79, 0x2e, 0x6f, 0x72, 366 0x67, 367 }, 368 .name_len = 25, 369 .name_type = GEN_DNS, 370 }, 371 .name = "www.openbsd.org", 372 .want_return = -1, 373 .want_match = 0, 374 }, 375 { 376 /* CN with SAN - non-matching due to non-matching SAN. */ 377 .common_name = "www.openbsd.org", 378 .common_name_len = -1, 379 .alt_name1 = { 380 .name = "ftp.openbsd.org", 381 .name_len = -1, 382 .name_type = GEN_DNS, 383 }, 384 .name = "www.openbsd.org", 385 .want_return = 0, 386 .want_match = 0, 387 }, 388 { 389 /* CN with SAN - error due to illegal dNSName. */ 390 .common_name = "www.openbsd.org", 391 .common_name_len = -1, 392 .alt_name1 = { 393 .name = " ", 394 .name_len = -1, 395 .name_type = GEN_DNS, 396 }, 397 .name = "www.openbsd.org", 398 .want_return = -1, 399 .want_match = 0, 400 }, 401}; 402 403#define N_VERIFY_TESTS \ 404 (sizeof(verify_tests) / sizeof(*verify_tests)) 405 406static void 407alt_names_add(STACK_OF(GENERAL_NAME) *alt_name_stack, struct alt_name *alt) 408{ 409 ASN1_STRING *alt_name_str; 410 GENERAL_NAME *alt_name; 411 412 if ((alt_name = GENERAL_NAME_new()) == NULL) 413 errx(1, "failed to malloc GENERAL_NAME"); 414 alt_name->type = alt->name_type; 415 416 if ((alt_name_str = ASN1_STRING_new()) == NULL) 417 errx(1, "failed to malloc alt name"); 418 if (ASN1_STRING_set(alt_name_str, alt->name, alt->name_len) == 0) 419 errx(1, "failed to set alt name"); 420 421 switch (alt_name->type) { 422 case GEN_DNS: 423 alt_name->d.dNSName = alt_name_str; 424 break; 425 case GEN_IPADD: 426 alt_name->d.iPAddress = alt_name_str; 427 break; 428 default: 429 errx(1, "unknown alt name type (%i)", alt_name->type); 430 } 431 432 if (sk_GENERAL_NAME_push(alt_name_stack, alt_name) == 0) 433 errx(1, "failed to push alt_name"); 434} 435 436static void 437cert_add_alt_names(X509 *cert, struct verify_test *vt) 438{ 439 STACK_OF(GENERAL_NAME) *alt_name_stack = NULL; 440 441 if (vt->alt_name1.name_type == 0) 442 return; 443 444 if ((alt_name_stack = sk_GENERAL_NAME_new_null()) == NULL) 445 errx(1, "failed to malloc sk_GENERAL_NAME"); 446 447 if (vt->alt_name1.name_type != 0) 448 alt_names_add(alt_name_stack, &vt->alt_name1); 449 if (vt->alt_name2.name_type != 0) 450 alt_names_add(alt_name_stack, &vt->alt_name2); 451 if (vt->alt_name3.name_type != 0) 452 alt_names_add(alt_name_stack, &vt->alt_name3); 453 454 if (X509_add1_ext_i2d(cert, NID_subject_alt_name, 455 alt_name_stack, 0, 0) == 0) 456 errx(1, "failed to set subject alt name"); 457 458 sk_GENERAL_NAME_pop_free(alt_name_stack, GENERAL_NAME_free); 459} 460 461static int 462do_verify_test(int test_no, struct verify_test *vt) 463{ 464 struct tls *tls; 465 X509_NAME *name; 466 X509 *cert; 467 int failed = 1; 468 int match; 469 470 /* Build certificate structure. */ 471 if ((cert = X509_new()) == NULL) 472 errx(1, "failed to malloc X509"); 473 474 if (vt->common_name_len != 0) { 475 if ((name = X509_NAME_new()) == NULL) 476 errx(1, "failed to malloc X509_NAME"); 477 if (X509_NAME_add_entry_by_NID(name, NID_commonName, 478 vt->name_type ? vt->name_type : MBSTRING_ASC, 479 (unsigned char *)vt->common_name, 480 vt->common_name_len, -1, 0) == 0) 481 errx(1, "failed to add name entry"); 482 if (X509_set_subject_name(cert, name) == 0) 483 errx(1, "failed to set subject name"); 484 X509_NAME_free(name); 485 } 486 487 if ((tls = tls_client()) == NULL) 488 errx(1, "failed to malloc tls_client"); 489 490 cert_add_alt_names(cert, vt); 491 492 match = 1; 493 494 if (tls_check_name(tls, cert, vt->name, &match) != vt->want_return) { 495 fprintf(stderr, "FAIL: test %i failed for check name '%s': " 496 "%s\n", test_no, vt->name, tls_error(tls)); 497 goto done; 498 } 499 if (match != vt->want_match) { 500 fprintf(stderr, "FAIL: test %i failed to match name '%s'\n", 501 test_no, vt->name); 502 goto done; 503 } 504 505 failed = 0; 506 507 done: 508 X509_free(cert); 509 tls_free(tls); 510 511 return (failed); 512} 513 514int 515main(int argc, char **argv) 516{ 517 int failed = 0; 518 size_t i; 519 520 tls_init(); 521 522 for (i = 0; i < N_VERIFY_TESTS; i++) 523 failed += do_verify_test(i, &verify_tests[i]); 524 525 return (failed); 526} 527