Coverage Report

Created: 2026-09-06 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/tsig.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <inttypes.h>
17
#include <stdbool.h>
18
#include <stdlib.h>
19
20
#include <isc/buffer.h>
21
#include <isc/hashmap.h>
22
#include <isc/log.h>
23
#include <isc/mem.h>
24
#include <isc/refcount.h>
25
#include <isc/result.h>
26
#include <isc/serial.h>
27
#include <isc/string.h>
28
#include <isc/time.h>
29
#include <isc/util.h>
30
31
#include <dns/fixedname.h>
32
#include <dns/keyvalues.h>
33
#include <dns/message.h>
34
#include <dns/rdata.h>
35
#include <dns/rdatalist.h>
36
#include <dns/rdataset.h>
37
#include <dns/rdatastruct.h>
38
#include <dns/tsig.h>
39
40
#include "tsig_p.h"
41
42
6
#define TSIGKEYRING_MAGIC    ISC_MAGIC('T', 'K', 'R', 'g')
43
#define VALID_TSIGKEYRING(x) ISC_MAGIC_VALID(x, TSIGKEYRING_MAGIC)
44
45
356
#define TSIG_MAGIC   ISC_MAGIC('T', 'S', 'I', 'G')
46
#define VALID_TSIGKEY(x) ISC_MAGIC_VALID(x, TSIG_MAGIC)
47
48
636
#define is_response(msg) ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
49
50
0
#define BADTIMELEN 6
51
52
static unsigned char hmacmd5_ndata[] = "\010hmac-md5\007sig-alg\003reg\003int";
53
54
static dns_name_t const hmacmd5 = DNS_NAME_INITABSOLUTE(hmacmd5_ndata);
55
const dns_name_t *dns_tsig_hmacmd5_name = &hmacmd5;
56
57
static unsigned char gsstsig_ndata[] = "\010gss-tsig";
58
static dns_name_t const gsstsig = DNS_NAME_INITABSOLUTE(gsstsig_ndata);
59
const dns_name_t *dns_tsig_gssapi_name = &gsstsig;
60
61
static unsigned char hmacsha1_ndata[] = "\011hmac-sha1";
62
static dns_name_t const hmacsha1 = DNS_NAME_INITABSOLUTE(hmacsha1_ndata);
63
const dns_name_t *dns_tsig_hmacsha1_name = &hmacsha1;
64
65
static unsigned char hmacsha224_ndata[] = "\013hmac-sha224";
66
static dns_name_t const hmacsha224 = DNS_NAME_INITABSOLUTE(hmacsha224_ndata);
67
const dns_name_t *dns_tsig_hmacsha224_name = &hmacsha224;
68
69
static unsigned char hmacsha256_ndata[] = "\013hmac-sha256";
70
static dns_name_t const hmacsha256 = DNS_NAME_INITABSOLUTE(hmacsha256_ndata);
71
const dns_name_t *dns_tsig_hmacsha256_name = &hmacsha256;
72
73
static unsigned char hmacsha384_ndata[] = "\013hmac-sha384";
74
static dns_name_t const hmacsha384 = DNS_NAME_INITABSOLUTE(hmacsha384_ndata);
75
const dns_name_t *dns_tsig_hmacsha384_name = &hmacsha384;
76
77
static unsigned char hmacsha512_ndata[] = "\013hmac-sha512";
78
static dns_name_t const hmacsha512 = DNS_NAME_INITABSOLUTE(hmacsha512_ndata);
79
const dns_name_t *dns_tsig_hmacsha512_name = &hmacsha512;
80
81
static const struct {
82
  const dns_name_t *name;
83
  unsigned int dstalg;
84
} known_algs[] = { { &hmacmd5, DST_ALG_HMACMD5 },
85
       { &gsstsig, DST_ALG_GSSAPI },
86
       { &hmacsha1, DST_ALG_HMACSHA1 },
87
       { &hmacsha224, DST_ALG_HMACSHA224 },
88
       { &hmacsha256, DST_ALG_HMACSHA256 },
89
       { &hmacsha384, DST_ALG_HMACSHA384 },
90
       { &hmacsha512, DST_ALG_HMACSHA512 } };
91
92
static isc_result_t
93
tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg);
94
95
static void
96
tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...)
97
  ISC_FORMAT_PRINTF(3, 4);
98
99
bool
100
558
dns__tsig_algvalid(unsigned int alg) {
101
558
  return alg == DST_ALG_HMACMD5 || alg == DST_ALG_HMACSHA1 ||
102
553
         alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
103
347
         alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512;
104
558
}
105
106
static void
107
932
tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
108
932
  va_list ap;
109
932
  char message[4096];
110
932
  char namestr[DNS_NAME_FORMATSIZE];
111
932
  char creatorstr[DNS_NAME_FORMATSIZE];
112
113
932
  if (!isc_log_wouldlog(level)) {
114
932
    return;
115
932
  }
116
0
  if (key != NULL) {
117
0
    dns_name_format(key->name, namestr, sizeof(namestr));
118
0
  } else {
119
0
    strlcpy(namestr, "<null>", sizeof(namestr));
120
0
  }
121
122
0
  if (key != NULL && key->generated && key->creator != NULL) {
123
0
    dns_name_format(key->creator, creatorstr, sizeof(creatorstr));
124
0
  } else {
125
0
    strlcpy(creatorstr, "<null>", sizeof(creatorstr));
126
0
  }
127
128
0
  va_start(ap, fmt);
129
0
  vsnprintf(message, sizeof(message), fmt, ap);
130
0
  va_end(ap);
131
0
  if (key != NULL && key->generated) {
132
0
    isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, level,
133
0
            "tsig key '%s' (%s): %s", namestr, creatorstr,
134
0
            message);
135
0
  } else {
136
0
    isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, level,
137
0
            "tsig key '%s': %s", namestr, message);
138
0
  }
139
0
}
140
141
static bool
142
246
tkey_match(void *node, const void *key) {
143
246
  dns_tsigkey_t *tkey = node;
144
145
246
  return dns_name_equal(tkey->name, key);
146
246
}
147
148
static bool
149
0
match_ptr(void *node, const void *key) {
150
0
  return node == key;
151
0
}
152
153
isc_result_t
154
dns_tsigkey_createfromkey(const dns_name_t *name, dst_algorithm_t algorithm,
155
        dst_key_t *dstkey, bool generated, bool restored,
156
        const dns_name_t *creator, isc_stdtime_t inception,
157
        isc_stdtime_t expire, isc_mem_t *mctx,
158
356
        dns_tsigkey_t **keyp) {
159
356
  dns_tsigkey_t *tkey = NULL;
160
356
  isc_result_t result;
161
162
356
  REQUIRE(keyp != NULL && *keyp == NULL);
163
356
  REQUIRE(name != NULL);
164
356
  REQUIRE(mctx != NULL);
165
166
356
  tkey = isc_mem_get(mctx, sizeof(dns_tsigkey_t));
167
356
  *tkey = (dns_tsigkey_t){
168
356
    .generated = generated,
169
356
    .restored = restored,
170
356
    .inception = inception,
171
356
    .expire = expire,
172
356
    .alg = algorithm,
173
356
    .algname = DNS_NAME_INITEMPTY,
174
356
    .lrulink = ISC_LINK_INITIALIZER,
175
356
  };
176
177
356
  tkey->name = dns_fixedname_initname(&tkey->fn);
178
356
  dns_name_copy(name, tkey->name);
179
356
  (void)dns_name_downcase(tkey->name, tkey->name);
180
181
356
  if (algorithm != DST_ALG_UNKNOWN) {
182
12
    if (dstkey != NULL && dst_key_alg(dstkey) != algorithm) {
183
0
      result = DNS_R_BADALG;
184
0
      goto cleanup_name;
185
0
    }
186
344
  } else if (dstkey != NULL) {
187
0
    result = DNS_R_BADALG;
188
0
    goto cleanup_name;
189
0
  }
190
191
356
  if (creator != NULL) {
192
0
    tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t));
193
0
    dns_name_init(tkey->creator);
194
0
    dns_name_dup(creator, mctx, tkey->creator);
195
0
  }
196
197
356
  if (dstkey != NULL) {
198
2
    dst_key_attach(dstkey, &tkey->key);
199
2
  }
200
201
356
  isc_refcount_init(&tkey->references, 1);
202
356
  isc_mem_attach(mctx, &tkey->mctx);
203
204
  /*
205
   * Ignore this if it's a GSS key, since the key size is meaningless.
206
   */
207
356
  if (dstkey != NULL && dst_key_size(dstkey) < 64 &&
208
0
      algorithm != DST_ALG_GSSAPI)
