blob: 8f4cbf8f99efec480610c95876ad948a42929221 [file] [log] [blame]
David Benjamin025b3d32014-07-01 19:53:04 -04001/* Copyright (c) 2014, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#include <sys/types.h>
16#include <sys/socket.h>
17#include <netinet/in.h>
18#include <arpa/inet.h>
David Benjamin8f2c20e2014-07-09 09:30:38 -040019#include <unistd.h>
David Benjamin025b3d32014-07-01 19:53:04 -040020
21#include <openssl/ssl.h>
22#include <openssl/bio.h>
David Benjamin8f2c20e2014-07-09 09:30:38 -040023#include <openssl/bytestring.h>
David Benjamin025b3d32014-07-01 19:53:04 -040024
David Benjamin1f5f62b2014-07-12 16:18:02 -040025static const char *expected_server_name = NULL;
26static int early_callback_called = 0;
David Benjamin8f2c20e2014-07-09 09:30:38 -040027
David Benjamin1f5f62b2014-07-12 16:18:02 -040028static int select_certificate_callback(const struct ssl_early_callback_ctx *ctx) {
David Benjamin8f2c20e2014-07-09 09:30:38 -040029 early_callback_called = 1;
30
David Benjamin7b030512014-07-08 17:30:11 -040031 if (!expected_server_name) {
32 return 1;
33 }
David Benjamin8f2c20e2014-07-09 09:30:38 -040034
David Benjamin7b030512014-07-08 17:30:11 -040035 const uint8_t *extension_data;
36 size_t extension_len;
37 CBS extension, server_name_list, host_name;
38 uint8_t name_type;
David Benjamin8f2c20e2014-07-09 09:30:38 -040039
David Benjamin7b030512014-07-08 17:30:11 -040040 if (!SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_server_name,
41 &extension_data,
42 &extension_len)) {
43 fprintf(stderr, "Could not find server_name extension.\n");
44 return -1;
45 }
David Benjamin8f2c20e2014-07-09 09:30:38 -040046
David Benjamin7b030512014-07-08 17:30:11 -040047 CBS_init(&extension, extension_data, extension_len);
48 if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) ||
49 CBS_len(&extension) != 0 ||
50 !CBS_get_u8(&server_name_list, &name_type) ||
51 name_type != TLSEXT_NAMETYPE_host_name ||
52 !CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
53 CBS_len(&server_name_list) != 0) {
54 fprintf(stderr, "Could not decode server_name extension.\n");
55 return -1;
56 }
57
58 if (CBS_len(&host_name) != strlen(expected_server_name) ||
59 memcmp(expected_server_name,
60 CBS_data(&host_name), CBS_len(&host_name)) != 0) {
61 fprintf(stderr, "Server name mismatch.\n");
David Benjamin8f2c20e2014-07-09 09:30:38 -040062 }
63
64 return 1;
65}
David Benjamin025b3d32014-07-01 19:53:04 -040066
David Benjamin1f5f62b2014-07-12 16:18:02 -040067static int skip_verify(int preverify_ok, X509_STORE_CTX *store_ctx) {
David Benjamin67666e72014-07-12 15:47:52 -040068 return 1;
69}
70
David Benjamin1f5f62b2014-07-12 16:18:02 -040071static const char *advertise_npn = NULL;
72
73static int next_protos_advertised_callback(SSL *ssl,
74 const uint8_t **out,
75 unsigned int *out_len,
76 void *arg) {
77 if (!advertise_npn)
78 return SSL_TLSEXT_ERR_NOACK;
79
80 // TODO(davidben): Support passing byte strings with NULs to the
81 // test shim.
82 *out = (const uint8_t*)advertise_npn;
83 *out_len = strlen(advertise_npn);
84 return SSL_TLSEXT_ERR_OK;
85}
86
87static SSL *setup_test(int is_server) {
David Benjamin025b3d32014-07-01 19:53:04 -040088 if (!SSL_library_init()) {
89 return NULL;
90 }
91
92 SSL_CTX *ssl_ctx = NULL;
93 SSL *ssl = NULL;
94 BIO *bio = NULL;
95
96 ssl_ctx = SSL_CTX_new(
97 is_server ? SSLv23_server_method() : SSLv23_client_method());
98 if (ssl_ctx == NULL) {
99 goto err;
100 }
101
102 if (!SSL_CTX_set_ecdh_auto(ssl_ctx, 1)) {
103 goto err;
104 }
105
106 if (!SSL_CTX_set_cipher_list(ssl_ctx, "ALL")) {
107 goto err;
108 }
109
David Benjamin8f2c20e2014-07-09 09:30:38 -0400110 ssl_ctx->select_certificate_cb = select_certificate_callback;
111
David Benjamin1f5f62b2014-07-12 16:18:02 -0400112 SSL_CTX_set_next_protos_advertised_cb(
113 ssl_ctx, next_protos_advertised_callback, NULL);
114
David Benjamin025b3d32014-07-01 19:53:04 -0400115 ssl = SSL_new(ssl_ctx);
116 if (ssl == NULL) {
117 goto err;
118 }
119
120 bio = BIO_new_fd(3, 1 /* take ownership */);
121 if (bio == NULL) {
122 goto err;
123 }
124
125 SSL_set_bio(ssl, bio, bio);
126 SSL_CTX_free(ssl_ctx);
127
128 return ssl;
129
130err:
131 if (bio != NULL) {
132 BIO_free(bio);
133 }
134 if (ssl != NULL) {
135 SSL_free(ssl);
136 }
137 if (ssl_ctx != NULL) {
138 SSL_CTX_free(ssl_ctx);
139 }
140 return NULL;
141}
142
143int main(int argc, char **argv) {
144 int i, is_server, ret;
David Benjamin7b030512014-07-08 17:30:11 -0400145 const char *expected_certificate_types = NULL;
David Benjamin1f5f62b2014-07-12 16:18:02 -0400146 const char *expected_next_proto = NULL;
David Benjamin025b3d32014-07-01 19:53:04 -0400147
148 if (argc < 2) {
149 fprintf(stderr, "Usage: %s (client|server) [flags...]\n", argv[0]);
150 return 1;
151 }
152 if (strcmp(argv[1], "client") == 0) {
153 is_server = 0;
154 } else if (strcmp(argv[1], "server") == 0) {
155 is_server = 1;
156 } else {
157 fprintf(stderr, "Usage: %s (client|server) [flags...]\n", argv[0]);
158 return 1;
159 }
160
161 SSL *ssl = setup_test(is_server);
162 if (ssl == NULL) {
163 BIO_print_errors_fp(stdout);
164 return 1;
165 }
166
167 for (i = 2; i < argc; i++) {
168 if (strcmp(argv[i], "-fallback-scsv") == 0) {
169 if (!SSL_enable_fallback_scsv(ssl)) {
170 BIO_print_errors_fp(stdout);
171 return 1;
172 }
173 } else if (strcmp(argv[i], "-key-file") == 0) {
174 i++;
175 if (i >= argc) {
176 fprintf(stderr, "Missing parameter\n");
177 return 1;
178 }
179 if (!SSL_use_PrivateKey_file(ssl, argv[i], SSL_FILETYPE_PEM)) {
180 BIO_print_errors_fp(stdout);
181 return 1;
182 }
183 } else if (strcmp(argv[i], "-cert-file") == 0) {
184 i++;
185 if (i >= argc) {
186 fprintf(stderr, "Missing parameter\n");
187 return 1;
188 }
189 if (!SSL_use_certificate_file(ssl, argv[i], SSL_FILETYPE_PEM)) {
190 BIO_print_errors_fp(stdout);
191 return 1;
192 }
David Benjamin197b3ab2014-07-02 18:37:33 -0400193 } else if (strcmp(argv[i], "-expect-server-name") == 0) {
194 i++;
195 if (i >= argc) {
196 fprintf(stderr, "Missing parameter\n");
197 return 1;
198 }
199 expected_server_name = argv[i];
David Benjamin7b030512014-07-08 17:30:11 -0400200 } else if (strcmp(argv[i], "-expect-certificate-types") == 0) {
201 i++;
202 if (i >= argc) {
203 fprintf(stderr, "Missing parameter\n");
204 return 1;
205 }
206 // Conveniently, 00 is not a certificate type.
207 expected_certificate_types = argv[i];
David Benjamin67666e72014-07-12 15:47:52 -0400208 } else if (strcmp(argv[i], "-require-any-client-certificate") == 0) {
209 SSL_set_verify(ssl, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
210 skip_verify);
David Benjamin1f5f62b2014-07-12 16:18:02 -0400211 } else if (strcmp(argv[i], "-advertise-npn") == 0) {
212 i++;
213 if (i >= argc) {
214 fprintf(stderr, "Missing parameter\n");
215 return 1;
216 }
217 advertise_npn = argv[i];
218 } else if (strcmp(argv[i], "-expect-next-proto") == 0) {
219 i++;
220 if (i >= argc) {
221 fprintf(stderr, "Missing parameter\n");
222 return 1;
223 }
224 expected_next_proto = argv[i];
David Benjamin025b3d32014-07-01 19:53:04 -0400225 } else {
226 fprintf(stderr, "Unknown argument: %s\n", argv[i]);
227 return 1;
228 }
229 }
230
231 if (is_server) {
232 ret = SSL_accept(ssl);
233 } else {
234 ret = SSL_connect(ssl);
235 }
236 if (ret != 1) {
237 SSL_free(ssl);
238 BIO_print_errors_fp(stdout);
239 return 2;
240 }
241
David Benjamin197b3ab2014-07-02 18:37:33 -0400242 if (expected_server_name) {
243 const char *server_name =
244 SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
245 if (strcmp(server_name, expected_server_name) != 0) {
246 fprintf(stderr, "servername mismatch (got %s; want %s)\n",
247 server_name, expected_server_name);
248 return 2;
249 }
David Benjamin8f2c20e2014-07-09 09:30:38 -0400250
251 if (!early_callback_called) {
252 fprintf(stderr, "early callback not called\n");
253 return 2;
254 }
David Benjamin197b3ab2014-07-02 18:37:33 -0400255 }
256
David Benjamin7b030512014-07-08 17:30:11 -0400257 if (expected_certificate_types) {
258 uint8_t *certificate_types;
259 int num_certificate_types =
260 SSL_get0_certificate_types(ssl, &certificate_types);
261 if (num_certificate_types != (int)strlen(expected_certificate_types) ||
262 memcmp(certificate_types,
263 expected_certificate_types,
264 num_certificate_types) != 0) {
265 fprintf(stderr, "certificate types mismatch\n");
266 return 2;
267 }
268 }
269
David Benjamin1f5f62b2014-07-12 16:18:02 -0400270 if (expected_next_proto) {
271 const uint8_t *next_proto;
272 unsigned next_proto_len;
273 SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
274 if (next_proto_len != strlen(expected_next_proto) ||
275 memcmp(next_proto, expected_next_proto, next_proto_len) != 0) {
276 fprintf(stderr, "negotiated next proto mismatch\n");
277 return 2;
278 }
279 }
280
David Benjamin025b3d32014-07-01 19:53:04 -0400281 for (;;) {
282 uint8_t buf[512];
283 int n = SSL_read(ssl, buf, sizeof(buf));
284 if (n < 0) {
285 SSL_free(ssl);
286 BIO_print_errors_fp(stdout);
287 return 3;
288 } else if (n == 0) {
289 break;
290 } else {
291 for (int i = 0; i < n; i++) {
292 buf[i] ^= 0xff;
293 }
294 int w = SSL_write(ssl, buf, n);
295 if (w != n) {
296 SSL_free(ssl);
297 BIO_print_errors_fp(stdout);
298 return 4;
299 }
300 }
301 }
302
303 SSL_free(ssl);
304 return 0;
305}