Coverage Report

Created: 2025-07-18 07:03

/src/bind9/lib/dns/ds.c
Line
Count
Source (jump to first uncovered line)
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 <string.h>
17
18
#include <isc/buffer.h>
19
#include <isc/md.h>
20
#include <isc/region.h>
21
#include <isc/result.h>
22
#include <isc/util.h>
23
24
#include <dns/ds.h>
25
#include <dns/fixedname.h>
26
#include <dns/keyvalues.h>
27
#include <dns/name.h>
28
#include <dns/rdata.h>
29
#include <dns/rdatastruct.h>
30
31
#include <dst/dst.h>
32
33
isc_result_t
34
dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key,
35
        dns_dsdigest_t digest_type, unsigned char *digest,
36
0
        size_t len, dns_rdata_ds_t *dsrdata) {
37
0
  isc_result_t result;
38
0
  dns_fixedname_t fname;
39
0
  dns_name_t *name;
40
0
  unsigned int digestlen = 0;
41
0
  unsigned int privatelen = 0;
42
0
  isc_region_t r;
43
0
  isc_md_t *md;
44
0
  const isc_md_type_t *md_type = NULL;
45
46
0
  REQUIRE(key != NULL);
47
0
  REQUIRE(key->type == dns_rdatatype_dnskey ||
48
0
    key->type == dns_rdatatype_cdnskey);
49
0
  REQUIRE(digest != NULL);
50
51
0
  if (!dst_ds_digest_supported(digest_type)) {
52
0
    return ISC_R_NOTIMPLEMENTED;
53
0
  }
54
55
0
  switch (digest_type) {
56
0
  case DNS_DSDIGEST_SHA1:
57
0
    md_type = ISC_MD_SHA1;
58
0
    break;
59
60
0
  case DNS_DSDIGEST_SHA384:
61
#ifdef DNS_DSDIGEST_SHA384PRIVATE
62
  case DNS_DSDIGEST_SHA384PRIVATE:
63
#endif
64
0
    md_type = ISC_MD_SHA384;
65
0
    break;
66
67
0
  case DNS_DSDIGEST_SHA256:
68
#ifdef DNS_DSDIGEST_SHA256PRIVATE
69
  case DNS_DSDIGEST_SHA256PRIVATE:
70
#endif
71
0
    md_type = ISC_MD_SHA256;
72
0
    break;
73
74
0
  default:
75
0
    UNREACHABLE();
76
0
  }
77
78
0
  name = dns_fixedname_initname(&fname);
79
0
  (void)dns_name_downcase(owner, name);
80
81
0
  md = isc_md_new();
82
83
0
  result = isc_md_init(md, md_type);
84
0
  if (result != ISC_R_SUCCESS) {
85
0
    goto end;
86
0
  }
87
88
0
  dns_name_toregion(name, &r);
89
90
0
  result = isc_md_update(md, r.base, r.length);
91
0
  if (result != ISC_R_SUCCESS) {
92
0
    goto end;
93
0
  }
94
95
0
  dns_rdata_toregion(key, &r);
96
0
  INSIST(r.length >= 4);
97
98
0
  result = isc_md_update(md, r.base, r.length);
99
0
  if (result != ISC_R_SUCCESS) {
100
0
    goto end;
101
0
  }
102
103
#if defined(DNS_DSDIGEST_SHA256PRIVATE) && defined(DNS_DSDIGEST_SHA384PRIVATE)
104
  /*
105
   * Insert PRIVATE algorithm identify at start of digest.
106
   */
107
  switch (digest_type) {
108
  case DNS_DSDIGEST_SHA1:
109
  case DNS_DSDIGEST_SHA256:
110
  case DNS_DSDIGEST_SHA384:
111
    break;
112
  case DNS_DSDIGEST_SHA256PRIVATE:
113
  case DNS_DSDIGEST_SHA384PRIVATE:
114
    switch (r.base[3]) {
115
    case DNS_KEYALG_PRIVATEDNS: {
116
      isc_region_t r2 = r;
117
      INSIST(r2.length >= 5);
118
      isc_region_consume(&r2, 4);
119
      dns_name_fromregion(name, &r2);
120
      dns_name_toregion(name, &r2);
121
      privatelen = r2.length;
122
      if (r2.length > len) {
123
        result = ISC_R_NOSPACE;
124
        goto end;
125
      }
126
      memmove(digest, r2.base, privatelen);
127
      digest += privatelen;
128
      len -= privatelen;
129
      break;
130
    }
131
    case DNS_KEYALG_PRIVATEOID: {
132
      isc_region_t r2 = r;
133
      INSIST(r2.length >= 5);
134
      isc_region_consume(&r2, 4);
135
      privatelen = r2.base[0] + 1;
136
      if (r2.base[0] > len) {
137
        result = ISC_R_NOSPACE;
138
        goto end;
139
      }
140
      INSIST(r2.length >= privatelen);
141
      memmove(digest, r2.base, privatelen);
142
      digest += privatelen;
143
      len -= privatelen;
144
      break;
145
    }
146
    default:
147
      break;
148
    }
149
    break;
150
  default:
151
    break;
152
  }
153
#endif
154
155
0
  size_t mdsize = isc_md_get_size(md);
156
0
  if (mdsize > len) {
157
0
    result = ISC_R_NOSPACE;
158
0
    goto end;
159
0
  }
160
161
0
  result = isc_md_final(md, digest, &digestlen);
162
0
  if (result != ISC_R_SUCCESS) {
163
0
    goto end;
164
0
  }
165
166
0
  dsrdata->mctx = NULL;
167
0
  dsrdata->common.rdclass = key->rdclass;
168
0
  dsrdata->common.rdtype = dns_rdatatype_ds;
169
0
  dsrdata->algorithm = r.base[3];
170
0
  dsrdata->key_tag = dst_region_computeid(&r);
171
0
  dsrdata->digest_type = digest_type;
172
0
  dsrdata->digest = digest - privatelen;
173
0
  dsrdata->length = digestlen + privatelen;
174
175
0
end:
176
0
  isc_md_free(md);
177
0
  return result;
178
0
}
179
180
isc_result_t
181
dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key,
182
      dns_dsdigest_t digest_type, unsigned char *buffer, size_t len,
183
0
      dns_rdata_t *rdata) {
184
0
  isc_result_t result;
185
0
  unsigned char digest[ISC_MAX_MD_SIZE];
186
0
  dns_rdata_ds_t ds;
187
0
  isc_buffer_t b;
188
189
0
  result = dns_ds_fromkeyrdata(owner, key, digest_type, digest, len, &ds);
190
0
  if (result != ISC_R_SUCCESS) {
191
0
    return result;
192
0
  }
193
194
0
  memset(buffer, 0, DNS_DS_BUFFERSIZE);
195
0
  isc_buffer_init(&b, buffer, DNS_DS_BUFFERSIZE);
196
0
  result = dns_rdata_fromstruct(rdata, key->rdclass, dns_rdatatype_ds,
197
0
              &ds, &b);
198
0
  return result;
199
0
}