209
0
  {
210
0
    char namestr[DNS_NAME_FORMATSIZE];
211
0
    dns_name_format(name, namestr, sizeof(namestr));
212
0
    isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
213
0
            ISC_LOG_INFO,
214
0
            "the key '%s' is too short to be secure",
215
0
            namestr);
216
0
  }
217
218
356
  tkey->magic = TSIG_MAGIC;
219
220
356
  if (tkey->restored) {
221
0
    tsig_log(tkey, ISC_LOG_DEBUG(3), "restored from file");
222
356
  } else if (tkey->generated) {
223
0
    tsig_log(tkey, ISC_LOG_DEBUG(3), "generated");
224
356
  } else {
225
356
    tsig_log(tkey, ISC_LOG_DEBUG(3), "statically configured");
226
356
  }
227
228
356
  SET_IF_NOT_NULL(keyp, tkey);
229
356
  return ISC_R_SUCCESS;
230
231
0
cleanup_name:
232
0
  isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t));
233
234
0
  return result;
235
356
}
236
237
static void
238
0
dns__tsigkey_deletelru(dns_tsigkeyring_t *ring, dns_tsigkey_t *tkey) {
239
0
  if (tkey->generated && ISC_SIEVE_LINKED(tkey, lrulink)) {
240
0
    ISC_SIEVE_UNLINK(ring->lrulist, tkey, lrulink);
241
0
    ring->generated--;
242
0
  }
243
0
}
244
245
static void
246
0
destroyring(dns_tsigkeyring_t *ring) {
247
0
  isc_result_t result;
248
0
  isc_hashmap_iter_t *it = NULL;
249
250
0
  RWLOCK(&ring->lock, isc_rwlocktype_write);
251
0
  isc_hashmap_iter_create(ring->keys, &it);
252
0
  for (result = isc_hashmap_iter_first(it); result == ISC_R_SUCCESS;
253
0
       result = isc_hashmap_iter_delcurrent_next(it))
254
0
  {
255
0
    dns_tsigkey_t *tkey = NULL;
256
0
    isc_hashmap_iter_current(it, (void **)&tkey);
257
258
0
    dns__tsigkey_deletelru(ring, tkey);
259
0
    dns_tsigkey_detach(&tkey);
260
0
  }
261
0
  isc_hashmap_iter_destroy(&it);
262
0
  isc_hashmap_destroy(&ring->keys);
263
0
  RWUNLOCK(&ring->lock, isc_rwlocktype_write);
264
265
0
  ring->magic = 0;
266
267
0
  isc_rwlock_destroy(&ring->lock);
268
0
  isc_mem_putanddetach(&ring->mctx, ring, sizeof(dns_tsigkeyring_t));
269
0
}
270
271
#if DNS_TSIG_TRACE
272
ISC_REFCOUNT_TRACE_IMPL(dns_tsigkeyring, destroyring);
273
#else
274
3.45k
ISC_REFCOUNT_IMPL(dns_tsigkeyring, destroyring);
dns_tsigkeyring_ref
Line
Count
Source
274
ISC_REFCOUNT_IMPL(dns_tsigkeyring, destroyring);
dns_tsigkeyring_unref
Line
Count
Source
274
ISC_REFCOUNT_IMPL(dns_tsigkeyring, destroyring);
dns_tsigkeyring_detach
Line
Count
Source
274
ISC_REFCOUNT_IMPL(dns_tsigkeyring, destroyring);
275
3.45k
#endif
276
3.45k
277
3.45k
/*
278
3.45k
 * Look up the DST_ALG_ constant for a given name.
279
3.45k
 */
