blob: d0117da286504fd81a4f96b6af948ccb8e096f34 [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
31 if (expected_server_name) {
32 const unsigned char *extension_data;
33 size_t extension_len;
34 CBS extension, server_name_list, host_name;
35 uint8_t name_type;
36
37 if (!SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_server_name,
38 &extension_data,
39 &extension_len)) {
40 fprintf(stderr, "Could not find server_name extension.");
41 return -1;
42 }
43
44 CBS_init(&extension, extension_data, extension_len);
45 if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) ||
46 CBS_len(&extension) != 0 ||
47 !CBS_get_u8(&server_name_list, &name_type) ||
48 name_type != TLSEXT_NAMETYPE_host_name ||
49 !CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
50 CBS_len(&server_name_list) != 0) {
51 fprintf(stderr, "Could not decode server_name extension.");
52 return -1;
53 }
54
55 if (CBS_len(&host_name) != strlen(expected_server_name) ||
56 memcmp(expected_server_name,
57 CBS_data(&host_name), CBS_len(&host_name)) != 0) {
58 fprintf(stderr, "Server name mismatch.");
59 }
60 }
61
62 return 1;
63}
David Benjamin025b3d32014-07-01 19:53:04 -040064
65SSL *setup_test(int is_server) {
66 if (!SSL_library_init()) {
67 return NULL;
68 }
69
70 SSL_CTX *ssl_ctx = NULL;
71 SSL *ssl = NULL;
72 BIO *bio = NULL;
73
74 ssl_ctx = SSL_CTX_new(
75 is_server ? SSLv23_server_method() : SSLv23_client_method());
76 if (ssl_ctx == NULL) {
77 goto err;
78 }
79
80 if (!SSL_CTX_set_ecdh_auto(ssl_ctx, 1)) {
81 goto err;
82 }
83
84 if (!SSL_CTX_set_cipher_list(ssl_ctx, "ALL")) {
85 goto err;
86 }
87
David Benjamin8f2c20e2014-07-09 09:30:38 -040088 ssl_ctx->select_certificate_cb = select_certificate_callback;
89
David Benjamin025b3d32014-07-01 19:53:04 -040090 ssl = SSL_new(ssl_ctx);
91 if (ssl == NULL) {
92 goto err;
93 }
94
95 bio = BIO_new_fd(3, 1 /* take ownership */);
96 if (bio == NULL) {
97 goto err;
98 }
99
100 SSL_set_bio(ssl, bio, bio);
101 SSL_CTX_free(ssl_ctx);
102
103 return ssl;
104
105err:
106 if (bio != NULL) {
107 BIO_free(bio);
108 }
109 if (ssl != NULL) {
110 SSL_free(ssl);
111 }
112 if (ssl_ctx != NULL) {
113 SSL_CTX_free(ssl_ctx);
114 }
115 return NULL;
116}
117
118int main(int argc, char **argv) {
119 int i, is_server, ret;
120
121 if (argc < 2) {
122 fprintf(stderr, "Usage: %s (client|server) [flags...]\n", argv[0]);
123 return 1;
124 }
125 if (strcmp(argv[1], "client") == 0) {
126 is_server = 0;
127 } else if (strcmp(argv[1], "server") == 0) {
128 is_server = 1;
129 } else {
130 fprintf(stderr, "Usage: %s (client|server) [flags...]\n", argv[0]);
131 return 1;
132 }
133
134 SSL *ssl = setup_test(is_server);
135 if (ssl == NULL) {
136 BIO_print_errors_fp(stdout);
137 return 1;
138 }
139
140 for (i = 2; i < argc; i++) {
141 if (strcmp(argv[i], "-fallback-scsv") == 0) {
142 if (!SSL_enable_fallback_scsv(ssl)) {
143 BIO_print_errors_fp(stdout);
144 return 1;
145 }
146 } else if (strcmp(argv[i], "-key-file") == 0) {
147 i++;
148 if (i >= argc) {
149 fprintf(stderr, "Missing parameter\n");
150 return 1;
151 }
152 if (!SSL_use_PrivateKey_file(ssl, argv[i], SSL_FILETYPE_PEM)) {
153 BIO_print_errors_fp(stdout);
154 return 1;
155 }
156 } else if (strcmp(argv[i], "-cert-file") == 0) {
157 i++;
158 if (i >= argc) {
159 fprintf(stderr, "Missing parameter\n");
160 return 1;
161 }
162 if (!SSL_use_certificate_file(ssl, argv[i], SSL_FILETYPE_PEM)) {
163 BIO_print_errors_fp(stdout);
164 return 1;
165 }
David Benjamin197b3ab2014-07-02 18:37:33 -0400166 } else if (strcmp(argv[i], "-expect-server-name") == 0) {
167 i++;
168 if (i >= argc) {
169 fprintf(stderr, "Missing parameter\n");
170 return 1;
171 }
172 expected_server_name = argv[i];
David Benjamin025b3d32014-07-01 19:53:04 -0400173 } else {
174 fprintf(stderr, "Unknown argument: %s\n", argv[i]);
175 return 1;
176 }
177 }
178
179 if (is_server) {
180 ret = SSL_accept(ssl);
181 } else {
182 ret = SSL_connect(ssl);
183 }
184 if (ret != 1) {
185 SSL_free(ssl);
186 BIO_print_errors_fp(stdout);
187 return 2;
188 }
189
David Benjamin197b3ab2014-07-02 18:37:33 -0400190 if (expected_server_name) {
191 const char *server_name =
192 SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
193 if (strcmp(server_name, expected_server_name) != 0) {
194 fprintf(stderr, "servername mismatch (got %s; want %s)\n",
195 server_name, expected_server_name);
196 return 2;
197 }
David Benjamin8f2c20e2014-07-09 09:30:38 -0400198
199 if (!early_callback_called) {
200 fprintf(stderr, "early callback not called\n");
201 return 2;
202 }
David Benjamin197b3ab2014-07-02 18:37:33 -0400203 }
204
David Benjamin025b3d32014-07-01 19:53:04 -0400205 for (;;) {
206 uint8_t buf[512];
207 int n = SSL_read(ssl, buf, sizeof(buf));
208 if (n < 0) {
209 SSL_free(ssl);
210 BIO_print_errors_fp(stdout);
211 return 3;
212 } else if (n == 0) {
213 break;
214 } else {
215 for (int i = 0; i < n; i++) {
216 buf[i] ^= 0xff;
217 }
218 int w = SSL_write(ssl, buf, n);
219 if (w != n) {
220 SSL_free(ssl);
221 BIO_print_errors_fp(stdout);
222 return 4;
223 }
224 }
225 }
226
227 SSL_free(ssl);
228 return 0;
229}