signed-unsigned comparison fixes and removed unused parameter.
[gnutls.git] / libdane / dane.c
blob052a0faa6feba7c92f56b5c595e2958baa15c45b
1 /*
2 * Copyright (C) 2012 KU Leuven
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of libdane.
8 * libdane is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #include <config.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <arpa/inet.h>
30 #include <unbound.h>
31 #include <gnutls/dane.h>
32 #include <gnutls/x509.h>
33 #include <gnutls/abstract.h>
34 #include <gnutls/crypto.h>
36 #define MAX_DATA_ENTRIES 4
38 #ifdef DEBUG
39 # define gnutls_assert() fprintf(stderr, "ASSERT: %s: %d\n", __FILE__, __LINE__);
40 # define gnutls_assert_val(x) gnutls_assert_val_int(x, __FILE__, __LINE__)
41 static int gnutls_assert_val_int (int val, const char *file, int line)
43 fprintf(stderr, "ASSERT: %s: %d\n", file, line);
44 return val;
46 #else
47 # define gnutls_assert()
48 # define gnutls_assert_val(x) (x)
49 #endif
51 struct dane_state_st
53 struct ub_ctx* ctx;
54 unsigned int flags;
57 struct dane_query_st
59 struct ub_result* result;
60 unsigned int data_entries;
61 dane_cert_usage_t usage[MAX_DATA_ENTRIES];
62 dane_cert_type_t type[MAX_DATA_ENTRIES];
63 dane_match_type_t match[MAX_DATA_ENTRIES];
64 gnutls_datum_t data[MAX_DATA_ENTRIES];
65 unsigned int flags;
66 dane_query_status_t status;
69 /**
70 * dane_query_status:
71 * @q: The query result structure
73 * This function will return the status of the query response.
74 * See %dane_query_status_t for the possible types.
76 * Returns: The status type.
77 **/
78 dane_query_status_t dane_query_status(dane_query_t q)
80 return q->status;
83 /**
84 * dane_query_entries:
85 * @q: The query result structure
87 * This function will return the number of entries in a query.
89 * Returns: The number of entries.
90 **/
91 unsigned int dane_query_entries(dane_query_t q)
93 return q->data_entries;
96 /**
97 * dane_query_data:
98 * @q: The query result structure
99 * @idx: The index of the query response.
100 * @usage: The certificate usage (see %dane_cert_usage_t)
101 * @type: The certificate type (see %dane_cert_type_t)
102 * @match: The DANE matching type (see %dane_match_type_t)
103 * @data: The DANE data.
105 * This function will provide the DANE data from the query
106 * response.
108 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
109 * negative error value.
111 int dane_query_data(dane_query_t q, unsigned int idx,
112 unsigned int *usage, unsigned int *type,
113 unsigned int *match, gnutls_datum_t * data)
115 if (idx >= q->data_entries)
116 return gnutls_assert_val(DANE_E_REQUESTED_DATA_NOT_AVAILABLE);
118 if (usage)
119 *usage = q->usage[idx];
120 if (type)
121 *type = q->type[idx];
122 if (match)
123 *match = q->match[idx];
124 if (data) {
125 data->data = q->data[idx].data;
126 data->size = q->data[idx].size;
129 return DANE_E_SUCCESS;
133 * dane_state_init:
134 * @s: The structure to be initialized
135 * @flags: flags from the %dane_state_flags enumeration
137 * This function will initialize a DANE query structure.
139 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
140 * negative error value.
142 int dane_state_init(dane_state_t* s, unsigned int flags)
144 struct ub_ctx* ctx;
145 int ret;
147 *s = calloc(1, sizeof(struct dane_state_st));
148 if (*s == NULL)
149 return gnutls_assert_val(DANE_E_MEMORY_ERROR);
151 ctx = ub_ctx_create();
152 if(!ctx) {
153 gnutls_assert();
154 ret = DANE_E_INITIALIZATION_ERROR;
155 goto cleanup;
157 ub_ctx_debugout(ctx, stderr);
159 if (!(flags & DANE_F_IGNORE_LOCAL_RESOLVER)) {
160 if( (ret=ub_ctx_resolvconf(ctx, NULL)) != 0) {
161 gnutls_assert();
162 ret = DANE_E_INITIALIZATION_ERROR;
163 goto cleanup;
166 if( (ret=ub_ctx_hosts(ctx, NULL)) != 0) {
167 gnutls_assert();
168 ret = DANE_E_INITIALIZATION_ERROR;
169 goto cleanup;
173 /* read public keys for DNSSEC verification */
174 if( (ret=ub_ctx_add_ta_file(ctx, (char*)UNBOUND_ROOT_KEY_FILE)) != 0) {
175 gnutls_assert();
176 ret = DANE_E_INITIALIZATION_ERROR;
177 goto cleanup;
180 (*s)->ctx = ctx;
181 (*s)->flags = flags;
183 return DANE_E_SUCCESS;
184 cleanup:
186 if (ctx)
187 ub_ctx_delete(ctx);
188 free(*s);
190 return ret;
194 * dane_state_deinit:
195 * @s: The structure to be deinitialized
197 * This function will deinitialize a DANE query structure.
200 void dane_state_deinit(dane_state_t s)
202 ub_ctx_delete(s->ctx);
203 free(s);
208 * dane_query_deinit:
209 * @q: The structure to be deinitialized
211 * This function will deinitialize a DANE query result structure.
214 void dane_query_deinit(dane_query_t q)
216 ub_resolve_free(q->result);
217 free(q);
221 * dane_query_tlsa:
222 * @s: The DANE state structure
223 * @r: A structure to place the result
224 * @host: The host name to resolve.
225 * @proto: The protocol type (tcp, udp, etc.)
226 * @port: The service port number (eg. 443).
228 * This function will query the DNS server for the TLSA (DANE)
229 * data for the given host.
231 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
232 * negative error value.
234 int dane_query_tlsa(dane_state_t s, dane_query_t *r, const char* host, const char* proto, unsigned int port)
236 char ns[1024];
237 int ret;
238 unsigned int i;
240 *r = calloc(1, sizeof(struct dane_query_st));
241 if (*r == NULL)
242 return gnutls_assert_val(DANE_E_MEMORY_ERROR);
244 snprintf(ns, sizeof(ns), "_%u._%s.%s", port, proto, host);
246 /* query for webserver */
247 ret = ub_resolve(s->ctx, ns, 52, 1, &(*r)->result);
248 if(ret != 0) {
249 return gnutls_assert_val(DANE_E_RESOLVING_ERROR);
252 /* show first result */
253 if(!(*r)->result->havedata) {
254 return gnutls_assert_val(DANE_E_NO_DANE_DATA);
257 i = 0;
258 do {
260 if ((*r)->result->len[i] > 3)
261 ret = DANE_E_SUCCESS;
262 else {
263 return gnutls_assert_val(DANE_E_RECEIVED_CORRUPT_DATA);
266 (*r)->usage[i] = (*r)->result->data[i][0];
267 (*r)->type[i] = (*r)->result->data[i][1];
268 (*r)->match[i] = (*r)->result->data[i][2];
269 (*r)->data[i].data = (void*)&(*r)->result->data[i][3];
270 (*r)->data[i].size = (*r)->result->len[i] - 3;
271 i++;
272 } while((*r)->result->data[i] != NULL);
274 (*r)->data_entries = i;
276 if (!(*r)->result->secure) {
277 if ((*r)->result->bogus)
278 ret = gnutls_assert_val(DANE_E_INVALID_DNSSEC_SIG);
279 else
280 ret = gnutls_assert_val(DANE_E_NO_DNSSEC_SIG);
283 /* show security status */
284 if ((*r)->result->secure) {
285 (*r)->status = DANE_QUERY_DNSSEC_VERIFIED;
286 } else if ((*r)->result->bogus) {
287 gnutls_assert();
288 (*r)->status = DANE_QUERY_BOGUS;
289 } else {
290 gnutls_assert();
291 (*r)->status = DANE_QUERY_NO_DNSSEC;
294 return ret;
297 static unsigned int matches(const gnutls_datum_t *raw1, const gnutls_datum_t *raw2,
298 dane_match_type_t match)
300 uint8_t digest[64];
301 int ret;
303 if (match == DANE_MATCH_EXACT) {
304 if (raw1->size != raw2->size)
305 return gnutls_assert_val(0);
307 if (memcmp(raw1->data, raw2->data, raw1->size) != 0)
308 return gnutls_assert_val(0);
310 return 1;
311 } else if (match == DANE_MATCH_SHA2_256) {
313 if (raw2->size != 32)
314 return gnutls_assert_val(0);
316 ret = gnutls_hash_fast(GNUTLS_DIG_SHA256, raw1->data, raw1->size, digest);
317 if (ret < 0)
318 return gnutls_assert_val(0);
320 if (memcmp(digest, raw2->data, 32) != 0)
321 return gnutls_assert_val(0);
323 return 1;
324 } else if (match == DANE_MATCH_SHA2_512) {
325 if (raw2->size != 64)
326 return gnutls_assert_val(0);
328 ret = gnutls_hash_fast(GNUTLS_DIG_SHA512, raw1->data, raw1->size, digest);
329 if (ret < 0)
330 return gnutls_assert_val(0);
332 if (memcmp(digest, raw2->data, 64) != 0)
333 return gnutls_assert_val(0);
335 return 1;
338 return gnutls_assert_val(0);
341 static int crt_to_pubkey(const gnutls_datum_t *raw_crt, gnutls_datum_t * out)
343 gnutls_pubkey_t pub = NULL;
344 gnutls_x509_crt_t crt = NULL;
345 int ret;
347 out->data = NULL;
349 ret = gnutls_x509_crt_init(&crt);
350 if (ret < 0)
351 return gnutls_assert_val(DANE_E_PUBKEY_ERROR);
353 ret = gnutls_pubkey_init( &pub);
354 if (ret < 0) {
355 gnutls_assert();
356 ret = DANE_E_PUBKEY_ERROR;
357 goto cleanup;
360 ret = gnutls_x509_crt_import(crt, raw_crt, GNUTLS_X509_FMT_DER);
361 if (ret < 0) {
362 gnutls_assert();
363 ret = DANE_E_PUBKEY_ERROR;
364 goto cleanup;
367 ret = gnutls_pubkey_import_x509(pub, crt, 0);
368 if (ret < 0) {
369 gnutls_assert();
370 ret = DANE_E_PUBKEY_ERROR;
371 goto cleanup;
374 ret = gnutls_pubkey_export2(pub, GNUTLS_X509_FMT_DER, out);
375 if (ret < 0) {
376 gnutls_assert();
377 ret = DANE_E_PUBKEY_ERROR;
378 goto cleanup;
381 ret = 0;
382 goto clean_certs;
384 cleanup:
385 free(out->data);
386 clean_certs:
387 if (pub)
388 gnutls_pubkey_deinit(pub);
389 if (crt)
390 gnutls_x509_crt_deinit(crt);
392 return ret;
395 static int verify_ca(const gnutls_datum_t *raw_crt, unsigned raw_crt_size,
396 gnutls_certificate_type_t crt_type,
397 dane_cert_type_t ctype,
398 dane_match_type_t match, gnutls_datum_t * data,
399 unsigned int *verify)
401 gnutls_datum_t pubkey = {NULL, 0};
402 int ret;
404 if (raw_crt_size < 2)
405 return gnutls_assert_val(DANE_E_INVALID_REQUEST);
407 if (ctype == DANE_CERT_X509 && crt_type == GNUTLS_CRT_X509) {
409 if (!matches(&raw_crt[1], data, match)) {
410 gnutls_assert();
411 *verify |= DANE_VERIFY_CA_CONSTRAINS_VIOLATED;
414 } else if (ctype == DANE_CERT_PK && crt_type == GNUTLS_CRT_X509) {
415 ret = crt_to_pubkey(&raw_crt[1], &pubkey);
416 if (ret < 0) {
417 gnutls_assert();
418 goto cleanup;
421 if (!matches(&pubkey, data, match)) {
422 gnutls_assert();
423 *verify |= DANE_VERIFY_CA_CONSTRAINS_VIOLATED;
427 ret = 0;
428 cleanup:
429 free(pubkey.data);
430 return ret;
433 static int verify_ee(const gnutls_datum_t *raw_crt, gnutls_certificate_type_t crt_type,
434 dane_cert_type_t ctype, dane_match_type_t match, gnutls_datum_t * data,
435 unsigned int *verify)
437 gnutls_datum_t pubkey = {NULL, 0};
438 int ret;
440 if (ctype == DANE_CERT_X509 && crt_type == GNUTLS_CRT_X509) {
442 if (!matches(raw_crt, data, match)) {
443 gnutls_assert();
444 *verify |= DANE_VERIFY_CERT_DIFFERS;
447 } else if (ctype == DANE_CERT_PK && crt_type == GNUTLS_CRT_X509) {
449 ret = crt_to_pubkey(raw_crt, &pubkey);
450 if (ret < 0) {
451 gnutls_assert();
452 goto cleanup;
455 if (!matches(&pubkey, data, match)) {
456 gnutls_assert();
457 *verify |= DANE_VERIFY_CERT_DIFFERS;
461 ret = 0;
462 cleanup:
463 free(pubkey.data);
464 return ret;
468 * dane_verify_crt:
469 * @s: A DANE state structure (may be NULL)
470 * @chain: A certificate chain
471 * @chain_size: The size of the chain
472 * @chain_type: The type of the certificate chain
473 * @hostname: The hostname associated with the chain
474 * @proto: The protocol of the service connecting (e.g. tcp)
475 * @port: The port of the service connecting (e.g. 443)
476 * @sflags: Flags for the the initialization of @s (if NULL)
477 * @vflags: Verification flags; should be zero
478 * @verify: An OR'ed list of %dane_verify_status_t.
480 * This function will verify the given certificate chain against the
481 * CA constrains and/or the certificate available via DANE.
482 * If no information via DANE can be obtained the flag %DANE_VERIFY_NO_DANE_INFO
483 * is set. If a DNSSEC signature is not available for the DANE
484 * record then the verify flag %DANE_VERIFY_NO_DNSSEC_DATA is set.
486 * Due to the many possible options of DANE, there is no single threat
487 * model countered. When notifying the user about DANE verification results
488 * it may be better to mention: DANE verification did not reject the certificate,
489 * rather than mentioning a successful DANE verication.
491 * If the @q parameter is provided it will be used for caching entries.
493 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
494 * negative error value.
497 int dane_verify_crt (dane_state_t s,
498 const gnutls_datum_t *chain, unsigned chain_size,
499 gnutls_certificate_type_t chain_type,
500 const char * hostname, const char* proto, unsigned int port,
501 unsigned int sflags, unsigned int vflags,
502 unsigned int *verify)
504 dane_state_t _s = NULL;
505 dane_query_t r = NULL;
506 int ret;
507 unsigned int usage, type, match, idx;
508 gnutls_datum_t data;
510 if (chain_type != GNUTLS_CRT_X509)
511 return gnutls_assert_val(DANE_E_INVALID_REQUEST);
513 *verify = 0;
515 if (s == NULL) {
516 ret = dane_state_init(&_s, sflags);
517 if (ret < 0) {
518 gnutls_assert();
519 return ret;
521 } else
522 _s = s;
524 ret = dane_query_tlsa(_s, &r, hostname, proto, port);
525 if (ret < 0) {
526 gnutls_assert();
527 goto cleanup;
530 idx = 0;
531 do {
532 ret = dane_query_data(r, idx++, &usage, &type, &match, &data);
533 if (ret == DANE_E_REQUESTED_DATA_NOT_AVAILABLE)
534 break;
536 if (ret < 0) {
537 gnutls_assert();
538 goto cleanup;
541 if (usage == DANE_CERT_USAGE_LOCAL_CA || usage == DANE_CERT_USAGE_CA) {
542 ret = verify_ca(chain, chain_size, chain_type, type, match, &data, verify);
543 if (ret < 0) {
544 gnutls_assert();
545 goto cleanup;
548 } else if (usage == DANE_CERT_USAGE_LOCAL_EE || usage == DANE_CERT_USAGE_EE) {
549 ret = verify_ee(&chain[0], chain_type, type, match, &data, verify);
550 if (ret < 0) {
551 gnutls_assert();
552 goto cleanup;
555 } while(1);
557 ret = 0;
559 cleanup:
560 if (s == NULL) dane_state_deinit(_s);
561 if (r != NULL) dane_query_deinit(r);
562 return ret;
566 * dane_verify_session_crt:
567 * @s: A DANE state structure (may be NULL)
568 * @session: A gnutls session
569 * @hostname: The hostname associated with the chain
570 * @proto: The protocol of the service connecting (e.g. tcp)
571 * @port: The port of the service connecting (e.g. 443)
572 * @sflags: Flags for the the initialization of @s (if NULL)
573 * @vflags: Verification flags; should be zero
574 * @verify: An OR'ed list of %dane_verify_status_t.
576 * This function will verify session's certificate chain against the
577 * CA constrains and/or the certificate available via DANE.
578 * See dane_verify_crt() for more information.
580 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
581 * negative error value.
584 int dane_verify_session_crt (
585 dane_state_t s,
586 gnutls_session_t session,
587 const char * hostname, const char* proto, unsigned int port,
588 unsigned int sflags, unsigned int vflags,
589 unsigned int *verify)
591 const gnutls_datum_t *cert_list;
592 unsigned int cert_list_size = 0;
593 unsigned int type;
595 cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
596 if (cert_list_size == 0) {
597 return gnutls_assert_val(DANE_E_NO_CERT);
600 type = gnutls_certificate_type_get(session);
602 return dane_verify_crt(s, cert_list, cert_list_size, type, hostname, proto, port, sflags, vflags, verify);