280
3.45k
dst_algorithm_t
281
3.45k
dns__tsig_algfromname(const dns_name_t *algorithm) {
282
4.72k
  for (size_t i = 0; i < ARRAY_SIZE(known_algs); ++i) {
283
4.14k
    const dns_name_t *name = known_algs[i].name;
284
4.14k
    if (algorithm == name || dns_name_equal(algorithm, name)) {
285
18
      return known_algs[i].dstalg;
286
18
    }
287
4.14k
  }
288
582
  return DST_ALG_UNKNOWN;
289
600
}
290
291
static isc_result_t
292
0
restore_key(dns_tsigkeyring_t *ring, isc_stdtime_t now, FILE *fp) {
293
0
  dst_key_t *dstkey = NULL;
294
0
  char namestr[1024];
295
0
  char creatorstr[1024];
296
0
  char algorithmstr[1024];
297
0
  char keystr[4096];
298
0
  unsigned int inception, expire;
299
0
  int n;
300
0
  isc_buffer_t b;
301
0
  dns_name_t *name = NULL, *creator = NULL, *algorithm = NULL;
302
0
  dns_fixedname_t fname, fcreator, falgorithm;
303
0
  isc_result_t result;
304
0
  unsigned int dstalg;
305
0
  dns_tsigkey_t *tkey = NULL;
306
307
0
  n = fscanf(fp, "%1023s %1023s %u %u %1023s %4095s\n", namestr,
308
0
       creatorstr, &inception, &expire, algorithmstr, keystr);
309
0
  if (n == EOF) {
310
0
    return ISC_R_NOMORE;
311
0
  }
312
0
  if (n != 6) {
313
0
    return ISC_R_FAILURE;
314
0
  }
315
316
0
  if (isc_serial_lt(expire, now)) {
317
0
    return DNS_R_EXPIRED;
318
0
  }
319
320
0
  name = dns_fixedname_initname(&fname);
321
0
  isc_buffer_init(&b, namestr, strlen(namestr));
322
0
  isc_buffer_add(&b, strlen(namestr));
323
0
  RETERR(dns_name_fromtext(name, &b, dns_rootname, 0));
324
325
0
  creator = dns_fixedname_initname(&fcreator);
326
0
  isc_buffer_init(&b, creatorstr, strlen(creatorstr));
327
0
  isc_buffer_add(&b, strlen(creatorstr));
328
0
  RETERR(dns_name_fromtext(creator, &b, dns_rootname, 0));
329
330
0
  algorithm = dns_fixedname_initname(&falgorithm);
331
0
  isc_buffer_init(&b, algorithmstr, strlen(algorithmstr));
332
0
  isc_buffer_add(&b, strlen(algorithmstr));
333
0
  RETERR(dns_name_fromtext(algorithm, &b, dns_rootname, 0));
334
335
0
  dstalg = dns__tsig_algfromname(algorithm);
336
0
  if (dstalg == DST_ALG_UNKNOWN) {
337
0
    return DNS_R_BADALG;
338
0
  }
339
340
0
  RETERR(dst_key_restore(name, dstalg, 0, DNS_KEYPROTO_DNSSEC,
341
0
             dns_rdataclass_in, ring->mctx, keystr, &dstkey));
342
343
0
  result = dns_tsigkey_createfromkey(name, dstalg, dstkey, true, true,
344
0
             creator, inception, expire,
345
0
             ring->mctx, &tkey);
346
0
  if (result == ISC_R_SUCCESS) {
347
0
    result = dns_tsigkeyring_add(ring, tkey);
348
0
  }
349
0
  dns_tsigkey_detach(&tkey);
350
0
  if (dstkey != NULL) {
351
0
    dst_key_free(&dstkey);
352
0
  }
353
0
  return result;
354
0
}
355
356
static void
357
0
dump_key(dns_tsigkey_t *tkey, FILE *fp) {
358
0
  char *buffer = NULL;
359
0
  int length = 0;
360
0
  char namestr[DNS_NAME_FORMATSIZE];
361
0
  char creatorstr[DNS_NAME_FORMATSIZE];
362
0
  char algorithmstr[DNS_NAME_FORMATSIZE];
363
0
  isc_result_t result;
364
365
0
  REQUIRE(tkey != NULL);
366
0
  REQUIRE(fp != NULL);
367
368
0
  dns_name_format(tkey->name, namestr, sizeof(namestr));
369
0
  dns_name_format(tkey->creator, creatorstr, sizeof(creatorstr));
370
0
  dns_name_format(dns_tsigkey_algorithm(tkey), algorithmstr,
371
0
      sizeof(algorithmstr));
372
0
  result = dst_key_dump(tkey->key, tkey->mctx, &buffer, &length);
373
0
  if (result == ISC_R_SUCCESS) {
374
0
    fprintf(fp, "%s %s %u %u %s %.*s\n", namestr, creatorstr,
375
0
      tkey->inception, tkey->expire, algorithmstr, length,
376
0
      buffer);
377
0
  }
378
0
  if (buffer != NULL) {
379
0
    isc_mem_put(tkey->mctx, buffer, length);
380
0
  }
381
0
}
382
383
isc_result_t
384
0
dns_tsigkeyring_dump(dns_tsigkeyring_t *ring, FILE *fp) {
385
0
  isc_result_t result;
386
0
  isc_stdtime_t now = isc_stdtime_now();
387
0
  isc_hashmap_iter_t *it = NULL;
388
0
  bool found = false;
389
390
0
  REQUIRE(VALID_TSIGKEYRING(ring));
391
392
0
  RWLOCK(&ring->lock, isc_rwlocktype_read);
393
0
  isc_hashmap_iter_create(ring->keys, &it);
394
0
  for (result = isc_hashmap_iter_first(it); result == ISC_R_SUCCESS;
395
0
       result = isc_hashmap_iter_next(it))
396
0
  {
397
0
    dns_tsigkey_t *tkey = NULL;
398
0
    isc_hashmap_iter_current(it, (void **)&tkey);
399
400
0
    if (tkey->generated && tkey->expire >= now) {
401
0
      dump_key(tkey, fp);
402
0
      found = true;
403
0
    }
404
0
  }
405
0
  isc_hashmap_iter_destroy(&it);
406
0
  RWUNLOCK(&ring->lock, isc_rwlocktype_read);
407
408
0
  return found ? ISC_R_SUCCESS : ISC_R_NOTFOUND;
409
0
}
410
411
const dns_name_t *
412
0
dns_tsigkey_identity(const dns_tsigkey_t *tsigkey) {
413
0
  REQUIRE(tsigkey == NULL || VALID_TSIGKEY(tsigkey));
414
415
0
  if (tsigkey == NULL) {
416
0
    return NULL;
417
0
  }
418
0
  if (tsigkey->generated) {
419
0
    return tsigkey->creator;
420
0
  } else {
421
0
    return tsigkey->name;
422
0
  }
423
0
}
424
425
isc_result_t
426
dns_tsigkey_create(const dns_name_t *name, dst_algorithm_t algorithm,
427
       unsigned char *secret, int length, isc_mem_t *mctx,
428
356
       dns_tsigkey_t **key) {
429
356
  dst_key_t *dstkey = NULL;
430
356
  isc_result_t result;
431
432
356
  REQUIRE(length >= 0);
433
356
  if (length > 0) {
434
2
    REQUIRE(secret != NULL);
435
2
  }
436
437
356
  if (dns__tsig_algvalid(algorithm)) {
438
11
    if (secret != NULL) {
439
2
      isc_buffer_t b;
440
441
2
      isc_buffer_init(&b, secret, length);
442
2
      isc_buffer_add(&b, length);
443
2
      RETERR(dst_key_frombuffer(
444
2
        name, algorithm, 0, DNS_KEYPROTO_DNSSEC,
445
2
        dns_rdataclass_in, &b, mctx, &dstkey));
446
2
    }
447
345
  } else if (length > 0) {
448
0
    return DNS_R_BADALG;
449
0
  }
450
451
356
  result = dns_tsigkey_createfromkey(name, algorithm, dstkey, false,
452
356
             false, NULL, 0, 0, mctx, key);
453
356
  if (dstkey != NULL) {
454
2
    dst_key_free(&dstkey);
455
2
  }
456
356
  return result;
457
356
}
458
459
static void
460
354
destroy_tsigkey(dns_tsigkey_t *key) {
461
354
  REQUIRE(VALID_TSIGKEY(key));
462
463
354
  key->magic = 0;
464
354
  if (key->key != NULL) {
465
0
    dst_key_free(&key->key);
466
0
  }
467
354
  if (key->creator != NULL) {
468
0
    dns_name_free(key->creator, key->mctx);
469
0
    isc_mem_put(key->mctx, key->creator, sizeof(dns_name_t));
470
0
  }
471
354
  isc_mem_putanddetach(&key->mctx, key, sizeof(dns_tsigkey_t));
472
354
}
473
474
#if DNS_TSIG_TRACE
475
ISC_REFCOUNT_TRACE_IMPL(dns_tsigkey, destroy_tsigkey);
476
#else
477
1.55k
ISC_REFCOUNT_IMPL(dns_tsigkey, destroy_tsigkey);
dns_tsigkey_ref
Line
Count
Source
477
ISC_REFCOUNT_IMPL(dns_tsigkey, destroy_tsigkey);
dns_tsigkey_unref
Line
Count
Source
477
ISC_REFCOUNT_IMPL(dns_tsigkey, destroy_tsigkey);
dns_tsigkey_detach
Line
Count
Source
477
ISC_REFCOUNT_IMPL(dns_tsigkey, destroy_tsigkey);
478
1.55k
#endif
479
1.55k
480
1.55k
static void
481
1.55k
dns__tsigkey_delete(dns_tsigkeyring_t *ring, dns_tsigkey_t *tkey) {
482
0
  isc_result_t result = isc_hashmap_delete(
483
0
    ring->keys, dns_name_hash(tkey->name), match_ptr, tkey);
484
0
  if (result == ISC_R_SUCCESS) {
485
0
    dns__tsigkey_deletelru(ring, tkey);
486
0
    dns_tsigkey_detach(&tkey);
487
0
  }
488
0
}
489
490
void
491
0
dns_tsigkey_delete(dns_tsigkeyring_t *ring, dns_tsigkey_t *tkey) {
492
0
  REQUIRE(VALID_TSIGKEY(tkey));
493
0
  REQUIRE(VALID_TSIGKEYRING(ring));
494
495
0
  RWLOCK(&ring->lock, isc_rwlocktype_write);
496
0
  dns__tsigkey_delete(ring, tkey);
497
0
  RWUNLOCK(&ring->lock, isc_rwlocktype_write);
498
0
}
499
500
isc_result_t
501
0
dns_tsig_sign(dns_message_t *msg) {
502
0
  dns_tsigkey_t *key = NULL;
503
0
  dns_rdata_any_tsig_t tsig, querytsig;
504
0
  unsigned char data[128];
505
0
  isc_buffer_t databuf, sigbuf;
506
0
  isc_buffer_t *dynbuf = NULL;
507
0
  dns_name_t *owner = NULL;
508
0
  dns_rdata_t *rdata = NULL;
509
0
  dns_rdatalist_t *datalist = NULL;
510
0
  dns_rdataset_t *dataset = NULL;
511
0
  isc_region_t r;
512
0
  isc_stdtime_t now;
513
0
  isc_mem_t *mctx = NULL;
514
0
  dst_context_t *ctx = NULL;
515
0
  isc_result_t result;
516
0
  unsigned char badtimedata[BADTIMELEN];
517
0
  unsigned int sigsize = 0;
518
0
  bool response;
519
520
0
  REQUIRE(msg != NULL);
521
0
  key = dns_message_gettsigkey(msg);
522
0
  REQUIRE(VALID_TSIGKEY(key));
523
524
  /*
525
   * If this is a response, there should be a TSIG in the query with the
526
   * the exception if this is a TKEY request (see RFC 3645, Section 2.2).
527
   */
528
0
  response = is_response(msg);
529
0
  if (response && msg->querytsig == NULL) {
530
0
    if (msg->tkey != 1) {
531
0
      return DNS_R_EXPECTEDTSIG;
532
0
    }
533
0
  }
534
535
0
  mctx = msg->mctx;
536
537
0
  now = msg->fuzzing ? msg->fuzztime : isc_stdtime_now();
538
0
  tsig = (dns_rdata_any_tsig_t){
539
0
    .mctx = mctx,
540
0
    .common.rdclass = dns_rdataclass_any,
541
0
    .common.rdtype = dns_rdatatype_tsig,
542
0
    .timesigned = now + msg->timeadjust,
543
0
    .fudge = DNS_TSIG_FUDGE,
544
0
    .originalid = msg->id,
545
0
    .error = response ? msg->querytsigstatus : dns_rcode_noerror,
546
0
  };
547
548
0
  dns_name_init(&tsig.algorithm);
549
0
  dns_name_clone(dns_tsigkey_algorithm(key), &tsig.algorithm);
550
551
0
  isc_buffer_init(&databuf, data, sizeof(data));
552
553
0
  if (tsig.error == dns_tsigerror_badtime) {
554
0
    isc_buffer_t otherbuf;
555
556
0
    tsig.otherlen = BADTIMELEN;
557
0
    tsig.other = badtimedata;
558
0
    isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
559
0
    isc_buffer_putuint48(&otherbuf, tsig.timesigned);
560
0
  }
561
562
0
  if (key->key != NULL && tsig.error != dns_tsigerror_badsig &&
563
0
      tsig.error != dns_tsigerror_badkey &&
564
0
      tsig.error != dns_tsigerror_badtrunc)
565
0
  {
566
0
    unsigned char header[DNS_MESSAGE_HEADERLEN];
567
0
    isc_buffer_t headerbuf;
568
0
    uint16_t digestbits;
569
0
    bool querytsig_ok = false;
570
571
    /*
572
     * If it is a response, we assume that the request MAC
573
     * has validated at this point. This is why we include a
574
     * MAC length > 0 in the reply.
575
     */
576
0
    RETERR(dst_context_create(key->key, mctx,
577
0
            DNS_LOGCATEGORY_DNSSEC, true, &ctx));
578
579
    /*
580
     * If this is a response, and if there was a TSIG in
581
     * the query, digest the request's MAC.
582
     *
583
     * (Note: querytsig should be non-NULL for all
584
     * responses except TKEY responses. Those may be signed
585
     * with the newly-negotiated TSIG key even if the query
586
     * wasn't signed.)
587
     */
588
0
    if (response && msg->querytsig != NULL) {
589
0
      dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
590
591
0
      INSIST(msg->verified_sig);
592
593
0
      result = dns_rdataset_first(msg->querytsig);
594
0
      if (result != ISC_R_SUCCESS) {
595
0
        goto cleanup_context;
596
0
      }
597
0
      dns_rdataset_current(msg->querytsig, &querytsigrdata);
598
0
      result = dns_rdata_tostruct(&querytsigrdata, &querytsig,
599
0
                NULL);
600
0
      if (result != ISC_R_SUCCESS) {
601
0
        goto cleanup_context;
602
0
      }
603
0
      isc_buffer_putuint16(&databuf, querytsig.siglen);
604
0
      if (isc_buffer_availablelength(&databuf) <
605
0
          querytsig.siglen)
606
0
      {
607
0
        result = ISC_R_NOSPACE;
608
0
        goto cleanup_context;
609
0
      }
610
0
      isc_buffer_putmem(&databuf, querytsig.signature,
611
0
            querytsig.siglen);
612
0
      isc_buffer_usedregion(&databuf, &r);
613
0
      result = dst_context_adddata(ctx, &r);
614
0
      if (result != ISC_R_SUCCESS) {
615
0
        goto cleanup_context;
616
0
      }
617
0
      querytsig_ok = true;
618
0
    }
619
620
    /*
621
     * Digest the header.
622
     */
623
0
    isc_buffer_init(&headerbuf, header, sizeof(header));
624
0
    dns_message_renderheader(msg, &headerbuf);
625
0
    isc_buffer_usedregion(&headerbuf, &r);
626
0
    result = dst_context_adddata(ctx, &r);
627
0
    if (result != ISC_R_SUCCESS) {
628
0
      goto cleanup_context;
629
0
    }
630
631
    /*
632
     * Digest the remainder of the message.
633
     */
634
0
    isc_buffer_usedregion(msg->buffer, &r);
635
0
    isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
636
0
    result = dst_context_adddata(ctx, &r);
637
0
    if (result != ISC_R_SUCCESS) {
638
0
      goto cleanup_context;
639
0
    }
640
641
0
    if (msg->tcp_continuation == 0) {
642
      /*
643
       * Digest the name, class, ttl, alg.
644
       */
645
0
      dns_name_toregion(key->name, &r);
646
0
      result = dst_context_adddata(ctx, &r);
647
0
      if (result != ISC_R_SUCCESS) {
648
0
        goto cleanup_context;
649
0
      }
650
651
0
      isc_buffer_clear(&databuf);
652
0
      isc_buffer_putuint16(&databuf, dns_rdataclass_any);
653
0
      isc_buffer_putuint32(&databuf, 0); /* ttl */
654
0
      isc_buffer_usedregion(&databuf, &r);
655
0
      result = dst_context_adddata(ctx, &r);
656
0
      if (result != ISC_R_SUCCESS) {
657
0
        goto cleanup_context;
658
0
      }
659
660
0
      dns_name_toregion(&tsig.algorithm, &r);
661
0
      result = dst_context_adddata(ctx, &r);
662
0
      if (result != ISC_R_SUCCESS) {
663
0
        goto cleanup_context;
664
0
      }
665
0
    }
666
    /* Digest the timesigned and fudge */
667
0
    isc_buffer_clear(&databuf);
668
0
    if (tsig.error == dns_tsigerror_badtime && querytsig_ok) {
669
0
      tsig.timesigned = querytsig.timesigned;
670
0
    }
671
0
    isc_buffer_putuint48(&databuf, tsig.timesigned);
672
0
    isc_buffer_putuint16(&databuf, tsig.fudge);
673
0
    isc_buffer_usedregion(&databuf, &r);
674
0
    result = dst_context_adddata(ctx, &r);
675
0
    if (result != ISC_R_SUCCESS) {
676
0
      goto cleanup_context;
677
0
    }
678
679
0
    if (msg->tcp_continuation == 0) {
680
      /*
681
       * Digest the error and other data length.
682
       */
683
0
      isc_buffer_clear(&databuf);
684
0
      isc_buffer_putuint16(&databuf, tsig.error);
685
0
      isc_buffer_putuint16(&databuf, tsig.otherlen);
686
687
0
      isc_buffer_usedregion(&databuf, &r);
688
0
      result = dst_context_adddata(ctx, &r);
689
0
      if (result != ISC_R_SUCCESS) {
690
0
        goto cleanup_context;
691
0
      }
692
693
      /*
694
       * Digest other data.
695
       */
696
0
      if (tsig.otherlen > 0) {
697
0
        r.length = tsig.otherlen;
698
0
        r.base = tsig.other;
699
0
        result = dst_context_adddata(ctx, &r);
700
0
        if (result != ISC_R_SUCCESS) {
701
0
          goto cleanup_context;
702
0
        }
703
0
      }
704
0
    }
705
706
0
    result = dst_key_sigsize(key->key, &sigsize);
707
0
    if (result != ISC_R_SUCCESS) {
708
0
      goto cleanup_context;
709
0
    }
710
0
    tsig.signature = isc_mem_get(mctx, sigsize);
711
712
0
    isc_buffer_init(&sigbuf, tsig.signature, sigsize);
713
0
    result = dst_context_sign(ctx, &sigbuf);
714
0
    if (result != ISC_R_SUCCESS) {
715
0
      goto cleanup_signature;
716
0
    }
717
0
    dst_context_destroy(&ctx);
718
0
    digestbits = dst_key_getbits(key->key);
719
0
    if (digestbits != 0) {
720
0
      unsigned int bytes = (digestbits + 7) / 8;
721
0
      if (querytsig_ok && bytes < querytsig.siglen) {
722
0
        bytes = querytsig.siglen;
723
0
      }
724
0
      if (bytes > isc_buffer_usedlength(&sigbuf)) {
725
0
        bytes = isc_buffer_usedlength(&sigbuf);
726
0
      }
727
0
      tsig.siglen = bytes;
728
0
    } else {
729
0
      tsig.siglen = isc_buffer_usedlength(&sigbuf);
730
0
    }
731
0
  } else {
732
0
    tsig.siglen = 0;
733
0
    tsig.signature = NULL;
734
0
  }
735
736
0
  dns_message_gettemprdata(msg, &rdata);
737
0
  isc_buffer_allocate(msg->mctx, &dynbuf, 512);
738
0
  result = dns_rdata_fromstruct(rdata, dns_rdataclass_any,
739
0
              dns_rdatatype_tsig, &tsig, dynbuf);
740
0
  if (result != ISC_R_SUCCESS) {
741
0
    goto cleanup_dynbuf;
742
0
  }
743
744
0
  dns_message_takebuffer(msg, &dynbuf);
745
746
0
  if (tsig.signature != NULL) {
747
0
    isc_mem_put(mctx, tsig.signature, sigsize);
748
0
  }
749
750
0
  dns_message_gettempname(msg, &owner);
751
0
  dns_name_copy(key->name, owner);
752
753
0
  dns_message_gettemprdatalist(msg, &datalist);
754
755
0
  dns_message_gettemprdataset(msg, &dataset);
756
0
  datalist->rdclass = dns_rdataclass_any;
757
0
  datalist->type = dns_rdatatype_tsig;
758
0
  ISC_LIST_APPEND(datalist->rdata, rdata, link);
759
0
  dns_rdatalist_tordataset(datalist, dataset);
760
0
  msg->tsig = dataset;
761
0
  msg->tsigname = owner;
762
763
  /* Windows does not like the tsig name being compressed. */
764
0
  msg->tsigname->attributes.nocompress = true;
765
766
0
  return ISC_R_SUCCESS;
767
768
0
cleanup_dynbuf:
769
0
  isc_buffer_free(&dynbuf);
770
0
  dns_message_puttemprdata(msg, &rdata);
771
0
cleanup_signature:
772
0
  if (tsig.signature != NULL) {
773
0
    isc_mem_put(mctx, tsig.signature, sigsize);
774
0
  }
775
0
cleanup_context:
776
0
  if (ctx != NULL) {
777
0
    dst_context_destroy(&ctx);
778
0
  }
779
0
  return result;
780
0
}
781
782
isc_result_t
783
dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
784
636
    dns_tsigkeyring_t *ring1, dns_tsigkeyring_t *ring2) {
785
636
  dns_rdata_any_tsig_t tsig, querytsig;
786
636
  isc_region_t r, source_r, header_r, sig_r;
787
636
  isc_buffer_t databuf;
788
636
  unsigned char data[32];
789
636
  dns_name_t *keyname = NULL;
790
636
  dns_rdata_t rdata = DNS_RDATA_INIT;
791
636
  isc_stdtime_t now;
792
636
  isc_result_t result;
793
636
  dns_tsigkey_t *tsigkey = NULL;
794
636
  dst_key_t *key = NULL;
795
636
  unsigned char header[DNS_MESSAGE_HEADERLEN];
796
636
  dst_context_t *ctx = NULL;
797
636
  isc_mem_t *mctx = NULL;
798
636
  uint16_t addcount, id;
799
636
  unsigned int siglen;
800
636
  unsigned int alg;
801
636
  bool response;
802
803
636
  REQUIRE(source != NULL);
804
636
  REQUIRE(DNS_MESSAGE_VALID(msg));
805
636
  tsigkey = dns_message_gettsigkey(msg);
806
636
  response = is_response(msg);
807
808
636
  REQUIRE(tsigkey == NULL || VALID_TSIGKEY(tsigkey));
809
810
636
  msg->verify_attempted = 1;
811
636
  msg->verified_sig = 0;
812
636
  msg->tsigstatus = dns_tsigerror_badsig;
813
814
636
  if (msg->tcp_continuation) {
815
0
    if (tsigkey == NULL || msg->querytsig == NULL) {
816
0
      return DNS_R_UNEXPECTEDTSIG;
817
0
    }
818
0
    return tsig_verify_tcp(source, msg);
819
0
  }
820
821
  /*
822
   * There should be a TSIG record...
823
   */
824
636
  if (msg->tsig == NULL) {
825
46
    return DNS_R_EXPECTEDTSIG;
826
46
  }
827
828
  /*
829
   * If this is a response and there's no key or query TSIG, there
830
   * shouldn't be one on the response.
831
   */
832
590
  if (response && (tsigkey == NULL || msg->querytsig == NULL)) {
833
2
    return DNS_R_UNEXPECTEDTSIG;
834
2
  }
835
836
588
  mctx = msg->mctx;
837
838
  /*
839
   * If we're here, we know the message is well formed and contains a
840
   * TSIG record.
841
   */
842
843
588
  keyname = msg->tsigname;
844
588
  RETERR(dns_rdataset_first(msg->tsig));
845
588
  dns_rdataset_current(msg->tsig, &rdata);
846
588
  RETERR(dns_rdata_tostruct(&rdata, &tsig, NULL));
847
588
  dns_rdata_reset(&rdata);
848
588
  if (response) {
849
170
    RETERR(dns_rdataset_first(msg->querytsig));
850
170
    dns_rdataset_current(msg->querytsig, &rdata);
851
170
    RETERR(dns_rdata_tostruct(&rdata, &querytsig, NULL));
852
170
  }
853
854
  /*
855
   * Do the key name and algorithm match that of the query?
856
   */
857
588
  if (response &&
858
170
      (!dns_name_equal(keyname, tsigkey->name) ||
859
170
       !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)))
