Coverage Report

Created: 2026-01-10 06:28

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