1 /*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 
3     This program is free software: you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation, either version 3 of the License, or
6     (at your option) any later version.
7 
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12 
13     You should have received a copy of the GNU General Public License
14     along with this program.  If not, see <https://www.gnu.org/licenses/>.
15  */
16 
17 #include <stdlib.h>
18 #include <string.h>
19 #include <tap/basic.h>
20 #include <time.h>
21 
22 #include "libknot/cookies.h"
23 #include "libknot/endian.h"
24 #include "libknot/errcode.h"
25 #include "contrib/sockaddr.h"
26 
client_generate(struct sockaddr_storage * s_addr,const uint8_t * c_secret,const char * msg,int code,const char * ref)27 static knot_edns_cookie_t client_generate(
28 	struct sockaddr_storage *s_addr, const uint8_t *c_secret,
29 	const char *msg, int code, const char *ref)
30 {
31 	knot_edns_cookie_params_t params = {
32 		.server_addr = s_addr,
33 	};
34 	memcpy(params.secret, c_secret, sizeof(params.secret));
35 
36 	knot_edns_cookie_t cc;
37 	int ret = knot_edns_cookie_client_generate(&cc, &params);
38 	is_int(code, ret, "client_generate ret: %s", msg);
39 	if (ret == KNOT_EOK) {
40 		ok(cc.len == KNOT_EDNS_COOKIE_CLNT_SIZE && memcmp(cc.data, ref, cc.len) == 0,
41 		   "client_generate value: %s", msg);
42 	}
43 	return cc;
44 }
45 
server_generate(struct sockaddr_storage * c_addr,const uint8_t * s_secret,uint32_t timestamp,const knot_edns_cookie_t * cc,const char * msg,int code,const char * ref)46 static knot_edns_cookie_t server_generate(
47 	struct sockaddr_storage *c_addr, const uint8_t *s_secret, uint32_t timestamp,
48 	const knot_edns_cookie_t *cc, const char *msg, int code, const char *ref)
49 {
50 	knot_edns_cookie_params_t params = {
51 		.version = KNOT_EDNS_COOKIE_VERSION,
52 		.timestamp = timestamp,
53 		.client_addr = c_addr,
54 	};
55 	memcpy(params.secret, s_secret, sizeof(params.secret));
56 
57 	knot_edns_cookie_t sc;
58 	int ret = knot_edns_cookie_server_generate(&sc, cc, &params);
59 	is_int(code, ret, "server_generate ret: %s", msg);
60 	if (ret == KNOT_EOK) {
61 		ok(sc.len == 16 && memcmp(sc.data, ref, sc.len) == 0,
62 		   "server_generate value: %s", msg);
63 	}
64 	return sc;
65 }
66 
client_check(struct sockaddr_storage * s_addr,const uint8_t * secret,knot_edns_cookie_t * cc,const char * msg,int code)67 static void client_check(
68 	struct sockaddr_storage *s_addr, const uint8_t *secret,
69 	knot_edns_cookie_t *cc, const char *msg, int code)
70 {
71 	knot_edns_cookie_params_t params = {
72 		.server_addr = s_addr,
73 	};
74 	memcpy(params.secret, secret, sizeof(params.secret));
75 
76 	int ret = knot_edns_cookie_client_check(cc, &params);
77 	is_int(code, ret, "client_check ret: %s", msg);
78 }
79 
server_check(struct sockaddr_storage * c_addr,const uint8_t * secret,knot_edns_cookie_t * sc,knot_edns_cookie_t * cc,uint32_t timestamp,const char * msg,int code)80 static void server_check(
81 	struct sockaddr_storage *c_addr, const uint8_t *secret,
82 	knot_edns_cookie_t *sc, knot_edns_cookie_t *cc, uint32_t timestamp,
83 	const char *msg, int code)
84 {
85 	knot_edns_cookie_params_t params = {
86 		.version = KNOT_EDNS_COOKIE_VERSION,
87 		.timestamp = timestamp,
88 		.lifetime_before = 3600,
89 		.lifetime_after = 300,
90 		.client_addr = c_addr,
91 	};
92 	memcpy(params.secret, secret, sizeof(params.secret));
93 
94 	int ret = knot_edns_cookie_server_check(sc, cc, &params);
95 	is_int(code, ret, "server_check ret: %s", msg);
96 }
97 
main(int argc,char * argv[])98 int main(int argc, char *argv[])
99 {
100 	plan_lazy();
101 
102 	knot_edns_cookie_t cc;
103 	knot_edns_cookie_t sc;
104 
105 	const uint8_t c_secret1[] = "\x3F\x66\x51\xC9\x81\xC1\xD7\x3E\x58\x79\x25\xD2\xF9\x98\x5F\x08";
106 	const uint8_t c_secret2[] = "\x4C\x31\x15\x17\xFA\xB6\xBF\xE2\xE1\x49\xAB\x74\xEC\x1B\xC9\xA0";
107 	const uint8_t s_secret1[] = "\xE5\xE9\x73\xE5\xA6\xB2\xA4\x3F\x48\xE7\xDC\x84\x9E\x37\xBF\xCF";
108 
109 	struct sockaddr_storage c4_sa1 = { 0 };
110 	struct sockaddr_storage c4_sa2 = { 0 };
111 	struct sockaddr_storage s4_sa = { 0 };
112 	sockaddr_set(&c4_sa1,  AF_INET, "198.51.100.100", 0);
113 	sockaddr_set(&c4_sa2, AF_INET, "203.0.113.203", 0);
114 	sockaddr_set(&s4_sa,  AF_INET, "192.0.2.53", 0);
115 
116 	struct sockaddr_storage c6_sa = { 0 };
117 	struct sockaddr_storage s6_sa = { 0 };
118 	sockaddr_set(&c6_sa, AF_INET6, "2001:db8:220:1:59de:d0f4:8769:82b8", 0);
119 	sockaddr_set(&s6_sa, AF_INET6, "2001:db8:8f::53", 0);
120 
121 	const uint8_t c_secret6[] = "\x3B\x49\x5B\xA6\xA5\xB7\xFD\x87\x73\x5B\xD5\x8F\x1E\xF7\x26\x1D";
122 	const uint8_t s_secret6[] = "\xDD\x3B\xDF\x93\x44\xB6\x78\xB1\x85\xA6\xF5\xCB\x60\xFC\xA7\x15";
123 	const uint8_t s_secret7[] = "\x44\x55\x36\xBC\xD2\x51\x32\x98\x07\x5A\x5D\x37\x96\x63\xC9\x62";
124 
125 	// Learning a new Server Cookie
126 
127 	cc = client_generate(&s4_sa, c_secret1, "IPv4", KNOT_EOK,
128 	                     "\x24\x64\xC4\xAB\xCF\x10\xC9\x57");
129 	client_check(&s4_sa, c_secret1, &cc, "IPv4", KNOT_EOK);
130 	sc = server_generate(&c4_sa1, s_secret1, 1559731985, &cc, "IPv4", KNOT_EOK,
131 	                     "\x01\x00\x00\x00\x5C\xF7\x9F\x11\x1F\x81\x30\xC3\xEE\xE2\x94\x80");
132 	server_check(&c4_sa1, s_secret1, &sc, &cc, 1559731985, "IPv4", KNOT_EOK);
133 
134 	// The same client learning a renewed (fresh) Server Cookie
135 
136 	server_generate(&c4_sa1, s_secret1, 1559734385, &cc, "IPv4", KNOT_EOK,
137 	                "\x01\x00\x00\x00\x5C\xF7\xA8\x71\xD4\xA5\x64\xA1\x44\x2A\xCA\x77");
138 
139 	// Another client learning a renewed Server Cookie
140 
141 	cc = client_generate(&s4_sa, c_secret2, "IPv4", KNOT_EOK,
142 	                     "\xFC\x93\xFC\x62\x80\x7D\xDB\x86");
143 	char *sc_reserverd = "\x01\xAB\xCD\xEF\x5C\xF7\x8F\x71\xA3\x14\x22\x7B\x66\x79\xEB\xF5";
144 	memcpy(sc.data, sc_reserverd, strlen(sc_reserverd));
145 	server_check(&c4_sa2, s_secret1, &sc, &cc, 1559727985, "IPv4", KNOT_EOK);
146 
147 	// Version check
148 
149 	sc.data[0] = 10;
150 	server_check(&c4_sa2, s_secret1, &sc, &cc, 1559727985, "version", KNOT_ENOTSUP);
151 
152 	// IPv6 query with rolled over secret
153 
154 	cc = client_generate(&s6_sa, c_secret6, "IPv6", KNOT_EOK,
155 	                     "\x22\x68\x1A\xB9\x7D\x52\xC2\x98");
156 	client_check(&s6_sa, c_secret6, &cc, "IPv6", KNOT_EOK);
157 	sc = server_generate(&c6_sa, s_secret6, 1559741817, &cc, "IPv6", KNOT_EOK,
158 	                     "\x01\x00\x00\x00\x5C\xF7\xC5\x79\x26\x55\x6B\xD0\x93\x4C\x72\xF8");
159 	server_check(&c6_sa, s_secret6, &sc, &cc, 1559741961, "IPv6", KNOT_EOK);
160 	sc = server_generate(&c6_sa, s_secret7, 1559741961, &cc, "IPv6", KNOT_EOK,
161 	                     "\x01\x00\x00\x00\x5C\xF7\xC6\x09\xA6\xBB\x79\xD1\x66\x25\x50\x7A");
162 
163 	// Past lifetime check
164 
165 	server_check(&c6_sa, s_secret7, &sc, &cc, 1559741961 + 3600, "last old", KNOT_EOK);
166 	server_check(&c6_sa, s_secret7, &sc, &cc, 1559741961 + 3601, "too old", KNOT_ERANGE);
167 
168 	// Future lifetime check
169 
170 	server_check(&c6_sa, s_secret7, &sc, &cc, 1559741961 - 300, "last new", KNOT_EOK);
171 	server_check(&c6_sa, s_secret7, &sc, &cc, 1559741961 - 301, "too new", KNOT_ERANGE);
172 
173 	return 0;
174 }
175