Skip to content
sslapitest.c 77.4 KiB
Newer Older
Matt Caswell's avatar
Matt Caswell committed

    /* Continue writing the message we started earlier */
    if (!SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written)
            || written != strlen(MSG1)) {
        printf("Failed writing message 1\n");
        goto end;
    }

    if (!SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes)
            || readbytes != strlen(MSG1)
            || memcmp(MSG1, buf, strlen(MSG1))) {
        printf("Failed reading message 1\n");
        goto end;
    }

    if (!SSL_write_ex(serverssl, MSG2, strlen(MSG2), &written)
            || written != strlen(MSG2)) {
        printf("Failed writing message 2\n");
        goto end;
    }

    /*
     * Should block due to the NewSessionTicket arrival unless we're using
     * read_ahead
     */
    if (idx == 0) {
        if (SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes)) {
            printf("Unexpected success reading message 2\n");
            goto end;
        }
Matt Caswell's avatar
Matt Caswell committed
    }

    if (!SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes)
            || readbytes != strlen(MSG2)
            || memcmp(MSG2, buf, strlen(MSG2))) {
        printf("Failed reading message 2\n");
        goto end;
    }

    testresult = 1;

 end:
    if(!testresult)
        ERR_print_errors_fp(stdout);
    SSL_SESSION_free(sess);
    SSL_free(serverssl);
    SSL_free(clientssl);
    SSL_CTX_free(sctx);
    SSL_CTX_free(cctx);

    return testresult;
}

static int test_early_data_not_expected(int idx)
Matt Caswell's avatar
Matt Caswell committed
{
    SSL_CTX *cctx = NULL, *sctx = NULL;
    SSL *clientssl = NULL, *serverssl = NULL;
    int testresult = 0;
    SSL_SESSION *sess;
    unsigned char buf[20];
    size_t readbytes, written;

    /*
     * Test that a server that doesn't try to read early data can handle a
     * client sending some.
     */

    if (!setupearly_data_test(&cctx, &sctx, &clientssl, &serverssl, &sess, idx))
Matt Caswell's avatar
Matt Caswell committed
        goto end;

    /* Write some early data */
    if (!SSL_write_early_data(clientssl, MSG1, strlen(MSG1), &written)) {
Matt Caswell's avatar
Matt Caswell committed
        printf("Unexpected failure writing message 1\n");
        goto end;
    }

    /*
     * Server should skip over early data and then block waiting for client to
     * continue handshake
     */
    if (SSL_accept(serverssl) > 0) {
        printf("Unexpected success setting up server connection\n");
        goto end;
    }

    if (SSL_connect(clientssl) <= 0) {
        printf("Failed setting up client connection\n");
        goto end;
    }

    if (SSL_get_early_data_status(serverssl) != SSL_EARLY_DATA_REJECTED) {
        printf("Unexpected early data status\n");
        goto end;
    }

    if (SSL_accept(serverssl) <= 0) {
        printf("Failed setting up server connection\n");
        goto end;
    }

    if (SSL_get_early_data_status(clientssl) != SSL_EARLY_DATA_REJECTED) {
        printf("Unexpected early data status (2)\n");
        goto end;
    }

    /* Send some normal data from client to server */
    if (!SSL_write_ex(clientssl, MSG2, strlen(MSG2), &written)
            || written != strlen(MSG2)) {
        printf("Failed writing message 2\n");
        goto end;
    }

    if (!SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes)
            || readbytes != strlen(MSG2)
            || memcmp(MSG2, buf, strlen(MSG2))) {
        printf("Failed reading message 2\n");
        goto end;
    }

    testresult = 1;

 end:
    if(!testresult)
        ERR_print_errors_fp(stdout);
    SSL_SESSION_free(sess);
    SSL_free(serverssl);
    SSL_free(clientssl);
    SSL_CTX_free(sctx);
    SSL_CTX_free(cctx);

    return testresult;
}


