summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjsing <>2022-01-05 09:59:39 +0000
committerjsing <>2022-01-05 09:59:39 +0000
commitefadcc5dd38b1eb8cc4d27a109eb179dbe38502d (patch)
treeb51d84957dee135214613b5328ddbc210a6eab16
parentb558c595e5afb498ed15f1643ba71fa9a3923b45 (diff)
downloadopenbsd-efadcc5dd38b1eb8cc4d27a109eb179dbe38502d.tar.gz
openbsd-efadcc5dd38b1eb8cc4d27a109eb179dbe38502d.tar.bz2
openbsd-efadcc5dd38b1eb8cc4d27a109eb179dbe38502d.zip
Provide regress for SSL public APIs.
This will largely test curly and inconsistent APIs that are not covered by other regress tests. Currently, this tests the wonder that is SSL_get_peer_cert_chain().
Diffstat (limited to '')
-rw-r--r--src/regress/lib/libssl/Makefile3
-rw-r--r--src/regress/lib/libssl/api/Makefile16
-rw-r--r--src/regress/lib/libssl/api/apitest.c369
3 files changed, 387 insertions, 1 deletions
diff --git a/src/regress/lib/libssl/Makefile b/src/regress/lib/libssl/Makefile
index ff06e0b0ba..1b852968f2 100644
--- a/src/regress/lib/libssl/Makefile
+++ b/src/regress/lib/libssl/Makefile
@@ -1,5 +1,6 @@
1# $OpenBSD: Makefile,v 1.47 2021/10/23 14:34:10 jsing Exp $ 1# $OpenBSD: Makefile,v 1.48 2022/01/05 09:59:39 jsing Exp $
2 2
3SUBDIR += api
3SUBDIR += asn1 4SUBDIR += asn1
4SUBDIR += buffer 5SUBDIR += buffer
5SUBDIR += bytestring 6SUBDIR += bytestring
diff --git a/src/regress/lib/libssl/api/Makefile b/src/regress/lib/libssl/api/Makefile
new file mode 100644
index 0000000000..0989fc2264
--- /dev/null
+++ b/src/regress/lib/libssl/api/Makefile
@@ -0,0 +1,16 @@
1# $OpenBSD: Makefile,v 1.1 2022/01/05 09:59:39 jsing Exp $
2
3PROG= apitest
4LDADD= -lssl -lcrypto
5DPADD= ${LIBSSL} ${LIBCRYPTO}
6WARNINGS= Yes
7CFLAGS+= -DLIBRESSL_INTERNAL -Werror
8
9REGRESS_TARGETS= \
10 regress-apitest
11
12regress-apitest: ${PROG}
13 ./apitest \
14 ${.CURDIR}/../../libssl/certs
15
16.include <bsd.regress.mk>
diff --git a/src/regress/lib/libssl/api/apitest.c b/src/regress/lib/libssl/api/apitest.c
new file mode 100644
index 0000000000..b5a5c544e2
--- /dev/null
+++ b/src/regress/lib/libssl/api/apitest.c
@@ -0,0 +1,369 @@
1/* $OpenBSD: apitest.c,v 1.1 2022/01/05 09:59:39 jsing Exp $ */
2/*
3 * Copyright (c) 2020, 2021 Joel Sing <jsing@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#include <err.h>
19
20#include <openssl/bio.h>
21#include <openssl/err.h>
22#include <openssl/ssl.h>
23
24const char *certs_path;
25
26int debug = 0;
27
28static int
29ssl_ctx_use_ca_file(SSL_CTX *ssl_ctx, const char *ca_file)
30{
31 char *ca_path = NULL;
32 int ret = 0;
33
34 if (asprintf(&ca_path, "%s/%s", certs_path, ca_file) == -1)
35 goto err;
36 if (!SSL_CTX_load_verify_locations(ssl_ctx, ca_path, NULL)) {
37 fprintf(stderr, "load_verify_locations(%s) failed\n", ca_path);
38 goto err;
39 }
40
41 ret = 1;
42
43 err:
44 free(ca_path);
45
46 return ret;
47}
48
49static int
50ssl_ctx_use_keypair(SSL_CTX *ssl_ctx, const char *chain_file,
51 const char *key_file)
52{
53 char *chain_path = NULL, *key_path = NULL;
54 int ret = 0;
55
56 if (asprintf(&chain_path, "%s/%s", certs_path, chain_file) == -1)
57 goto err;
58 if (SSL_CTX_use_certificate_chain_file(ssl_ctx, chain_path) != 1) {
59 fprintf(stderr, "FAIL: Failed to load certificates\n");
60 goto err;
61 }
62 if (asprintf(&key_path, "%s/%s", certs_path, key_file) == -1)
63 goto err;
64 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_path,
65 SSL_FILETYPE_PEM) != 1) {
66 fprintf(stderr, "FAIL: Failed to load private key\n");
67 goto err;
68 }
69
70 ret = 1;
71
72 err:
73 free(chain_path);
74 free(key_path);
75
76 return ret;
77}
78
79static SSL *
80tls_client(BIO *rbio, BIO *wbio)
81{
82 SSL_CTX *ssl_ctx = NULL;
83 SSL *ssl = NULL;
84
85 if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL)
86 errx(1, "client context");
87
88 SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
89
90 if (!ssl_ctx_use_ca_file(ssl_ctx, "ca-root-rsa.pem"))
91 goto failure;
92 if (!ssl_ctx_use_keypair(ssl_ctx, "client1-rsa-chain.pem",
93 "client1-rsa.pem"))
94 goto failure;
95
96 if ((ssl = SSL_new(ssl_ctx)) == NULL)
97 errx(1, "client ssl");
98
99 BIO_up_ref(rbio);
100 BIO_up_ref(wbio);
101
102 SSL_set_bio(ssl, rbio, wbio);
103
104 failure:
105 SSL_CTX_free(ssl_ctx);
106
107 return ssl;
108}
109
110static SSL *
111tls_server(BIO *rbio, BIO *wbio)
112{
113 SSL_CTX *ssl_ctx = NULL;
114 SSL *ssl = NULL;
115
116 if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL)
117 errx(1, "server context");
118
119 SSL_CTX_set_dh_auto(ssl_ctx, 2);
120
121 SSL_CTX_set_verify(ssl_ctx,
122 SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
123
124 if (!ssl_ctx_use_ca_file(ssl_ctx, "ca-root-rsa.pem"))
125 goto failure;
126 if (!ssl_ctx_use_keypair(ssl_ctx, "server1-rsa-chain.pem",
127 "server1-rsa.pem"))
128 goto failure;
129
130 if ((ssl = SSL_new(ssl_ctx)) == NULL)
131 errx(1, "server ssl");
132
133 BIO_up_ref(rbio);
134 BIO_up_ref(wbio);
135
136 SSL_set_bio(ssl, rbio, wbio);
137
138 failure:
139 SSL_CTX_free(ssl_ctx);
140
141 return ssl;
142}
143
144static int
145ssl_error(SSL *ssl, const char *name, const char *desc, int ssl_ret)
146{
147 int ssl_err;
148
149 ssl_err = SSL_get_error(ssl, ssl_ret);
150
151 if (ssl_err == SSL_ERROR_WANT_READ) {
152 return 1;
153 } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
154 return 1;
155 } else if (ssl_err == SSL_ERROR_SYSCALL && errno == 0) {
156 /* Yup, this is apparently a thing... */
157 } else {
158 fprintf(stderr, "FAIL: %s %s failed - ssl err = %d, errno = %d\n",
159 name, desc, ssl_err, errno);
160 ERR_print_errors_fp(stderr);
161 return 0;
162 }
163
164 return 1;
165}
166
167static int
168do_connect(SSL *ssl, const char *name, int *done)
169{
170 int ssl_ret;
171
172 if ((ssl_ret = SSL_connect(ssl)) == 1) {
173 fprintf(stderr, "INFO: %s connect done\n", name);
174 *done = 1;
175 return 1;
176 }
177
178 return ssl_error(ssl, name, "connect", ssl_ret);
179}
180
181static int
182do_accept(SSL *ssl, const char *name, int *done)
183{
184 int ssl_ret;
185
186 if ((ssl_ret = SSL_accept(ssl)) == 1) {
187 fprintf(stderr, "INFO: %s accept done\n", name);
188 *done = 1;
189 return 1;
190 }
191
192 return ssl_error(ssl, name, "accept", ssl_ret);
193}
194
195typedef int (*ssl_func)(SSL *ssl, const char *name, int *done);
196
197static int
198do_client_server_loop(SSL *client, ssl_func client_func, SSL *server,
199 ssl_func server_func)
200{
201 int client_done = 0, server_done = 0;
202 int i = 0;
203
204 do {
205 if (!client_done) {
206 if (debug)
207 fprintf(stderr, "DEBUG: client loop\n");
208 if (!client_func(client, "client", &client_done))
209 return 0;
210 }
211 if (!server_done) {
212 if (debug)
213 fprintf(stderr, "DEBUG: server loop\n");
214 if (!server_func(server, "server", &server_done))
215 return 0;
216 }
217 } while (i++ < 100 && (!client_done || !server_done));
218
219 if (!client_done || !server_done)
220 fprintf(stderr, "FAIL: gave up\n");
221
222 return client_done && server_done;
223}
224
225static int
226ssl_get_peer_cert_chain_test(uint16_t tls_version)
227{
228 STACK_OF(X509) *peer_chain;
229 X509 *peer_cert;
230 BIO *client_wbio = NULL, *server_wbio = NULL;
231 SSL *client = NULL, *server = NULL;
232 int failed = 1;
233
234 if ((client_wbio = BIO_new(BIO_s_mem())) == NULL)
235 goto failure;
236 if (BIO_set_mem_eof_return(client_wbio, -1) <= 0)
237 goto failure;
238
239 if ((server_wbio = BIO_new(BIO_s_mem())) == NULL)
240 goto failure;
241 if (BIO_set_mem_eof_return(server_wbio, -1) <= 0)
242 goto failure;
243
244 if ((client = tls_client(server_wbio, client_wbio)) == NULL)
245 goto failure;
246 if (tls_version != 0) {
247 if (!SSL_set_min_proto_version(client, tls_version))
248 goto failure;
249 if (!SSL_set_max_proto_version(client, tls_version))
250 goto failure;
251 }
252
253 if ((server = tls_server(client_wbio, server_wbio)) == NULL)
254 goto failure;
255 if (tls_version != 0) {
256 if (!SSL_set_min_proto_version(server, tls_version))
257 goto failure;
258 if (!SSL_set_max_proto_version(server, tls_version))
259 goto failure;
260 }
261
262 if (!do_client_server_loop(client, do_connect, server, do_accept)) {
263 fprintf(stderr, "FAIL: client and server handshake failed\n");
264 goto failure;
265 }
266
267 if (tls_version != 0) {
268 if (SSL_version(client) != tls_version) {
269 fprintf(stderr, "FAIL: client got TLS version %x, "
270 "want %x\n", SSL_version(client), tls_version);
271 goto failure;
272 }
273 if (SSL_version(server) != tls_version) {
274 fprintf(stderr, "FAIL: server got TLS version %x, "
275 "want %x\n", SSL_version(server), tls_version);
276 goto failure;
277 }
278 }
279
280 /*
281 * Due to the wonders of API inconsistency, SSL_get_peer_cert_chain()
282 * includes the peer's leaf certificate when called by the client,
283 * however it does not when called by the server. Futhermore, the
284 * certificate returned by SSL_get_peer_certificate() has already
285 * had its reference count incremented and must be freed, where as
286 * the certificates returned from SSL_get_peer_cert_chain() must
287 * not be freed... *sigh*
288 */
289 peer_cert = SSL_get_peer_certificate(client);
290 peer_chain = SSL_get_peer_cert_chain(client);
291 X509_free(peer_cert);
292
293 if (peer_cert == NULL) {
294 fprintf(stderr, "FAIL: client got no peer cert\n");
295 goto failure;
296 }
297 if (sk_X509_num(peer_chain) != 2) {
298 fprintf(stderr, "FAIL: client got peer cert chain with %d "
299 "certificates, want 2\n", sk_X509_num(peer_chain));
300 goto failure;
301 }
302 if (X509_cmp(peer_cert, sk_X509_value(peer_chain, 0)) != 0) {
303 fprintf(stderr, "FAIL: client got peer cert chain without peer "
304 "certificate\n");
305 goto failure;
306 }
307
308 peer_cert = SSL_get_peer_certificate(server);
309 peer_chain = SSL_get_peer_cert_chain(server);
310 X509_free(peer_cert);
311
312 if (peer_cert == NULL) {
313 fprintf(stderr, "FAIL: server got no peer cert\n");
314 goto failure;
315 }
316 if (sk_X509_num(peer_chain) != 1) {
317 fprintf(stderr, "FAIL: server got peer cert chain with %d "
318 "certificates, want 1\n", sk_X509_num(peer_chain));
319 goto failure;
320 }
321 if (X509_cmp(peer_cert, sk_X509_value(peer_chain, 0)) == 0) {
322 fprintf(stderr, "FAIL: server got peer cert chain with peer "
323 "certificate\n");
324 goto failure;
325 }
326
327 fprintf(stderr, "INFO: Done!\n");
328
329 failed = 0;
330
331 failure:
332 BIO_free(client_wbio);
333 BIO_free(server_wbio);
334
335 SSL_free(client);
336 SSL_free(server);
337
338 return failed;
339}
340
341static int
342ssl_get_peer_cert_chain_tests(void)
343{
344 int failed = 0;
345
346 fprintf(stderr, "\n== Testing SSL_get_peer_cert_chain()... ==\n");
347
348 failed |= ssl_get_peer_cert_chain_test(0);
349 failed |= ssl_get_peer_cert_chain_test(TLS1_3_VERSION);
350 failed |= ssl_get_peer_cert_chain_test(TLS1_2_VERSION);
351
352 return failed;
353}
354
355int
356main(int argc, char **argv)
357{
358 int failed = 0;
359
360 if (argc != 2) {
361 fprintf(stderr, "usage: %s certspath\n", argv[0]);
362 exit(1);
363 }
364 certs_path = argv[1];
365
366 failed |= ssl_get_peer_cert_chain_tests();
367
368 return failed;
369}