summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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}