PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/ncat/test/test-wildcard.c

https://github.com/prakashgamit/nmap
C | 576 lines | 447 code | 84 blank | 45 comment | 129 complexity | 8df8ac76cdc641e01ca50fc7452b4d0b MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.0, LGPL-2.1
  1. /*
  2. Usage: ./test-wildcard
  3. This is a test program for the ssl_post_connect_check function. It generates
  4. certificates with a variety of different combinations of commonNames and
  5. dNSNames, then checks that matching names are accepted and non-matching names
  6. are rejected. The SSL transactions happen over OpenSSL BIO pairs.
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <openssl/bio.h>
  12. #include <openssl/ssl.h>
  13. #include <openssl/err.h>
  14. #include <openssl/x509.h>
  15. #include <openssl/x509v3.h>
  16. #include "ncat_core.h"
  17. #define KEY_BITS 1024
  18. static int tests_run = 0, tests_passed = 0;
  19. /* A length-delimited string. */
  20. struct lstr {
  21. size_t len;
  22. const char *s;
  23. };
  24. /* Make an anonymous struct lstr. */
  25. #define LSTR(s) { sizeof(s) - 1, (s) }
  26. /* Variable-length arrays of struct lstr are terminated with a special sentinel
  27. value. */
  28. #define LSTR_SENTINEL { -1, NULL }
  29. const struct lstr lstr_sentinel = LSTR_SENTINEL;
  30. int is_sentinel(const struct lstr *name) {
  31. return name->len == -1;
  32. }
  33. int ssl_post_connect_check(SSL *ssl, const char *hostname);
  34. static struct lstr *check(SSL *ssl, const struct lstr names[]);
  35. static int ssl_ctx_trust_cert(SSL_CTX *ctx, X509 *cert);
  36. static int gen_cert(X509 **cert, EVP_PKEY **key,
  37. const struct lstr commonNames[], const struct lstr dNSNames[]);
  38. static void print_escaped(const char *s, size_t len);
  39. static void print_array(const struct lstr array[]);
  40. static int arrays_equal(const struct lstr a[], const struct lstr b[]);
  41. /* Returns positive on success, 0 on failure. The various arrays must be
  42. NULL-terminated. */
  43. static int test(const struct lstr commonNames[], const struct lstr dNSNames[],
  44. const struct lstr test_names[], const struct lstr expected[])
  45. {
  46. SSL_CTX *server_ctx, *client_ctx;
  47. SSL *server_ssl, *client_ssl;
  48. BIO *server_bio, *client_bio;
  49. X509 *cert;
  50. EVP_PKEY *key;
  51. struct lstr *results;
  52. int need_accept, need_connect;
  53. int passed;
  54. tests_run++;
  55. ncat_assert(gen_cert(&cert, &key, commonNames, dNSNames) == 1);
  56. ncat_assert(BIO_new_bio_pair(&server_bio, 0, &client_bio, 0) == 1);
  57. server_ctx = SSL_CTX_new(SSLv23_server_method());
  58. ncat_assert(server_ctx != NULL);
  59. client_ctx = SSL_CTX_new(SSLv23_client_method());
  60. ncat_assert(client_ctx != NULL);
  61. SSL_CTX_set_verify(client_ctx, SSL_VERIFY_PEER, NULL);
  62. SSL_CTX_set_verify_depth(client_ctx, 1);
  63. ssl_ctx_trust_cert(client_ctx, cert);
  64. server_ssl = SSL_new(server_ctx);
  65. ncat_assert(server_ssl != NULL);
  66. SSL_set_accept_state(server_ssl);
  67. SSL_set_bio(server_ssl, server_bio, server_bio);
  68. ncat_assert(SSL_use_certificate(server_ssl, cert) == 1);
  69. ncat_assert(SSL_use_PrivateKey(server_ssl, key) == 1);
  70. client_ssl = SSL_new(client_ctx);
  71. ncat_assert(client_ssl != NULL);
  72. SSL_set_connect_state(client_ssl);
  73. SSL_set_bio(client_ssl, client_bio, client_bio);
  74. passed = 0;
  75. need_accept = 1;
  76. need_connect = 1;
  77. do {
  78. int rc, err;
  79. if (need_accept) {
  80. rc = SSL_accept(server_ssl);
  81. err = SSL_get_error(server_ssl, rc);
  82. if (rc == 1) {
  83. need_accept = 0;
  84. } else {
  85. if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
  86. printf("SSL_accept: %s \n",
  87. ERR_error_string(ERR_get_error(), NULL));
  88. goto end;
  89. }
  90. }
  91. }
  92. if (need_connect) {
  93. rc = SSL_connect(client_ssl);
  94. err = SSL_get_error(client_ssl, rc);
  95. if (rc == 1) {
  96. need_connect = 0;
  97. } else {
  98. if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
  99. printf("SSL_connect: %s \n",
  100. ERR_error_string(ERR_get_error(), NULL));
  101. goto end;
  102. }
  103. }
  104. }
  105. } while (need_accept || need_connect);
  106. results = check(client_ssl, test_names);
  107. if (arrays_equal(results, expected)) {
  108. tests_passed++;
  109. passed = 1;
  110. printf("PASS CN");
  111. print_array(commonNames);
  112. printf(" DNS");
  113. print_array(dNSNames);
  114. printf("\n");
  115. } else {
  116. printf("FAIL CN");
  117. print_array(commonNames);
  118. printf(" DNS");
  119. print_array(dNSNames);
  120. printf("\n");
  121. printf(" got ");
  122. print_array(results);
  123. printf("\n");
  124. printf("expected ");
  125. print_array(expected);
  126. printf("\n");
  127. }
  128. free(results);
  129. end:
  130. X509_free(cert);
  131. EVP_PKEY_free(key);
  132. (void) BIO_destroy_bio_pair(server_bio);
  133. SSL_CTX_free(server_ctx);
  134. SSL_CTX_free(client_ctx);
  135. SSL_free(server_ssl);
  136. SSL_free(client_ssl);
  137. return passed;
  138. }
  139. /* Returns a sentinel-terminated malloc-allocated array of names that match ssl
  140. with ssl_post_connect_check. */
  141. static struct lstr *check(SSL *ssl, const struct lstr names[])
  142. {
  143. const struct lstr *name;
  144. struct lstr *results = NULL;
  145. size_t size = 0, capacity = 0;
  146. if (names == NULL)
  147. return NULL;
  148. for (name = names; !is_sentinel(name); name++) {
  149. if (ssl_post_connect_check(ssl, name->s)) {
  150. if (size >= capacity) {
  151. capacity = (size + 1) * 2;
  152. results = safe_realloc(results, (capacity + 1) * sizeof(results[0]));
  153. }
  154. results[size++] = *name;
  155. }
  156. }
  157. results = safe_realloc(results, (size + 1) * sizeof(results[0]));
  158. results[size] = lstr_sentinel;
  159. return results;
  160. }
  161. /* Make a certificate object trusted by an SSL_CTX. I coulnd't find a way to do
  162. this directly, so the certificate is written in PEM format to a temporary
  163. file and then loaded with SSL_CTX_load_verify_locations. Returns 1 on success
  164. and 0 on failure. */
  165. static int ssl_ctx_trust_cert(SSL_CTX *ctx, X509 *cert)
  166. {
  167. char name[] = "ncat-test-XXXXXX";
  168. int fd;
  169. FILE *fp;
  170. int rc;
  171. fd = mkstemp(name);
  172. if (fd == -1)
  173. return 0;
  174. fp = fdopen(fd, "w");
  175. if (fp == NULL) {
  176. close(fd);
  177. return 0;
  178. }
  179. if (PEM_write_X509(fp, cert) == 0) {
  180. fclose(fp);
  181. return 0;
  182. }
  183. fclose(fp);
  184. rc = SSL_CTX_load_verify_locations(ctx, name, NULL);
  185. if (rc == 0) {
  186. fprintf(stderr, "SSL_CTX_load_verify_locations: %s \n",
  187. ERR_error_string(ERR_get_error(), NULL));
  188. }
  189. if (unlink(name) == -1)
  190. fprintf(stderr, "unlink(\"%s\"): %s\n", name, strerror(errno));
  191. return rc;
  192. }
  193. static int set_dNSNames(X509 *cert, const struct lstr dNSNames[])
  194. {
  195. STACK_OF(GENERAL_NAME) *gen_names;
  196. GENERAL_NAME *gen_name;
  197. X509_EXTENSION *ext;
  198. const struct lstr *name;
  199. if (dNSNames == NULL || is_sentinel(&dNSNames[0]))
  200. return 1;
  201. /* We break the abstraction here a bit because the normal way of setting
  202. a list of values, using an i2v method, uses a stack of CONF_VALUE that
  203. doesn't contain the length of each value. We rely on the fact that
  204. the internal representation (the "i" in "i2d") for
  205. NID_subject_alt_name is STACK_OF(GENERAL_NAME). */
  206. gen_names = sk_GENERAL_NAME_new_null();
  207. if (gen_names == NULL)
  208. return 0;
  209. for (name = dNSNames; !is_sentinel(name); name++) {
  210. gen_name = GENERAL_NAME_new();
  211. if (gen_name == NULL)
  212. goto stack_err;
  213. gen_name->type = GEN_DNS;
  214. gen_name->d.dNSName = M_ASN1_IA5STRING_new();
  215. if (gen_name->d.dNSName == NULL)
  216. goto name_err;
  217. if (ASN1_STRING_set(gen_name->d.dNSName, name->s, name->len) == 0)
  218. goto name_err;
  219. if (sk_GENERAL_NAME_push(gen_names, gen_name) == 0)
  220. goto name_err;
  221. }
  222. ext = X509V3_EXT_i2d(NID_subject_alt_name, 0, gen_names);
  223. if (ext == NULL)
  224. goto stack_err;
  225. if (X509_add_ext(cert, ext, -1) == 0) {
  226. X509_EXTENSION_free(ext);
  227. goto stack_err;
  228. }
  229. X509_EXTENSION_free(ext);
  230. sk_GENERAL_NAME_pop_free(gen_names, GENERAL_NAME_free);
  231. return 1;
  232. name_err:
  233. GENERAL_NAME_free(gen_name);
  234. stack_err:
  235. sk_GENERAL_NAME_pop_free(gen_names, GENERAL_NAME_free);
  236. return 0;
  237. }
  238. static int gen_cert(X509 **cert, EVP_PKEY **key,
  239. const struct lstr commonNames[], const struct lstr dNSNames[])
  240. {
  241. RSA *rsa;
  242. int rc;
  243. *cert = NULL;
  244. *key = NULL;
  245. /* Generate a private key. */
  246. *key = EVP_PKEY_new();
  247. if (*key == NULL)
  248. goto err;
  249. do {
  250. rsa = RSA_generate_key(KEY_BITS, RSA_F4, NULL, NULL);
  251. if (rsa == NULL)
  252. goto err;
  253. rc = RSA_check_key(rsa);
  254. } while (rc == 0);
  255. if (rc == -1)
  256. goto err;
  257. if (EVP_PKEY_assign_RSA(*key, rsa) == 0) {
  258. RSA_free(rsa);
  259. goto err;
  260. }
  261. /* Generate a certificate. */
  262. *cert = X509_new();
  263. if (*cert == NULL)
  264. goto err;
  265. if (X509_set_version(*cert, 2) == 0) /* Version 3. */
  266. goto err;
  267. ASN1_INTEGER_set(X509_get_serialNumber(*cert), get_random_u32() & 0x7FFFFFFF);
  268. /* Set the commonNames. */
  269. if (commonNames != NULL) {
  270. X509_NAME *subj;
  271. const struct lstr *name;
  272. subj = X509_get_subject_name(*cert);
  273. for (name = commonNames; !is_sentinel(name); name++) {
  274. if (X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
  275. (unsigned char *) name->s, name->len, -1, 0) == 0) {
  276. goto err;
  277. }
  278. }
  279. }
  280. /* Set the dNSNames. */
  281. if (set_dNSNames(*cert, dNSNames) == 0)
  282. goto err;
  283. if (X509_set_issuer_name(*cert, X509_get_subject_name(*cert)) == 0
  284. || X509_gmtime_adj(X509_get_notBefore(*cert), 0) == 0
  285. || X509_gmtime_adj(X509_get_notAfter(*cert), 60) == 0
  286. || X509_set_pubkey(*cert, *key) == 0) {
  287. goto err;
  288. }
  289. /* Sign it. */
  290. if (X509_sign(*cert, *key, EVP_sha1()) == 0)
  291. goto err;
  292. return 1;
  293. err:
  294. if (*cert != NULL)
  295. X509_free(*cert);
  296. if (*key != NULL)
  297. EVP_PKEY_free(*key);
  298. return 0;
  299. }
  300. static void print_escaped(const char *s, size_t len)
  301. {
  302. int c;
  303. for ( ; len > 0; len--) {
  304. c = (unsigned char) *s++;
  305. if (isprint(c) && !isspace(c))
  306. putchar(c);
  307. else
  308. printf("\\%03o", c);
  309. }
  310. }
  311. static void print_array(const struct lstr array[])
  312. {
  313. const struct lstr *p;
  314. if (array == NULL) {
  315. printf("[]");
  316. return;
  317. }
  318. printf("[");
  319. for (p = array; !is_sentinel(p); p++) {
  320. if (p != array)
  321. printf(" ");
  322. print_escaped(p->s, p->len);
  323. }
  324. printf("]");
  325. }
  326. static int lstr_equal(const struct lstr *a, const struct lstr *b)
  327. {
  328. return a->len == b->len && memcmp(a->s, b->s, a->len) == 0;
  329. }
  330. static int arrays_equal(const struct lstr a[], const struct lstr b[])
  331. {
  332. if (a == NULL)
  333. return b == NULL;
  334. if (b == NULL)
  335. return a == NULL;
  336. while (!is_sentinel(a) && !is_sentinel(b)) {
  337. if (!lstr_equal(a, b))
  338. return 0;
  339. a++;
  340. b++;
  341. }
  342. return is_sentinel(a) && is_sentinel(b);
  343. }
  344. /* This is just a constant used to give a fixed length to the arrays that are
  345. conceptually variable-length in the test cases. Increase it if some array
  346. grows too big. */
  347. #define ARR_LEN 10
  348. const struct lstr test_names[] = {
  349. LSTR("a.com"), LSTR("www.a.com"), LSTR("sub.www.a.com"),
  350. LSTR("www.example.com"), LSTR("example.co.uk"), LSTR("*.*.com"),
  351. LSTR_SENTINEL
  352. };
  353. /* These tests just check that matching a single string works properly. */
  354. struct {
  355. const struct lstr name[ARR_LEN];
  356. const struct lstr expected[ARR_LEN];
  357. } single_tests[] = {
  358. { { LSTR_SENTINEL },
  359. { LSTR_SENTINEL } },
  360. { { LSTR("a.com"), LSTR_SENTINEL },
  361. { LSTR("a.com"), LSTR_SENTINEL } },
  362. { { LSTR("www.a.com"), LSTR_SENTINEL },
  363. { LSTR("www.a.com"), LSTR_SENTINEL } },
  364. { { LSTR("*.a.com"), LSTR_SENTINEL },
  365. { LSTR("www.a.com"), LSTR_SENTINEL } },
  366. { { LSTR("w*.a.com"), LSTR_SENTINEL },
  367. { LSTR_SENTINEL } },
  368. { { LSTR("*w.a.com"), LSTR_SENTINEL },
  369. { LSTR_SENTINEL } },
  370. { { LSTR("www.*.com"), LSTR_SENTINEL },
  371. { LSTR_SENTINEL } },
  372. { { LSTR("*.com"), LSTR_SENTINEL },
  373. { LSTR_SENTINEL } },
  374. { { LSTR("*.com."), LSTR_SENTINEL },
  375. { LSTR_SENTINEL } },
  376. { { LSTR("*.*.com"), LSTR_SENTINEL },
  377. { LSTR_SENTINEL } },
  378. { { LSTR("a.com\0evil.com"), LSTR_SENTINEL },
  379. { LSTR_SENTINEL } },
  380. };
  381. /* These test different combinations of commonName and dNSName. */
  382. struct {
  383. const struct lstr common[ARR_LEN];
  384. const struct lstr dns[ARR_LEN];
  385. const struct lstr expected[ARR_LEN];
  386. } double_tests[] = {
  387. /* Should not match any commonName if any dNSNames exist. */
  388. { { LSTR("a.com"), LSTR_SENTINEL },
  389. { LSTR("example.co.uk"), LSTR_SENTINEL },
  390. { LSTR("example.co.uk"), LSTR_SENTINEL } },
  391. { { LSTR("a.com"), LSTR_SENTINEL },
  392. { LSTR("b.com"), LSTR_SENTINEL },
  393. { LSTR_SENTINEL } },
  394. /* Should check against all of the dNSNames. */
  395. { { LSTR_SENTINEL },
  396. { LSTR("a.com"), LSTR("example.co.uk"), LSTR("b.com"), LSTR_SENTINEL },
  397. { LSTR("a.com"), LSTR("example.co.uk"), LSTR_SENTINEL } },
  398. };
  399. const struct lstr specificity_test_names[] = {
  400. LSTR("a.com"),
  401. LSTR("sub.b.com"), LSTR("sub.c.com"), LSTR("sub.d.com"),
  402. LSTR("sub.sub.e.com"), LSTR("sub.sub.f.com"), LSTR("sub.sub.g.com"),
  403. LSTR_SENTINEL
  404. };
  405. /* Validation should check only the "most specific" commonName if multiple
  406. exist. This "most specific" term is used in RFCs 2818, 4261, and 5018 at
  407. least, but is not defined anywhere that I can find. Let's interpret it as the
  408. greatest number of name elements, with wildcard names considered less
  409. specific than all non-wildcard names. For ties, the name that comes later is
  410. considered more specific. */
  411. struct {
  412. const struct lstr patterns[ARR_LEN];
  413. const struct lstr expected_forward;
  414. const struct lstr expected_backward;
  415. } specificity_tests[] = {
  416. { { LSTR("a.com"), LSTR("*.b.com"), LSTR("sub.c.com"), LSTR("sub.d.com"), LSTR("*.sub.e.com"), LSTR("*.sub.f.com"), LSTR("sub.sub.g.com"), LSTR_SENTINEL },
  417. LSTR("sub.sub.g.com"), LSTR("sub.sub.g.com") },
  418. { { LSTR("a.com"), LSTR("*.b.com"), LSTR("sub.c.com"), LSTR("sub.d.com"), LSTR("*.sub.e.com"), LSTR("*.sub.f.com"), LSTR_SENTINEL },
  419. LSTR("sub.d.com"), LSTR("sub.c.com") },
  420. { { LSTR("a.com"), LSTR("*.b.com"), LSTR("sub.c.com"), LSTR("*.sub.e.com"), LSTR("*.sub.f.com"), LSTR_SENTINEL },
  421. LSTR("sub.c.com"), LSTR("sub.c.com") },
  422. { { LSTR("a.com"), LSTR("*.b.com"), LSTR("*.sub.e.com"), LSTR("*.sub.f.com"), LSTR_SENTINEL },
  423. LSTR("a.com"), LSTR("a.com") },
  424. { { LSTR("*.b.com"), LSTR("*.sub.e.com"), LSTR("*.sub.f.com"), LSTR_SENTINEL },
  425. LSTR("sub.sub.f.com"), LSTR("sub.sub.e.com") },
  426. { { LSTR("*.b.com"), LSTR("*.sub.e.com"), LSTR_SENTINEL },
  427. LSTR("sub.sub.e.com"), LSTR("sub.sub.e.com") },
  428. };
  429. #define NELEMS(a) (sizeof(a) / sizeof(a[0]))
  430. void reverse(struct lstr a[])
  431. {
  432. struct lstr tmp;
  433. unsigned int i, j;
  434. i = 0;
  435. for (j = 0; !is_sentinel(&a[j]); j++)
  436. ;
  437. if (j == 0)
  438. return;
  439. j--;
  440. while (i < j) {
  441. tmp = a[i];
  442. a[i] = a[j];
  443. a[j] = tmp;
  444. i++;
  445. j--;
  446. }
  447. }
  448. void test_specificity(const struct lstr patterns[],
  449. const struct lstr test_names[],
  450. const struct lstr expected_forward[],
  451. const struct lstr expected_backward[])
  452. {
  453. struct lstr scratch[ARR_LEN];
  454. unsigned int i;
  455. for (i = 0; i < ARR_LEN && !is_sentinel(&patterns[i]); i++)
  456. scratch[i] = patterns[i];
  457. ncat_assert(i < ARR_LEN);
  458. scratch[i] = lstr_sentinel;
  459. test(scratch, NULL, test_names, expected_forward);
  460. reverse(scratch);
  461. test(scratch, NULL, test_names, expected_backward);
  462. return;
  463. }
  464. int main(void)
  465. {
  466. unsigned int i;
  467. SSL_library_init();
  468. ERR_load_crypto_strings();
  469. SSL_load_error_strings();
  470. /* Test single pattens in both the commonName and dNSName positions. */
  471. for (i = 0; i < NELEMS(single_tests); i++)
  472. test(single_tests[i].name, NULL, test_names, single_tests[i].expected);
  473. for (i = 0; i < NELEMS(single_tests); i++)
  474. test(NULL, single_tests[i].name, test_names, single_tests[i].expected);
  475. for (i = 0; i < NELEMS(double_tests); i++) {
  476. test(double_tests[i].common, double_tests[i].dns,
  477. test_names, double_tests[i].expected);
  478. }
  479. for (i = 0; i < NELEMS(specificity_tests); i++) {
  480. struct lstr expected_forward[2], expected_backward[2];
  481. /* Put the expected names in arrays for the test. */
  482. expected_forward[0] = specificity_tests[i].expected_forward;
  483. expected_forward[1] = lstr_sentinel;
  484. expected_backward[0] = specificity_tests[i].expected_backward;
  485. expected_backward[1] = lstr_sentinel;
  486. test_specificity(specificity_tests[i].patterns,
  487. specificity_test_names, expected_forward, expected_backward);
  488. }
  489. printf("%d / %d tests passed.\n", tests_passed, tests_run);
  490. return tests_passed == tests_run ? 0 : 1;
  491. }