# ifndef OPENSSL_NO_TLS1_2
static int test_early_data_tls1_2(int idx)
Matt Caswell's avatar
Matt Caswell committed
{
    SSL_CTX *cctx = NULL, *sctx = NULL;
    SSL *clientssl = NULL, *serverssl = NULL;
    int testresult = 0;
    unsigned char buf[20];
    size_t readbytes, written;

    /*
     * Test that a server attempting to read early data can handle a connection
     * from a TLSv1.2 client.
     */

    if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), &sctx,
                             &cctx, cert, privkey)) {
        printf("Unable to create SSL_CTX pair\n");
        goto end;
    }

    /* When idx == 1 we repeat the tests with read_ahead set */
    if (idx > 0) {
        SSL_CTX_set_read_ahead(cctx, 1);
        SSL_CTX_set_read_ahead(sctx, 1);
    }

Matt Caswell's avatar
Matt Caswell committed
    if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) {
        printf("Unable to create SSL objects\n");
        goto end;
    }

    /* Write some data - should block due to handshake with server */
    SSL_set_max_proto_version(clientssl, TLS1_2_VERSION);
    SSL_set_connect_state(clientssl);
    if (SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written)) {
        printf("Unexpected success writing message 1\n");
        goto end;
    }

    /*
     * Server should do TLSv1.2 handshake. First it will block waiting for more
     * messages from client after ServerDone. Then SSL_read_early_data should
     * finish and detect that early data has not been sent
Matt Caswell's avatar
Matt Caswell committed
     */
    if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
                != SSL_READ_EARLY_DATA_ERROR) {
Matt Caswell's avatar
Matt Caswell committed
        printf("Unexpected success reading early data\n");
        goto end;
    }

    /*
     * Continue writing the message we started earlier. Will still block waiting
     * for the CCS/Finished from server
     */
    if (SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written)) {
        printf("Unexpected success writing message 1\n");
        goto end;
    }

    if (SSL_read_early_data(serverssl, buf, sizeof(buf), &readbytes)
                != SSL_READ_EARLY_DATA_FINISH
Matt Caswell's avatar
Matt Caswell committed
            || readbytes != 0) {
        printf("Failed reading early data\n");
        goto end;
    }

    if (SSL_get_early_data_status(serverssl) != SSL_EARLY_DATA_NOT_SENT) {
        printf("Unexpected early data status\n");
        goto end;
    }

    /* Continue writing the message we started earlier */
    if (!SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written)
            || written != strlen(MSG1)) {
        printf("Failed writing message 1\n");
        goto end;
    }

    if (SSL_get_early_data_status(clientssl) != SSL_EARLY_DATA_NOT_SENT) {
        printf("Unexpected early data status (2)\n");
        goto end;
    }

    if (!SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes)
            || readbytes != strlen(MSG1)
            || memcmp(MSG1, buf, strlen(MSG1))) {
        printf("Failed reading message 1\n");
        goto end;
    }

    if (!SSL_write_ex(serverssl, MSG2, strlen(MSG2), &written)
            || written != strlen(MSG2)) {
        printf("Failed writing message 2\n");
        goto end;
    }

    if (!SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes)
            || readbytes != strlen(MSG2)
            || memcmp(MSG2, buf, strlen(MSG2))) {
        printf("Failed reading message 2\n");
        goto end;
    }

    testresult = 1;

 end:
    if(!testresult)
        ERR_print_errors_fp(stdout);
    SSL_free(serverssl);
    SSL_free(clientssl);
    SSL_CTX_free(sctx);
    SSL_CTX_free(cctx);

    return testresult;
}
# endif
#endif

2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559
static int clntaddoldcb = 0;
static int clntparseoldcb = 0;
static int srvaddoldcb = 0;
static int srvparseoldcb = 0;
static int clntaddnewcb = 0;
static int clntparsenewcb = 0;
static int srvaddnewcb = 0;
static int srvparsenewcb = 0;

#define TEST_EXT_TYPE1  0xff00

