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