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