-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathtlsa.c
153 lines (134 loc) · 4.52 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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
* Part of DNS zone file validator `validns`.
*
* Copyright 2011-2014 Anton Berezin <[email protected]>
* 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.
* See https://tools.ietf.org/html/draft-ietf-dane-smime-16
* for SMIMEA description.
*/
static struct rr* tlsa_smimea_parse(char *name, long ttl, int type, char *s)
{
struct rr_tlsa_smimea *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 %s data", type == T_TLSA ? "TLSA" : "SMIMEA");
}
return store_record(type, name, ttl, rr);
}
static char* tlsa_smimea_human(struct rr *rrv)
{
RRCAST(tlsa_smimea);
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_smimea_wirerdata(struct rr *rrv)
{
RRCAST(tlsa_smimea);
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;
}
static void* smimea_validate_set(struct rr_set *rr_set)
{
struct rr *rr;
struct named_rr *named_rr;
char *s;
int hash_len = 0;
int len;
if (G.opt.policy_checks[POLICY_SMIMEA_HOST]) {
rr = rr_set->tail;
named_rr = rr_set->named_rr;
/* c93f1e400f26708f98cb19d936620da35eec8f72e57f9eec01c1afd6._smimecert.example.com. */
s = named_rr->name;
while (isxdigit(*s)) {
hash_len++;
s++;
}
if (*s++ != '.' || hash_len != 56) {
not_a_proper_smimea_domainname:
return moan(rr->file_name, rr->line, "not a proper domain name for an SMIMEA record");
}
len = strlen(s);
if (len < 11) goto not_a_proper_smimea_domainname;
if (memcmp(s, "_smimecert.", 11) != 0) goto not_a_proper_smimea_domainname;
}
return NULL;
}
struct rr_methods tlsa_methods = { tlsa_smimea_parse, tlsa_smimea_human, tlsa_smimea_wirerdata, tlsa_validate_set, NULL };
struct rr_methods smimea_methods = { tlsa_smimea_parse, tlsa_smimea_human, tlsa_smimea_wirerdata, smimea_validate_set, NULL };