860
32
  {
861
32
    msg->tsigstatus = dns_tsigerror_badkey;
862
32
    tsig_log(msg->tsigkey, 2,
863
32
       "key name and algorithm do not match");
864
32
    return DNS_R_TSIGVERIFYFAILURE;
865
32
  }
866
867
  /*
868
   * Get the current time.
869
   */
870
556
  if (msg->fuzzing) {
871
556
    now = msg->fuzztime;
872
556
  } else {
873
0
    now = isc_stdtime_now();
874
0
  }
875
876
  /*
877
   * Find dns_tsigkey_t based on keyname.
878
   */
879
556
  if (tsigkey == NULL) {
880
355
    result = ISC_R_NOTFOUND;
881
355
    if (ring1 != NULL) {
882
345
      result = dns_tsigkey_find(&tsigkey, keyname,
883
345
              &tsig.algorithm, ring1);
884
345
    }
885
355
    if (result == ISC_R_NOTFOUND && ring2 != NULL) {
886
344
      result = dns_tsigkey_find(&tsigkey, keyname,
887
344
              &tsig.algorithm, ring2);
888
344
    }
889
355
    if (result != ISC_R_SUCCESS) {
890
354
      msg->tsigstatus = dns_tsigerror_badkey;
891
354
      alg = dns__tsig_algfromname(&tsig.algorithm);
892
354
      RETERR(dns_tsigkey_create(keyname, alg, NULL, 0, mctx,
893
354
              &msg->tsigkey));
894
354
      if (alg == DST_ALG_UNKNOWN) {
895
344
        dns_name_clone(&tsig.algorithm,
896
344
                 &msg->tsigkey->algname);
897
344
      }
898
899
354
      tsig_log(msg->tsigkey, 2, "unknown key");
900
354
      return DNS_R_TSIGVERIFYFAILURE;
901
354
    }
902
1
    msg->tsigkey = tsigkey;
903
1
  }
