blob: 72be47eeab25562697ad2bf0a4f060f8d2ce1846 [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 Benjamin8f2c20e2014-07-09 09:30:38 -040025const char *expected_server_name = NULL;
26int early_callback_called = 0;
27
28int select_certificate_callback(const struct ssl_early_callback_ctx *ctx) {
29 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
67SSL *setup_test(int is_server) {
68 if (!SSL_library_init()) {
69 return NULL;
70 }
71
72 SSL_CTX *ssl_ctx = NULL;
73 SSL *ssl = NULL;
74 BIO *bio = NULL;
75
76 ssl_ctx = SSL_CTX_new(
77 is_server ? SSLv23_server_method() : SSLv23_client_method());
78 if (ssl_ctx == NULL) {
79 goto err;
80 }
81
82 if (!SSL_CTX_set_ecdh_auto(ssl_ctx, 1)) {
83 goto err;
84 }
85
86 if (!SSL_CTX_set_cipher_list(ssl_ctx, "ALL")) {
87 goto err;
88 }
89
David Benjamin8f2c20e2014-07-09 09:30:38 -040090 ssl_ctx->select_certificate_cb = select_certificate_callback;
91
David Benjamin025b3d32014-07-01 19:53:04 -040092 ssl = SSL_new(ssl_ctx);
93 if (ssl == NULL) {
94 goto err;
95 }
96
97 bio = BIO_new_fd(3, 1 /* take ownership */);
98 if (bio == NULL) {
99 goto err;
100 }
101
102 SSL_set_bio(ssl, bio, bio);
103 SSL_CTX_free(ssl_ctx);
104
105 return ssl;
106
107err:
108 if (bio != NULL) {
109 BIO_free(bio);
110 }
111 if (ssl != NULL) {
112 SSL_free(ssl);
113 }
114 if (ssl_ctx != NULL) {
115 SSL_CTX_free(ssl_ctx);
116 }
117 return NULL;
118}
119
120int main(int argc, char **argv) {
121 int i, is_server, ret;
David Benjamin7b030512014-07-08 17:30:11 -0400122 const char *expected_certificate_types = NULL;
David Benjamin025b3d32014-07-01 19:53:04 -0400123
124 if (argc < 2) {
125 fprintf(stderr, "Usage: %s (client|server) [flags...]\n", argv[0]);
126 return 1;
127 }
128 if (strcmp(argv[1], "client") == 0) {
129 is_server = 0;
130 } else if (strcmp(argv[1], "server") == 0) {
131 is_server = 1;
132 } else {
133 fprintf(stderr, "Usage: %s (client|server) [flags...]\n", argv[0]);
134 return 1;
135 }
136
137 SSL *ssl = setup_test(is_server);
138 if (ssl == NULL) {
139 BIO_print_errors_fp(stdout);
140 return 1;
141 }
142
143 for (i = 2; i < argc; i++) {
144 if (strcmp(argv[i], "-fallback-scsv") == 0) {
145 if (!SSL_enable_fallback_scsv(ssl)) {
146 BIO_print_errors_fp(stdout);
147 return 1;
148 }
149 } else if (strcmp(argv[i], "-key-file") == 0) {
150 i++;
151 if (i >= argc) {
152 fprintf(stderr, "Missing parameter\n");
153 return 1;
154 }
155 if (!SSL_use_PrivateKey_file(ssl, argv[i], SSL_FILETYPE_PEM)) {
156 BIO_print_errors_fp(stdout);
157 return 1;
158 }
159 } else if (strcmp(argv[i], "-cert-file") == 0) {
160 i++;
161 if (i >= argc) {
162 fprintf(stderr, "Missing parameter\n");
163 return 1;
164 }
165 if (!SSL_use_certificate_file(ssl, argv[i], SSL_FILETYPE_PEM)) {
166 BIO_print_errors_fp(stdout);
167 return 1;
168 }
David Benjamin197b3ab2014-07-02 18:37:33 -0400169 } else if (strcmp(argv[i], "-expect-server-name") == 0) {
170 i++;
171 if (i >= argc) {
172 fprintf(stderr, "Missing parameter\n");
173 return 1;
174 }
175 expected_server_name = argv[i];
David Benjamin7b030512014-07-08 17:30:11 -0400176 } else if (strcmp(argv[i], "-expect-certificate-types") == 0) {
177 i++;
178 if (i >= argc) {
179 fprintf(stderr, "Missing parameter\n");
180 return 1;
181 }
182 // Conveniently, 00 is not a certificate type.
183 expected_certificate_types = argv[i];
David Benjamin025b3d32014-07-01 19:53:04 -0400184 } else {
185 fprintf(stderr, "Unknown argument: %s\n", argv[i]);
186 return 1;
187 }
188 }
189
190 if (is_server) {
191 ret = SSL_accept(ssl);
192 } else {
193 ret = SSL_connect(ssl);
194 }
195 if (ret != 1) {
196 SSL_free(ssl);
197 BIO_print_errors_fp(stdout);
198 return 2;
199 }
200
David Benjamin197b3ab2014-07-02 18:37:33 -0400201 if (expected_server_name) {
202 const char *server_name =
203 SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
204 if (strcmp(server_name, expected_server_name) != 0) {
205 fprintf(stderr, "servername mismatch (got %s; want %s)\n",
206 server_name, expected_server_name);
207 return 2;
208 }
David Benjamin8f2c20e2014-07-09 09:30:38 -0400209
210 if (!early_callback_called) {
211 fprintf(stderr, "early callback not called\n");
212 return 2;
213 }
David Benjamin197b3ab2014-07-02 18:37:33 -0400214 }
215
David Benjamin7b030512014-07-08 17:30:11 -0400216 if (expected_certificate_types) {
217 uint8_t *certificate_types;
218 int num_certificate_types =
219 SSL_get0_certificate_types(ssl, &certificate_types);
220 if (num_certificate_types != (int)strlen(expected_certificate_types) ||
221 memcmp(certificate_types,
222 expected_certificate_types,
223 num_certificate_types) != 0) {
224 fprintf(stderr, "certificate types mismatch\n");
225 return 2;
226 }
227 }
228
David Benjamin025b3d32014-07-01 19:53:04 -0400229 for (;;) {
230 uint8_t buf[512];
231 int n = SSL_read(ssl, buf, sizeof(buf));
232 if (n < 0) {
233 SSL_free(ssl);
234 BIO_print_errors_fp(stdout);
235 return 3;
236 } else if (n == 0) {
237 break;
238 } else {
239 for (int i = 0; i < n; i++) {
240 buf[i] ^= 0xff;
241 }
242 int w = SSL_write(ssl, buf, n);
243 if (w != n) {
244 SSL_free(ssl);
245 BIO_print_errors_fp(stdout);
246 return 4;
247 }
248 }
249 }
250
251 SSL_free(ssl);
252 return 0;
253}