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