File: tlsa.c

package info (click to toggle)
validns 0.8%2Bgit20160720-3
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 1,120 kB
  • ctags: 786
  • sloc: ansic: 7,241; perl: 283; makefile: 160
file content (121 lines) | stat: -rw-r--r-- 3,126 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
 * Part of DNS zone file validator `validns`.
 *
 * Copyright 2011-2014 Anton Berezin <tobez@tobez.org>
 * Modified BSD license.
 * (See LICENSE file in the distribution.)
 *
 */
#include <sys/types.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <ctype.h>

#include "common.h"
#include "textparse.h"
#include "mempool.h"
#include "carp.h"
#include "rr.h"

/* See http://www.rfc-editor.org/internet-drafts/draft-ietf-dane-protocol-23.txt
 * for TLSA description.
 */

static struct rr* tlsa_parse(char *name, long ttl, int type, char *s)
{
	struct rr_tlsa *rr = getmem(sizeof(*rr));
	int cert_usage, selector, matching_type;

	cert_usage = extract_integer(&s, "certificate usage field", NULL);
	if (cert_usage < 0)	return NULL;
	if (cert_usage > 3)
		return bitch("bad certificate usage field");
	rr->cert_usage = cert_usage;

	selector = extract_integer(&s, "selector field", NULL);
	if (selector < 0)	return NULL;
	if (selector > 1)
		return bitch("bad selector field");
	rr->selector = selector;

	matching_type = extract_integer(&s, "matching type field", NULL);
	if (matching_type < 0)	return NULL;
	if (matching_type > 2)
		return bitch("bad matching type field");
	rr->matching_type = matching_type;

	rr->association_data = extract_hex_binary_data(&s, "certificate association data", EXTRACT_EAT_WHITESPACE);
	if (rr->association_data.length < 0)	return NULL;
	switch (rr->matching_type) {
	case 1:
		if (rr->association_data.length != SHA256_BYTES)
			return bitch("bad SHA-256 hash length");
		break;
	case 2:
		if (rr->association_data.length != SHA512_BYTES)
			return bitch("bad SHA-512 hash length");
		break;
	}

	if (*s) {
		return bitch("garbage after valid TLSA data");
	}
	return store_record(type, name, ttl, rr);
}

static char* tlsa_human(struct rr *rrv)
{
	RRCAST(tlsa);
    char s[1024];

    snprintf(s, 1024, "%d %d %d ...",
		rr->cert_usage, rr->selector, rr->matching_type);
    return quickstrdup_temp(s);
}

static struct binary_data tlsa_wirerdata(struct rr *rrv)
{
	RRCAST(tlsa);

	return compose_binary_data("111d", 1,
		rr->cert_usage, rr->selector, rr->matching_type,
		rr->association_data);
}

static void* tlsa_validate_set(struct rr_set *rr_set)
{
	struct rr *rr;
	struct named_rr *named_rr;
	char *s;
	int port = 0;
	int len;

	if (G.opt.policy_checks[POLICY_TLSA_HOST]) {
		rr = rr_set->tail;
		named_rr = rr_set->named_rr;

		/* _25._tcp.mail.example.com. */
		s = named_rr->name;
		if (*s != '_') {
not_a_prefixed_domain_name:
			return moan(rr->file_name, rr->line, "not a proper prefixed DNS domain name");
		}
		s++;
		while (isdigit(*s)) {
			port = port * 10  + *s - '0';
			s++;
		}
		if (port <= 0 || port > 65535)	goto not_a_prefixed_domain_name;
		if (*s++ != '.')	goto not_a_prefixed_domain_name;
		len = strlen(s);
		if (len < 6)	goto not_a_prefixed_domain_name;
		if (memcmp(s, "_tcp.", 5) != 0 &&
			memcmp(s, "_udp.", 5) != 0 &&
			memcmp(s, "_sctp.", 6) != 0)	goto not_a_prefixed_domain_name;
	}
	return NULL;
}

struct rr_methods tlsa_methods = { tlsa_parse, tlsa_human, tlsa_wirerdata, tlsa_validate_set, NULL };