904
905
202
  key = tsigkey->key;
906
907
  /*
908
   * Check digest length.
909
   */
910
202
  alg = dst_key_alg(key);
911
202
  RETERR(dst_key_sigsize(key, &siglen));
912
202
  if (dns__tsig_algvalid(alg)) {
913
202
    uint16_t digestbits = dst_key_getbits(key);
914
915
202
    if (tsig.siglen > siglen) {
916
11
      tsig_log(msg->tsigkey, 2, "signature length too big");
917
11
      return DNS_R_FORMERR;
918
11
    }
919
191
    if (tsig.siglen > 0 &&
920
48
        (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2)))
921
11
    {
922
11
      tsig_log(msg->tsigkey, 2,
923
11
         "signature length below minimum");
924
11
      return DNS_R_FORMERR;
925
11
    }
926
927
180
    if (tsig.siglen > 0 && digestbits != 0 &&
928
0
        tsig.siglen < ((digestbits + 7) / 8))
929
0
    {
930
0
      msg->tsigstatus = dns_tsigerror_badtrunc;
931
0
      tsig_log(msg->tsigkey, 2,
932
0
         "truncated signature length too small");
933
0
      return DNS_R_TSIGVERIFYFAILURE;
934
0
    }
935
180
    if (tsig.siglen > 0 && digestbits == 0 && tsig.siglen < siglen)
936
10
    {
937
10
      msg->tsigstatus = dns_tsigerror_badtrunc;
938
10
      tsig_log(msg->tsigkey, 2, "signature length too small");
939
10
      return DNS_R_TSIGVERIFYFAILURE;
940
10
    }
941
180
  }
942
943
170
  if (tsig.siglen > 0) {
944
27
    uint16_t addcount_n;
945
946
27
    sig_r.base = tsig.signature;
947
27
    sig_r.length = tsig.siglen;
948
949
27
    RETERR(dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC,
950
27
            false, &ctx));
951
952
27
    if (response) {
953
3
      isc_buffer_init(&databuf, data, sizeof(data));
954
3
      isc_buffer_putuint16(&databuf, querytsig.siglen);
955
3
      isc_buffer_usedregion(&databuf, &r);
956
3
      result = dst_context_adddata(ctx, &r);
957
3
      if (result != ISC_R_SUCCESS) {
958
0
        goto cleanup_context;
959
0
      }
960
3
      if (querytsig.siglen > 0) {
961
3
        r.length = querytsig.siglen;
962
3
        r.base = querytsig.signature;
963
3
        result = dst_context_adddata(ctx, &r);
964
3
        if (result != ISC_R_SUCCESS) {
965
0
          goto cleanup_context;
966
0
        }
967
3
      }
968
3
    }
969
970
    /*
971
     * Extract the header.
972
     */
973
27
    isc_buffer_usedregion(source, &r);
974
27
    memmove(header, r.base, DNS_MESSAGE_HEADERLEN);
975
27
    isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