static int old_add_cb(SSL *s, unsigned int ext_type, const unsigned char **out,
                      size_t *outlen, int *al, void *add_arg)
{
    int *server = (int *)add_arg;
    unsigned char *data;

    if (SSL_is_server(s))
        srvaddoldcb++;
    else
        clntaddoldcb++;

    if (*server != SSL_is_server(s))
        return -1;

    data = OPENSSL_malloc(sizeof(char));
    if (data == NULL)
        return -1;

    *data = 1;
    *out = data;
    *outlen = sizeof(char);

    return 1;
}

static void old_free_cb(SSL *s, unsigned int ext_type, const unsigned char *out,
                        void *add_arg)
{
    OPENSSL_free((unsigned char *)out);
}

static int old_parse_cb(SSL *s, unsigned int ext_type, const unsigned char *in,
                        size_t inlen, int *al, void *parse_arg)
{
    int *server = (int *)parse_arg;

    if (SSL_is_server(s))
        srvparseoldcb++;
    else
        clntparseoldcb++;

    if (*server != SSL_is_server(s))
        return -1;

    if (inlen != sizeof(char) || *in != 1)
        return -1;

    return 1;
}

static int new_add_cb(SSL *s, unsigned int ext_type, unsigned int context,
                      const unsigned char **out, size_t *outlen, X509 *x,
                      size_t chainidx, int *al, void *add_arg)
{
    int *server = (int *)add_arg;
    unsigned char *data;

    if (SSL_is_server(s))
        srvaddnewcb++;
    else
        clntaddnewcb++;

    if (*server != SSL_is_server(s))
        return -1;

    data = OPENSSL_malloc(sizeof(char));
    if (data == NULL)
        return -1;

    *data = 1;
    *out = data;
    *outlen = sizeof(char);

    return 1;
}

static void new_free_cb(SSL *s, unsigned int ext_type, unsigned int context,
                        const unsigned char *out, void *add_arg)
{
    OPENSSL_free((unsigned char *)out);
}

static int new_parse_cb(SSL *s, unsigned int ext_type, unsigned int context,
                        const unsigned char *in, size_t inlen, X509 *x,
                        size_t chainidx, int *al, void *parse_arg)
{
    int *server = (int *)parse_arg;

    if (SSL_is_server(s))
        srvparsenewcb++;
    else
        clntparsenewcb++;

    if (*server != SSL_is_server(s))
        return -1;

    if (inlen != sizeof(char) || *in != 1)
        return -1;

    return 1;
}
/*
 * Custom call back tests.
 * Test 0: Old style callbacks in TLSv1.2
 * Test 1: New style callbacks in TLSv1.2
 * Test 2: New style callbacks in TLSv1.3. Extensions in CH and EE
 * Test 3: New style callbacks in TLSv1.3. Extensions in CH, SH, EE, Cert + NST
 */
