diff --git a/test/handshake_helper.c b/test/handshake_helper.c index 2b869a4247..c82581c576 100644 --- a/test/handshake_helper.c +++ b/test/handshake_helper.c @@ -590,7 +590,14 @@ static void do_reneg_setup_step(const SSL_TEST_CTX *test_ctx, PEER *peer) 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); + || test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT + || test_ctx->handshake_mode + == SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER + || test_ctx->handshake_mode + == SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT); + + /* Reset the count of the amount of app data we need to read/write */ + peer->bytes_to_write = peer->bytes_to_read = test_ctx->app_data_size; /* Check if we are the peer that is going to initiate */ if ((test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER @@ -642,6 +649,29 @@ static void do_reneg_setup_step(const SSL_TEST_CTX *test_ctx, PEER *peer) peer->status = PEER_RETRY; return; } + } else if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER + || test_ctx->handshake_mode + == SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT) { + if (SSL_is_server(peer->ssl) + != (test_ctx->handshake_mode + == SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER)) { + peer->status = PEER_SUCCESS; + return; + } + + ret = SSL_key_update(peer->ssl, test_ctx->key_update_type); + if (!ret) { + peer->status = PEER_ERROR; + return; + } + do_handshake_step(peer); + /* + * This is a one step handshake. We shouldn't get anything other than + * PEER_SUCCESS + */ + if (peer->status != PEER_SUCCESS) + peer->status = PEER_ERROR; + return; } /* @@ -663,7 +693,7 @@ static void do_reneg_setup_step(const SSL_TEST_CTX *test_ctx, PEER *peer) peer->status = PEER_ERROR; return; } - /* If we're no in init yet then we're not done with setup yet */ + /* If we're not in init yet then we're not done with setup yet */ if (!SSL_in_init(peer->ssl)) return; } @@ -720,12 +750,20 @@ static connect_phase_t next_phase(const SSL_TEST_CTX *test_ctx, switch (phase) { case HANDSHAKE: if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER - || test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT) + || test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT + || test_ctx->handshake_mode + == SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT + || test_ctx->handshake_mode + == SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER) return RENEG_APPLICATION_DATA; return APPLICATION_DATA; case RENEG_APPLICATION_DATA: return RENEG_SETUP; case RENEG_SETUP: + if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER + || test_ctx->handshake_mode + == SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT) + return APPLICATION_DATA; return RENEG_HANDSHAKE; case RENEG_HANDSHAKE: return APPLICATION_DATA; diff --git a/test/recipes/80-test_ssl_new.t b/test/recipes/80-test_ssl_new.t index 5c512cf3f5..640f314fbc 100644 --- a/test/recipes/80-test_ssl_new.t +++ b/test/recipes/80-test_ssl_new.t @@ -29,7 +29,7 @@ map { s/\.in// } @conf_files; # We hard-code the number of tests to double-check that the globbing above # finds all files as expected. -plan tests => 20; # = scalar @conf_srcs +plan tests => 21; # = scalar @conf_srcs # Some test results depend on the configuration of enabled protocols. We only # verify generated sources in the default configuration. @@ -82,6 +82,7 @@ my %skip = ( "18-dtls-renegotiate.conf" => $no_dtls, "19-mac-then-encrypt.conf" => $no_pre_tls1_3, "20-cert-select.conf" => disabled("tls1_2") || $no_ec, + "21-key-update.conf" => disabled("tls1_3"), ); foreach my $conf (@conf_files) { diff --git a/test/ssl-tests/21-key-update.conf b/test/ssl-tests/21-key-update.conf new file mode 100644 index 0000000000..b79eb44494 --- /dev/null +++ b/test/ssl-tests/21-key-update.conf @@ -0,0 +1,112 @@ +# Generated with generate_ssl_tests.pl + +num_tests = 4 + +test-0 = 0-update-key-client-update-not-requested +test-1 = 1-update-key-server-update-not-requested +test-2 = 2-update-key-client-update-requested +test-3 = 3-update-key-server-update-requested +# =========================================================== + +[0-update-key-client-update-not-requested] +ssl_conf = 0-update-key-client-update-not-requested-ssl + +[0-update-key-client-update-not-requested-ssl] +server = 0-update-key-client-update-not-requested-server +client = 0-update-key-client-update-not-requested-client + +[0-update-key-client-update-not-requested-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[0-update-key-client-update-not-requested-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-0] +ExpectedResult = Success +HandshakeMode = KeyUpdateClient +KeyUpdateType = KeyUpdateNotRequested +ResumptionExpected = No + + +# =========================================================== + +[1-update-key-server-update-not-requested] +ssl_conf = 1-update-key-server-update-not-requested-ssl + +[1-update-key-server-update-not-requested-ssl] +server = 1-update-key-server-update-not-requested-server +client = 1-update-key-server-update-not-requested-client + +[1-update-key-server-update-not-requested-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[1-update-key-server-update-not-requested-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-1] +ExpectedResult = Success +HandshakeMode = KeyUpdateServer +KeyUpdateType = KeyUpdateNotRequested +ResumptionExpected = No + + +# =========================================================== + +[2-update-key-client-update-requested] +ssl_conf = 2-update-key-client-update-requested-ssl + +[2-update-key-client-update-requested-ssl] +server = 2-update-key-client-update-requested-server +client = 2-update-key-client-update-requested-client + +[2-update-key-client-update-requested-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[2-update-key-client-update-requested-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-2] +ExpectedResult = Success +HandshakeMode = KeyUpdateClient +KeyUpdateType = KeyUpdateRequested +ResumptionExpected = No + + +# =========================================================== + +[3-update-key-server-update-requested] +ssl_conf = 3-update-key-server-update-requested-ssl + +[3-update-key-server-update-requested-ssl] +server = 3-update-key-server-update-requested-server +client = 3-update-key-server-update-requested-client + +[3-update-key-server-update-requested-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[3-update-key-server-update-requested-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-3] +ExpectedResult = Success +HandshakeMode = KeyUpdateServer +KeyUpdateType = KeyUpdateRequested +ResumptionExpected = No + + diff --git a/test/ssl-tests/21-key-update.conf.in b/test/ssl-tests/21-key-update.conf.in new file mode 100644 index 0000000000..4bebb487d6 --- /dev/null +++ b/test/ssl-tests/21-key-update.conf.in @@ -0,0 +1,62 @@ +# -*- mode: perl; -*- +# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + + +## Test KeyUpdate + +use strict; +use warnings; + +package ssltests; + +our @tests = ( + { + name => "update-key-client-update-not-requested", + server => {}, + client => {}, + test => { + "HandshakeMode" => "KeyUpdateClient", + "KeyUpdateType" => "KeyUpdateNotRequested", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + }, + { + name => "update-key-server-update-not-requested", + server => {}, + client => {}, + test => { + "HandshakeMode" => "KeyUpdateServer", + "KeyUpdateType" => "KeyUpdateNotRequested", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + }, + { + name => "update-key-client-update-requested", + server => {}, + client => {}, + test => { + "HandshakeMode" => "KeyUpdateClient", + "KeyUpdateType" => "KeyUpdateRequested", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + }, + { + name => "update-key-server-update-requested", + server => {}, + client => {}, + test => { + "HandshakeMode" => "KeyUpdateServer", + "KeyUpdateType" => "KeyUpdateRequested", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + } +); diff --git a/test/ssl_test_ctx.c b/test/ssl_test_ctx.c index c5b9a3ebe6..66fb31ce5a 100644 --- a/test/ssl_test_ctx.c +++ b/test/ssl_test_ctx.c @@ -322,6 +322,8 @@ static const test_enum ssl_handshake_modes[] = { {"Resume", SSL_TEST_HANDSHAKE_RESUME}, {"RenegotiateServer", SSL_TEST_HANDSHAKE_RENEG_SERVER}, {"RenegotiateClient", SSL_TEST_HANDSHAKE_RENEG_CLIENT}, + {"KeyUpdateServer", SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER}, + {"KeyUpdateClient", SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT}, }; __owur static int parse_handshake_mode(SSL_TEST_CTX *test_ctx, const char *value) @@ -345,6 +347,24 @@ const char *ssl_handshake_mode_name(ssl_handshake_mode_t mode) IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_CLIENT_CONF, client, reneg_ciphers) +/* KeyUpdateType */ + +static const test_enum ssl_key_update_types[] = { + {"KeyUpdateRequested", SSL_KEY_UPDATE_REQUESTED}, + {"KeyUpdateNotRequested", SSL_KEY_UPDATE_NOT_REQUESTED}, +}; + +__owur static int parse_key_update_type(SSL_TEST_CTX *test_ctx, const char *value) +{ + int ret_value; + if (!parse_enum(ssl_key_update_types, OSSL_NELEM(ssl_key_update_types), + &ret_value, value)) { + return 0; + } + test_ctx->key_update_type = ret_value; + return 1; +} + /* CT Validation */ static const test_enum ssl_ct_validation_modes[] = { @@ -522,6 +542,7 @@ static const ssl_test_ctx_option ssl_test_ctx_options[] = { { "ExpectedNPNProtocol", &parse_test_expected_npn_protocol }, { "ExpectedALPNProtocol", &parse_test_expected_alpn_protocol }, { "HandshakeMode", &parse_handshake_mode }, + { "KeyUpdateType", &parse_key_update_type }, { "ResumptionExpected", &parse_test_resumption_expected }, { "ApplicationData", &parse_test_app_data_size }, { "MaxFragmentSize", &parse_test_max_fragment_size }, diff --git a/test/ssl_test_ctx.h b/test/ssl_test_ctx.h index 6036a02bc9..eaeee1fd3c 100644 --- a/test/ssl_test_ctx.h +++ b/test/ssl_test_ctx.h @@ -57,7 +57,9 @@ typedef enum { SSL_TEST_HANDSHAKE_SIMPLE = 0, /* Default */ SSL_TEST_HANDSHAKE_RESUME, SSL_TEST_HANDSHAKE_RENEG_SERVER, - SSL_TEST_HANDSHAKE_RENEG_CLIENT + SSL_TEST_HANDSHAKE_RENEG_CLIENT, + SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER, + SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT } ssl_handshake_mode_t; typedef enum { @@ -121,6 +123,8 @@ typedef struct { int app_data_size; /* Maximum send fragment size. */ int max_fragment_size; + /* KeyUpdate type */ + SSL_KEY_UPDATE key_update_type; /* * Extra server/client configurations. Per-handshake.