1 /*
2  * Part of DNS zone file validator `validns`.
3  *
4  * Copyright 2011-2014 Anton Berezin <tobez@tobez.org>
5  * Modified BSD license.
6  * (See LICENSE file in the distribution.)
7  *
8  */
9 #include <sys/types.h>
10 #include <stdio.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
13 #include <string.h>
14 #include <ctype.h>
15 
16 #include "common.h"
17 #include "textparse.h"
18 #include "mempool.h"
19 #include "carp.h"
20 #include "rr.h"
21 
22 /* See http://www.rfc-editor.org/internet-drafts/draft-ietf-dane-protocol-23.txt
23  * for TLSA description.
24  */
25 
tlsa_parse(char * name,long ttl,int type,char * s)26 static struct rr* tlsa_parse(char *name, long ttl, int type, char *s)
27 {
28 	struct rr_tlsa *rr = getmem(sizeof(*rr));
29 	int cert_usage, selector, matching_type;
30 
31 	cert_usage = extract_integer(&s, "certificate usage field");
32 	if (cert_usage < 0)	return NULL;
33 	if (cert_usage > 3)
34 		return bitch("bad certificate usage field");
35 	rr->cert_usage = cert_usage;
36 
37 	selector = extract_integer(&s, "selector field");
38 	if (selector < 0)	return NULL;
39 	if (selector > 1)
40 		return bitch("bad selector field");
41 	rr->selector = selector;
42 
43 	matching_type = extract_integer(&s, "matching type field");
44 	if (matching_type < 0)	return NULL;
45 	if (matching_type > 2)
46 		return bitch("bad matching type field");
47 	rr->matching_type = matching_type;
48 
49 	rr->association_data = extract_hex_binary_data(&s, "certificate association data", EXTRACT_EAT_WHITESPACE);
50 	if (rr->association_data.length < 0)	return NULL;
51 	switch (rr->matching_type) {
52 	case 1:
53 		if (rr->association_data.length != SHA256_BYTES)
54 			return bitch("bad SHA-256 hash length");
55 		break;
56 	case 2:
57 		if (rr->association_data.length != SHA512_BYTES)
58 			return bitch("bad SHA-512 hash length");
59 		break;
60 	}
61 
62 	if (*s) {
63 		return bitch("garbage after valid TLSA data");
64 	}
65 	return store_record(type, name, ttl, rr);
66 }
67 
tlsa_human(struct rr * rrv)68 static char* tlsa_human(struct rr *rrv)
69 {
70 	RRCAST(tlsa);
71     char s[1024];
72 
73     snprintf(s, 1024, "%d %d %d ...",
74 		rr->cert_usage, rr->selector, rr->matching_type);
75     return quickstrdup_temp(s);
76 }
77 
tlsa_wirerdata(struct rr * rrv)78 static struct binary_data tlsa_wirerdata(struct rr *rrv)
79 {
80 	RRCAST(tlsa);
81 
82 	return compose_binary_data("111d", 1,
83 		rr->cert_usage, rr->selector, rr->matching_type,
84 		rr->association_data);
85 }
86 
tlsa_validate_set(struct rr_set * rr_set)87 static void* tlsa_validate_set(struct rr_set *rr_set)
88 {
89 	struct rr *rr;
90 	struct named_rr *named_rr;
91 	char *s;
92 	int port = 0;
93 	int len;
94 
95 	if (G.opt.policy_checks[POLICY_TLSA_HOST]) {
96 		rr = rr_set->tail;
97 		named_rr = rr_set->named_rr;
98 
99 		/* _25._tcp.mail.example.com. */
100 		s = named_rr->name;
101 		if (*s != '_') {
102 not_a_prefixed_domain_name:
103 			return moan(rr->file_name, rr->line, "not a proper prefixed DNS domain name");
104 		}
105 		s++;
106 		while (isdigit(*s)) {
107 			port = port * 10  + *s - '0';
108 			s++;
109 		}
110 		if (port <= 0 || port > 65535)	goto not_a_prefixed_domain_name;
111 		if (*s++ != '.')	goto not_a_prefixed_domain_name;
112 		len = strlen(s);
113 		if (len < 6)	goto not_a_prefixed_domain_name;
114 		if (memcmp(s, "_tcp.", 5) != 0 &&
115 			memcmp(s, "_udp.", 5) != 0 &&
116 			memcmp(s, "_sctp.", 6) != 0)	goto not_a_prefixed_domain_name;
117 	}
118 	return NULL;
119 }
120 
121 struct rr_methods tlsa_methods = { tlsa_parse, tlsa_human, tlsa_wirerdata, tlsa_validate_set, NULL };
122