static int test_custom_exts(int tst) {
    SSL_CTX *cctx = NULL, *sctx = NULL;
    SSL *clientssl = NULL, *serverssl = NULL;
    int testresult = 0;
    static int server = 1;
    static int client = 0;
    SSL_SESSION *sess = NULL;
    unsigned int context;

    /* Reset callback counters */
    clntaddoldcb = clntparseoldcb = srvaddoldcb = srvparseoldcb = 0;
    clntaddnewcb = clntparsenewcb = srvaddnewcb = srvparsenewcb = 0;

    if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), &sctx,
                             &cctx, cert, privkey)) {
        printf("Unable to create SSL_CTX pair\n");
        return 0;
    }

    if (tst < 2) {
        SSL_CTX_set_options(cctx, SSL_OP_NO_TLSv1_3);
        SSL_CTX_set_options(sctx, SSL_OP_NO_TLSv1_3);
    }

    if (tst == 3) {
        context = SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
                  | SSL_EXT_TLS1_3_SERVER_HELLO
                  | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
                  | SSL_EXT_TLS1_3_CERTIFICATE
                  | SSL_EXT_TLS1_3_NEW_SESSION_TICKET;
    } else {
        context = SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
                  | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS;
    }

    /* Create a client side custom extension */
    if (tst == 0) {
        if (!SSL_CTX_add_client_custom_ext(cctx, TEST_EXT_TYPE1, old_add_cb,
                                           old_free_cb, &client, old_parse_cb,
                                           &client)) {
            printf("Unable to create old style client side custom extension\n");
            return 0;
        }
    } else {
        if (!SSL_CTX_add_custom_ext(cctx, TEST_EXT_TYPE1, context, new_add_cb,
                                    new_free_cb, &client, new_parse_cb,
                                    &client)) {
            printf("Unable to create new style client side custom extension\n");
            return 0;
        }
    }

    /* Should not be able to add duplicates */
    if (SSL_CTX_add_client_custom_ext(cctx, TEST_EXT_TYPE1, old_add_cb,
                                      old_free_cb, &client, old_parse_cb,
                                      &client)) {
        printf("Unexpected success adding duplicate client custom extension\n");
        return 0;
    }
    if (SSL_CTX_add_custom_ext(cctx, TEST_EXT_TYPE1, context, new_add_cb,
                               new_free_cb, &client, new_parse_cb, &client)) {
        printf("Unexpected success adding duplicate client custom extension\n");
        return 0;
    }

    /* Create a server side custom extension */
    if (tst == 0) {
        if (!SSL_CTX_add_server_custom_ext(sctx, TEST_EXT_TYPE1, old_add_cb,
                                           old_free_cb, &server, old_parse_cb,
                                           &server)) {
            printf("Unable to create old style server side custom extension\n");
            return 0;
        }
    } else {
        if (!SSL_CTX_add_custom_ext(sctx, TEST_EXT_TYPE1, context, new_add_cb,
                                    new_free_cb, &server, new_parse_cb,
                                    &server)) {
            printf("Unable to create new style server side custom extension\n");
            return 0;
        }
    }

    /* Should not be able to add duplicates */
    if (SSL_CTX_add_server_custom_ext(sctx, TEST_EXT_TYPE1, old_add_cb,
                                      old_free_cb, &server, old_parse_cb,
                                      &server)) {
        printf("Unexpected success adding duplicate server custom extension\n");
        return 0;
    }
    if (SSL_CTX_add_custom_ext(sctx, TEST_EXT_TYPE1, context, new_add_cb,
                               new_free_cb, &server, new_parse_cb, &server)) {
        printf("Unexpected success adding duplicate server custom extension\n");
        return 0;
    }

    if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) {
        printf("Unable to create SSL objects\n");
        goto end;
    }

    if (!create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) {
        printf("Unable to create SSL connection\n");
        goto end;
    }

    if (tst == 0) {
        if (clntaddoldcb != 1 || clntparseoldcb != 1 || srvaddoldcb != 1
                || srvparseoldcb != 1) {
            printf("Custom extension callbacks not called\n");
            goto end;
        }
    } else if (tst == 1 || tst == 2) {
        if (clntaddnewcb != 1 || clntparsenewcb != 1 || srvaddnewcb != 1
                || srvparsenewcb != 1) {
            printf("Custom extension callbacks not called\n");
            goto end;
        }
    } else {
        if (clntaddnewcb != 1 || clntparsenewcb != 4 || srvaddnewcb != 4
                || srvparsenewcb != 1) {
            printf("Custom extension callbacks not called\n");
            goto end;
        }
    }

    sess = SSL_get1_session(clientssl);

    SSL_shutdown(clientssl);
    SSL_shutdown(serverssl);

    SSL_free(serverssl);
    SSL_free(clientssl);
    serverssl = clientssl = NULL;

    if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) {
        printf("Unable to create SSL objects (2)\n");
        goto end;
    }

    if (!SSL_set_session(clientssl, sess)) {
        printf("Failed setting session\n");
        goto end;
    }

    if (!create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) {
        printf("Unable to create SSL connection (2)\n");
        goto end;
    }

    /*
     * For a resumed session we expect to add the ClientHello extension. For the
     * old style callbacks we ignore it on the server side because they set
     * SSL_EXT_IGNORE_ON_RESUMPTION. The new style callbacks do not ignore
     * them.
     */
    if (tst == 0) {
        if (clntaddoldcb != 2 || clntparseoldcb != 1 || srvaddoldcb != 1
                || srvparseoldcb != 1) {
            printf("Unexpected custom extension callback calls\n");
            goto end;
        }
    } else if (tst == 1 || tst == 2) {
        if (clntaddnewcb != 2 || clntparsenewcb != 2 || srvaddnewcb != 2
                || srvparsenewcb != 2) {
            printf("Unexpected custom extension callback calls\n");
            goto end;
        }
    } else {
        /* No Certificate message extensions in the resumption handshake */
        if (clntaddnewcb != 2 || clntparsenewcb != 7 || srvaddnewcb != 7
                || srvparsenewcb != 2) {
            printf("Unexpected custom extension callback calls\n");
            goto end;
        }
    }

    testresult = 1;

