forked from tobez/validns
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tlsa.c
121 lines (105 loc) · 3.04 KB
/
tlsa.c
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, 2012 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");
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");
if (selector < 0) return NULL;
if (selector > 1)
return bitch("bad selector field");
rr->selector = selector;
matching_type = extract_integer(&s, "matching type field");
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 };