976
977
    /*
978
     * Decrement the additional field counter.
979
     */
980
27
    memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
981
27
    addcount_n = ntohs(addcount);
982
27
    addcount = htons((uint16_t)(addcount_n - 1));
983
27
    memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
984
985
    /*
986
     * Put in the original id.
987
     */
988
27
    id = htons(tsig.originalid);
989
27
    memmove(&header[0], &id, 2);
990
991
    /*
992
     * Digest the modified header.
993
     */
994
27
    header_r.base = (unsigned char *)header;
995
27
    header_r.length = DNS_MESSAGE_HEADERLEN;
996
27
    result = dst_context_adddata(ctx, &header_r);
997
27
    if (result != ISC_R_SUCCESS) {
998
0
      goto cleanup_context;
999
0
    }
1000
1001
    /*
1002
     * Digest all non-TSIG records.
1003
     */
1004
27
    isc_buffer_usedregion(source, &source_r);
1005
27
    r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1006
27
    r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1007
27
    result = dst_context_adddata(ctx, &r);
1008
27
    if (result != ISC_R_SUCCESS) {
1009
0
      goto cleanup_context;
1010
0
    }
1011
1012
    /*
1013
     * Digest the key name.
1014
     */
1015
27
    dns_name_toregion(tsigkey->name, &r);
1016
27
    result = dst_context_adddata(ctx, &r);
1017
27
    if (result != ISC_R_SUCCESS) {
1018
0
      goto cleanup_context;
1019
0
    }
1020
1021
27
    isc_buffer_init(&databuf, data, sizeof(data));
1022
27
    isc_buffer_putuint16(&databuf, tsig.common.rdclass);
1023
27
    isc_buffer_putuint32(&databuf, msg->tsig->ttl);
1024
27
    isc_buffer_usedregion(&databuf, &r);
1025
27
    result = dst_context_adddata(ctx, &r);
1026
27
    if (result != ISC_R_SUCCESS) {
1027
0
      goto cleanup_context;
1028
0
    }
1029
1030
    /*
1031
     * Digest the key algorithm.
1032
     */
1033
27
    dns_name_toregion(dns_tsigkey_algorithm(tsigkey), &r);
1034
27
    result = dst_context_adddata(ctx, &r);
1035
27
    if (result != ISC_R_SUCCESS) {
1036
0
      goto cleanup_context;
1037
0
    }
1038
1039
27
    isc_buffer_clear(&databuf);
1040
27
    isc_buffer_putuint48(&databuf, tsig.timesigned);
1041
27
    isc_buffer_putuint16(&databuf, tsig.fudge);
1042
27
    isc_buffer_putuint16(&databuf, tsig.error);
1043
27
    isc_buffer_putuint16(&databuf, tsig.otherlen);
1044
27
    isc_buffer_usedregion(&databuf, &r);
1045
27
    result = dst_context_adddata(ctx, &r);
1046
27
    if (result != ISC_R_SUCCESS) {
1047
0
      goto cleanup_context;
1048
0
    }
1049
1050
27
    if (tsig.otherlen > 0) {
1051
23
      r.base = tsig.other;
1052
23
      r.length = tsig.otherlen;
1053
23
      result = dst_context_adddata(ctx, &r);
1054
23
      if (result != ISC_R_SUCCESS) {
1055
0
        goto cleanup_context;
1056
0
      }
1057
23
    }
1058
1059
27
    result = dst_context_verify(ctx, &sig_r);
1060
27
    if (result == DST_R_VERIFYFAILURE) {
1061
25
      result = DNS_R_TSIGVERIFYFAILURE;
1062
25
      tsig_log(msg->tsigkey, 2,
1063
25
         "signature failed to verify(1)");
1064
25
      goto cleanup_context;
1065
25
    } else if (result != ISC_R_SUCCESS) {
1066
0
      goto cleanup_context;
1067
0
    }
1068
2
    msg->verified_sig = 1;
1069
143
  } else if (!response || (tsig.error != dns_tsigerror_badsig &&
1070
103
         tsig.error != dns_tsigerror_badkey))
1071
33
  {
1072
33
    tsig_log(msg->tsigkey, 2, "signature was empty");
1073
33
    return DNS_R_TSIGVERIFYFAILURE;
1074
33
  }
1075
1076
  /*
1077
   * Here at this point, the MAC has been verified. Even if any of
1078
   * the following code returns a TSIG error, the reply will be
1079
   * signed and WILL always include the request MAC in the digest
1080
   * computation.
1081
   */
1082
1083
  /*
1084
   * Is the time ok?
1085
   */
1086
112
  if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
1087
3
    msg->tsigstatus = dns_tsigerror_badtime;
1088
3
    tsig_log(msg->tsigkey, 2, "signature has expired");
1089
3
    result = DNS_R_CLOCKSKEW;
1090
3
    goto cleanup_context;
1091
109
  } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) {
1092
97
    msg->tsigstatus = dns_tsigerror_badtime;
1093
97
    tsig_log(msg->tsigkey, 2, "signature is in the future");
1094
97
    result = DNS_R_CLOCKSKEW;
1095
97
    goto cleanup_context;
1096
97
  }
1097
1098
12
  if (response && tsig.error != dns_rcode_noerror) {
1099
10
    msg->tsigstatus = tsig.error;
1100
10
    if (tsig.error == dns_tsigerror_badtime) {
1101
0
      result = DNS_R_CLOCKSKEW;
1102
10
    } else {
1103
10
      result = DNS_R_TSIGERRORSET;
1104
10
    }
1105
10
    goto cleanup_context;
1106
10
  }
1107
1108
2
  msg->tsigstatus = dns_rcode_noerror;
1109
2
  result = ISC_R_SUCCESS;
1110
1111
137
cleanup_context:
1112
137
  if (ctx != NULL) {
1113
27
    dst_context_destroy(&ctx);
1114
27
  }
1115
1116
137
  return result;
1117
2
}
1118
1119
static isc_result_t
1120
0
tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
1121
0
  dns_rdata_any_tsig_t tsig, querytsig;
1122
0
  isc_region_t r, source_r, header_r, sig_r;
1123
0
  isc_buffer_t databuf;
1124
0
  unsigned char data[32];
1125
0
  dns_name_t *keyname = NULL;
1126
0
  dns_rdata_t rdata = DNS_RDATA_INIT;
1127
0
  isc_stdtime_t now;
1128
0
  isc_result_t result;
1129
0
  dns_tsigkey_t *tsigkey = NULL;
1130
0
  dst_key_t *key = NULL;
1131
0
  unsigned char header[DNS_MESSAGE_HEADERLEN];
1132
0
  uint16_t addcount, id;
1133
0
  bool has_tsig = false;
1134
0
  isc_mem_t *mctx = NULL;
1135
0
  unsigned int siglen;
1136
0
  unsigned int alg;
1137
1138
0
  REQUIRE(source != NULL);
1139
0
  REQUIRE(msg != NULL);
1140
0
  REQUIRE(dns_message_gettsigkey(msg) != NULL);
1141
0
  REQUIRE(msg->tcp_continuation == 1);
1142
0
  REQUIRE(msg->querytsig != NULL);
1143
1144
0
  msg->verified_sig = 0;
1145
0
  msg->tsigstatus = dns_tsigerror_badsig;
1146
1147
0
  if (!is_response(msg)) {
1148
0
    return DNS_R_EXPECTEDRESPONSE;
1149
0
  }
1150
1151
0
  mctx = msg->mctx;
1152
1153
0
  tsigkey = dns_message_gettsigkey(msg);
1154
0
  key = tsigkey->key;
1155
1156
  /*
1157
   * Extract and parse the previous TSIG
1158
   */
1159
0
  RETERR(dns_rdataset_first(msg->querytsig));
1160
0
  dns_rdataset_current(msg->querytsig, &rdata);
1161
0
  RETERR(dns_rdata_tostruct(&rdata, &querytsig, NULL));
1162
0
  dns_rdata_reset(&rdata);
1163
1164
  /*
1165
   * If there is a TSIG in this message, do some checks.
1166
   */
1167
0
  if (msg->tsig != NULL) {
1168
0
    has_tsig = true;
1169
1170
0
    keyname = msg->tsigname;
1171
0
    result = dns_rdataset_first(msg->tsig);
1172
0
    if (result != ISC_R_SUCCESS) {
1173
0
      goto cleanup_querystruct;
1174
0
    }
1175
0
    dns_rdataset_current(msg->tsig, &rdata);
1176
0
    result = dns_rdata_tostruct(&rdata, &tsig, NULL);
1177
0
    if (result != ISC_R_SUCCESS) {
1178
0
      goto cleanup_querystruct;
1179
0
    }
1180
1181
    /*
1182
     * Do the key name and algorithm match that of the query?
1183
     */
1184
0
    if (!dns_name_equal(keyname, tsigkey->name) ||
1185
0
        !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))
