xref: /openbsd/regress/lib/libssl/verify/verify.c (revision 5a38ef86)
1 /*	$OpenBSD: verify.c,v 1.1.1.1 2021/08/30 17:27:45 tb Exp $ */
2 /*
3  * Copyright (c) 2021 Theo Buehler <tb@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /* Based on https://github.com/noxxi/libressl-tests */
19 
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include <openssl/bio.h>
26 #include <openssl/crypto.h>
27 #include <openssl/err.h>
28 #include <openssl/x509_vfy.h>
29 #include <openssl/ssl.h>
30 
31 struct peer_config {
32 	const char *name;
33 	int server;
34 	const char *cert;
35 	const char *key;
36 	const char *ca_file;
37 };
38 
39 struct ssl_wildcard_test_data {
40 	const char *description;
41 	struct peer_config client_config;
42 	struct peer_config server_config;
43 	long verify_result;
44 };
45 
46 static const struct ssl_wildcard_test_data ssl_wildcard_tests[] = {
47 	{
48 		.description = "unusual wildcard cert, no CA given to client",
49 		.client_config = {
50 			.name = "client",
51 			.server = 0,
52 			.cert = NULL,
53 			.ca_file = NULL,
54 		},
55 		.server_config = {
56 			.name = "server",
57 			.server = 1,
58 			.cert = "server-unusual-wildcard.pem",
59 			.key = "server-unusual-wildcard.pem",
60 		},
61 		/* OpenSSL returns X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE */
62 		.verify_result = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
63 	},
64 
65 	{
66 		.description = "unusual wildcard cert, CA given to client",
67 		.client_config = {
68 			.name = "client",
69 			.server = 0,
70 			.cert = NULL,
71 			.ca_file = "caR.pem",
72 		},
73 		.server_config = {
74 			.name = "server",
75 			.server = 1,
76 			.cert = "server-unusual-wildcard.pem",
77 			.key = "server-unusual-wildcard.pem",
78 		},
79 		.verify_result = X509_V_OK,
80 	},
81 
82 	{
83 		.description = "common wildcard cert, no CA given to client",
84 		.client_config = {
85 			.name = "client",
86 			.server = 0,
87 			.cert = NULL,
88 			.ca_file = NULL,
89 		},
90 		.server_config = {
91 			.name = "server",
92 			.server = 1,
93 			.cert = "server-common-wildcard.pem",
94 			.key = "server-common-wildcard.pem",
95 		},
96 		/* OpenSSL returns X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE */
97 		.verify_result = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
98 	},
99 
100 	{
101 		.description = "common wildcard cert, CA given to client",
102 		.client_config = {
103 			.name = "client",
104 			.server = 0,
105 			.cert = NULL,
106 			.ca_file = "caR.pem",
107 		},
108 		.server_config = {
109 			.name = "server",
110 			.server = 1,
111 			.cert = "server-common-wildcard.pem",
112 			.key = "server-common-wildcard.pem",
113 		},
114 		.verify_result = X509_V_OK,
115 	},
116 
117 	{
118 		.description = "server sends all chain certificates",
119 		.client_config = {
120 			.name = "client",
121 			.server = 0,
122 			.cert = NULL,
123 			.ca_file = "caR.pem",
124 		},
125 		.server_config = {
126 			.name = "server",
127 			.server = 1,
128 			.cert = "server-subca-chainS.pem",
129 			.key = "server-subca-chainS.pem",
130 			.ca_file = "subcaR.pem"
131 		},
132 		.verify_result = X509_V_OK,
133 	},
134 };
135 
136 static const size_t N_SSL_WILDCARD_TESTS =
137     sizeof(ssl_wildcard_tests) / sizeof(ssl_wildcard_tests[0]);
138 
139 static SSL_CTX *
140 peer_config_to_ssl_ctx(const struct peer_config *config)
141 {
142 	SSL_CTX *ctx;
143 
144 	if ((ctx = SSL_CTX_new(TLS_method())) == NULL) {
145 		fprintf(stderr, "SSL_CTX_new(%s) failed\n", config->name);
146 		goto err;
147 	}
148 
149 	if (config->server) {
150 		if (!SSL_CTX_use_certificate_file(ctx, config->cert,
151 		    SSL_FILETYPE_PEM)) {
152 			fprintf(stderr, "use_certificate_file(%s) failed\n",
153 			    config->name);
154 			goto err;
155 		}
156 		if (config->key != NULL && !SSL_CTX_use_PrivateKey_file(ctx,
157 		    config->key, SSL_FILETYPE_PEM)) {
158 			fprintf(stderr, "use_PrivateKey_file(%s) failed\n",
159 			    config->name);
160 			goto err;
161 		}
162 	}
163 
164 	if (config->ca_file != NULL) {
165 		if (!SSL_CTX_load_verify_locations(ctx, config->ca_file, NULL)) {
166 			fprintf(stderr, "load_verify_locations(%s) failed\n",
167 			    config->name);
168 			goto err;
169 		}
170 	}
171 
172 	return ctx;
173 
174  err:
175 	SSL_CTX_free(ctx);
176 	return NULL;
177 }
178 
179 /* Connect client and server via a pair of "nonblocking" memory BIOs. */
180 static int
181 connect_peers(SSL *client_ssl, SSL *server_ssl, const char *description)
182 {
183 	BIO *client_wbio = NULL, *server_wbio = NULL;
184 	int ret = 0;
185 
186 	if ((client_wbio = BIO_new(BIO_s_mem())) == NULL) {
187 		fprintf(stderr, "%s: failed to create client BIO\n",
188 		    description);
189 		goto err;
190 	}
191 	if ((server_wbio = BIO_new(BIO_s_mem())) == NULL) {
192 		fprintf(stderr, "%s: failed to create server BIO\n",
193 		    description);
194 		goto err;
195 	}
196 	if (BIO_set_mem_eof_return(client_wbio, -1) <= 0) {
197 		fprintf(stderr, "%s: failed to set client eof return\n",
198 		    description);
199 		goto err;
200 	}
201 	if (BIO_set_mem_eof_return(server_wbio, -1) <= 0) {
202 		fprintf(stderr, "%s: failed to set server eof return\n",
203 		    description);
204 		goto err;
205 	}
206 
207 	/* Avoid double free. SSL_set_bio() takes ownership of the BIOs. */
208 	BIO_up_ref(client_wbio);
209 	BIO_up_ref(server_wbio);
210 
211 	SSL_set_bio(client_ssl, server_wbio, client_wbio);
212 	SSL_set_bio(server_ssl, client_wbio, server_wbio);
213 	client_wbio = NULL;
214 	server_wbio = NULL;
215 
216 	ret = 1;
217 
218  err:
219 	BIO_free(client_wbio);
220 	BIO_free(server_wbio);
221 
222 	return ret;
223 }
224 
225 static int
226 push_data_to_peer(SSL *ssl, int *ret, int (*func)(SSL *), const char *func_name,
227     const char *description)
228 {
229 	int ssl_err = 0;
230 
231 	if (*ret == 1)
232 		return 1;
233 
234 	/*
235 	 * Do SSL_connect/SSL_accept/SSL_shutdown once and loop while hitting
236 	 * WANT_WRITE.  If done or on WANT_READ hand off to peer.
237 	 */
238 
239 	do {
240 		if ((*ret = func(ssl)) <= 0)
241 			ssl_err = SSL_get_error(ssl, *ret);
242 	} while (*ret <= 0 && ssl_err == SSL_ERROR_WANT_WRITE);
243 
244 	/* Ignore erroneous error - see SSL_shutdown(3)... */
245 	if (func == SSL_shutdown && ssl_err == SSL_ERROR_SYSCALL)
246 		return 1;
247 
248 	if (*ret <= 0 && ssl_err != SSL_ERROR_WANT_READ) {
249 		fprintf(stderr, "%s: %s failed\n", description, func_name);
250 		ERR_print_errors_fp(stderr);
251 		return 0;
252 	}
253 
254 	return 1;
255 }
256 
257 /*
258  * Alternate between loops of SSL_connect() and SSL_accept() as long as only
259  * WANT_READ and WANT_WRITE situations are encountered. A function is repeated
260  * until WANT_READ is returned or it succeeds, then it's the other function's
261  * turn to make progress. Succeeds if SSL_connect() and SSL_accept() return 1.
262  */
263 static int
264 handshake(SSL *client_ssl, SSL *server_ssl, const char *description)
265 {
266 	int loops = 0, client_ret = 0, server_ret = 0;
267 
268 	while (loops++ < 10 && (client_ret <= 0 || server_ret <= 0)) {
269 		if (!push_data_to_peer(client_ssl, &client_ret, SSL_connect,
270 		    "SSL_connect", description))
271 			return 0;
272 
273 		if (!push_data_to_peer(server_ssl, &server_ret, SSL_accept,
274 		    "SSL_accept", description))
275 			return 0;
276 	}
277 
278 	if (client_ret != 1 || server_ret != 1) {
279 		fprintf(stderr, "%s: failed\n", __func__);
280 		return 0;
281 	}
282 
283 	return 1;
284 }
285 
286 static int
287 shutdown_peers(SSL *client_ssl, SSL *server_ssl, const char *description)
288 {
289 	int loops = 0, client_ret = 0, server_ret = 0;
290 
291 	while (loops++ < 10 && (client_ret <= 0 || server_ret <= 0)) {
292 		if (!push_data_to_peer(client_ssl, &client_ret, SSL_shutdown,
293 		    "client shutdown", description))
294 			return 0;
295 
296 		if (!push_data_to_peer(server_ssl, &server_ret, SSL_shutdown,
297 		    "server shutdown", description))
298 			return 0;
299 	}
300 
301 	if (client_ret != 1 || server_ret != 1) {
302 		fprintf(stderr, "%s: failed\n", __func__);
303 		return 0;
304 	}
305 
306 	return 1;
307 }
308 
309 static int
310 test_ssl_wildcards(const struct ssl_wildcard_test_data *test)
311 {
312 	SSL_CTX *client_ctx = NULL, *server_ctx = NULL;
313 	SSL *client_ssl = NULL, *server_ssl = NULL;
314 	long verify_result;
315 	int failed = 1;
316 
317 	if ((client_ctx = peer_config_to_ssl_ctx(&test->client_config)) == NULL)
318 		goto err;
319 	if ((server_ctx = peer_config_to_ssl_ctx(&test->server_config)) == NULL)
320 		goto err;
321 
322 	if ((client_ssl = SSL_new(client_ctx)) == NULL) {
323 		fprintf(stderr, "%s: failed to create client SSL\n",
324 		    test->description);
325 		goto err;
326 	}
327 	if ((server_ssl = SSL_new(server_ctx)) == NULL) {
328 		fprintf(stderr, "%s: failed to create server SSL\n",
329 		    test->description);
330 		goto err;
331 	}
332 
333 	if (!connect_peers(client_ssl, server_ssl, test->description))
334 		goto err;
335 
336 	if (!handshake(client_ssl, server_ssl, test->description))
337 		goto err;
338 
339 	verify_result = SSL_get_verify_result(client_ssl);
340 
341 	if (test->verify_result == verify_result) {
342 		failed = 0;
343 		fprintf(stderr, "%s: ok\n", test->description);
344 	} else
345 		fprintf(stderr, "%s: verify_result: want %ld, got %ld\n",
346 		    test->description, test->verify_result, verify_result);
347 
348 	if (!shutdown_peers(client_ssl, server_ssl, test->description))
349 		goto err;
350 
351  err:
352 	SSL_CTX_free(client_ctx);
353 	SSL_CTX_free(server_ctx);
354 	SSL_free(client_ssl);
355 	SSL_free(server_ssl);
356 
357 	return failed;
358 }
359 
360 int
361 main(int argc, char **argv)
362 {
363 	size_t i;
364 	int failed = 0;
365 
366 	for (i = 0; i < N_SSL_WILDCARD_TESTS; i++)
367 		failed |= test_ssl_wildcards(&ssl_wildcard_tests[i]);
368 
369 	if (failed == 0)
370 		printf("PASS %s\n", __FILE__);
371 
372 	return failed;
373 }
374