blob: 9540f3d56a4dac5632ee966233fb439eb54099fc [file] [log] [blame]
romanf02273a2023-05-25 09:44:11 +02001/**
2 * @file server_config_ks.c
3 * @author Roman Janota <janota@cesnet.cz>
4 * @brief libnetconf2 keystore configuration functions
5 *
6 * @copyright
7 * Copyright (c) 2023 CESNET, z.s.p.o.
8 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
16#define _GNU_SOURCE
17
18#include <assert.h>
roman3f9b65c2023-06-05 14:26:58 +020019#include <stdint.h>
romanf02273a2023-05-25 09:44:11 +020020#include <stdlib.h>
21#include <string.h>
22
roman3f9b65c2023-06-05 14:26:58 +020023#include <libyang/libyang.h>
24
romanf02273a2023-05-25 09:44:11 +020025#include "compat.h"
roman3f9b65c2023-06-05 14:26:58 +020026#include "log_p.h"
romanf02273a2023-05-25 09:44:11 +020027#include "server_config_p.h"
roman3f9b65c2023-06-05 14:26:58 +020028#include "session_p.h"
romanf02273a2023-05-25 09:44:11 +020029
30extern struct nc_server_opts server_opts;
31
32/**
33 * @brief Get the pointer to an asymmetric key structure based on node's location in the YANG data.
34 *
35 * @param[in] node Node from which the asymmetric key containing this node is derived.
36 * @param[out] askey Asymmetric key containing the node.
37 * @return 0 on success, 1 on error.
38 */
39static int
40nc_server_config_get_asymmetric_key(const struct lyd_node *node, struct nc_asymmetric_key **askey)
41{
42 uint16_t i;
43 const char *askey_name;
44 struct nc_keystore *ks;
roman94de2c12023-10-12 11:44:04 +020045 const char *node_name = LYD_NAME(node);
romanf02273a2023-05-25 09:44:11 +020046
roman4cb8bb12023-06-29 09:16:46 +020047 assert(node && askey);
romanf02273a2023-05-25 09:44:11 +020048
49 while (node) {
50 if (!strcmp(LYD_NAME(node), "asymmetric-key")) {
51 break;
52 }
53 node = lyd_parent(node);
54 }
55
56 if (!node) {
roman94de2c12023-10-12 11:44:04 +020057 ERR(NULL, "Node \"%s\" is not contained in an asymmetric-key subtree.", node_name);
romanf02273a2023-05-25 09:44:11 +020058 return 1;
59 }
60
61 node = lyd_child(node);
62 assert(!strcmp(LYD_NAME(node), "name"));
63 askey_name = lyd_get_value(node);
64
65 ks = &server_opts.keystore;
66 for (i = 0; i < ks->asym_key_count; i++) {
67 if (!strcmp(ks->asym_keys[i].name, askey_name)) {
68 *askey = &ks->asym_keys[i];
69 return 0;
70 }
71 }
72
73 ERR(NULL, "Asymmetric key \"%s\" was not found.", askey_name);
74 return 1;
75}
76
77/**
78 * @brief Get the pointer to a certificate structure based on node's location in the YANG data.
79 *
80 * @param[in] node Node from which the certificate containing this node is derived.
81 * @param[out] cert Certificate containing the node.
82 * @return 0 on success, 1 on error.
83 */
84static int
roman4cb8bb12023-06-29 09:16:46 +020085nc_server_config_get_certificate(const struct lyd_node *node, struct nc_certificate **cert)
romanf02273a2023-05-25 09:44:11 +020086{
87 uint16_t i;
88 const char *cert_name;
roman4cb8bb12023-06-29 09:16:46 +020089 struct nc_asymmetric_key *askey;
roman94de2c12023-10-12 11:44:04 +020090 const char *node_name = LYD_NAME(node);
romanf02273a2023-05-25 09:44:11 +020091
roman4cb8bb12023-06-29 09:16:46 +020092 assert(node && cert);
93
94 if (nc_server_config_get_asymmetric_key(node, &askey)) {
95 return 1;
96 }
romanf02273a2023-05-25 09:44:11 +020097
98 while (node) {
99 if (!strcmp(LYD_NAME(node), "certificate")) {
100 break;
101 }
102 node = lyd_parent(node);
103 }
104
105 if (!node) {
roman94de2c12023-10-12 11:44:04 +0200106 ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", node_name);
romanf02273a2023-05-25 09:44:11 +0200107 return 1;
108 }
109
110 node = lyd_child(node);
111 assert(!strcmp(LYD_NAME(node), "name"));
112 cert_name = lyd_get_value(node);
113
114 for (i = 0; i < askey->cert_count; i++) {
115 if (!strcmp(askey->certs[i].name, cert_name)) {
116 *cert = &askey->certs[i];
117 return 0;
118 }
119 }
120
121 ERR(NULL, "Certificate \"%s\" was not found.", cert_name);
122 return 1;
123}
124
125static void
126nc_server_config_ks_del_asymmetric_key_cert(struct nc_asymmetric_key *key, struct nc_certificate *cert)
127{
128 free(cert->name);
roman3f9b65c2023-06-05 14:26:58 +0200129 free(cert->data);
romanf02273a2023-05-25 09:44:11 +0200130
131 key->cert_count--;
roman94de2c12023-10-12 11:44:04 +0200132 if (!key->cert_count) {
romanf02273a2023-05-25 09:44:11 +0200133 free(key->certs);
134 key->certs = NULL;
roman94de2c12023-10-12 11:44:04 +0200135 } else if (cert != &key->certs[key->cert_count]) {
136 memcpy(cert, &key->certs[key->cert_count], sizeof *key->certs);
romanf02273a2023-05-25 09:44:11 +0200137 }
138}
139
140static void
romanf02273a2023-05-25 09:44:11 +0200141nc_server_config_ks_del_asymmetric_key(struct nc_asymmetric_key *key)
142{
143 uint16_t i, cert_count;
144 struct nc_keystore *ks = &server_opts.keystore;
145
146 free(key->name);
roman94de2c12023-10-12 11:44:04 +0200147 free(key->pubkey_data);
148 free(key->privkey_data);
romanf02273a2023-05-25 09:44:11 +0200149
150 cert_count = key->cert_count;
151 for (i = 0; i < cert_count; i++) {
152 nc_server_config_ks_del_asymmetric_key_cert(key, &key->certs[i]);
153 }
154
155 ks->asym_key_count--;
156 if (!ks->asym_key_count) {
157 free(ks->asym_keys);
158 ks->asym_keys = NULL;
roman94de2c12023-10-12 11:44:04 +0200159 } else if (key != &ks->asym_keys[ks->asym_key_count]) {
160 memcpy(key, &ks->asym_keys[ks->asym_key_count], sizeof *ks->asym_keys);
romanf02273a2023-05-25 09:44:11 +0200161 }
162}
163
164static int
165nc_server_config_ks_asymmetric_keys(const struct lyd_node *node, NC_OPERATION op)
166{
167 struct nc_keystore *ks = &server_opts.keystore;
168 uint16_t i, asym_key_count;
169
170 (void) node;
171
172 if (op == NC_OP_DELETE) {
173 asym_key_count = ks->asym_key_count;
174 for (i = 0; i < asym_key_count; i++) {
175 nc_server_config_ks_del_asymmetric_key(&ks->asym_keys[i]);
176 }
177 }
178
179 return 0;
180}
181
182int
183nc_server_config_ks_keystore(const struct lyd_node *node, NC_OPERATION op)
184{
185 (void) node;
186
187 if (op == NC_OP_DELETE) {
188 nc_server_config_ks_asymmetric_keys(NULL, NC_OP_DELETE);
189 }
190
191 return 0;
192}
193
194static int
195nc_server_config_ks_create_asymmetric_key(const struct lyd_node *node)
196{
197 struct nc_keystore *ks = &server_opts.keystore;
198
199 node = lyd_child(node);
200 assert(!strcmp(LYD_NAME(node), "name"));
201
202 return nc_server_config_realloc(lyd_get_value(node), (void **)&ks->asym_keys, sizeof *ks->asym_keys, &ks->asym_key_count);
203}
204
205static int
206nc_server_config_ks_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
207{
208 int ret = 0;
209 struct nc_asymmetric_key *key;
210
211 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
212
213 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
214 ret = nc_server_config_ks_create_asymmetric_key(node);
215 } else {
216 if (nc_server_config_get_asymmetric_key(node, &key)) {
217 ret = 1;
218 goto cleanup;
219 }
220
221 nc_server_config_ks_del_asymmetric_key(key);
222 }
223
224cleanup:
225 return ret;
226}
227
228static int
229nc_server_config_ks_public_key_format(const struct lyd_node *node, NC_OPERATION op)
230{
231 struct nc_asymmetric_key *key;
232 const char *format;
233
234 (void) op;
235
236 assert(!strcmp(LYD_NAME(node), "public-key-format"));
237
238 if (nc_server_config_get_asymmetric_key(node, &key)) {
239 return 1;
240 }
241
242 format = ((struct lyd_node_term *)node)->value.ident->name;
243 if (!strcmp(format, "ssh-public-key-format")) {
roman13145912023-08-17 15:36:54 +0200244 key->pubkey_type = NC_PUBKEY_FORMAT_SSH;
romanf02273a2023-05-25 09:44:11 +0200245 } else if (!strcmp(format, "subject-public-key-info-format")) {
roman3f9b65c2023-06-05 14:26:58 +0200246 key->pubkey_type = NC_PUBKEY_FORMAT_X509;
romanf02273a2023-05-25 09:44:11 +0200247 } else {
248 ERR(NULL, "Public key format (%s) not supported.", format);
249 }
250
251 return 0;
252}
253
254static int
255nc_server_config_ks_public_key(const struct lyd_node *node, NC_OPERATION op)
256{
257 struct nc_asymmetric_key *key;
258
259 (void) op;
260
261 assert(!strcmp(LYD_NAME(node), "public-key"));
262
263 if (nc_server_config_get_asymmetric_key(node, &key)) {
264 return 1;
265 }
266
267 /* replace the pubkey */
roman94de2c12023-10-12 11:44:04 +0200268 free(key->pubkey_data);
roman3f9b65c2023-06-05 14:26:58 +0200269 key->pubkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +0200270 NC_CHECK_ERRMEM_RET(!key->pubkey_data, 1);
romanf02273a2023-05-25 09:44:11 +0200271
272 return 0;
273}
274
275static int
276nc_server_config_ks_private_key_format(const struct lyd_node *node, NC_OPERATION op)
277{
278 struct nc_asymmetric_key *key;
279 const char *format;
roman3f9b65c2023-06-05 14:26:58 +0200280 NC_PRIVKEY_FORMAT privkey_type;
281
282 (void) op;
romanf02273a2023-05-25 09:44:11 +0200283
284 assert(!strcmp(LYD_NAME(node), "private-key-format"));
285
286 if (nc_server_config_get_asymmetric_key(node, &key)) {
287 return 1;
288 }
289
290 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +0200291 if (!format) {
292 return 1;
romanf02273a2023-05-25 09:44:11 +0200293 }
294
roman3f9b65c2023-06-05 14:26:58 +0200295 privkey_type = nc_server_config_get_private_key_type(format);
296 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
297 return 1;
298 }
299 key->privkey_type = privkey_type;
300
romanf02273a2023-05-25 09:44:11 +0200301 return 0;
302}
303
304static int
305nc_server_config_ks_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
306{
307 struct nc_asymmetric_key *key;
308
309 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
310
311 if (nc_server_config_get_asymmetric_key(node, &key)) {
312 return 1;
313 }
314
315 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
316 /* replace the privkey */
roman94de2c12023-10-12 11:44:04 +0200317 free(key->privkey_data);
roman3f9b65c2023-06-05 14:26:58 +0200318 key->privkey_data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +0200319 NC_CHECK_ERRMEM_RET(!key->privkey_data, 1);
romanf02273a2023-05-25 09:44:11 +0200320 } else if (op == NC_OP_DELETE) {
roman94de2c12023-10-12 11:44:04 +0200321 free(key->privkey_data);
322 key->privkey_data = NULL;
romanf02273a2023-05-25 09:44:11 +0200323 }
324
325 return 0;
326}
327
328static int
329nc_server_config_ks_create_certificate(const struct lyd_node *node, struct nc_asymmetric_key *key)
330{
331 node = lyd_child(node);
332 assert(!strcmp(LYD_NAME(node), "name"));
333
334 return nc_server_config_realloc(lyd_get_value(node), (void **)&key->certs, sizeof *key->certs, &key->cert_count);
335}
336
337static int
338nc_server_config_ks_certificate(const struct lyd_node *node, NC_OPERATION op)
339{
340 int ret = 0;
341 struct nc_asymmetric_key *key;
342 struct nc_certificate *cert;
343
344 assert(!strcmp(LYD_NAME(node), "certificate"));
345
346 if (nc_server_config_get_asymmetric_key(node, &key)) {
347 ret = 1;
348 goto cleanup;
349 }
350
351 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
352 ret = nc_server_config_ks_create_certificate(node, key);
353 } else {
roman4cb8bb12023-06-29 09:16:46 +0200354 if (nc_server_config_get_certificate(node, &cert)) {
romanf02273a2023-05-25 09:44:11 +0200355 ret = 1;
356 goto cleanup;
357 }
358
359 nc_server_config_ks_del_asymmetric_key_cert(key, cert);
360 }
361
362cleanup:
363 return ret;
364}
365
366static int
367nc_server_config_ks_cert_data(const struct lyd_node *node, NC_OPERATION op)
368{
romanf02273a2023-05-25 09:44:11 +0200369 struct nc_certificate *cert;
370
romanf02273a2023-05-25 09:44:11 +0200371 assert(!strcmp(LYD_NAME(node), "cert-data"));
372
373 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman4cb8bb12023-06-29 09:16:46 +0200374 if (nc_server_config_get_certificate(node, &cert)) {
romanf02273a2023-05-25 09:44:11 +0200375 return 1;
376 }
377
378 /* replace the cert data */
roman94de2c12023-10-12 11:44:04 +0200379 free(cert->data);
roman3f9b65c2023-06-05 14:26:58 +0200380 cert->data = strdup(lyd_get_value(node));
roman3a95bb22023-10-26 11:07:17 +0200381 NC_CHECK_ERRMEM_RET(!cert->data, 1);
romanf02273a2023-05-25 09:44:11 +0200382 }
383
384 return 0;
385}
386
387int
388nc_server_config_parse_keystore(const struct lyd_node *node, NC_OPERATION op)
389{
390 const char *name = LYD_NAME(node);
roman94de2c12023-10-12 11:44:04 +0200391 int ret = 0;
romanf02273a2023-05-25 09:44:11 +0200392
393 if (!strcmp(name, "keystore")) {
roman94de2c12023-10-12 11:44:04 +0200394 ret = nc_server_config_ks_keystore(node, op);
romanf02273a2023-05-25 09:44:11 +0200395 } else if (!strcmp(name, "asymmetric-keys")) {
roman94de2c12023-10-12 11:44:04 +0200396 ret = nc_server_config_ks_asymmetric_keys(node, op);
romanf02273a2023-05-25 09:44:11 +0200397 } else if (!strcmp(name, "asymmetric-key")) {
roman94de2c12023-10-12 11:44:04 +0200398 ret = nc_server_config_ks_asymmetric_key(node, op);
romanf02273a2023-05-25 09:44:11 +0200399 } else if (!strcmp(name, "public-key-format")) {
roman94de2c12023-10-12 11:44:04 +0200400 ret = nc_server_config_ks_public_key_format(node, op);
romanf02273a2023-05-25 09:44:11 +0200401 } else if (!strcmp(name, "public-key")) {
roman94de2c12023-10-12 11:44:04 +0200402 ret = nc_server_config_ks_public_key(node, op);
romanf02273a2023-05-25 09:44:11 +0200403 } else if (!strcmp(name, "private-key-format")) {
roman94de2c12023-10-12 11:44:04 +0200404 ret = nc_server_config_ks_private_key_format(node, op);
romanf02273a2023-05-25 09:44:11 +0200405 } else if (!strcmp(name, "cleartext-private-key")) {
roman94de2c12023-10-12 11:44:04 +0200406 ret = nc_server_config_ks_cleartext_private_key(node, op);
romanf02273a2023-05-25 09:44:11 +0200407 } else if (!strcmp(name, "certificate")) {
roman94de2c12023-10-12 11:44:04 +0200408 ret = nc_server_config_ks_certificate(node, op);
romanf02273a2023-05-25 09:44:11 +0200409 } else if (!strcmp(name, "cert-data")) {
roman94de2c12023-10-12 11:44:04 +0200410 ret = nc_server_config_ks_cert_data(node, op);
411 }
412
413 if (ret) {
414 ERR(NULL, "Configuring (%s) failed.", name);
415 return 1;
romanf02273a2023-05-25 09:44:11 +0200416 }
417
418 return 0;
romanf02273a2023-05-25 09:44:11 +0200419}
420
421int
422nc_server_config_fill_keystore(const struct lyd_node *data, NC_OPERATION op)
423{
424 int ret = 0;
425 uint32_t prev_lo;
426 struct lyd_node *tree;
427
428 /* silently search for nodes, some of them may not be present */
429 prev_lo = ly_log_options(0);
430
431 ret = lyd_find_path(data, "/ietf-keystore:keystore", 0, &tree);
432 if (ret || (tree->flags & LYD_DEFAULT)) {
roman5cbb6532023-06-22 12:53:17 +0200433 /* not found */
romanf02273a2023-05-25 09:44:11 +0200434 ret = 0;
435 goto cleanup;
436 }
437
roman0bbc19c2023-05-26 09:59:09 +0200438 if (nc_server_config_parse_tree(tree, op, NC_MODULE_KEYSTORE)) {
romanf02273a2023-05-25 09:44:11 +0200439 ret = 1;
440 goto cleanup;
441 }
442
443cleanup:
444 /* reset the logging options back to what they were */
445 ly_log_options(prev_lo);
446 return ret;
447}