From bdca44306d287c869147cf2b4a7f227c5bfa5922 Mon Sep 17 00:00:00 2001 From: Michal Vasko Date: Mon, 2 Nov 2026 11:11:10 +0100 Subject: [PATCH 1/4] build REFACTOR separate SSH and TLS support --- .github/workflows/ci.yml | 60 +- CMakeLists.txt | 153 +- Doxyfile.in | 2 +- README.md | 4 +- nc_client.h.in | 11 +- nc_server.h.in | 11 +- nc_version.h.in | 2 +- src/io.c | 32 +- src/log.c | 10 +- src/log.h | 7 +- src/server_config.c | 808 ++-- src/server_config.h | 1204 +----- src/server_config_ssh.h | 545 +++ src/server_config_tls.h | 530 +++ src/server_config_util.c | 197 +- src/server_config_util.h | 11 +- src/server_config_util_ssh.c | 5 +- src/session.c | 95 +- src/session.h | 18 +- src/session_client.c | 50 +- src/session_client.h | 12 +- src/session_client_ch.h | 16 +- src/session_client_tls.c | 10 +- ...ion_mbedtls.c => session_crypto_mbedtls.c} | 3494 +++++++++-------- ...ion_openssl.c => session_crypto_openssl.c} | 2779 +++++++------ ...ion_wrapper.h => session_crypto_wrapper.h} | 705 ++-- src/session_p.h | 216 +- src/session_server.c | 742 ++-- src/session_server.h | 27 +- src/session_server_ch.h | 6 +- src/session_server_ssh.c | 44 +- src/session_server_ssh_auth_callback.c | 17 +- src/session_server_ssh_auth_message.c | 22 +- src/session_server_ssh_wrapper.h | 64 +- src/session_server_tls.c | 24 +- tests/CMakeLists.txt | 2 +- tests/config.h.in | 4 +- 37 files changed, 6128 insertions(+), 5811 deletions(-) create mode 100644 src/server_config_ssh.h create mode 100644 src/server_config_tls.h rename src/{session_mbedtls.c => session_crypto_mbedtls.c} (96%) rename src/{session_openssl.c => session_crypto_openssl.c} (97%) rename src/{session_wrapper.h => session_crypto_wrapper.h} (90%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8fcf6320..584ebdc9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: build-type: "Release", dep-build-type: "Release", cc: "gcc", - options: "-DENABLE_TESTS=ON -DENABLE_DNSSEC=ON", + options: "-DENABLE_TESTS=ON", tls-lib: "MbedTLS", packages: "", snaps: "", @@ -63,7 +63,7 @@ jobs: make-target: "" } - { - name: "Release, clang", + name: "Release, clang, OpenSSL", os: "ubuntu-24.04", build-type: "Release", dep-build-type: "Release", @@ -88,13 +88,65 @@ jobs: make-prepend: "", make-target: "" } + - { + name: "Debug, gcc, OpenSSL, SSH only", + os: "ubuntu-24.04", + build-type: "Debug", + dep-build-type: "Release", + cc: "gcc", + options: "-DENABLE_DNSSEC=ON -DENABLE_SSH=ON -DENABLE_TLS=OFF", + tls-lib: "OpenSSL", + packages: "valgrind", + snaps: "", + make-prepend: "", + make-target: "" + } + - { + name: "Debug, gcc, OpenSSL, TLS only", + os: "ubuntu-24.04", + build-type: "Debug", + dep-build-type: "Release", + cc: "gcc", + options: "-DENABLE_DNSSEC=ON -DENABLE_SSH=OFF -DENABLE_TLS=ON", + tls-lib: "OpenSSL", + packages: "valgrind", + snaps: "", + make-prepend: "", + make-target: "" + } - { name: "Debug, gcc, MbedTLS", os: "ubuntu-24.04", build-type: "Debug", dep-build-type: "Release", cc: "gcc", - options: "-DENABLE_DNSSEC=ON", + options: "", + tls-lib: "MbedTLS", + packages: "valgrind", + snaps: "", + make-prepend: "", + make-target: "" + } + - { + name: "Debug, gcc, MbedTLS, SSH only", + os: "ubuntu-24.04", + build-type: "Debug", + dep-build-type: "Release", + cc: "gcc", + options: "-DENABLE_SSH=ON -DENABLE_TLS=OFF", + tls-lib: "MbedTLS", + packages: "valgrind", + snaps: "", + make-prepend: "", + make-target: "" + } + - { + name: "Debug, gcc, MbedTLS, TLS only", + os: "ubuntu-24.04", + build-type: "Debug", + dep-build-type: "Release", + cc: "gcc", + options: "-DENABLE_SSH=OFF -DENABLE_TLS=ON", tls-lib: "MbedTLS", packages: "valgrind", snaps: "", @@ -121,7 +173,7 @@ jobs: build-type: "Debug", dep-build-type: "Release", cc: "gcc", - options: "-DENABLE_SSH_TLS=OFF", + options: "-DENABLE_SSH=OFF -DENABLE_TLS=OFF", tls-lib: "", packages: "valgrind", snaps: "", diff --git a/CMakeLists.txt b/CMakeLists.txt index 14fe8d37..601b8025 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,8 +91,9 @@ else() endif() option(ENABLE_EXAMPLES "Build examples" ON) option(ENABLE_COVERAGE "Build code coverage report from tests" OFF) -option(ENABLE_SSH_TLS "Enable NETCONF over SSH and TLS support (via libssh and OpenSSL)" ON) -option(ENABLE_DNSSEC "Enable support for SSHFP retrieval using DNSSEC for SSH (requires OpenSSL and libval)" OFF) +option(ENABLE_SSH "Enable NETCONF over SSH support (requires libssh)" ON) +option(ENABLE_TLS "Enable NETCONF over TLS support (requires OpenSSL or MbedTLS)" ON) +option(ENABLE_DNSSEC "Enable support for SSHFP retrieval using DNSSEC for SSH (requires libval and OpenSSL)" OFF) option(ENABLE_PAM "Detect and use PAM" ON) option(ENABLE_COMMON_TARGETS "Define common custom target names such as 'doc' or 'uninstall', may cause conflicts when using add_subdirectory() to build this project" ON) option(ENABLE_IP_FREEBIND "Enable the IP_FREEBIND/IPV6_FREEBIND options on the listening TCP socket" OFF) @@ -121,21 +122,6 @@ set(libsrc src/server_config_util.c src/proxy_unix.c) -if(ENABLE_SSH_TLS) - list(APPEND libsrc - src/session_client_ssh.c - src/session_server_ssh.c - src/server_config_util_ssh.c - src/session_client_tls.c - src/session_server_tls.c - src/server_config_util_tls.c) - set(SSH_TLS_MACRO "#ifndef NC_ENABLED_SSH_TLS\n#define NC_ENABLED_SSH_TLS\n#endif") -endif() - -if(ENABLE_IP_FREEBIND) - check_symbol_exists(IP_FREEBIND "netinet/in.h" NC_ENABLE_IP_FREEBIND) -endif() - set(headers src/log.h src/netconf.h @@ -143,9 +129,7 @@ set(headers src/messages_client.h src/messages_server.h src/session_client.h - src/session_client_ch.h src/session_server.h - src/session_server_ch.h src/server_config.h src/proxy_unix.h) @@ -158,12 +142,47 @@ set(doxy_files src/messages_client.h src/messages_server.h src/session_client.h - src/session_client_ch.h src/session_server.h - src/session_server_ch.h src/server_config.h src/proxy_unix.h) +if(ENABLE_SSH) + list(APPEND libsrc + src/session_client_ssh.c + src/session_server_ssh.c + src/server_config_util_ssh.c) + list(APPEND headers + src/server_config_ssh.h) + list(APPEND doxy_files + src/server_config_ssh.h) + set(SSH_MACRO "#ifndef NC_SSH\n# define NC_SSH\n#endif") + set(SSH_SERVER_INCLUDE_MACRO "#include ") +endif() + +if(ENABLE_TLS) + list(APPEND libsrc + src/session_client_tls.c + src/session_server_tls.c + src/server_config_util_tls.c) + list(APPEND headers + src/server_config_tls.h) + list(APPEND doxy_files + src/server_config_tls.h) + set(TLS_MACRO "#ifndef NC_TLS\n# define NC_TLS\n#endif") + set(TLS_SERVER_INCLUDE_MACRO "#include ") +endif() + +if(ENABLE_SSH OR ENABLE_TLS) + list(APPEND headers + src/session_server_ch.h + src/session_client_ch.h) + list(APPEND doxy_files + src/session_server_ch.h + src/session_client_ch.h) + set(CH_SERVER_INCLUDE_MACRO "#include ") + set(CH_CLIENT_INCLUDE_MACRO "#include ") +endif() + # source files to be covered by the 'format' target set(format_sources compat/*.c @@ -177,15 +196,24 @@ set(format_sources # # checks # -if(ENABLE_DNSSEC AND NOT ENABLE_SSH_TLS) +if(ENABLE_DNSSEC AND NOT ENABLE_SSH) message(WARNING "DNSSEC SSHFP retrieval cannot be used without SSH support.") set(ENABLE_DNSSEC OFF) endif() -if(ENABLE_COMPLY_WITH_ORAN_WG11 AND NOT ENABLE_SSH_TLS) +if(ENABLE_COMPLY_WITH_ORAN_WG11 AND NOT ENABLE_TLS) message(WARNING "O-RAN WG11 compliance cannot be used without TLS support.") set(ENABLE_COMPLY_WITH_ORAN_WG11 OFF) endif() +if(ENABLE_COMPLY_WITH_ORAN_WG11) + # comply with the O-RAN WG11 security spec (e.g. client cert Extended Key Usage and Key Usage checks) + set(NC_COMPLY_WITH_ORAN_WG11 ON) +endif() + +if(ENABLE_EXAMPLES AND NOT ENABLE_SSH) + message(WARNING "Examples will not be compiled because SSH is disabled.") + set(ENABLE_EXAMPLES OFF) +endif() if(ENABLE_VALGRIND_TESTS) find_program(VALGRIND_FOUND valgrind) @@ -209,7 +237,7 @@ if(ENABLE_COVERAGE) gen_coverage_enable(${ENABLE_TESTS}) endif() -if ("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG") +if("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG") source_format_enable(0.77) endif() @@ -248,26 +276,51 @@ check_function_exists(pthread_timedjoin_np HAVE_PTHREAD_TIMEDJOIN_NP) # header file compatibility check_include_file("shadow.h" HAVE_SHADOW) check_include_file("termios.h" HAVE_TERMIOS) +if(ENABLE_IP_FREEBIND) + check_symbol_exists(IP_FREEBIND "netinet/in.h" NC_ENABLE_IP_FREEBIND) +endif() + +# dependencies - libval +if(ENABLE_DNSSEC) + find_package(LibVAL REQUIRED) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_DNSSEC") + target_link_libraries(netconf2 ${LIBVAL_LIBRARIES}) + include_directories(${LIBVAL_INCLUDE_DIRS}) +endif() -if(ENABLE_SSH_TLS) - # dependencies - mbedTLS (higher preference) or OpenSSL - find_package(MbedTLS 3.5.0) - if (MBEDTLS_FOUND) +if(ENABLE_SSH OR ENABLE_TLS) + # dependencies - mbedTLS (preferred normally) or OpenSSL (preferred and required with DNSSEC) + if(NOT ENABLE_DNSSEC) + find_package(MbedTLS 3.5.0) + endif() + if(MBEDTLS_FOUND) # dependencies - mbedtls set(HAVE_MBEDTLS TRUE) - list(APPEND libsrc src/session_mbedtls.c) + list(APPEND libsrc src/session_crypto_mbedtls.c) include_directories(${MBEDTLS_INCLUDE_DIRS}) target_link_libraries(netconf2 ${MBEDTLS_LIBRARIES}) list(APPEND CMAKE_REQUIRED_LIBRARIES ${MBEDTLS_LIBRARIES}) else() # dependencies - openssl find_package(OpenSSL 3.0.0 REQUIRED) - list(APPEND libsrc src/session_openssl.c) + list(APPEND libsrc src/session_crypto_openssl.c) include_directories(${OPENSSL_INCLUDE_DIR}) target_link_libraries(netconf2 ${OPENSSL_LIBRARIES}) list(APPEND CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) endif() + # dependencies - libcurl + find_package(CURL 7.30.0 REQUIRED) + if(TARGET CURL::libcurl) + target_link_libraries(netconf2 CURL::libcurl) + else() + target_link_libraries(netconf2 ${CURL_LIBRARIES}) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${CURL_LIBRARY}) + include_directories(${CURL_INCLUDE_DIRS}) + endif() +endif() + +if(ENABLE_SSH) # dependencies - libssh find_package(LibSSH 0.9.5 REQUIRED) target_link_libraries(netconf2 ${LIBSSH_LIBRARIES}) @@ -280,16 +333,6 @@ if(ENABLE_SSH_TLS) list(APPEND libsrc src/session_server_ssh_auth_message.c) endif() - # dependencies - libcurl - find_package(CURL 7.30.0 REQUIRED) - if(TARGET CURL::libcurl) - target_link_libraries(netconf2 CURL::libcurl) - else() - target_link_libraries(netconf2 ${CURL_LIBRARIES}) - list(APPEND CMAKE_REQUIRED_LIBRARIES ${CURL_LIBRARY}) - include_directories(${CURL_INCLUDE_DIRS}) - endif() - # crypt (if not found, assume no library needs to be linked) if(${CMAKE_SYSTEM_NAME} MATCHES "QNX") set(LIBCRYPT login) @@ -319,22 +362,6 @@ if(ENABLE_SSH_TLS) else() message(WARNING "SSH Keyboard Interactive system method: disabled") endif() - - # set compiler flag - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_ENABLED_SSH_TLS") - - # comply with the O-RAN WG11 security spec (e.g. client cert Extended Key Usage and Key Usage checks) - if(ENABLE_COMPLY_WITH_ORAN_WG11) - set(NC_COMPLY_WITH_ORAN_WG11 ON) - endif() -endif() - -# dependencies - libval -if(ENABLE_DNSSEC) - find_package(LibVAL REQUIRED) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_DNSSEC") - target_link_libraries(netconf2 ${LIBVAL_LIBRARIES}) - include_directories(${LIBVAL_INCLUDE_DIRS}) endif() # dependencies - libyang @@ -342,6 +369,14 @@ find_package(LibYANG ${LIBYANG_DEP_SOVERSION} REQUIRED) target_link_libraries(netconf2 ${LIBYANG_LIBRARIES}) include_directories(${LIBYANG_INCLUDE_DIRS}) +# set compiler flags +if(ENABLE_SSH) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_SSH") +endif() +if(ENABLE_TLS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_TLS") +endif() + # set sources target_sources(netconf2 PRIVATE ${libsrc} ${compatsrc}) @@ -384,11 +419,7 @@ endif() # examples if(ENABLE_EXAMPLES) - if(NOT ENABLE_SSH_TLS) - message(WARNING "Examples will not be compiled because SSH and TLS are disabled.") - else() - add_subdirectory(examples) - endif() + add_subdirectory(examples) endif() # tests diff --git a/Doxyfile.in b/Doxyfile.in index 9fd8854d..eec79256 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -2069,7 +2069,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = NC_ENABLED_SSH_TLS +PREDEFINED = NC_SSH NC_TLS # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/README.md b/README.md index 422688b4..47f2e053 100644 --- a/README.md +++ b/README.md @@ -120,11 +120,11 @@ $ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. The NETCONF protocol specification allows to use the protocol on top of several transport protocols. **libnetconf2** provides support for SSH and TLS transport. By default, both SSH and TLS transport is enabled. Disabling -and enabling both the transport protocols can be made +and enabling each of the transport protocols can be made in the same way. The following command has actually the same effect as specifying no option since it specifies the default settings. ``` -$ cmake -DENABLE_SSH_TLS=ON .. +$ cmake -DENABLE_SSH=ON -DENABLE_TLS=ON .. ``` ### DNSSEC SSHFP Retrieval diff --git a/nc_client.h.in b/nc_client.h.in index 0e0a36fb..20fc80cb 100644 --- a/nc_client.h.in +++ b/nc_client.h.in @@ -1,11 +1,11 @@ /** * @file nc_client.h * @author Radek Krejci - * @author Michal Vasko + * @author Michal Vasko * @brief libnetconf2 main public header for NETCONF clients. * * @copyright - * Copyright (c) 2015 - 2025 CESNET, z.s.p.o. + * Copyright (c) 2015 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. @@ -21,13 +21,16 @@ extern "C" { #endif -@SSH_TLS_MACRO@ +@SSH_MACRO@ + +@TLS_MACRO@ + +@CH_CLIENT_INCLUDE_MACRO@ #include #include #include #include -#include #include #ifdef __cplusplus diff --git a/nc_server.h.in b/nc_server.h.in index cb2f2437..79b2f74f 100644 --- a/nc_server.h.in +++ b/nc_server.h.in @@ -5,7 +5,7 @@ * @brief libnetconf2 main public header for NETCONF servers. * * @copyright - * Copyright (c) 2015 - 2025 CESNET, z.s.p.o. + * Copyright (c) 2015 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. @@ -21,14 +21,19 @@ extern "C" { #endif -@SSH_TLS_MACRO@ +@SSH_MACRO@ +@SSH_SERVER_INCLUDE_MACRO@ + +@TLS_MACRO@ +@TLS_SERVER_INCLUDE_MACRO@ + +@CH_SERVER_INCLUDE_MACRO@ #include #include #include #include #include -#include #ifdef __cplusplus } diff --git a/nc_version.h.in b/nc_version.h.in index 37c2e863..9d881b1e 100644 --- a/nc_version.h.in +++ b/nc_version.h.in @@ -4,7 +4,7 @@ * @brief libnetconf2 version information * * @copyright - * Copyright (c) 2021 - 2025 CESNET, z.s.p.o. + * Copyright (c) 2021 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. diff --git a/src/io.c b/src/io.c index bc403804..1e804032 100644 --- a/src/io.c +++ b/src/io.c @@ -41,11 +41,9 @@ #include "session.h" #include "session_p.h" -#ifdef NC_ENABLED_SSH_TLS - -#include "session_wrapper.h" - -#endif /* NC_ENABLED_SSH_TLS */ +#ifdef NC_TLS +# include "session_crypto_wrapper.h" +#endif /* NC_TLS */ const char *nc_msgtype2str[] = { "error", @@ -129,7 +127,7 @@ nc_read(struct nc_session *session, char *buf, uint32_t count, int no_wait, uint } break; -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH case NC_TI_SSH: /* read via libssh */ r = ssh_channel_read(session->ti.libssh.channel, buf + readd, count - readd, 0); @@ -151,7 +149,9 @@ nc_read(struct nc_session *session, char *buf, uint32_t count, int no_wait, uint break; } break; +#endif /* NC_SSH */ +#ifdef NC_TLS case NC_TI_TLS: r = nc_tls_read_wrap(session, (unsigned char *)buf + readd, count - readd); if (r < 0) { @@ -159,7 +159,7 @@ nc_read(struct nc_session *session, char *buf, uint32_t count, int no_wait, uint return r; } break; -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ } if (r == 0) { @@ -444,7 +444,7 @@ nc_read_poll(struct nc_session *session, int io_timeout) } switch (session->ti_type) { -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH case NC_TI_SSH: if (io_timeout == -1) { /* BUG libssh 0.11.0 replaces timeout -1 with 0 for non-blocking sessions */ @@ -471,6 +471,8 @@ nc_read_poll(struct nc_session *session, int io_timeout) fds.revents = 0; } break; +#endif /* NC_SSH */ +#ifdef NC_TLS case NC_TI_TLS: ret = nc_tls_get_num_pending_bytes_wrap(session->ti.tls.session); if (ret) { @@ -481,7 +483,7 @@ nc_read_poll(struct nc_session *session, int io_timeout) } fds.fd = nc_tls_get_fd_wrap(session); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ /* fallthrough */ case NC_TI_FD: case NC_TI_UNIX: @@ -598,14 +600,16 @@ nc_session_is_connected(const struct nc_session *session) case NC_TI_UNIX: fds.fd = session->ti.unixsock.sock; break; -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH case NC_TI_SSH: fds.fd = ssh_get_fd(session->ti.libssh.session); break; +#endif /* NC_SSH */ +#ifdef NC_TLS case NC_TI_TLS: fds.fd = nc_tls_get_fd_wrap(session); break; -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ default: return 0; } @@ -676,7 +680,7 @@ nc_write(struct nc_session *session, const void *buf, uint32_t count) } break; -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH case NC_TI_SSH: if (ssh_channel_is_closed(session->ti.libssh.channel)) { ERR(session, "SSH channel unexpectedly closed."); @@ -690,6 +694,8 @@ nc_write(struct nc_session *session, const void *buf, uint32_t count) return -1; } break; +#endif /* NC_SSH */ +#ifdef NC_TLS case NC_TI_TLS: c = nc_tls_write_wrap(session, (const unsigned char *)buf + written, count - written); if (c < 0) { @@ -697,7 +703,7 @@ nc_write(struct nc_session *session, const void *buf, uint32_t count) return -1; } break; -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ default: ERRINT; return -1; diff --git a/src/log.c b/src/log.c index 7b2c5a01..2ca36d6a 100644 --- a/src/log.c +++ b/src/log.c @@ -24,9 +24,9 @@ #include -#ifdef NC_ENABLED_SSH_TLS - #include -#endif /* NC_ENABLED_SSH_TLS */ +#ifdef NC_SSH +# include +#endif /* NC_SSH */ #include "compat.h" #include "config.h" @@ -65,7 +65,7 @@ struct { {NC_VERB_DEBUG_LOWLVL, "[DBL]"} }; -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH static void nc_libssh_log_cb(int priority, const char *UNUSED(function), const char *buffer, void *UNUSED(userdata)) @@ -99,7 +99,7 @@ nc_libssh_thread_verbosity(int level) ssh_set_log_level(level); } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH */ void nc_log_vprintf(const struct nc_session *session, NC_VERB_LEVEL level, const char *format, va_list args) diff --git a/src/log.h b/src/log.h index b4365ccc..c4492094 100644 --- a/src/log.h +++ b/src/log.h @@ -1,10 +1,11 @@ /** * @file log.h * @author Radek Krejci + * @author Michal Vasko * @brief libnetconf2 logger * * @copyright - * Copyright (c) 2015 - 2021 CESNET, z.s.p.o. + * Copyright (c) 2015 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. @@ -50,7 +51,7 @@ typedef enum NC_VERB_LEVEL { */ void nc_verbosity(NC_VERB_LEVEL level); -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH /** * @brief Set libssh verbosity level. @@ -69,7 +70,7 @@ void nc_verbosity(NC_VERB_LEVEL level); */ void nc_libssh_thread_verbosity(int level); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH */ /** * @brief Set libnetconf print callback. diff --git a/src/server_config.c b/src/server_config.c index 12633b95..46b151b5 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -125,145 +125,7 @@ nc_lyd_find_child_optional(const struct lyd_node *ctx_node, const char *child, s lyd_find_path(ctx_node, child, 0, match); } -/** - * @brief Get the instance a created or moved entry of an ordered-by user list should be placed after. - * - * The position is stored in the "key" metadata of the entry as a single key predicate - * (for example "[name='endpt']"), an empty value means the entry belongs first. - * - * @param[in] node List entry from the diff, the list is expected to have exactly one key. - * @param[out] anchor Name of the instance the entry should be placed after, NULL if it belongs first. - * Points into the metadata value, so it is not terminated, use @p anchor_len. - * @param[out] anchor_len Length of @p anchor. - * @param[out] move Whether the diff specifies a position at all. - * @return 0 on success, 1 on error. - */ -static int -nc_server_config_get_userord_anchor(const struct lyd_node *node, const char **anchor, uint32_t *anchor_len, int *move) -{ - struct lyd_meta *meta; - const char *val, *key_end, *val_end; - char quot; - - *anchor = NULL; - *anchor_len = 0; - *move = 0; - - meta = lyd_find_meta(node->meta, NULL, "yang:key"); - if (!meta) { - /* the diff says nothing about the position, for example because it was not created by libyang */ - return 0; - } - - *move = 1; - val = lyd_get_meta_value(meta); - if (!val[0]) { - /* the entry belongs first */ - return 0; - } - - key_end = strchr(val, '='); - if ((val[0] != '[') || !key_end) { - goto error; - } - - /* libyang always quotes the value with a quote it does not contain, so there is no escaping */ - quot = key_end[1]; - if ((quot != '\'') && (quot != '\"')) { - goto error; - } - - val_end = strchr(key_end + 2, quot); - if (!val_end || (val_end[1] != ']')) { - goto error; - } - - *anchor = key_end + 2; - *anchor_len = (uint32_t)(val_end - (key_end + 2)); - return 0; - -error: - ERR(NULL, "Invalid \"key\" metadata value \"%s\" of node \"%s\".", val, LYD_NAME(node)); - return 1; -} - -/** - * @brief Move an entry of an ordered-by user list to the position specified by the diff. - * - * The entries are stored in a sized array in the order they are configured in, so the item is - * moved within the array and the items in between are shifted. If the instance the entry should - * follow is not found, the entry is left where it is. - * - * @param[in] node List entry from the diff, the list is expected to have exactly one key. - * @param[in] index Current index of the entry in @p items. - * @param[in,out] items Sized array of the list entries. - * @param[in] item_size Size of a single item of @p items. - * @param[in] name_offset Offset of the entry name (the list key) within an item of @p items. - * @return 0 on success, 1 on error. - */ -static int -nc_server_config_move_userord_item(const struct lyd_node *node, LYA_COUNT_T index, void *items, - uint32_t item_size, uint32_t name_offset) -{ - int move = 0; - const char *anchor = NULL, *name; - uint32_t anchor_len = 0; - LYA_COUNT_T count, i, new_index; - char *item, *tmp; - - NC_CHECK_RET(nc_server_config_get_userord_anchor(node, &anchor, &anchor_len, &move)); - if (!move) { - /* keep the current position */ - return 0; - } - - count = LYA_COUNT(items); - assert(index < count); - - if (!anchor) { - /* the entry belongs first */ - new_index = 0; - } else { - /* find the instance the entry should follow */ - for (i = 0; i < count; ++i) { - name = *(char **)((char *)items + (i * item_size) + name_offset); - if (!strncmp(name, anchor, anchor_len) && !name[anchor_len]) { - break; - } - } - if (i == count) { - WRN(NULL, "Instance \"%.*s\" to order the node \"%s\" after not found, keeping its position.", - (int)anchor_len, anchor, LYD_NAME(node)); - return 0; - } - - /* the entry is removed from its current position first, which shifts a following anchor down */ - new_index = (i < index) ? i + 1 : i; - } - - if (new_index == index) { - /* already in place */ - return 0; - } - - tmp = malloc(item_size); - NC_CHECK_ERRMEM_RET(!tmp, 1); - - item = (char *)items + (index * item_size); - memcpy(tmp, item, item_size); - if (new_index > index) { - memmove(item, item + item_size, (new_index - index) * item_size); - } else { - memmove((char *)items + ((new_index + 1) * item_size), (char *)items + (new_index * item_size), - (index - new_index) * item_size); - } - memcpy((char *)items + (new_index * item_size), tmp, item_size); - - free(tmp); - return 0; -} - -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH /** * @brief Free SSH server options. @@ -273,8 +135,8 @@ nc_server_config_move_userord_item(const struct lyd_node *node, LYA_COUNT_T inde static void nc_server_config_ssh_opts_free(struct nc_server_ssh_opts *opts) { - struct nc_hostkey *hostkey; - struct nc_auth_client *auth_client; + struct nc_ssh_hostkey *hostkey; + struct nc_ssh_auth_client *auth_client; struct nc_public_key *pubkey; LYA_COUNT_T i = 0, j = 0; @@ -323,6 +185,10 @@ nc_server_config_ssh_opts_free(struct nc_server_ssh_opts *opts) free(opts); } +#endif /* NC_SSH */ + +#ifdef NC_TLS + /** * @brief Free TLS server options. * @@ -331,7 +197,7 @@ nc_server_config_ssh_opts_free(struct nc_server_ssh_opts *opts) static void nc_server_config_tls_opts_free(struct nc_server_tls_opts *opts) { - struct nc_ctn *ctn, *next; + struct nc_tls_ctn *ctn, *next; LYA_COUNT_T i = 0; if (!opts) { @@ -385,7 +251,7 @@ nc_server_config_tls_opts_free(struct nc_server_tls_opts *opts) free(opts); } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ /** * @brief Free UNIX server options. @@ -417,7 +283,7 @@ nc_server_config_unix_opts_free(struct nc_server_unix_opts *opts) free(opts); } -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /** * @brief Free keystore configuration data. @@ -499,7 +365,7 @@ nc_server_config_truststore_free(struct nc_truststore *ts) memset(ts, 0, sizeof(*ts)); } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ /** * @brief Free the data of a server configuration generation. @@ -541,14 +407,16 @@ nc_server_config_free(struct nc_server_config *config) /* free transport specific options */ switch (endpt->ti) { -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH case NC_TI_SSH: nc_server_config_ssh_opts_free(endpt->opts.ssh); break; +#endif /* NC_SSH */ +#ifdef NC_TLS case NC_TI_TLS: nc_server_config_tls_opts_free(endpt->opts.tls); break; -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ case NC_TI_UNIX: nc_server_config_unix_opts_free(endpt->opts.unix); break; @@ -575,14 +443,16 @@ nc_server_config_free(struct nc_server_config *config) /* free transport specific options */ switch (ch_endpt->ti) { -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH case NC_TI_SSH: nc_server_config_ssh_opts_free(ch_endpt->opts.ssh); break; +#endif /* NC_SSH */ +#ifdef NC_TLS case NC_TI_TLS: nc_server_config_tls_opts_free(ch_endpt->opts.tls); break; -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ default: ERRINT; break; @@ -592,14 +462,14 @@ nc_server_config_free(struct nc_server_config *config) } LYA_FREE(config->ch_clients); -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /* free keystore and truststore */ nc_server_config_keystore_free(&config->keystore); nc_server_config_truststore_free(&config->truststore); /* free certificate expiration intervals */ LYA_FREE(config->cert_exp_notif_intervals); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ memset(config, 0, sizeof(*config)); } @@ -664,8 +534,16 @@ nc_server_config_load_modules(struct ly_ctx **ctx) } } - /* all features */ - const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL}; + /* all features supported */ + const char *ietf_netconf_server[] = { +#ifdef NC_SSH + "ssh-listen", "ssh-call-home", +#endif /* NC_SSH */ +#ifdef NC_TLS + "tls-listen", "tls-call-home", +#endif /* NC_TLS */ + "central-netconf-server-supported", NULL + }; /* all features */ const char *ietf_x509_cert_to_name[] = {NULL}; /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification, @@ -717,7 +595,7 @@ nc_server_config_load_modules(struct ly_ctx **ctx) }; const char **module_features[] = { - ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common, + ietf_netconf_server, ietf_x509_cert_to_name, ietf_crypto_types, ietf_tcp_common, ietf_tcp_server, ietf_tcp_client, ietf_ssh_common, ietf_ssh_server, iana_ssh_encryption_algs, iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, iana_crypt_hash, ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs, @@ -747,7 +625,7 @@ nc_server_config_load_modules(struct ly_ctx **ctx) * ===================================================================================== */ -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) static int config_local_address(const struct lyd_node *node, enum nc_operation parent_op, struct nc_bind *bind) @@ -919,25 +797,6 @@ config_tcp_server_params(const struct lyd_node *node, enum nc_operation parent_o return 0; } -static int -config_hostkey_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_hostkey *hostkey) -{ - enum nc_operation op; - - NC_NODE_GET_OP(node, parent_op, &op); - - if (op == NC_OP_DELETE) { - free(hostkey->name); - hostkey->name = NULL; - } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(hostkey->name); - hostkey->name = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_RET(!hostkey->name, 1); - } - - return 0; -} - static int config_pubkey_format(const struct lyd_node *node, enum nc_operation parent_op, struct nc_public_key *pubkey) { @@ -1052,7 +911,184 @@ config_encrypted_privkey_data(const struct lyd_node *node, enum nc_operation UNU } static int -config_hostkey_pubkey_inline(const struct lyd_node *node, enum nc_operation parent_op, struct nc_hostkey *hostkey) +config_endpt_reference(const struct lyd_node *node, enum nc_operation parent_op, char **endpt_ref) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(*endpt_ref); + *endpt_ref = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(*endpt_ref); + *endpt_ref = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!*endpt_ref, 1); + } + + return 0; +} + +/** + * @brief Get the instance a created or moved entry of an ordered-by user list should be placed after. + * + * The position is stored in the "key" metadata of the entry as a single key predicate + * (for example "[name='endpt']"), an empty value means the entry belongs first. + * + * @param[in] node List entry from the diff, the list is expected to have exactly one key. + * @param[out] anchor Name of the instance the entry should be placed after, NULL if it belongs first. + * Points into the metadata value, so it is not terminated, use @p anchor_len. + * @param[out] anchor_len Length of @p anchor. + * @param[out] move Whether the diff specifies a position at all. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_get_userord_anchor(const struct lyd_node *node, const char **anchor, uint32_t *anchor_len, int *move) +{ + struct lyd_meta *meta; + const char *val, *key_end, *val_end; + char quot; + + *anchor = NULL; + *anchor_len = 0; + *move = 0; + + meta = lyd_find_meta(node->meta, NULL, "yang:key"); + if (!meta) { + /* the diff says nothing about the position, for example because it was not created by libyang */ + return 0; + } + + *move = 1; + val = lyd_get_meta_value(meta); + if (!val[0]) { + /* the entry belongs first */ + return 0; + } + + key_end = strchr(val, '='); + if ((val[0] != '[') || !key_end) { + goto error; + } + + /* libyang always quotes the value with a quote it does not contain, so there is no escaping */ + quot = key_end[1]; + if ((quot != '\'') && (quot != '\"')) { + goto error; + } + + val_end = strchr(key_end + 2, quot); + if (!val_end || (val_end[1] != ']')) { + goto error; + } + + *anchor = key_end + 2; + *anchor_len = (uint32_t)(val_end - (key_end + 2)); + return 0; + +error: + ERR(NULL, "Invalid \"key\" metadata value \"%s\" of node \"%s\".", val, LYD_NAME(node)); + return 1; +} + +/** + * @brief Move an entry of an ordered-by user list to the position specified by the diff. + * + * The entries are stored in a sized array in the order they are configured in, so the item is + * moved within the array and the items in between are shifted. If the instance the entry should + * follow is not found, the entry is left where it is. + * + * @param[in] node List entry from the diff, the list is expected to have exactly one key. + * @param[in] index Current index of the entry in @p items. + * @param[in,out] items Sized array of the list entries. + * @param[in] item_size Size of a single item of @p items. + * @param[in] name_offset Offset of the entry name (the list key) within an item of @p items. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_move_userord_item(const struct lyd_node *node, LYA_COUNT_T index, void *items, + uint32_t item_size, uint32_t name_offset) +{ + int move = 0; + const char *anchor = NULL, *name; + uint32_t anchor_len = 0; + LYA_COUNT_T count, i, new_index; + char *item, *tmp; + + NC_CHECK_RET(nc_server_config_get_userord_anchor(node, &anchor, &anchor_len, &move)); + if (!move) { + /* keep the current position */ + return 0; + } + + count = LYA_COUNT(items); + assert(index < count); + + if (!anchor) { + /* the entry belongs first */ + new_index = 0; + } else { + /* find the instance the entry should follow */ + for (i = 0; i < count; ++i) { + name = *(char **)((char *)items + (i * item_size) + name_offset); + if (!strncmp(name, anchor, anchor_len) && !name[anchor_len]) { + break; + } + } + if (i == count) { + WRN(NULL, "Instance \"%.*s\" to order the node \"%s\" after not found, keeping its position.", + (int)anchor_len, anchor, LYD_NAME(node)); + return 0; + } + + /* the entry is removed from its current position first, which shifts a following anchor down */ + new_index = (i < index) ? i + 1 : i; + } + + if (new_index == index) { + /* already in place */ + return 0; + } + + tmp = malloc(item_size); + NC_CHECK_ERRMEM_RET(!tmp, 1); + + item = (char *)items + (index * item_size); + memcpy(tmp, item, item_size); + if (new_index > index) { + memmove(item, item + item_size, (new_index - index) * item_size); + } else { + memmove((char *)items + ((new_index + 1) * item_size), (char *)items + (new_index * item_size), + (index - new_index) * item_size); + } + memcpy((char *)items + (new_index * item_size), tmp, item_size); + + free(tmp); + return 0; +} + +static int +config_ch_local_port(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_endpt *endpt) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + endpt->src_port = 0; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + endpt->src_port = strtoul(lyd_get_value(node), NULL, 10); + } + + return 0; +} + +#endif /* NC_SSH or NC_TLS */ + +#ifdef NC_SSH + +static int +config_ssh_hostkey_pubkey_inline(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_hostkey *hostkey) { struct lyd_node *n, *cleartext = NULL, *hidden = NULL, *encrypted = NULL; enum nc_operation op; @@ -1102,7 +1138,7 @@ config_hostkey_pubkey_inline(const struct lyd_node *node, enum nc_operation pare } static int -config_hostkey_pubkey_keystore(const struct lyd_node *node, enum nc_operation parent_op, struct nc_hostkey *hostkey) +config_ssh_hostkey_pubkey_keystore(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_hostkey *hostkey) { enum nc_operation op; @@ -1123,7 +1159,7 @@ config_hostkey_pubkey_keystore(const struct lyd_node *node, enum nc_operation pa } static int -config_hostkey_public_key(const struct lyd_node *node, enum nc_operation parent_op, struct nc_hostkey *hostkey) +config_ssh_hostkey_public_key(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_hostkey *hostkey) { enum nc_operation op; struct lyd_node *inline_def = NULL, *keystore_ref = NULL; @@ -1134,17 +1170,36 @@ config_hostkey_public_key(const struct lyd_node *node, enum nc_operation parent_ nc_lyd_find_child_optional(node, "inline-definition", &inline_def); nc_lyd_find_child_optional(node, "central-keystore-reference", &keystore_ref); if (inline_def) { - NC_CHECK_RET(config_hostkey_pubkey_inline(inline_def, op, hostkey)); + NC_CHECK_RET(config_ssh_hostkey_pubkey_inline(inline_def, op, hostkey)); } if (keystore_ref) { - NC_CHECK_RET(config_hostkey_pubkey_keystore(keystore_ref, op, hostkey)); + NC_CHECK_RET(config_ssh_hostkey_pubkey_keystore(keystore_ref, op, hostkey)); + } + + return 0; +} + +static int +config_ssh_hostkey_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_hostkey *hostkey) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(hostkey->name); + hostkey->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(hostkey->name); + hostkey->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!hostkey->name, 1); } return 0; } static int -config_hostkey_certificate(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +config_ssh_hostkey_certificate(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) { CONFIG_LOG_UNSUPPORTED(node); return 0; @@ -1155,7 +1210,7 @@ config_ssh_hostkey(const struct lyd_node *node, enum nc_operation parent_op, str { struct lyd_node *n, *public_key = NULL, *certificate = NULL; enum nc_operation op; - struct nc_hostkey *hostkey = NULL; + struct nc_ssh_hostkey *hostkey = NULL; const char *name; LYA_COUNT_T i = 0; @@ -1189,18 +1244,18 @@ config_ssh_hostkey(const struct lyd_node *node, enum nc_operation parent_op, str } /* config hostkey name */ - NC_CHECK_RET(config_hostkey_name(n, op, hostkey)); + NC_CHECK_RET(config_ssh_hostkey_name(n, op, hostkey)); /* config public-key / certificate */ nc_lyd_find_child_optional(node, "public-key", &public_key); nc_lyd_find_child_optional(node, "certificate", &certificate); if (public_key) { /* config public key */ - NC_CHECK_RET(config_hostkey_public_key(public_key, op, hostkey)); + NC_CHECK_RET(config_ssh_hostkey_public_key(public_key, op, hostkey)); } if (certificate) { /* config certificate */ - NC_CHECK_RET(config_hostkey_certificate(certificate, op)); + NC_CHECK_RET(config_ssh_hostkey_certificate(certificate, op)); } /* all children processed, we can now delete the hostkey */ @@ -1214,7 +1269,7 @@ config_ssh_hostkey(const struct lyd_node *node, enum nc_operation parent_op, str } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* the list is ordered-by user, place the hostkey at its configured position */ NC_CHECK_RET(nc_server_config_move_userord_item(node, i, ssh->hostkeys, - (uint32_t)sizeof *ssh->hostkeys, (uint32_t)offsetof(struct nc_hostkey, name))); + (uint32_t)sizeof *ssh->hostkeys, (uint32_t)offsetof(struct nc_ssh_hostkey, name))); } return 0; @@ -1267,7 +1322,7 @@ config_ssh_server_identity(const struct lyd_node *node, enum nc_operation parent } static int -config_ssh_user_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) +config_ssh_user_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_auth_client *user) { enum nc_operation op; @@ -1286,7 +1341,7 @@ config_ssh_user_name(const struct lyd_node *node, enum nc_operation parent_op, s } static int -config_pubkey_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_public_key *key) +config_ssh_pubkey_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_public_key *key) { enum nc_operation op; @@ -1305,7 +1360,7 @@ config_pubkey_name(const struct lyd_node *node, enum nc_operation parent_op, str } static int -config_ssh_user_public_key(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) +config_ssh_user_public_key(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_auth_client *user) { enum nc_operation op; struct lyd_node *n; @@ -1341,7 +1396,7 @@ config_ssh_user_public_key(const struct lyd_node *node, enum nc_operation parent } /* config public key name */ - NC_CHECK_RET(config_pubkey_name(n, op, key)); + NC_CHECK_RET(config_ssh_pubkey_name(n, op, key)); /* config public key format */ nc_lyd_find_child_optional(node, "public-key-format", &n); @@ -1367,7 +1422,7 @@ config_ssh_user_public_key(const struct lyd_node *node, enum nc_operation parent } static int -config_ssh_user_pubkey_inline(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) +config_ssh_user_pubkey_inline(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_auth_client *user) { struct lyd_node *n; enum nc_operation op; @@ -1389,7 +1444,7 @@ config_ssh_user_pubkey_inline(const struct lyd_node *node, enum nc_operation par } static int -config_ssh_user_pubkey_truststore(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) +config_ssh_user_pubkey_truststore(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_auth_client *user) { enum nc_operation op; @@ -1410,7 +1465,7 @@ config_ssh_user_pubkey_truststore(const struct lyd_node *node, enum nc_operation } static int -config_ssh_user_pubkey_system(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) +config_ssh_user_pubkey_system(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_auth_client *user) { enum nc_operation op; @@ -1426,7 +1481,7 @@ config_ssh_user_pubkey_system(const struct lyd_node *node, enum nc_operation par } static int -config_ssh_user_public_keys(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) +config_ssh_user_public_keys(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_auth_client *user) { struct lyd_node *inline_def = NULL, *truststore_ref = NULL, *system = NULL; enum nc_operation op; @@ -1451,7 +1506,7 @@ config_ssh_user_public_keys(const struct lyd_node *node, enum nc_operation paren } static int -config_ssh_user_hashed_password(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) +config_ssh_user_hashed_password(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_auth_client *user) { enum nc_operation op; @@ -1471,7 +1526,7 @@ config_ssh_user_hashed_password(const struct lyd_node *node, enum nc_operation p } static int -config_ssh_user_password(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) +config_ssh_user_password(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_auth_client *user) { struct lyd_node *n; enum nc_operation op; @@ -1496,7 +1551,7 @@ config_ssh_user_hostbased(const struct lyd_node *node, enum nc_operation UNUSED( } static int -config_ssh_user_none(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) +config_ssh_user_none(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ssh_auth_client *user) { enum nc_operation op; @@ -1513,16 +1568,16 @@ config_ssh_user_none(const struct lyd_node *node, enum nc_operation parent_op, s static int config_ssh_user_keyboard_interactive_system(const struct lyd_node *node, enum nc_operation parent_op, - struct nc_auth_client *user) + struct nc_ssh_auth_client *user) { enum nc_operation op; NC_NODE_GET_OP(node, parent_op, &op); if (op == NC_OP_DELETE) { - user->kbdint_method = NC_KBDINT_AUTH_METHOD_NONE; + user->kbdint_method = NC_SSH_KBDINT_AUTH_METHOD_NONE; } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - user->kbdint_method = NC_KBDINT_AUTH_METHOD_SYSTEM; + user->kbdint_method = NC_SSH_KBDINT_AUTH_METHOD_SYSTEM; } return 0; @@ -1530,7 +1585,7 @@ config_ssh_user_keyboard_interactive_system(const struct lyd_node *node, enum nc static int config_ssh_user_keyboard_interactive(const struct lyd_node *node, enum nc_operation parent_op, - struct nc_auth_client *user) + struct nc_ssh_auth_client *user) { struct lyd_node *system = NULL; enum nc_operation op; @@ -1551,7 +1606,7 @@ config_ssh_user(const struct lyd_node *node, enum nc_operation parent_op, struct { enum nc_operation op; struct lyd_node *n; - struct nc_auth_client *user = NULL; + struct nc_ssh_auth_client *user = NULL; const char *name; uint32_t i = 0; @@ -1674,25 +1729,6 @@ config_ssh_max_auth_attempts(const struct lyd_node *node, enum nc_operation UNUS return 0; } -static int -config_endpt_reference(const struct lyd_node *node, enum nc_operation parent_op, char **endpt_ref) -{ - enum nc_operation op; - - NC_NODE_GET_OP(node, parent_op, &op); - - if (op == NC_OP_DELETE) { - free(*endpt_ref); - *endpt_ref = NULL; - } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(*endpt_ref); - *endpt_ref = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_RET(!*endpt_ref, 1); - } - - return 0; -} - static int config_ssh_client_auth(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { @@ -1740,6 +1776,17 @@ config_ssh_client_auth(const struct lyd_node *node, enum nc_operation parent_op, return 0; } +#endif /* NC_SSH */ + +#if defined (NC_SSH) || defined (NC_TLS) + +static int +config_generate_csr(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} + /** * @brief Delete an algorithm from a @p sep separated list of algorithms. * @@ -1839,8 +1886,12 @@ nc_server_config_add_alg(char **list, const char *alg, const char sep) return 0; } +#endif /* NC_SSH or NC_TLS */ + +#ifdef NC_SSH + static int -config_hostkey_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) +config_ssh_hostkey_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { enum nc_operation op; const char *alg; @@ -1870,7 +1921,7 @@ config_hostkey_alg(const struct lyd_node *node, enum nc_operation parent_op, str } static int -config_transport_param_hkalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) +config_ssh_transport_param_hkalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { enum nc_operation op; struct lyd_node *n; @@ -1879,14 +1930,14 @@ config_transport_param_hkalgs(const struct lyd_node *node, enum nc_operation par /* configure all host-key algorithms (leaf-lists) */ LY_LIST_FOR(lyd_child(node), n) { - NC_CHECK_RET(config_hostkey_alg(n, op, ssh)); + NC_CHECK_RET(config_ssh_hostkey_alg(n, op, ssh)); } return 0; } static int -config_kex_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) +config_ssh_kex_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { enum nc_operation op; const char *alg; @@ -1913,7 +1964,7 @@ config_kex_alg(const struct lyd_node *node, enum nc_operation parent_op, struct } static int -config_transport_param_kexalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) +config_ssh_transport_param_kexalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { enum nc_operation op; struct lyd_node *n; @@ -1922,14 +1973,14 @@ config_transport_param_kexalgs(const struct lyd_node *node, enum nc_operation pa /* configure all kex algorithms (leaf-lists) */ LY_LIST_FOR(lyd_child(node), n) { - NC_CHECK_RET(config_kex_alg(n, op, ssh)); + NC_CHECK_RET(config_ssh_kex_alg(n, op, ssh)); } return 0; } static int -config_enc_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) +config_ssh_enc_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { enum nc_operation op; const char *alg; @@ -1956,7 +2007,7 @@ config_enc_alg(const struct lyd_node *node, enum nc_operation parent_op, struct } static int -config_transport_param_encalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) +config_ssh_transport_param_encalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { enum nc_operation op; struct lyd_node *n; @@ -1965,14 +2016,14 @@ config_transport_param_encalgs(const struct lyd_node *node, enum nc_operation pa /* configure all encryption algorithms (leaf-lists) */ LY_LIST_FOR(lyd_child(node), n) { - NC_CHECK_RET(config_enc_alg(n, op, ssh)); + NC_CHECK_RET(config_ssh_enc_alg(n, op, ssh)); } return 0; } static int -config_mac_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) +config_ssh_mac_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { enum nc_operation op; const char *alg; @@ -1999,7 +2050,7 @@ config_mac_alg(const struct lyd_node *node, enum nc_operation parent_op, struct } static int -config_transport_param_macalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) +config_ssh_transport_param_macalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { enum nc_operation op; struct lyd_node *n; @@ -2008,7 +2059,7 @@ config_transport_param_macalgs(const struct lyd_node *node, enum nc_operation pa /* configure all mac algorithms (leaf-lists) */ LY_LIST_FOR(lyd_child(node), n) { - NC_CHECK_RET(config_mac_alg(n, op, ssh)); + NC_CHECK_RET(config_ssh_mac_alg(n, op, ssh)); } return 0; @@ -2025,25 +2076,25 @@ config_ssh_transport_params(const struct lyd_node *node, enum nc_operation paren /* config host-key */ nc_lyd_find_child_optional(node, "host-key", &n); if (n) { - NC_CHECK_RET(config_transport_param_hkalgs(n, op, ssh)); + NC_CHECK_RET(config_ssh_transport_param_hkalgs(n, op, ssh)); } /* config kex-algorithms */ nc_lyd_find_child_optional(node, "key-exchange", &n); if (n) { - NC_CHECK_RET(config_transport_param_kexalgs(n, op, ssh)); + NC_CHECK_RET(config_ssh_transport_param_kexalgs(n, op, ssh)); } /* config encryption-algorithms */ nc_lyd_find_child_optional(node, "encryption", &n); if (n) { - NC_CHECK_RET(config_transport_param_encalgs(n, op, ssh)); + NC_CHECK_RET(config_ssh_transport_param_encalgs(n, op, ssh)); } /* config mac-algorithms */ nc_lyd_find_child_optional(node, "mac", &n); if (n) { - NC_CHECK_RET(config_transport_param_macalgs(n, op, ssh)); + NC_CHECK_RET(config_ssh_transport_param_macalgs(n, op, ssh)); } return 0; @@ -2141,8 +2192,12 @@ config_ssh(const struct lyd_node *node, enum nc_operation parent_op, struct nc_e return 0; } +#endif /* NC_SSH */ + +#ifdef NC_TLS + static int -config_cert_data(const struct lyd_node *node, enum nc_operation parent_op, struct nc_certificate *cert) +config_tls_cert_data(const struct lyd_node *node, enum nc_operation parent_op, struct nc_certificate *cert) { enum nc_operation op; @@ -2161,14 +2216,7 @@ config_cert_data(const struct lyd_node *node, enum nc_operation parent_op, struc } static int -config_generate_csr(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) -{ - CONFIG_LOG_UNSUPPORTED(node); - return 0; -} - -static int -config_cert_expiration(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +config_tls_cert_expiration(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) { CONFIG_LOG_UNSUPPORTED(node); return 0; @@ -2219,7 +2267,7 @@ config_tls_server_ident_cert_inline(const struct lyd_node *node, enum nc_operati /* config certificate data */ nc_lyd_find_child_optional(node, "cert-data", &n); if (n) { - NC_CHECK_RET(config_cert_data(n, op, &opts->local.cert), 1); + NC_CHECK_RET(config_tls_cert_data(n, op, &opts->local.cert), 1); } /* config generate csr */ @@ -2231,7 +2279,7 @@ config_tls_server_ident_cert_inline(const struct lyd_node *node, enum nc_operati /* config certificate expiration */ nc_lyd_find_child_optional(node, "certificate-expiration", &n); if (n) { - NC_CHECK_RET(config_cert_expiration(n, op), 1); + NC_CHECK_RET(config_tls_cert_expiration(n, op), 1); } if (op == NC_OP_DELETE) { @@ -2242,8 +2290,8 @@ config_tls_server_ident_cert_inline(const struct lyd_node *node, enum nc_operati } static int -config_tls_server_ident_cert_keystore_asym_key_ref(const struct lyd_node *node, - enum nc_operation parent_op, struct nc_server_tls_opts *tls) +config_tls_server_ident_cert_keystore_asym_key_ref(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_tls_opts *tls) { enum nc_operation op; @@ -2262,8 +2310,8 @@ config_tls_server_ident_cert_keystore_asym_key_ref(const struct lyd_node *node, } static int -config_tls_server_ident_cert_keystore_cert_ref(const struct lyd_node *node, - enum nc_operation parent_op, struct nc_server_tls_opts *tls) +config_tls_server_ident_cert_keystore_cert_ref(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_tls_opts *tls) { enum nc_operation op; @@ -2383,7 +2431,7 @@ config_tls_server_identity(const struct lyd_node *node, enum nc_operation parent } static int -config_cert_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_certificate *cert) +config_tls_cert_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_certificate *cert) { enum nc_operation op; @@ -2439,18 +2487,18 @@ config_tls_client_auth_ca_cert(const struct lyd_node *node, } /* config ca-cert name */ - NC_CHECK_RET(config_cert_name(n, op, cert)); + NC_CHECK_RET(config_tls_cert_name(n, op, cert)); /* config ca-cert data */ nc_lyd_find_child_optional(node, "cert-data", &n); if (n) { - NC_CHECK_RET(config_cert_data(n, op, cert)); + NC_CHECK_RET(config_tls_cert_data(n, op, cert)); } /* config certificate expiration */ nc_lyd_find_child_optional(node, "certificate-expiration", &n); if (n) { - NC_CHECK_RET(config_cert_expiration(n, op), 1); + NC_CHECK_RET(config_tls_cert_expiration(n, op), 1); } /* all children processed, we can now delete the ca-cert */ @@ -2510,7 +2558,8 @@ config_tls_client_auth_ca_certs_truststore(const struct lyd_node *node, } static int -config_tls_client_auth_ca_certs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_client_auth *client_auth) +config_tls_client_auth_ca_certs(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_tls_client_auth *client_auth) { struct lyd_node *inline_def, *truststore_ref; enum nc_operation op; @@ -2531,8 +2580,8 @@ config_tls_client_auth_ca_certs(const struct lyd_node *node, enum nc_operation p } static int -config_tls_client_auth_ee_cert(const struct lyd_node *node, - enum nc_operation parent_op, struct nc_server_tls_client_auth *client_auth) +config_tls_client_auth_ee_cert(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_tls_client_auth *client_auth) { enum nc_operation op; struct lyd_node *n; @@ -2568,18 +2617,18 @@ config_tls_client_auth_ee_cert(const struct lyd_node *node, } /* config ee-cert name */ - NC_CHECK_RET(config_cert_name(n, op, cert)); + NC_CHECK_RET(config_tls_cert_name(n, op, cert)); /* config ee-cert data */ nc_lyd_find_child_optional(node, "cert-data", &n); if (n) { - NC_CHECK_RET(config_cert_data(n, op, cert)); + NC_CHECK_RET(config_tls_cert_data(n, op, cert)); } /* config certificate expiration */ nc_lyd_find_child_optional(node, "certificate-expiration", &n); if (n) { - NC_CHECK_RET(config_cert_expiration(n, op), 1); + NC_CHECK_RET(config_tls_cert_expiration(n, op), 1); } /* all children processed, we can now delete the ee-cert */ @@ -2736,7 +2785,7 @@ config_tls_client_auth(const struct lyd_node *node, enum nc_operation parent_op, * @return 0 on success, 1 on error. */ static int -nc_server_config_str2tls_version(const char *str, enum nc_tls_version *version) +config_tls_str2tls_version(const char *str, enum nc_tls_version *version) { *version = NC_TLS_VERSION_NONE; @@ -2767,7 +2816,7 @@ config_tls_version_min(const struct lyd_node *node, enum nc_operation parent_op, ver = ((struct lyd_node_term *)node)->value.ident->name; assert(ver); - NC_CHECK_RET(nc_server_config_str2tls_version(ver, &v)); + NC_CHECK_RET(config_tls_str2tls_version(ver, &v)); tls->min_version = v; } @@ -2789,7 +2838,7 @@ config_tls_version_max(const struct lyd_node *node, enum nc_operation parent_op, ver = ((struct lyd_node_term *)node)->value.ident->name; assert(ver); - NC_CHECK_RET(nc_server_config_str2tls_version(ver, &v)); + NC_CHECK_RET(config_tls_str2tls_version(ver, &v)); tls->max_version = v; } @@ -2936,7 +2985,7 @@ config_tls_server_params(const struct lyd_node *node, enum nc_operation parent_o } static int -config_fingerprint(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ctn *ctn) +config_tls_fingerprint(const struct lyd_node *node, enum nc_operation parent_op, struct nc_tls_ctn *ctn) { enum nc_operation op; @@ -2955,7 +3004,7 @@ config_fingerprint(const struct lyd_node *node, enum nc_operation parent_op, str } static int -config_map_type(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ctn *ctn) +config_tls_map_type(const struct lyd_node *node, enum nc_operation parent_op, struct nc_tls_ctn *ctn) { enum nc_operation op; const char *type; @@ -2990,7 +3039,7 @@ config_map_type(const struct lyd_node *node, enum nc_operation parent_op, struct } static int -config_ctn_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ctn *ctn) +config_tls_ctn_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_tls_ctn *ctn) { enum nc_operation op; @@ -3009,12 +3058,12 @@ config_ctn_name(const struct lyd_node *node, enum nc_operation parent_op, struct } static int -config_cert_to_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) +config_tls_cert_to_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { struct lyd_node *n; enum nc_operation op; uint32_t id; - struct nc_ctn *ctn = NULL, *iter, *prev = NULL; + struct nc_tls_ctn *ctn = NULL, *iter, *prev = NULL; NC_NODE_GET_OP(node, parent_op, &op); @@ -3058,19 +3107,19 @@ config_cert_to_name(const struct lyd_node *node, enum nc_operation parent_op, st /* config fingerprint */ nc_lyd_find_child_optional(node, "fingerprint", &n); if (n) { - NC_CHECK_RET(config_fingerprint(n, op, ctn)); + NC_CHECK_RET(config_tls_fingerprint(n, op, ctn)); } /* config map type */ nc_lyd_find_child_optional(node, "map-type", &n); if (n) { - NC_CHECK_RET(config_map_type(n, op, ctn)); + NC_CHECK_RET(config_tls_map_type(n, op, ctn)); } /* config name */ nc_lyd_find_child_optional(node, "name", &n); if (n) { - NC_CHECK_RET(config_ctn_name(n, op, ctn)); + NC_CHECK_RET(config_tls_ctn_name(n, op, ctn)); } /* all children processed, we can now delete the ctn */ @@ -3089,7 +3138,7 @@ config_cert_to_name(const struct lyd_node *node, enum nc_operation parent_op, st } static int -config_client_identity_mappings(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) +config_tls_client_identity_mappings(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { struct lyd_node *n; enum nc_operation op; @@ -3098,7 +3147,7 @@ config_client_identity_mappings(const struct lyd_node *node, enum nc_operation p /* config all cert to name mappings */ LY_LIST_FOR(lyd_child(node), n) { - NC_CHECK_RET(config_cert_to_name(n, op, tls)); + NC_CHECK_RET(config_tls_cert_to_name(n, op, tls)); } return 0; @@ -3115,7 +3164,7 @@ config_tls_netconf_server_params(const struct lyd_node *node, enum nc_operation /* config client identity mappings */ nc_lyd_find_child_optional(node, "client-identity-mappings", &n); if (n) { - NC_CHECK_RET(config_client_identity_mappings(n, op, tls)); + NC_CHECK_RET(config_tls_client_identity_mappings(n, op, tls)); } return 0; @@ -3164,7 +3213,7 @@ config_tls(const struct lyd_node *node, enum nc_operation parent_op, struct nc_e return 0; } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ static int config_unix_socket_path(const struct lyd_node *node, enum nc_operation parent_op, struct nc_endpt *endpt) @@ -3560,7 +3609,7 @@ static int config_endpoint(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_config *config) { - struct lyd_node *n, *ssh, *tls, *unix; + struct lyd_node *n, *cont; enum nc_operation op; struct nc_endpt *endpt = NULL; const char *name; @@ -3597,20 +3646,23 @@ config_endpoint(const struct lyd_node *node, enum nc_operation parent_op, NC_CHECK_RET(config_endpoint_name(n, op, endpt)); /* config ssh/tls/unix (augment) choice */ - nc_lyd_find_child_optional(node, "ssh", &ssh); - nc_lyd_find_child_optional(node, "tls", &tls); - nc_lyd_find_child_optional(node, "libnetconf2-netconf-server:unix", &unix); - -#ifdef NC_ENABLED_SSH_TLS - if (ssh) { - NC_CHECK_RET(config_ssh(ssh, op, endpt)); +#ifdef NC_SSH + nc_lyd_find_child_optional(node, "ssh", &cont); + if (cont) { + NC_CHECK_RET(config_ssh(cont, op, endpt)); } - if (tls) { - NC_CHECK_RET(config_tls(tls, op, endpt)); +#endif /* NC_SSH */ + +#ifdef NC_TLS + nc_lyd_find_child_optional(node, "tls", &cont); + if (cont) { + NC_CHECK_RET(config_tls(cont, op, endpt)); } -#endif /* NC_ENABLED_SSH_TLS */ - if (unix) { - NC_CHECK_RET(config_unix(unix, op, endpt)); +#endif /* NC_TLS */ + + nc_lyd_find_child_optional(node, "libnetconf2-netconf-server:unix", &cont); + if (cont) { + NC_CHECK_RET(config_unix(cont, op, endpt)); } /* all children processed, we can now delete the endpoint */ @@ -3674,6 +3726,8 @@ config_listen(const struct lyd_node *node, enum nc_operation parent_op, return 0; } +#if defined (NC_SSH) || defined (NC_TLS) + static int config_ch_client_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_client *client) { @@ -3693,8 +3747,6 @@ config_ch_client_name(const struct lyd_node *node, enum nc_operation parent_op, return 0; } -#ifdef NC_ENABLED_SSH_TLS - static int config_remote_address(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_endpt *endpt) { @@ -3741,22 +3793,6 @@ config_ch_local_address(const struct lyd_node *node, enum nc_operation parent_op return 0; } -static int -config_ch_local_port(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_endpt *endpt) -{ - enum nc_operation op; - - NC_NODE_GET_OP(node, parent_op, &op); - - if (op == NC_OP_DELETE) { - endpt->src_port = 0; - } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->src_port = strtoul(lyd_get_value(node), NULL, 10); - } - - return 0; -} - static int config_proxy_server(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) { @@ -3811,6 +3847,8 @@ config_tcp_client_params(const struct lyd_node *node, enum nc_operation parent_o return 0; } +#ifdef NC_SSH + static int config_ch_endpoint_ssh(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_endpt *endpt) { @@ -3853,6 +3891,10 @@ config_ch_endpoint_ssh(const struct lyd_node *node, enum nc_operation parent_op, return 0; } +#endif /* NC_SSH */ + +#ifdef NC_TLS + static int config_ch_endpoint_tls(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_endpt *endpt) { @@ -3895,7 +3937,7 @@ config_ch_endpoint_tls(const struct lyd_node *node, enum nc_operation parent_op, return 0; } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ static int config_ch_endpoint_name(const struct lyd_node *node, enum nc_operation op, @@ -3955,19 +3997,24 @@ config_ch_client_endpoint(const struct lyd_node *node, enum nc_operation parent_ /* config name */ NC_CHECK_RET(config_ch_endpoint_name(n, op, endpt)); -#ifdef NC_ENABLED_SSH_TLS - struct lyd_node *ssh, *tls; +#ifdef NC_SSH + struct lyd_node *ssh; /* config ssh/tls choice */ nc_lyd_find_child_optional(node, "ssh", &ssh); - nc_lyd_find_child_optional(node, "tls", &tls); if (ssh) { NC_CHECK_RET(config_ch_endpoint_ssh(ssh, op, endpt)); } +#endif /* NC_SSH */ + +#ifdef NC_TLS + struct lyd_node *tls; + + nc_lyd_find_child_optional(node, "tls", &tls); if (tls) { NC_CHECK_RET(config_ch_endpoint_tls(tls, op, endpt)); } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ /* all children processed, we can now delete the endpoint */ if (op == NC_OP_DELETE) { @@ -4190,8 +4237,7 @@ config_ch_client_reconnect_strategy(const struct lyd_node *node, enum nc_operati } static int -config_netconf_client(const struct lyd_node *node, enum nc_operation parent_op, - struct nc_server_config *config) +config_netconf_client(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_config *config) { struct lyd_node *n; enum nc_operation op; @@ -4276,6 +4322,8 @@ config_call_home(const struct lyd_node *node, enum nc_operation parent_op, return 0; } +#endif /* NC_SSH or NC_TLS */ + /** * @brief Handler for the /ietf-netconf-server:netconf-server configuration subtree. * @@ -4300,11 +4348,13 @@ config_netconf_server(const struct lyd_node *node, enum nc_operation parent_op, NC_CHECK_RET(config_listen(n, op, config)); } +#if defined (NC_SSH) || defined (NC_TLS) /* configure call-home */ nc_lyd_find_child_optional(node, "call-home", &n); if (n) { NC_CHECK_RET(config_call_home(n, op, config)); } +#endif /* NC_SSH or NC_TLS */ return 0; } @@ -4350,7 +4400,7 @@ nc_server_config_netconf_server(const struct lyd_node *tree, int is_diff, struct return rc; } -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /* * ===================================================================================== @@ -5134,7 +5184,7 @@ nc_server_config_truststore(const struct lyd_node *tree, int is_diff, struct nc_ return rc; } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ /* * ===================================================================================== @@ -5142,7 +5192,7 @@ nc_server_config_truststore(const struct lyd_node *tree, int is_diff, struct nc_ * ===================================================================================== */ -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /** * @brief Convert a string representation of certificate expiration time to struct. @@ -5305,7 +5355,7 @@ config_cert_exp_notif_intervals(const struct lyd_node *node, enum nc_operation p return 0; } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ static int config_ignored_hello_module(const struct lyd_node *node, enum nc_operation parent_op, @@ -5358,7 +5408,7 @@ config_ignored_hello_module(const struct lyd_node *node, enum nc_operation paren return 0; } -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH static int config_ssh_password_lockout(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_config *config) @@ -5393,7 +5443,7 @@ config_ssh_password_lockout(const struct lyd_node *node, enum nc_operation paren return 0; } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH */ static int config_ln2_netconf_server(const struct lyd_node *node, enum nc_operation parent_op, @@ -5405,7 +5455,7 @@ config_ln2_netconf_server(const struct lyd_node *node, enum nc_operation parent_ NC_NODE_GET_OP(node, parent_op, &op); -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) struct lyd_node *n; /* config certificate-expiration-notif-intervals */ @@ -5413,13 +5463,15 @@ config_ln2_netconf_server(const struct lyd_node *node, enum nc_operation parent_ if (n) { NC_CHECK_RET(config_cert_exp_notif_intervals(n, op, config)); } +#endif /* NC_SSH or NC_TLS */ +#ifdef NC_SSH /* config ssh-password-lockout */ nc_lyd_find_child_optional(node, "ssh-password-lockout", &n); if (n) { NC_CHECK_RET(config_ssh_password_lockout(n, op, config)); } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH */ /* config all ignored-hello-modules */ NC_CHECK_RET(lyd_find_xpath(node, "ignored-hello-module", &set), 1); @@ -5474,7 +5526,7 @@ nc_server_config_libnetconf2_netconf_server(const struct lyd_node *tree, int is_ return rc; } -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH /** * @brief Create a deep copy of the SSH server options. @@ -5488,10 +5540,10 @@ nc_server_config_ssh_dup(const struct nc_server_ssh_opts *src, struct nc_server_ { int rc = 0; uint32_t i, j; - const struct nc_hostkey *src_hostkey; - struct nc_hostkey *dst_hostkey; - const struct nc_auth_client *src_auth_client; - struct nc_auth_client *dst_auth_client; + const struct nc_ssh_hostkey *src_hostkey; + struct nc_ssh_hostkey *dst_hostkey; + const struct nc_ssh_auth_client *src_auth_client; + struct nc_ssh_auth_client *dst_auth_client; *dst = calloc(1, sizeof **dst); NC_CHECK_ERRMEM_RET(!*dst, 1); @@ -5605,6 +5657,10 @@ nc_server_config_ssh_dup(const struct nc_server_ssh_opts *src, struct nc_server_ return rc; } +#endif /* NC_SSH */ + +#ifdef NC_TLS + /** * @brief Create a deep copy of the TLS server options. * @@ -5619,8 +5675,8 @@ nc_server_config_tls_dup(const struct nc_server_tls_opts *src, struct nc_server_ uint32_t i; const struct nc_server_tls_client_auth *src_ca; struct nc_server_tls_client_auth *dst_ca; - const struct nc_ctn *src_ctn; - struct nc_ctn *dst_ctn, *prev_ctn; + const struct nc_tls_ctn *src_ctn; + struct nc_tls_ctn *dst_ctn, *prev_ctn; *dst = calloc(1, sizeof **dst); NC_CHECK_ERRMEM_RET(!*dst, 1); @@ -5738,7 +5794,7 @@ nc_server_config_tls_dup(const struct nc_server_tls_opts *src, struct nc_server_ return rc; } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ /** * @brief Create a deep copy of the UNIX server options. @@ -5789,7 +5845,7 @@ nc_server_config_unix_dup(const struct nc_server_unix_opts *src, struct nc_serve return rc; } -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /** * @brief Create a deep copy of the keystore. @@ -5948,7 +6004,7 @@ nc_server_config_truststore_dup(const struct nc_truststore *src, struct nc_trust return rc; } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ /** * @brief Create a deep copy of the server configuration. @@ -6003,16 +6059,18 @@ nc_server_config_dup(const struct nc_server_config *src, struct nc_server_config dst_endpt->ti = src_endpt->ti; switch (src_endpt->ti) { -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH case NC_TI_SSH: NC_CHECK_ERR_GOTO(rc = nc_server_config_ssh_dup(src_endpt->opts.ssh, &dst_endpt->opts.ssh), ERR(NULL, "Duplicating SSH transport information failed."), cleanup); break; +#endif /* NC_SSH */ +#ifdef NC_TLS case NC_TI_TLS: NC_CHECK_ERR_GOTO(rc = nc_server_config_tls_dup(src_endpt->opts.tls, &dst_endpt->opts.tls), ERR(NULL, "Duplicating TLS transport information failed."), cleanup); break; -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ case NC_TI_UNIX: NC_CHECK_ERR_GOTO(rc = nc_server_config_unix_dup(src_endpt->opts.unix, &dst_endpt->opts.unix), ERR(NULL, "Duplicating UNIX transport information failed."), cleanup); @@ -6059,16 +6117,18 @@ nc_server_config_dup(const struct nc_server_config *src, struct nc_server_config dst_ch_endpt->ti = src_ch_endpt->ti; switch (src_ch_endpt->ti) { -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH case NC_TI_SSH: NC_CHECK_ERR_GOTO(rc = nc_server_config_ssh_dup(src_ch_endpt->opts.ssh, &dst_ch_endpt->opts.ssh), ERR(NULL, "Duplicating SSH transport information failed."), cleanup); break; +#endif /* NC_SSH */ +#ifdef NC_TLS case NC_TI_TLS: NC_CHECK_ERR_GOTO(rc = nc_server_config_tls_dup(src_ch_endpt->opts.tls, &dst_ch_endpt->opts.tls), ERR(NULL, "Duplicating TLS transport information failed."), cleanup); break; -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ default: break; } @@ -6090,7 +6150,7 @@ nc_server_config_dup(const struct nc_server_config *src, struct nc_server_config LYA_INCREMENT(dst->ch_clients); } -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /* dup keystore */ NC_CHECK_ERR_GOTO(rc = nc_server_config_keystore_dup(&src->keystore, &dst->keystore), ERR(NULL, "Duplicating keystore failed."), cleanup); @@ -6106,15 +6166,17 @@ nc_server_config_dup(const struct nc_server_config *src, struct nc_server_config dst->cert_exp_notif_intervals[i] = src->cert_exp_notif_intervals[i]; LYA_INCREMENT(dst->cert_exp_notif_intervals); } +#endif /* NC_SSH or NC_TLS */ +#ifdef NC_SSH dst->authlock = src->authlock; -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH */ cleanup: return rc; } -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /** * @brief Wake up the certificate expiration notification thread to update its data. @@ -6131,7 +6193,7 @@ nc_server_config_cert_exp_notif_thread_wakeup(void) nc_mutex_unlock(&server_opts.cert_exp_notif.lock, __func__); } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ /** * @brief Allocate a new server configuration generation. @@ -6203,7 +6265,7 @@ nc_server_config_setup_diff(const struct lyd_node *data) nc_server_config_release(cur_config); cur_config = NULL; -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /* configure keystore */ NC_CHECK_ERR_GOTO(ret = nc_server_config_keystore(data, 1, config_copy), ERR(NULL, "Applying ietf-keystore configuration failed."), cleanup); @@ -6211,7 +6273,7 @@ nc_server_config_setup_diff(const struct lyd_node *data) /* configure truststore */ NC_CHECK_ERR_GOTO(ret = nc_server_config_truststore(data, 1, config_copy), ERR(NULL, "Applying ietf-truststore configuration failed."), cleanup); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ /* configure netconf-server */ NC_CHECK_ERR_GOTO(ret = nc_server_config_netconf_server(data, 1, config_copy), @@ -6225,12 +6287,12 @@ nc_server_config_setup_diff(const struct lyd_node *data) NC_CHECK_ERR_GOTO(ret = nc_server_binds_reconcile(config_copy), ERR(NULL, "Starting to listen on new endpoints failed."), cleanup); -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /* dispatch new call-home threads, the listening sockets are already reconciled with the new * generation so a failure here has to be rolled back */ NC_CHECK_ERR_GOTO(ret = nc_server_ch_clients_reconcile(config_copy), ERR(NULL, "Dispatching new call-home threads failed."), rollback); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ /* CONFIG WR LOCK - only the pointer swap */ if (nc_rwlock_lock(&server_opts.config_lock, NC_RWLOCK_WRITE, NC_CONFIG_LOCK_TIMEOUT, __func__) != 1) { @@ -6249,10 +6311,10 @@ nc_server_config_setup_diff(const struct lyd_node *data) /* the old generation is freed once its last reader releases it */ nc_server_config_release(old_config); -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /* wake up the cert expiration notif thread */ nc_server_config_cert_exp_notif_thread_wakeup(); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ goto cleanup; @@ -6262,9 +6324,9 @@ nc_server_config_setup_diff(const struct lyd_node *data) cur_config = nc_server_config_acquire(); if (cur_config) { nc_server_binds_reconcile(cur_config); -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) nc_server_ch_clients_reconcile(cur_config); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ } cleanup: @@ -6316,7 +6378,7 @@ nc_server_config_setup_data(const struct lyd_node *data) */ NC_CHECK_GOTO(ret = nc_server_config_new(&config), cleanup); -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /* configure keystore */ NC_CHECK_ERR_GOTO(ret = nc_server_config_keystore(data, 0, config), ERR(NULL, "Applying ietf-keystore configuration failed."), cleanup); @@ -6324,7 +6386,7 @@ nc_server_config_setup_data(const struct lyd_node *data) /* configure truststore */ NC_CHECK_ERR_GOTO(ret = nc_server_config_truststore(data, 0, config), ERR(NULL, "Applying ietf-truststore configuration failed."), cleanup); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ /* configure netconf-server */ NC_CHECK_ERR_GOTO(ret = nc_server_config_netconf_server(data, 0, config), @@ -6338,12 +6400,12 @@ nc_server_config_setup_data(const struct lyd_node *data) NC_CHECK_ERR_GOTO(ret = nc_server_binds_reconcile(config), ERR(NULL, "Starting to listen on new endpoints failed."), cleanup); -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /* dispatch new call-home connections, the listening sockets are already reconciled with the new * generation so a failure here has to be rolled back */ NC_CHECK_ERR_GOTO(ret = nc_server_ch_clients_reconcile(config), ERR(NULL, "Dispatching new call-home connections failed."), rollback); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ /* CONFIG WR LOCK - only the pointer swap */ if (nc_rwlock_lock(&server_opts.config_lock, NC_RWLOCK_WRITE, NC_CONFIG_LOCK_TIMEOUT, __func__) != 1) { @@ -6362,10 +6424,10 @@ nc_server_config_setup_data(const struct lyd_node *data) /* the old generation is freed once its last reader releases it */ nc_server_config_release(old_config); -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /* wake up the cert expiration notif thread */ nc_server_config_cert_exp_notif_thread_wakeup(); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ goto cleanup; @@ -6375,9 +6437,9 @@ nc_server_config_setup_data(const struct lyd_node *data) cur_config = nc_server_config_acquire(); if (cur_config) { nc_server_binds_reconcile(cur_config); -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) nc_server_ch_clients_reconcile(cur_config); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ } cleanup: @@ -6414,7 +6476,7 @@ nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path) return ret; } -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /** * @brief Create operational data for supported algorithms. @@ -6474,6 +6536,10 @@ nc_server_config_oper_get_algs(const struct ly_ctx *ctx, const char *mod, const return rc; } +#endif /* NC_SSH or NC_TLS */ + +#ifdef NC_SSH + /** * @brief Get operational data for supported hostkey algorithms. * @@ -6614,17 +6680,6 @@ nc_server_config_oper_get_supported_ssh_algs(const struct ly_ctx *ctx, struct ly return rc; } -API int -nc_server_config_oper_get_supported_tls_algs(const struct ly_ctx *ctx, struct lyd_node **supported_algs) -{ - const char *mod = "ietf-tls-common"; - - NC_CHECK_ARG_RET(NULL, ctx, supported_algs, 1); - - /* cipher suites are based on the used TLS library */ - return nc_server_config_oper_get_algs(ctx, mod, NULL, nc_tls_supported_cipher_suites, supported_algs); -} - API int nc_server_config_oper_get_user_password_last_modified(const char *ch_client, const char *endpoint, const char *username, time_t *last_modified) @@ -6712,4 +6767,19 @@ nc_server_config_oper_get_user_password_last_modified(const char *ch_client, con return rc; } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH */ + +#ifdef NC_TLS + +API int +nc_server_config_oper_get_supported_tls_algs(const struct ly_ctx *ctx, struct lyd_node **supported_algs) +{ + const char *mod = "ietf-tls-common"; + + NC_CHECK_ARG_RET(NULL, ctx, supported_algs, 1); + + /* cipher suites are based on the used TLS library */ + return nc_server_config_oper_get_algs(ctx, mod, NULL, nc_tls_supported_cipher_suites, supported_algs); +} + +#endif /* NC_TLS */ diff --git a/src/server_config.h b/src/server_config.h index 45f3155e..e465830a 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -1,10 +1,11 @@ /** * @file server_config.h * @author Roman Janota + * @author Michal Vasko * @brief libnetconf2 server configuration * * @copyright - * Copyright (c) 2023 CESNET, z.s.p.o. + * Copyright (c) 2023 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. @@ -112,7 +113,7 @@ int nc_server_config_setup_data(const struct lyd_node *data); */ int nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path); -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) /** * @brief Creates new YANG configuration data nodes for address and port. @@ -120,99 +121,16 @@ int nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path); * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. * If an endpoint with this identifier already exists, its contents might be changed. - * @param[in] transport Either SSH or TLS transport for the given endpoint. + * @param[in] transport Either SSH or TLS transport of the given endpoint. * @param[in] address New listening address. * @param[in] port New listening port. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * @param[in,out] config Configuration YANG data tree. If NULL, it will be created. * Otherwise the new YANG data will be added to the previous data and may override it. * @return 0 on success, non-zero otherwise. */ int nc_server_config_add_address_port(const struct ly_ctx *ctx, const char *endpt_name, NC_TRANSPORT_IMPL transport, const char *address, uint16_t port, struct lyd_node **config); -#endif /* NC_ENABLED_SSH_TLS */ - -/** - * @brief Deletes an endpoint from the YANG data. - * - * @param[in] endpt_name Optional identifier of an endpoint to be deleted. - * If NULL, all of the endpoints will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note If the last endpoint is deleted, the parent listen presence container - * is also deleted to maintain a valid YANG data tree. - */ -int nc_server_config_del_endpt(const char *endpt_name, struct lyd_node **config); - -/** - * @brief Creates new YANG data nodes for a UNIX socket endpoint. - * - * To learn how authentication works, look at ::nc_server_config_add_unix_user_mapping(). - * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its contents might be changed. - * @param[in] path Path to the UNIX socket. The parent directory must be writable by the server process. - * @param[in] mode Optional UNIX socket file mode in octal format (e.g., "0777"). - * If NULL, the default value ("0660") will be used. - * @param[in] owner Optional owner of the UNIX socket file. - * If NULL, the owner will be set to the user running the server process. - * @param[in] group Optional group of the UNIX socket file. - * If NULL, the group will be set to the group of the user running the server process. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - * - */ -int nc_server_config_add_unix_socket(const struct ly_ctx *ctx, const char *endpt_name, const char *path, - const char *mode, const char *owner, const char *group, struct lyd_node **config); - -/** - * @brief Creates new YANG data nodes for a UNIX username mapping. - * - * Specifies who can connect to a UNIX socket endpoint. There are 3 following scenarios: - * - * 1) If no mappings are configured for the client @p system_user, then the client can - * only connect if its username matches @p netconf_user. - * - * 2) If a mapping for the client @p system_user is configured, but no @p netconf_user s - * are specified, then the client cannot connect with any username. - * - * 3) If a mapping for the client @p system_user is configured, and at least one @p netconf_user - * is specified, then the client can connect only with one of the specified usernames. - * If a wildcard value "*" is configured for @p netconf_user, then the client can connect - * with any NETCONF username. - * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its contents might be changed. - * @param[in] system_user System user name, who the mapping will be created for. - * @param[in] netconf_user Username that the @p system_user can use to connect to the endpoint. - * Special value "*" can be used to allow any username. - * If NULL, empty mapping will be created, which means that the @p system_user - * can not connect to the endpoint with any username. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_unix_user_mapping(const struct ly_ctx *ctx, const char *endpt_name, - const char *system_user, const char *netconf_user, struct lyd_node **config); - -/** - * @brief Deletes a UNIX username mapping from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] system_user Optional identifier of a system user whose mapping will be deleted. - * If NULL, all of the mappings for the endpoint will be deleted. - * @param[in,out] config Configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_unix_user_mapping(const char *endpt_name, const char *system_user, - struct lyd_node **config); - -#ifdef NC_ENABLED_SSH_TLS - /** * @brief Creates new YANG data nodes for an asymmetric key in the keystore. * @@ -325,178 +243,113 @@ int nc_server_config_add_truststore_cert(const struct ly_ctx *ctx, const char *c * @param[in,out] config Configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_truststore_cert(const char *cert_bag_name, - const char *cert_name, struct lyd_node **config); +int nc_server_config_del_truststore_cert(const char *cert_bag_name, const char *cert_name, struct lyd_node **config); -/** - * @brief Gets all the SSH transport algorithms supported by the server. - * - * @note Actual usable algorithms depend on the underlying libssh library version, - * the returned list is based on libssh v0.11.0. - * - * @param[in] ctx libyang context. - * @param[out] supported_algs Supported SSH transport algorithms. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_oper_get_supported_ssh_algs(const struct ly_ctx *ctx, struct lyd_node **supported_algs); +#endif /* NC_SSH or NC_TLS */ /** - * @brief Gets all the TLS transport cipher suites supported by the server. - * - * @note Actual usable cipher suites depend on the underlying TLS library and its version. + * @brief Deletes an endpoint from the YANG data. * - * @param[in] ctx libyang context. - * @param[out] supported_algs Supported cipher suites. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_oper_get_supported_tls_algs(const struct ly_ctx *ctx, struct lyd_node **supported_algs); - -/** - * @brief Gets the last modified time of an SSH user's password. + * @note If the last endpoint is deleted, the parent listen presence container + * is also deleted to maintain a valid YANG data tree. * - * @param[in] ch_client Name of the call-home client the user is configured on. NULL if the user is on a listening endpoint. - * @param[in] endpoint Name of the endpoint the user is configured on. Can be either a listening or call-home endpoint. - * @param[in] username Name of the SSH user. - * @param[out] last_modified Time of the last password modification. + * @param[in] endpt_name Optional identifier of an endpoint to be deleted. + * If NULL, all of the endpoints will be deleted. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_oper_get_user_password_last_modified(const char *ch_client, - const char *endpoint, const char *username, time_t *last_modified); - -/** - * @} Server Configuration Functions - */ +int nc_server_config_del_endpt(const char *endpt_name, struct lyd_node **config); /** - * @defgroup server_config_ssh SSH Server Configuration - * @ingroup server_config + * @brief Creates new YANG data nodes for a UNIX socket endpoint. * - * @brief SSH server configuration creation and deletion - * @{ - */ - -/** - * @brief Creates new YANG configuration data nodes for a hostkey. + * To learn how authentication works, look at ::nc_server_config_add_unix_user_mapping(). * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its hostkey might be changed. - * @param[in] hostkey_name Arbitrary identifier of the hostkey. - * If a hostkey with this identifier already exists, its contents will be changed. - * @param[in] privkey_path Path to a file containing a private key. - * The private key has to be in a PEM format. Only RSA and ECDSA keys are supported. - * @param[in] pubkey_path Optional path to a file containing a public key. If NULL, public key will be - * generated from the private key. + * If an endpoint with this identifier already exists, its contents might be changed. + * @param[in] path Path to the UNIX socket. The parent directory must be writable by the server process. + * @param[in] mode Optional UNIX socket file mode in octal format (e.g., "0777"). + * If NULL, the default value ("0660") will be used. + * @param[in] owner Optional owner of the UNIX socket file. + * If NULL, the owner will be set to the user running the server process. + * @param[in] group Optional group of the UNIX socket file. + * If NULL, the group will be set to the group of the user running the server process. * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. * Otherwise the new YANG data will be added to the previous data and may override it. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_add_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, - const char *privkey_path, const char *pubkey_path, struct lyd_node **config); +int nc_server_config_add_unix_socket(const struct ly_ctx *ctx, const char *endpt_name, const char *path, + const char *mode, const char *owner, const char *group, struct lyd_node **config); /** - * @brief Deletes a hostkey from the YANG data. + * @brief Creates new YANG data nodes for a UNIX username mapping. * - * @param[in] ctx libyang context. - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] hostkey_name Optional identifier of the hostkey to be deleted. - * If NULL, all of the hostkeys on this endpoint will be deleted. - * @param[in,out] config Configuration YANG data tree. - * @return 0 on success, non-zero otherwise. + * Specifies who can connect to a UNIX socket endpoint. There are 3 following scenarios: * - * @note If the last hostkey is deleted, the configuration becomes invalid. - * Add a new hostkey to make it valid again. - */ -int nc_server_config_del_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_name, - const char *hostkey_name, struct lyd_node **config); - -/** - * @brief Creates new YANG data nodes for a reference to an asymmetric key located in the keystore. + * 1) If no mappings are configured for the client @p system_user, then the client can + * only connect if its username matches @p netconf_user. * - * This asymmetric key pair will be used as the SSH hostkey. + * 2) If a mapping for the client @p system_user is configured, but no @p netconf_user s + * are specified, then the client cannot connect with any username. + * + * 3) If a mapping for the client @p system_user is configured, and at least one @p netconf_user + * is specified, then the client can connect only with one of the specified usernames. + * If a wildcard value "*" is configured for @p netconf_user, then the client can connect + * with any NETCONF username. * * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of an endpoint. - * If an endpoint with this identifier already exists, its contents will be changed. - * @param[in] hostkey_name Arbitrary identifier of the endpoint's hostkey. - * If an endpoint's hostkey with this identifier already exists, its contents will be changed. - * @param[in] keystore_reference Name of the asymmetric key pair to be referenced and used as a hostkey. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents might be changed. + * @param[in] system_user System user name, who the mapping will be created for. + * @param[in] netconf_user Username that the @p system_user can use to connect to the endpoint. + * Special value "*" can be used to allow any username. + * If NULL, empty mapping will be created, which means that the @p system_user + * can not connect to the endpoint with any username. * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. * Otherwise the new YANG data will be added to the previous data and may override it. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_add_ssh_keystore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, - const char *keystore_reference, struct lyd_node **config); +int nc_server_config_add_unix_user_mapping(const struct ly_ctx *ctx, const char *endpt_name, + const char *system_user, const char *netconf_user, struct lyd_node **config); /** - * @brief Deletes a keystore reference from the YANG data. + * @brief Deletes a UNIX username mapping from the YANG data. * * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] hostkey_name Identifier of an existing hostkey on the given endpoint. + * @param[in] system_user Optional identifier of a system user whose mapping will be deleted. + * If NULL, all of the mappings for the endpoint will be deleted. * @param[in,out] config Configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_ssh_keystore_ref(const char *endpt_name, const char *hostkey_name, +int nc_server_config_del_unix_user_mapping(const char *endpt_name, const char *system_user, struct lyd_node **config); -/** - * @brief Creates new YANG configuration data nodes for an SSH user's public key authentication method. - * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its user might be changed. - * @param[in] user_name Arbitrary identifier of the user. - * If an user with this identifier already exists, its contents will be changed. - * @param[in] pubkey_name Arbitrary identifier of the user's public key. - * If a public key with this identifier already exists for this user, its contents will be changed. - * @param[in] pubkey_path Path to a file containing the user's public key. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ssh_user_pubkey(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config); - -/** - * @brief Deletes an SSH user's public key from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] user_name Identifier of an existing user on the given endpoint. - * @param[in] pubkey_name Optional identifier of a public key to be deleted. - * If NULL, all of the users public keys will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_ssh_user_pubkey(const char *endpt_name, const char *user_name, - const char *pubkey_name, struct lyd_node **config); +#ifdef NC_SSH /** - * @brief Creates new YANG configuration data nodes for an SSH user that will use system's authorized_keys to authenticate. + * @brief Gets all the SSH transport algorithms supported by the server. * - * The path to the authorized_keys file must be configured to successfully - * authenticate, see ::nc_server_ssh_set_authkey_path_format(). + * @note Actual usable algorithms depend on the underlying libssh library version, + * the returned list is based on libssh v0.11.0. * * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its user might be changed. - * @param[in] user_name Arbitrary identifier of the user. - * If an user with this identifier already exists, its contents will be changed. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. + * @param[out] supported_algs Supported SSH transport algorithms. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_add_ssh_user_authkey(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config); +int nc_server_config_oper_get_supported_ssh_algs(const struct ly_ctx *ctx, struct lyd_node **supported_algs); /** - * @brief Deletes an SSH user's authorized_keys method from the YANG data. + * @brief Gets the last modified time of an SSH user's password. * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] user_name Identifier of an existing user on the given endpoint. - * @param[in,out] config Modified configuration YANG data tree. + * @param[in] ch_client Name of the call-home client the user is configured on. NULL if the user is on a listening endpoint. + * @param[in] endpoint Name of the endpoint the user is configured on. Can be either a listening or call-home endpoint. + * @param[in] username Name of the SSH user. + * @param[out] last_modified Time of the last password modification. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_ssh_user_authkey(const char *endpt_name, const char *user_name, struct lyd_node **config); +int nc_server_config_oper_get_user_password_last_modified(const char *ch_client, const char *endpoint, + const char *username, time_t *last_modified); /** * @brief Hashes a clear-text 'iana-crypt-hash' password the way the server stores it in its configuration. @@ -512,431 +365,72 @@ int nc_server_config_del_ssh_user_authkey(const char *endpt_name, const char *us */ int nc_server_config_hash_password(const char *crypt_hash, char **hashed_password); +#endif /* NC_SSH */ + +#ifdef NC_TLS + /** - * @brief Creates new YANG configuration data nodes for an SSH user's password authentication method. + * @brief Gets all the TLS transport cipher suites supported by the server. + * + * @note Actual usable cipher suites depend on the underlying TLS library and its version. * * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its user might be changed. - * @param[in] user_name Arbitrary identifier of the user. - * If an user with this identifier already exists, its contents will be changed. - * @param[in] password Clear-text password to be set for the user. It will be hashed. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. + * @param[out] supported_algs Supported cipher suites. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, const char *password, struct lyd_node **config); +int nc_server_config_oper_get_supported_tls_algs(const struct ly_ctx *ctx, struct lyd_node **supported_algs); + +#endif /* NC_TLS */ /** - * @brief Deletes an SSH user's password from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] user_name Identifier of an existing user on the given endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. + * @} Server Configuration Functions */ -int nc_server_config_del_ssh_user_password(const char *endpt_name, const char *user_name, - struct lyd_node **config); + +#if defined (NC_SSH) || defined (NC_TLS) /** - * @brief Creates new YANG configuration data nodes for an SSH user's keyboard interactive authentication method. - * - * One of Linux PAM, local users, or user callback is used to authenticate users with this SSH method (see \ref ln2doc_kbdint "the documentation"). + * @defgroup server_config_ch Call Home Server Configuration + * @ingroup server_config * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its user might be changed. - * @param[in] user_name Arbitrary identifier of the user. - * If an user with this identifier already exists, its contents will be changed. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. + * @brief Call Home server configuration creation and deletion + * @{ */ -int nc_server_config_add_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config); /** - * @brief Deletes an SSH user's keyboard interactive authentication from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] user_name Identifier of an existing user on the given endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. + * @} Call Home Server Configuration */ -int nc_server_config_del_ssh_user_interactive(const char *endpt_name, const char *user_name, - struct lyd_node **config); /** - * @brief Deletes an SSH user from the YANG data. + * @defgroup server_config_ch_functions Call Home Server Configuration Functions + * @ingroup server_config_ch * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] user_name Optional identifier of an user to be deleted. - * If NULL, all of the users on this endpoint will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. + * @brief Call Home server configuration functions + * @{ */ -int nc_server_config_del_ssh_user(const char *endpt_name, - const char *user_name, struct lyd_node **config); /** - * @brief Creates new YANG data nodes for a reference to a public key bag located in the truststore. - * - * The public key's located in the bag will be used for client authentication. + * @brief Creates new YANG configuration data nodes for a Call Home client's address and port. * * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of an endpoint. - * If an endpoint with this identifier already exists, its contents will be changed. - * @param[in] user_name Arbitrary identifier of the endpoint's user. - * If an endpoint's user with this identifier already exists, its contents will be changed. - * @param[in] truststore_reference Name of the public key bag to be referenced and used for authentication. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the client's endpoint. + * If the client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] transport Transport protocol to be used on this endpoint - either SSH or TLS. + * @param[in] address Address to connect to. + * @param[in] port Port to connect to. * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. * Otherwise the new YANG data will be added to the previous data and may override it. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_add_ssh_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, - const char *truststore_reference, struct lyd_node **config); +int nc_server_config_add_ch_address_port(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + NC_TRANSPORT_IMPL transport, const char *address, const char *port, struct lyd_node **config); /** - * @brief Deletes a truststore reference from the YANG data. + * @brief Deletes a Call Home client from the YANG data. * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] user_name Identifier of an user on the given endpoint whose truststore reference will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_ssh_truststore_ref(const char *endpt_name, const char *user_name, - struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes, which will be a reference to another SSH endpoint's users. - * - * Whenever a client tries to connect to the referencing endpoint, all of its users will be tried first. If no match is - * found, the referenced endpoint's configured users will be tried. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its contents will be changed. - * @param[in] referenced_endpt Identifier of an endpoint, which has to exist whenever this data - * is applied. The referenced endpoint can reference another one and so on, but there mustn't be a cycle. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ssh_endpoint_client_ref(const struct ly_ctx *ctx, const char *endpt_name, - const char *referenced_endpt, struct lyd_node **config); - -/** - * @brief Deletes reference to another SSH endpoint's users from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_ssh_endpoint_client_ref(const char *endpt_name, struct lyd_node **config); - -/** - * @} SSH Server Configuration - */ - -/** - * @defgroup server_config_tls TLS Server Configuration - * @ingroup server_config - * - * @brief TLS server configuration creation and deletion - * @{ - */ - -/** - * @brief Creates new YANG configuration data nodes for a server's certificate. - * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its server certificate will be changed. - * @param[in] privkey_path Path to the server's PEM encoded private key file. - * @param[in] pubkey_path Optional path to the server's public key file. If not provided, - * it will be generated from the private key. - * @param[in] cert_path Path to the server's certificate file. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path, - const char *pubkey_path, const char *cert_path, struct lyd_node **config); - -/** - * @brief Deletes the server's certificate from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note Deleting the server certificate makes the configuration invalid. - * Add a new server certificate to make it valid again. - */ -int nc_server_config_del_tls_server_cert(const char *endpt_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a keystore reference to the TLS server's certificate. - * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its contents will be changed. - * @param[in] asym_key_ref Name of the asymmetric key pair in the keystore to be referenced. - * @param[in] cert_ref Name of the certificate, which must belong to the given asymmetric key pair, to be referenced. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_tls_keystore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *asym_key_ref, - const char *cert_ref, struct lyd_node **config); - -/** - * @brief Deletes a TLS server certificate keystore reference from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note Deleting the keystore reference makes the configuration invalid. - * Add a new keystore reference to make it valid again. - */ -int nc_server_config_del_tls_keystore_ref(const char *endpt_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a client's (end-entity) certificate. - * - * A client certificate is authenticated if it is an exact match to a configured client certificate. - * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its contents will be changed. - * @param[in] cert_name Arbitrary identifier of the client's certificate. - * If a client certificate with this identifier already exists, it will be changed. - * @param[in] cert_path Path to the client's certificate file. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, - const char *cert_path, struct lyd_node **config); - -/** - * @brief Deletes a client (end-entity) certificate from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] cert_name Optional name of a certificate to be deleted. - * If NULL, all of the end-entity certificates on the given endpoint will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note If the last certificate is deleted, the parent ee-certs container and - * possibly the client-authentication container are also deleted to maintain - * a valid YANG data tree. - */ -int nc_server_config_del_tls_client_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a truststore reference to a set of client (end-entity) certificates. - * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its contents will be changed. - * @param[in] cert_bag_ref Identifier of the certificate bag in the truststore to be referenced. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_tls_client_cert_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, - const char *cert_bag_ref, struct lyd_node **config); - -/** - * @brief Deletes a client (end-entity) certificates truststore reference from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note The parent ee-certs container and possibly the client-authentication - * container are also deleted to maintain a valid YANG data tree. - */ -int nc_server_config_del_tls_client_cert_truststore_ref(const char *endpt_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a client certificate authority (trust-anchor) certificate. - * - * A client certificate is authenticated if it has a valid chain of trust to any configured CA cert. - * The configured CA cert, up to which the valid chain of trust can be built, does not have to be - * self-signed (the root CA). That means that the chain may be incomplete, yet the client will be authenticated. - * - * For example assume a certificate chain - * A <- B <- C, - * where A is the root CA, then the client certificate C will be authenticated either - * if solely B is configured, or if both A and B are configured. C will not be authenticated - * if just A is configured as a CA certificate. - * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its contents will be changed. - * @param[in] cert_name Arbitrary identifier of the certificate authority certificate. - * If a CA with this identifier already exists, it will be changed. - * @param[in] cert_path Path to the CA certificate file. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_tls_ca_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, - const char *cert_path, struct lyd_node **config); - -/** - * @brief Deletes a client certificate authority (trust-anchor) certificate from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] cert_name Optional name of a certificate to be deleted. - * If NULL, all of the CA certificates on the given endpoint will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note If the last certificate is deleted, the parent ca-certs container and - * possibly the client-authentication container are also deleted to maintain - * a valid YANG data tree. - */ -int nc_server_config_del_tls_ca_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a truststore reference to a set of client certificate authority (trust-anchor) certificates. - * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its contents will be changed. - * @param[in] cert_bag_ref Identifier of the certificate bag in the truststore to be referenced. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_tls_ca_cert_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, - const char *cert_bag_ref, struct lyd_node **config); - -/** - * @brief Deletes a client certificate authority (trust-anchor) certificates truststore reference from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note The parent ca-certs container and possibly the client-authentication - * container are also deleted to maintain a valid YANG data tree. - */ -int nc_server_config_del_tls_ca_cert_truststore_ref(const char *endpt_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes, which will be a reference to another TLS endpoint's certificates. - * - * Whenever an user tries to connect to the referencing endpoint, all of its certificates will be tried first. If no match is - * found, the referenced endpoint's configured certificates will be tried. The same applies to cert-to-name entries. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its contents will be changed. - * @param[in] referenced_endpt Identifier of an endpoint, which has to exist whenever this data - * is applied. The referenced endpoint can reference another one and so on, but there mustn't be a cycle. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_tls_endpoint_client_ref(const struct ly_ctx *ctx, const char *endpt_name, - const char *referenced_endpt, struct lyd_node **config); - -/** - * @brief Deletes reference to another TLS endpoint's users from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_tls_endpoint_client_ref(const char *endpt_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a cert-to-name entry. - * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its contents will be changed. - * @param[in] id ID of the entry. The lower the ID, the higher the priority of the entry (it will be checked earlier). - * @param[in] fingerprint Optional fingerprint of the entry. The fingerprint should always be set, however if it is - * not set, it will match any certificate. Entry with no fingerprint should therefore be placed only as the last entry. - * @param[in] map_type Mapping username to the certificate option. - * @param[in] name Username for this cert-to-name entry. Mandatory if @p map_type is set to ::NC_TLS_CTN_SPECIFIED. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, uint32_t id, const char *fingerprint, - NC_TLS_CTN_MAPTYPE map_type, const char *name, struct lyd_node **config); - -/** - * @brief Deletes a cert-to-name entry from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] id Optional ID of the CTN entry. - * If 0, all of the cert-to-name entries on the given endpoint will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note If the last cert-to-name entry is deleted, the configuration becomes - * invalid. Add a new cert-to-name entry to make it valid again. - */ -int nc_server_config_del_tls_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config); - -/** - * @} TLS Server Configuration - */ - -/** - * @defgroup server_config_ch Call Home Server Configuration - * @ingroup server_config - * - * @brief Call Home server configuration creation and deletion - * @{ - */ - -/** - * @} Call Home Server Configuration - */ - -/** - * @defgroup server_config_ch_functions Call Home Server Configuration Functions - * @ingroup server_config_ch - * - * @brief Call Home server configuration functions - * @{ - */ - -/** - * @brief Creates new YANG configuration data nodes for a Call Home client's address and port. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the client's endpoint. - * If the client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] transport Transport protocol to be used on this endpoint - either SSH or TLS. - * @param[in] address Address to connect to. - * @param[in] port Port to connect to. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_address_port(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - NC_TRANSPORT_IMPL transport, const char *address, const char *port, struct lyd_node **config); - -#endif /* NC_ENABLED_SSH_TLS */ - -/** - * @brief Deletes a Call Home client from the YANG data. - * - * @param[in] client_name Optional identifier of a client to be deleted. - * If NULL, all of the Call Home clients will be deleted. + * @param[in] client_name Optional identifier of a client to be deleted. + * If NULL, all of the Call Home clients will be deleted. * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. * @@ -1083,506 +577,10 @@ int nc_server_config_del_ch_reconnect_strategy(const char *client_name, struct l * @} Call Home Server Configuration Functions */ -#ifdef NC_ENABLED_SSH_TLS - -/** - * @defgroup server_config_ch_ssh SSH Call Home Server Configuration - * @ingroup server_config_ch - * - * @brief SSH Call Home server configuration creation and deletion - * @{ - */ - -/** - * @brief Creates new YANG data nodes for a Call Home SSH hostkey. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the client's endpoint. - * If the client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] hostkey_name Arbitrary identifier of the endpoint's hostkey. - * If the endpoint's hostkey with this identifier already exists, its contents will be changed. - * @param[in] privkey_path Path to a file containing a private key. - * The private key has to be in a PEM format. Only RSA and ECDSA keys are supported. - * @param[in] pubkey_path Path to a file containing a public key. If NULL, public key will be - * generated from the private key. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_ssh_hostkey(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *hostkey_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config); - -/** - * @brief Deletes a Call Home hostkey from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. - * @param[in] hostkey_name Optional identifier of a hostkey to be deleted. - * If NULL, all of the hostkeys on the given endpoint will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note If the last hostkey is deleted, the configuration becomes invalid. - * Add a new hostkey to make it valid again. - */ -int nc_server_config_del_ch_ssh_hostkey(const char *client_name, const char *endpt_name, - const char *hostkey_name, struct lyd_node **config); - -/** - * @brief Creates new YANG data nodes for a reference to an asymmetric key located in the keystore. - * - * This asymmetric key pair will be used as the Call Home SSH hostkey. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the client's endpoint. - * If the client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] hostkey_name Arbitrary identifier of the endpoint's hostkey. - * If the endpoint's hostkey with this identifier already exists, its contents will be changed. - * @param[in] keystore_reference Name of the asymmetric key pair to be referenced and used as a hostkey. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_ssh_keystore_ref(const struct ly_ctx *ctx, const char *client_name, - const char *endpt_name, const char *hostkey_name, const char *keystore_reference, struct lyd_node **config); - -/** - * @brief Deletes a Call Home keystore reference from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. - * @param[in] hostkey_name Identifier of an existing hostkey that belongs to the given CH endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_ch_ssh_keystore_ref(const char *client_name, const char *endpt_name, - const char *hostkey_name, struct lyd_node **config); - -/** - * @brief Creates new YANG data nodes for a Call Home SSH user's public key authentication method. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the client's endpoint. - * If the client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] user_name Arbitrary identifier of the endpoint's user. - * If the endpoint's user with this identifier already exists, its contents will be changed. - * @param[in] pubkey_name Arbitrary identifier of the user's public key. - * If the user's public key with this identifier already exists, its contents will be changed. - * @param[in] pubkey_path Path to a file containing a public key. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_ssh_user_pubkey(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *user_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config); - -/** - * @brief Deletes a Call Home SSH user's public key from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. - * @param[in] user_name Identifier of an existing SSH user that belongs to the given CH endpoint. - * @param[in] pubkey_name Optional identifier of a public key to be deleted. - * If NULL, all of the public keys which belong to the given SSH user will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_ch_ssh_user_pubkey(const char *client_name, const char *endpt_name, - const char *user_name, const char *pubkey_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home SSH user that will use system's authorized_keys to authenticate. - * - * The path to the authorized_keys file must be configured to successfully - * authenticate, see ::nc_server_ssh_set_authkey_path_format(). - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the client's endpoint. - * If the client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] user_name Arbitrary identifier of the endpoint's user. - * If the endpoint's user with this identifier already exists, its contents will be changed. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_ssh_user_authkey(const struct ly_ctx *ctx, const char *client_name, - const char *endpt_name, const char *user_name, struct lyd_node **config); - -/** - * @brief Deletes a Call Home SSH user's authorized_keys method from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. - * @param[in] user_name Identifier of an existing user on the given endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_ch_del_ssh_user_authkey(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config); - -/** - * @brief Creates new YANG data nodes for a Call Home SSH user's password authentication method. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the client's endpoint. - * If the client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] user_name Arbitrary identifier of the endpoint's user. - * If the endpoint's user with this identifier already exists, its contents will be changed. - * @param[in] password Clear-text password to be set for the user. It will be hashed. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_ssh_user_password(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *user_name, const char *password, struct lyd_node **config); - -/** - * @brief Deletes a Call Home SSH user's password from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. - * @param[in] user_name Identifier of an existing SSH user that belongs to the given CH endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_ch_ssh_user_password(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home SSH user's keyboard interactive authentication method. - * - * One of Linux PAM, local users, or user callback is used to authenticate users with this SSH method (see \ref ln2doc_kbdint "the documentation"). - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the client's endpoint. - * If the client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] user_name Arbitrary identifier of the endpoint's user. - * If the endpoint's user with this identifier already exists, its contents will be changed. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_ssh_user_interactive(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config); - -/** - * @brief Deletes a Call Home SSH user's keyboard interactive authentication from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. - * @param[in] user_name Identifier of an existing SSH user that belongs to the given CH endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_ch_ssh_user_interactive(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config); - -/** - * @brief Deletes a Call Home SSH user from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. - * @param[in] user_name Identifier of an existing SSH user that belongs to the given CH endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_ch_ssh_user(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config); - -/** - * @brief Creates new YANG data nodes for a reference to a public key bag located in the truststore. - * - * The public key's located in the bag will be used for Call Home SSH client authentication. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the client's endpoint. - * If the client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] user_name Arbitrary identifier of the endpoint's user. - * If the endpoint's user with this identifier already exists, its contents will be changed. - * @param[in] truststore_reference Name of the public key bag to be referenced and used for authentication. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_ssh_truststore_ref(const struct ly_ctx *ctx, const char *client_name, - const char *endpt_name, const char *user_name, const char *truststore_reference, struct lyd_node **config); - -/** - * @brief Deletes a Call Home SSH truststore reference from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. - * @param[in] user_name Identifier of an existing SSH user that belongs to the given CH endpoint. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_ch_ssh_truststore_ref(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config); - -/** - * @} SSH Call Home Server Configuration - */ - -/** - * @defgroup server_config_ch_tls TLS Call Home Server Configuration - * @ingroup server_config_ch - * - * @brief TLS Call Home server configuration creation and deletion - * @{ - */ - -/** - * @brief Creates new YANG configuration data nodes for a Call Home server's certificate. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. - * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] privkey_path Path to the server's PEM encoded private key file. - * @param[in] pubkey_path Optional path to the server's public key file. If not provided, - * it will be generated from the private key. - * @param[in] cert_path Path to the server's certificate file. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_tls_server_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *privkey_path, const char *pubkey_path, const char *cert_path, struct lyd_node **config); - -/** - * @brief Deletes a Call Home server certificate from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note Deleting the server certificate makes the configuration invalid. - * Add a new server certificate to make it valid again. - */ -int nc_server_config_del_ch_tls_server_cert(const char *client_name, const char *endpt_name, - struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a keystore reference to the Call Home TLS server's certificate. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. - * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] asym_key_ref Name of the asymmetric key pair in the keystore to be referenced. - * @param[in] cert_ref Name of the certificate, which must belong to the given asymmetric key pair, to be referenced. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_tls_keystore_ref(const struct ly_ctx *ctx, const char *client_name, - const char *endpt_name, const char *asym_key_ref, const char *cert_ref, struct lyd_node **config); - -/** - * @brief Deletes a TLS server certificate keystore reference from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note Deleting the keystore reference makes the configuration invalid. - * Add a new keystore reference to make it valid again. - */ -int nc_server_config_del_ch_tls_keystore_ref(const char *client_name, const char *endpt_name, - struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home client's (end-entity) certificate. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. - * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] cert_name Arbitrary identifier of the Call Home endpoint's end-entity certificate. - * If an Call Home endpoint's end-entity certificate with this identifier already exists, its contents will be changed. - * @param[in] cert_path Path to the certificate file. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_tls_client_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *cert_name, const char *cert_path, struct lyd_node **config); - -/** - * @brief Deletes a Call Home client (end-entity) certificate from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. - * @param[in] cert_name Optional identifier of a client certificate to be deleted. - * If NULL, all of the client certificates will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note If the last certificate is deleted, the parent ee-certs container and - * possibly the client-authentication container are also deleted to maintain - * a valid YANG data tree. - */ -int nc_server_config_del_ch_tls_client_cert(const char *client_name, const char *endpt_name, - const char *cert_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home truststore reference to a set of client (end-entity) certificates. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. - * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] cert_bag_ref Identifier of the certificate bag in the truststore to be referenced. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_tls_client_cert_truststore_ref(const struct ly_ctx *ctx, const char *client_name, - const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config); - -/** - * @brief Deletes a Call Home client (end-entity) certificates truststore reference from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note The parent ee-certs container and possibly the client-authentication - * container are also deleted to maintain a valid YANG data tree. - */ -int nc_server_config_del_ch_tls_client_cert_truststore_ref(const char *client_name, const char *endpt_name, - struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a client certificate authority (trust-anchor) certificate. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. - * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] cert_name Arbitrary identifier of the Call Home endpoint's certificate authority certificate. - * If an Call Home endpoint's CA certificate with this identifier already exists, its contents will be changed. - * @param[in] cert_path Path to the certificate file. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_tls_ca_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *cert_name, const char *cert_path, struct lyd_node **config); - -/** - * @brief Deletes a Call Home client certificate authority (trust-anchor) certificate from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. - * @param[in] cert_name Optional identifier of a CA certificate to be deleted. - * If NULL, all of the CA certificates will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note If the last certificate is deleted, the parent ca-certs container and - * possibly the client-authentication container are also deleted to maintain - * a valid YANG data tree. - */ -int nc_server_config_del_ch_tls_ca_cert(const char *client_name, const char *endpt_name, - const char *cert_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home truststore reference to a set of client certificate authority (trust-anchor) certificates. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. - * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] cert_bag_ref Identifier of the certificate bag in the truststore to be referenced. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_tls_ca_cert_truststore_ref(const struct ly_ctx *ctx, const char *client_name, - const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config); - -/** - * @brief Deletes a Call Home client certificate authority (trust-anchor) certificates truststore reference from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note The parent ca-certs container and possibly the client-authentication - * container are also deleted to maintain a valid YANG data tree. - */ -int nc_server_config_del_ch_tls_ca_cert_truststore_ref(const char *client_name, const char *endpt_name, - struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home cert-to-name entry. - * - * @param[in] ctx libyang context. - * @param[in] client_name Arbitrary identifier of the Call Home client. - * If a Call Home client with this identifier already exists, its contents will be changed. - * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. - * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. - * @param[in] id ID of the entry. The lower the ID, the higher the priority of the entry (it will be checked earlier). - * @param[in] fingerprint Optional fingerprint of the entry. The fingerprint should always be set, however if it is - * not set, it will match any certificate. Entry with no fingerprint should therefore be placed only as the last entry. - * @param[in] map_type Mapping username to the certificate option. - * @param[in] name Username for this cert-to-name entry. Mandatory if @p map_type is set to ::NC_TLS_CTN_SPECIFIED. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. - * Otherwise the new YANG data will be added to the previous data and may override it. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_tls_ctn(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, struct lyd_node **config); - -/** - * @brief Deletes a Call Home cert-to-name entry from the YANG data. - * - * @param[in] client_name Identifier of an existing Call Home client. - * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. - * @param[in] id Optional identifier of the Call Home CTN entry to be deleted. - * If 0, all of the CTN entries will be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - * - * @note If the last cert-to-name entry is deleted, the configuration becomes - * invalid. Add a new cert-to-name entry to make it valid again. - */ -int nc_server_config_del_ch_tls_ctn(const char *client_name, const char *endpt_name, - uint32_t id, struct lyd_node **config); - -/** - * @} TLS Call Home Server Configuration - */ - -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ #ifdef __cplusplus } #endif -#endif /* NC_SESSION_SERVER_H_ */ +#endif /* NC_CONFIG_SERVER_H_ */ diff --git a/src/server_config_ssh.h b/src/server_config_ssh.h new file mode 100644 index 00000000..b2eef5a6 --- /dev/null +++ b/src/server_config_ssh.h @@ -0,0 +1,545 @@ +/** + * @file server_config.h + * @author Roman Janota + * @author Michal Vasko + * @brief libnetconf2 server SSH configuration + * + * @copyright + * Copyright (c) 2023 - 2026 CESNET, z.s.p.o. + * + * This source code is licensed under BSD 3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + */ + +#ifndef NC_CONFIG_SERVER_SSH_H_ +#define NC_CONFIG_SERVER_SSH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include + +#include "session.h" + +/** + * @defgroup server_config_ssh SSH Server Configuration + * @ingroup server_config + * + * @brief SSH server configuration creation and deletion + * @{ + */ + +/** + * @brief Creates new YANG configuration data nodes for a hostkey. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its hostkey might be changed. + * @param[in] hostkey_name Arbitrary identifier of the hostkey. + * If a hostkey with this identifier already exists, its contents will be changed. + * @param[in] privkey_path Path to a file containing a private key. + * The private key has to be in a PEM format. Only RSA and ECDSA keys are supported. + * @param[in] pubkey_path Optional path to a file containing a public key. If NULL, public key will be + * generated from the private key. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, + const char *privkey_path, const char *pubkey_path, struct lyd_node **config); + +/** + * @brief Deletes a hostkey from the YANG data. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] hostkey_name Optional identifier of the hostkey to be deleted. + * If NULL, all of the hostkeys on this endpoint will be deleted. + * @param[in,out] config Configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note If the last hostkey is deleted, the configuration becomes invalid. + * Add a new hostkey to make it valid again. + */ +int nc_server_config_del_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_name, + const char *hostkey_name, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a reference to an asymmetric key located in the keystore. + * + * This asymmetric key pair will be used as the SSH hostkey. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of an endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] hostkey_name Arbitrary identifier of the endpoint's hostkey. + * If an endpoint's hostkey with this identifier already exists, its contents will be changed. + * @param[in] keystore_reference Name of the asymmetric key pair to be referenced and used as a hostkey. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_keystore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, + const char *keystore_reference, struct lyd_node **config); + +/** + * @brief Deletes a keystore reference from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] hostkey_name Identifier of an existing hostkey on the given endpoint. + * @param[in,out] config Configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ssh_keystore_ref(const char *endpt_name, const char *hostkey_name, + struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for an SSH user's public key authentication method. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, its contents will be changed. + * @param[in] pubkey_name Arbitrary identifier of the user's public key. + * If a public key with this identifier already exists for this user, its contents will be changed. + * @param[in] pubkey_path Path to a file containing the user's public key. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_user_pubkey(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config); + +/** + * @brief Deletes an SSH user's public key from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] user_name Identifier of an existing user on the given endpoint. + * @param[in] pubkey_name Optional identifier of a public key to be deleted. + * If NULL, all of the users public keys will be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ssh_user_pubkey(const char *endpt_name, const char *user_name, + const char *pubkey_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for an SSH user that will use system's authorized_keys to authenticate. + * + * The path to the authorized_keys file must be configured to successfully + * authenticate, see ::nc_server_ssh_set_authkey_path_format(). + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, its contents will be changed. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_user_authkey(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Deletes an SSH user's authorized_keys method from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] user_name Identifier of an existing user on the given endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ssh_user_authkey(const char *endpt_name, const char *user_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for an SSH user's password authentication method. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, its contents will be changed. + * @param[in] password Clear-text password to be set for the user. It will be hashed. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *password, struct lyd_node **config); + +/** + * @brief Deletes an SSH user's password from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] user_name Identifier of an existing user on the given endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ssh_user_password(const char *endpt_name, const char *user_name, + struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for an SSH user's keyboard interactive authentication method. + * + * One of Linux PAM, local users, or user callback is used to authenticate users with this SSH method (see \ref ln2doc_kbdint "the documentation"). + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, its contents will be changed. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Deletes an SSH user's keyboard interactive authentication from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] user_name Identifier of an existing user on the given endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ssh_user_interactive(const char *endpt_name, const char *user_name, + struct lyd_node **config); + +/** + * @brief Deletes an SSH user from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] user_name Optional identifier of an user to be deleted. + * If NULL, all of the users on this endpoint will be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ssh_user(const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a reference to a public key bag located in the truststore. + * + * The public key's located in the bag will be used for client authentication. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of an endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] user_name Arbitrary identifier of the endpoint's user. + * If an endpoint's user with this identifier already exists, its contents will be changed. + * @param[in] truststore_reference Name of the public key bag to be referenced and used for authentication. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, + const char *truststore_reference, struct lyd_node **config); + +/** + * @brief Deletes a truststore reference from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] user_name Identifier of an user on the given endpoint whose truststore reference will be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ssh_truststore_ref(const char *endpt_name, const char *user_name, + struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes, which will be a reference to another SSH endpoint's users. + * + * Whenever a client tries to connect to the referencing endpoint, all of its users will be tried first. If no match is + * found, the referenced endpoint's configured users will be tried. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] referenced_endpt Identifier of an endpoint, which has to exist whenever this data + * is applied. The referenced endpoint can reference another one and so on, but there mustn't be a cycle. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_endpoint_client_ref(const struct ly_ctx *ctx, const char *endpt_name, + const char *referenced_endpt, struct lyd_node **config); + +/** + * @brief Deletes reference to another SSH endpoint's users from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ssh_endpoint_client_ref(const char *endpt_name, struct lyd_node **config); + +/** + * @} SSH Server Configuration + */ + +/** + * @defgroup server_config_ch_ssh SSH Call Home Server Configuration + * @ingroup server_config_ch + * + * @brief SSH Call Home server configuration creation and deletion + * @{ + */ + +/** + * @brief Creates new YANG data nodes for a Call Home SSH hostkey. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the client's endpoint. + * If the client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] hostkey_name Arbitrary identifier of the endpoint's hostkey. + * If the endpoint's hostkey with this identifier already exists, its contents will be changed. + * @param[in] privkey_path Path to a file containing a private key. + * The private key has to be in a PEM format. Only RSA and ECDSA keys are supported. + * @param[in] pubkey_path Path to a file containing a public key. If NULL, public key will be + * generated from the private key. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_ssh_hostkey(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *hostkey_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config); + +/** + * @brief Deletes a Call Home hostkey from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. + * @param[in] hostkey_name Optional identifier of a hostkey to be deleted. + * If NULL, all of the hostkeys on the given endpoint will be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note If the last hostkey is deleted, the configuration becomes invalid. + * Add a new hostkey to make it valid again. + */ +int nc_server_config_del_ch_ssh_hostkey(const char *client_name, const char *endpt_name, + const char *hostkey_name, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a reference to an asymmetric key located in the keystore. + * + * This asymmetric key pair will be used as the Call Home SSH hostkey. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the client's endpoint. + * If the client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] hostkey_name Arbitrary identifier of the endpoint's hostkey. + * If the endpoint's hostkey with this identifier already exists, its contents will be changed. + * @param[in] keystore_reference Name of the asymmetric key pair to be referenced and used as a hostkey. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_ssh_keystore_ref(const struct ly_ctx *ctx, const char *client_name, + const char *endpt_name, const char *hostkey_name, const char *keystore_reference, struct lyd_node **config); + +/** + * @brief Deletes a Call Home keystore reference from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. + * @param[in] hostkey_name Identifier of an existing hostkey that belongs to the given CH endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ch_ssh_keystore_ref(const char *client_name, const char *endpt_name, + const char *hostkey_name, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a Call Home SSH user's public key authentication method. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the client's endpoint. + * If the client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] user_name Arbitrary identifier of the endpoint's user. + * If the endpoint's user with this identifier already exists, its contents will be changed. + * @param[in] pubkey_name Arbitrary identifier of the user's public key. + * If the user's public key with this identifier already exists, its contents will be changed. + * @param[in] pubkey_path Path to a file containing a public key. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_ssh_user_pubkey(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *user_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config); + +/** + * @brief Deletes a Call Home SSH user's public key from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. + * @param[in] user_name Identifier of an existing SSH user that belongs to the given CH endpoint. + * @param[in] pubkey_name Optional identifier of a public key to be deleted. + * If NULL, all of the public keys which belong to the given SSH user will be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ch_ssh_user_pubkey(const char *client_name, const char *endpt_name, + const char *user_name, const char *pubkey_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call Home SSH user that will use system's authorized_keys to authenticate. + * + * The path to the authorized_keys file must be configured to successfully + * authenticate, see ::nc_server_ssh_set_authkey_path_format(). + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the client's endpoint. + * If the client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] user_name Arbitrary identifier of the endpoint's user. + * If the endpoint's user with this identifier already exists, its contents will be changed. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_ssh_user_authkey(const struct ly_ctx *ctx, const char *client_name, + const char *endpt_name, const char *user_name, struct lyd_node **config); + +/** + * @brief Deletes a Call Home SSH user's authorized_keys method from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. + * @param[in] user_name Identifier of an existing user on the given endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_ch_del_ssh_user_authkey(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a Call Home SSH user's password authentication method. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the client's endpoint. + * If the client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] user_name Arbitrary identifier of the endpoint's user. + * If the endpoint's user with this identifier already exists, its contents will be changed. + * @param[in] password Clear-text password to be set for the user. It will be hashed. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_ssh_user_password(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *user_name, const char *password, struct lyd_node **config); + +/** + * @brief Deletes a Call Home SSH user's password from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. + * @param[in] user_name Identifier of an existing SSH user that belongs to the given CH endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ch_ssh_user_password(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call Home SSH user's keyboard interactive authentication method. + * + * One of Linux PAM, local users, or user callback is used to authenticate users with this SSH method (see \ref ln2doc_kbdint "the documentation"). + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the client's endpoint. + * If the client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] user_name Arbitrary identifier of the endpoint's user. + * If the endpoint's user with this identifier already exists, its contents will be changed. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_ssh_user_interactive(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Deletes a Call Home SSH user's keyboard interactive authentication from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. + * @param[in] user_name Identifier of an existing SSH user that belongs to the given CH endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ch_ssh_user_interactive(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Deletes a Call Home SSH user from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. + * @param[in] user_name Identifier of an existing SSH user that belongs to the given CH endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ch_ssh_user(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a reference to a public key bag located in the truststore. + * + * The public key's located in the bag will be used for Call Home SSH client authentication. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the client's endpoint. + * If the client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] user_name Arbitrary identifier of the endpoint's user. + * If the endpoint's user with this identifier already exists, its contents will be changed. + * @param[in] truststore_reference Name of the public key bag to be referenced and used for authentication. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_ssh_truststore_ref(const struct ly_ctx *ctx, const char *client_name, + const char *endpt_name, const char *user_name, const char *truststore_reference, struct lyd_node **config); + +/** + * @brief Deletes a Call Home SSH truststore reference from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. + * @param[in] user_name Identifier of an existing SSH user that belongs to the given CH endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ch_ssh_truststore_ref(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @} SSH Call Home Server Configuration + */ + +#ifdef __cplusplus +} +#endif + +#endif /* NC_CONFIG_SERVER_SSH_H_ */ diff --git a/src/server_config_tls.h b/src/server_config_tls.h new file mode 100644 index 00000000..72c50ae1 --- /dev/null +++ b/src/server_config_tls.h @@ -0,0 +1,530 @@ +/** + * @file server_config_tls.h + * @author Roman Janota + * @author Michal Vasko + * @brief libnetconf2 server TLS configuration + * + * @copyright + * Copyright (c) 2023 - 2026 CESNET, z.s.p.o. + * + * This source code is licensed under BSD 3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + */ + +#ifndef NC_CONFIG_SERVER_TLS_H_ +#define NC_CONFIG_SERVER_TLS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include + +#include "session.h" + +/** + * @defgroup server_config_tls TLS Server Configuration + * @ingroup server_config + * + * @brief TLS server configuration creation and deletion + * @{ + */ + +/** + * @brief Creates new YANG configuration data nodes for a server's certificate. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its server certificate will be changed. + * @param[in] privkey_path Path to the server's PEM encoded private key file. + * @param[in] pubkey_path Optional path to the server's public key file. If not provided, + * it will be generated from the private key. + * @param[in] cert_path Path to the server's certificate file. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path, + const char *pubkey_path, const char *cert_path, struct lyd_node **config); + +/** + * @brief Deletes the server's certificate from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note Deleting the server certificate makes the configuration invalid. + * Add a new server certificate to make it valid again. + */ +int nc_server_config_del_tls_server_cert(const char *endpt_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a keystore reference to the TLS server's certificate. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] asym_key_ref Name of the asymmetric key pair in the keystore to be referenced. + * @param[in] cert_ref Name of the certificate, which must belong to the given asymmetric key pair, to be referenced. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_tls_keystore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *asym_key_ref, + const char *cert_ref, struct lyd_node **config); + +/** + * @brief Deletes a TLS server certificate keystore reference from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note Deleting the keystore reference makes the configuration invalid. + * Add a new keystore reference to make it valid again. + */ +int nc_server_config_del_tls_keystore_ref(const char *endpt_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a client's (end-entity) certificate. + * + * A client certificate is authenticated if it is an exact match to a configured client certificate. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] cert_name Arbitrary identifier of the client's certificate. + * If a client certificate with this identifier already exists, it will be changed. + * @param[in] cert_path Path to the client's certificate file. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, + const char *cert_path, struct lyd_node **config); + +/** + * @brief Deletes a client (end-entity) certificate from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] cert_name Optional name of a certificate to be deleted. + * If NULL, all of the end-entity certificates on the given endpoint will be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note If the last certificate is deleted, the parent ee-certs container and + * possibly the client-authentication container are also deleted to maintain + * a valid YANG data tree. + */ +int nc_server_config_del_tls_client_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a truststore reference to a set of client (end-entity) certificates. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] cert_bag_ref Identifier of the certificate bag in the truststore to be referenced. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_tls_client_cert_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, + const char *cert_bag_ref, struct lyd_node **config); + +/** + * @brief Deletes a client (end-entity) certificates truststore reference from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note The parent ee-certs container and possibly the client-authentication + * container are also deleted to maintain a valid YANG data tree. + */ +int nc_server_config_del_tls_client_cert_truststore_ref(const char *endpt_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a client certificate authority (trust-anchor) certificate. + * + * A client certificate is authenticated if it has a valid chain of trust to any configured CA cert. + * The configured CA cert, up to which the valid chain of trust can be built, does not have to be + * self-signed (the root CA). That means that the chain may be incomplete, yet the client will be authenticated. + * + * For example assume a certificate chain + * A < B < C, + * where A is the root CA, then the client certificate C will be authenticated either + * if solely B is configured, or if both A and B are configured. C will not be authenticated + * if just A is configured as a CA certificate. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] cert_name Arbitrary identifier of the certificate authority certificate. + * If a CA with this identifier already exists, it will be changed. + * @param[in] cert_path Path to the CA certificate file. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_tls_ca_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, + const char *cert_path, struct lyd_node **config); + +/** + * @brief Deletes a client certificate authority (trust-anchor) certificate from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] cert_name Optional name of a certificate to be deleted. + * If NULL, all of the CA certificates on the given endpoint will be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note If the last certificate is deleted, the parent ca-certs container and + * possibly the client-authentication container are also deleted to maintain + * a valid YANG data tree. + */ +int nc_server_config_del_tls_ca_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a truststore reference to a set of client certificate authority (trust-anchor) certificates. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] cert_bag_ref Identifier of the certificate bag in the truststore to be referenced. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_tls_ca_cert_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, + const char *cert_bag_ref, struct lyd_node **config); + +/** + * @brief Deletes a client certificate authority (trust-anchor) certificates truststore reference from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note The parent ca-certs container and possibly the client-authentication + * container are also deleted to maintain a valid YANG data tree. + */ +int nc_server_config_del_tls_ca_cert_truststore_ref(const char *endpt_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes, which will be a reference to another TLS endpoint's certificates. + * + * Whenever an user tries to connect to the referencing endpoint, all of its certificates will be tried first. If no match is + * found, the referenced endpoint's configured certificates will be tried. The same applies to cert-to-name entries. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] referenced_endpt Identifier of an endpoint, which has to exist whenever this data + * is applied. The referenced endpoint can reference another one and so on, but there mustn't be a cycle. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_tls_endpoint_client_ref(const struct ly_ctx *ctx, const char *endpt_name, + const char *referenced_endpt, struct lyd_node **config); + +/** + * @brief Deletes reference to another TLS endpoint's users from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_tls_endpoint_client_ref(const char *endpt_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a cert-to-name entry. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] id ID of the entry. The lower the ID, the higher the priority of the entry (it will be checked earlier). + * @param[in] fingerprint Optional fingerprint of the entry. The fingerprint should always be set, however if it is + * not set, it will match any certificate. Entry with no fingerprint should therefore be placed only as the last entry. + * @param[in] map_type Mapping username to the certificate option. + * @param[in] name Username for this cert-to-name entry. Mandatory if @p map_type is set to ::NC_TLS_CTN_SPECIFIED. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, uint32_t id, const char *fingerprint, + NC_TLS_CTN_MAPTYPE map_type, const char *name, struct lyd_node **config); + +/** + * @brief Deletes a cert-to-name entry from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] id Optional ID of the CTN entry. + * If 0, all of the cert-to-name entries on the given endpoint will be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note If the last cert-to-name entry is deleted, the configuration becomes + * invalid. Add a new cert-to-name entry to make it valid again. + */ +int nc_server_config_del_tls_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config); + +/** + * @} TLS Server Configuration + */ + +/** + * @defgroup server_config_ch_tls TLS Call Home Server Configuration + * @ingroup server_config_ch + * + * @brief TLS Call Home server configuration creation and deletion + * @{ + */ + +/** + * @brief Creates new YANG configuration data nodes for a Call Home server's certificate. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. + * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] privkey_path Path to the server's PEM encoded private key file. + * @param[in] pubkey_path Optional path to the server's public key file. If not provided, + * it will be generated from the private key. + * @param[in] cert_path Path to the server's certificate file. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_tls_server_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *privkey_path, const char *pubkey_path, const char *cert_path, struct lyd_node **config); + +/** + * @brief Deletes a Call Home server certificate from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note Deleting the server certificate makes the configuration invalid. + * Add a new server certificate to make it valid again. + */ +int nc_server_config_del_ch_tls_server_cert(const char *client_name, const char *endpt_name, + struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a keystore reference to the Call Home TLS server's certificate. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. + * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] asym_key_ref Name of the asymmetric key pair in the keystore to be referenced. + * @param[in] cert_ref Name of the certificate, which must belong to the given asymmetric key pair, to be referenced. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_tls_keystore_ref(const struct ly_ctx *ctx, const char *client_name, + const char *endpt_name, const char *asym_key_ref, const char *cert_ref, struct lyd_node **config); + +/** + * @brief Deletes a TLS server certificate keystore reference from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note Deleting the keystore reference makes the configuration invalid. + * Add a new keystore reference to make it valid again. + */ +int nc_server_config_del_ch_tls_keystore_ref(const char *client_name, const char *endpt_name, + struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call Home client's (end-entity) certificate. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. + * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] cert_name Arbitrary identifier of the Call Home endpoint's end-entity certificate. + * If an Call Home endpoint's end-entity certificate with this identifier already exists, its contents will be changed. + * @param[in] cert_path Path to the certificate file. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_tls_client_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *cert_name, const char *cert_path, struct lyd_node **config); + +/** + * @brief Deletes a Call Home client (end-entity) certificate from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. + * @param[in] cert_name Optional identifier of a client certificate to be deleted. + * If NULL, all of the client certificates will be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note If the last certificate is deleted, the parent ee-certs container and + * possibly the client-authentication container are also deleted to maintain + * a valid YANG data tree. + */ +int nc_server_config_del_ch_tls_client_cert(const char *client_name, const char *endpt_name, + const char *cert_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call Home truststore reference to a set of client (end-entity) certificates. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. + * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] cert_bag_ref Identifier of the certificate bag in the truststore to be referenced. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_tls_client_cert_truststore_ref(const struct ly_ctx *ctx, const char *client_name, + const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config); + +/** + * @brief Deletes a Call Home client (end-entity) certificates truststore reference from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note The parent ee-certs container and possibly the client-authentication + * container are also deleted to maintain a valid YANG data tree. + */ +int nc_server_config_del_ch_tls_client_cert_truststore_ref(const char *client_name, const char *endpt_name, + struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a client certificate authority (trust-anchor) certificate. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. + * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] cert_name Arbitrary identifier of the Call Home endpoint's certificate authority certificate. + * If an Call Home endpoint's CA certificate with this identifier already exists, its contents will be changed. + * @param[in] cert_path Path to the certificate file. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_tls_ca_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *cert_name, const char *cert_path, struct lyd_node **config); + +/** + * @brief Deletes a Call Home client certificate authority (trust-anchor) certificate from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. + * @param[in] cert_name Optional identifier of a CA certificate to be deleted. + * If NULL, all of the CA certificates will be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note If the last certificate is deleted, the parent ca-certs container and + * possibly the client-authentication container are also deleted to maintain + * a valid YANG data tree. + */ +int nc_server_config_del_ch_tls_ca_cert(const char *client_name, const char *endpt_name, + const char *cert_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call Home truststore reference to a set of client certificate authority (trust-anchor) certificates. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. + * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] cert_bag_ref Identifier of the certificate bag in the truststore to be referenced. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_tls_ca_cert_truststore_ref(const struct ly_ctx *ctx, const char *client_name, + const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config); + +/** + * @brief Deletes a Call Home client certificate authority (trust-anchor) certificates truststore reference from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note The parent ca-certs container and possibly the client-authentication + * container are also deleted to maintain a valid YANG data tree. + */ +int nc_server_config_del_ch_tls_ca_cert_truststore_ref(const char *client_name, const char *endpt_name, + struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call Home cert-to-name entry. + * + * @param[in] ctx libyang context. + * @param[in] client_name Arbitrary identifier of the Call Home client. + * If a Call Home client with this identifier already exists, its contents will be changed. + * @param[in] endpt_name Arbitrary identifier of the Call Home client's endpoint. + * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. + * @param[in] id ID of the entry. The lower the ID, the higher the priority of the entry (it will be checked earlier). + * @param[in] fingerprint Optional fingerprint of the entry. The fingerprint should always be set, however if it is + * not set, it will match any certificate. Entry with no fingerprint should therefore be placed only as the last entry. + * @param[in] map_type Mapping username to the certificate option. + * @param[in] name Username for this cert-to-name entry. Mandatory if @p map_type is set to ::NC_TLS_CTN_SPECIFIED. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_tls_ctn(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, struct lyd_node **config); + +/** + * @brief Deletes a Call Home cert-to-name entry from the YANG data. + * + * @param[in] client_name Identifier of an existing Call Home client. + * @param[in] endpt_name Identifier of an existing Call Home endpoint that belongs to the given client. + * @param[in] id Optional identifier of the Call Home CTN entry to be deleted. + * If 0, all of the CTN entries will be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + * + * @note If the last cert-to-name entry is deleted, the configuration becomes + * invalid. Add a new cert-to-name entry to make it valid again. + */ +int nc_server_config_del_ch_tls_ctn(const char *client_name, const char *endpt_name, + uint32_t id, struct lyd_node **config); + +/** + * @} TLS Call Home Server Configuration + */ + +#ifdef __cplusplus +} +#endif + +#endif /* NC_CONFIG_SERVER_TLS_H_ */ diff --git a/src/server_config_util.c b/src/server_config_util.c index 4b7bb67c..8fea77bc 100644 --- a/src/server_config_util.c +++ b/src/server_config_util.c @@ -31,11 +31,9 @@ #include "session.h" #include "session_p.h" -#ifdef NC_ENABLED_SSH_TLS - -#include "session_wrapper.h" - -#endif /* NC_ENABLED_SSH_TLS */ +#if defined (NC_SSH) || defined (NC_TLS) +# include "session_crypto_wrapper.h" +#endif /* NC_SSH or NC_TLS */ int nc_server_config_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...) @@ -350,7 +348,7 @@ nc_server_config_del_unix_user_mapping(const char *endpt_name, const char *syste } } -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) const char * nc_server_config_util_privkey_format_to_identityref(enum nc_privkey_format format) @@ -381,7 +379,7 @@ nc_server_config_util_rsa_pubkey_param_to_bin(void *bn, unsigned char **bin, int *bin = NULL; /* convert to binary */ - if (nc_tls_mpi2bin_wrap(bn, &bin_tmp, bin_len)) { + if (nc_mpi2bin_wrap(bn, &bin_tmp, bin_len)) { ret = 1; goto cleanup; } @@ -417,12 +415,12 @@ nc_server_config_util_pkey_to_ssh_pubkey(void *pkey, char **pubkey) NC_CHECK_ARG_RET(NULL, pkey, pubkey, 1); - if (nc_tls_privkey_is_rsa_wrap(pkey)) { + if (nc_privkey_is_rsa_wrap(pkey)) { /* RSA key */ algorithm_name = "ssh-rsa"; /* get the public key params */ - if (nc_tls_get_rsa_pubkey_params_wrap(pkey, &e, &n)) { + if (nc_get_rsa_pubkey_params_wrap(pkey, &e, &n)) { ret = 1; goto cleanup; } @@ -460,9 +458,9 @@ nc_server_config_util_pkey_to_ssh_pubkey(void *pkey, char **pubkey) memcpy(bin_tmp, &n_len_be, 4); bin_tmp += 4; memcpy(bin_tmp, n_bin, n_len); - } else if (nc_tls_privkey_is_ec_wrap(pkey)) { + } else if (nc_privkey_is_ec_wrap(pkey)) { /* EC Private key, get it's group first */ - ec_group = nc_tls_get_ec_group_wrap(pkey); + ec_group = nc_get_ec_group_wrap(pkey); if (!ec_group) { ret = 1; goto cleanup; @@ -485,7 +483,7 @@ nc_server_config_util_pkey_to_ssh_pubkey(void *pkey, char **pubkey) } /* get the public key - p, which is a point on the elliptic curve */ - ret = nc_tls_get_ec_pubkey_params_wrap(pkey, &p, &p_grp); + ret = nc_get_ec_pubkey_params_wrap(pkey, &p, &p_grp); if (ret) { ERR(NULL, "Getting public key point from the EC private key failed."); ret = 1; @@ -493,7 +491,7 @@ nc_server_config_util_pkey_to_ssh_pubkey(void *pkey, char **pubkey) } /* EC point to bin */ - ret = nc_tls_ec_point_to_bin_wrap(p, p_grp, &p_bin, &p_len); + ret = nc_ec_point_to_bin_wrap(p, p_grp, &p_bin, &p_len); if (ret) { ERR(NULL, "Converting EC public key point to binary failed."); ret = 1; @@ -541,10 +539,10 @@ nc_server_config_util_pkey_to_ssh_pubkey(void *pkey, char **pubkey) } cleanup: - nc_tls_destroy_mpi_wrap(e); - nc_tls_destroy_mpi_wrap(n); - nc_tls_ec_point_destroy_wrap(p); - nc_tls_ec_group_destroy_wrap(p_grp); + nc_destroy_mpi_wrap(e); + nc_destroy_mpi_wrap(n); + nc_ec_point_destroy_wrap(p); + nc_ec_group_destroy_wrap(p_grp); free(bin); free(e_bin); free(n_bin); @@ -562,7 +560,7 @@ nc_server_config_util_pkey_to_spki_pubkey(void *pkey, char **pubkey) NC_CHECK_ARG_RET(NULL, pkey, pubkey, 1); - pub_pem = nc_tls_export_pubkey_pem_wrap(pkey); + pub_pem = nc_export_pubkey_pem_wrap(pkey); if (!pub_pem) { ret = 1; goto cleanup; @@ -587,12 +585,12 @@ nc_server_config_util_read_certificate(const char *cert_path, char **cert) NC_CHECK_ARG_RET(NULL, cert_path, cert, 1); - crt = nc_tls_import_cert_file_wrap(cert_path); + crt = nc_import_cert_file_wrap(cert_path); if (!crt) { return 1; } - pem = nc_tls_export_cert_pem_wrap(crt); + pem = nc_export_cert_pem_wrap(crt); if (!pem) { ret = 1; goto cleanup; @@ -605,7 +603,7 @@ nc_server_config_util_read_certificate(const char *cert_path, char **cert) cleanup: free(pem); - nc_tls_cert_destroy_wrap(crt); + nc_cert_destroy_wrap(crt); return ret; } @@ -678,16 +676,18 @@ nc_server_config_util_read_spki_pubkey(const char *pubkey_path, char **pubkey) NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1); /* read the pubkey from file */ - pub_pkey = nc_tls_import_pubkey_file_wrap(pubkey_path); + pub_pkey = nc_import_pubkey_file_wrap(pubkey_path); if (!pub_pkey) { return 1; } ret = nc_server_config_util_pkey_to_ssh_pubkey(pub_pkey, pubkey); - nc_tls_privkey_destroy_wrap(pub_pkey); + nc_privkey_destroy_wrap(pub_pkey); return ret; } +#ifdef NC_SSH + static int nc_server_config_util_read_openssh_pubkey(const char *pubkey_path, char **pubkey) { @@ -713,6 +713,8 @@ nc_server_config_util_read_openssh_pubkey(const char *pubkey_path, char **pubkey return 0; } +#endif /* NC_SSH */ + int nc_server_config_util_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey) { @@ -748,8 +750,12 @@ nc_server_config_util_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey /* it's ssh2 public key */ ret = nc_server_config_util_read_ssh2_pubkey(pubkey_path, pubkey); } else { +#ifdef NC_SSH /* it's probably OpenSSH public key */ ret = nc_server_config_util_read_openssh_pubkey(pubkey_path, pubkey); +#else + ret = -1; +#endif /* NC_SSH */ } if (ret) { ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path); @@ -761,6 +767,52 @@ nc_server_config_util_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey return ret; } +#ifdef NC_SSH + +/** + * @brief Get private key using libssh functions. + * + * @param[in] privkey_path Path to the private key file. + * @param[out] pkey TLS backend's underlying private key structure. + * @return 0 on success, 1 on failure. + */ +static int +nc_server_config_util_get_privkey_libssh(const char *privkey_path, void **pkey) +{ + int ret = 0; + ssh_key key = NULL; + char *privkey_buf = NULL; + + /* import the OpenSSH private key using libssh */ + ret = ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, &key); + if (ret) { + ERR(NULL, "Importing privkey from file \"%s\" failed.", privkey_path); + ret = 1; + goto cleanup; + } + + /* export the key in PEM */ + ret = ssh_pki_export_privkey_base64(key, NULL, NULL, NULL, &privkey_buf); + if (ret) { + ERR(NULL, "Exporting privkey to base64 failed."); + goto cleanup; + } + + /* convert the base64 PEM to libtls private key representation */ + *pkey = nc_pem_to_privkey_wrap(privkey_buf); + if (!*pkey) { + ret = 1; + goto cleanup; + } + +cleanup: + free(privkey_buf); + ssh_key_free(key); + return ret; +} + +#endif /* NC_SSH */ + int nc_server_config_util_get_spki_pubkey_file(const char *pubkey_path, char **pubkey) { @@ -771,7 +823,7 @@ nc_server_config_util_get_spki_pubkey_file(const char *pubkey_path, char **pubke *pubkey = NULL; - pkey = nc_tls_import_pubkey_file_wrap(pubkey_path); + pkey = nc_import_pubkey_file_wrap(pubkey_path); if (!pkey) { return 1; } @@ -782,7 +834,7 @@ nc_server_config_util_get_spki_pubkey_file(const char *pubkey_path, char **pubke } cleanup: - nc_tls_privkey_destroy_wrap(pkey); + nc_privkey_destroy_wrap(pkey); return ret; } @@ -823,52 +875,10 @@ nc_server_config_util_get_privkey_libtls(const char *privkey_path, void **pkey) { *pkey = NULL; - *pkey = nc_tls_import_privkey_file_wrap(privkey_path); + *pkey = nc_import_privkey_file_wrap(privkey_path); return *pkey ? 0 : 1; } -/** - * @brief Get private key using libssh functions. - * - * @param[in] privkey_path Path to the private key file. - * @param[out] pkey TLS backend's underlying private key structure. - * @return 0 on success, 1 on failure. - */ -static int -nc_server_config_util_get_privkey_libssh(const char *privkey_path, void **pkey) -{ - int ret = 0; - ssh_key key = NULL; - char *privkey_buf = NULL; - - /* import the OpenSSH private key using libssh */ - ret = ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, &key); - if (ret) { - ERR(NULL, "Importing privkey from file \"%s\" failed.", privkey_path); - ret = 1; - goto cleanup; - } - - /* export the key in PEM */ - ret = ssh_pki_export_privkey_base64(key, NULL, NULL, NULL, &privkey_buf); - if (ret) { - ERR(NULL, "Exporting privkey to base64 failed."); - goto cleanup; - } - - /* convert the base64 PEM to libtls private key representation */ - *pkey = nc_tls_pem_to_privkey_wrap(privkey_buf); - if (!*pkey) { - ret = 1; - goto cleanup; - } - -cleanup: - free(privkey_buf); - ssh_key_free(key); - return ret; -} - static int nc_server_config_util_privkey_strip_header_footer(const char *orig_privkey, char **privkey) { @@ -942,10 +952,12 @@ nc_server_config_util_get_privkey(const char *privkey_path, enum nc_privkey_form /* the TLS lib can do this */ ret = nc_server_config_util_get_privkey_libtls(privkey_path, pkey); break; +#ifdef NC_SSH case NC_PRIVKEY_FORMAT_OPENSSH: /* need the help of libssh */ ret = nc_server_config_util_get_privkey_libssh(privkey_path, pkey); break; +#endif /* NC_SSH */ default: ERR(NULL, "Private key format not recognized."); ret = 1; @@ -958,7 +970,7 @@ nc_server_config_util_get_privkey(const char *privkey_path, enum nc_privkey_form /* export the private key to its original format type, * all of this was done to avoid having to parse the private key ourselves * and since we have a "pkey" we can be sure, that the private key is valid */ - ret = nc_tls_privkey_export_wrap(*pkey, *privkey_format, &priv); + ret = nc_privkey_export_wrap(*pkey, *privkey_format, &priv); if (ret) { goto cleanup; } @@ -1031,7 +1043,7 @@ nc_server_config_util_get_asym_key_pair(const char *privkey_path, const char *pu } cleanup: - nc_tls_privkey_destroy_wrap(pkey); + nc_privkey_destroy_wrap(pkey); return ret; } @@ -1049,11 +1061,17 @@ nc_server_config_add_address_port(const struct ly_ctx *ctx, const char *endpt_na path_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/%s/tcp-server-parameters/" "local-bind[local-address='%s']/local-port"; +#ifdef NC_SSH if (transport == NC_TI_SSH) { transport_str = "ssh"; - } else if (transport == NC_TI_TLS) { + } else +#endif /* NC_SSH */ +#ifdef NC_TLS + if (transport == NC_TI_TLS) { transport_str = "tls"; - } else { + } else +#endif /* NC_TLS */ + { ERR(NULL, "Can not set address and port of a non SSH/TLS endpoint."); ret = 1; goto cleanup; @@ -1078,15 +1096,21 @@ nc_server_config_add_ch_address_port(const struct ly_ctx *ctx, const char *clien NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, address, port, config, 1); +#ifdef NC_SSH if (transport == NC_TI_SSH) { /* SSH path */ address_fmt = "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/tcp-client-parameters/remote-address"; port_fmt = "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/tcp-client-parameters/remote-port"; - } else if (transport == NC_TI_TLS) { + } else +#endif /* NC_SSH */ +#ifdef NC_TLS + if (transport == NC_TI_TLS) { /* TLS path */ address_fmt = "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tcp-client-parameters/remote-address"; port_fmt = "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tcp-client-parameters/remote-port"; - } else { + } else +#endif /* NC_TLS */ + { ERR(NULL, "Transport not supported."); ret = 1; goto cleanup; @@ -1160,14 +1184,22 @@ nc_server_config_add_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IM NC_CHECK_ARG_RET(NULL, ctx, asym_key_name, privkey_path, config, 1); - /* get the keys as a string from the given files */ + /* get the keys as a string from the given files and pubkey format */ +#ifdef NC_SSH if (ti == NC_TI_SSH) { ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_SSH, &privkey, &privkey_type, &pubkey); - } else if (ti == NC_TI_TLS) { + pubkey_format = "ietf-crypto-types:ssh-public-key-format"; + } else +#endif /* NC_SSH */ +#ifdef NC_TLS + if (ti == NC_TI_TLS) { ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey, &privkey_type, &pubkey); - } else { + pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; + } else +#endif /* NC_TLS */ + { ERR(NULL, "Only SSH and TLS transports can be used to create an asymmetric key pair in the keystore."); ret = 1; goto cleanup; @@ -1176,13 +1208,6 @@ nc_server_config_add_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IM goto cleanup; } - /* get pubkey format str */ - if (ti == NC_TI_SSH) { - pubkey_format = "ietf-crypto-types:ssh-public-key-format"; - } else { - pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; - } - /* get privkey identityref value */ privkey_format = nc_server_config_util_privkey_format_to_identityref(privkey_type); if (!privkey_format) { @@ -1356,8 +1381,6 @@ nc_server_config_del_truststore_cert(const char *cert_bag_name, } } -#endif /* NC_ENABLED_SSH_TLS */ - API int nc_server_config_add_ch_persistent(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config) { @@ -1516,3 +1539,5 @@ nc_server_config_del_ch_reconnect_strategy(const char *ch_client_name, struct ly return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/reconnect-strategy", ch_client_name); } + +#endif /* NC_SSH or NC_TLS */ diff --git a/src/server_config_util.h b/src/server_config_util.h index e2f93843..db6301e9 100644 --- a/src/server_config_util.h +++ b/src/server_config_util.h @@ -4,7 +4,7 @@ * @brief libnetconf2 server configuration utlities header * * @copyright - * Copyright (c) 2023 CESNET, z.s.p.o. + * Copyright (c) 2023 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. @@ -20,8 +20,6 @@ #include "session_p.h" -#ifdef NC_ENABLED_SSH_TLS - /* private key's pkcs8 header */ #define NC_PKCS8_PRIVKEY_HEADER "-----BEGIN PRIVATE KEY-----\n" @@ -93,7 +91,6 @@ int nc_server_config_util_get_asym_key_pair(const char *privkey_path, const char * * @param[in] pubkey_path Path to the public key. * @param[out] pubkey Base64 encoded public key. - * * @return 0 on success, non-zero otherwise. */ int nc_server_config_util_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey); @@ -103,7 +100,6 @@ int nc_server_config_util_get_ssh_pubkey_file(const char *pubkey_path, char **pu * * @param[in] cert_path Path to the certificate. * @param[out] cert Base64 PEM encoded certificate data. - * * @return 0 on success, non-zero otherwise. */ int nc_server_config_util_read_certificate(const char *cert_path, char **cert); @@ -112,13 +108,10 @@ int nc_server_config_util_read_certificate(const char *cert_path, char **cert); * @brief Converts private key format to its associated identityref value. * * @param[in] format Private key format. - * * @return Identityref on success, NULL on failure. */ const char *nc_server_config_util_privkey_format_to_identityref(enum nc_privkey_format format); -#endif /* NC_ENABLED_SSH_TLS */ - /** * @brief Creates YANG data nodes in a path and gives the final node a value. * @@ -166,4 +159,4 @@ int nc_server_config_delete(struct lyd_node **tree, const char *path_fmt, ...); */ int nc_server_config_check_delete(struct lyd_node **tree, const char *path_fmt, ...); -#endif /* NC_CONFIG_NEW_H_ */ +#endif /* NC_SERVER_CONFIG_UTIL_H_ */ diff --git a/src/server_config_util_ssh.c b/src/server_config_util_ssh.c index f15456c1..a91dc583 100644 --- a/src/server_config_util_ssh.c +++ b/src/server_config_util_ssh.c @@ -4,7 +4,7 @@ * @brief libnetconf2 server SSH configuration utilities * * @copyright - * Copyright (c) 2023 CESNET, z.s.p.o. + * Copyright (c) 2023 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ #include "config.h" #include "log_p.h" #include "server_config.h" +#include "session_crypto_wrapper.h" #include "session_p.h" static int @@ -514,7 +515,7 @@ nc_server_config_crypt_password(const char *password, char **hashed_password) NC_CHECK_ERRMEM_GOTO(!cdata, ret = 1, cleanup); /* generate a random salt compatible with crypt SHA-512: "$6$$" */ - if (nc_tls_generate_random_bytes_wrap(rnd, sizeof rnd)) { + if (nc_ssh_generate_random_bytes_wrap(rnd, sizeof rnd)) { ret = 1; goto cleanup; } diff --git a/src/session.c b/src/session.c index 6b3565b7..170fb78f 100644 --- a/src/session.c +++ b/src/session.c @@ -36,15 +36,18 @@ #include "netconf.h" #include "session_p.h" -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) +# include "session_crypto_wrapper.h" +#endif /* NC_SSH or NC_TLS */ -#include "session_server_ssh_wrapper.h" -#include "session_wrapper.h" +#ifdef NC_SSH +# include +# include "session_server_ssh_wrapper.h" +#endif /* NC_SSH */ -#include -#include - -#endif /* NC_ENABLED_SSH_TLS */ +#ifdef NC_TLS +# include +#endif /* NC_TLS */ /* in seconds */ #define NC_CLIENT_HELLO_TIMEOUT 60 @@ -144,7 +147,7 @@ nc_poll(struct pollfd *pfd, uint16_t pfd_count, int timeout_ms) return rc; } -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) void * nc_base64der_to_cert(const char *data) @@ -159,7 +162,7 @@ nc_base64der_to_cert(const char *data) return NULL; } - cert = nc_tls_pem_to_cert_wrap(buf); + cert = nc_pem_to_cert_wrap(buf); free(buf); return cert; } @@ -199,7 +202,7 @@ nc_is_pk_subject_public_key_info(const char *b64) tmp = bin; /* try to parse the supposed SubjectPublicKeyInfo binary data */ - if (nc_tls_is_der_subpubkey_wrap(tmp, len)) { + if (nc_is_der_subpubkey_wrap(tmp, len)) { /* success, it's most likely SubjectPublicKeyInfo */ ret = 1; } else { @@ -212,7 +215,7 @@ nc_is_pk_subject_public_key_info(const char *b64) return ret; } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ int nc_sock_configure_ka(int sock, const struct nc_keepalives *ka) @@ -672,7 +675,7 @@ nc_session_get_port(const struct nc_session *session) return session->port; } -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH API const char * nc_session_ssh_get_protocol_string(const struct nc_session *session) @@ -697,7 +700,7 @@ nc_session_ssh_get_banner(const struct nc_session *session) return nc_session_ssh_get_protocol_string(session); } -#endif +#endif /* NC_SSH */ API const struct ly_ctx * nc_session_get_ctx(const struct nc_session *session) @@ -779,7 +782,7 @@ nc_session_free_send_transport_shutdown(struct nc_session *session) case NC_TI_UNIX: /* nothing needed - the transport will be closed by caller */ break; -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH case NC_TI_SSH: if (session->ti.libssh.channel) { if (session->side == NC_SERVER) { @@ -793,13 +796,15 @@ nc_session_free_send_transport_shutdown(struct nc_session *session) } } break; +#endif /* NC_SSH */ +#ifdef NC_TLS case NC_TI_TLS: /* send TLS close_notify alert - we can still receive data from the peer, but not send */ if (session->ti.tls.session) { nc_tls_close_notify_wrap(session->ti.tls.session); } break; -#endif +#endif /* NC_TLS */ default: break; } @@ -958,7 +963,7 @@ nc_session_free_transport(struct nc_session *session, int *multisession) sock = session->ti.unixsock.sock; break; -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH case NC_TI_SSH: { int r; struct nc_session *siter; @@ -1085,6 +1090,8 @@ nc_session_free_transport(struct nc_session *session, int *multisession) } break; } +#endif /* NC_SSH */ +#ifdef NC_TLS case NC_TI_TLS: sock = nc_tls_get_fd_wrap(session); @@ -1096,11 +1103,11 @@ nc_session_free_transport(struct nc_session *session, int *multisession) session->ti.tls.config = NULL; if (session->side == NC_SERVER) { - nc_tls_cert_destroy_wrap(session->opts.server.client_cert); + nc_cert_destroy_wrap(session->opts.server.client_cert); } break; -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ case NC_TI_NONE: break; } @@ -1932,7 +1939,7 @@ nc_ch_handshake_io(struct nc_session *session) return type; } -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_TLS /** * @brief CURL callback for downloading data. @@ -2541,7 +2548,7 @@ nc_session_tls_crl_verify_post_handshake(void *tls_session, void *cert_store) return ret; } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ /** * @brief Initialize or destroy the global state of the libraries used by libnetconf2. @@ -2553,14 +2560,19 @@ nc_session_tls_crl_verify_post_handshake(void *tls_session, void *cert_store) static int nc_global_init_destroy(NC_SIDE side, int destroy) { -#ifdef NC_ENABLED_SSH_TLS - /* lock protecting the init flags and the global init of the libraries, which is not thread-safe */ - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + int rc = 0, *inited; + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; /* lock protecting the init flags and the init functions */ + static int init_client = 0, init_server = 0; /* whether the client/server side has the libraries initialized */ - /* whether the client/server side has the libraries initialized */ - static int init_client = 0, init_server = 0; - - int rc = 0, curl_inited = 0, tls_inited = 0, *inited; +#ifdef NC_TLS + int curl_inited = 0; +#endif /* NC_TLS */ +#if defined (NC_SSH) || defined (NC_TLS) + int tls_inited = 0; +#endif /* NC_SSH or NC_TLS */ +#ifdef NC_SSH + int libssh_inited = 0; +#endif /* NC_SSH */ inited = (side == NC_CLIENT) ? &init_client : &init_server; @@ -2576,9 +2588,15 @@ nc_global_init_destroy(NC_SIDE side, int destroy) if (!init_client && !init_server) { /* the last side using the libraries, destroy them in the reverse order */ +#ifdef NC_SSH ssh_finalize(); +#endif /* NC_SSH */ +#if defined (NC_SSH) || defined (NC_TLS) nc_tls_backend_destroy_wrap(); +#endif /* NC_SSH or NC_TLS */ +#ifdef NC_TLS curl_global_cleanup(); +#endif /* NC_TLS */ } goto cleanup; } @@ -2589,50 +2607,59 @@ nc_global_init_destroy(NC_SIDE side, int destroy) goto cleanup; } +#ifdef NC_TLS if (curl_global_init(CURL_GLOBAL_SSL | CURL_GLOBAL_ACK_EINTR)) { ERR(NULL, "%s: failed to init CURL.", __func__); rc = -1; goto cleanup; } curl_inited = 1; +#endif /* NC_TLS */ +#if defined (NC_SSH) || defined (NC_TLS) if (nc_tls_backend_init_wrap()) { ERR(NULL, "%s: failed to init the SSL library backend.", __func__); rc = -1; goto cleanup; } tls_inited = 1; +#endif /* NC_SSH or NC_TLS */ +#ifdef NC_SSH /* optional for dynamic library, mandatory for static */ if (ssh_init()) { ERR(NULL, "%s: failed to init libssh.", __func__); rc = -1; goto cleanup; } + libssh_inited = 1; +#endif /* NC_SSH */ *inited = 1; cleanup: if (rc) { - /* leave no library initialized behind */ +#ifdef NC_SSH + if (libssh_inited) { + ssh_finalize(); + } +#endif /* NC_SSH */ +#if defined (NC_SSH) || defined (NC_TLS) if (tls_inited) { nc_tls_backend_destroy_wrap(); } +#endif /* NC_SSH or NC_TLS */ +#ifdef NC_TLS if (curl_inited) { curl_global_cleanup(); } +#endif /* NC_TLS */ } /* GLOBAL INIT UNLOCK */ pthread_mutex_unlock(&lock); return rc; -#else - (void)side; - (void)destroy; - - return 0; -#endif /* NC_ENABLED_SSH_TLS */ } int diff --git a/src/session.h b/src/session.h index c8626c53..fb7485af 100644 --- a/src/session.h +++ b/src/session.h @@ -5,7 +5,7 @@ * @brief libnetconf2 session manipulation * * @copyright - * Copyright (c) 2015 - 2023 CESNET, z.s.p.o. + * Copyright (c) 2015 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. @@ -21,9 +21,9 @@ extern "C" { #endif -#include "netconf.h" +#include -#ifdef NC_ENABLED_SSH_TLS +#include "netconf.h" /** * @brief Enumeration of NETCONF SSH authentication methods @@ -58,8 +58,6 @@ typedef enum { NC_TLS_CTN_COMMON_NAME /**< common name as username */ } NC_TLS_CTN_MAPTYPE; -#endif /* NC_ENABLED_SSH_TLS */ - /** * @brief Enumeration of the supported NETCONF protocol versions */ @@ -87,11 +85,13 @@ typedef enum { NC_TI_FD, /**< file descriptors - use standard input/output, transport protocol is implemented outside the current application */ NC_TI_UNIX, /**< unix socket */ -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH NC_TI_SSH, /**< SSH - use libssh library, only for NETCONF over SSH transport */ +#endif /* NC_SSH */ +#ifdef NC_TLS NC_TI_TLS /**< TLS - use either OpenSSL or MbedTLS library, only for NETCONF over TLS transport */ -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ } NC_TRANSPORT_IMPL; /** @@ -189,7 +189,7 @@ const char *nc_session_get_host(const struct nc_session *session); */ uint16_t nc_session_get_port(const struct nc_session *session); -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH /** * @brief Get the SSH protocol identification string sent by the peer. @@ -208,7 +208,7 @@ const char *nc_session_ssh_get_protocol_string(const struct nc_session *session) */ const char *nc_session_ssh_get_banner(const struct nc_session *session); -#endif +#endif /* NC_SSH */ /** * @brief Get session path (unix socket only). diff --git a/src/session_client.c b/src/session_client.c index 82e11bcd..d89d89d8 100644 --- a/src/session_client.c +++ b/src/session_client.c @@ -35,8 +35,8 @@ #include #include -#ifdef NC_ENABLED_SSH_TLS -#include +#ifdef NC_SSH +# include #endif #include @@ -50,11 +50,11 @@ static const char *ncds2str[] = {NULL, "config", "url", "running", "startup", "candidate"}; -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH char *sshauth_password(const char *username, const char *hostname, void *priv); char *sshauth_interactive(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv); char *sshauth_privkey_passphrase(const char *privkey_path, void *priv); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH */ static pthread_once_t nc_client_context_once = PTHREAD_ONCE_INIT; static pthread_key_t nc_client_context_key; @@ -78,7 +78,7 @@ nc_client_context_free(void *ptr) free(c->opts.capabilities); free(c->unix_opts.username); -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) for (i = 0; i < c->opts.ch_bind_count; ++i) { close(c->opts.ch_binds_aux[i].sock); free((char *)c->opts.ch_binds[i].address); @@ -86,13 +86,18 @@ nc_client_context_free(void *ptr) free(c->opts.ch_binds); c->opts.ch_binds = NULL; c->opts.ch_bind_count = 0; +#endif /* NC_SSH or NC_TLS */ +#ifdef NC_SSH _nc_client_ssh_destroy_opts(&c->ssh_opts); _nc_client_ssh_destroy_opts(&c->ssh_ch_opts); +#endif /* NC_SSH */ +#ifdef NC_TLS _nc_client_tls_destroy_opts(&c->tls_opts); _nc_client_tls_destroy_opts(&c->tls_ch_opts); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ + free(c); } @@ -122,7 +127,7 @@ nc_client_context_location(void) e->opts.ka.idle_time = 1; e->opts.ka.max_probes = 10; e->opts.ka.probe_interval = 5; -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH # ifdef HAVE_TERMIOS e->ssh_opts.knownhosts_mode = NC_SSH_KNOWNHOSTS_ASK; # else @@ -143,7 +148,7 @@ nc_client_context_location(void) e->ssh_ch_opts.auth_pref[0].value = 1; e->ssh_ch_opts.auth_pref[1].value = 2; e->ssh_ch_opts.auth_pref[2].value = 3; -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH */ /* init the monitoring thread data lock */ pthread_mutex_init(&e->opts.monitoring_thread_data.lock, NULL); @@ -1753,7 +1758,7 @@ nc_sock_connect(const char *src_addr, uint16_t src_port, const char *dst_addr, u return -1; } -#ifdef NC_ENABLED_SSH_TLS +#if defined (NC_SSH) || defined (NC_TLS) int nc_client_ch_add_bind_listen(const char *address, uint16_t port, const char *hostname, NC_TRANSPORT_IMPL ti) @@ -1872,11 +1877,17 @@ nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **session) return -1; } +#ifdef NC_SSH if (client_opts.ch_binds_aux[bind_idx].ti == NC_TI_SSH) { *session = nc_accept_callhome_ssh_sock(sock, host, port, ctx); - } else if (client_opts.ch_binds_aux[bind_idx].ti == NC_TI_TLS) { + } else +#endif /* NC_SSH */ +#ifdef NC_TLS + if (client_opts.ch_binds_aux[bind_idx].ti == NC_TI_TLS) { *session = nc_accept_callhome_tls_sock(sock, host, port, ctx, client_opts.ch_binds_aux[bind_idx].hostname); - } else { + } else +#endif /* NC_TLS */ + { close(sock); *session = NULL; } @@ -1890,7 +1901,7 @@ nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **session) return 1; } -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH or NC_TLS */ API int nc_session_ntf_thread_running(const struct nc_session *session) @@ -1916,11 +1927,16 @@ nc_client_destroy(void) { nc_client_set_schema_searchpath(NULL); nc_client_unix_set_username(NULL); -#ifdef NC_ENABLED_SSH_TLS + +#if defined (NC_SSH) || defined (NC_TLS) nc_client_ch_del_bind(NULL, 0, 0); +#endif /* NC_SSH or NC_TLS */ +#ifdef NC_SSH nc_client_ssh_destroy_opts(); +#endif /* NC_SSH */ +#ifdef NC_TLS nc_client_tls_destroy_opts(); -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ nc_global_destroy(NC_CLIENT); } @@ -3265,14 +3281,16 @@ nc_client_monitoring_get_session_fd(struct nc_session *session) case NC_TI_UNIX: fd = session->ti.unixsock.sock; break; -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH case NC_TI_SSH: fd = ssh_get_fd(session->ti.libssh.session); break; +#endif /* NC_SSH */ +#ifdef NC_TLS case NC_TI_TLS: fd = nc_tls_get_fd_wrap(session); break; -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ case NC_TI_NONE: /* invalid */ break; diff --git a/src/session_client.h b/src/session_client.h index b2a7a127..d4a16cc4 100644 --- a/src/session_client.h +++ b/src/session_client.h @@ -26,9 +26,9 @@ extern "C" { #include "netconf.h" #include "session.h" -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH # include -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH */ /** * @addtogroup client @@ -193,7 +193,7 @@ struct nc_session *nc_connect_unix(const char *address, struct ly_ctx *ctx); /** @} Client Session */ -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH /** * @defgroup client_ssh Client SSH @@ -418,6 +418,10 @@ struct nc_session *nc_connect_ssh_channel(struct nc_session *session, struct ly_ /** @} Client SSH */ +#endif /* NC_SSH */ + +#ifdef NC_TLS + /** * @defgroup client_tls Client TLS * @ingroup client @@ -482,7 +486,7 @@ struct nc_session *nc_connect_tls(const char *host, uint16_t port, struct ly_ctx /** @} Client TLS */ -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ /** * @addtogroup client_session diff --git a/src/session_client_ch.h b/src/session_client_ch.h index 74a79776..f508eeb2 100644 --- a/src/session_client_ch.h +++ b/src/session_client_ch.h @@ -4,7 +4,7 @@ * @brief libnetconf2 Call Home session client manipulation * * @copyright - * Copyright (c) 2015 - 2023 CESNET, z.s.p.o. + * Copyright (c) 2015 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. @@ -22,16 +22,14 @@ extern "C" { #include -#ifdef NC_ENABLED_SSH_TLS +#ifdef NC_SSH # include -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_SSH */ #include "messages_client.h" #include "netconf.h" #include "session.h" -#ifdef NC_ENABLED_SSH_TLS - /** * @defgroup client_ch Client-side Call Home * @ingroup client @@ -55,6 +53,8 @@ int nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **sess /** @} Client-side Call Home */ +#ifdef NC_SSH + /** * @defgroup client_ch_ssh Client-side Call Home on SSH * @ingroup client_ch @@ -250,6 +250,10 @@ const char *nc_client_ssh_ch_get_username(void); /** @} Client-side Call Home on SSH */ +#endif /* NC_SSH */ + +#ifdef NC_TLS + /** * @defgroup client_ch_tls Client-side Call Home on TLS * @ingroup client_ch @@ -325,7 +329,7 @@ void nc_client_tls_ch_get_trusted_ca_paths(const char **ca_file, const char **ca /** @} Client-side Call Home on TLS */ -#endif /* NC_ENABLED_SSH_TLS */ +#endif /* NC_TLS */ #ifdef __cplusplus } diff --git a/src/session_client_tls.c b/src/session_client_tls.c index 0c0b5468..426905ba 100644 --- a/src/session_client_tls.c +++ b/src/session_client_tls.c @@ -4,10 +4,8 @@ * @author Michal Vasko * @brief libnetconf2 - TLS specific session client transport functions * - * This source is compiled only with libssl. - * * @copyright - * Copyright (c) 2015 CESNET, z.s.p.o. + * Copyright (c) 2015 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. @@ -31,8 +29,8 @@ #include "log_p.h" #include "session_client.h" #include "session_client_ch.h" +#include "session_crypto_wrapper.h" #include "session_p.h" -#include "session_wrapper.h" void _nc_client_tls_destroy_opts(struct nc_client_tls_opts *opts) @@ -317,8 +315,8 @@ nc_client_tls_session_new(int sock, const char *host, struct nc_client_tls_opts } nc_tls_session_destroy_wrap(tls_session); - nc_tls_cert_destroy_wrap(cli_cert); - nc_tls_privkey_destroy_wrap(cli_pkey); + nc_cert_destroy_wrap(cli_cert); + nc_privkey_destroy_wrap(cli_pkey); nc_tls_cert_store_destroy_wrap(cert_store); nc_tls_config_destroy_wrap(tls_cfg); return NULL; diff --git a/src/session_mbedtls.c b/src/session_crypto_mbedtls.c similarity index 96% rename from src/session_mbedtls.c rename to src/session_crypto_mbedtls.c index d0bb4f09..d2d250a2 100644 --- a/src/session_mbedtls.c +++ b/src/session_crypto_mbedtls.c @@ -1,5 +1,5 @@ /** - * @file session_mbedtls.c + * @file session_crypto_mbedtls.c * @author Roman Janota * @brief libnetconf2 - wrapped MbedTLS function calls for TLS/asymmetric cryptography support * @@ -8,7 +8,7 @@ * This file is included in the build process only if MbedTLS is being used. * * @copyright - * Copyright (c) 2024 CESNET, z.s.p.o. + * Copyright (c) 2024 - 2026 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ #define _GNU_SOURCE +#include "session_crypto_wrapper.h" + #include #include #include @@ -29,16 +31,11 @@ #include #include -#include - #include "compat.h" #include "config.h" #include "log_p.h" #include "session.h" #include "session_p.h" -#include "session_wrapper.h" - -#include #include #include @@ -54,42 +51,21 @@ #include /** - * @brief List of supported cipher suites for MbedTLS. + * @brief Create a new private key context. * - * This list is used to populate the operational data for supported cipher suites. - * Obtained from v4.0.0. + * @return New private key context or NULL. */ -const char *nc_tls_supported_cipher_suites[] = { - "TLS_PSK_WITH_NULL_SHA", "TLS_PSK_WITH_AES_128_CBC_SHA", "TLS_PSK_WITH_AES_256_CBC_SHA", - "TLS_PSK_WITH_AES_128_GCM_SHA256", "TLS_PSK_WITH_AES_256_GCM_SHA384", "TLS_PSK_WITH_AES_128_CBC_SHA256", - "TLS_PSK_WITH_AES_256_CBC_SHA384", "TLS_PSK_WITH_NULL_SHA256", "TLS_PSK_WITH_NULL_SHA384", - "TLS_ECDHE_ECDSA_WITH_NULL_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_NULL_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_PSK_WITH_NULL_SHA", "TLS_ECDHE_PSK_WITH_NULL_SHA256", - "TLS_ECDHE_PSK_WITH_NULL_SHA384", "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", - "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", - "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", "TLS_PSK_WITH_ARIA_128_CBC_SHA256", "TLS_PSK_WITH_ARIA_256_CBC_SHA384", - "TLS_PSK_WITH_ARIA_128_GCM_SHA256", "TLS_PSK_WITH_ARIA_256_GCM_SHA384", "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", - "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", - "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", - "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", "TLS_PSK_WITH_AES_128_CCM", "TLS_PSK_WITH_AES_256_CCM", - "TLS_PSK_WITH_AES_128_CCM_8", "TLS_PSK_WITH_AES_256_CCM_8", "TLS_ECDHE_ECDSA_WITH_AES_128_CCM", - "TLS_ECDHE_ECDSA_WITH_AES_256_CCM", "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", NULL -}; +static void * +nc_pkey_new_wrap(void) +{ + mbedtls_pk_context *pkey; + + pkey = malloc(sizeof *pkey); + NC_CHECK_ERRMEM_RET(!pkey, NULL); + + mbedtls_pk_init(pkey); + return pkey; +} /** * @brief Converts MbedTLS error code to a string and merges it with an arbitrary error message. @@ -167,42 +143,6 @@ nc_mbedtls_strerr(const struct nc_session *session, int mbedtls_err_code, const free(err_buf); } -/** - * @brief Converts DN to a string. - * - * @param[in] dn Internal DN representation. - * @return DN string on success, NULL of fail. - */ -static char * -nc_server_tls_dn2str(const mbedtls_x509_name *dn) -{ - char *str; - size_t len = 64; - int r; - - str = malloc(len); - NC_CHECK_ERRMEM_RET(!str, NULL); - - while ((r = mbedtls_x509_dn_gets(str, len, dn)) == MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) { - /* the error is also returned for any attribute value longer than MBEDTLS_X509_MAX_DN_NAME_SIZE, - * which no buffer size can fix, so limit the growth */ - if (len >= NC_TLS_DN_STR_MAX_LEN) { - break; - } - - len <<= 1; - str = nc_realloc(str, len); - NC_CHECK_ERRMEM_RET(!str, NULL); - } - if (r < 1) { - free(str); - nc_mbedtls_strerr(NULL, r, "Failed to convert DN to string"); - return NULL; - } - - return str; -} - /** * @brief Create a new random number generator context. * @@ -211,7 +151,7 @@ nc_server_tls_dn2str(const mbedtls_x509_name *dn) * @return 0 on success, 1 on failure. */ static int -nc_tls_rng_new(mbedtls_ctr_drbg_context **ctr_drbg, mbedtls_entropy_context **entropy) +nc_rng_new(mbedtls_ctr_drbg_context **ctr_drbg, mbedtls_entropy_context **entropy) { int rc; @@ -253,7 +193,7 @@ nc_tls_rng_new(mbedtls_ctr_drbg_context **ctr_drbg, mbedtls_entropy_context **en * @param[in] entropy Entropy context. */ static void -nc_tls_rng_destroy(mbedtls_ctr_drbg_context *ctr_drbg, mbedtls_entropy_context *entropy) +nc_rng_destroy(mbedtls_ctr_drbg_context *ctr_drbg, mbedtls_entropy_context *entropy) { mbedtls_ctr_drbg_free(ctr_drbg); free(ctr_drbg); @@ -263,6 +203,23 @@ nc_tls_rng_destroy(mbedtls_ctr_drbg_context *ctr_drbg, mbedtls_entropy_context * } } +/** + * @brief Create a new MbedTLS certificate. + * + * @return Created certificate, NULL on error. + */ +static void * +nc_cert_new(void) +{ + mbedtls_x509_crt *cert; + + cert = malloc(sizeof *cert); + NC_CHECK_ERRMEM_RET(!cert, NULL); + + mbedtls_x509_crt_init(cert); + return cert; +} + /** * @brief Get a string representation of the verification error. * @@ -311,6 +268,46 @@ nc_tls_backend_destroy_wrap(void) mbedtls_psa_crypto_free(); } +#ifdef NC_TLS + +/** + * @brief List of supported cipher suites for MbedTLS. + * + * This list is used to populate the operational data for supported cipher suites. + * Obtained from v4.0.0. + */ +const char *nc_tls_supported_cipher_suites[] = { + "TLS_PSK_WITH_NULL_SHA", "TLS_PSK_WITH_AES_128_CBC_SHA", "TLS_PSK_WITH_AES_256_CBC_SHA", + "TLS_PSK_WITH_AES_128_GCM_SHA256", "TLS_PSK_WITH_AES_256_GCM_SHA384", "TLS_PSK_WITH_AES_128_CBC_SHA256", + "TLS_PSK_WITH_AES_256_CBC_SHA384", "TLS_PSK_WITH_NULL_SHA256", "TLS_PSK_WITH_NULL_SHA384", + "TLS_ECDHE_ECDSA_WITH_NULL_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_NULL_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_PSK_WITH_NULL_SHA", "TLS_ECDHE_PSK_WITH_NULL_SHA256", + "TLS_ECDHE_PSK_WITH_NULL_SHA384", "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", "TLS_PSK_WITH_ARIA_128_CBC_SHA256", "TLS_PSK_WITH_ARIA_256_CBC_SHA384", + "TLS_PSK_WITH_ARIA_128_GCM_SHA256", "TLS_PSK_WITH_ARIA_256_GCM_SHA384", "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", + "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", "TLS_PSK_WITH_AES_128_CCM", "TLS_PSK_WITH_AES_256_CCM", + "TLS_PSK_WITH_AES_128_CCM_8", "TLS_PSK_WITH_AES_256_CCM_8", "TLS_ECDHE_ECDSA_WITH_AES_128_CCM", + "TLS_ECDHE_ECDSA_WITH_AES_256_CCM", "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", NULL +}; + void * nc_tls_session_new_wrap(void *tls_cfg) { @@ -378,101 +375,18 @@ nc_tls_config_destroy_wrap(void *tls_cfg) free(tls_cfg); } -void * -nc_tls_cert_new_wrap(void) -{ - mbedtls_x509_crt *cert; - - cert = malloc(sizeof *cert); - NC_CHECK_ERRMEM_RET(!cert, NULL); - - mbedtls_x509_crt_init(cert); - return cert; -} - -void -nc_tls_cert_destroy_wrap(void *cert) -{ - mbedtls_x509_crt_free(cert); - free(cert); -} - -/** - * @brief Create a new private key context. - * - * @return New private key context or NULL. - */ -static void * -nc_tls_pkey_new_wrap(void) -{ - mbedtls_pk_context *pkey; - - pkey = malloc(sizeof *pkey); - NC_CHECK_ERRMEM_RET(!pkey, NULL); - - mbedtls_pk_init(pkey); - return pkey; -} - -void -nc_tls_privkey_destroy_wrap(void *pkey) -{ - mbedtls_pk_free(pkey); - free(pkey); -} - void * nc_tls_cert_store_new_wrap(void) { /* certificate is the same as a certificate store in MbedTLS */ - return nc_tls_cert_new_wrap(); + return nc_cert_new(); } void nc_tls_cert_store_destroy_wrap(void *cert_store) { /* certificate is the same as a certificate store in MbedTLS */ - nc_tls_cert_destroy_wrap(cert_store); -} - -void * -nc_tls_crl_store_new_wrap(void) -{ - mbedtls_x509_crl *crl; - - crl = malloc(sizeof *crl); - NC_CHECK_ERRMEM_RET(!crl, NULL); - - mbedtls_x509_crl_init(crl); - return crl; -} - -void -nc_tls_crl_store_destroy_wrap(void *crl_store) -{ - mbedtls_x509_crl_free(crl_store); - free(crl_store); -} - -void * -nc_tls_pem_to_cert_wrap(const char *cert_data) -{ - int rc; - mbedtls_x509_crt *cert; - - cert = nc_tls_cert_new_wrap(); - if (!cert) { - return NULL; - } - - rc = mbedtls_x509_crt_parse(cert, (const unsigned char *)cert_data, strlen(cert_data) + 1); - if (rc) { - nc_mbedtls_strerr(NULL, rc, "Parsing certificate data failed"); - nc_tls_cert_destroy_wrap(cert); - return NULL; - } - - return cert; + nc_cert_destroy_wrap(cert_store); } int @@ -491,950 +405,975 @@ nc_tls_add_cert_to_store_wrap(void *cert, void *cert_store) } void * -nc_tls_pem_to_privkey_wrap(const char *privkey_data) +nc_tls_get_sans_wrap(void *cert) { - int rc = 0; - mbedtls_pk_context *pkey = NULL; - mbedtls_ctr_drbg_context *ctr_drbg = NULL; - mbedtls_entropy_context *entropy = NULL; + return &(((mbedtls_x509_crt *)cert)->subject_alt_names); +} - rc = nc_tls_rng_new(&ctr_drbg, &entropy); - if (rc) { - goto cleanup; - } +void +nc_tls_sans_destroy_wrap(void *UNUSED(sans)) +{ + return; +} - pkey = nc_tls_pkey_new_wrap(); - if (!pkey) { - rc = 1; - goto cleanup; - } +int +nc_tls_get_num_sans_wrap(void *sans) +{ + mbedtls_x509_sequence *iter; + int n = 0; - rc = mbedtls_pk_parse_key(pkey, (const unsigned char *)privkey_data, strlen(privkey_data) + 1, NULL, 0, mbedtls_ctr_drbg_random, ctr_drbg); - if (rc) { - nc_mbedtls_strerr(NULL, rc, "Parsing private key data failed"); - goto cleanup; + /* sans are a linked list */ + iter = sans; + while (iter) { + ++n; + iter = iter->next; } -cleanup: - if (rc) { - nc_tls_privkey_destroy_wrap(pkey); - pkey = NULL; - } - nc_tls_rng_destroy(ctr_drbg, entropy); - return pkey; + return n; } int -nc_server_tls_add_crl_to_store_wrap(const unsigned char *crl_data, size_t size, void *crl_store) +nc_tls_get_san_value_type_wrap(void *sans, int idx, char **san_value, NC_TLS_CTN_MAPTYPE *san_type) { - int r, rc = 0; - unsigned char *pem = NULL; - - if (!crl_data || !size) { - ERR(NULL, "CRL data is empty."); - return 1; + int i, rc, ret = 0; + mbedtls_x509_sequence *iter; + mbedtls_x509_subject_alternative_name san = {0}; + const mbedtls_x509_buf *ip, *str; + + *san_value = NULL; + *san_type = NC_TLS_CTN_UNKNOWN; + + /* find the SAN */ + iter = sans; + for (i = 0; i < idx; i++) { + iter = iter->next; } - /* determine the format by checking for the PEM header */ - if (!strncmp((const char *)crl_data, "-----BEGIN", 10)) { - /* PEM requires null-terminated data for mbedtls_x509_crl_parse */ - pem = malloc(size + 1); - NC_CHECK_ERRMEM_GOTO(!pem, rc = 1, cleanup); - memcpy(pem, crl_data, size); - pem[size] = '\0'; - r = mbedtls_x509_crl_parse(crl_store, pem, size + 1); - } else { - r = mbedtls_x509_crl_parse_der(crl_store, crl_data, size); + /* parse it */ + rc = mbedtls_x509_parse_subject_alt_name(&iter->buf, &san); + if (rc && (rc != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE)) { + return -1; } - if (r) { - nc_mbedtls_strerr(NULL, r, "Parsing downloaded CRL failed"); - rc = 1; - goto cleanup; + + /* get its type and value */ + switch (san.type) { + case MBEDTLS_X509_SAN_DNS_NAME: + case MBEDTLS_X509_SAN_RFC822_NAME: + str = &san.san.unstructured_name; + if (!str->len) { + WRN(NULL, "SAN value is empty, skipping."); + ret = 1; + goto cleanup; + } else if (memchr(str->p, '\0', str->len)) { + /* the value would get truncated */ + WRN(NULL, "SAN value includes a NUL character, skipping."); + ret = 1; + goto cleanup; + } + + *san_type = (san.type == MBEDTLS_X509_SAN_DNS_NAME) ? NC_TLS_CTN_SAN_DNS_NAME : NC_TLS_CTN_SAN_RFC822_NAME; + *san_value = strndup((const char *)str->p, str->len); + NC_CHECK_ERRMEM_GOTO(!*san_value, ret = -1, cleanup); + break; + case MBEDTLS_X509_SAN_IP_ADDRESS: + *san_type = NC_TLS_CTN_SAN_IP_ADDRESS; + ip = &san.san.unstructured_name; + if (ip->len == 4) { + rc = asprintf(san_value, "%d.%d.%d.%d", ip->p[0], ip->p[1], ip->p[2], ip->p[3]); + NC_CHECK_ERRMEM_GOTO(rc == -1, ret = -1, cleanup); + } else if (ip->len == 16) { + rc = asprintf(san_value, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + ip->p[0], ip->p[1], ip->p[2], ip->p[3], ip->p[4], ip->p[5], + ip->p[6], ip->p[7], ip->p[8], ip->p[9], ip->p[10], ip->p[11], + ip->p[12], ip->p[13], ip->p[14], ip->p[15]); + NC_CHECK_ERRMEM_GOTO(rc == -1, ret = -1, cleanup); + } else { + WRN(NULL, "SAN IP address in an unknown format (length is %d).", ip->len); + ret = 1; + } + break; + default: + /* we dont care about other types */ + *san_type = NC_TLS_CTN_UNKNOWN; + ret = 1; + break; } cleanup: - free(pem); - return rc; + mbedtls_x509_free_subject_alt_name(&san); + return ret; } int -nc_server_tls_set_tls_versions_wrap(void *tls_cfg, enum nc_tls_version min, enum nc_tls_version max) +nc_tls_get_num_certs_wrap(void *chain) { - /* set the minimum version if any, otherwise leave it to MbedTLS default */ - if (min & NC_TLS_VERSION_1_2) { - mbedtls_ssl_conf_min_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_2); - } else if (min & NC_TLS_VERSION_1_3) { - mbedtls_ssl_conf_min_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_3); - } + mbedtls_x509_crt *iter; + int n = 0; - /* set the maximum version if any, otherwise leave it to MbedTLS default */ - if (max & NC_TLS_VERSION_1_3) { - mbedtls_ssl_conf_max_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_3); - } else if (max & NC_TLS_VERSION_1_2) { - mbedtls_ssl_conf_max_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_2); + /* chain is a linked list */ + iter = chain; + while (iter) { + ++n; + iter = iter->next; } - return 0; + return n; } -/** - * @brief Duplicates a certificate. - * - * @param[in] cert Certificate to duplicate. - * @return Duplicated certificate or NULL. - */ -static mbedtls_x509_crt * -nc_tls_cert_dup(const mbedtls_x509_crt *cert) +void * +nc_tls_get_cert_wrap(void *chain, int idx) { - mbedtls_x509_crt *new_cert; + int i; + mbedtls_x509_crt *iter; - new_cert = nc_tls_cert_new_wrap(); - if (!new_cert) { + if (!chain || (idx < 0)) { return NULL; } - if (mbedtls_x509_crt_parse_der(new_cert, cert->raw.p, cert->raw.len)) { - free(new_cert); - return NULL; + iter = chain; + for (i = 0; iter && (i < idx); i++) { + iter = iter->next; } - return new_cert; + return iter; } -/** - * @brief Duplicate a certificate and prepend it to a chain. - * - * @param[in] cert Certificate to duplicate and prepend. - * @param[in,out] chain Chain to prepend the certificate to. - * @return 0 on success, -1 on error. - */ -static int -nc_server_tls_prepend_cert_to_chain(mbedtls_x509_crt *cert, mbedtls_x509_crt **chain) +int +nc_tls_init_ctx_wrap(void *cert, void *pkey, void *cert_store, void *cipher_suites, struct nc_tls_ctx *tls_ctx) { - mbedtls_x509_crt *copy; - - copy = nc_tls_cert_dup(cert); - if (!copy) { - return -1; + /* setup rng */ + if (nc_rng_new(&tls_ctx->ctr_drbg, &tls_ctx->entropy)) { + return 1; } - copy->next = *chain; - *chain = copy; + /* fill the context */ + tls_ctx->cipher_suites = cipher_suites; + tls_ctx->sock = malloc(sizeof *tls_ctx->sock); + NC_CHECK_ERRMEM_RET(!tls_ctx->sock, 1); + tls_ctx->cert = cert; + tls_ctx->pkey = pkey; + tls_ctx->cert_store = cert_store; + return 0; +} + +int +nc_tls_setup_config_from_ctx_wrap(struct nc_tls_ctx *tls_ctx, void *tls_cfg) +{ + /* set config's rng */ + mbedtls_ssl_conf_rng(tls_cfg, mbedtls_ctr_drbg_random, tls_ctx->ctr_drbg); + /* set config's cert and key */ + mbedtls_ssl_conf_own_cert(tls_cfg, tls_ctx->cert, tls_ctx->pkey); + /* + * Do NOT pass a CRL store to mbedtls_ssl_conf_ca_chain. CRL verification + * is done post-handshake so that CRLs for peer certificates (received + * during the handshake) can also be downloaded and checked. + */ + mbedtls_ssl_conf_ca_chain(tls_cfg, tls_ctx->cert_store, NULL); return 0; } +void +nc_tls_ctx_destroy_wrap(struct nc_tls_ctx *tls_ctx) +{ + nc_rng_destroy(tls_ctx->ctr_drbg, tls_ctx->entropy); + nc_cert_destroy_wrap(tls_ctx->cert); + nc_privkey_destroy_wrap(tls_ctx->pkey); + nc_tls_cert_store_destroy_wrap(tls_ctx->cert_store); + free(tls_ctx->sock); + free(tls_ctx->cipher_suites); +} + +uint32_t +nc_tls_get_verify_result_wrap(void *tls_session) +{ + return mbedtls_ssl_get_verify_result(tls_session); +} + +char * +nc_tls_verify_error_string_wrap(uint32_t err_code) +{ + return nc_tls_get_verify_err_str(err_code); +} + /** - * @brief Check whether a certificate is already present in a chain. + * @brief Callback for sending data. * - * @param[in] cert Certificate to search for. - * @param[in] chain Certificate chain. - * @return 1 if found, 0 otherwise. + * @param[in] ctx Socket. + * @param[in] buf Data to send. + * @param[in] len Length of the data. + * @return Number of bytes sent or negative value on error. */ static int -nc_server_tls_cert_in_chain(const mbedtls_x509_crt *cert, const mbedtls_x509_crt *chain) +nc_tls_send(void *ctx, const unsigned char *buf, size_t len) { - const mbedtls_x509_crt *iter; + int sock, ret; - for (iter = chain; iter; iter = iter->next) { - if (cert->raw.p && iter->raw.p && (cert->raw.len == iter->raw.len) && !memcmp(cert->raw.p, iter->raw.p, cert->raw.len)) { - return 1; + NC_CHECK_ARG_RET(NULL, ctx, MBEDTLS_ERR_NET_INVALID_CONTEXT); + + sock = *(int *)ctx; + + ret = send(sock, buf, len, MSG_NOSIGNAL); + if (ret < 0) { + if ((errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINTR)) { + return MBEDTLS_ERR_SSL_WANT_WRITE; + } else if ((errno == EPIPE) || (errno == ECONNRESET)) { + return MBEDTLS_ERR_NET_CONN_RESET; + } else { + return MBEDTLS_ERR_NET_SEND_FAILED; } } - return 0; + return ret; } /** - * @brief Prepend issuer chain for a certificate. - * - * Repeatedly parse issuer_raw of @p cert into a certificate, then parse issuer_raw - * of that parsed issuer, and so on. Parsed issuers are prepended into @p chain in - * root-first order so that prepending the actual cert afterwards yields peer-first - * order. + * @brief Callback for receiving data. * - * @param[in] cert Certificate whose issuers are to be prepended. - * @param[in,out] chain Chain to prepend issuer certificates to. - * @return 0 on success, -1 on error. + * @param[in] ctx Socket. + * @param[out] buf Buffer to store the received data. + * @param[in] len Length of the buffer. + * @return Number of bytes received or negative value on error. */ static int -nc_server_tls_prepend_issuer_chain(mbedtls_x509_crt *cert, mbedtls_x509_crt **chain) +nc_tls_recv(void *ctx, unsigned char *buf, size_t len) { - size_t i = 0; - mbedtls_x509_crt *copy; - const mbedtls_x509_crt *issuer, *iter, *cur; - mbedtls_x509_crt *issuers[MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE - 1]; + int sock, ret; - cur = cert; - while (cur && (i < (sizeof issuers / sizeof *issuers))) { - if (!cur->issuer_raw.p || !cur->issuer_raw.len) { - break; - } + NC_CHECK_ARG_RET(NULL, ctx, MBEDTLS_ERR_NET_INVALID_CONTEXT); - if ((cur->issuer_raw.len == cur->subject_raw.len) && !memcmp(cur->issuer_raw.p, cur->subject_raw.p, cur->issuer_raw.len)) { - /* self-issued root reached */ - break; + sock = *(int *)ctx; + + ret = recv(sock, buf, len, 0); + if (ret < 0) { + if ((errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINTR)) { + return MBEDTLS_ERR_SSL_WANT_READ; + } else if ((errno == EPIPE) || (errno == ECONNRESET)) { + return MBEDTLS_ERR_NET_CONN_RESET; + } else { + return MBEDTLS_ERR_NET_RECV_FAILED; } + } - /* find issuer cert by matching issuer DN to subject DN */ - issuer = NULL; - for (iter = cert; iter; iter = iter->next) { - if ((iter->subject_raw.len == cur->issuer_raw.len) && - !memcmp(iter->subject_raw.p, cur->issuer_raw.p, cur->issuer_raw.len)) { - issuer = iter; - break; - } - } - if (!issuer) { - /* no more issuers available in the certificate set */ - break; - } + return ret; +} - if (nc_server_tls_cert_in_chain(issuer, *chain)) { - /* already present in chain */ +void +nc_tls_set_fd_wrap(void *tls_session, int sock, struct nc_tls_ctx *tls_ctx) +{ + /* mbedtls sets a pointer to the sock, which is stored in tls_ctx */ + *tls_ctx->sock = sock; + mbedtls_ssl_set_bio(tls_session, tls_ctx->sock, nc_tls_send, nc_tls_recv, NULL); +} + +int +nc_tls_read_wrap(struct nc_session *session, unsigned char *buf, size_t size) +{ + int rc; + mbedtls_ssl_context *tls_session = session->ti.tls.session; + + rc = mbedtls_ssl_read(tls_session, buf, size); + if (rc <= 0) { + switch (rc) { + case MBEDTLS_ERR_SSL_WANT_READ: + case MBEDTLS_ERR_SSL_WANT_WRITE: + rc = 0; + break; + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + nc_mbedtls_strerr(session, rc, "Communication socket unexpectedly closed"); + NC_SESSION_STATUS_SET(session, NC_STATUS_INVALID); + NC_SESSION_TERM_REASON_SET(session, NC_SESSION_TERM_DROPPED); + rc = -1; + break; + default: + nc_mbedtls_strerr(session, rc, "TLS communication error occurred"); + NC_SESSION_STATUS_SET(session, NC_STATUS_INVALID); + NC_SESSION_TERM_REASON_SET(session, NC_SESSION_TERM_OTHER); + rc = -1; break; } + } - copy = nc_tls_cert_dup(issuer); - if (!copy) { - goto error; - } + return rc; +} - issuers[i] = copy; - ++i; - cur = issuer; - } +int +nc_tls_write_wrap(struct nc_session *session, const unsigned char *buf, size_t size) +{ + int rc = 0; + mbedtls_ssl_context *tls_session = session->ti.tls.session; - while (i) { - --i; - issuers[i]->next = *chain; - *chain = issuers[i]; + rc = mbedtls_ssl_write(tls_session, buf, size); + if (rc < 0) { + switch (rc) { + case MBEDTLS_ERR_SSL_WANT_READ: + case MBEDTLS_ERR_SSL_WANT_WRITE: + rc = 0; + break; + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + nc_mbedtls_strerr(session, rc, "TLS connection was properly closed."); + rc = -1; + break; + default: + nc_mbedtls_strerr(session, rc, "TLS communication error occurred"); + rc = -1; + break; + } } - return 0; + return rc; +} -error: - while (i) { - --i; - nc_tls_cert_destroy_wrap(issuers[i]); - } - return -1; +int +nc_tls_get_num_pending_bytes_wrap(void *tls_session) +{ + return mbedtls_ssl_get_bytes_avail(tls_session); } -#ifdef NC_COMPLY_WITH_ORAN_WG11 +int +nc_tls_get_fd_wrap(const struct nc_session *session) +{ + return session->ti.tls.ctx.sock ? *session->ti.tls.ctx.sock : -1; +} -/** - * @brief Check that a client certificate complies with the O-RAN WG11 6.9.3 key usage requirements. - * - * The end-entity (client) certificate MUST carry the clientAuth Extended Key Usage and a Key Usage - * extension with the digitalSignature bit set (the client signs the CertificateVerify handshake message). - * - * @param[in] session Session for logging. - * @param[in] cert Client (leaf) certificate to check. - * @param[in,out] flags Verification flags, set on failure. - * @return 0 if the certificate complies, non-zero otherwise. - */ -static int -nc_server_tls_check_oran_wg11_usage(struct nc_session *session, mbedtls_x509_crt *cert, uint32_t *flags) +void +nc_tls_close_notify_wrap(void *tls_session) { - const mbedtls_x509_sequence *usage; - int has_client_auth = 0; + int rc; - /* the client certificate MUST carry the clientAuth Extended Key Usage */ - for (usage = &cert->ext_key_usage; usage && usage->buf.p; usage = usage->next) { - if (!MBEDTLS_OID_CMP(MBEDTLS_OID_CLIENT_AUTH, &usage->buf)) { - has_client_auth = 1; - break; + while ((rc = mbedtls_ssl_close_notify(tls_session))) { + if ((rc != MBEDTLS_ERR_SSL_WANT_READ) && (rc != MBEDTLS_ERR_SSL_WANT_WRITE)) { + /* some error occurred */ + nc_mbedtls_strerr(NULL, rc, "Sending TLS close notify failed"); + return; } } - if (!has_client_auth) { - ERR(session, "Cert verify: fail (client certificate lacks the required clientAuth Extended Key Usage)."); - *flags |= MBEDTLS_X509_BADCERT_EXT_KEY_USAGE; - return 1; - } +} - /* the client certificate MUST also carry a Key Usage extension with the digitalSignature bit set */ - if (!mbedtls_x509_crt_has_ext_type(cert, MBEDTLS_X509_EXT_KEY_USAGE) || - mbedtls_x509_crt_check_key_usage(cert, MBEDTLS_X509_KU_DIGITAL_SIGNATURE)) { - ERR(session, "Cert verify: fail (client certificate lacks the required digitalSignature Key Usage)."); - *flags |= MBEDTLS_X509_BADCERT_KEY_USAGE; - return 1; +/** + * @brief Convert the MbedTLS key export type to a label for the keylog file. + * + * @param[in] type MbedTLS key export type. + * @return Label for the keylog file or NULL if the type is not supported. + */ +static const char * +nc_tls_keylog_type2label(mbedtls_ssl_key_export_type type) +{ + switch (type) { + case MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET: + return "CLIENT_RANDOM"; +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 + case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET: + return "CLIENT_HANDSHAKE_TRAFFIC_SECRET"; + case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET: + return "SERVER_HANDSHAKE_TRAFFIC_SECRET"; + case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET: + return "CLIENT_TRAFFIC_SECRET_0"; + case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET: + return "SERVER_TRAFFIC_SECRET_0"; +#endif + default: + return NULL; } - - return 0; } -#endif /* NC_COMPLY_WITH_ORAN_WG11 */ - /** - * @brief Verify a certificate. - * - * @param[in] cb_data Callback data (session, opts, data for CTN). - * @param[in] cert Certificate to verify. - * @param[in] depth Certificate depth in the chain. - * @param[in,out] flags Verification flags. Used to propagate errors. - * @return 0 on success (verification result is based on the value of flags), non-zero on fatal-error. + * @brief Callback for writing a line in the keylog file. */ -static int -nc_server_tls_verify_cb(void *cb_data, mbedtls_x509_crt *cert, int depth, uint32_t *flags) +static void +nc_tls_keylog_write_line(void *UNUSED(p_expkey), mbedtls_ssl_key_export_type type, const unsigned char *secret, + size_t secret_len, const unsigned char client_random[32], + const unsigned char UNUSED(server_random[32]), mbedtls_tls_prf_types UNUSED(tls_prf_type)) { - int ret = 0; - struct nc_tls_verify_cb_data *data = cb_data; - char *err; + size_t linelen, len = 0, i, client_random_len; + char buf[256]; + const char *label; - if (!data->chain) { - /* first call, prepend the issuer chain so that we have the whole chain available for CTN */ - ret = nc_server_tls_prepend_issuer_chain(cert, (mbedtls_x509_crt **)&data->chain); - if (ret) { - nc_tls_cert_destroy_wrap(data->chain); - return MBEDTLS_ERR_X509_ALLOC_FAILED; - } + if (!server_opts.tls_keylog_file) { + return; } - /* prepend to the chain we're building to maintain peer-first order */ - if (!nc_server_tls_cert_in_chain(cert, (const mbedtls_x509_crt *)data->chain)) { - ret = nc_server_tls_prepend_cert_to_chain(cert, (mbedtls_x509_crt **)&data->chain); - if (ret) { - nc_tls_cert_destroy_wrap(data->chain); - return MBEDTLS_ERR_X509_ALLOC_FAILED; - } + label = nc_tls_keylog_type2label(type); + if (!label) { + /* type not supported */ + return; } - if (!*flags) { - /* in-built verification was successful */ - ret = nc_server_tls_verify_cert(cert, depth, 1, data); - } else { - /* in-built verification failed, but the client still may be authenticated if: - * 1) the peer cert matches any configured end-entity cert - * 2) the peer cert has a valid chain of trust to any configured certificate authority cert - * otherwise just continue until we reach the peer cert (depth = 0) - */ - if ((depth == 0) && (*flags == MBEDTLS_X509_BADCERT_NOT_TRUSTED)) { - /* not trusted self-signed peer certificate, case 1) */ - ret = nc_server_tls_verify_cert(cert, depth, 0, data); - if (!ret) { - *flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED; - } - } else if (*flags == MBEDTLS_X509_BADCERT_MISSING) { - /* full chain of trust is invalid, but it may be valid partially, case 2) */ - ret = nc_server_tls_verify_cert(cert, depth, 0, data); - if (!ret) { - *flags &= ~MBEDTLS_X509_BADCERT_MISSING; - } - } else { - err = nc_tls_get_verify_err_str(*flags); - ERR(data->session, "Cert verify: fail (%s).", err); - free(err); - ret = 1; - } + /*