New SSL test framework
[openssl.git] / test / ssl_test_ctx.c
1 /*
2  * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL licenses, (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * https://www.openssl.org/source/license.html
8  * or in the file LICENSE in the source distribution.
9  */
10
11 #include <string.h>
12
13 #include <openssl/e_os2.h>
14 #include <openssl/crypto.h>
15
16 #include "e_os.h"
17 #include "ssl_test_ctx.h"
18
19 /* True enums and other test configuration values that map to an int. */
20 typedef struct {
21     const char *name;
22     int value;
23 } test_enum;
24
25
26 __owur static int parse_enum(const test_enum *enums, size_t num_enums,
27                              int *value, const char *name)
28 {
29     size_t i;
30     for (i = 0; i < num_enums; i++) {
31         if (strcmp(enums[i].name, name) == 0) {
32             *value = enums[i].value;
33             return 1;
34         }
35     }
36     return 0;
37 }
38
39 static const char *enum_name(const test_enum *enums, size_t num_enums,
40                              int value)
41 {
42     size_t i;
43     for (i = 0; i < num_enums; i++) {
44         if (enums[i].value == value) {
45             return enums[i].name;
46         }
47     }
48     return "InvalidValue";
49 }
50
51
52 /*******************/
53 /* ExpectedResult. */
54 /*******************/
55
56 static const test_enum ssl_test_results[] = {
57     {"Success", SSL_TEST_SUCCESS},
58     {"ServerFail", SSL_TEST_SERVER_FAIL},
59     {"ClientFail", SSL_TEST_CLIENT_FAIL},
60     {"InternalError", SSL_TEST_INTERNAL_ERROR},
61 };
62
63 __owur static int parse_expected_result(SSL_TEST_CTX *test_ctx, const char *value)
64 {
65     int ret_value;
66     if (!parse_enum(ssl_test_results, OSSL_NELEM(ssl_test_results),
67                     &ret_value, value)) {
68         return 0;
69     }
70     test_ctx->expected_result = ret_value;
71     return 1;
72 }
73
74 const char *ssl_test_result_t_name(ssl_test_result_t result)
75 {
76     return enum_name(ssl_test_results, OSSL_NELEM(ssl_test_results), result);
77 }
78
79 /******************************/
80 /* ClientAlert / ServerAlert. */
81 /******************************/
82
83 static const test_enum ssl_alerts[] = {
84     {"UnknownCA", SSL_AD_UNKNOWN_CA},
85 };
86
87 __owur static int parse_alert(int *alert, const char *value)
88 {
89     return parse_enum(ssl_alerts, OSSL_NELEM(ssl_alerts), alert, value);
90 }
91
92 __owur static int parse_client_alert(SSL_TEST_CTX *test_ctx, const char *value)
93 {
94     return parse_alert(&test_ctx->client_alert, value);
95 }
96
97 __owur static int parse_server_alert(SSL_TEST_CTX *test_ctx, const char *value)
98 {
99     return parse_alert(&test_ctx->server_alert, value);
100 }
101
102 const char *ssl_alert_name(int alert)
103 {
104     return enum_name(ssl_alerts, OSSL_NELEM(ssl_alerts), alert);
105 }
106
107 /************/
108 /* Protocol */
109 /************/
110
111 static const test_enum ssl_protocols[] = {
112      {"TLSv1.2", TLS1_2_VERSION},
113      {"TLSv1.1", TLS1_1_VERSION},
114      {"TLSv1", TLS1_VERSION},
115      {"SSLv3", SSL3_VERSION},
116 };
117
118 __owur static int parse_protocol(SSL_TEST_CTX *test_ctx, const char *value)
119 {
120     return parse_enum(ssl_protocols, OSSL_NELEM(ssl_protocols),
121                       &test_ctx->protocol, value);
122 }
123
124 const char *ssl_protocol_name(int protocol)
125 {
126     return enum_name(ssl_protocols, OSSL_NELEM(ssl_protocols), protocol);
127 }
128
129
130 /*************************************************************/
131 /* Known test options and their corresponding parse methods. */
132 /*************************************************************/
133
134 typedef struct {
135     const char *name;
136     int (*parse)(SSL_TEST_CTX *test_ctx, const char *value);
137 } ssl_test_ctx_option;
138
139 static const ssl_test_ctx_option ssl_test_ctx_options[] = {
140     { "ExpectedResult", &parse_expected_result },
141     { "ClientAlert", &parse_client_alert },
142     { "ServerAlert", &parse_server_alert },
143     { "Protocol", &parse_protocol },
144 };
145
146
147 /*
148  * Since these methods are used to create tests, we use OPENSSL_assert liberally
149  * for malloc failures and other internal errors.
150  */
151 SSL_TEST_CTX *SSL_TEST_CTX_new()
152 {
153     SSL_TEST_CTX *ret;
154     ret = OPENSSL_zalloc(sizeof(*ret));
155     OPENSSL_assert(ret != NULL);
156     ret->expected_result = SSL_TEST_SUCCESS;
157     return ret;
158 }
159
160 void SSL_TEST_CTX_free(SSL_TEST_CTX *ctx)
161 {
162     OPENSSL_free(ctx);
163 }
164
165 SSL_TEST_CTX *SSL_TEST_CTX_create(const CONF *conf, const char *test_section)
166 {
167     STACK_OF(CONF_VALUE) *sk_conf;
168     SSL_TEST_CTX *ctx;
169     int i;
170     size_t j;
171
172     sk_conf = NCONF_get_section(conf, test_section);
173     OPENSSL_assert(sk_conf != NULL);
174
175     ctx = SSL_TEST_CTX_new();
176     OPENSSL_assert(ctx != NULL);
177
178     for (i = 0; i < sk_CONF_VALUE_num(sk_conf); i++) {
179         int found = 0;
180         const CONF_VALUE *option = sk_CONF_VALUE_value(sk_conf, i);
181         for (j = 0; j < OSSL_NELEM(ssl_test_ctx_options); j++) {
182             if (strcmp(option->name, ssl_test_ctx_options[j].name) == 0) {
183                 if (!ssl_test_ctx_options[j].parse(ctx, option->value)) {
184                     fprintf(stderr, "Bad value %s for option %s\n",
185                             option->value, option->name);
186                     goto err;
187                 }
188                 found = 1;
189                 break;
190             }
191         }
192         if (!found) {
193             fprintf(stderr, "Unknown test option: %s\n", option->name);
194             goto err;
195         }
196     }
197
198     goto done;
199
200  err:
201     SSL_TEST_CTX_free(ctx);
202     ctx = NULL;
203  done:
204     return ctx;
205 }