1186
0
    {
1187
0
      msg->tsigstatus = dns_tsigerror_badkey;
1188
0
      result = DNS_R_TSIGVERIFYFAILURE;
1189
0
      tsig_log(msg->tsigkey, 2,
1190
0
         "key name and algorithm do not match");
1191
0
      goto cleanup_querystruct;
1192
0
    }
1193
1194
    /*
1195
     * Check digest length.
1196
     */
1197
0
    alg = dst_key_alg(key);
1198
0
    result = dst_key_sigsize(key, &siglen);
1199
0
    if (result != ISC_R_SUCCESS) {
1200
0
      goto cleanup_querystruct;
1201
0
    }
1202
0
    if (dns__tsig_algvalid(alg)) {
1203
0
      uint16_t digestbits = dst_key_getbits(key);
1204
1205
0
      if (tsig.siglen > siglen) {
1206
0
        tsig_log(tsigkey, 2,
1207
0
           "signature length too big");
1208
0
        result = DNS_R_FORMERR;
1209
0
        goto cleanup_querystruct;
1210
0
      }
1211
0
      if (tsig.siglen > 0 &&
1212
0
          (tsig.siglen < 10 ||
1213
0
           tsig.siglen < ((siglen + 1) / 2)))
1214
0
      {
1215
0
        tsig_log(tsigkey, 2,
1216
0
           "signature length below minimum");
1217
0
        result = DNS_R_FORMERR;
1218
0
        goto cleanup_querystruct;
1219
0
      }
1220
1221
0
      if (tsig.siglen > 0 && digestbits != 0 &&
1222
0
          tsig.siglen < ((digestbits + 7) / 8))
1223
0
      {
1224
0
        msg->tsigstatus = dns_tsigerror_badtrunc;
1225
0
        tsig_log(msg->tsigkey, 2,
1226
0
           "truncated signature length "
1227
0
           "too small");
1228
0
        result = DNS_R_TSIGVERIFYFAILURE;
1229
0
        goto cleanup_querystruct;
1230
0
      }
1231
0
      if (tsig.siglen > 0 && digestbits == 0 &&
1232
0
          tsig.siglen < siglen)
1233
0
      {
1234
0
        msg->tsigstatus = dns_tsigerror_badtrunc;
1235
0
        tsig_log(msg->tsigkey, 2,
1236
0
           "signature length too small");
1237
0
        result = DNS_R_TSIGVERIFYFAILURE;
1238
0
        goto cleanup_querystruct;
1239
0
      }
1240
0
    }
1241
0
  }
1242
1243
0
  if (msg->tsigctx == NULL) {
1244
0
    result = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC,
1245
0
              false, &msg->tsigctx);
1246
0
    if (result != ISC_R_SUCCESS) {
1247
0
      goto cleanup_querystruct;
1248
0
    }
1249
1250
    /*
1251
     * Digest the length of the query signature
1252
     */
1253
0
    isc_buffer_init(&databuf, data, sizeof(data));
1254
0
    isc_buffer_putuint16(&databuf, querytsig.siglen);
1255
0
    isc_buffer_usedregion(&databuf, &r);
1256
0
    result = dst_context_adddata(msg->tsigctx, &r);
1257
0
    if (result != ISC_R_SUCCESS) {
1258
0
      goto cleanup_context;
1259
0
    }
1260
1261
    /*
1262
     * Digest the data of the query signature
1263
     */
1264
0
    if (querytsig.siglen > 0) {
1265
0
      r.length = querytsig.siglen;
1266
0
      r.base = querytsig.signature;
1267
0
      result = dst_context_adddata(msg->tsigctx, &r);
1268
0
      if (result != ISC_R_SUCCESS) {
1269
0
        goto cleanup_context;
1270
0
      }
1271
0
    }
1272
0
  }
1273
1274
  /*
1275
   * Extract the header.
1276
   */
1277
0
  isc_buffer_usedregion(source, &r);
1278
0
  memmove(header, r.base, DNS_MESSAGE_HEADERLEN);
1279
0
  isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1280
1281
  /*
1282
   * Decrement the additional field counter if necessary.
1283
   */
1284
0
  if (has_tsig) {
1285
0
    uint16_t addcount_n;
1286
1287
0
    memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1288
0
    addcount_n = ntohs(addcount);
1289
0
    addcount = htons((uint16_t)(addcount_n - 1));
1290
0
    memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1291
1292
    /*
1293
     * Put in the original id.
1294
     *
1295
     * XXX Can TCP transfers be forwarded?  How would that
1296
     * work?
1297
     */
1298
0
    id = htons(tsig.originalid);
1299
0
    memmove(&header[0], &id, 2);
1300
0
  }
1301
1302
  /*
1303
   * Digest the modified header.
1304
   */
1305
0
  header_r.base = (unsigned char *)header;
1306
0
  header_r.length = DNS_MESSAGE_HEADERLEN;
1307
0
  result = dst_context_adddata(msg->tsigctx, &header_r);
1308
0
  if (result != ISC_R_SUCCESS) {
1309
0
    goto cleanup_context;
1310
0
  }
1311
1312
  /*
1313
   * Digest all non-TSIG records.
1314
   */
1315
0
  isc_buffer_usedregion(source, &source_r);
1316
0
  r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1317
0
  if (has_tsig) {
1318
0
    r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1319
0
  } else {
1320
0
    r.length = source_r.length - DNS_MESSAGE_HEADERLEN;
1321
0
  }
1322
0
  result = dst_context_adddata(msg->tsigctx, &r);
1323
0
  if (result != ISC_R_SUCCESS) {
1324
0
    goto cleanup_context;
1325
0
  }
1326
1327
  /*
1328
   * Digest the time signed and fudge.
1329
   */
1330
0
  if (has_tsig) {
1331
0
    isc_buffer_init(&databuf, data, sizeof(data));
1332
0
    isc_buffer_putuint48(&databuf, tsig.timesigned);
1333
0
    isc_buffer_putuint16(&databuf, tsig.fudge);
1334
0
    isc_buffer_usedregion(&databuf, &r);
1335
0
    result = dst_context_adddata(msg->tsigctx, &r);
1336
0
    if (result != ISC_R_SUCCESS) {
1337
0
      goto cleanup_context;
1338
0
    }
1339
1340
0
    sig_r.base = tsig.signature;
1341
0
    sig_r.length = tsig.siglen;
1342
0
    if (tsig.siglen == 0) {
1343
0
      if (tsig.error != dns_rcode_noerror) {
1344
0
        msg->tsigstatus = tsig.error;
1345
0
        if (tsig.error == dns_tsigerror_badtime) {
1346
0
          result = DNS_R_CLOCKSKEW;
1347
0
        } else {
1348
0
          result = DNS_R_TSIGERRORSET;
1349
0
        }
1350
0
      } else {
1351
0
        tsig_log(msg->tsigkey, 2, "signature is empty");
1352
0
        result = DNS_R_TSIGVERIFYFAILURE;
1353
0
      }
1354
0
      goto cleanup_context;
1355
0
    }
1356
1357
0
    result = dst_context_verify(msg->tsigctx, &sig_r);
1358
0
    if (result == DST_R_VERIFYFAILURE) {
1359
0
      tsig_log(msg->tsigkey, 2,
1360
0
         "signature failed to verify(2)");
1361
0
      result = DNS_R_TSIGVERIFYFAILURE;
1362
0
      goto cleanup_context;
1363
0
    } else if (result != ISC_R_SUCCESS) {
1364
0
      goto cleanup_context;
1365
0
    }
1366
0
    msg->verified_sig = 1;
1367
1368
    /*
1369
     * Here at this point, the MAC has been verified. Even
1370
     * if any of the following code returns a TSIG error,
1371
     * the reply will be signed and WILL always include the
1372
     * request MAC in the digest computation.
1373
     */
1374
1375
    /*
1376
     * Is the time ok?
1377
     */
1378
0
    if (msg->fuzzing) {
1379
0
      now = msg->fuzztime;
1380
0
    } else {
1381
0
      now = isc_stdtime_now();
1382
0
    }
1383
1384
0
    if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
1385
0
      msg->tsigstatus = dns_tsigerror_badtime;
1386
0
      tsig_log(msg->tsigkey, 2, "signature has expired");
1387
0
      result = DNS_R_CLOCKSKEW;
1388
0
      goto cleanup_context;
1389
0
    } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge)
