summaryrefslogtreecommitdiffstats
path: root/test/ssl_test_ctx.c
diff options
context:
space:
mode:
authorEmilia Kasper <emilia@openssl.org>2016-03-17 15:14:30 +0100
committerEmilia Kasper <emilia@openssl.org>2016-04-05 13:44:46 +0200
commit453dfd8d5ee0893146e0fb61a5978ab59ba95c01 (patch)
tree6ada91599f4ebe125be3d34a69716b23a0688b05 /test/ssl_test_ctx.c
parent173f613b6a9029f34454b642ee4f3db6c6566fcb (diff)
New SSL test framework
Currently, SSL tests are configured via command-line switches to ssltest.c. This results in a lot of duplication between ssltest.c and apps, and a complex setup. ssltest.c is also simply old and needs maintenance. Instead, we already have a way to configure SSL servers and clients, so we leverage that. SSL tests can now be configured from a configuration file. Test servers and clients are configured using the standard ssl_conf module. Additional test settings are configured via a test configuration. Moreover, since the CONF language involves unnecessary boilerplate, the test conf itself is generated from a shorter Perl syntax. The generated testcase files are checked in to the repo to make it easier to verify that the intended test cases are in fact run; and to simplify debugging failures. To demonstrate the approach, min/max protocol tests are converted to the new format. This change also fixes MinProtocol and MaxProtocol handling. It was previously requested that an SSL_CTX have both the server and client flags set for these commands; this clearly can never work. Guide to this PR: - test/ssl_test.c - test framework - test/ssl_test_ctx.* - test configuration structure - test/handshake_helper.* - new SSL test handshaking code - test/ssl-tests/ - test configurations - test/generate_ssl_tests.pl - script for generating CONF-style test configurations from perl inputs Reviewed-by: Richard Levitte <levitte@openssl.org>
Diffstat (limited to 'test/ssl_test_ctx.c')
-rw-r--r--test/ssl_test_ctx.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/test/ssl_test_ctx.c b/test/ssl_test_ctx.c
new file mode 100644
index 0000000000..0c1bbbde9e
--- /dev/null
+++ b/test/ssl_test_ctx.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL licenses, (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * https://www.openssl.org/source/license.html
+ * or in the file LICENSE in the source distribution.
+ */
+
+#include <string.h>
+
+#include <openssl/e_os2.h>
+#include <openssl/crypto.h>
+
+#include "e_os.h"
+#include "ssl_test_ctx.h"
+
+/* True enums and other test configuration values that map to an int. */
+typedef struct {
+ const char *name;
+ int value;
+} test_enum;
+
+
+__owur static int parse_enum(const test_enum *enums, size_t num_enums,
+ int *value, const char *name)
+{
+ size_t i;
+ for (i = 0; i < num_enums; i++) {
+ if (strcmp(enums[i].name, name) == 0) {
+ *value = enums[i].value;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static const char *enum_name(const test_enum *enums, size_t num_enums,
+ int value)
+{
+ size_t i;
+ for (i = 0; i < num_enums; i++) {
+ if (enums[i].value == value) {
+ return enums[i].name;
+ }
+ }
+ return "InvalidValue";
+}
+
+
+/*******************/
+/* ExpectedResult. */
+/*******************/
+
+static const test_enum ssl_test_results[] = {
+ {"Success", SSL_TEST_SUCCESS},
+ {"ServerFail", SSL_TEST_SERVER_FAIL},
+ {"ClientFail", SSL_TEST_CLIENT_FAIL},
+ {"InternalError", SSL_TEST_INTERNAL_ERROR},
+};
+
+__owur static int parse_expected_result(SSL_TEST_CTX *test_ctx, const char *value)
+{
+ int ret_value;
+ if (!parse_enum(ssl_test_results, OSSL_NELEM(ssl_test_results),
+ &ret_value, value)) {
+ return 0;
+ }
+ test_ctx->expected_result = ret_value;
+ return 1;
+}
+
+const char *ssl_test_result_t_name(ssl_test_result_t result)
+{
+ return enum_name(ssl_test_results, OSSL_NELEM(ssl_test_results), result);
+}
+
+/******************************/
+/* ClientAlert / ServerAlert. */
+/******************************/
+
+static const test_enum ssl_alerts[] = {
+ {"UnknownCA", SSL_AD_UNKNOWN_CA},
+};
+
+__owur static int parse_alert(int *alert, const char *value)
+{
+ return parse_enum(ssl_alerts, OSSL_NELEM(ssl_alerts), alert, value);
+}
+
+__owur static int parse_client_alert(SSL_TEST_CTX *test_ctx, const char *value)
+{
+ return parse_alert(&test_ctx->client_alert, value);
+}
+
+__owur static int parse_server_alert(SSL_TEST_CTX *test_ctx, const char *value)
+{
+ return parse_alert(&test_ctx->server_alert, value);
+}
+
+const char *ssl_alert_name(int alert)
+{
+ return enum_name(ssl_alerts, OSSL_NELEM(ssl_alerts), alert);
+}
+
+/************/
+/* Protocol */
+/************/
+
+static const test_enum ssl_protocols[] = {
+ {"TLSv1.2", TLS1_2_VERSION},
+ {"TLSv1.1", TLS1_1_VERSION},
+ {"TLSv1", TLS1_VERSION},
+ {"SSLv3", SSL3_VERSION},
+};
+
+__owur static int parse_protocol(SSL_TEST_CTX *test_ctx, const char *value)
+{
+ return parse_enum(ssl_protocols, OSSL_NELEM(ssl_protocols),
+ &test_ctx->protocol, value);
+}
+
+const char *ssl_protocol_name(int protocol)
+{
+ return enum_name(ssl_protocols, OSSL_NELEM(ssl_protocols), protocol);
+}
+
+
+/*************************************************************/
+/* Known test options and their corresponding parse methods. */
+/*************************************************************/
+
+typedef struct {
+ const char *name;
+ int (*parse)(SSL_TEST_CTX *test_ctx, const char *value);
+} ssl_test_ctx_option;
+
+static const ssl_test_ctx_option ssl_test_ctx_options[] = {
+ { "ExpectedResult", &parse_expected_result },
+ { "ClientAlert", &parse_client_alert },
+ { "ServerAlert", &parse_server_alert },
+ { "Protocol", &parse_protocol },
+};
+
+
+/*
+ * Since these methods are used to create tests, we use OPENSSL_assert liberally
+ * for malloc failures and other internal errors.
+ */
+SSL_TEST_CTX *SSL_TEST_CTX_new()
+{
+ SSL_TEST_CTX *ret;
+ ret = OPENSSL_zalloc(sizeof(*ret));
+ OPENSSL_assert(ret != NULL);
+ ret->expected_result = SSL_TEST_SUCCESS;
+ return ret;
+}
+
+void SSL_TEST_CTX_free(SSL_TEST_CTX *ctx)
+{
+ OPENSSL_free(ctx);
+}
+
+SSL_TEST_CTX *SSL_TEST_CTX_create(const CONF *conf, const char *test_section)
+{
+ STACK_OF(CONF_VALUE) *sk_conf;
+ SSL_TEST_CTX *ctx;
+ int i;
+ size_t j;
+
+ sk_conf = NCONF_get_section(conf, test_section);
+ OPENSSL_assert(sk_conf != NULL);
+
+ ctx = SSL_TEST_CTX_new();
+ OPENSSL_assert(ctx != NULL);
+
+ for (i = 0; i < sk_CONF_VALUE_num(sk_conf); i++) {
+ int found = 0;
+ const CONF_VALUE *option = sk_CONF_VALUE_value(sk_conf, i);
+ for (j = 0; j < OSSL_NELEM(ssl_test_ctx_options); j++) {
+ if (strcmp(option->name, ssl_test_ctx_options[j].name) == 0) {
+ if (!ssl_test_ctx_options[j].parse(ctx, option->value)) {
+ fprintf(stderr, "Bad value %s for option %s\n",
+ option->value, option->name);
+ goto err;
+ }
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ fprintf(stderr, "Unknown test option: %s\n", option->name);
+ goto err;
+ }
+ }
+
+ goto done;
+
+ err:
+ SSL_TEST_CTX_free(ctx);
+ ctx = NULL;
+ done:
+ return ctx;
+}