1 /* $OpenBSD: signertest.c,v 1.6 2023/04/14 12:41:26 tb Exp $ */
2 /*
3 * Copyright (c) 2017, 2018, 2022 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 <sys/socket.h>
19 #include <sys/stat.h>
20
21 #include <err.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include <openssl/bio.h>
29 #include <openssl/err.h>
30 #include <openssl/pem.h>
31 #include <openssl/x509.h>
32
33 #include <tls.h>
34
35 #include "tls_internal.h"
36
37 #ifndef CERTSDIR
38 #define CERTSDIR "."
39 #endif
40
41 const char *cert_path = CERTSDIR;
42 int sign_cb_count;
43
44 static void
hexdump(const unsigned char * buf,size_t len)45 hexdump(const unsigned char *buf, size_t len)
46 {
47 size_t i;
48
49 for (i = 1; i <= len; i++)
50 fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
51
52 fprintf(stderr, "\n");
53 }
54
55 static void
load_file(const char * filename,const uint8_t ** data,size_t * data_len)56 load_file(const char *filename, const uint8_t **data, size_t *data_len)
57 {
58 char *filepath;
59 struct stat sb;
60 uint8_t *buf;
61 size_t len;
62 ssize_t n;
63 int fd;
64
65 if (asprintf(&filepath, "%s/%s", cert_path, filename) == -1)
66 err(1, "asprintf");
67 if ((fd = open(filepath, O_RDONLY)) == -1)
68 err(1, "failed to open '%s'", filepath);
69 if ((fstat(fd, &sb)) == -1)
70 err(1, "failed to stat '%s'", filepath);
71 if (sb.st_size < 0)
72 err(1, "file size invalid for '%s'", filepath);
73 len = (size_t)sb.st_size;
74 if ((buf = malloc(len)) == NULL)
75 err(1, "out of memory");
76 n = read(fd, buf, len);
77 if (n < 0 || (size_t)n != len)
78 err(1, "failed to read '%s'", filepath);
79 close(fd);
80
81 *data = buf;
82 *data_len = len;
83
84 free(filepath);
85 }
86
87 static int
compare_mem(char * label,const uint8_t * data1,size_t data1_len,const uint8_t * data2,size_t data2_len)88 compare_mem(char *label, const uint8_t *data1, size_t data1_len,
89 const uint8_t *data2, size_t data2_len)
90 {
91 if (data1_len != data2_len) {
92 fprintf(stderr, "FAIL: %s length mismatch (%zu != %zu)\n",
93 label, data1_len, data2_len);
94 fprintf(stderr, "Got:\n");
95 hexdump(data1, data1_len);
96 fprintf(stderr, "Want:\n");
97 hexdump(data2, data2_len);
98 return -1;
99 }
100 if (data1 == data2) {
101 fprintf(stderr, "FAIL: %s comparing same memory (%p == %p)\n",
102 label, data1, data2);
103 return -1;
104 }
105 if (memcmp(data1, data2, data1_len) != 0) {
106 fprintf(stderr, "FAIL: %s data mismatch\n", label);
107 fprintf(stderr, "Got:\n");
108 hexdump(data1, data1_len);
109 fprintf(stderr, "Want:\n");
110 hexdump(data2, data2_len);
111 return -1;
112 }
113 return 0;
114 }
115
116 const char *server_ecdsa_pubkey_hash = \
117 "SHA256:cef2616ece9a57a76d072013b0faad2232511487c67c45bf00fbcecc070e2f5b";
118 const char *server_rsa_pubkey_hash = \
119 "SHA256:f03c535d374614e7356c0a4e6fd37fe94297b60ed86212adcba40e8e0b07bc9f";
120 const char *server_unknown_pubkey_hash = \
121 "SHA256:f03c535d374614e7356c0a4e6fd37fe94297b60ed86212adcba40e8e0b07bc9e";
122
123 const uint8_t test_digest[] = {
124 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
125 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
126 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
127 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
128 };
129
130 const uint8_t test_rsa_signature[] = {
131 0x77, 0xfb, 0xdd, 0x41, 0x45, 0x40, 0x25, 0xd6,
132 0x01, 0xe0, 0x59, 0x04, 0x65, 0xae, 0xa1, 0x59,
133 0xae, 0xa2, 0x44, 0x08, 0xf7, 0x02, 0x3d, 0xe4,
134 0xc6, 0x0d, 0x4d, 0x9a, 0x3a, 0xce, 0x34, 0xbe,
135 0x2e, 0xc0, 0xfc, 0xbd, 0x5b, 0x21, 0xe4, 0xbb,
136 0xce, 0x02, 0xfd, 0xc3, 0xfc, 0x3d, 0x25, 0xe7,
137 0xd1, 0x9a, 0x13, 0x60, 0xcb, 0x07, 0xda, 0x23,
138 0xf7, 0xa3, 0xf0, 0xaf, 0x16, 0x1b, 0x28, 0x54,
139 0x0a, 0x3c, 0xc1, 0x31, 0x08, 0x0f, 0x2f, 0xce,
140 0x6d, 0x09, 0x45, 0x48, 0xee, 0x37, 0xa8, 0xc3,
141 0x91, 0xcb, 0xde, 0xad, 0xc6, 0xcf, 0x18, 0x19,
142 0xeb, 0xad, 0x08, 0x66, 0x2f, 0xce, 0x1d, 0x07,
143 0xe3, 0x03, 0x84, 0x00, 0xca, 0x0f, 0x1d, 0x0f,
144 0x0e, 0x6e, 0x54, 0xc1, 0x39, 0x3f, 0x2a, 0x78,
145 0xc8, 0xa3, 0x6d, 0x52, 0xb9, 0x26, 0x8e, 0x7e,
146 0x7a, 0x18, 0x3c, 0x8a, 0x50, 0xa3, 0xad, 0xab,
147 0xd0, 0x03, 0xc5, 0x3e, 0xa5, 0x46, 0x87, 0xb0,
148 0x03, 0xde, 0xd9, 0xe5, 0x4d, 0x73, 0x95, 0xcf,
149 0xe1, 0x59, 0x8e, 0x2e, 0x50, 0x69, 0xe6, 0x20,
150 0xaf, 0x21, 0x4f, 0xe6, 0xc4, 0x86, 0x11, 0x36,
151 0x79, 0x68, 0x83, 0xde, 0x0e, 0x81, 0xde, 0x2e,
152 0xd0, 0x19, 0x3f, 0x4b, 0xad, 0x3e, 0xbf, 0xdd,
153 0x14, 0x4d, 0x66, 0xf3, 0x7f, 0x7d, 0xca, 0xed,
154 0x99, 0x62, 0xdc, 0x7c, 0xb2, 0x8b, 0x57, 0xcb,
155 0xdf, 0xed, 0x16, 0x13, 0x86, 0xd8, 0xd8, 0xb4,
156 0x44, 0x6e, 0xd5, 0x54, 0xbc, 0xdf, 0xe7, 0x34,
157 0x10, 0xa4, 0x17, 0x5f, 0xb7, 0xe1, 0x33, 0x2c,
158 0xc1, 0x70, 0x5b, 0x87, 0x0d, 0x39, 0xee, 0xe8,
159 0xec, 0x18, 0x92, 0xe8, 0x95, 0xa8, 0x93, 0x26,
160 0xdf, 0x26, 0x93, 0x96, 0xfd, 0xad, 0x81, 0xb6,
161 0xeb, 0x72, 0x9c, 0xd4, 0xcc, 0xf6, 0x9f, 0xb0,
162 0xbb, 0xbd, 0xbd, 0x44, 0x1c, 0x99, 0x07, 0x6d,
163 };
164
165 static int
do_signer_tests(void)166 do_signer_tests(void)
167 {
168 char *server_rsa_filepath = NULL;
169 const uint8_t *server_ecdsa = NULL;
170 size_t server_ecdsa_len;
171 struct tls_signer *signer = NULL;
172 uint8_t *signature = NULL;
173 size_t signature_len;
174 EC_KEY *ec_key = NULL;
175 X509 *x509 = NULL;
176 BIO *bio = NULL;
177 int failed = 1;
178
179 load_file("server1-ecdsa.pem", &server_ecdsa, &server_ecdsa_len);
180
181 if (asprintf(&server_rsa_filepath, "%s/%s", cert_path,
182 "server1-rsa.pem") == -1) {
183 fprintf(stderr, "FAIL: failed to build rsa file path\n");
184 goto failure;
185 }
186
187 /* Load the ECDSA public key - we'll need it later. */
188 if ((bio = BIO_new_mem_buf(server_ecdsa, server_ecdsa_len)) == NULL) {
189 fprintf(stderr, "FAIL: failed to create bio\n");
190 goto failure;
191 }
192 if ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) == NULL) {
193 fprintf(stderr, "FAIL: failed to load certificate\n");
194 goto failure;
195 }
196 if ((ec_key = EVP_PKEY_get1_EC_KEY(X509_get0_pubkey(x509))) == NULL) {
197 fprintf(stderr, "FAIL: failed to get EC public key\n");
198 goto failure;
199 }
200
201 /* Create signer and add key pairs (one ECDSA, one RSA). */
202 if ((signer = tls_signer_new()) == NULL) {
203 fprintf(stderr, "FAIL: failed to create tls signer\n");
204 goto failure;
205 }
206 if (tls_signer_add_keypair_mem(signer, server_ecdsa, server_ecdsa_len,
207 server_ecdsa, server_ecdsa_len) == -1) {
208 fprintf(stderr, "FAIL: failed to add ECDSA keypair to tls "
209 "signer: %s\n", tls_signer_error(signer));
210 goto failure;
211 }
212 if (tls_signer_add_keypair_file(signer, server_rsa_filepath,
213 server_rsa_filepath) == -1) {
214 fprintf(stderr, "FAIL: failed to add RSA keypair to tls "
215 "signer: %s\n", tls_signer_error(signer));
216 goto failure;
217 }
218
219 /* Sign with RSA. */
220 if (tls_signer_sign(signer, server_rsa_pubkey_hash, test_digest,
221 sizeof(test_digest), TLS_PADDING_RSA_PKCS1, &signature,
222 &signature_len) == -1) {
223 fprintf(stderr, "FAIL: failed to sign with RSA key: %s\n",
224 tls_signer_error(signer));
225 goto failure;
226 }
227 if (compare_mem("rsa signature", signature, signature_len,
228 test_rsa_signature, sizeof(test_rsa_signature)) == -1)
229 goto failure;
230
231 free(signature);
232 signature = NULL;
233
234 /*
235 * Sign with ECDSA - ECDSA signatures are non-deterministic so we cannot
236 * check against a known value, rather we can only verify the signature.
237 */
238 if (tls_signer_sign(signer, server_ecdsa_pubkey_hash, test_digest,
239 sizeof(test_digest), TLS_PADDING_NONE, &signature,
240 &signature_len) == -1) {
241 fprintf(stderr, "FAIL: failed to sign with ECDSA key: %s\n",
242 tls_signer_error(signer));
243 goto failure;
244 }
245 if (ECDSA_verify(0, test_digest, sizeof(test_digest), signature,
246 signature_len, ec_key) != 1) {
247 fprintf(stderr, "FAIL: failed to verify ECDSA signature\n");
248 goto failure;
249 }
250
251 free(signature);
252 signature = NULL;
253
254 /* Attempt to sign with an unknown cert pubkey hash. */
255 if (tls_signer_sign(signer, server_unknown_pubkey_hash, test_digest,
256 sizeof(test_digest), TLS_PADDING_NONE, &signature,
257 &signature_len) != -1) {
258 fprintf(stderr, "FAIL: signing succeeded with unknown key\n");
259 goto failure;
260 }
261 if (strcmp(tls_signer_error(signer), "key not found") != 0) {
262 fprintf(stderr, "FAIL: got tls signer error '%s', want "
263 "'key not found'\n", tls_signer_error(signer));
264 goto failure;
265 }
266
267 failed = 0;
268
269 failure:
270 BIO_free(bio);
271 EC_KEY_free(ec_key);
272 X509_free(x509);
273 tls_signer_free(signer);
274 free((uint8_t *)server_ecdsa);
275 free(server_rsa_filepath);
276 free(signature);
277
278 return failed;
279 }
280
281 static int
do_tls_handshake(char * name,struct tls * ctx)282 do_tls_handshake(char *name, struct tls *ctx)
283 {
284 int rv;
285
286 rv = tls_handshake(ctx);
287 if (rv == 0)
288 return (1);
289 if (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT)
290 return (0);
291
292 errx(1, "%s handshake failed: %s", name, tls_error(ctx));
293 }
294
295 static int
do_client_server_handshake(char * desc,struct tls * client,struct tls * server_cctx)296 do_client_server_handshake(char *desc, struct tls *client,
297 struct tls *server_cctx)
298 {
299 int i, client_done, server_done;
300
301 i = client_done = server_done = 0;
302 do {
303 if (client_done == 0)
304 client_done = do_tls_handshake("client", client);
305 if (server_done == 0)
306 server_done = do_tls_handshake("server", server_cctx);
307 } while (i++ < 100 && (client_done == 0 || server_done == 0));
308
309 if (client_done == 0 || server_done == 0) {
310 printf("FAIL: %s TLS handshake did not complete\n", desc);
311 return (1);
312 }
313
314 return (0);
315 }
316
317 static int
test_tls_handshake_socket(struct tls * client,struct tls * server)318 test_tls_handshake_socket(struct tls *client, struct tls *server)
319 {
320 struct tls *server_cctx;
321 int failure;
322 int sv[2];
323
324 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC,
325 sv) == -1)
326 err(1, "failed to create socketpair");
327
328 if (tls_accept_socket(server, &server_cctx, sv[0]) == -1)
329 errx(1, "failed to accept: %s", tls_error(server));
330
331 if (tls_connect_socket(client, sv[1], "test") == -1)
332 errx(1, "failed to connect: %s", tls_error(client));
333
334 failure = do_client_server_handshake("socket", client, server_cctx);
335
336 tls_free(server_cctx);
337
338 close(sv[0]);
339 close(sv[1]);
340
341 return (failure);
342 }
343
344 static int
test_signer_tls_sign(void * cb_arg,const char * pubkey_hash,const uint8_t * input,size_t input_len,int padding_type,uint8_t ** out_signature,size_t * out_signature_len)345 test_signer_tls_sign(void *cb_arg, const char *pubkey_hash,
346 const uint8_t *input, size_t input_len, int padding_type,
347 uint8_t **out_signature, size_t *out_signature_len)
348 {
349 struct tls_signer *signer = cb_arg;
350
351 sign_cb_count++;
352
353 return tls_signer_sign(signer, pubkey_hash, input, input_len,
354 padding_type, out_signature, out_signature_len);
355 }
356
357 static int
test_signer_tls(char * certfile,char * keyfile,char * cafile)358 test_signer_tls(char *certfile, char *keyfile, char *cafile)
359 {
360 struct tls_config *client_cfg, *server_cfg;
361 struct tls_signer *signer;
362 struct tls *client, *server;
363 int failure = 0;
364
365 if ((signer = tls_signer_new()) == NULL)
366 errx(1, "failed to create tls signer");
367 if (tls_signer_add_keypair_file(signer, certfile, keyfile))
368 errx(1, "failed to add keypair to signer");
369
370 if ((client = tls_client()) == NULL)
371 errx(1, "failed to create tls client");
372 if ((client_cfg = tls_config_new()) == NULL)
373 errx(1, "failed to create tls client config");
374 tls_config_insecure_noverifyname(client_cfg);
375 if (tls_config_set_ca_file(client_cfg, cafile) == -1)
376 errx(1, "failed to set ca: %s", tls_config_error(client_cfg));
377
378 if ((server = tls_server()) == NULL)
379 errx(1, "failed to create tls server");
380 if ((server_cfg = tls_config_new()) == NULL)
381 errx(1, "failed to create tls server config");
382 if (tls_config_set_sign_cb(server_cfg, test_signer_tls_sign,
383 signer) == -1)
384 errx(1, "failed to set server signer callback: %s",
385 tls_config_error(server_cfg));
386 if (tls_config_set_cert_file(server_cfg, certfile) == -1)
387 errx(1, "failed to set server certificate: %s",
388 tls_config_error(server_cfg));
389
390 if (tls_configure(client, client_cfg) == -1)
391 errx(1, "failed to configure client: %s", tls_error(client));
392 if (tls_configure(server, server_cfg) == -1)
393 errx(1, "failed to configure server: %s", tls_error(server));
394
395 tls_config_free(client_cfg);
396 tls_config_free(server_cfg);
397
398 failure |= test_tls_handshake_socket(client, server);
399
400 tls_signer_free(signer);
401 tls_free(client);
402 tls_free(server);
403
404 return (failure);
405 }
406
407 static int
do_signer_tls_tests(void)408 do_signer_tls_tests(void)
409 {
410 char *server_ecdsa_cert = NULL, *server_ecdsa_key = NULL;
411 char *server_rsa_cert = NULL, *server_rsa_key = NULL;
412 char *ca_root_ecdsa = NULL, *ca_root_rsa = NULL;
413 int failure = 0;
414
415 if (asprintf(&ca_root_ecdsa, "%s/%s", cert_path,
416 "ca-root-ecdsa.pem") == -1)
417 err(1, "ca ecdsa root");
418 if (asprintf(&ca_root_rsa, "%s/%s", cert_path,
419 "ca-root-rsa.pem") == -1)
420 err(1, "ca rsa root");
421 if (asprintf(&server_ecdsa_cert, "%s/%s", cert_path,
422 "server1-ecdsa-chain.pem") == -1)
423 err(1, "server ecdsa chain");
424 if (asprintf(&server_ecdsa_key, "%s/%s", cert_path,
425 "server1-ecdsa.pem") == -1)
426 err(1, "server ecdsa key");
427 if (asprintf(&server_rsa_cert, "%s/%s", cert_path,
428 "server1-rsa-chain.pem") == -1)
429 err(1, "server rsa chain");
430 if (asprintf(&server_rsa_key, "%s/%s", cert_path,
431 "server1-rsa.pem") == -1)
432 err(1, "server rsa key");
433
434 failure |= test_signer_tls(server_ecdsa_cert, server_ecdsa_key,
435 ca_root_ecdsa);
436 failure |= test_signer_tls(server_rsa_cert, server_rsa_key,
437 ca_root_rsa);
438
439 if (sign_cb_count != 2) {
440 fprintf(stderr, "FAIL: sign callback was called %d times, "
441 "want 2\n", sign_cb_count);
442 failure |= 1;
443 }
444
445 free(ca_root_ecdsa);
446 free(ca_root_rsa);
447 free(server_ecdsa_cert);
448 free(server_ecdsa_key);
449 free(server_rsa_cert);
450 free(server_rsa_key);
451
452 return (failure);
453 }
454
455 int
main(int argc,char ** argv)456 main(int argc, char **argv)
457 {
458 int failure = 0;
459
460 if (argc > 2) {
461 fprintf(stderr, "usage: %s [certpath]\n", argv[0]);
462 return (1);
463 }
464 if (argc == 2)
465 cert_path = argv[1];
466
467 failure |= do_signer_tests();
468 failure |= do_signer_tls_tests();
469
470 return (failure);
471 }
472