some more text for TPMs
[gnutls.git] / libdane / dane.c
blobf3d28341e3eed0240aa087911da585c3969a9a98
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 struct dane_query_st
40 unsigned int data_entries;
41 dane_cert_usage_t usage[MAX_DATA_ENTRIES];
42 dane_cert_type_t type[MAX_DATA_ENTRIES];
43 dane_match_type_t match[MAX_DATA_ENTRIES];
44 gnutls_datum_t data[MAX_DATA_ENTRIES];
45 struct ub_ctx* ctx;
46 struct ub_result* result;
47 unsigned int flags;
48 dane_query_status_t status;
51 /**
52 * dane_query_status:
53 * @q: The query structure
55 * This function will return the status of the query response.
56 * See %dane_query_status_t for the possible types.
58 * Returns: The status type.
59 **/
60 dane_query_status_t dane_query_status(dane_query_t q)
62 return q->status;
65 /**
66 * dane_query_entries:
67 * @q: The query structure
69 * This function will return the number of entries in a query.
71 * Returns: The number of entries.
72 **/
73 unsigned int dane_query_entries(dane_query_t q)
75 return q->data_entries;
78 /**
79 * dane_query_data:
80 * @q: The query structure
81 * @idx: The index of the query response.
82 * @usage: The certificate usage (see %dane_cert_usage_t)
83 * @type: The certificate type (see %dane_cert_type_t)
84 * @match: The DANE matching type (see %dane_match_type_t)
85 * @data: The DANE data.
87 * This function will provide the DANE data from the query
88 * response.
90 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
91 * negative error value.
92 **/
93 int dane_query_data(dane_query_t q, unsigned int idx,
94 unsigned int *usage, unsigned int *type,
95 unsigned int *match, gnutls_datum_t * data)
97 if (idx >= q->data_entries)
98 return DANE_E_REQUESTED_DATA_NOT_AVAILABLE;
100 if (usage)
101 *usage = q->usage[idx];
102 if (type)
103 *type = q->type[idx];
104 if (match)
105 *match = q->match[idx];
106 if (data) {
107 data->data = q->data[idx].data;
108 data->size = q->data[idx].size;
111 return DANE_E_SUCCESS;
115 * dane_query_init:
116 * @q: The structure to be initialized
117 * @flags: flags from the DANE_F_* definitions
119 * This function will initialize a DANE query structure.
121 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
122 * negative error value.
124 int dane_query_init(dane_query_t* q, unsigned int flags)
126 struct ub_ctx* ctx;
127 int ret;
129 *q = calloc(1, sizeof(struct dane_query_st));
130 if (*q == NULL)
131 return DANE_E_MEMORY_ERROR;
133 ctx = ub_ctx_create();
134 if(!ctx) {
135 ret = DANE_E_INITIALIZATION_ERROR;
136 goto cleanup;
138 ub_ctx_debugout(ctx, stderr);
140 if (!(flags & DANE_F_IGNORE_LOCAL_RESOLVER)) {
141 if( (ret=ub_ctx_resolvconf(ctx, NULL)) != 0) {
142 ret = DANE_E_INITIALIZATION_ERROR;
143 goto cleanup;
146 if( (ret=ub_ctx_hosts(ctx, NULL)) != 0) {
147 ret = DANE_E_INITIALIZATION_ERROR;
148 goto cleanup;
152 /* read public keys for DNSSEC verification */
153 if( (ret=ub_ctx_add_ta_file(ctx, (char*)UNBOUND_ROOT_KEY_FILE)) != 0) {
154 ret = DANE_E_INITIALIZATION_ERROR;
155 goto cleanup;
158 (*q)->ctx = ctx;
159 (*q)->flags = flags;
161 return DANE_E_SUCCESS;
162 cleanup:
164 if (ctx)
165 ub_ctx_delete(ctx);
166 free(*q);
168 return ret;
172 * dane_query_init:
173 * @q: The structure to be deinitialized
175 * This function will deinitialize a DANE query structure.
178 void dane_query_deinit(dane_query_t q)
180 if (q->result)
181 ub_ctx_delete(q->ctx);
182 ub_resolve_free(q->result);
184 free(q);
188 * dane_query_resolve_tlsa:
189 * @q: The query structure
190 * @host: The host name to resolve.
191 * @proto: The protocol type (tcp, udp, etc.)
192 * @port: The service port number (eg. 443).
194 * This function will query the DNS server for the TLSA (DANE)
195 * data for the given host.
197 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
198 * negative error value.
200 int dane_query_resolve_tlsa(dane_query_t q, const char* host, const char* proto, unsigned int port)
202 char ns[1024];
203 int ret;
204 unsigned int i;
206 if (q->result) {
207 ub_resolve_free(q->result);
208 q->result = NULL;
211 snprintf(ns, sizeof(ns), "_%u._%s.%s", port, proto, host);
213 /* query for webserver */
214 ret = ub_resolve(q->ctx, ns, 52, 1, &q->result);
215 if(ret != 0) {
216 return DANE_E_RESOLVING_ERROR;
219 /* show first result */
220 if(!q->result->havedata) {
221 return DANE_E_NO_DANE_DATA;
224 i = 0;
225 do {
227 if (q->result->len[i] > 3)
228 ret = DANE_E_SUCCESS;
229 else {
230 return DANE_E_RECEIVED_CORRUPT_DATA;
233 q->usage[i] = q->result->data[i][0];
234 q->type[i] = q->result->data[i][1];
235 q->match[i] = q->result->data[i][2];
236 q->data[i].data = (void*)&q->result->data[i][3];
237 q->data[i].size = q->result->len[i];
238 i++;
239 } while(q->result->data[i] != NULL);
241 q->data_entries = i;
243 if (q->flags & DANE_F_REQUIRE_DNSSEC) {
244 if (!q->result->secure) {
245 if (q->result->bogus)
246 ret = DANE_E_INVALID_DNSSEC_SIG;
247 else
248 ret = DANE_E_NO_DNSSEC_SIG;
252 /* show security status */
253 if (q->result->secure)
254 q->status = DANE_QUERY_DNSSEC_VERIFIED;
255 else if (q->result->bogus)
256 q->status = DANE_QUERY_BOGUS;
257 else q->status = DANE_QUERY_NO_DNSSEC;
259 return ret;
262 static unsigned int matches(const gnutls_datum_t *raw1, const gnutls_datum_t *raw2,
263 dane_match_type_t match)
265 uint8_t digest[64];
266 int ret;
268 if (match == DANE_MATCH_EXACT) {
269 if (raw1->size != raw2->size)
270 return 0;
272 if (memcmp(raw1->data, raw2->data, raw1->size) != 0)
273 return 0;
275 return 1;
276 } else if (match == DANE_MATCH_SHA2_256) {
278 if (raw2->size < 32)
279 return 0;
281 ret = gnutls_hash_fast(GNUTLS_DIG_SHA256, raw1->data, raw1->size, digest);
282 if (ret < 0)
283 return 0;
285 if (memcmp(digest, raw2->data, 32) != 0)
286 return 0;
288 return 1;
289 } else if (match == DANE_MATCH_SHA2_512) {
290 if (raw2->size < 64)
291 return 0;
293 ret = gnutls_hash_fast(GNUTLS_DIG_SHA512, raw1->data, raw1->size, digest);
294 if (ret < 0)
295 return 0;
297 if (memcmp(digest, raw2->data, 64) != 0)
298 return 0;
300 return 1;
303 return 0;
306 static int crt_to_pubkey(const gnutls_datum_t *raw_crt, gnutls_datum_t * out)
308 gnutls_pubkey_t pub = NULL;
309 gnutls_x509_crt_t crt = NULL;
310 int ret;
311 size_t size;
313 out->data = NULL;
315 ret = gnutls_x509_crt_init(&crt);
316 if (ret < 0)
317 return DANE_E_PUBKEY_ERROR;
319 ret = gnutls_pubkey_init( &pub);
320 if (ret < 0) {
321 ret = DANE_E_PUBKEY_ERROR;
322 goto cleanup;
325 ret = gnutls_x509_crt_import(crt, raw_crt, GNUTLS_X509_FMT_DER);
326 if (ret < 0) {
327 ret = DANE_E_PUBKEY_ERROR;
328 goto cleanup;
331 ret = gnutls_pubkey_import_x509(pub, crt, 0);
332 if (ret < 0) {
333 ret = DANE_E_PUBKEY_ERROR;
334 goto cleanup;
337 size = 0;
338 ret = gnutls_pubkey_export(pub, GNUTLS_X509_FMT_DER, NULL, &size);
339 if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
340 ret = DANE_E_PUBKEY_ERROR;
341 goto cleanup;
344 out->data = malloc(size);
345 if (out->data == NULL) {
346 ret = DANE_E_MEMORY_ERROR;
347 goto cleanup;
350 ret = gnutls_pubkey_export(pub, GNUTLS_X509_FMT_DER, out->data, &size);
351 if (ret < 0) {
352 ret = DANE_E_PUBKEY_ERROR;
353 goto cleanup;
356 out->size = size;
358 ret = 0;
359 goto clean_certs;
361 cleanup:
362 free(out->data);
363 clean_certs:
364 if (pub)
365 gnutls_pubkey_deinit(pub);
366 if (crt)
367 gnutls_x509_crt_deinit(crt);
369 return ret;
372 static int verify_ca(const gnutls_datum_t *raw_crt, unsigned raw_crt_size,
373 gnutls_certificate_type_t crt_type,
374 dane_cert_type_t ctype,
375 dane_match_type_t match, gnutls_datum_t * data,
376 unsigned int *verify)
378 gnutls_datum_t pubkey = {NULL, 0};
379 int ret;
381 if (raw_crt_size < 2)
382 return DANE_E_INVALID_REQUEST;
384 if (ctype == DANE_CERT_X509 && crt_type == GNUTLS_CRT_X509) {
386 if (!matches(&raw_crt[1], data, match))
387 *verify |= DANE_VERIFY_CA_CONSTRAINS_VIOLATED;
389 } else if (ctype == DANE_CERT_PK && crt_type == GNUTLS_CRT_X509) {
390 ret = crt_to_pubkey(&raw_crt[1], &pubkey);
391 if (ret < 0)
392 goto cleanup;
394 if (!matches(&pubkey, data, match))
395 *verify |= DANE_VERIFY_CA_CONSTRAINS_VIOLATED;
398 ret = 0;
399 cleanup:
400 free(pubkey.data);
401 return ret;
404 static int verify_ee(const gnutls_datum_t *raw_crt, gnutls_certificate_type_t crt_type,
405 dane_cert_type_t ctype, dane_match_type_t match, gnutls_datum_t * data,
406 unsigned int *verify)
408 gnutls_datum_t pubkey = {NULL, 0};
409 int ret;
411 if (ctype == DANE_CERT_X509 && crt_type == GNUTLS_CRT_X509) {
413 if (!matches(raw_crt, data, match))
414 *verify |= DANE_VERIFY_CERT_DIFFERS;
416 } else if (ctype == DANE_CERT_PK && crt_type == GNUTLS_CRT_X509) {
418 ret = crt_to_pubkey(raw_crt, &pubkey);
419 if (ret < 0)
420 goto cleanup;
422 if (!matches(&pubkey, data, match))
423 *verify |= DANE_VERIFY_CERT_DIFFERS;
426 ret = 0;
427 cleanup:
428 free(pubkey.data);
429 return ret;
433 * dane_verify_crt:
434 * @chain: A certificate chain
435 * @chain_size: The size of the chain
436 * @chain_type: The type of the certificate chain
437 * @hostname: The hostname associated with the chain
438 * @proto: The protocol of the service connecting (e.g. tcp)
439 * @port: The port of the service connecting (e.g. 443)
440 * @flags: The %DANE_F flags.
441 * @verify: An OR'ed list of %dane_verify_status_t.
443 * This function will verify the given certificate chain against the
444 * CA constrains and/or the certificate available via DANE.
445 * If no information via DANE can be obtained the flag %DANE_VERIFY_NO_DANE_INFO
446 * is set. If a DNSSEC signature is not available for the DANE
447 * record then the verify flag %DANE_VERIFY_NO_DNSSEC_DATA is set.
449 * Note that when verifying untrusted certificates, it is recommended to
450 * use the %DANE_F_REQUIRE_DNSSEC flag.
452 * Due to the many possible options of DANE, there is no single threat
453 * model countered. When notifying the user about DANE verification results
454 * it may be better to mention: DANE verification did not reject the certificate,
455 * rather than mentioning a successful DANE verication.
457 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
458 * negative error value.
461 int dane_verify_crt (
462 const gnutls_datum_t *chain, unsigned chain_size,
463 gnutls_certificate_type_t chain_type,
464 const char * hostname, const char* proto, unsigned int port,
465 unsigned int flags, unsigned int *verify)
467 dane_query_t q;
468 int ret;
469 unsigned int usage, type, match, idx, status;
470 gnutls_datum_t data;
472 if (chain_type != GNUTLS_CRT_X509)
473 return DANE_E_INVALID_REQUEST;
475 *verify = 0;
477 ret = dane_query_init(&q, flags);
478 if (ret < 0) {
479 return ret;
482 ret = dane_query_resolve_tlsa(q, hostname, proto, port);
483 if (ret < 0) {
484 goto cleanup;
487 status = dane_query_status(q);
488 if (status == DANE_QUERY_BOGUS) {
489 *verify |= DANE_VERIFY_DNSSEC_DATA_INVALID;
490 goto cleanup;
491 } else if (status == DANE_QUERY_NO_DNSSEC) {
492 *verify |= DANE_VERIFY_NO_DNSSEC_DATA;
493 goto cleanup;
496 idx = 0;
497 do {
498 ret = dane_query_data(q, idx++, &usage, &type, &match, &data);
499 if (ret == DANE_E_REQUESTED_DATA_NOT_AVAILABLE)
500 break;
502 if (ret < 0) {
503 goto cleanup;
506 if (usage == DANE_CERT_USAGE_LOCAL_CA || usage == DANE_CERT_USAGE_CA) {
507 ret = verify_ca(chain, chain_size, chain_type, type, match, &data, verify);
508 if (ret < 0)
509 goto cleanup;
511 } else if (usage == DANE_CERT_USAGE_LOCAL_EE || usage == DANE_CERT_USAGE_EE) {
512 ret = verify_ee(&chain[0], chain_type, type, match, &data, verify);
513 if (ret < 0)
514 goto cleanup;
516 } while(1);
518 ret = 0;
520 cleanup:
521 dane_query_deinit(q);
522 return ret;
526 * dane_verify_session_crt:
527 * @session: A gnutls session
528 * @hostname: The hostname associated with the chain
529 * @proto: The protocol of the service connecting (e.g. tcp)
530 * @port: The port of the service connecting (e.g. 443)
531 * @flags: The %DANE_F flags.
532 * @verify: An OR'ed list of %dane_verify_status_t.
534 * This function will verify session's certificate chain against the
535 * CA constrains and/or the certificate available via DANE.
536 * See dane_verify_crt() for more information.
538 * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
539 * negative error value.
542 int dane_verify_session_crt (
543 gnutls_session_t session,
544 const char * hostname, const char* proto, unsigned int port,
545 unsigned int flags, unsigned int *verify)
547 const gnutls_datum_t *cert_list;
548 unsigned int cert_list_size = 0;
549 unsigned int type;
551 cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
552 if (cert_list_size == 0) {
553 return DANE_E_NO_CERT;
556 type = gnutls_certificate_type_get(session);
558 return dane_verify_crt(cert_list, cert_list_size, type, hostname, proto, port, flags, verify);