1390
0
    {
1391
0
      msg->tsigstatus = dns_tsigerror_badtime;
1392
0
      tsig_log(msg->tsigkey, 2, "signature is in the future");
1393
0
      result = DNS_R_CLOCKSKEW;
1394
0
      goto cleanup_context;
1395
0
    }
1396
1397
0
    if (tsig.error != dns_rcode_noerror) {
1398
0
      msg->tsigstatus = tsig.error;
1399
0
      if (tsig.error == dns_tsigerror_badtime) {
1400
0
        result = DNS_R_CLOCKSKEW;
1401
0
      } else {
1402
0
        result = DNS_R_TSIGERRORSET;
1403
0
      }
1404
0
      goto cleanup_context;
1405
0
    }
1406
0
  }
1407
1408
0
  msg->tsigstatus = dns_rcode_noerror;
1409
0
  result = ISC_R_SUCCESS;
1410
1411
0
cleanup_context:
1412
  /*
1413
   * Except in error conditions, don't destroy the DST context
1414
   * for unsigned messages; it is a running sum till the next
1415
   * TSIG signed message.
1416
   */
1417
0
  if ((result != ISC_R_SUCCESS || has_tsig) && msg->tsigctx != NULL) {
1418
0
    dst_context_destroy(&msg->tsigctx);
1419
0
  }
1420
1421
0
cleanup_querystruct:
1422
0
  dns_rdata_freestruct(&querytsig);
1423
1424
0
  return result;
1425
0
}
1426
1427
isc_result_t
1428
dns_tsigkey_find(dns_tsigkey_t **tsigkey, const dns_name_t *name,
1429
689
     const dns_name_t *algorithm, dns_tsigkeyring_t *ring) {
1430
689
  dns_tsigkey_t *key = NULL;
1431
689
  isc_result_t result;
1432
689
  isc_rwlocktype_t locktype = isc_rwlocktype_read;
1433
689
  isc_stdtime_t now = isc_stdtime_now();
1434
1435
689
  REQUIRE(name != NULL);
1436
689
  REQUIRE(VALID_TSIGKEYRING(ring));
1437
689
  REQUIRE(tsigkey != NULL && *tsigkey == NULL);
1438
1439
689
again:
1440
689
  RWLOCK(&ring->lock, locktype);
1441
689
  result = isc_hashmap_find(ring->keys, dns_name_hash(name), tkey_match,
1442
689
          name, (void **)&key);
1443
689
  if (result == ISC_R_NOTFOUND) {
1444
443
    RWUNLOCK(&ring->lock, locktype);
1445
443
    return result;
1446
443
  }
1447
1448
246
  if (algorithm != NULL && key->alg != dns__tsig_algfromname(algorithm)) {
1449
245
    RWUNLOCK(&ring->lock, locktype);
1450
245
    return ISC_R_NOTFOUND;
1451
245
  }
1452
1
  if (key->inception != key->expire && isc_serial_lt(key->expire, now)) {
1453
    /*
1454
     * The key has expired.
1455
     */
1456
0
    if (locktype == isc_rwlocktype_read) {
1457
0
      RWUNLOCK(&ring->lock, locktype);
1458
0
      locktype = isc_rwlocktype_write;
1459
0
      key = NULL;
1460
0
      goto again;
1461
0
    }
1462
0
    dns__tsigkey_delete(ring, key);
1463
0
    RWUNLOCK(&ring->lock, locktype);
1464
0
    return ISC_R_NOTFOUND;
1465
0
  }
1466
1
  dns_tsigkey_ref(key);
1467
1
  RWUNLOCK(&ring->lock, locktype);
1468
1
  if (key->generated) {
1469
0
    ISC_SIEVE_MARK(key, visited);
1470
0
  }
1471
1
  *tsigkey = key;
1472
1
  return ISC_R_SUCCESS;
1473
1
}
1474
1475
const dns_name_t *
1476
27
dns_tsigkey_algorithm(dns_tsigkey_t *tkey) {
1477
27
  REQUIRE(VALID_TSIGKEY(tkey));
1478
1479
27
  switch (tkey->alg) {
1480
0
  case DST_ALG_HMACMD5:
1481
0
    return dns_tsig_hmacmd5_name;
1482
0
  case DST_ALG_HMACSHA1:
1483
0
    return dns_tsig_hmacsha1_name;
1484
0
  case DST_ALG_HMACSHA224:
1485
0
    return dns_tsig_hmacsha224_name;
1486
27
  case DST_ALG_HMACSHA256:
1487
27
    return dns_tsig_hmacsha256_name;
1488
0
  case DST_ALG_HMACSHA384:
1489
0
    return dns_tsig_hmacsha384_name;
1490
0
  case DST_ALG_HMACSHA512:
1491
0
    return dns_tsig_hmacsha512_name;
1492
0
  case DST_ALG_GSSAPI:
1493
0
    return dns_tsig_gssapi_name;
1494
1495
0
  case DST_ALG_UNKNOWN:
1496
    /*
1497
     * If the tsigkey object was created with an
1498
     * unknown algorithm, then we cloned
1499
     * the algorithm name here.
1500
     */
1501
0
    return &tkey->algname;
1502
1503
0
  default:
1504
0
    UNREACHABLE();
1505
27
  }
1506
27
}
1507
1508
void
1509
6
dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsigkeyring_t **ringp) {
1510
6
  dns_tsigkeyring_t *ring = NULL;
1511
1512
6
  REQUIRE(mctx != NULL);
1513
6
  REQUIRE(ringp != NULL && *ringp == NULL);
1514
1515
6
  ring = isc_mem_get(mctx, sizeof(dns_tsigkeyring_t));
1516
6
  *ring = (dns_tsigkeyring_t){
1517
6
    .magic = TSIGKEYRING_MAGIC,
1518
6
    .mctx = isc_mem_ref(mctx),
1519
6
    .references = ISC_REFCOUNT_INITIALIZER(1),
1520
6
  };
1521
1522
6
  ISC_SIEVE_INIT(ring->lrulist);
1523
1524
6
  isc_hashmap_create(mctx, 12, &ring->keys);
1525
6
  isc_rwlock_init(&ring->lock);
1526
1527
6
  *ringp = ring;
1528
6
}
1529
1530
isc_result_t
1531
2
dns_tsigkeyring_add(dns_tsigkeyring_t *ring, dns_tsigkey_t *tkey) {
1532
2
  isc_result_t result;
1533
1534
2
  REQUIRE(VALID_TSIGKEY(tkey));
1535
2
  REQUIRE(VALID_TSIGKEYRING(ring));
1536
1537
2
  RWLOCK(&ring->lock, isc_rwlocktype_write);
1538
2
  result = isc_hashmap_add(ring->keys, dns_name_hash(tkey->name),
1539
2
         tkey_match, tkey->name, tkey, NULL);
1540
2
  if (result == ISC_R_SUCCESS) {
1541
2
    dns_tsigkey_ref(tkey);
1542
1543
    /*
1544
     * If this is a TKEY-generated key, add it to the LRU list,
1545
     * and if we've exceeded the quota for generated keys,
1546
     * delete the least recently used one.
1547
     */
1548
2
    if (tkey->generated) {
1549
0
      if (++ring->generated > DNS_TSIG_MAXGENERATEDKEYS) {
1550
0
        dns_tsigkey_t *key = ISC_SIEVE_NEXT(
1551
0
          ring->lrulist, visited, lrulink);
1552
0
        dns__tsigkey_delete(ring, key);
1553
0
      }
1554
      /*
1555
       * Insert the new key AFTER any possible eviction, so
1556
       * that the key is not evicted immediately after the
1557
       * insertion.
1558
       */
1559
0
      ISC_SIEVE_INSERT(ring->lrulist, tkey, lrulink);
1560
0
    }
1561
2
  }
1562
2
  RWUNLOCK(&ring->lock, isc_rwlocktype_write);
1563
1564
2
  return result;
1565
2
}
1566
1567
void
1568
0
dns_tsigkeyring_restore(dns_tsigkeyring_t *ring, FILE *fp) {
1569
0
  isc_stdtime_t now = isc_stdtime_now();
1570
0
  isc_result_t result;
1571
1572
0
  do {
1573
0
    result = restore_key(ring, now, fp);
1574
0
    if (result == ISC_R_NOMORE) {
1575
0
      return;
1576
0
    }
1577
0
    if (result == DNS_R_BADALG || result == DNS_R_EXPIRED) {
1578
0
      result = ISC_R_SUCCESS;
1579
0
    }
1580
0
  } while (result == ISC_R_SUCCESS);
1581
0
}