1 /*  Copyright (C) 2018 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 <assert.h>
18 #include <inttypes.h>
19 #include <time.h>
20 #include <stdint.h>
21 
22 #include "libdnssec/error.h"
23 #include "libdnssec/tsig.h"
24 #include "libknot/attribute.h"
25 #include "libknot/tsig-op.h"
26 #include "libknot/errcode.h"
27 #include "libknot/descriptor.h"
28 #include "libknot/rrtype/tsig.h"
29 #include "libknot/packet/wire.h"
30 #include "libknot/consts.h"
31 #include "libknot/packet/rrset-wire.h"
32 #include "libknot/wire.h"
33 #include "contrib/string.h"
34 
35 const int KNOT_TSIG_MAX_DIGEST_SIZE = 64;    // size of HMAC-SHA512 digest
36 const uint16_t KNOT_TSIG_FUDGE_DEFAULT = 300;  // default Fudge value
37 
check_algorithm(const knot_rrset_t * tsig_rr)38 static int check_algorithm(const knot_rrset_t *tsig_rr)
39 {
40 	if (tsig_rr == NULL) {
41 		return KNOT_EINVAL;
42 	}
43 
44 	const knot_dname_t *alg_name = knot_tsig_rdata_alg_name(tsig_rr);
45 	if (!alg_name) {
46 		return KNOT_EMALF;
47 	}
48 
49 	dnssec_tsig_algorithm_t alg = dnssec_tsig_algorithm_from_dname(alg_name);
50 	if (alg == DNSSEC_TSIG_UNKNOWN) {
51 		return KNOT_TSIG_EBADKEY;
52 	}
53 
54 	return KNOT_EOK;
55 }
56 
check_key(const knot_rrset_t * tsig_rr,const knot_tsig_key_t * tsig_key)57 static int check_key(const knot_rrset_t *tsig_rr, const knot_tsig_key_t *tsig_key)
58 {
59 	if (tsig_rr == NULL || tsig_key == NULL) {
60 		return KNOT_EINVAL;
61 	}
62 
63 	const knot_dname_t *tsig_name = tsig_rr->owner;
64 	if (!tsig_name) {
65 		return KNOT_EMALF;
66 	}
67 
68 	if (!knot_dname_is_equal(tsig_name, tsig_key->name)) {
69 		return KNOT_TSIG_EBADKEY;
70 	}
71 
72 	return KNOT_EOK;
73 }
74 
compute_digest(const uint8_t * wire,size_t wire_len,uint8_t * digest,size_t * digest_len,const knot_tsig_key_t * key)75 static int compute_digest(const uint8_t *wire, size_t wire_len,
76                           uint8_t *digest, size_t *digest_len,
77                           const knot_tsig_key_t *key)
78 {
79 	if (!wire || !digest || !digest_len || !key) {
80 		return KNOT_EINVAL;
81 	}
82 
83 	if (!key->name) {
84 		return KNOT_EMALF;
85 	}
86 
87 	dnssec_tsig_ctx_t *ctx = NULL;
88 	int result = dnssec_tsig_new(&ctx, key->algorithm, &key->secret);
89 	if (result != DNSSEC_EOK) {
90 		return KNOT_TSIG_EBADSIG;
91 	}
92 
93 	dnssec_binary_t cover = { .data = (uint8_t *)wire, .size = wire_len };
94 	dnssec_tsig_add(ctx, &cover);
95 
96 	*digest_len = dnssec_tsig_size(ctx);
97 	dnssec_tsig_write(ctx, digest);
98 	dnssec_tsig_free(ctx);
99 
100 	return KNOT_EOK;
101 }
102 
check_time_signed(const knot_rrset_t * tsig_rr,uint64_t prev_time_signed)103 static int check_time_signed(const knot_rrset_t *tsig_rr, uint64_t prev_time_signed)
104 {
105 	if (!tsig_rr) {
106 		return KNOT_EINVAL;
107 	}
108 
109 	/* Get the time signed and fudge values. */
110 	uint64_t time_signed = knot_tsig_rdata_time_signed(tsig_rr);
111 	if (time_signed == 0) {
112 		return KNOT_TSIG_EBADTIME;
113 	}
114 	uint16_t fudge = knot_tsig_rdata_fudge(tsig_rr);
115 	if (fudge == 0) {
116 		return KNOT_TSIG_EBADTIME;
117 	}
118 
119 	/* Get the current time. */
120 	time_t curr_time = time(NULL);
121 
122 	/*!< \todo bleeding eyes. */
123 	double diff = difftime(curr_time, (time_t)time_signed);
124 
125 	if (diff > fudge || diff < -fudge) {
126 		return KNOT_TSIG_EBADTIME;
127 	}
128 
129 	diff = difftime((time_t)time_signed, prev_time_signed);
130 
131 	if (diff < 0) {
132 		return KNOT_TSIG_EBADTIME;
133 	}
134 
135 	return KNOT_EOK;
136 }
137 
write_tsig_variables(uint8_t * wire,const knot_rrset_t * tsig_rr)138 static int write_tsig_variables(uint8_t *wire, const knot_rrset_t *tsig_rr)
139 {
140 	if (wire == NULL || tsig_rr == NULL) {
141 		return KNOT_EINVAL;
142 	}
143 
144 	/* Copy TSIG variables - starting with key name. */
145 	const knot_dname_t *tsig_owner = tsig_rr->owner;
146 	if (!tsig_owner) {
147 		return KNOT_EINVAL;
148 	}
149 
150 	int offset = 0;
151 
152 	offset += knot_dname_to_wire(wire + offset, tsig_owner, KNOT_DNAME_MAXLEN);
153 
154 	/*!< \todo which order? */
155 
156 	/* Copy class. */
157 	knot_wire_write_u16(wire + offset, tsig_rr->rclass);
158 	offset += sizeof(uint16_t);
159 
160 	/* Copy TTL - always 0. */
161 	knot_wire_write_u32(wire + offset, tsig_rr->ttl);
162 	offset += sizeof(uint32_t);
163 
164 	/* Copy alg name. */
165 	const knot_dname_t *alg_name = knot_tsig_rdata_alg_name(tsig_rr);
166 	if (!alg_name) {
167 		return KNOT_EINVAL;
168 	}
169 
170 	/* Te algorithm name must be in canonical form, i.e. in lowercase. */
171 	uint8_t *alg_name_wire = wire + offset;
172 	offset += knot_dname_to_wire(alg_name_wire, alg_name, KNOT_DNAME_MAXLEN);
173 	knot_dname_to_lower(alg_name_wire);
174 
175 	/* Following data are written in network order. */
176 	/* Time signed. */
177 	knot_wire_write_u48(wire + offset, knot_tsig_rdata_time_signed(tsig_rr));
178 	offset += 6;
179 	/* Fudge. */
180 	knot_wire_write_u16(wire + offset, knot_tsig_rdata_fudge(tsig_rr));
181 	offset += sizeof(uint16_t);
182 	/* TSIG error. */
183 	knot_wire_write_u16(wire + offset, knot_tsig_rdata_error(tsig_rr));
184 	offset += sizeof(uint16_t);
185 	/* Get other data length. */
186 	uint16_t other_data_length = knot_tsig_rdata_other_data_length(tsig_rr);
187 	/* Get other data. */
188 	const uint8_t *other_data = knot_tsig_rdata_other_data(tsig_rr);
189 	if (!other_data) {
190 		return KNOT_EINVAL;
191 	}
192 
193 	/*
194 	 * We cannot write the whole other_data, as it contains its length in
195 	 * machine order.
196 	 */
197 	knot_wire_write_u16(wire + offset, other_data_length);
198 	offset += sizeof(uint16_t);
199 
200 	/* Skip the length. */
201 	memcpy(wire + offset, other_data, other_data_length);
202 
203 	return KNOT_EOK;
204 }
205 
wire_write_timers(uint8_t * wire,const knot_rrset_t * tsig_rr)206 static int wire_write_timers(uint8_t *wire, const knot_rrset_t *tsig_rr)
207 {
208 	if (wire == NULL || tsig_rr == NULL) {
209 		return KNOT_EINVAL;
210 	}
211 
212 	//write time signed
213 	knot_wire_write_u48(wire, knot_tsig_rdata_time_signed(tsig_rr));
214 	//write fudge
215 	knot_wire_write_u16(wire + 6, knot_tsig_rdata_fudge(tsig_rr));
216 
217 	return KNOT_EOK;
218 }
219 
create_sign_wire(const uint8_t * msg,size_t msg_len,const uint8_t * request_mac,size_t request_mac_len,uint8_t * digest,size_t * digest_len,const knot_rrset_t * tmp_tsig,const knot_tsig_key_t * key)220 static int create_sign_wire(const uint8_t *msg, size_t msg_len,
221                             const uint8_t *request_mac, size_t request_mac_len,
222                             uint8_t *digest, size_t *digest_len,
223                             const knot_rrset_t *tmp_tsig,
224                             const knot_tsig_key_t *key)
225 {
226 	if (!msg || !key || digest_len == NULL) {
227 		return KNOT_EINVAL;
228 	}
229 
230 	/* Create tmp TSIG. */
231 	int ret = KNOT_EOK;
232 
233 	/*
234 	 * Create tmp wire, it should contain message
235 	 * plus request mac plus tsig varibles.
236 	 */
237 	size_t wire_len = msg_len + request_mac_len + (request_mac_len > 0 ? 2 : 0) +
238 	                  knot_tsig_rdata_tsig_variables_length(tmp_tsig);
239 	uint8_t *wire = malloc(wire_len);
240 	if (!wire) {
241 		return KNOT_ENOMEM;
242 	}
243 
244 	memset(wire, 0, wire_len);
245 
246 	uint8_t *pos = wire;
247 
248 	/* Copy the request MAC - should work even if NULL. */
249 	if (request_mac_len > 0) {
250 		knot_wire_write_u16(pos, request_mac_len);
251 		pos += 2;
252 		memcpy(pos, request_mac, request_mac_len);
253 	}
254 	pos += request_mac_len;
255 	/* Copy the original message. */
256 	memcpy(pos, msg, msg_len);
257 	pos += msg_len;
258 	/* Copy TSIG variables. */
259 	ret = write_tsig_variables(pos, tmp_tsig);
260 	if (ret != KNOT_EOK) {
261 		free(wire);
262 		return ret;
263 	}
264 
265 	/* Compute digest. */
266 	ret = compute_digest(wire, wire_len, digest, digest_len, key);
267 	if (ret != KNOT_EOK) {
268 		*digest_len = 0;
269 		free(wire);
270 		return ret;
271 	}
272 
273 	free(wire);
274 
275 	return KNOT_EOK;
276 }
277 
create_sign_wire_next(const uint8_t * msg,size_t msg_len,const uint8_t * prev_mac,size_t prev_mac_len,uint8_t * digest,size_t * digest_len,const knot_rrset_t * tmp_tsig,const knot_tsig_key_t * key)278 static int create_sign_wire_next(const uint8_t *msg, size_t msg_len,
279                                  const uint8_t *prev_mac, size_t prev_mac_len,
280                                  uint8_t *digest, size_t *digest_len,
281                                  const knot_rrset_t *tmp_tsig,
282                                  const knot_tsig_key_t *key)
283 {
284 	if (!msg || !key || digest_len == NULL) {
285 		return KNOT_EINVAL;
286 	}
287 
288 	/* Create tmp TSIG. */
289 	int ret = KNOT_EOK;
290 
291 	/*
292 	 * Create tmp wire, it should contain message
293 	 * plus request mac plus tsig varibles.
294 	 */
295 	size_t wire_len = msg_len + prev_mac_len + knot_tsig_rdata_tsig_timers_length() + 2;
296 	uint8_t *wire = malloc(wire_len);
297 	if (!wire) {
298 		return KNOT_ENOMEM;
299 	}
300 
301 	memset(wire, 0, wire_len);
302 
303 	/* Copy the request MAC - should work even if NULL. */
304 	knot_wire_write_u16(wire, prev_mac_len);
305 	memcpy(wire + 2, prev_mac, prev_mac_len);
306 	/* Copy the original message. */
307 	memcpy(wire + prev_mac_len + 2, msg, msg_len);
308 	/* Copy TSIG variables. */
309 
310 	ret = wire_write_timers(wire + prev_mac_len + msg_len + 2, tmp_tsig);
311 	if (ret != KNOT_EOK) {
312 		free(wire);
313 		return ret;
314 	}
315 
316 	/* Compute digest. */
317 	ret = compute_digest(wire, wire_len, digest, digest_len, key);
318 	if (ret != KNOT_EOK) {
319 		*digest_len = 0;
320 		free(wire);
321 		return ret;
322 	}
323 
324 	free(wire);
325 
326 	return KNOT_EOK;
327 }
328 
329 _public_
knot_tsig_sign(uint8_t * msg,size_t * msg_len,size_t msg_max_len,const uint8_t * request_mac,size_t request_mac_len,uint8_t * digest,size_t * digest_len,const knot_tsig_key_t * key,uint16_t tsig_rcode,uint64_t request_time_signed)330 int knot_tsig_sign(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
331                    const uint8_t *request_mac, size_t request_mac_len,
332                    uint8_t *digest, size_t *digest_len,
333                    const knot_tsig_key_t *key, uint16_t tsig_rcode,
334                    uint64_t request_time_signed)
335 {
336 	if (!msg || !msg_len || !key || digest == NULL || digest_len == NULL) {
337 		return KNOT_EINVAL;
338 	}
339 
340 	knot_rrset_t *tmp_tsig = knot_rrset_new(key->name, KNOT_RRTYPE_TSIG,
341 	                                        KNOT_CLASS_ANY, 0, NULL);
342 	if (!tmp_tsig) {
343 		return KNOT_ENOMEM;
344 	}
345 
346 	/* Create rdata for TSIG RR. */
347 	uint16_t rdata_rcode = KNOT_RCODE_NOERROR;
348 	if (tsig_rcode == KNOT_RCODE_BADTIME) {
349 		rdata_rcode = tsig_rcode;
350 	}
351 
352 	const uint8_t *alg_name = dnssec_tsig_algorithm_to_dname(key->algorithm);
353 	size_t alg_size = dnssec_tsig_algorithm_size(key->algorithm);
354 	knot_tsig_create_rdata(tmp_tsig, alg_name, alg_size, rdata_rcode);
355 
356 	/* Distinguish BADTIME response. */
357 	if (tsig_rcode == KNOT_RCODE_BADTIME) {
358 		/* Set client's time signed into the time signed field. */
359 		knot_tsig_rdata_set_time_signed(tmp_tsig, request_time_signed);
360 
361 		/* Store current time into Other data. */
362 		uint8_t time_signed[6];
363 		time_t now = time(NULL);
364 		knot_wire_write_u48(time_signed, now);
365 
366 		knot_tsig_rdata_set_other_data(tmp_tsig, 6, time_signed);
367 	} else {
368 		knot_tsig_rdata_set_time_signed(tmp_tsig, time(NULL));
369 
370 		/* Set other len. */
371 		knot_tsig_rdata_set_other_data(tmp_tsig, 0, 0);
372 	}
373 
374 	knot_tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT);
375 
376 	/* Set original ID */
377 	knot_tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));
378 
379 	uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
380 	size_t digest_tmp_len = 0;
381 
382 	int ret = create_sign_wire(msg, *msg_len, /*msg_max_len,*/
383 	                           request_mac, request_mac_len,
384 	                           digest_tmp, &digest_tmp_len, tmp_tsig, key);
385 	if (ret != KNOT_EOK) {
386 		knot_rrset_free(tmp_tsig, NULL);
387 		return ret;
388 	}
389 
390 	/* Set the digest. */
391 	knot_tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp);
392 
393 	/* Write RRSet to wire */
394 	ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
395 	                         msg_max_len - *msg_len, NULL);
396 	if (ret < 0) {
397 		*digest_len = 0;
398 		knot_rrset_free(tmp_tsig, NULL);
399 		return ret;
400 	}
401 
402 	size_t tsig_wire_len = ret;
403 
404 	knot_rrset_free(tmp_tsig, NULL);
405 
406 	*msg_len += tsig_wire_len;
407 
408 	uint16_t arcount = knot_wire_get_arcount(msg);
409 	knot_wire_set_arcount(msg, ++arcount);
410 
411 	/* everything went ok, save the digest to the output parameter */
412 	memcpy(digest, digest_tmp, digest_tmp_len);
413 	*digest_len = digest_tmp_len;
414 
415 	return KNOT_EOK;
416 }
417 
418 _public_
knot_tsig_sign_next(uint8_t * msg,size_t * msg_len,size_t msg_max_len,const uint8_t * prev_digest,size_t prev_digest_len,uint8_t * digest,size_t * digest_len,const knot_tsig_key_t * key,uint8_t * to_sign,size_t to_sign_len)419 int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
420                         const uint8_t *prev_digest, size_t prev_digest_len,
421                         uint8_t *digest, size_t *digest_len,
422                         const knot_tsig_key_t *key, uint8_t *to_sign,
423                         size_t to_sign_len)
424 {
425 	if (!msg || !msg_len || !key || !digest || !digest_len) {
426 		return KNOT_EINVAL;
427 	}
428 
429 	uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
430 	size_t digest_tmp_len = 0;
431 	knot_rrset_t *tmp_tsig = knot_rrset_new(key->name, KNOT_RRTYPE_TSIG,
432 	                                        KNOT_CLASS_ANY, 0, NULL);
433 	if (!tmp_tsig) {
434 		return KNOT_ENOMEM;
435 	}
436 
437 	/* Create rdata for TSIG RR. */
438 	const uint8_t *alg_name = dnssec_tsig_algorithm_to_dname(key->algorithm);
439 	size_t alg_size = dnssec_tsig_algorithm_size(key->algorithm);
440 	knot_tsig_create_rdata(tmp_tsig, alg_name, alg_size, 0);
441 	knot_tsig_rdata_set_time_signed(tmp_tsig, time(NULL));
442 	knot_tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT);
443 
444 	/* Create wire to be signed. */
445 	size_t wire_len = prev_digest_len + to_sign_len + KNOT_TSIG_TIMERS_LENGTH + 2;
446 	uint8_t *wire = malloc(wire_len);
447 	if (!wire) {
448 		knot_rrset_free(tmp_tsig, NULL);
449 		return KNOT_ENOMEM;
450 	}
451 	memset(wire, 0, wire_len);
452 
453 	/* Write previous digest length. */
454 	knot_wire_write_u16(wire, prev_digest_len);
455 	/* Write previous digest. */
456 	memcpy(wire + 2, prev_digest, prev_digest_len);
457 	/* Write original message. */
458 	memcpy(wire + prev_digest_len + 2, to_sign, to_sign_len);
459 	/* Write timers. */
460 	wire_write_timers(wire + prev_digest_len + to_sign_len + 2, tmp_tsig);
461 
462 	int ret = compute_digest(wire, wire_len, digest_tmp, &digest_tmp_len, key);
463 	free(wire);
464 	if (ret != KNOT_EOK) {
465 		knot_rrset_free(tmp_tsig, NULL);
466 		*digest_len = 0;
467 		return ret;
468 	}
469 
470 	if (digest_tmp_len > *digest_len) {
471 		knot_rrset_free(tmp_tsig, NULL);
472 		*digest_len = 0;
473 		return KNOT_ESPACE;
474 	}
475 
476 	/* Set the MAC. */
477 	knot_tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp);
478 
479 	/* Set original id. */
480 	knot_tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));
481 
482 	/* Set other data. */
483 	knot_tsig_rdata_set_other_data(tmp_tsig, 0, NULL);
484 
485 	ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
486 	                         msg_max_len - *msg_len, NULL);
487 	if (ret < 0) {
488 		knot_rrset_free(tmp_tsig, NULL);
489 		*digest_len = 0;
490 		return ret;
491 	}
492 
493 	size_t tsig_wire_size = ret;
494 
495 	knot_rrset_free(tmp_tsig, NULL);
496 
497 	*msg_len += tsig_wire_size;
498 	uint16_t arcount = knot_wire_get_arcount(msg);
499 	knot_wire_set_arcount(msg, ++arcount);
500 
501 	memcpy(digest, digest_tmp, digest_tmp_len);
502 	*digest_len = digest_tmp_len;
503 
504 	return KNOT_EOK;
505 }
506 
check_digest(const knot_rrset_t * tsig_rr,const uint8_t * wire,size_t size,const uint8_t * request_mac,size_t request_mac_len,const knot_tsig_key_t * tsig_key,uint64_t prev_time_signed,int use_times)507 static int check_digest(const knot_rrset_t *tsig_rr,
508                         const uint8_t *wire, size_t size,
509                         const uint8_t *request_mac, size_t request_mac_len,
510                         const knot_tsig_key_t *tsig_key,
511                         uint64_t prev_time_signed, int use_times)
512 {
513 	if (!wire || !tsig_key) {
514 		return KNOT_EINVAL;
515 	}
516 
517 	/* No TSIG record means verification failure. */
518 	if (tsig_rr == NULL) {
519 		return KNOT_TSIG_EBADKEY;
520 	}
521 
522 	/* Check that libknot knows the algorithm. */
523 	int ret = check_algorithm(tsig_rr);
524 	if (ret != KNOT_EOK) {
525 		return ret;
526 	}
527 
528 	/* Check that key is valid, ie. the same as given in args. */
529 	ret = check_key(tsig_rr, tsig_key);
530 	if (ret != KNOT_EOK) {
531 		return ret;
532 	}
533 
534 	uint8_t *wire_to_sign = malloc(size);
535 	if (!wire_to_sign) {
536 		return KNOT_ENOMEM;
537 	}
538 
539 	memcpy(wire_to_sign, wire, size);
540 
541 	// restore message ID to which the signature had been created with
542 	knot_wire_set_id(wire_to_sign, knot_tsig_rdata_orig_id(tsig_rr));
543 
544 	uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
545 	size_t digest_tmp_len = 0;
546 	assert(tsig_rr->rrs.count > 0);
547 
548 	if (use_times) {
549 		/* Wire is not a single packet, TSIG RRs must be stripped already. */
550 		ret = create_sign_wire_next(wire_to_sign, size,
551 		                            request_mac, request_mac_len,
552 		                            digest_tmp, &digest_tmp_len,
553 		                            tsig_rr, tsig_key);
554 	} else {
555 		ret = create_sign_wire(wire_to_sign, size,
556 		                       request_mac, request_mac_len,
557 		                       digest_tmp, &digest_tmp_len,
558 		                       tsig_rr, tsig_key);
559 	}
560 
561 	assert(tsig_rr->rrs.count > 0);
562 	free(wire_to_sign);
563 
564 	if (ret != KNOT_EOK) {
565 		return ret;
566 	}
567 
568 	/* Compare MAC from TSIG RR RDATA with just computed digest. */
569 
570 	/*!< \todo move to function. */
571 	const knot_dname_t *alg_name = knot_tsig_rdata_alg_name(tsig_rr);
572 	dnssec_tsig_algorithm_t alg = dnssec_tsig_algorithm_from_dname(alg_name);
573 
574 	/*! \todo [TSIG] TRUNCATION */
575 	uint16_t mac_length = knot_tsig_rdata_mac_length(tsig_rr);
576 	const uint8_t *tsig_mac = knot_tsig_rdata_mac(tsig_rr);
577 
578 	if (mac_length != dnssec_tsig_algorithm_size(alg)) {
579 		return KNOT_TSIG_EBADSIG;
580 	}
581 
582 	if (const_time_memcmp(tsig_mac, digest_tmp, mac_length) != 0) {
583 		return KNOT_TSIG_EBADSIG;
584 	}
585 
586 	/* Check TSIG validity period, must be after the signature check! */
587 	ret = check_time_signed(tsig_rr, prev_time_signed);
588 	if (ret != KNOT_EOK) {
589 		return ret;
590 	}
591 
592 	return KNOT_EOK;
593 }
594 
595 _public_
knot_tsig_server_check(const knot_rrset_t * tsig_rr,const uint8_t * wire,size_t size,const knot_tsig_key_t * tsig_key)596 int knot_tsig_server_check(const knot_rrset_t *tsig_rr,
597                            const uint8_t *wire, size_t size,
598                            const knot_tsig_key_t *tsig_key)
599 {
600 	return check_digest(tsig_rr, wire, size, NULL, 0, tsig_key, 0, 0);
601 }
602 
603 _public_
knot_tsig_client_check(const knot_rrset_t * tsig_rr,const uint8_t * wire,size_t size,const uint8_t * request_mac,size_t request_mac_len,const knot_tsig_key_t * tsig_key,uint64_t prev_time_signed)604 int knot_tsig_client_check(const knot_rrset_t *tsig_rr,
605                            const uint8_t *wire, size_t size,
606                            const uint8_t *request_mac, size_t request_mac_len,
607                            const knot_tsig_key_t *tsig_key,
608                            uint64_t prev_time_signed)
609 {
610 	return check_digest(tsig_rr, wire, size, request_mac, request_mac_len,
611 	                    tsig_key, prev_time_signed, 0);
612 }
613 
614 _public_
knot_tsig_client_check_next(const knot_rrset_t * tsig_rr,const uint8_t * wire,size_t size,const uint8_t * prev_digest,size_t prev_digest_len,const knot_tsig_key_t * tsig_key,uint64_t prev_time_signed)615 int knot_tsig_client_check_next(const knot_rrset_t *tsig_rr,
616                                 const uint8_t *wire, size_t size,
617                                 const uint8_t *prev_digest,
618                                 size_t prev_digest_len,
619                                 const knot_tsig_key_t *tsig_key,
620                                 uint64_t prev_time_signed)
621 {
622 	return check_digest(tsig_rr, wire, size, prev_digest,
623 	                    prev_digest_len, tsig_key, prev_time_signed, 1);
624 }
625 
626 _public_
knot_tsig_add(uint8_t * msg,size_t * msg_len,size_t msg_max_len,uint16_t tsig_rcode,const knot_rrset_t * tsig_rr)627 int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
628                   uint16_t tsig_rcode, const knot_rrset_t *tsig_rr)
629 {
630 	/*! \todo Revise!! */
631 
632 	if (!msg || !msg_len || !tsig_rr) {
633 		return KNOT_EINVAL;
634 	}
635 
636 	/*! \todo What key to use, when we do not sign? Does this even work? */
637 	knot_rrset_t *tmp_tsig = knot_rrset_new(tsig_rr->owner, KNOT_RRTYPE_TSIG,
638 		                                KNOT_CLASS_ANY, 0, NULL);
639 	if (!tmp_tsig) {
640 		return KNOT_ENOMEM;
641 	}
642 
643 	assert(tsig_rcode != KNOT_RCODE_BADTIME);
644 	knot_tsig_create_rdata(tmp_tsig, knot_tsig_rdata_alg_name(tsig_rr), 0, tsig_rcode);
645 	knot_tsig_rdata_set_time_signed(tmp_tsig, knot_tsig_rdata_time_signed(tsig_rr));
646 
647 	/* Comparing to BIND it was found out that the Fudge should always be
648 	 * set to the server's value.
649 	 */
650 	knot_tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT);
651 
652 	/* Set original ID */
653 	knot_tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));
654 
655 	/* Set other len. */
656 	knot_tsig_rdata_set_other_data(tmp_tsig, 0, 0);
657 
658 	/* Append TSIG RR. */
659 	int ret = knot_tsig_append(msg, msg_len, msg_max_len, tmp_tsig);
660 
661 	/* key_name already referenced in RRSet, no need to free separately. */
662 	knot_rrset_free(tmp_tsig, NULL);
663 
664 	return ret;
665 }
666 
667 _public_
knot_tsig_append(uint8_t * msg,size_t * msg_len,size_t msg_max_len,const knot_rrset_t * tsig_rr)668 int knot_tsig_append(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
669                      const knot_rrset_t *tsig_rr)
670 {
671 	/* Write RRSet to wire */
672 	int ret = knot_rrset_to_wire(tsig_rr, msg + *msg_len,
673 	                             msg_max_len - *msg_len, NULL);
674 	if (ret < 0) {
675 		return ret;
676 	}
677 
678 	*msg_len += ret;
679 
680 	knot_wire_set_arcount(msg, knot_wire_get_arcount(msg) + 1);
681 
682 	return KNOT_EOK;
683 }
684