Coverage Report

Created: 2025-12-14 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/keystore.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 <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
0
ISC_REFCOUNT_IMPL(dns_keystore, dns__keystore_destroy);
Unexecuted instantiation: dns_keystore_ref
Unexecuted instantiation: dns_keystore_unref
Unexecuted instantiation: dns_keystore_detach
76
0
#endif
77
0
78
0
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
  dns_fixedname_t fname;
138
0
  dns_name_t *pname = dns_fixedname_initname(&fname);
139
140
  /* uri + object */
141
0
  if (isc_buffer_availablelength(buf) < strlen(uri) + strlen(";object="))
142
0
  {
143
0
    return ISC_R_NOSPACE;
144
0
  }
145
0
  isc_buffer_putstr(buf, uri);
146
0
  isc_buffer_putstr(buf, ";object=");
147
  /* zone name */
148
0
  RETERR(dns_name_tofilenametext(zname, false, buf));
149
  /*
150
   * policy name
151
   *
152
   * Note that strlen(policy) is not the actual length, but if this
153
   * already does not fit, the escaped version returned from
154
   * dns_name_tofilenametext() certainly won't fit.
155
   */
156
0
  if (isc_buffer_availablelength(buf) < (strlen(policy) + 1)) {
157
0
    return ISC_R_NOSPACE;
158
0
  }
159
0
  isc_buffer_putstr(buf, "-");
160
0
  RETERR(dns_name_fromstring(pname, policy, dns_rootname, 0, NULL));
161
0
  RETERR(dns_name_tofilenametext(pname, false, buf));
162
  /* key type + current time */
163
0
  isc_time_formatshorttimestamp(&now, timebuf, sizeof(timebuf));
164
0
  return isc_buffer_printf(buf, "-%s-%s", ksk ? "ksk" : "zsk", timebuf);
165
0
}
166
167
isc_result_t
168
dns_keystore_keygen(dns_keystore_t *keystore, const dns_name_t *origin,
169
        const char *policy, dns_rdataclass_t rdclass,
170
        isc_mem_t *mctx, uint32_t alg, int size, int flags,
171
0
        dst_key_t **dstkey) {
172
0
  isc_result_t result;
173
0
  dst_key_t *newkey = NULL;
174
0
  const char *uri = NULL;
175
176
0
  REQUIRE(DNS_KEYSTORE_VALID(keystore));
177
0
  REQUIRE(dns_name_isvalid(origin));
178
0
  REQUIRE(policy != NULL);
179
0
  REQUIRE(mctx != NULL);
180
0
  REQUIRE(dstkey != NULL && *dstkey == NULL);
181
182
0
  uri = dns_keystore_pkcs11uri(keystore);
183
0
  if (uri != NULL) {
184
    /*
185
     * Create the PKCS#11 label.
186
     * The label consists of the configured URI, and the object
187
     * parameter.  The object parameter needs to be unique.  We
188
     * know that for a given point in time, there will be at most
189
     * one key per type created for each zone in a given DNSSEC
190
     * policy.  Hence the object is constructed out of the following
191
     * parts: the zone name, policy name, key type, and the
192
     * current time.
193
     *
194
     * The object may not contain any characters that conflict with
195
     * special characters in the PKCS#11 URI scheme syntax (see
196
     * RFC 7512, Section 2.3). Therefore, we mangle the zone name
197
     * and policy name through 'dns_name_tofilenametext()'. We
198
     * could create a new function to convert a name to PKCS#11
199
     * text, but this existing function will suffice.
200
     */
201
0
    char label[NAME_MAX];
202
0
    isc_buffer_t buf;
203
0
    isc_buffer_init(&buf, label, sizeof(label));
204
0
    result = buildpkcs11label(uri, origin, policy, flags, &buf);
205
0
    if (result != ISC_R_SUCCESS) {
206
0
      char namebuf[DNS_NAME_FORMATSIZE];
207
0
      dns_name_format(origin, namebuf, sizeof(namebuf));
208
0
      isc_log_write(
209
0
        DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
210
0
        ISC_LOG_ERROR,
211
0
        "keystore: failed to create PKCS#11 object "
212
0
        "for zone %s, policy %s: %s",
213
0
        namebuf, policy, isc_result_totext(result));
214
0
      return result;
215
0
    }
216
217
    /* Generate the key */
218
0
    result = dst_key_generate(origin, alg, size, 0, flags,
219
0
            DNS_KEYPROTO_DNSSEC, rdclass, label,
220
0
            mctx, &newkey, NULL);
221
222
0
    if (result != ISC_R_SUCCESS) {
223
0
      isc_log_write(
224
0
        DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
225
0
        ISC_LOG_ERROR,
226
0
        "keystore: failed to generate PKCS#11 object "
227
0
        "%s: %s",
228
0
        label, isc_result_totext(result));
229
0
      return result;
230
0
    }
231
0
    isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
232
0
            ISC_LOG_ERROR,
233
0
            "keystore: generated PKCS#11 object %s", label);
234
0
  } else {
235
0
    result = dst_key_generate(origin, alg, size, 0, flags,
236
0
            DNS_KEYPROTO_DNSSEC, rdclass, NULL,
237
0
            mctx, &newkey, NULL);
238
0
  }
239
240
0
  if (result == ISC_R_SUCCESS) {
241
0
    *dstkey = newkey;
242
0
  }
243
0
  return result;
244
0
}
245
246
isc_result_t
247
dns_keystorelist_find(dns_keystorelist_t *list, const char *name,
248
0
          dns_keystore_t **kspp) {
249
0
  REQUIRE(kspp != NULL && *kspp == NULL);
250
251
0
  if (list == NULL) {
252
0
    return ISC_R_NOTFOUND;
253
0
  }
254
255
0
  ISC_LIST_FOREACH(*list, keystore, link) {
256
0
    if (strcmp(keystore->name, name) == 0) {
257
0
      dns_keystore_attach(keystore, kspp);
258
0
      return ISC_R_SUCCESS;
259
0
    }
260
0
  }
261
262
0
  return ISC_R_NOTFOUND;
263
0
}