doc update
[gnutls.git] / libdane / dane.c
blob7114ae7a0dafa0839c357a3123d3d7a42f9f0b5a
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>
35 #include "../lib/gnutls_int.h"
37 #define MAX_DATA_ENTRIES 4
39 #ifdef DEBUG
40 # define gnutls_assert() fprintf(stderr, "ASSERT: %s: %d\n", __FILE__, __LINE__);
41 # define gnutls_assert_val(x) gnutls_assert_val_int(x, __FILE__, __LINE__)
42 static int gnutls_assert_val_int (int val, const char *file, int line)
44 fprintf(stderr, "ASSERT: %s: %d\n", file, line);
45 return val;
47 #else
48 # define gnutls_assert()
49 # define gnutls_assert_val(x) (x)
50 #endif
52 struct dane_state_st
54 struct ub_ctx* ctx;
55 unsigned int flags;
58 struct dane_query_st
60 struct ub_result* result;
61 unsigned int data_entries;
62 dane_cert_usage_t usage[MAX_DATA_ENTRIES];
63 dane_cert_type_t type[MAX_DATA_ENTRIES];
64 dane_match_type_t match[MAX_DATA_ENTRIES];
65 gnutls_datum_t data[MAX_DATA_ENTRIES];
66 unsigned int flags;
67 dane_query_status_t status;
70 /**
71 * dane_query_status:
72 * @q: The query result structure
74 * This function will return the status of the query response.
75 * See %dane_query_status_t for the possible types.
77 * Returns: The status type.
78 **/
79 dane_query_status_t dane_query_status(dane_query_t q)
81 return q->status;
84 /**
85 * dane_query_entries:
86 * @q: The query result structure
88 * This function will return the number of entries in a query.
90 * Returns: The number of entries.
91 **/
92 unsigned int dane_query_entries(dane_query_t q)
94 return q->data_entries;
97 /**
98 * dane_query_data:
99 * @q: The query result structure
100 * @idx: The index of the query response.
101 * @usage: The certificate usage (see %dane_cert_usage_t)
102 * @type: The certificate type (see %dane_cert_type_t)
103 * @match: The DANE matching type (see %dane_match_type_t)
104 * @data: The DANE data.
106 * This function will provide the DANE data from the query
107 * response.
109 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
110 * negative error value.
112 int dane_query_data(dane_query_t q, unsigned int idx,
113 unsigned int *usage, unsigned int *type,
114 unsigned int *match, gnutls_datum_t * data)
116 if (idx >= q->data_entries)
117 return gnutls_assert_val(DANE_E_REQUESTED_DATA_NOT_AVAILABLE);
119 if (usage)
120 *usage = q->usage[idx];
121 if (type)
122 *type = q->type[idx];
123 if (match)
124 *match = q->match[idx];
125 if (data) {
126 data->data = q->data[idx].data;
127 data->size = q->data[idx].size;
130 return DANE_E_SUCCESS;
134 * dane_state_init:
135 * @s: The structure to be initialized
136 * @flags: flags from the %dane_state_flags enumeration
138 * This function will initialize a DANE query structure.
140 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
141 * negative error value.
143 int dane_state_init(dane_state_t* s, unsigned int flags)
145 struct ub_ctx* ctx;
146 int ret;
148 *s = calloc(1, sizeof(struct dane_state_st));
149 if (*s == NULL)
150 return gnutls_assert_val(DANE_E_MEMORY_ERROR);
152 ctx = ub_ctx_create();
153 if(!ctx) {
154 gnutls_assert();
155 ret = DANE_E_INITIALIZATION_ERROR;
156 goto cleanup;
158 ub_ctx_debugout(ctx, stderr);
160 if (!(flags & DANE_F_IGNORE_LOCAL_RESOLVER)) {
161 if( (ret=ub_ctx_resolvconf(ctx, NULL)) != 0) {
162 gnutls_assert();
163 ret = DANE_E_INITIALIZATION_ERROR;
164 goto cleanup;
167 if( (ret=ub_ctx_hosts(ctx, NULL)) != 0) {
168 gnutls_assert();
169 ret = DANE_E_INITIALIZATION_ERROR;
170 goto cleanup;
174 /* read public keys for DNSSEC verification */
175 if( (ret=ub_ctx_add_ta_file(ctx, (char*)UNBOUND_ROOT_KEY_FILE)) != 0) {
176 gnutls_assert();
177 ret = DANE_E_INITIALIZATION_ERROR;
178 goto cleanup;
181 (*s)->ctx = ctx;
182 (*s)->flags = flags;
184 return DANE_E_SUCCESS;
185 cleanup:
187 if (ctx)
188 ub_ctx_delete(ctx);
189 free(*s);
191 return ret;
195 * dane_state_deinit:
196 * @s: The structure to be deinitialized
198 * This function will deinitialize a DANE query structure.
201 void dane_state_deinit(dane_state_t s)
203 ub_ctx_delete(s->ctx);
204 free(s);
209 * dane_query_deinit:
210 * @q: The structure to be deinitialized
212 * This function will deinitialize a DANE query result structure.
215 void dane_query_deinit(dane_query_t q)
217 ub_resolve_free(q->result);
218 free(q);
222 * dane_query_tlsa:
223 * @s: The DANE state structure
224 * @r: A structure to place the result
225 * @host: The host name to resolve.
226 * @proto: The protocol type (tcp, udp, etc.)
227 * @port: The service port number (eg. 443).
229 * This function will query the DNS server for the TLSA (DANE)
230 * data for the given host.
232 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
233 * negative error value.
235 int dane_query_tlsa(dane_state_t s, dane_query_t *r, const char* host, const char* proto, unsigned int port)
237 char ns[1024];
238 int ret;
239 unsigned int i;
241 *r = calloc(1, sizeof(struct dane_query_st));
242 if (*r == NULL)
243 return gnutls_assert_val(DANE_E_MEMORY_ERROR);
245 snprintf(ns, sizeof(ns), "_%u._%s.%s", port, proto, host);
247 /* query for webserver */
248 ret = ub_resolve(s->ctx, ns, 52, 1, &(*r)->result);
249 if(ret != 0) {
250 return gnutls_assert_val(DANE_E_RESOLVING_ERROR);
253 /* show first result */
254 if(!(*r)->result->havedata) {
255 return gnutls_assert_val(DANE_E_NO_DANE_DATA);
258 i = 0;
259 do {
261 if ((*r)->result->len[i] > 3)
262 ret = DANE_E_SUCCESS;
263 else {
264 return gnutls_assert_val(DANE_E_RECEIVED_CORRUPT_DATA);
267 (*r)->usage[i] = (*r)->result->data[i][0];
268 (*r)->type[i] = (*r)->result->data[i][1];
269 (*r)->match[i] = (*r)->result->data[i][2];
270 (*r)->data[i].data = (void*)&(*r)->result->data[i][3];
271 (*r)->data[i].size = (*r)->result->len[i] - 3;
272 i++;
273 } while((*r)->result->data[i] != NULL);
275 (*r)->data_entries = i;
277 if (!(*r)->result->secure) {
278 if ((*r)->result->bogus)
279 ret = gnutls_assert_val(DANE_E_INVALID_DNSSEC_SIG);
280 else
281 ret = gnutls_assert_val(DANE_E_NO_DNSSEC_SIG);
284 /* show security status */
285 if ((*r)->result->secure) {
286 (*r)->status = DANE_QUERY_DNSSEC_VERIFIED;
287 } else if ((*r)->result->bogus) {
288 gnutls_assert();
289 (*r)->status = DANE_QUERY_BOGUS;
290 } else {
291 gnutls_assert();
292 (*r)->status = DANE_QUERY_NO_DNSSEC;
295 return ret;
298 static unsigned int matches(const gnutls_datum_t *raw1, const gnutls_datum_t *raw2,
299 dane_match_type_t match)
301 uint8_t digest[64];
302 int ret;
304 if (match == DANE_MATCH_EXACT) {
305 if (raw1->size != raw2->size)
306 return gnutls_assert_val(0);
308 if (memcmp(raw1->data, raw2->data, raw1->size) != 0)
309 return gnutls_assert_val(0);
311 return 1;
312 } else if (match == DANE_MATCH_SHA2_256) {
314 if (raw2->size != 32)
315 return gnutls_assert_val(0);
317 ret = gnutls_hash_fast(GNUTLS_DIG_SHA256, raw1->data, raw1->size, digest);
318 if (ret < 0)
319 return gnutls_assert_val(0);
321 if (memcmp(digest, raw2->data, 32) != 0)
322 return gnutls_assert_val(0);
324 return 1;
325 } else if (match == DANE_MATCH_SHA2_512) {
326 if (raw2->size != 64)
327 return gnutls_assert_val(0);
329 ret = gnutls_hash_fast(GNUTLS_DIG_SHA512, raw1->data, raw1->size, digest);
330 if (ret < 0)
331 return gnutls_assert_val(0);
333 if (memcmp(digest, raw2->data, 64) != 0)
334 return gnutls_assert_val(0);
336 return 1;
339 return gnutls_assert_val(0);
342 static int crt_to_pubkey(const gnutls_datum_t *raw_crt, gnutls_datum_t * out)
344 gnutls_pubkey_t pub = NULL;
345 gnutls_x509_crt_t crt = NULL;
346 int ret;
348 out->data = NULL;
350 ret = gnutls_x509_crt_init(&crt);
351 if (ret < 0)
352 return gnutls_assert_val(DANE_E_PUBKEY_ERROR);
354 ret = gnutls_pubkey_init( &pub);
355 if (ret < 0) {
356 gnutls_assert();
357 ret = DANE_E_PUBKEY_ERROR;
358 goto cleanup;
361 ret = gnutls_x509_crt_import(crt, raw_crt, GNUTLS_X509_FMT_DER);
362 if (ret < 0) {
363 gnutls_assert();
364 ret = DANE_E_PUBKEY_ERROR;
365 goto cleanup;
368 ret = gnutls_pubkey_import_x509(pub, crt, 0);
369 if (ret < 0) {
370 gnutls_assert();
371 ret = DANE_E_PUBKEY_ERROR;
372 goto cleanup;
375 ret = gnutls_pubkey_export2(pub, GNUTLS_X509_FMT_DER, out);
376 if (ret < 0) {
377 gnutls_assert();
378 ret = DANE_E_PUBKEY_ERROR;
379 goto cleanup;
382 ret = 0;
383 goto clean_certs;
385 cleanup:
386 free(out->data);
387 clean_certs:
388 if (pub)
389 gnutls_pubkey_deinit(pub);
390 if (crt)
391 gnutls_x509_crt_deinit(crt);
393 return ret;
396 static int verify_ca(const gnutls_datum_t *raw_crt, unsigned raw_crt_size,
397 gnutls_certificate_type_t crt_type,
398 dane_cert_type_t ctype,
399 dane_match_type_t match, gnutls_datum_t * data,
400 unsigned int *verify)
402 gnutls_datum_t pubkey = {NULL, 0};
403 int ret;
405 if (raw_crt_size < 2)
406 return gnutls_assert_val(DANE_E_INVALID_REQUEST);
408 if (ctype == DANE_CERT_X509 && crt_type == GNUTLS_CRT_X509) {
410 if (!matches(&raw_crt[1], data, match)) {
411 gnutls_assert();
412 *verify |= DANE_VERIFY_CA_CONSTRAINS_VIOLATED;
415 } else if (ctype == DANE_CERT_PK && crt_type == GNUTLS_CRT_X509) {
416 ret = crt_to_pubkey(&raw_crt[1], &pubkey);
417 if (ret < 0) {
418 gnutls_assert();
419 goto cleanup;
422 if (!matches(&pubkey, data, match)) {
423 gnutls_assert();
424 *verify |= DANE_VERIFY_CA_CONSTRAINS_VIOLATED;
428 ret = 0;
429 cleanup:
430 free(pubkey.data);
431 return ret;
434 static int verify_ee(const gnutls_datum_t *raw_crt, gnutls_certificate_type_t crt_type,
435 dane_cert_type_t ctype, dane_match_type_t match, gnutls_datum_t * data,
436 unsigned int *verify)
438 gnutls_datum_t pubkey = {NULL, 0};
439 int ret;
441 if (ctype == DANE_CERT_X509 && crt_type == GNUTLS_CRT_X509) {
443 if (!matches(raw_crt, data, match)) {
444 gnutls_assert();
445 *verify |= DANE_VERIFY_CERT_DIFFERS;
448 } else if (ctype == DANE_CERT_PK && crt_type == GNUTLS_CRT_X509) {
450 ret = crt_to_pubkey(raw_crt, &pubkey);
451 if (ret < 0) {
452 gnutls_assert();
453 goto cleanup;
456 if (!matches(&pubkey, data, match)) {
457 gnutls_assert();
458 *verify |= DANE_VERIFY_CERT_DIFFERS;
462 ret = 0;
463 cleanup:
464 free(pubkey.data);
465 return ret;
469 * dane_verify_crt:
470 * @s: A DANE state structure (may be NULL)
471 * @chain: A certificate chain
472 * @chain_size: The size of the chain
473 * @chain_type: The type of the certificate chain
474 * @hostname: The hostname associated with the chain
475 * @proto: The protocol of the service connecting (e.g. tcp)
476 * @port: The port of the service connecting (e.g. 443)
477 * @sflags: Flags for the the initialization of @s (if NULL)
478 * @vflags: Verification flags; should be zero
479 * @verify: An OR'ed list of %dane_verify_status_t.
481 * This function will verify the given certificate chain against the
482 * CA constrains and/or the certificate available via DANE.
483 * If no information via DANE can be obtained the flag %DANE_VERIFY_NO_DANE_INFO
484 * is set. If a DNSSEC signature is not available for the DANE
485 * record then the verify flag %DANE_VERIFY_NO_DNSSEC_DATA is set.
487 * Due to the many possible options of DANE, there is no single threat
488 * model countered. When notifying the user about DANE verification results
489 * it may be better to mention: DANE verification did not reject the certificate,
490 * rather than mentioning a successful DANE verication.
492 * If the @q parameter is provided it will be used for caching entries.
494 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
495 * negative error value.
498 int dane_verify_crt (dane_state_t s,
499 const gnutls_datum_t *chain, unsigned chain_size,
500 gnutls_certificate_type_t chain_type,
501 const char * hostname, const char* proto, unsigned int port,
502 unsigned int sflags, unsigned int vflags,
503 unsigned int *verify)
505 dane_state_t _s = NULL;
506 dane_query_t r = NULL;
507 int ret;
508 unsigned int usage, type, match, idx;
509 gnutls_datum_t data;
511 if (chain_type != GNUTLS_CRT_X509)
512 return gnutls_assert_val(DANE_E_INVALID_REQUEST);
514 *verify = 0;
516 if (s == NULL) {
517 ret = dane_state_init(&_s, sflags);
518 if (ret < 0) {
519 gnutls_assert();
520 return ret;
522 } else
523 _s = s;
525 ret = dane_query_tlsa(_s, &r, hostname, proto, port);
526 if (ret < 0) {
527 gnutls_assert();
528 goto cleanup;
531 idx = 0;
532 do {
533 ret = dane_query_data(r, idx++, &usage, &type, &match, &data);
534 if (ret == DANE_E_REQUESTED_DATA_NOT_AVAILABLE)
535 break;
537 if (ret < 0) {
538 gnutls_assert();
539 goto cleanup;
542 if (usage == DANE_CERT_USAGE_LOCAL_CA || usage == DANE_CERT_USAGE_CA) {
543 ret = verify_ca(chain, chain_size, chain_type, type, match, &data, verify);
544 if (ret < 0) {
545 gnutls_assert();
546 goto cleanup;
549 } else if (usage == DANE_CERT_USAGE_LOCAL_EE || usage == DANE_CERT_USAGE_EE) {
550 ret = verify_ee(&chain[0], chain_type, type, match, &data, verify);
551 if (ret < 0) {
552 gnutls_assert();
553 goto cleanup;
556 } while(1);
558 ret = 0;
560 cleanup:
561 if (s == NULL) dane_state_deinit(_s);
562 if (r != NULL) dane_query_deinit(r);
563 return ret;
567 * dane_verify_session_crt:
568 * @s: A DANE state structure (may be NULL)
569 * @session: A gnutls session
570 * @hostname: The hostname associated with the chain
571 * @proto: The protocol of the service connecting (e.g. tcp)
572 * @port: The port of the service connecting (e.g. 443)
573 * @sflags: Flags for the the initialization of @s (if NULL)
574 * @vflags: Verification flags; should be zero
575 * @verify: An OR'ed list of %dane_verify_status_t.
577 * This function will verify session's certificate chain against the
578 * CA constrains and/or the certificate available via DANE.
579 * See dane_verify_crt() for more information.
581 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
582 * negative error value.
585 int dane_verify_session_crt (
586 dane_state_t s,
587 gnutls_session_t session,
588 const char * hostname, const char* proto, unsigned int port,
589 unsigned int sflags, unsigned int vflags,
590 unsigned int *verify)
592 const gnutls_datum_t *cert_list;
593 unsigned int cert_list_size = 0;
594 unsigned int type;
596 cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
597 if (cert_list_size == 0) {
598 return gnutls_assert_val(DANE_E_NO_CERT);
601 type = gnutls_certificate_type_get(session);
603 return dane_verify_crt(s, cert_list, cert_list_size, type, hostname, proto, port, sflags, vflags, verify);
607 * dane_verification_status_print:
608 * @status: The status flags to be printed
609 * @type: The certificate type
610 * @out: Newly allocated datum with (0) terminated string.
611 * @flags: should be zero
613 * This function will pretty print the status of a verification
614 * process -- eg. the one obtained by dane_verify_crt().
616 * The output @out needs to be deallocated using gnutls_free().
618 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
619 * negative error value.
622 dane_verification_status_print (unsigned int status,
623 gnutls_datum_t * out, unsigned int flags)
625 gnutls_buffer_st str;
626 int ret;
628 _gnutls_buffer_init (&str);
630 if (status == 0)
631 _gnutls_buffer_append_str (&str, _("Certificate matches. "));
632 else
633 _gnutls_buffer_append_str (&str, _("Verification failed. "));
635 if (status & DANE_VERIFY_CA_CONSTRAINS_VIOLATED)
636 _gnutls_buffer_append_str (&str, _("CA constrains were violated. "));
638 if (status & DANE_VERIFY_CERT_DIFFERS)
639 _gnutls_buffer_append_str (&str, _("The certificate differs. "));
641 if (status & DANE_VERIFY_NO_DANE_INFO)
642 _gnutls_buffer_append_str (&str, _("There were no DANE information. "));
644 ret = _gnutls_buffer_to_datum( &str, out);
645 if (out->size > 0) out->size--;
647 return ret;