blob: b39f8d8d5b1624410f49a9504c96c53d66a6c987 [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;
45
roman4cb8bb12023-06-29 09:16:46 +020046 assert(node && askey);
romanf02273a2023-05-25 09:44:11 +020047
48 while (node) {
49 if (!strcmp(LYD_NAME(node), "asymmetric-key")) {
50 break;
51 }
52 node = lyd_parent(node);
53 }
54
55 if (!node) {
56 ERR(NULL, "Node \"%s\" is not contained in an asymmetric-key subtree.", LYD_NAME(node));
57 return 1;
58 }
59
60 node = lyd_child(node);
61 assert(!strcmp(LYD_NAME(node), "name"));
62 askey_name = lyd_get_value(node);
63
64 ks = &server_opts.keystore;
65 for (i = 0; i < ks->asym_key_count; i++) {
66 if (!strcmp(ks->asym_keys[i].name, askey_name)) {
67 *askey = &ks->asym_keys[i];
68 return 0;
69 }
70 }
71
72 ERR(NULL, "Asymmetric key \"%s\" was not found.", askey_name);
73 return 1;
74}
75
76/**
77 * @brief Get the pointer to a certificate structure based on node's location in the YANG data.
78 *
79 * @param[in] node Node from which the certificate containing this node is derived.
80 * @param[out] cert Certificate containing the node.
81 * @return 0 on success, 1 on error.
82 */
83static int
roman4cb8bb12023-06-29 09:16:46 +020084nc_server_config_get_certificate(const struct lyd_node *node, struct nc_certificate **cert)
romanf02273a2023-05-25 09:44:11 +020085{
86 uint16_t i;
87 const char *cert_name;
roman4cb8bb12023-06-29 09:16:46 +020088 struct nc_asymmetric_key *askey;
romanf02273a2023-05-25 09:44:11 +020089
roman4cb8bb12023-06-29 09:16:46 +020090 assert(node && cert);
91
92 if (nc_server_config_get_asymmetric_key(node, &askey)) {
93 return 1;
94 }
romanf02273a2023-05-25 09:44:11 +020095
96 while (node) {
97 if (!strcmp(LYD_NAME(node), "certificate")) {
98 break;
99 }
100 node = lyd_parent(node);
101 }
102
103 if (!node) {
104 ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", LYD_NAME(node));
105 return 1;
106 }
107
108 node = lyd_child(node);
109 assert(!strcmp(LYD_NAME(node), "name"));
110 cert_name = lyd_get_value(node);
111
112 for (i = 0; i < askey->cert_count; i++) {
113 if (!strcmp(askey->certs[i].name, cert_name)) {
114 *cert = &askey->certs[i];
115 return 0;
116 }
117 }
118
119 ERR(NULL, "Certificate \"%s\" was not found.", cert_name);
120 return 1;
121}
122
123static void
124nc_server_config_ks_del_asymmetric_key_cert(struct nc_asymmetric_key *key, struct nc_certificate *cert)
125{
126 free(cert->name);
127 cert->name = NULL;
128
roman3f9b65c2023-06-05 14:26:58 +0200129 free(cert->data);
130 cert->data = NULL;
romanf02273a2023-05-25 09:44:11 +0200131
132 key->cert_count--;
133 if (key->cert_count == 0) {
134 free(key->certs);
135 key->certs = NULL;
136 }
137}
138
139static void
140nc_server_config_ks_del_public_key(struct nc_asymmetric_key *key)
141{
roman3f9b65c2023-06-05 14:26:58 +0200142 free(key->pubkey_data);
143 key->pubkey_data = NULL;
romanf02273a2023-05-25 09:44:11 +0200144}
145
146static void
147nc_server_config_ks_del_private_key(struct nc_asymmetric_key *key)
148{
roman3f9b65c2023-06-05 14:26:58 +0200149 free(key->privkey_data);
150 key->privkey_data = NULL;
romanf02273a2023-05-25 09:44:11 +0200151}
152
153static void
154nc_server_config_ks_del_cert_data(struct nc_certificate *cert)
155{
roman3f9b65c2023-06-05 14:26:58 +0200156 free(cert->data);
157 cert->data = NULL;
romanf02273a2023-05-25 09:44:11 +0200158}
159
160static void
161nc_server_config_ks_del_asymmetric_key(struct nc_asymmetric_key *key)
162{
163 uint16_t i, cert_count;
164 struct nc_keystore *ks = &server_opts.keystore;
165
166 free(key->name);
167 key->name = NULL;
168
169 nc_server_config_ks_del_public_key(key);
170 nc_server_config_ks_del_private_key(key);
171
172 cert_count = key->cert_count;
173 for (i = 0; i < cert_count; i++) {
174 nc_server_config_ks_del_asymmetric_key_cert(key, &key->certs[i]);
175 }
176
177 ks->asym_key_count--;
178 if (!ks->asym_key_count) {
179 free(ks->asym_keys);
180 ks->asym_keys = NULL;
181 }
182}
183
184static int
185nc_server_config_ks_asymmetric_keys(const struct lyd_node *node, NC_OPERATION op)
186{
187 struct nc_keystore *ks = &server_opts.keystore;
188 uint16_t i, asym_key_count;
189
190 (void) node;
191
192 if (op == NC_OP_DELETE) {
193 asym_key_count = ks->asym_key_count;
194 for (i = 0; i < asym_key_count; i++) {
195 nc_server_config_ks_del_asymmetric_key(&ks->asym_keys[i]);
196 }
197 }
198
199 return 0;
200}
201
202int
203nc_server_config_ks_keystore(const struct lyd_node *node, NC_OPERATION op)
204{
205 (void) node;
206
207 if (op == NC_OP_DELETE) {
208 nc_server_config_ks_asymmetric_keys(NULL, NC_OP_DELETE);
209 }
210
211 return 0;
212}
213
214static int
215nc_server_config_ks_create_asymmetric_key(const struct lyd_node *node)
216{
217 struct nc_keystore *ks = &server_opts.keystore;
218
219 node = lyd_child(node);
220 assert(!strcmp(LYD_NAME(node), "name"));
221
222 return nc_server_config_realloc(lyd_get_value(node), (void **)&ks->asym_keys, sizeof *ks->asym_keys, &ks->asym_key_count);
223}
224
225static int
226nc_server_config_ks_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
227{
228 int ret = 0;
229 struct nc_asymmetric_key *key;
230
231 assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
232
233 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
234 ret = nc_server_config_ks_create_asymmetric_key(node);
235 } else {
236 if (nc_server_config_get_asymmetric_key(node, &key)) {
237 ret = 1;
238 goto cleanup;
239 }
240
241 nc_server_config_ks_del_asymmetric_key(key);
242 }
243
244cleanup:
245 return ret;
246}
247
248static int
249nc_server_config_ks_public_key_format(const struct lyd_node *node, NC_OPERATION op)
250{
251 struct nc_asymmetric_key *key;
252 const char *format;
253
254 (void) op;
255
256 assert(!strcmp(LYD_NAME(node), "public-key-format"));
257
258 if (nc_server_config_get_asymmetric_key(node, &key)) {
259 return 1;
260 }
261
262 format = ((struct lyd_node_term *)node)->value.ident->name;
263 if (!strcmp(format, "ssh-public-key-format")) {
roman13145912023-08-17 15:36:54 +0200264 key->pubkey_type = NC_PUBKEY_FORMAT_SSH;
romanf02273a2023-05-25 09:44:11 +0200265 } else if (!strcmp(format, "subject-public-key-info-format")) {
roman3f9b65c2023-06-05 14:26:58 +0200266 key->pubkey_type = NC_PUBKEY_FORMAT_X509;
romanf02273a2023-05-25 09:44:11 +0200267 } else {
268 ERR(NULL, "Public key format (%s) not supported.", format);
269 }
270
271 return 0;
272}
273
274static int
275nc_server_config_ks_public_key(const struct lyd_node *node, NC_OPERATION op)
276{
277 struct nc_asymmetric_key *key;
278
279 (void) op;
280
281 assert(!strcmp(LYD_NAME(node), "public-key"));
282
283 if (nc_server_config_get_asymmetric_key(node, &key)) {
284 return 1;
285 }
286
287 /* replace the pubkey */
288 nc_server_config_ks_del_public_key(key);
roman3f9b65c2023-06-05 14:26:58 +0200289 key->pubkey_data = strdup(lyd_get_value(node));
290 if (!key->pubkey_data) {
romanf02273a2023-05-25 09:44:11 +0200291 ERRMEM;
292 return 1;
293 }
294
295 return 0;
296}
297
298static int
299nc_server_config_ks_private_key_format(const struct lyd_node *node, NC_OPERATION op)
300{
301 struct nc_asymmetric_key *key;
302 const char *format;
roman3f9b65c2023-06-05 14:26:58 +0200303 NC_PRIVKEY_FORMAT privkey_type;
304
305 (void) op;
romanf02273a2023-05-25 09:44:11 +0200306
307 assert(!strcmp(LYD_NAME(node), "private-key-format"));
308
309 if (nc_server_config_get_asymmetric_key(node, &key)) {
310 return 1;
311 }
312
313 format = ((struct lyd_node_term *)node)->value.ident->name;
roman3f9b65c2023-06-05 14:26:58 +0200314 if (!format) {
315 return 1;
romanf02273a2023-05-25 09:44:11 +0200316 }
317
roman3f9b65c2023-06-05 14:26:58 +0200318 privkey_type = nc_server_config_get_private_key_type(format);
319 if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
320 return 1;
321 }
322 key->privkey_type = privkey_type;
323
romanf02273a2023-05-25 09:44:11 +0200324 return 0;
325}
326
327static int
328nc_server_config_ks_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op)
329{
330 struct nc_asymmetric_key *key;
331
332 assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
333
334 if (nc_server_config_get_asymmetric_key(node, &key)) {
335 return 1;
336 }
337
338 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
339 /* replace the privkey */
340 nc_server_config_ks_del_private_key(key);
roman3f9b65c2023-06-05 14:26:58 +0200341 key->privkey_data = strdup(lyd_get_value(node));
342 if (!key->privkey_data) {
romanf02273a2023-05-25 09:44:11 +0200343 ERRMEM;
344 return 1;
345 }
346 } else if (op == NC_OP_DELETE) {
347 nc_server_config_ks_del_private_key(key);
348 }
349
350 return 0;
351}
352
353static int
354nc_server_config_ks_create_certificate(const struct lyd_node *node, struct nc_asymmetric_key *key)
355{
356 node = lyd_child(node);
357 assert(!strcmp(LYD_NAME(node), "name"));
358
359 return nc_server_config_realloc(lyd_get_value(node), (void **)&key->certs, sizeof *key->certs, &key->cert_count);
360}
361
362static int
363nc_server_config_ks_certificate(const struct lyd_node *node, NC_OPERATION op)
364{
365 int ret = 0;
366 struct nc_asymmetric_key *key;
367 struct nc_certificate *cert;
368
369 assert(!strcmp(LYD_NAME(node), "certificate"));
370
371 if (nc_server_config_get_asymmetric_key(node, &key)) {
372 ret = 1;
373 goto cleanup;
374 }
375
376 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
377 ret = nc_server_config_ks_create_certificate(node, key);
378 } else {
roman4cb8bb12023-06-29 09:16:46 +0200379 if (nc_server_config_get_certificate(node, &cert)) {
romanf02273a2023-05-25 09:44:11 +0200380 ret = 1;
381 goto cleanup;
382 }
383
384 nc_server_config_ks_del_asymmetric_key_cert(key, cert);
385 }
386
387cleanup:
388 return ret;
389}
390
391static int
392nc_server_config_ks_cert_data(const struct lyd_node *node, NC_OPERATION op)
393{
romanf02273a2023-05-25 09:44:11 +0200394 struct nc_certificate *cert;
395
romanf02273a2023-05-25 09:44:11 +0200396 assert(!strcmp(LYD_NAME(node), "cert-data"));
397
398 if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
roman4cb8bb12023-06-29 09:16:46 +0200399 if (nc_server_config_get_certificate(node, &cert)) {
romanf02273a2023-05-25 09:44:11 +0200400 return 1;
401 }
402
403 /* replace the cert data */
404 nc_server_config_ks_del_cert_data(cert);
roman3f9b65c2023-06-05 14:26:58 +0200405 cert->data = strdup(lyd_get_value(node));
406 if (!cert->data) {
romanf02273a2023-05-25 09:44:11 +0200407 ERRMEM;
408 return 1;
409 }
410 }
411
412 return 0;
413}
414
415int
416nc_server_config_parse_keystore(const struct lyd_node *node, NC_OPERATION op)
417{
418 const char *name = LYD_NAME(node);
419
420 if (!strcmp(name, "keystore")) {
421 if (nc_server_config_ks_keystore(node, op)) {
422 goto error;
423 }
424 } else if (!strcmp(name, "asymmetric-keys")) {
425 if (nc_server_config_ks_asymmetric_keys(node, op)) {
426 goto error;
427 }
428 } else if (!strcmp(name, "asymmetric-key")) {
429 if (nc_server_config_ks_asymmetric_key(node, op)) {
430 goto error;
431 }
432 } else if (!strcmp(name, "public-key-format")) {
433 if (nc_server_config_ks_public_key_format(node, op)) {
434 goto error;
435 }
436 } else if (!strcmp(name, "public-key")) {
437 if (nc_server_config_ks_public_key(node, op)) {
438 goto error;
439 }
440 } else if (!strcmp(name, "private-key-format")) {
441 if (nc_server_config_ks_private_key_format(node, op)) {
442 goto error;
443 }
444 } else if (!strcmp(name, "cleartext-private-key")) {
445 if (nc_server_config_ks_cleartext_private_key(node, op)) {
446 goto error;
447 }
448 } else if (!strcmp(name, "certificate")) {
449 if (nc_server_config_ks_certificate(node, op)) {
450 goto error;
451 }
452 } else if (!strcmp(name, "cert-data")) {
453 if (nc_server_config_ks_cert_data(node, op)) {
454 goto error;
455 }
456 }
457
458 return 0;
459
460error:
461 ERR(NULL, "Configuring (%s) failed.", name);
462 return 1;
463}
464
465int
466nc_server_config_fill_keystore(const struct lyd_node *data, NC_OPERATION op)
467{
468 int ret = 0;
469 uint32_t prev_lo;
470 struct lyd_node *tree;
471
472 /* silently search for nodes, some of them may not be present */
473 prev_lo = ly_log_options(0);
474
475 ret = lyd_find_path(data, "/ietf-keystore:keystore", 0, &tree);
476 if (ret || (tree->flags & LYD_DEFAULT)) {
roman5cbb6532023-06-22 12:53:17 +0200477 /* not found */
romanf02273a2023-05-25 09:44:11 +0200478 ret = 0;
479 goto cleanup;
480 }
481
roman0bbc19c2023-05-26 09:59:09 +0200482 if (nc_server_config_parse_tree(tree, op, NC_MODULE_KEYSTORE)) {
romanf02273a2023-05-25 09:44:11 +0200483 ret = 1;
484 goto cleanup;
485 }
486
487cleanup:
488 /* reset the logging options back to what they were */
489 ly_log_options(prev_lo);
490 return ret;
491}