X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=test%2Fhandshake_helper.c;h=c14d8e38c4cab39edec269a7409c58c32127e233;hb=d18afb5bf29dc3b81b5f7a9eda2abde35041a441;hp=409f16cf0872afd4e0bdb3e4ae3d7a8ebbea412a;hpb=dd8e5a573272d369cb6dd21592e2b1b1d3941939;p=oweals%2Fopenssl.git diff --git a/test/handshake_helper.c b/test/handshake_helper.c index 409f16cf08..c14d8e38c4 100644 --- a/test/handshake_helper.c +++ b/test/handshake_helper.c @@ -144,6 +144,38 @@ static int servername_reject_cb(SSL *s, int *ad, void *arg) return select_server_ctx(s, arg, 0); } +static unsigned char dummy_ocsp_resp_good_val = 0xff; +static unsigned char dummy_ocsp_resp_bad_val = 0xfe; + +static int server_ocsp_cb(SSL *s, void *arg) +{ + unsigned char *resp; + + resp = OPENSSL_malloc(1); + if (resp == NULL) + return SSL_TLSEXT_ERR_ALERT_FATAL; + /* + * For the purposes of testing we just send back a dummy OCSP response + */ + *resp = *(unsigned char *)arg; + if (!SSL_set_tlsext_status_ocsp_resp(s, resp, 1)) + return SSL_TLSEXT_ERR_ALERT_FATAL; + + return SSL_TLSEXT_ERR_OK; +} + +static int client_ocsp_cb(SSL *s, void *arg) +{ + const unsigned char *resp; + int len; + + len = SSL_get_tlsext_status_ocsp_resp(s, &resp); + if (len != 1 || *resp != dummy_ocsp_resp_good_val) + return 0; + + return 1; +} + static int verify_reject_cb(X509_STORE_CTX *ctx, void *arg) { X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION); return 0; @@ -319,6 +351,16 @@ static void configure_handshake_ctx(SSL_CTX *server_ctx, SSL_CTX *server2_ctx, break; } + if (extra->server.cert_status != SSL_TEST_CERT_STATUS_NONE) { + SSL_CTX_set_tlsext_status_type(client_ctx, TLSEXT_STATUSTYPE_ocsp); + SSL_CTX_set_tlsext_status_cb(client_ctx, client_ocsp_cb); + SSL_CTX_set_tlsext_status_arg(client_ctx, NULL); + SSL_CTX_set_tlsext_status_cb(server_ctx, server_ocsp_cb); + SSL_CTX_set_tlsext_status_arg(server_ctx, + ((extra->server.cert_status == SSL_TEST_CERT_STATUS_GOOD_RESPONSE) + ? &dummy_ocsp_resp_good_val : &dummy_ocsp_resp_bad_val)); + } + /* * The initial_ctx/session_ctx always handles the encrypt/decrypt of the * session ticket. This ticket_key callback is assigned to the second @@ -541,6 +583,85 @@ static void do_app_data_step(PEER *peer) } } +static void do_reneg_setup_step(const SSL_TEST_CTX *test_ctx, PEER *peer) +{ + int ret; + char buf; + + TEST_check(peer->status == PEER_RETRY); + TEST_check(test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER + || test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT); + + /* Check if we are the peer that is going to initiate */ + if ((test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER + && SSL_is_server(peer->ssl)) + || (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT + && !SSL_is_server(peer->ssl))) { + /* + * If we already asked for a renegotiation then fall through to the + * SSL_read() below. + */ + if (!SSL_renegotiate_pending(peer->ssl)) { + /* + * If we are the client we will always attempt to resume the + * session. The server may or may not resume dependant on the + * setting of SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION + */ + if (SSL_is_server(peer->ssl)) + ret = SSL_renegotiate(peer->ssl); + else + ret = SSL_renegotiate_abbreviated(peer->ssl); + if (!ret) { + peer->status = PEER_ERROR; + return; + } + do_handshake_step(peer); + /* + * If status is PEER_RETRY it means we're waiting on the peer to + * continue the handshake. As far as setting up the renegotiation is + * concerned that is a success. The next step will continue the + * handshake to its conclusion. + * + * If status is PEER_SUCCESS then we are the server and we have + * successfully sent the HelloRequest. We need to continue to wait + * until the handshake arrives from the client. + */ + if (peer->status == PEER_RETRY) + peer->status = PEER_SUCCESS; + else if (peer->status == PEER_SUCCESS) + peer->status = PEER_RETRY; + return; + } + } + + /* + * The SSL object is still expecting app data, even though it's going to + * get a handshake message. We try to read, and it should fail - after which + * we should be in a handshake + */ + ret = SSL_read(peer->ssl, &buf, sizeof(buf)); + if (ret >= 0) { + /* + * We're not actually expecting data - we're expecting a reneg to + * start + */ + peer->status = PEER_ERROR; + return; + } else { + int error = SSL_get_error(peer->ssl, ret); + if (error != SSL_ERROR_WANT_READ) { + peer->status = PEER_ERROR; + return; + } + /* If we're no in init yet then we're not done with setup yet */ + if (!SSL_in_init(peer->ssl)) + return; + } + + peer->status = PEER_SUCCESS; +} + + /* * RFC 5246 says: * @@ -575,15 +696,28 @@ static void do_shutdown_step(PEER *peer) typedef enum { HANDSHAKE, + RENEG_APPLICATION_DATA, + RENEG_SETUP, + RENEG_HANDSHAKE, APPLICATION_DATA, SHUTDOWN, CONNECTION_DONE } connect_phase_t; -static connect_phase_t next_phase(connect_phase_t phase) +static connect_phase_t next_phase(const SSL_TEST_CTX *test_ctx, + connect_phase_t phase) { switch (phase) { case HANDSHAKE: + if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER + || test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT) + return RENEG_APPLICATION_DATA; + return APPLICATION_DATA; + case RENEG_APPLICATION_DATA: + return RENEG_SETUP; + case RENEG_SETUP: + return RENEG_HANDSHAKE; + case RENEG_HANDSHAKE: return APPLICATION_DATA; case APPLICATION_DATA: return SHUTDOWN; @@ -594,12 +728,22 @@ static connect_phase_t next_phase(connect_phase_t phase) } } -static void do_connect_step(PEER *peer, connect_phase_t phase) +static void do_connect_step(const SSL_TEST_CTX *test_ctx, PEER *peer, + connect_phase_t phase) { switch (phase) { case HANDSHAKE: do_handshake_step(peer); break; + case RENEG_APPLICATION_DATA: + do_app_data_step(peer); + break; + case RENEG_SETUP: + do_reneg_setup_step(test_ctx, peer); + break; + case RENEG_HANDSHAKE: + do_handshake_step(peer); + break; case APPLICATION_DATA: do_app_data_step(peer); break; @@ -801,18 +945,18 @@ static HANDSHAKE_RESULT *do_handshake_internal( */ for(;;) { if (client_turn) { - do_connect_step(&client, phase); + do_connect_step(test_ctx, &client, phase); status = handshake_status(client.status, server.status, 1 /* client went last */); } else { - do_connect_step(&server, phase); + do_connect_step(test_ctx, &server, phase); status = handshake_status(server.status, client.status, 0 /* server went last */); } switch (status) { case HANDSHAKE_SUCCESS: - phase = next_phase(phase); + phase = next_phase(test_ctx, phase); if (phase == CONNECTION_DONE) { ret->result = SSL_TEST_SUCCESS; goto err; @@ -900,11 +1044,9 @@ HANDSHAKE_RESULT *do_handshake(SSL_CTX *server_ctx, SSL_CTX *server2_ctx, result = do_handshake_internal(server_ctx, server2_ctx, client_ctx, test_ctx, &test_ctx->extra, NULL, &session); - if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_SIMPLE) + if (test_ctx->handshake_mode != SSL_TEST_HANDSHAKE_RESUME) goto end; - TEST_check(test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RESUME); - if (result->result != SSL_TEST_SUCCESS) { result->result = SSL_TEST_FIRST_HANDSHAKE_FAILED; goto end;