1c7da899bSchristos /*
221497c5cSchristos * Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
3c7da899bSchristos *
4*b0d17251Schristos * Licensed under the Apache License 2.0 (the "License"). You may not use
5c7da899bSchristos * this file except in compliance with the License. You can obtain a copy
6c7da899bSchristos * in the file LICENSE in the source distribution or at
7c7da899bSchristos * https://www.openssl.org/source/license.html
8c7da899bSchristos */
9c7da899bSchristos
10c7da899bSchristos #include <stdio.h>
11c7da899bSchristos #include <string.h>
12c7da899bSchristos #include <ctype.h>
13c7da899bSchristos #include <limits.h>
14c7da899bSchristos #include <errno.h>
15c7da899bSchristos
16c7da899bSchristos #include <openssl/crypto.h>
17c7da899bSchristos #include <openssl/evp.h>
18c7da899bSchristos #include <openssl/x509.h>
19c7da899bSchristos #include <openssl/ssl.h>
20c7da899bSchristos #include <openssl/err.h>
21c7da899bSchristos #include <openssl/conf.h>
22c7da899bSchristos #ifndef OPENSSL_NO_ENGINE
23c7da899bSchristos # include <openssl/engine.h>
24c7da899bSchristos #endif
2513d40330Schristos #include "testutil.h"
26c7da899bSchristos
2713d40330Schristos #include "internal/nelem.h"
28c7da899bSchristos
29c7da899bSchristos #define _UC(c) ((unsigned char)(c))
30c7da899bSchristos
3113d40330Schristos static const char *basedomain;
3213d40330Schristos static const char *CAfile;
3313d40330Schristos static const char *tlsafile;
34c7da899bSchristos
35c7da899bSchristos /*
36c7da899bSchristos * Forward declaration, of function that uses internal interfaces, from headers
37c7da899bSchristos * included at the end of this module.
38c7da899bSchristos */
39c7da899bSchristos static void store_ctx_dane_init(X509_STORE_CTX *, SSL *);
40c7da899bSchristos
41c7da899bSchristos static int saved_errno;
42c7da899bSchristos
save_errno(void)43c7da899bSchristos static void save_errno(void)
44c7da899bSchristos {
45c7da899bSchristos saved_errno = errno;
46c7da899bSchristos }
47c7da899bSchristos
restore_errno(void)48c7da899bSchristos static int restore_errno(void)
49c7da899bSchristos {
50c7da899bSchristos int ret = errno;
51c7da899bSchristos errno = saved_errno;
52c7da899bSchristos return ret;
53c7da899bSchristos }
54c7da899bSchristos
verify_chain(SSL * ssl,STACK_OF (X509)* chain)55c7da899bSchristos static int verify_chain(SSL *ssl, STACK_OF(X509) *chain)
56c7da899bSchristos {
5713d40330Schristos X509_STORE_CTX *store_ctx = NULL;
5813d40330Schristos SSL_CTX *ssl_ctx = NULL;
5913d40330Schristos X509_STORE *store = NULL;
6013d40330Schristos int ret = 0;
61c7da899bSchristos int store_ctx_idx = SSL_get_ex_data_X509_STORE_CTX_idx();
62c7da899bSchristos
6313d40330Schristos if (!TEST_ptr(store_ctx = X509_STORE_CTX_new())
6413d40330Schristos || !TEST_ptr(ssl_ctx = SSL_get_SSL_CTX(ssl))
6513d40330Schristos || !TEST_ptr(store = SSL_CTX_get_cert_store(ssl_ctx))
66*b0d17251Schristos || !TEST_true(X509_STORE_CTX_init(store_ctx, store, NULL, chain))
6713d40330Schristos || !TEST_true(X509_STORE_CTX_set_ex_data(store_ctx, store_ctx_idx,
6813d40330Schristos ssl)))
69c7da899bSchristos goto end;
70c7da899bSchristos
71*b0d17251Schristos X509_STORE_CTX_set_default(store_ctx, SSL_is_server(ssl)
72*b0d17251Schristos ? "ssl_client" : "ssl_server");
73c7da899bSchristos X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(store_ctx),
74c7da899bSchristos SSL_get0_param(ssl));
75c7da899bSchristos store_ctx_dane_init(store_ctx, ssl);
76c7da899bSchristos
7713d40330Schristos if (SSL_get_verify_callback(ssl) != NULL)
78c7da899bSchristos X509_STORE_CTX_set_verify_cb(store_ctx, SSL_get_verify_callback(ssl));
79c7da899bSchristos
8013d40330Schristos /* Mask "internal failures" (-1) from our return value. */
81*b0d17251Schristos if (!TEST_int_ge(ret = X509_STORE_CTX_verify(store_ctx), 0))
8213d40330Schristos ret = 0;
83c7da899bSchristos
84c7da899bSchristos SSL_set_verify_result(ssl, X509_STORE_CTX_get_error(store_ctx));
8513d40330Schristos
86c7da899bSchristos end:
87c7da899bSchristos X509_STORE_CTX_free(store_ctx);
8813d40330Schristos return ret;
89c7da899bSchristos }
90c7da899bSchristos
STACK_OF(X509)91c7da899bSchristos static STACK_OF(X509) *load_chain(BIO *fp, int nelem)
92c7da899bSchristos {
93c7da899bSchristos int count;
94c7da899bSchristos char *name = 0;
95c7da899bSchristos char *header = 0;
96c7da899bSchristos unsigned char *data = 0;
97c7da899bSchristos long len;
98c7da899bSchristos char *errtype = 0; /* if error: cert or pkey? */
99c7da899bSchristos STACK_OF(X509) *chain;
100c7da899bSchristos typedef X509 *(*d2i_X509_t)(X509 **, const unsigned char **, long);
101c7da899bSchristos
10213d40330Schristos if (!TEST_ptr(chain = sk_X509_new_null()))
10313d40330Schristos goto err;
104c7da899bSchristos
105c7da899bSchristos for (count = 0;
106c7da899bSchristos count < nelem && errtype == 0
10713d40330Schristos && PEM_read_bio(fp, &name, &header, &data, &len) == 1;
108c7da899bSchristos ++count) {
109c7da899bSchristos if (strcmp(name, PEM_STRING_X509) == 0
110c7da899bSchristos || strcmp(name, PEM_STRING_X509_TRUSTED) == 0
111c7da899bSchristos || strcmp(name, PEM_STRING_X509_OLD) == 0) {
11213d40330Schristos d2i_X509_t d = strcmp(name, PEM_STRING_X509_TRUSTED) != 0
11313d40330Schristos ? d2i_X509_AUX : d2i_X509;
11413d40330Schristos X509 *cert;
11513d40330Schristos const unsigned char *p = data;
116c7da899bSchristos
11713d40330Schristos if (!TEST_ptr(cert = d(0, &p, len))
11813d40330Schristos || !TEST_long_eq(p - data, len)) {
11913d40330Schristos TEST_info("Certificate parsing error");
120c7da899bSchristos goto err;
121c7da899bSchristos }
12213d40330Schristos
12313d40330Schristos if (!TEST_true(sk_X509_push(chain, cert)))
12413d40330Schristos goto err;
125c7da899bSchristos } else {
12613d40330Schristos TEST_info("Unknown chain file object %s", name);
127c7da899bSchristos goto err;
128c7da899bSchristos }
129c7da899bSchristos
130c7da899bSchristos OPENSSL_free(name);
131c7da899bSchristos OPENSSL_free(header);
132c7da899bSchristos OPENSSL_free(data);
13313d40330Schristos name = header = NULL;
13413d40330Schristos data = NULL;
135c7da899bSchristos }
136c7da899bSchristos
137c7da899bSchristos if (count == nelem) {
138c7da899bSchristos ERR_clear_error();
139c7da899bSchristos return chain;
140c7da899bSchristos }
141c7da899bSchristos
142c7da899bSchristos err:
14313d40330Schristos OPENSSL_free(name);
14413d40330Schristos OPENSSL_free(header);
14513d40330Schristos OPENSSL_free(data);
146c7da899bSchristos sk_X509_pop_free(chain, X509_free);
147c7da899bSchristos return NULL;
148c7da899bSchristos }
149c7da899bSchristos
read_to_eol(BIO * f)150c7da899bSchristos static char *read_to_eol(BIO *f)
151c7da899bSchristos {
15221497c5cSchristos static char buf[4096];
153c7da899bSchristos int n;
154c7da899bSchristos
155*b0d17251Schristos if (BIO_gets(f, buf, sizeof(buf)) <= 0)
156c7da899bSchristos return NULL;
157c7da899bSchristos
158c7da899bSchristos n = strlen(buf);
159c7da899bSchristos if (buf[n - 1] != '\n') {
16013d40330Schristos if (n + 1 == sizeof(buf))
16113d40330Schristos TEST_error("input too long");
16213d40330Schristos else
16313d40330Schristos TEST_error("EOF before newline");
164c7da899bSchristos return NULL;
165c7da899bSchristos }
166c7da899bSchristos
167c7da899bSchristos /* Trim trailing whitespace */
168c7da899bSchristos while (n > 0 && isspace(_UC(buf[n - 1])))
169c7da899bSchristos buf[--n] = '\0';
170c7da899bSchristos
171c7da899bSchristos return buf;
172c7da899bSchristos }
173c7da899bSchristos
174c7da899bSchristos /*
175c7da899bSchristos * Hex decoder that tolerates optional whitespace
176c7da899bSchristos */
hexdecode(const char * in,void * result)177c7da899bSchristos static ossl_ssize_t hexdecode(const char *in, void *result)
178c7da899bSchristos {
179c7da899bSchristos unsigned char **out = (unsigned char **)result;
18013d40330Schristos unsigned char *ret;
18113d40330Schristos unsigned char *cp;
182c7da899bSchristos uint8_t byte;
183c7da899bSchristos int nibble = 0;
184c7da899bSchristos
18513d40330Schristos if (!TEST_ptr(ret = OPENSSL_malloc(strlen(in) / 2)))
186c7da899bSchristos return -1;
18713d40330Schristos cp = ret;
188c7da899bSchristos
189c7da899bSchristos for (byte = 0; *in; ++in) {
190c7da899bSchristos int x;
191c7da899bSchristos
192c7da899bSchristos if (isspace(_UC(*in)))
193c7da899bSchristos continue;
194c7da899bSchristos x = OPENSSL_hexchar2int(*in);
195c7da899bSchristos if (x < 0) {
196c7da899bSchristos OPENSSL_free(ret);
197c7da899bSchristos return 0;
198c7da899bSchristos }
199c7da899bSchristos byte |= (char)x;
200c7da899bSchristos if ((nibble ^= 1) == 0) {
201c7da899bSchristos *cp++ = byte;
202c7da899bSchristos byte = 0;
203c7da899bSchristos } else {
204c7da899bSchristos byte <<= 4;
205c7da899bSchristos }
206c7da899bSchristos }
207c7da899bSchristos if (nibble != 0) {
208c7da899bSchristos OPENSSL_free(ret);
209c7da899bSchristos return 0;
210c7da899bSchristos }
211c7da899bSchristos
212c7da899bSchristos return cp - (*out = ret);
213c7da899bSchristos }
214c7da899bSchristos
checked_uint8(const char * in,void * out)215c7da899bSchristos static ossl_ssize_t checked_uint8(const char *in, void *out)
216c7da899bSchristos {
217c7da899bSchristos uint8_t *result = (uint8_t *)out;
218c7da899bSchristos const char *cp = in;
219c7da899bSchristos char *endp;
220c7da899bSchristos long v;
221c7da899bSchristos int e;
222c7da899bSchristos
223c7da899bSchristos save_errno();
224c7da899bSchristos v = strtol(cp, &endp, 10);
225c7da899bSchristos e = restore_errno();
226c7da899bSchristos
227c7da899bSchristos if (((v == LONG_MIN || v == LONG_MAX) && e == ERANGE) ||
228c7da899bSchristos endp == cp || !isspace(_UC(*endp)) ||
229c7da899bSchristos v != (*(uint8_t *)result = (uint8_t) v)) {
230c7da899bSchristos return -1;
231c7da899bSchristos }
232c7da899bSchristos for (cp = endp; isspace(_UC(*cp)); ++cp)
233c7da899bSchristos continue;
234c7da899bSchristos return cp - in;
235c7da899bSchristos }
236c7da899bSchristos
237c7da899bSchristos struct tlsa_field {
238c7da899bSchristos void *var;
239c7da899bSchristos const char *name;
240c7da899bSchristos ossl_ssize_t (*parser)(const char *, void *);
241c7da899bSchristos };
242c7da899bSchristos
tlsa_import_rr(SSL * ssl,const char * rrdata)243c7da899bSchristos static int tlsa_import_rr(SSL *ssl, const char *rrdata)
244c7da899bSchristos {
245c7da899bSchristos static uint8_t usage;
246c7da899bSchristos static uint8_t selector;
247c7da899bSchristos static uint8_t mtype;
248c7da899bSchristos static unsigned char *data = NULL;
249c7da899bSchristos static struct tlsa_field tlsa_fields[] = {
250c7da899bSchristos { &usage, "usage", checked_uint8 },
251c7da899bSchristos { &selector, "selector", checked_uint8 },
252c7da899bSchristos { &mtype, "mtype", checked_uint8 },
253c7da899bSchristos { &data, "data", hexdecode },
254c7da899bSchristos { NULL, }
255c7da899bSchristos };
256c7da899bSchristos int ret;
257c7da899bSchristos struct tlsa_field *f;
258c7da899bSchristos const char *cp = rrdata;
259c7da899bSchristos ossl_ssize_t len = 0;
260c7da899bSchristos
261c7da899bSchristos for (f = tlsa_fields; f->var; ++f) {
262c7da899bSchristos if ((len = f->parser(cp += len, f->var)) <= 0) {
26313d40330Schristos TEST_info("bad TLSA %s field in: %s", f->name, rrdata);
264c7da899bSchristos return 0;
265c7da899bSchristos }
266c7da899bSchristos }
26713d40330Schristos
268c7da899bSchristos ret = SSL_dane_tlsa_add(ssl, usage, selector, mtype, data, len);
269c7da899bSchristos OPENSSL_free(data);
270c7da899bSchristos if (ret == 0) {
27113d40330Schristos TEST_info("unusable TLSA rrdata: %s", rrdata);
272c7da899bSchristos return 0;
273c7da899bSchristos }
274c7da899bSchristos if (ret < 0) {
27513d40330Schristos TEST_info("error loading TLSA rrdata: %s", rrdata);
276c7da899bSchristos return 0;
277c7da899bSchristos }
27813d40330Schristos
279c7da899bSchristos return ret;
280c7da899bSchristos }
281c7da899bSchristos
allws(const char * cp)282c7da899bSchristos static int allws(const char *cp)
283c7da899bSchristos {
284c7da899bSchristos while (*cp)
285c7da899bSchristos if (!isspace(_UC(*cp++)))
286c7da899bSchristos return 0;
287c7da899bSchristos return 1;
288c7da899bSchristos }
289c7da899bSchristos
test_tlsafile(SSL_CTX * ctx,const char * base_name,BIO * f,const char * path)290c7da899bSchristos static int test_tlsafile(SSL_CTX *ctx, const char *base_name,
291c7da899bSchristos BIO *f, const char *path)
292c7da899bSchristos {
293c7da899bSchristos char *line;
294c7da899bSchristos int testno = 0;
295c7da899bSchristos int ret = 1;
296c7da899bSchristos SSL *ssl;
297c7da899bSchristos
298c7da899bSchristos while (ret > 0 && (line = read_to_eol(f)) != NULL) {
299c7da899bSchristos STACK_OF(X509) *chain;
300c7da899bSchristos int ntlsa;
301c7da899bSchristos int ncert;
302c7da899bSchristos int noncheck;
303c7da899bSchristos int want;
304c7da899bSchristos int want_depth;
305c7da899bSchristos int off;
306c7da899bSchristos int i;
307c7da899bSchristos int ok;
308c7da899bSchristos int err;
309c7da899bSchristos int mdpth;
310c7da899bSchristos
311c7da899bSchristos if (*line == '\0' || *line == '#')
312c7da899bSchristos continue;
313c7da899bSchristos
314c7da899bSchristos ++testno;
315c7da899bSchristos if (sscanf(line, "%d %d %d %d %d%n",
316c7da899bSchristos &ntlsa, &ncert, &noncheck, &want, &want_depth, &off) != 5
317c7da899bSchristos || !allws(line + off)) {
31813d40330Schristos TEST_error("Malformed line for test %d", testno);
319c7da899bSchristos return 0;
320c7da899bSchristos }
321c7da899bSchristos
32213d40330Schristos if (!TEST_ptr(ssl = SSL_new(ctx)))
32313d40330Schristos return 0;
324c7da899bSchristos SSL_set_connect_state(ssl);
325c7da899bSchristos if (SSL_dane_enable(ssl, base_name) <= 0) {
326c7da899bSchristos SSL_free(ssl);
32713d40330Schristos return 0;
328c7da899bSchristos }
329c7da899bSchristos if (noncheck)
330c7da899bSchristos SSL_dane_set_flags(ssl, DANE_FLAG_NO_DANE_EE_NAMECHECKS);
331c7da899bSchristos
332c7da899bSchristos for (i = 0; i < ntlsa; ++i) {
333c7da899bSchristos if ((line = read_to_eol(f)) == NULL || !tlsa_import_rr(ssl, line)) {
334c7da899bSchristos SSL_free(ssl);
335c7da899bSchristos return 0;
336c7da899bSchristos }
337c7da899bSchristos }
338c7da899bSchristos
339c7da899bSchristos /* Don't report old news */
340c7da899bSchristos ERR_clear_error();
34113d40330Schristos if (!TEST_ptr(chain = load_chain(f, ncert))) {
342c7da899bSchristos SSL_free(ssl);
34313d40330Schristos return 0;
344c7da899bSchristos }
345c7da899bSchristos
346c7da899bSchristos ok = verify_chain(ssl, chain);
347c7da899bSchristos sk_X509_pop_free(chain, X509_free);
348c7da899bSchristos err = SSL_get_verify_result(ssl);
349c7da899bSchristos /*
350c7da899bSchristos * Peek under the hood, normally TLSA match data is hidden when
351c7da899bSchristos * verification fails, we can obtain any suppressed data by setting the
352c7da899bSchristos * verification result to X509_V_OK before looking.
353c7da899bSchristos */
354c7da899bSchristos SSL_set_verify_result(ssl, X509_V_OK);
355c7da899bSchristos mdpth = SSL_get0_dane_authority(ssl, NULL, NULL);
356c7da899bSchristos /* Not needed any more, but lead by example and put the error back. */
357c7da899bSchristos SSL_set_verify_result(ssl, err);
358c7da899bSchristos SSL_free(ssl);
359c7da899bSchristos
36013d40330Schristos if (!TEST_int_eq(err, want)) {
361c7da899bSchristos if (want == X509_V_OK)
36213d40330Schristos TEST_info("Verification failure in test %d: %d=%s",
36313d40330Schristos testno, err, X509_verify_cert_error_string(err));
364c7da899bSchristos else
36513d40330Schristos TEST_info("Unexpected error in test %d", testno);
36613d40330Schristos ret = 0;
367c7da899bSchristos continue;
368c7da899bSchristos }
36913d40330Schristos if (!TEST_false(want == 0 && ok == 0)) {
37013d40330Schristos TEST_info("Verification failure in test %d: ok=0", testno);
371c7da899bSchristos ret = 0;
37213d40330Schristos continue;
373c7da899bSchristos }
37413d40330Schristos if (!TEST_int_eq(mdpth, want_depth)) {
37513d40330Schristos TEST_info("In test test %d", testno);
37613d40330Schristos ret = 0;
37713d40330Schristos }
378c7da899bSchristos }
379c7da899bSchristos ERR_clear_error();
380c7da899bSchristos
381c7da899bSchristos return ret;
382c7da899bSchristos }
383c7da899bSchristos
run_tlsatest(void)38413d40330Schristos static int run_tlsatest(void)
385c7da899bSchristos {
386c7da899bSchristos SSL_CTX *ctx = NULL;
38713d40330Schristos BIO *f = NULL;
38813d40330Schristos int ret = 0;
389c7da899bSchristos
39013d40330Schristos if (!TEST_ptr(f = BIO_new_file(tlsafile, "r"))
39113d40330Schristos || !TEST_ptr(ctx = SSL_CTX_new(TLS_client_method()))
39213d40330Schristos || !TEST_int_gt(SSL_CTX_dane_enable(ctx), 0)
393*b0d17251Schristos || !TEST_true(SSL_CTX_load_verify_file(ctx, CAfile))
394*b0d17251Schristos || !TEST_int_gt(SSL_CTX_dane_mtype_set(ctx, EVP_sha512(), 2, 1), 0)
395*b0d17251Schristos || !TEST_int_gt(SSL_CTX_dane_mtype_set(ctx, EVP_sha256(), 1, 2), 0)
39613d40330Schristos || !TEST_int_gt(test_tlsafile(ctx, basedomain, f, tlsafile), 0))
397c7da899bSchristos goto end;
39813d40330Schristos ret = 1;
399c7da899bSchristos
400c7da899bSchristos end:
401c7da899bSchristos BIO_free(f);
402c7da899bSchristos SSL_CTX_free(ctx);
403c7da899bSchristos
40413d40330Schristos return ret;
405c7da899bSchristos }
406c7da899bSchristos
407*b0d17251Schristos OPT_TEST_DECLARE_USAGE("basedomain CAfile tlsafile\n")
408*b0d17251Schristos
setup_tests(void)40913d40330Schristos int setup_tests(void)
41013d40330Schristos {
411*b0d17251Schristos if (!test_skip_common_options()) {
412*b0d17251Schristos TEST_error("Error parsing test options\n");
41313d40330Schristos return 0;
41413d40330Schristos }
41513d40330Schristos
416*b0d17251Schristos if (!TEST_ptr(basedomain = test_get_argument(0))
417*b0d17251Schristos || !TEST_ptr(CAfile = test_get_argument(1))
418*b0d17251Schristos || !TEST_ptr(tlsafile = test_get_argument(2)))
419*b0d17251Schristos return 0;
420*b0d17251Schristos
42113d40330Schristos ADD_TEST(run_tlsatest);
42213d40330Schristos return 1;
42313d40330Schristos }
42413d40330Schristos
42513d40330Schristos #include "internal/dane.h"
426c7da899bSchristos
store_ctx_dane_init(X509_STORE_CTX * store_ctx,SSL * ssl)427c7da899bSchristos static void store_ctx_dane_init(X509_STORE_CTX *store_ctx, SSL *ssl)
428c7da899bSchristos {
429c7da899bSchristos X509_STORE_CTX_set0_dane(store_ctx, SSL_get0_dane(ssl));
430c7da899bSchristos }
431