Coverage Report

Created: 2025-08-26 06:59

/src/bind9/lib/dns/keystore.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/assertions.h>
19
#include <isc/buffer.h>
20
#include <isc/dir.h>
21
#include <isc/mem.h>
22
#include <isc/time.h>
23
#include <isc/util.h>
24
25
#include <dns/fixedname.h>
26
#include <dns/keystore.h>
27
#include <dns/keyvalues.h>
28
29
void
30
0
dns_keystore_create(isc_mem_t *mctx, const char *name, dns_keystore_t **kspp) {
31
0
  dns_keystore_t *keystore;
32
33
0
  REQUIRE(name != NULL);
34
0
  REQUIRE(kspp != NULL && *kspp == NULL);
35
36
0
  keystore = isc_mem_get(mctx, sizeof(*keystore));
37
0
  keystore->mctx = NULL;
38
0
  isc_mem_attach(mctx, &keystore->mctx);
39
40
0
  keystore->name = isc_mem_strdup(mctx, name);
41
0
  isc_mutex_init(&keystore->lock);
42
43
0
  isc_refcount_init(&keystore->references, 1);
44
45
0
  ISC_LINK_INIT(keystore, link);
46
47
0
  keystore->directory = NULL;
48
0
  keystore->pkcs11uri = NULL;
49
50
0
  keystore->magic = DNS_KEYSTORE_MAGIC;
51
0
  *kspp = keystore;
52
0
}
53
54
static inline void
55
0
dns__keystore_destroy(dns_keystore_t *keystore) {
56
0
  char *name;
57
58
0
  REQUIRE(!ISC_LINK_LINKED(keystore, link));
59
60
0
  isc_mutex_destroy(&keystore->lock);
61
0
  name = UNCONST(keystore->name);
62
0
  isc_mem_free(keystore->mctx, name);
63
0
  if (keystore->directory != NULL) {
64
0
    isc_mem_free(keystore->mctx, keystore->directory);
65
0
  }
66
0
  if (keystore->pkcs11uri != NULL) {
67
0
    isc_mem_free(keystore->mctx, keystore->pkcs11uri);
68
0
  }
69
0
  isc_mem_putanddetach(&keystore->mctx, keystore, sizeof(*keystore));
70
0
}
71
72
#ifdef DNS_KEYSTORE_TRACE
73
ISC_REFCOUNT_TRACE_IMPL(dns_keystore, dns__keystore_destroy);
74
#else
75
ISC_REFCOUNT_IMPL(dns_keystore, dns__keystore_destroy);
76
#endif
77
78
const char *
79
0
dns_keystore_name(dns_keystore_t *keystore) {
80
0
  REQUIRE(DNS_KEYSTORE_VALID(keystore));
81
82
0
  return keystore->name;
83
0
}
84
85
const char *
86
0
dns_keystore_directory(dns_keystore_t *keystore, const char *keydir) {
87
0
  if (keystore == NULL) {
88
0
    return keydir;
89
0
  }
90
91
0
  INSIST(DNS_KEYSTORE_VALID(keystore));
92
93
0
  if (keystore->directory == NULL) {
94
0
    return keydir;
95
0
  }
96
97
0
  return keystore->directory;
98
0
}
99
100
void
101
0
dns_keystore_setdirectory(dns_keystore_t *keystore, const char *dir) {
102
0
  REQUIRE(DNS_KEYSTORE_VALID(keystore));
103
104
0
  if (keystore->directory != NULL) {
105
0
    isc_mem_free(keystore->mctx, keystore->directory);
106
0
  }
107
0
  keystore->directory = (dir == NULL)
108
0
              ? NULL
109
0
              : isc_mem_strdup(keystore->mctx, dir);
110
0
}
111
112
const char *
113
0
dns_keystore_pkcs11uri(dns_keystore_t *keystore) {
114
0
  REQUIRE(DNS_KEYSTORE_VALID(keystore));
115
116
0
  return keystore->pkcs11uri;
117
0
}
118
119
void
120
0
dns_keystore_setpkcs11uri(dns_keystore_t *keystore, const char *uri) {
121
0
  REQUIRE(DNS_KEYSTORE_VALID(keystore));
122
123
0
  if (keystore->pkcs11uri != NULL) {
124
0
    isc_mem_free(keystore->mctx, keystore->pkcs11uri);
125
0
  }
126
0
  keystore->pkcs11uri = (uri == NULL)
127
0
              ? NULL
128
0
              : isc_mem_strdup(keystore->mctx, uri);
129
0
}
130
131
static isc_result_t
132
buildpkcs11label(const char *uri, const dns_name_t *zname, const char *policy,
133
0
     int flags, isc_buffer_t *buf) {
134
0
  bool ksk = ((flags & DNS_KEYFLAG_KSK) != 0);
135
0
  char timebuf[18];
136
0
  isc_time_t now = isc_time_now();
137
0
  isc_result_t result;
138
0
  dns_fixedname_t fname;
139
0
  dns_name_t *pname = dns_fixedname_initname(&fname);
140
141
  /* uri + object */
142
0
  if (isc_buffer_availablelength(buf) < strlen(uri) + strlen(";object="))
143
0
  {
144
0
    return ISC_R_NOSPACE;
145
0
  }
146
0
  isc_buffer_putstr(buf, uri);
147
0
  isc_buffer_putstr(buf, ";object=");
148
  /* zone name */
149
0
  result = dns_name_tofilenametext(zname, false, buf);
150
0
  if (result != ISC_R_SUCCESS) {
151
0
    return result;
152
0
  }
153
  /*
154
   * policy name
155
   *
156
   * Note that strlen(policy) is not the actual length, but if this
157
   * already does not fit, the escaped version returned from
158
   * dns_name_tofilenametext() certainly won't fit.
159
   */
160
0
  if (isc_buffer_availablelength(buf) < (strlen(policy) + 1)) {
161
0
    return ISC_R_NOSPACE;
162
0
  }
163
0
  isc_buffer_putstr(buf, "-");
164
0
  result = dns_name_fromstring(pname, policy, dns_rootname, 0, NULL);
165
0
  if (result != ISC_R_SUCCESS) {
166
0
    return result;
167
0
  }
168
0
  result = dns_name_tofilenametext(pname, false, buf);
169
0
  if (result != ISC_R_SUCCESS) {
170
0
    return result;
171
0
  }
172
  /* key type + current time */
173
0
  isc_time_formatshorttimestamp(&now, timebuf, sizeof(timebuf));
174
0
  return isc_buffer_printf(buf, "-%s-%s", ksk ? "ksk" : "zsk", timebuf);
175
0
}
176
177
isc_result_t
178
dns_keystore_keygen(dns_keystore_t *keystore, const dns_name_t *origin,
179
        const char *policy, dns_rdataclass_t rdclass,
180
        isc_mem_t *mctx, uint32_t alg, int size, int flags,
181
0
        dst_key_t **dstkey) {
182
0
  isc_result_t result;
183
0
  dst_key_t *newkey = NULL;
184
0
  const char *uri = NULL;
185
186
0
  REQUIRE(DNS_KEYSTORE_VALID(keystore));
187
0
  REQUIRE(dns_name_isvalid(origin));
188
0
  REQUIRE(policy != NULL);
189
0
  REQUIRE(mctx != NULL);
190
0
  REQUIRE(dstkey != NULL && *dstkey == NULL);
191
192
0
  uri = dns_keystore_pkcs11uri(keystore);
193
0
  if (uri != NULL) {
194
    /*
195
     * Create the PKCS#11 label.
196
     * The label consists of the configured URI, and the object
197
     * parameter.  The object parameter needs to be unique.  We
198
     * know that for a given point in time, there will be at most
199
     * one key per type created for each zone in a given DNSSEC
200
     * policy.  Hence the object is constructed out of the following
201
     * parts: the zone name, policy name, key type, and the
202
     * current time.
203
     *
204
     * The object may not contain any characters that conflict with
205
     * special characters in the PKCS#11 URI scheme syntax (see
206
     * RFC 7512, Section 2.3). Therefore, we mangle the zone name
207
     * and policy name through 'dns_name_tofilenametext()'. We
208
     * could create a new function to convert a name to PKCS#11
209
     * text, but this existing function will suffice.
210
     */
211
0
    char label[NAME_MAX];
212
0
    isc_buffer_t buf;
213
0
    isc_buffer_init(&buf, label, sizeof(label));
214
0
    result = buildpkcs11label(uri, origin, policy, flags, &buf);
215
0
    if (result != ISC_R_SUCCESS) {
216
0
      char namebuf[DNS_NAME_FORMATSIZE];
217
0
      dns_name_format(origin, namebuf, sizeof(namebuf));
218
0
      isc_log_write(
219
0
        DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
220
0
        ISC_LOG_ERROR,
221
0
        "keystore: failed to create PKCS#11 object "
222
0
        "for zone %s, policy %s: %s",
223
0
        namebuf, policy, isc_result_totext(result));
224
0
      return result;
225
0
    }
226
227
    /* Generate the key */
228
0
    result = dst_key_generate(origin, alg, size, 0, flags,
229
0
            DNS_KEYPROTO_DNSSEC, rdclass, label,
230
0
            mctx, &newkey, NULL);
231
232
0
    if (result != ISC_R_SUCCESS) {
233
0
      isc_log_write(
234
0
        DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
235
0
        ISC_LOG_ERROR,
236
0
        "keystore: failed to generate PKCS#11 object "
237
0
        "%s: %s",
238
0
        label, isc_result_totext(result));
239
0
      return result;
240
0
    }
241
0
    isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
242
0
            ISC_LOG_ERROR,
243
0
            "keystore: generated PKCS#11 object %s", label);
244
0
  } else {
245
0
    result = dst_key_generate(origin, alg, size, 0, flags,
246
0
            DNS_KEYPROTO_DNSSEC, rdclass, NULL,
247
0
            mctx, &newkey, NULL);
248
0
  }
249
250
0
  if (result == ISC_R_SUCCESS) {
251
0
    *dstkey = newkey;
252
0
  }
253
0
  return result;
254
0
}
255
256
isc_result_t
257
dns_keystorelist_find(dns_keystorelist_t *list, const char *name,
258
0
          dns_keystore_t **kspp) {
259
0
  REQUIRE(kspp != NULL && *kspp == NULL);
260
261
0
  if (list == NULL) {
262
0
    return ISC_R_NOTFOUND;
263
0
  }
264
265
0
  ISC_LIST_FOREACH(*list, keystore, link) {
266
0
    if (strcmp(keystore->name, name) == 0) {
267
0
      dns_keystore_attach(keystore, kspp);
268
0
      return ISC_R_SUCCESS;
269
0
    }
270
0
  }
271
272
0
  return ISC_R_NOTFOUND;
273
0
}