blob: 078b73c7c4dad5db79560943a425dac1062a02d7 [file] [log] [blame]
roman3f9b65c2023-06-05 14:26:58 +02001/**
2 * @file config_new_tls.c
3 * @author Roman Janota <janota@cesnet.cz>
4 * @brief libnetconf2 TLS server new configuration creation 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 <stdint.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include <libyang/libyang.h>
24
25#include "compat.h"
26#include "config.h"
27#include "config_new.h"
28#include "log_p.h"
29#include "server_config.h"
30#include "session.h"
31#include "session_p.h"
32
33API int
34nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, uint32_t id, const char *fingerprint,
35 NC_TLS_CTN_MAPTYPE map_type, const char *name, struct lyd_node **config)
36{
37 int ret = 0;
38 char *tree_path = NULL;
39 struct lyd_node *new_tree;
40
41 NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, map_type, name, 1);
42 NC_CHECK_ARG_RET(NULL, config, 1);
43
44 /* prepare path for instertion of leaves later */
45 asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/"
46 "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']", endpt_name, id);
47 if (!tree_path) {
48 ERRMEM;
49 ret = 1;
50 goto cleanup;
51 }
52
53 /* create all the nodes in the path */
54 ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree);
55 if (ret) {
56 goto cleanup;
57 }
58 if (!*config) {
59 *config = new_tree;
60 }
61
62 if (!new_tree) {
63 /* no new nodes were created */
64 ret = lyd_find_path(*config, tree_path, 0, &new_tree);
65 } else {
66 /* config was NULL */
67 ret = lyd_find_path(new_tree, tree_path, 0, &new_tree);
68 }
69 if (ret) {
70 ERR(NULL, "Unable to find netconf-server-parameters container.");
71 goto cleanup;
72 }
73
74 /* not mandatory */
75 if (fingerprint) {
76 ret = lyd_new_term(new_tree, NULL, "fingerprint", fingerprint, 0, NULL);
77 if (ret) {
78 goto cleanup;
79 }
80 }
81
82 /* insert map-type */
83 switch (map_type) {
84 case NC_TLS_CTN_SPECIFIED:
85 ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:specified", 0, NULL);
86 break;
87 case NC_TLS_CTN_SAN_RFC822_NAME:
88 ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-rfc822-name", 0, NULL);
89 break;
90 case NC_TLS_CTN_SAN_DNS_NAME:
91 ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-dns-name", 0, NULL);
92 break;
93 case NC_TLS_CTN_SAN_IP_ADDRESS:
94 ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-ip-address", 0, NULL);
95 break;
96 case NC_TLS_CTN_SAN_ANY:
97 ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-any", 0, NULL);
98 break;
99 case NC_TLS_CTN_COMMON_NAME:
100 ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:common-name", 0, NULL);
101 break;
102 case NC_TLS_CTN_UNKNOWN:
103 default:
104 ERR(NULL, "Unknown map_type.");
105 ret = 1;
106 break;
107 }
108 if (ret) {
109 goto cleanup;
110 }
111
112 /* insert name */
113 ret = lyd_new_term(new_tree, NULL, "name", name, 0, NULL);
114 if (ret) {
115 goto cleanup;
116 }
117
118 /* check if top-level container has operation and if not, add it */
119 ret = nc_config_new_check_add_operation(ctx, *config);
120 if (ret) {
121 goto cleanup;
122 }
123
124 /* Add all default nodes */
125 ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL);
126 if (ret) {
127 goto cleanup;
128 }
129
130cleanup:
131 free(tree_path);
132 return ret;
133}
134
135API int
136nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *pubkey_path,
137 const char *privkey_path, const char *certificate_path, struct lyd_node **config)
138{
139 int ret = 0;
140 char *tree_path = NULL, *privkey = NULL, *pubkey = NULL, *pubkey_stripped = NULL, *privkey_stripped, *cert = NULL;
141 struct lyd_node *new_tree;
142 NC_PRIVKEY_FORMAT privkey_type;
143 NC_PUBKEY_FORMAT pubkey_type;
144 const char *privkey_identity;
145
146 NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, certificate_path, 1);
147 NC_CHECK_ARG_RET(NULL, config, 1);
148
149 /* get the keys as a string from the given files */
150 ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type);
151 if (ret) {
152 ERR(NULL, "Getting keys from file(s) failed.");
153 goto cleanup;
154 }
155
156 ret = nc_server_config_new_read_certificate(certificate_path, &cert);
157 if (ret) {
158 ERR(NULL, "Getting certificate from file \"%s\" failed.", certificate_path);
159 goto cleanup;
160 }
161
162 /* prepare path for instertion of leaves later */
163 asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate/local-definition", endpt_name);
164 if (!tree_path) {
165 ERRMEM;
166 ret = 1;
167 goto cleanup;
168 }
169
170 /* create all the nodes in the path */
171 ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree);
172 if (ret) {
173 goto cleanup;
174 }
175 if (!*config) {
176 *config = new_tree;
177 }
178
179 if (!new_tree) {
180 /* no new nodes were created */
181 ret = lyd_find_path(*config, tree_path, 0, &new_tree);
182 } else {
183 /* config was NULL */
184 ret = lyd_find_path(new_tree, tree_path, 0, &new_tree);
185 }
186 if (ret) {
187 ERR(NULL, "Unable to find local-definition container.");
188 goto cleanup;
189 }
190
191 /* insert pubkey format */
192 if (pubkey_type == NC_PUBKEY_FORMAT_X509) {
193 ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:public-key-info-format", 0, NULL);
194 } else {
195 ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:ssh-public-key-format", 0, NULL);
196 }
197 if (ret) {
198 goto cleanup;
199 }
200
201 /* strip pubkey's header and footer only if it's generated from pkcs8 key (using OpenSSL),
202 * otherwise it's already stripped
203 */
204 if (!pubkey_path && (privkey_type == NC_PRIVKEY_FORMAT_X509)) {
205 pubkey_stripped = pubkey + strlen("-----BEGIN PUBLIC KEY-----") + 1;
206 pubkey_stripped[strlen(pubkey_stripped) - strlen("-----END PUBLIC KEY-----") - 2] = '\0';
207 } else {
208 pubkey_stripped = pubkey;
209 }
210
211 /* insert pubkey b64 */
212 ret = lyd_new_term(new_tree, NULL, "public-key", pubkey_stripped, 0, NULL);
213 if (ret) {
214 goto cleanup;
215 }
216
217 /* get privkey identityref value */
218 privkey_identity = nc_config_new_privkey_format_to_identityref(privkey_type);
219 if (!privkey_identity) {
220 ret = 1;
221 goto cleanup;
222 }
223
224 /* insert private key format */
225 ret = lyd_new_term(new_tree, NULL, "private-key-format", privkey_identity, 0, NULL);
226 if (ret) {
227 goto cleanup;
228 }
229
230 if (privkey_type == NC_PRIVKEY_FORMAT_OPENSSH) {
231 /* only OpenSSH private keys have different header and footer after processing */
232 privkey_stripped = privkey + strlen(NC_OPENSSH_PRIVKEY_HEADER);
233 privkey_stripped[strlen(privkey_stripped) - strlen(NC_OPENSSH_PRIVKEY_FOOTER)] = '\0';
234 } else {
235 /* the rest share the same header and footer */
236 privkey_stripped = privkey + strlen(NC_PKCS8_PRIVKEY_HEADER);
237 privkey_stripped[strlen(privkey_stripped) - strlen(NC_PKCS8_PRIVKEY_FOOTER)] = '\0';
238 }
239
240 ret = lyd_new_term(new_tree, NULL, "cleartext-private-key", privkey_stripped, 0, NULL);
241 if (ret) {
242 goto cleanup;
243 }
244
245 ret = lyd_new_term(new_tree, NULL, "cert-data", cert, 0, NULL);
246 if (ret) {
247 goto cleanup;
248 }
249
250 /* check if top-level container has operation and if not, add it */
251 ret = nc_config_new_check_add_operation(ctx, *config);
252 if (ret) {
253 goto cleanup;
254 }
255
256 /* Add all default nodes */
257 ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL);
258 if (ret) {
259 goto cleanup;
260 }
261
262cleanup:
263 free(privkey);
264 free(pubkey);
265 free(cert);
266 free(tree_path);
267 return ret;
268}
269
270API int
271nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name,
272 const char *cert_path, struct lyd_node **config)
273{
274 int ret = 0;
275 struct lyd_node *new_tree;
276 char *tree_path = NULL, *cert = NULL;
277
278 NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1);
279
280 ret = nc_server_config_new_read_certificate(cert_path, &cert);
281 if (ret) {
282 ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path);
283 goto cleanup;
284 }
285
286 /* prepare path for instertion of leaves later */
287 asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/"
288 "client-authentication/ee-certs/local-definition/certificate[name='%s']", endpt_name, cert_name);
289 if (!tree_path) {
290 ERRMEM;
291 ret = 1;
292 goto cleanup;
293 }
294
295 /* create all the nodes in the path */
296 ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree);
297 if (ret) {
298 goto cleanup;
299 }
300 if (!*config) {
301 *config = new_tree;
302 }
303
304 if (!new_tree) {
305 /* no new nodes were created */
306 ret = lyd_find_path(*config, tree_path, 0, &new_tree);
307 } else {
308 /* config was NULL */
309 ret = lyd_find_path(new_tree, tree_path, 0, &new_tree);
310 }
311 if (ret) {
312 goto cleanup;
313 }
314
315 /* insert cert-data */
316 ret = lyd_new_term(new_tree, NULL, "cert-data", cert, 0, NULL);
317 if (ret) {
318 goto cleanup;
319 }
320
321 /* check if top-level container has operation and if not, add it */
322 ret = nc_config_new_check_add_operation(ctx, *config);
323 if (ret) {
324 goto cleanup;
325 }
326
327 /* Add all default nodes */
328 ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL);
329 if (ret) {
330 goto cleanup;
331 }
332
333cleanup:
334 free(cert);
335 free(tree_path);
336 return ret;
337}
338
339API int
340nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name,
341 const char *cert_path, struct lyd_node **config)
342{
343 int ret = 0;
344 struct lyd_node *new_tree;
345 char *tree_path = NULL, *cert = NULL;
346
347 NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1);
348
349 ret = nc_server_config_new_read_certificate(cert_path, &cert);
350 if (ret) {
351 ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path);
352 goto cleanup;
353 }
354
355 /* prepare path for instertion of leaves later */
356 asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/"
357 "client-authentication/ca-certs/local-definition/certificate[name='%s']", endpt_name, cert_name);
358 if (!tree_path) {
359 ERRMEM;
360 ret = 1;
361 goto cleanup;
362 }
363
364 /* create all the nodes in the path */
365 ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree);
366 if (ret) {
367 goto cleanup;
368 }
369 if (!*config) {
370 *config = new_tree;
371 }
372
373 if (!new_tree) {
374 /* no new nodes were created */
375 ret = lyd_find_path(*config, tree_path, 0, &new_tree);
376 } else {
377 /* config was NULL */
378 ret = lyd_find_path(new_tree, tree_path, 0, &new_tree);
379 }
380 if (ret) {
381 goto cleanup;
382 }
383
384 /* insert cert-data */
385 ret = lyd_new_term(new_tree, NULL, "cert-data", cert, 0, NULL);
386 if (ret) {
387 goto cleanup;
388 }
389
390 /* check if top-level container has operation and if not, add it */
391 ret = nc_config_new_check_add_operation(ctx, *config);
392 if (ret) {
393 goto cleanup;
394 }
395
396 /* Add all default nodes */
397 ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL);
398 if (ret) {
399 goto cleanup;
400 }
401
402cleanup:
403 free(cert);
404 free(tree_path);
405 return ret;
406}