end:
    SSL_SESSION_free(sess);
    SSL_free(serverssl);
    SSL_free(clientssl);
    SSL_CTX_free(sctx);
    SSL_CTX_free(cctx);

    return testresult;
}

int test_main(int argc, char *argv[])
    int testresult = 1;
Matt Caswell's avatar
Matt Caswell committed

    if (argc != 3) {
        printf("Invalid argument count\n");
Matt Caswell's avatar
Matt Caswell committed
    }

    cert = argv[1];
    privkey = argv[2];

    ADD_TEST(test_large_message_tls);
Matt Caswell's avatar
Matt Caswell committed
    ADD_TEST(test_large_message_tls_read_ahead);
Matt Caswell's avatar
Matt Caswell committed
#ifndef OPENSSL_NO_DTLS
    ADD_TEST(test_large_message_dtls);
Matt Caswell's avatar
Matt Caswell committed
#endif
#ifndef OPENSSL_NO_OCSP
    ADD_TEST(test_tlsext_status_type);
Matt Caswell's avatar
Matt Caswell committed
    ADD_TEST(test_session_with_only_int_cache);
    ADD_TEST(test_session_with_only_ext_cache);
    ADD_TEST(test_session_with_both_cache);
    ADD_ALL_TESTS(test_ssl_set_bio, TOTAL_SSL_SET_BIO_TESTS);
Matt Caswell's avatar
Matt Caswell committed
    ADD_TEST(test_ssl_bio_pop_next_bio);
    ADD_TEST(test_ssl_bio_pop_ssl_bio);
    ADD_TEST(test_ssl_bio_change_rbio);
    ADD_TEST(test_ssl_bio_change_wbio);
    ADD_ALL_TESTS(test_set_sigalgs, OSSL_NELEM(testsigalgs) * 2);
    ADD_TEST(test_keylog);
#ifndef OPENSSL_NO_TLS1_3
    ADD_TEST(test_keylog_no_master_key);
#endif
#ifndef OPENSSL_NO_TLS1_2
    ADD_TEST(test_early_cb);
Matt Caswell's avatar
Matt Caswell committed
#endif
#ifndef OPENSSL_NO_TLS1_3
    ADD_ALL_TESTS(test_early_data_read_write, 2);
    ADD_ALL_TESTS(test_early_data_skip, 2);
    ADD_ALL_TESTS(test_early_data_not_sent, 2);
    ADD_ALL_TESTS(test_early_data_not_expected, 2);
Matt Caswell's avatar
Matt Caswell committed
# ifndef OPENSSL_NO_TLS1_2
    ADD_ALL_TESTS(test_early_data_tls1_2, 2);
Matt Caswell's avatar
Matt Caswell committed
# endif
    ADD_ALL_TESTS(test_custom_exts, 4);
    testresult = run_tests(argv[0]);
    bio_s_mempacket_test_free();

    return testresult;