X-Git-Url: https://www.bearssl.org/gitweb//home/git/?p=BearSSL;a=blobdiff_plain;f=test%2Ftest_x509.c;h=2c61cf5dd24507e30b136dddefe32c9b9ccbd542;hp=c4f088588002f18370d04508e8bcbbf068c3a58b;hb=4b6046412bf927d6424f20fc7ee495bb96dbd227;hpb=e61ad42191511226309bad2cbde8cd9e8cc743cb diff --git a/test/test_x509.c b/test/test_x509.c index c4f0885..2c61cf5 100644 --- a/test/test_x509.c +++ b/test/test_x509.c @@ -27,10 +27,22 @@ #include #include +#ifdef _WIN32 +#include +#else +#include +#endif + #include "bearssl.h" +#define STR(x) STR_(x) +#define STR_(x) #x +#ifdef SRCDIRNAME +#define DIRNAME STR(SRCDIRNAME) "/test/x509" +#else #define DIRNAME "test/x509" -#define CONFFILE (DIRNAME "/alltests.txt") +#endif +#define CONFFILE DIRNAME "/alltests.txt" #define DEFAULT_TIME "2016-08-30T18:00:00Z" static void * @@ -1519,9 +1531,9 @@ run_test_case(test_case *tc) br_x509_minimal_set_hash(&ctx, id, hash_impls[u].impl); } } - br_x509_minimal_set_rsa(&ctx, br_rsa_i32_pkcs1_vrfy); + br_x509_minimal_set_rsa(&ctx, br_rsa_pkcs1_vrfy_get_default()); br_x509_minimal_set_ecdsa(&ctx, - &br_ec_prime_i31, br_ecdsa_i31_vrfy_asn1); + br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default()); /* * Set the validation date. @@ -1626,11 +1638,403 @@ run_test_case(test_case *tc) printf("OK\n"); } +/* + * A custom structure for tests, synchronised with the test certificate + * names.crt. + * + * If num is 1 or more, then this is a DN element with OID '1.1.1.1.num'. + * If num is -1 or less, then this is a SAN element of type -num. + * If num is 0, then this is a SAN element of type OtherName with + * OID 1.3.6.1.4.1.311.20.2.3 (Microsoft UPN). + */ +typedef struct { + int num; + int status; + const char *expected; +} name_element_test; + +static name_element_test names_ref[] = { + /* === DN tests === */ + { + /* [12] 66:6f:6f */ + 1, 1, "foo" + }, + { + /* [12] 62:61:72 */ + 1, 1, "bar" + }, + { + /* [18] 31:32:33:34 */ + 2, 1, "1234" + }, + { + /* [19] 66:6f:6f */ + 3, 1, "foo" + }, + { + /* [20] 66:6f:6f */ + 4, 1, "foo" + }, + { + /* [22] 66:6f:6f */ + 5, 1, "foo" + }, + { + /* [30] 00:66:00:6f:00:6f */ + 6, 1, "foo" + }, + { + /* [30] fe:ff:00:66:00:6f:00:6f */ + 7, 1, "foo" + }, + { + /* [30] ff:fe:66:00:6f:00:6f:00 */ + 8, 1, "foo" + }, + { + /* [20] 63:61:66:e9 */ + 9, 1, "caf\xC3\xA9" + }, + { + /* [12] 63:61:66:c3:a9 */ + 10, 1, "caf\xC3\xA9" + }, + { + /* [12] 63:61:66:e0:83:a9 */ + 11, -1, NULL + }, + { + /* [12] 63:61:66:e3:90:8c */ + 12, 1, "caf\xE3\x90\x8C" + }, + { + /* [30] 00:63:00:61:00:66:34:0c */ + 13, 1, "caf\xE3\x90\x8C" + }, + { + /* [12] 63:61:66:c3 */ + 14, -1, NULL + }, + { + /* [30] d8:42:df:f4:00:67:00:6f */ + 15, 1, "\xF0\xA0\xAF\xB4go" + }, + { + /* [30] 00:66:d8:42 */ + 16, -1, NULL + }, + { + /* [30] d8:42:00:66 */ + 17, -1, NULL + }, + { + /* [30] df:f4:00:66 */ + 18, -1, NULL + }, + { + /* [12] 66:00:6f */ + 19, -1, NULL + }, + { + /* [30] 00:00:34:0c */ + 20, -1, NULL + }, + { + /* [30] 34:0c:00:00:00:66 */ + 21, -1, NULL + }, + { + /* [12] ef:bb:bf:66:6f:6f */ + 22, 1, "foo" + }, + { + /* [30] 00:66:ff:fe:00:6f */ + 23, -1, NULL + }, + { + /* [30] 00:66:ff:fd:00:6f */ + 24, 1, "f\xEF\xBF\xBDo" + }, + + /* === Value not found in the DN === */ + { + 127, 0, NULL + }, + + /* === SAN tests === */ + { + /* SAN OtherName (Microsoft UPN) */ + 0, 1, "foo@bar.com" + }, + { + /* SAN rfc822Name */ + -1, 1, "bar@foo.com" + }, + { + /* SAN dNSName */ + -2, 1, "example.com" + }, + { + /* SAN dNSName */ + -2, 1, "www.example.com" + }, + { + /* uniformResourceIdentifier */ + -6, 1, "http://www.example.com/" + } +}; + +static void +free_name_elements(br_name_element *elts, size_t num) +{ + size_t u; + + for (u = 0; u < num; u ++) { + xfree((void *)elts[u].oid); + xfree(elts[u].buf); + } + xfree(elts); +} + +static void +test_name_extraction(void) +{ + unsigned char *data; + size_t len; + br_x509_minimal_context ctx; + uint32_t days, seconds; + size_t u; + unsigned status; + br_name_element *names; + size_t num_names; + int good; + + printf("Name extraction: "); + fflush(stdout); + data = read_file("names.crt", &len); + br_x509_minimal_init(&ctx, &br_sha256_vtable, NULL, 0); + for (u = 0; hash_impls[u].id; u ++) { + int id; + + id = hash_impls[u].id; + br_x509_minimal_set_hash(&ctx, id, hash_impls[u].impl); + } + br_x509_minimal_set_rsa(&ctx, br_rsa_pkcs1_vrfy_get_default()); + br_x509_minimal_set_ecdsa(&ctx, + br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default()); + string_to_time(DEFAULT_TIME, &days, &seconds); + br_x509_minimal_set_time(&ctx, days, seconds); + + num_names = (sizeof names_ref) / (sizeof names_ref[0]); + names = xmalloc(num_names * sizeof *names); + for (u = 0; u < num_names; u ++) { + int num; + unsigned char *oid; + + num = names_ref[u].num; + if (num > 0) { + oid = xmalloc(5); + oid[0] = 4; + oid[1] = 0x29; + oid[2] = 0x01; + oid[3] = 0x01; + oid[4] = num; + } else if (num == 0) { + oid = xmalloc(13); + oid[0] = 0x00; + oid[1] = 0x00; + oid[2] = 0x0A; + oid[3] = 0x2B; + oid[4] = 0x06; + oid[5] = 0x01; + oid[6] = 0x04; + oid[7] = 0x01; + oid[8] = 0x82; + oid[9] = 0x37; + oid[10] = 0x14; + oid[11] = 0x02; + oid[12] = 0x03; + } else { + oid = xmalloc(2); + oid[0] = 0x00; + oid[1] = -num; + } + names[u].oid = oid; + names[u].buf = xmalloc(256); + names[u].len = 256; + } + br_x509_minimal_set_name_elements(&ctx, names, num_names); + + /* + * Put "canaries" to detect actual stack usage. + */ + for (u = 0; u < (sizeof ctx.dp_stack) / sizeof(uint32_t); u ++) { + ctx.dp_stack[u] = 0xA7C083FE; + } + for (u = 0; u < (sizeof ctx.rp_stack) / sizeof(uint32_t); u ++) { + ctx.rp_stack[u] = 0xA7C083FE; + } + + /* + * Run the engine. Since we set no trust anchor, we expect a status + * of "not trusted". + */ + ctx.vtable->start_chain(&ctx.vtable, NULL); + ctx.vtable->start_cert(&ctx.vtable, len); + ctx.vtable->append(&ctx.vtable, data, len); + ctx.vtable->end_cert(&ctx.vtable); + status = ctx.vtable->end_chain(&ctx.vtable); + if (status != BR_ERR_X509_NOT_TRUSTED) { + fprintf(stderr, "wrong status: %u\n", status); + exit(EXIT_FAILURE); + } + + /* + * Check stack usage. + */ + for (u = (sizeof ctx.dp_stack) / sizeof(uint32_t); u > 0; u --) { + if (ctx.dp_stack[u - 1] != 0xA7C083FE) { + if (max_dp_usage < u) { + max_dp_usage = u; + } + break; + } + } + for (u = (sizeof ctx.rp_stack) / sizeof(uint32_t); u > 0; u --) { + if (ctx.rp_stack[u - 1] != 0xA7C083FE) { + if (max_rp_usage < u) { + max_rp_usage = u; + } + break; + } + } + + good = 1; + for (u = 0; u < num_names; u ++) { + if (names[u].status != names_ref[u].status) { + printf("ERR: name %u (id=%d): status=%d, expected=%d\n", + (unsigned)u, names_ref[u].num, + names[u].status, names_ref[u].status); + if (names[u].status > 0) { + unsigned char *p; + + printf(" obtained:"); + p = (unsigned char *)names[u].buf; + while (*p) { + printf(" %02X", *p ++); + } + printf("\n"); + } + good = 0; + continue; + } + if (names_ref[u].expected == NULL) { + if (names[u].buf[0] != 0) { + printf("ERR: name %u not zero-terminated\n", + (unsigned)u); + good = 0; + continue; + } + } else { + if (strcmp(names[u].buf, names_ref[u].expected) != 0) { + unsigned char *p; + + printf("ERR: name %u (id=%d): wrong value\n", + (unsigned)u, names_ref[u].num); + printf(" expected:"); + p = (unsigned char *)names_ref[u].expected; + while (*p) { + printf(" %02X", *p ++); + } + printf("\n"); + printf(" obtained:"); + p = (unsigned char *)names[u].buf; + while (*p) { + printf(" %02X", *p ++); + } + printf("\n"); + good = 0; + continue; + } + } + } + if (!good) { + exit(EXIT_FAILURE); + } + + /* + for (u = 0; u < num_names; u ++) { + printf("%u: (%d)", (unsigned)u, names[u].status); + if (names[u].status > 0) { + size_t v; + + for (v = 0; names[u].buf[v]; v ++) { + printf(" %02x", names[u].buf[v]); + } + } + printf("\n"); + } + */ + + xfree(data); + free_name_elements(names, num_names); + printf("OK\n"); +} + int -main(void) +main(int argc, const char *argv[]) { size_t u; +#ifdef SRCDIRNAME + /* + * We want to change the current directory to that of the + * executable, so that test files are reliably located. We + * do that only if SRCDIRNAME is defined (old Makefile would + * not do that). + */ + if (argc >= 1) { + const char *arg, *c; + + arg = argv[0]; + for (c = arg + strlen(arg);; c --) { + int sep, r; + +#ifdef _WIN32 + sep = (*c == '/') || (*c == '\\'); +#else + sep = (*c == '/'); +#endif + if (sep) { + size_t len; + char *dn; + + len = 1 + (c - arg); + dn = xmalloc(len + 1); + memcpy(dn, arg, len); + dn[len] = 0; +#ifdef _WIN32 + r = _chdir(dn); +#else + r = chdir(dn); +#endif + if (r != 0) { + fprintf(stderr, "warning: could not" + " set directory to '%s'\n", dn); + } + xfree(dn); + break; + } + if (c == arg) { + break; + } + } + } +#else + (void)argc; + (void)argv; +#endif + process_conf_file(CONFFILE); max_dp_usage = 0; @@ -1638,6 +2042,7 @@ main(void) for (u = 0; u < all_chains_ptr; u ++) { run_test_case(&all_chains[u]); } + test_name_extraction(); printf("Maximum data stack usage: %u\n", (unsigned)max_dp_usage); printf("Maximum return stack usage: %u\n", (unsigned)max_rp_usage); @@ -1648,5 +2053,6 @@ main(void) free_test_case_contents(&all_chains[u]); } xfree(all_chains); + return 0; }