Coverage Report

Created: 2025-11-11 07:03

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