From a19f91b9cf2c7252c24db0884349ff775dc0892c Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 2 Feb 2023 08:58:27 +0100 Subject: [PATCH 001/134] libnetconf UPDATE YANG data configuration Configuration based on YANG data. Open 2 ssh channels on one session. Pubkey,interactive,pw,none SSH authentication working. SSH message callback not a callback anymore, handle SSH messages manually. ietf-netconf-server and all models it imports added and a libnetconf2 own model with augments. And finally only local-definition of keys supported. 2 tests. NBC API changes. --- CMakeLists.txt | 6 +- examples/client.c | 2 + examples/example.h.in | 3 + examples/server.c | 139 +- modules/iana-crypt-hash.yang | 124 + .../iana-ssh-encryption-algs@2022-06-16.yang | 392 ++ ...iana-ssh-key-exchange-algs@2022-06-16.yang | 2219 ++++++++++ modules/iana-ssh-mac-algs@2022-06-16.yang | 167 + .../iana-ssh-public-key-algs@2022-06-16.yang | 441 ++ ...iana-tls-cipher-suite-algs@2022-06-16.yang | 3778 +++++++++++++++++ modules/ietf-crypto-types@2022-07-07.yang | 1021 +++++ modules/ietf-keystore@2022-05-24.yang | 412 ++ modules/ietf-netconf-server@2022-05-24.yang | 677 +++ modules/ietf-ssh-common@2022-07-18.yang | 257 ++ modules/ietf-ssh-server@2022-07-18.yang | 414 ++ modules/ietf-tcp-client@2022-05-24.yang | 316 ++ modules/ietf-tcp-common@2022-05-24.yang | 115 + modules/ietf-tcp-server@2022-05-24.yang | 114 + modules/ietf-tls-common@2022-07-18.yang | 311 ++ modules/ietf-tls-server@2022-07-18.yang | 525 +++ modules/ietf-truststore@2022-05-24.yang | 339 ++ modules/ietf-x509-cert-to-name.yang | 314 ++ modules/libnetconf2-netconf-server.yang | 35 + src/config.h.in | 5 + src/config_server.c | 2389 +++++++++++ src/config_server.h | 83 + src/log_p.h | 6 + src/session.c | 38 +- src/session_client.c | 2 +- src/session_client_ssh.c | 2 +- src/session_p.h | 161 +- src/session_server_tls.c | 18 +- tests/CMakeLists.txt | 6 +- tests/client/test_client_ssh.c | 124 +- tests/config.h.in | 1 + tests/pam/pam_netconf.c | 6 +- tests/test_auth.c | 457 ++ tests/test_nc3.c | 243 ++ tests/test_pam.c | 193 - tests/test_two_channels.c | 282 ++ 40 files changed, 15759 insertions(+), 378 deletions(-) create mode 100644 modules/iana-crypt-hash.yang create mode 100644 modules/iana-ssh-encryption-algs@2022-06-16.yang create mode 100644 modules/iana-ssh-key-exchange-algs@2022-06-16.yang create mode 100644 modules/iana-ssh-mac-algs@2022-06-16.yang create mode 100644 modules/iana-ssh-public-key-algs@2022-06-16.yang create mode 100644 modules/iana-tls-cipher-suite-algs@2022-06-16.yang create mode 100644 modules/ietf-crypto-types@2022-07-07.yang create mode 100644 modules/ietf-keystore@2022-05-24.yang create mode 100644 modules/ietf-netconf-server@2022-05-24.yang create mode 100644 modules/ietf-ssh-common@2022-07-18.yang create mode 100644 modules/ietf-ssh-server@2022-07-18.yang create mode 100644 modules/ietf-tcp-client@2022-05-24.yang create mode 100644 modules/ietf-tcp-common@2022-05-24.yang create mode 100644 modules/ietf-tcp-server@2022-05-24.yang create mode 100644 modules/ietf-tls-common@2022-07-18.yang create mode 100644 modules/ietf-tls-server@2022-07-18.yang create mode 100644 modules/ietf-truststore@2022-05-24.yang create mode 100644 modules/ietf-x509-cert-to-name.yang create mode 100644 modules/libnetconf2-netconf-server.yang create mode 100644 src/config_server.c create mode 100644 src/config_server.h create mode 100644 tests/test_auth.c create mode 100644 tests/test_nc3.c delete mode 100644 tests/test_pam.c create mode 100644 tests/test_two_channels.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a29e96d..47405677 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,7 +111,8 @@ set(libsrc src/messages_server.c src/session.c src/session_client.c - src/session_server.c) + src/session_server.c + src/config_server.c) if(ENABLE_SSH) list(APPEND libsrc @@ -136,7 +137,8 @@ set(headers src/session_client.h src/session_client_ch.h src/session_server.h - src/session_server_ch.h) + src/session_server_ch.h + src/config_server.h) # files to generate doxygen from set(doxy_files diff --git a/examples/client.c b/examples/client.c index 38512b60..1ebf11c2 100644 --- a/examples/client.c +++ b/examples/client.c @@ -150,6 +150,7 @@ main(int argc, char **argv) } nc_client_init(); + /* set the path to search for schemas */ nc_client_set_schema_searchpath(MODULES_DIR); @@ -176,6 +177,7 @@ main(int argc, char **argv) case 'd': nc_verbosity(NC_VERB_DEBUG); + nc_libssh_thread_verbosity(2); break; default: diff --git a/examples/example.h.in b/examples/example.h.in index c003565f..5aa11f33 100644 --- a/examples/example.h.in +++ b/examples/example.h.in @@ -21,6 +21,9 @@ /* directory with library YANG modules */ #define MODULES_DIR "@CMAKE_SOURCE_DIR@/modules" +/* directory with examples source code and this header */ +#define EXAMPLES_DIR "@CMAKE_SOURCE_DIR@/examples" + /* SSH listening IP address */ #define SSH_ADDRESS "127.0.0.1" diff --git a/examples/server.c b/examples/server.c index 2a55c771..c0e7cc57 100644 --- a/examples/server.c +++ b/examples/server.c @@ -27,6 +27,7 @@ #include +#include "config_server.h" #include "log.h" #include "messages_server.h" #include "netconf.h" @@ -34,6 +35,7 @@ #include "session_server_ch.h" volatile int exit_application = 0; +struct lyd_node *tree; static void sigint_handler(int signum) @@ -52,6 +54,7 @@ get_rpc(struct lyd_node *rpc, struct nc_session *session) struct lyd_node *filter, *err; struct lyd_meta *m, *type = NULL, *select = NULL; struct ly_set *set = NULL; + LY_ERR ret; ctx = nc_session_get_ctx(session); @@ -62,7 +65,8 @@ get_rpc(struct lyd_node *rpc, struct nc_session *session) } /* search for the optional filter in the RPC */ - if (lyd_find_path(rpc, "filter", 0, &filter)) { + ret = lyd_find_path(rpc, "filter", 0, &filter); + if (ret && (ret != LY_ENOTFOUND)) { err = nc_err(ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP); goto error; } @@ -198,107 +202,48 @@ help_print() " -s, --ssh\t\tCreate a SSH server with the host SSH key located at .\n\n"); } -static int -hostkey_callback(const char *name, void *user_data, char **privkey_path, char **privkey_data, NC_SSH_KEY_TYPE *privkey_type) -{ - /* return only known hostkey */ - if (strcmp(name, "server_hostkey")) { - return 1; - } - - /* the hostkey is in a file */ - *privkey_path = strdup(user_data); - *privkey_data = NULL; - *privkey_type = NC_SSH_KEY_UNKNOWN; - - return 0; -} - -static int -password_callback(const struct nc_session *session, const char *password, void *user_data) -{ - (void) user_data; - const char *username; - - /* get username from the NETCONF session */ - username = nc_session_get_username(session); - - /* compare it with the defined username and password */ - if (strcmp(username, SSH_USERNAME) || strcmp(password, SSH_PASSWORD)) { - return 1; - } - - return 0; -} - static int init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_TRANSPORT_IMPL server_type) { - struct lys_module *module; int rc = 0; - const char *features[] = {"*", NULL}; + const char *config_file_path = EXAMPLES_DIR "/config.xml"; - /* initialize the server */ - if (nc_server_init()) { - ERR_MSG_CLEANUP("Error occurred while initializing the server.\n"); + if (path) { + /* if a path is supplied, then use it */ + config_file_path = path; } if (server_type == NC_TI_UNIX) { - /* add a new UNIX socket endpoint with an arbitrary name main_unix */ - if (nc_server_add_endpt("main_unix", NC_TI_UNIX)) { - ERR_MSG_CLEANUP("Couldn't add end point.\n"); - } - - /* set endpoint listening address to the path from the parameter */ - if (nc_server_endpt_set_address("main_unix", path)) { - ERR_MSG_CLEANUP("Couldn't set address of end point.\n"); - } - } else { - /* add a new SSH endpoint with an arbitrary name main_ssh */ - if (nc_server_add_endpt("main_ssh", NC_TI_LIBSSH)) { - ERR_MSG_CLEANUP("Couldn't add end point.\n"); - } - - /* set generic hostkey callback which will be used for retrieving all the hostkeys */ - nc_server_ssh_set_hostkey_clb(hostkey_callback, (void *)path, NULL); - - /* set 'password' SSH authentication callback */ - nc_server_ssh_set_passwd_auth_clb(password_callback, NULL, NULL); - - /* add a new hostkey called server_hostkey, whose data will be retrieved by the hostkey callback */ - nc_server_ssh_endpt_add_hostkey("main_ssh", "server_hostkey", -1); - - /* set endpoint listening address to the defined IP address */ - if (nc_server_endpt_set_address("main_ssh", SSH_ADDRESS)) { - ERR_MSG_CLEANUP("Couldn't set address of end point.\n"); - } + ERR_MSG_CLEANUP("Only support SSH for now.\n"); + } - /* set endpoint listening port to the defined one */ - if (nc_server_endpt_set_port("main_ssh", SSH_PORT)) { - ERR_MSG_CLEANUP("Couldn't set port of end point.\n"); - } + /* create a libyang context that will determine which YANG modules will be supported by the server */ + rc = ly_ctx_new(MODULES_DIR, 0, context); + if (rc) { + ERR_MSG_CLEANUP("Error while creating a new context.\n"); + } - /* allow only 'password' SSH authentication method for the endpoint */ - if (nc_server_ssh_endpt_set_auth_methods("main_ssh", NC_SSH_AUTH_PASSWORD)) { - ERR_MSG_CLEANUP("Couldn't set authentication methods of end point.\n"); - } + /* implement the base NETCONF modules */ + rc = nc_server_init_ctx(context); + if (rc) { + ERR_MSG_CLEANUP("Error while initializing context.\n"); } - /* create a libyang context that will determine which YANG modules will be supported by the server */ - if (ly_ctx_new(MODULES_DIR, 0, context)) { - ERR_MSG_CLEANUP("Couldn't create new libyang context.\n"); + /* load all required modules for configuration, so the configuration of the server can be done */ + rc = nc_server_config_load_modules(context); + if (rc) { + ERR_MSG_CLEANUP("Error loading modules required for configuration of the server.\n"); } - /* support and load the base NETCONF ietf-netconf module with all its features enabled */ - module = ly_ctx_load_module(*context, "ietf-netconf", NULL, features); - if (!module) { - ERR_MSG_CLEANUP("Couldn't load ietf-netconf module.\n"); + /* parse YANG data from a file, configure the server based on the parsed YANG configuration data */ + rc = nc_server_config_setup_path(*context, config_file_path); + if (rc) { + ERR_MSG_CLEANUP("Error setting the path to the configuration data.\n"); } - /* support get-schema RPC for the server to be able to send YANG modules */ - module = ly_ctx_load_module(*context, "ietf-netconf-monitoring", NULL, features); - if (!module) { - ERR_MSG_CLEANUP("Couldn't load ietf-netconf-monitoring module.\n"); + /* initialize the server */ + if (nc_server_init()) { + ERR_MSG_CLEANUP("Error occurred while initializing the server.\n"); } /* create a new poll session structure, which is used for polling RPCs sent by clients */ @@ -324,7 +269,7 @@ main(int argc, char **argv) struct ly_ctx *context = NULL; struct nc_session *session, *new_session; struct nc_pollsession *ps = NULL; - const char *unix_socket_path = NULL, *ssh_public_key_path = NULL; + const char *unix_socket_path = NULL, *config_file_path = NULL; struct option options[] = { {"help", no_argument, NULL, 'h'}, @@ -341,7 +286,7 @@ main(int argc, char **argv) opterr = 0; - while ((opt = getopt_long(argc, argv, "hu:s:d", options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, ":s:hu:d", options, NULL)) != -1) { switch (opt) { case 'h': help_print(); @@ -356,9 +301,10 @@ main(int argc, char **argv) break; case 's': - ssh_public_key_path = optarg; - if (init(&context, &ps, ssh_public_key_path, NC_TI_LIBSSH)) { + config_file_path = optarg; + if (init(&context, &ps, config_file_path, NC_TI_LIBSSH)) { ERR_MSG_CLEANUP("Failed to initialize a SSH server\n"); + goto cleanup; } printf("Using SSH!\n"); break; @@ -367,6 +313,18 @@ main(int argc, char **argv) nc_verbosity(NC_VERB_DEBUG); break; + case ':': + if (optopt == 's') { + if (init(&context, &ps, NULL, NC_TI_LIBSSH)) { + ERR_MSG_CLEANUP("Failed to initialize a SSH server\n"); + goto cleanup; + } + printf("Using SSH!\n"); + break; + } else { + ERR_MSG_CLEANUP("Invalid option or missing argument\n"); + } + default: ERR_MSG_CLEANUP("Invalid option or missing argument\n"); } @@ -440,6 +398,7 @@ main(int argc, char **argv) } nc_ps_free(ps); nc_server_destroy(); + lyd_free_all(tree); ly_ctx_destroy(context); return rc; } diff --git a/modules/iana-crypt-hash.yang b/modules/iana-crypt-hash.yang new file mode 100644 index 00000000..eaf6258c --- /dev/null +++ b/modules/iana-crypt-hash.yang @@ -0,0 +1,124 @@ +module iana-crypt-hash { + namespace "urn:ietf:params:xml:ns:yang:iana-crypt-hash"; + prefix ianach; + + organization "IANA"; + contact + " Internet Assigned Numbers Authority + + Postal: ICANN + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292 + + Tel: +1 310 823 9358 + E-Mail: iana&iana.org"; + description + "This YANG module defines a typedef for storing passwords + using a hash function, and features to indicate which hash + functions are supported by an implementation. + + The latest revision of this YANG module can be obtained from + the IANA web site. + + Requests for new values should be made to IANA via + email (iana&iana.org). + + Copyright (c) 2014 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + The initial version of this YANG module is part of RFC XXXX; + see the RFC itself for full legal notices."; + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2014-04-04 { + description + "Initial revision."; + reference + "RFC XXXX: A YANG Data Model for System Management"; + } + + typedef crypt-hash { + type string { + pattern + '$0$.*' + + '|$1$[a-zA-Z0-9./]{1,8}$[a-zA-Z0-9./]{22}' + + '|$5$(rounds=\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{43}' + + '|$6$(rounds=\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{86}'; + } + description + "The crypt-hash type is used to store passwords using + a hash function. The algorithms for applying the hash + function and encoding the result are implemented in + various UNIX systems as the function crypt(3). + + A value of this type matches one of the forms: + + $0$ + $$$ + $$$$ + + The '$0$' prefix signals that the value is clear text. When + such a value is received by the server, a hash value is + calculated, and the string '$$$' or + $$$$ is prepended to the result. This + value is stored in the configuration data store. + + If a value starting with '$$', where is not '0', is + received, the server knows that the value already represents a + hashed value, and stores it as is in the data store. + + When a server needs to verify a password given by a user, it + finds the stored password hash string for that user, extracts + the salt, and calculates the hash with the salt and given + password as input. If the calculated hash value is the same + as the stored value, the password given by the client is + accepted. + + This type defines the following hash functions: + + id | hash function | feature + ---+---------------+------------------- + 1 | MD5 | crypt-hash-md5 + 5 | SHA-256 | crypt-hash-sha-256 + 6 | SHA-512 | crypt-hash-sha-512 + + The server indicates support for the different hash functions + by advertising the corresponding feature."; + reference + "IEEE Std 1003.1-2008 - crypt() function + RFC 1321: The MD5 Message-Digest Algorithm + FIPS.180-3.2008: Secure Hash Standard"; + } + + feature crypt-hash-md5 { + description + "Indicates that the device supports the MD5 + hash function in 'crypt-hash' values"; + reference "RFC 1321: The MD5 Message-Digest Algorithm"; + } + + feature crypt-hash-sha-256 { + description + "Indicates that the device supports the SHA-256 + hash function in 'crypt-hash' values"; + reference "FIPS.180-3.2008: Secure Hash Standard"; + } + + feature crypt-hash-sha-512 { + description + "Indicates that the device supports the SHA-512 + hash function in 'crypt-hash' values"; + reference "FIPS.180-3.2008: Secure Hash Standard"; + } + +} diff --git a/modules/iana-ssh-encryption-algs@2022-06-16.yang b/modules/iana-ssh-encryption-algs@2022-06-16.yang new file mode 100644 index 00000000..fabfd96b --- /dev/null +++ b/modules/iana-ssh-encryption-algs@2022-06-16.yang @@ -0,0 +1,392 @@ +module iana-ssh-encryption-algs { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:iana-ssh-encryption-algs"; + prefix sshea; + + organization + "Internet Assigned Numbers Authority (IANA)"; + + contact + "Postal: ICANN + 12025 Waterfront Drive, Suite 300 + Los Angeles, CA 90094-2536 + United States of America + Tel: +1 310 301 5800 + Email: iana@iana.org"; + + description + "This module defines identities for the encryption algorithms + defined in the 'Encryption Algorithm Names' sub-registry of the + 'Secure Shell (SSH) Protocol Parameters' registry maintained + by IANA. + + Copyright (c) 2022 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + The initial version of this YANG module is part of RFC EEEE + (https://www.rfc-editor.org/info/rfcEEEE); see the RFC + itself for full legal notices."; + + revision 2022-06-16 { + description + "Updated to reflect contents of the encryption algorithms + registry on June 16, 2022."; + } + + revision 2021-06-01 { + description + "Initial version"; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + // Typedefs + + typedef encryption-algorithm-ref { + type identityref { + base "encryption-alg-base"; + } + description + "A reference to a SSH encryption algorithm identifier."; + } + + // Identities + + identity encryption-alg-base { + description + "Base identity used to identify encryption algorithms."; + } + + identity triple-des-cbc { // YANG IDs cannot begin with a number + base encryption-alg-base; + description + "3DES-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity blowfish-cbc { + base encryption-alg-base; + description + "BLOWFISH-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity twofish256-cbc { + base encryption-alg-base; + description + "TWOFISH256-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity twofish-cbc { + base encryption-alg-base; + description + "TWOFISH-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity twofish192-cbc { + base encryption-alg-base; + description + "TWOFISH192-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity twofish128-cbc { + base encryption-alg-base; + description + "TWOFISH128-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity aes256-cbc { + base encryption-alg-base; + description + "AES256-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity aes192-cbc { + base encryption-alg-base; + description + "AES192-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity aes128-cbc { + base encryption-alg-base; + description + "AES128-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity serpent256-cbc { + base encryption-alg-base; + description + "SERPENT256-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity serpent192-cbc { + base encryption-alg-base; + description + "SERPENT192-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity serpent128-cbc { + base encryption-alg-base; + description + "SERPENT128-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity arcfour { + base encryption-alg-base; + status obsolete; + description + "ARCFOUR"; + reference + "RFC 8758: + Deprecating RC4 in Secure Shell (SSH)"; + } + + identity idea-cbc { + base encryption-alg-base; + description + "IDEA-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity cast128-cbc { + base encryption-alg-base; + description + "CAST128-CBC"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity none { + base encryption-alg-base; + description + "NONE"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + identity des-cbc { + base encryption-alg-base; + status obsolete; + description + "DES-CBC"; + reference + "FIPS 46-3: + Data Encryption Standard (DES)"; + } + + identity arcfour128 { + base encryption-alg-base; + status obsolete; + description + "ARCFOUR128"; + reference + "RFC 8758: + Deprecating RC4 in Secure Shell (SSH)"; + } + + identity arcfour256 { + base encryption-alg-base; + status obsolete; + description + "ARCFOUR256"; + reference + "RFC 8758: + Deprecating RC4 in Secure Shell (SSH)"; + } + + identity aes128-ctr { + base encryption-alg-base; + description + "AES128-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity aes192-ctr { + base encryption-alg-base; + description + "AES192-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity aes256-ctr { + base encryption-alg-base; + description + "AES256-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity triple-des-ctr { // YANG IDs cannot begin with a number + base encryption-alg-base; + description + "3DES-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity blowfish-ctr { + base encryption-alg-base; + description + "BLOWFISH-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity twofish128-ctr { + base encryption-alg-base; + description + "TWOFISH128-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity twofish192-ctr { + base encryption-alg-base; + description + "TWOFISH192-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity twofish256-ctr { + base encryption-alg-base; + description + "TWOFISH256-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity serpent128-ctr { + base encryption-alg-base; + description + "SERPENT128-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity serpent192-ctr { + base encryption-alg-base; + description + "SERPENT192-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity serpent256-ctr { + base encryption-alg-base; + description + "SERPENT256-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity idea-ctr { + base encryption-alg-base; + description + "IDEA-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity cast128-ctr { + base encryption-alg-base; + description + "CAST128-CTR"; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption Modes"; + } + + identity aead-aes-128-gcm { + base encryption-alg-base; + description + "AEAD_AES_128_GCM"; + reference + "RFC 5647: + AES Galois Counter Mode for the + Secure Shell Transport Layer Protocol"; + } + + identity aead-aes-256-gcm { + base encryption-alg-base; + description + "AEAD_AES_256_GCM"; + reference + "RFC 5647: + AES Galois Counter Mode for the + Secure Shell Transport Layer Protocol"; + } + + // Protocol-accessible Nodes + + container supported-algorithms { + config false; + description + "A container for a list of encryption algorithms + supported by the server."; + leaf-list supported-algorithm { + type encryption-algorithm-ref; + description + "A encryption algorithm supported by the server."; + } + } + +} diff --git a/modules/iana-ssh-key-exchange-algs@2022-06-16.yang b/modules/iana-ssh-key-exchange-algs@2022-06-16.yang new file mode 100644 index 00000000..c4bab5b9 --- /dev/null +++ b/modules/iana-ssh-key-exchange-algs@2022-06-16.yang @@ -0,0 +1,2219 @@ +module iana-ssh-key-exchange-algs { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:iana-ssh-key-exchange-algs"; + prefix sshkea; + + organization + "Internet Assigned Numbers Authority (IANA)"; + + contact + "Postal: ICANN + 12025 Waterfront Drive, Suite 300 + Los Angeles, CA 90094-2536 + United States of America + Tel: +1 310 301 5800 + Email: iana@iana.org"; + + description + "This module defines identities for the key exchange algorithms + defined in the 'Key Exchange Method Names' sub-registry of the + 'Secure Shell (SSH) Protocol Parameters' registry maintained + by IANA. + + Copyright (c) 2022 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + The initial version of this YANG module is part of RFC EEEE + (https://www.rfc-editor.org/info/rfcEEEE); see the RFC + itself for full legal notices."; + + revision 2022-06-16 { + description + "Updated to reflect contents of the key exchange algorithms + registry on June 16, 2022."; + } + + revision 2021-06-01 { + description + "Initial version"; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + // Typedefs + + typedef key-exchange-algorithm-ref { + type identityref { + base "key-exchange-alg-base"; + } + description + "A reference to a SSH key exchange algorithm identifier."; + } + + // Identities + + identity key-exchange-alg-base { + description + "Base identity used to identify key exchange algorithms."; + } + + identity diffie-hellman-group-exchange-sha1 { + base key-exchange-alg-base; + description + "DIFFIE-HELLMAN-GROUP-EXCHANGE-SHA1"; + reference + "RFC 4419: + Diffie-Hellman Group Exchange for the + Secure Shell (SSH) Transport Layer Protocol"; + } + + identity diffie-hellman-group-exchange-sha256 { + base key-exchange-alg-base; + description + "DIFFIE-HELLMAN-GROUP-EXCHANGE-SHA256"; + reference + "RFC 4419: + Diffie-Hellman Group Exchange for the + Secure Shell (SSH) Transport Layer Protocol"; + } + + identity diffie-hellman-group1-sha1 { + base key-exchange-alg-base; + description + "DIFFIE-HELLMAN-GROUP1-SHA1"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity diffie-hellman-group14-sha1 { + base key-exchange-alg-base; + description + "DIFFIE-HELLMAN-GROUP14-SHA1"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity diffie-hellman-group14-sha256 { + base key-exchange-alg-base; + description + "DIFFIE-HELLMAN-GROUP14-SHA256"; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + identity diffie-hellman-group15-sha512 { + base key-exchange-alg-base; + description + "DIFFIE-HELLMAN-GROUP15-SHA512"; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + identity diffie-hellman-group16-sha512 { + base key-exchange-alg-base; + description + "DIFFIE-HELLMAN-GROUP16-SHA512"; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + identity diffie-hellman-group17-sha512 { + base key-exchange-alg-base; + description + "DIFFIE-HELLMAN-GROUP17-SHA512"; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + identity diffie-hellman-group18-sha512 { + base key-exchange-alg-base; + description + "DIFFIE-HELLMAN-GROUP18-SHA512"; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + identity ecdh-sha2-nistp256 { + base key-exchange-alg-base; + description + "ECDH-SHA2-NISTP256 (secp256r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdh-sha2-nistp384 { + base key-exchange-alg-base; + description + "ECDH-SHA2-NISTP384 (secp384r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdh-sha2-nistp521 { + base key-exchange-alg-base; + description + "ECDH-SHA2-NISTP521 (secp521r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdh-sha2-1.3.132.0.1 { + base key-exchange-alg-base; + description + "ECDH-SHA2-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdh-sha2-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + description + "ECDH-SHA2-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdh-sha2-1.3.132.0.33 { + base key-exchange-alg-base; + description + "ECDH-SHA2-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdh-sha2-1.3.132.0.26 { + base key-exchange-alg-base; + description + "ECDH-SHA2-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdh-sha2-1.3.132.0.27 { + base key-exchange-alg-base; + description + "ECDH-SHA2-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdh-sha2-1.3.132.0.16 { + base key-exchange-alg-base; + description + "ECDH-SHA2-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdh-sha2-1.3.132.0.36 { + base key-exchange-alg-base; + description + "ECDH-SHA2-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdh-sha2-1.3.132.0.37 { + base key-exchange-alg-base; + description + "ECDH-SHA2-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdh-sha2-1.3.132.0.38 { + base key-exchange-alg-base; + description + "ECDH-SHA2-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecmqv-sha2 { + base key-exchange-alg-base; + description + "ECMQV-SHA2"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity gss-group1-sha1-nistp256 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-nistp384 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-nistp521 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-1.3.132.0.1 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-1.3.132.0.33 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-1.3.132.0.26 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-1.3.132.0.27 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-1.3.132.0.16 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-1.3.132.0.36 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-1.3.132.0.37 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-1.3.132.0.38 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-curve25519-sha256 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group1-sha1-curve448-sha512 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP1-SHA1-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-nistp256 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-nistp384 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-nistp521 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-1.3.132.0.1 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-1.3.132.0.33 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-1.3.132.0.26 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-1.3.132.0.27 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-1.3.132.0.16 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + identity gss-group14-sha1-1.3.132.0.36 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-1.3.132.0.37 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-1.3.132.0.38 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-curve25519-sha256 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha1-curve448-sha512 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GROUP14-SHA1-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-nistp256 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-nistp384 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-nistp521 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-1.3.132.0.1 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-1.3.132.0.33 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-1.3.132.0.26 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-1.3.132.0.27 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-1.3.132.0.16 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-1.3.132.0.36 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-1.3.132.0.37 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-1.3.132.0.38 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-curve25519-sha256 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-gex-sha1-curve448-sha512 { + base key-exchange-alg-base; + status deprecated; + description + "GSS-GEX-SHA1-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity rsa1024-sha1 { + base key-exchange-alg-base; + status obsolete; + description + "RSA1024-SHA1"; + reference + "RFC 4432: + RSA Key Exchange for the Secure Shell (SSH) + Transport Layer Protocol"; + } + + identity rsa2048-sha256 { + base key-exchange-alg-base; + description + "RSA2048-SHA256"; + reference + "RFC 4432: + RSA Key Exchange for the Secure Shell (SSH) + Transport Layer Protocol"; + } + + identity ext-info-s { + base key-exchange-alg-base; + description + "EXT-INFO-S"; + reference + "RFC 8308: + Extension Negotiation in the Secure Shell (SSH) Protocol"; + } + + identity ext-info-c { + base key-exchange-alg-base; + description + "EXT-INFO-C"; + reference + "RFC 8308: + Extension Negotiation in the Secure Shell (SSH) Protocol"; + } + + identity gss-group14-sha256-nistp256 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-nistp384 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-nistp521 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-1.3.132.0.1 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-1.3.132.0.33 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-1.3.132.0.26 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-1.3.132.0.27 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-1.3.132.0.16 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-1.3.132.0.36 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-1.3.132.0.37 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-1.3.132.0.38 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-curve25519-sha256 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group14-sha256-curve448-sha512 { + base key-exchange-alg-base; + description + "GSS-GROUP14-SHA256-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-nistp256 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-nistp384 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-nistp521 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-1.3.132.0.1 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-1.3.132.0.33 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-1.3.132.0.26 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-1.3.132.0.27 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-1.3.132.0.16 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-1.3.132.0.36 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-1.3.132.0.37 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-1.3.132.0.38 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-curve25519-sha256 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group15-sha512-curve448-sha512 { + base key-exchange-alg-base; + description + "GSS-GROUP15-SHA512-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-nistp256 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-nistp384 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-nistp521 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-1.3.132.0.1 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-1.3.132.0.33 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-1.3.132.0.26 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-1.3.132.0.27 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-1.3.132.0.16 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-1.3.132.0.36 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-1.3.132.0.37 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-1.3.132.0.38 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-curve25519-sha256 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group16-sha512-curve448-sha512 { + base key-exchange-alg-base; + description + "GSS-GROUP16-SHA512-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-nistp256 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-nistp384 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-nistp521 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-1.3.132.0.1 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-1.3.132.0.33 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-1.3.132.0.26 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-1.3.132.0.27 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-1.3.132.0.16 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-1.3.132.0.36 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-1.3.132.0.37 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-1.3.132.0.38 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-curve25519-sha256 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group17-sha512-curve448-sha512 { + base key-exchange-alg-base; + description + "GSS-GROUP17-SHA512-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-nistp256 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-nistp384 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-nistp521 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-1.3.132.0.1 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-1.3.132.0.33 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-1.3.132.0.26 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-1.3.132.0.27 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-1.3.132.0.16 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-1.3.132.0.36 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-1.3.132.0.37 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-1.3.132.0.38 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-curve25519-sha256 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-group18-sha512-curve448-sha512 { + base key-exchange-alg-base; + description + "GSS-GROUP18-SHA512-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-nistp256 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-nistp384 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-nistp521 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-1.3.132.0.1 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-1.3.132.0.33 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-1.3.132.0.26 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-1.3.132.0.27 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-1.3.132.0.16 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-1.3.132.0.36 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-1.3.132.0.37 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-1.3.132.0.38 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-curve25519-sha256 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp256-sha256-curve448-sha512 { + base key-exchange-alg-base; + description + "GSS-NISTP256-SHA256-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-nistp256 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-nistp384 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-nistp521 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-1.3.132.0.1 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-1.3.132.0.33 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-1.3.132.0.26 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-1.3.132.0.27 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-1.3.132.0.16 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-1.3.132.0.36 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-1.3.132.0.37 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-1.3.132.0.38 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-curve25519-sha256 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp384-sha384-curve448-sha512 { + base key-exchange-alg-base; + description + "GSS-NISTP384-SHA384-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-nistp256 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-nistp384 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-nistp521 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-1.3.132.0.1 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-1.3.132.0.33 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-1.3.132.0.26 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-1.3.132.0.27 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-1.3.132.0.16 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-1.3.132.0.36 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-1.3.132.0.37 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-1.3.132.0.38 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-curve25519-sha256 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-nistp521-sha512-curve448-sha512 { + base key-exchange-alg-base; + description + "GSS-NISTP521-SHA512-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-nistp256 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-nistp384 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-nistp521 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-1.3.132.0.1 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-1.2.840.10045.3.1.1 (nistp192, + secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-1.3.132.0.33 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-1.3.132.0.26 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-1.3.132.0.27 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-1.3.132.0.16 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-1.3.132.0.36 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-1.3.132.0.37 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-1.3.132.0.38 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + identity gss-curve25519-sha256-curve25519-sha256 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve25519-sha256-curve448-sha512 { + base key-exchange-alg-base; + description + "GSS-CURVE25519-SHA256-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-nistp256 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-NISTP256 (secp256r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-nistp384 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-NISTP384 (secp384r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-nistp521 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-NISTP521 (secp521r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-1.3.132.0.1 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-1.2.840.10045.3.1.1 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-1.3.132.0.33 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-1.3.132.0.26 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-1.3.132.0.27 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-1.3.132.0.16 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-1.3.132.0.36 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-1.3.132.0.37 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-1.3.132.0.38 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-curve25519-sha256 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-CURVE25519-SHA256"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity gss-curve448-sha512-curve448-sha512 { + base key-exchange-alg-base; + description + "GSS-CURVE448-SHA512-CURVE448-SHA512"; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + identity curve25519-sha256 { + base key-exchange-alg-base; + description + "CURVE25519-SHA256"; + reference + "RFC 8731: + Secure Shell (SSH) Key Exchange Method + Using Curve25519 and Curve448"; + } + + identity curve448-sha512 { + base key-exchange-alg-base; + description + "CURVE448-SHA512"; + reference + "RFC 8731: + Secure Shell (SSH) Key Exchange Method + Using Curve25519 and Curve448"; + } + + // Protocol-accessible Nodes + + container supported-algorithms { + config false; + description + "A container for a list of key exchange algorithms + supported by the server."; + leaf-list supported-algorithm { + type key-exchange-algorithm-ref; + description + "A key exchange algorithm supported by the server."; + } + } + +} diff --git a/modules/iana-ssh-mac-algs@2022-06-16.yang b/modules/iana-ssh-mac-algs@2022-06-16.yang new file mode 100644 index 00000000..c2574007 --- /dev/null +++ b/modules/iana-ssh-mac-algs@2022-06-16.yang @@ -0,0 +1,167 @@ +module iana-ssh-mac-algs { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:iana-ssh-mac-algs"; + prefix sshma; + + organization + "Internet Assigned Numbers Authority (IANA)"; + + contact + "Postal: ICANN + 12025 Waterfront Drive, Suite 300 + Los Angeles, CA 90094-2536 + United States of America + Tel: +1 310 301 5800 + Email: iana@iana.org"; + + description + "This module defines identities for the MAC algorithms + defined in the 'MAC Algorithm Names' sub-registry of the + 'Secure Shell (SSH) Protocol Parameters' registry maintained + by IANA. + + Copyright (c) 2022 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + The initial version of this YANG module is part of RFC EEEE + (https://www.rfc-editor.org/info/rfcEEEE); see the RFC + itself for full legal notices."; + + revision 2022-06-16 { + description + "Updated to reflect contents of the MAC algorithms + registry on June 16, 2022."; + } + + revision 2021-06-01 { + description + "Initial version"; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + // Typedefs + + typedef mac-algorithm-ref { + type identityref { + base "mac-alg-base"; + } + description + "A reference to a SSH mac algorithm identifier."; + } + + // Identities + + identity mac-alg-base { + description + "Base identity used to identify message authentication + code (MAC) algorithms."; + } + + identity hmac-sha1 { + base mac-alg-base; + description + "HMAC-SHA1"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity hmac-sha1-96 { + base mac-alg-base; + description + "HMAC-SHA1-96"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity hmac-md5 { + base mac-alg-base; + description + "HMAC-MD5"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity hmac-md5-96 { + base mac-alg-base; + description + "HMAC-MD5-96"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity none { + base mac-alg-base; + description + "NONE"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity aead-aes-128-gcm { + base mac-alg-base; + description + "AEAD_AES_128_GCM"; + reference + "RFC 5647: + AES Galois Counter Mode for the + Secure Shell Transport Layer Protocol"; + } + + identity aead-aes-256-gcm { + base mac-alg-base; + description + "AEAD_AES_256_GCM"; + reference + "RFC 5647: + AES Galois Counter Mode for the + Secure Shell Transport Layer Protocol"; + } + + identity hmac-sha2-256 { + base mac-alg-base; + description + "HMAC-SHA2-256"; + reference + "RFC 6668: + SHA-2 Data Integrity Verification for the + Secure Shell (SSH) Transport Layer Protocol"; + } + + identity hmac-sha2-512 { + base mac-alg-base; + description + "HMAC-SHA2-512"; + reference + "RFC 6668: + SHA-2 Data Integrity Verification for the + Secure Shell (SSH) Transport Layer Protocol"; + } + + // Protocol-accessible Nodes + + container supported-algorithms { + config false; + description + "A container for a list of MAC algorithms + supported by the server."; + leaf-list supported-algorithm { + type mac-algorithm-ref; + description + "A MAC algorithm supported by the server."; + } + } + +} diff --git a/modules/iana-ssh-public-key-algs@2022-06-16.yang b/modules/iana-ssh-public-key-algs@2022-06-16.yang new file mode 100644 index 00000000..647a7edb --- /dev/null +++ b/modules/iana-ssh-public-key-algs@2022-06-16.yang @@ -0,0 +1,441 @@ +module iana-ssh-public-key-algs { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:iana-ssh-public-key-algs"; + prefix sshpka; + + organization + "Internet Assigned Numbers Authority (IANA)"; + + contact + "Postal: ICANN + 12025 Waterfront Drive, Suite 300 + Los Angeles, CA 90094-2536 + United States of America + Tel: +1 310 301 5800 + Email: iana@iana.org"; + + description + "This module defines identities for the public key algorithms + defined in the 'Public Key Algorithm Names' sub-registry of the + 'Secure Shell (SSH) Protocol Parameters' registry maintained + by IANA. + + Copyright (c) 2022 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + The initial version of this YANG module is part of RFC EEEE + (https://www.rfc-editor.org/info/rfcEEEE); see the RFC + itself for full legal notices."; + + revision 2022-06-16 { + description + "Updated to reflect contents of the public key algorithms + registry on June 16, 2022."; + } + + revision 2021-06-01 { + description + "Initial version"; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + // Typedefs + + typedef public-key-algorithm-ref { + type identityref { + base "public-key-alg-base"; + } + description + "A reference to a SSH public key algorithm identifier."; + } + + // Identities + + identity public-key-alg-base { + description + "Base identity used to identify public key algorithms."; + } + + identity ssh-dss { + base public-key-alg-base; + description + "SSH-DSS"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity ssh-rsa { + base public-key-alg-base; + description + "SSH-RSA"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity rsa-sha2-256 { + base public-key-alg-base; + description + "RSA-SHA2-256"; + reference + "RFC 8332: + Use of RSA Keys with SHA-256 and SHA-512 + in the Secure Shell (SSH) Protocol"; + } + + identity rsa-sha2-512 { + base public-key-alg-base; + description + "RSA-SHA2-512"; + reference + "RFC 8332: + Use of RSA Keys with SHA-256 and SHA-512 + in the Secure Shell (SSH) Protocol"; + } + + identity spki-sign-rsa { + base public-key-alg-base; + description + "SPKI-SIGN-RSA"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity spki-sign-dss { + base public-key-alg-base; + description + "SPKI-SIGN-DSS"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity pgp-sign-rsa { + base public-key-alg-base; + description + "PGP-SIGN-RSA"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity pgp-sign-dss { + base public-key-alg-base; + description + "PGP-SIGN-DSS"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity null { + base public-key-alg-base; + description + "NULL"; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol"; + } + + identity ecdsa-sha2-nistp256 { + base public-key-alg-base; + description + "ECDSA-SHA2-NISTP256 (secp256r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdsa-sha2-nistp384 { + base public-key-alg-base; + description + "ECDSA-SHA2-NISTP384 (secp384r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdsa-sha2-nistp521 { + base public-key-alg-base; + description + "ECDSA-SHA2-NISTP521 (secp521r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdsa-sha2-1.3.132.0.1 { + base public-key-alg-base; + description + "ECDSA-SHA2-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdsa-sha2-1.2.840.10045.3.1.1 { + base public-key-alg-base; + description + "ECDSA-SHA2-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdsa-sha2-1.3.132.0.33 { + base public-key-alg-base; + description + "ECDSA-SHA2-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdsa-sha2-1.3.132.0.26 { + base public-key-alg-base; + description + "ECDSA-SHA2-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdsa-sha2-1.3.132.0.27 { + base public-key-alg-base; + description + "ECDSA-SHA2-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdsa-sha2-1.3.132.0.16 { + base public-key-alg-base; + description + "ECDSA-SHA2-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdsa-sha2-1.3.132.0.36 { + base public-key-alg-base; + description + "ECDSA-SHA2-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdsa-sha2-1.3.132.0.37 { + base public-key-alg-base; + description + "ECDSA-SHA2-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity ecdsa-sha2-1.3.132.0.38 { + base public-key-alg-base; + description + "ECDSA-SHA2-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer"; + } + + identity x509v3-ssh-dss { + base public-key-alg-base; + description + "X509V3-SSH-DSS"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ssh-rsa { + base public-key-alg-base; + description + "X509V3-SSH-RSA"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-rsa2048-sha256 { + base public-key-alg-base; + description + "X509V3-RSA2048-SHA256"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-nistp256 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-NISTP256 (secp256r1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-nistp384 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-NISTP384 (secp384r1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-nistp521 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-NISTP521 (secp521r1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-1.3.132.0.1 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-1.3.132.0.1 (nistk163, sect163k1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-1.2.840.10045.3.1.1 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-1.2.840.10045.3.1.1 (nistp192, secp192r1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-1.3.132.0.33 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-1.3.132.0.33 (nistp224, secp224r1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-1.3.132.0.26 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-1.3.132.0.26 (nistk233, sect233k1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-1.3.132.0.27 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-1.3.132.0.27 (nistb233, sect233r1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-1.3.132.0.16 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-1.3.132.0.16 (nistk283, sect283k1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-1.3.132.0.36 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-1.3.132.0.36 (nistk409, sect409k1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-1.3.132.0.37 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-1.3.132.0.37 (nistb409, sect409r1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity x509v3-ecdsa-sha2-1.3.132.0.38 { + base public-key-alg-base; + description + "X509V3-ECDSA-SHA2-1.3.132.0.38 (nistt571, sect571k1)"; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + identity ssh-ed25519 { + base public-key-alg-base; + description + "SSH-ED25519"; + reference + "RFC 8709: + Ed25519 and Ed448 Public Key Algorithms for the + Secure Shell (SSH) Protocol"; + } + + identity ssh-ed448 { + base public-key-alg-base; + description + "SSH-ED448"; + reference + "RFC 8709: + Ed25519 and Ed448 Public Key Algorithms for the + Secure Shell (SSH) Protocol"; + } + + // Protocol-accessible Nodes + + container supported-algorithms { + config false; + description + "A container for a list of public key algorithms + supported by the server."; + leaf-list supported-algorithm { + type public-key-algorithm-ref; + description + "A public key algorithm supported by the server."; + } + } + +} diff --git a/modules/iana-tls-cipher-suite-algs@2022-06-16.yang b/modules/iana-tls-cipher-suite-algs@2022-06-16.yang new file mode 100644 index 00000000..78d310d4 --- /dev/null +++ b/modules/iana-tls-cipher-suite-algs@2022-06-16.yang @@ -0,0 +1,3778 @@ +module iana-tls-cipher-suite-algs { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:iana-tls-cipher-suite-algs"; + prefix tlscsa; + + organization + "Internet Assigned Numbers Authority (IANA)"; + + contact + "Postal: ICANN + 12025 Waterfront Drive, Suite 300 + Los Angeles, CA 90094-2536 + United States of America + Tel: +1 310 301 5800 + Email: iana@iana.org"; + + description + "This module defines identities for the Cipher Suite + algorithms defined in the 'TLS Cipher Suites' sub-registry + of the 'Transport Layer Security (TLS) Parameters' registry + maintained by IANA. + + Copyright (c) 2022 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + The initial version of this YANG module is part of RFC FFFF + (https://www.rfc-editor.org/info/rfcFFFF); see the RFC + itself for full legal notices."; + + revision 2022-06-16 { + description + "Updated to reflect contents of the public key algorithms + registry on June 16, 2022."; + } + + revision 2021-06-02 { + description + "Initial version"; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + // Typedefs + + typedef cipher-suite-algorithm-ref { + type identityref { + base "cipher-suite-alg-base"; + } + description + "A reference to a TLS cipher suite algorithm identifier."; + } + // Identities + + identity cipher-suite-alg-base { + description + "Base identity used to identify TLS cipher suites."; + } + + identity tls-null-with-null-null { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-NULL-WITH-NULL-NULL"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-rsa-with-null-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-NULL-MD5"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-rsa-with-null-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-NULL-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-rsa-export-with-rc4-40-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-EXPORT-WITH-RC4-40-MD5"; + reference + "RFC 4346: + The TLS Protocol Version 1.1 + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + identity tls-rsa-with-rc4-128-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-RC4-128-MD5"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2 + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-rsa-with-rc4-128-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-RC4-128-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2 + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-rsa-export-with-rc2-cbc-40-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-EXPORT-WITH-RC2-CBC-40-MD5"; + reference + "RFC 4346: + The TLS Protocol Version 1.1"; + } + + identity tls-rsa-with-idea-cbc-sha { + base cipher-suite-alg-base; + status obsolete; + description + "TLS-RSA-WITH-IDEA-CBC-SHA"; + reference + "RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS) + RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-rsa-export-with-des40-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-EXPORT-WITH-DES40-CBC-SHA"; + reference + "RFC 4346: + The TLS Protocol Version 1.1"; + } + + identity tls-rsa-with-des-cbc-sha { + base cipher-suite-alg-base; + status obsolete; + description + "TLS-RSA-WITH-DES-CBC-SHA"; + reference + "RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS) + RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-rsa-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-dss-export-with-des40-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-EXPORT-WITH-DES40-CBC-SHA"; + reference + "RFC 4346: + The TLS Protocol Version 1.1"; + } + + identity tls-dh-dss-with-des-cbc-sha { + base cipher-suite-alg-base; + status obsolete; + description + "TLS-DH-DSS-WITH-DES-CBC-SHA"; + reference + "RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS) + RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-dh-dss-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-rsa-export-with-des40-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-EXPORT-WITH-DES40-CBC-SHA"; + reference + "RFC 4346: + The TLS Protocol Version 1.1"; + } + + identity tls-dh-rsa-with-des-cbc-sha { + base cipher-suite-alg-base; + status obsolete; + description + "TLS-DH-RSA-WITH-DES-CBC-SHA"; + reference + "RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS) + RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-dh-rsa-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dhe-dss-export-with-des40-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-EXPORT-WITH-DES40-CBC-SHA"; + reference + "RFC 4346: + The TLS Protocol Version 1.1"; + } + + identity tls-dhe-dss-with-des-cbc-sha { + base cipher-suite-alg-base; + status obsolete; + description + "TLS-DHE-DSS-WITH-DES-CBC-SHA"; + reference + "RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS) + RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-dhe-dss-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dhe-rsa-export-with-des40-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-EXPORT-WITH-DES40-CBC-SHA"; + reference + "RFC 4346: + The TLS Protocol Version 1.1"; + } + + identity tls-dhe-rsa-with-des-cbc-sha { + base cipher-suite-alg-base; + status obsolete; + description + "TLS-DHE-RSA-WITH-DES-CBC-SHA"; + reference + "RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS) + RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-dhe-rsa-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-anon-export-with-rc4-40-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-EXPORT-WITH-RC4-40-MD5"; + reference + "RFC 4346: + The TLS Protocol Version 1.1 + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-dh-anon-with-rc4-128-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-RC4-128-MD5"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2 + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-dh-anon-export-with-des40-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-EXPORT-WITH-DES40-CBC-SHA"; + reference + "RFC 4346: + The TLS Protocol Version 1.1"; + } + + identity tls-dh-anon-with-des-cbc-sha { + base cipher-suite-alg-base; + status obsolete; + description + "TLS-DH-ANON-WITH-DES-CBC-SHA"; + reference + "RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS) + RFC 5469: + DES and IDEA Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-dh-anon-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-krb5-with-des-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-WITH-DES-CBC-SHA"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-krb5-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-krb5-with-rc4-128-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-WITH-RC4-128-SHA"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS) + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-krb5-with-idea-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-WITH-IDEA-CBC-SHA"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-krb5-with-des-cbc-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-WITH-DES-CBC-MD5"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-krb5-with-3des-ede-cbc-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-WITH-3DES-EDE-CBC-MD5"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-krb5-with-rc4-128-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-WITH-RC4-128-MD5"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS) + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-krb5-with-idea-cbc-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-WITH-IDEA-CBC-MD5"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-krb5-export-with-des-cbc-40-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-EXPORT-WITH-DES-CBC-40-SHA"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-krb5-export-with-rc2-cbc-40-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-EXPORT-WITH-RC2-CBC-40-SHA"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-krb5-export-with-rc4-40-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-EXPORT-WITH-RC4-40-SHA"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS) + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-krb5-export-with-des-cbc-40-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-EXPORT-WITH-DES-CBC-40-MD5"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-krb5-export-with-rc2-cbc-40-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-EXPORT-WITH-RC2-CBC-40-MD5"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-krb5-export-with-rc4-40-md5 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-KRB5-EXPORT-WITH-RC4-40-MD5"; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to + Transport Layer Security (TLS) + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-psk-with-null-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-NULL-SHA"; + reference + "RFC 4785: + Pre-Shared Key Cipher Suites with NULL Encryption for + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-null-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-NULL-SHA"; + reference + "RFC 4785: + Pre-Shared Key Cipher Suites with NULL Encryption for + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-null-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-NULL-SHA"; + reference + "RFC 4785: + Pre-Shared Key Cipher Suites with NULL Encryption for + Transport Layer Security (TLS)"; + } + + identity tls-rsa-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-AES-128-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + identity tls-dh-dss-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-AES-128-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-rsa-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-AES-128-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dhe-dss-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dhe-rsa-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-anon-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-AES-128-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-rsa-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-AES-256-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-dss-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-AES-256-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-rsa-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-AES-256-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dhe-dss-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dhe-rsa-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-anon-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-AES-256-CBC-SHA"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-rsa-with-null-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-NULL-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-rsa-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-rsa-with-aes-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-AES-256-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-dss-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-rsa-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dhe-dss-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-rsa-with-camellia-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-dss-with-camellia-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-CAMELLIA-128-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-rsa-with-camellia-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-CAMELLIA-128-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dhe-dss-with-camellia-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dhe-rsa-with-camellia-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-anon-with-camellia-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-CAMELLIA-128-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dhe-rsa-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-dss-with-aes-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-AES-256-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-rsa-with-aes-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-AES-256-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dhe-dss-with-aes-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dhe-rsa-with-aes-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-anon-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-dh-anon-with-aes-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-AES-256-CBC-SHA256"; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2"; + } + + identity tls-rsa-with-camellia-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-dss-with-camellia-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-CAMELLIA-256-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-rsa-with-camellia-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-CAMELLIA-256-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dhe-dss-with-camellia-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dhe-rsa-with-camellia-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-anon-with-camellia-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-CAMELLIA-256-CBC-SHA"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-psk-with-rc4-128-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-RC4-128-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS) + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-psk-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-psk-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-AES-128-CBC-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-psk-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-AES-256-CBC-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-rc4-128-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-RC4-128-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS) + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-dhe-psk-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-AES-128-CBC-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-AES-256-CBC-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-rc4-128-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-RC4-128-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS) + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-rsa-psk-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-AES-128-CBC-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-AES-256-CBC-SHA"; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-rsa-with-seed-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-SEED-CBC-SHA"; + reference + "RFC 4162: + Addition of SEED Ciphersuites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-dss-with-seed-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-SEED-CBC-SHA"; + reference + "RFC 4162: + Addition of SEED Ciphersuites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-rsa-with-seed-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-SEED-CBC-SHA"; + reference + "RFC 4162: + Addition of SEED Ciphersuites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-dss-with-seed-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-SEED-CBC-SHA"; + reference + "RFC 4162: + Addition of SEED Ciphersuites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-rsa-with-seed-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-SEED-CBC-SHA"; + reference + "RFC 4162: + Addition of SEED Ciphersuites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-anon-with-seed-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-SEED-CBC-SHA"; + reference + "RFC 4162: + Addition of SEED Ciphersuites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-rsa-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-dhe-rsa-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + description + "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-dhe-rsa-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + description + "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-dh-rsa-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-dh-rsa-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-dhe-dss-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-dhe-dss-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-dh-dss-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-dh-dss-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-dh-anon-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-dh-anon-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5288: + AES-GCM Cipher Suites for TLS"; + } + + identity tls-psk-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-psk-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-dhe-psk-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + description + "TLS-DHE-PSK-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-dhe-psk-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + description + "TLS-DHE-PSK-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-rsa-psk-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-rsa-psk-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-psk-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-psk-with-aes-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-AES-256-CBC-SHA384"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-psk-with-null-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-NULL-SHA256"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-psk-with-null-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-NULL-SHA384"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-dhe-psk-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-dhe-psk-with-aes-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-AES-256-CBC-SHA384"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-dhe-psk-with-null-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-NULL-SHA256"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-dhe-psk-with-null-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-NULL-SHA384"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-rsa-psk-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-rsa-psk-with-aes-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-AES-256-CBC-SHA384"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-rsa-psk-with-null-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-NULL-SHA256"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-rsa-psk-with-null-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-NULL-SHA384"; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for Transport Layer Security + (TLS) with SHA-256/384 and AES Galois Counter Mode"; + } + + identity tls-rsa-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-dss-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-rsa-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dhe-dss-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dhe-rsa-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-anon-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-rsa-with-camellia-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-dss-with-camellia-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-CAMELLIA-256-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-rsa-with-camellia-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-CAMELLIA-256-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dhe-dss-with-camellia-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dhe-rsa-with-camellia-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-dh-anon-with-camellia-256-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-CAMELLIA-256-CBC-SHA256"; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + + identity tls-sm4-gcm-sm3 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SM4-GCM-SM3"; + reference + "RFC 8998: + ShangMi (SM) Cipher Suites for Transport Layer Security + (TLS) Protocol Version 1.3"; + } + identity tls-sm4-ccm-sm3 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SM4-CCM-SM3"; + reference + "RFC 8998: + ShangMi (SM) Cipher Suites for Transport Layer Security + (TLS) Protocol Version 1.3"; + } + + identity tls-empty-renegotiation-info-scsv { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-EMPTY-RENEGOTIATION-INFO-SCSV"; + reference + "RFC 5746: + Transport Layer Security (TLS) + Renegotiation Indication Extension"; + } + + identity tls-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + description + "TLS-AES-128-GCM-SHA256"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity tls-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + description + "TLS-AES-256-GCM-SHA384"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity tls-chacha20-poly1305-sha256 { + base cipher-suite-alg-base; + description + "TLS-CHACHA20-POLY1305-SHA256"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + identity tls-aes-128-ccm-sha256 { + base cipher-suite-alg-base; + description + "TLS-AES-128-CCM-SHA256"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity tls-aes-128-ccm-8-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-AES-128-CCM-8-SHA256"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity tls-fallback-scsv { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-FALLBACK-SCSV"; + reference + "RFC 7507: + TLS Fallback Signaling Cipher Suite Value (SCSV) + for Preventing Protocol Downgrade Attacks"; + } + + identity tls-ecdh-ecdsa-with-null-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-NULL-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdh-ecdsa-with-rc4-128-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-RC4-128-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-ecdh-ecdsa-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdh-ecdsa-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdh-ecdsa-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdhe-ecdsa-with-null-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-NULL-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdhe-ecdsa-with-rc4-128-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-RC4-128-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-ecdhe-ecdsa-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdhe-ecdsa-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdhe-ecdsa-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdh-rsa-with-null-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-NULL-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdh-rsa-with-rc4-128-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-RC4-128-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-ecdh-rsa-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdh-rsa-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdh-rsa-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdhe-rsa-with-null-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-NULL-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdhe-rsa-with-rc4-128-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-RC4-128-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-ecdhe-rsa-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdhe-rsa-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdhe-rsa-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdh-anon-with-null-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ANON-WITH-NULL-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdh-anon-with-rc4-128-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ANON-WITH-RC4-128-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-ecdh-anon-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ANON-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdh-anon-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ANON-WITH-AES-128-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-ecdh-anon-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ANON-WITH-AES-256-CBC-SHA"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity tls-srp-sha-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SRP-SHA-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 5054: + Using SRP for TLS Authentication"; + } + + identity tls-srp-sha-rsa-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SRP-SHA-RSA-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 5054: + Using SRP for TLS Authentication"; + } + + identity tls-srp-sha-dss-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SRP-SHA-DSS-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 5054: + Using SRP for TLS Authentication"; + } + + identity tls-srp-sha-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SRP-SHA-WITH-AES-128-CBC-SHA"; + reference + "RFC 5054: + Using SRP for TLS Authentication"; + } + + identity tls-srp-sha-rsa-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SRP-SHA-RSA-WITH-AES-128-CBC-SHA"; + reference + "RFC 5054: + Using SRP for TLS Authentication"; + } + + identity tls-srp-sha-dss-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SRP-SHA-DSS-WITH-AES-128-CBC-SHA"; + reference + "RFC 5054: + Using SRP for TLS Authentication"; + } + + identity tls-srp-sha-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SRP-SHA-WITH-AES-256-CBC-SHA"; + reference + "RFC 5054: + Using SRP for TLS Authentication"; + } + identity tls-srp-sha-rsa-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SRP-SHA-RSA-WITH-AES-256-CBC-SHA"; + reference + "RFC 5054: + Using SRP for TLS Authentication"; + } + + identity tls-srp-sha-dss-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SRP-SHA-DSS-WITH-AES-256-CBC-SHA"; + reference + "RFC 5054: + Using SRP for TLS Authentication"; + } + + identity tls-ecdhe-ecdsa-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdhe-ecdsa-with-aes-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdh-ecdsa-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdh-ecdsa-with-aes-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA384"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdhe-rsa-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdhe-rsa-with-aes-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdh-rsa-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + identity tls-ecdh-rsa-with-aes-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdhe-ecdsa-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + description + "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdhe-ecdsa-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + description + "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdh-ecdsa-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdh-ecdsa-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdhe-rsa-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + description + "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdhe-rsa-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + description + "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdh-rsa-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-AES-128-GCM-SHA256"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdh-rsa-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-AES-256-GCM-SHA384"; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 + and AES Galois Counter Mode"; + } + + identity tls-ecdhe-psk-with-rc4-128-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-RC4-128-SHA"; + reference + "RFC 5489: + ECDHE_PSK Ciphersuites for Transport Layer Security (TLS) + RFC 6347: + Datagram Transport Layer Security version 1.2"; + } + + identity tls-ecdhe-psk-with-3des-ede-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-3DES-EDE-CBC-SHA"; + reference + "RFC 5489: + ECDHE_PSK Ciphersuites for Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-aes-128-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA"; + reference + "RFC 5489: + ECDHE_PSK Ciphersuites for Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-aes-256-cbc-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA"; + reference + "RFC 5489: + ECDHE_PSK Ciphersuites for Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-aes-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256"; + reference + "RFC 5489: + ECDHE_PSK Ciphersuites for Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-aes-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA384"; + reference + "RFC 5489: + ECDHE_PSK Ciphersuites for Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-null-sha { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-NULL-SHA"; + reference + "RFC 5489: + ECDHE_PSK Ciphersuites for Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-null-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-NULL-SHA256"; + reference + "RFC 5489: + ECDHE_PSK Ciphersuites for Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-null-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-NULL-SHA384"; + reference + "RFC 5489: + ECDHE_PSK Ciphersuites for Transport Layer Security (TLS)"; + } + + identity tls-rsa-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-dss-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-dss-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-rsa-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-rsa-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-dss-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-dss-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-rsa-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-rsa-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-anon-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-anon-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-ecdsa-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-ecdsa-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-ecdsa-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-ecdsa-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-rsa-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-rsa-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + identity tls-ecdh-rsa-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-rsa-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-rsa-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-rsa-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-rsa-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-rsa-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-dss-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-dss-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-dss-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-dss-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-anon-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-anon-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-ecdsa-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-ecdsa-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-ecdsa-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-ecdsa-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-rsa-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-rsa-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-rsa-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-rsa-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-psk-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-psk-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-psk-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-psk-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-aria-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-ARIA-128-GCM-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-aria-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-ARIA-256-GCM-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-aria-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-ARIA-128-CBC-SHA256"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + identity tls-ecdhe-psk-with-aria-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-ARIA-256-CBC-SHA384"; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-ecdsa-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-ecdsa-with-camellia-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-ecdsa-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-ecdsa-with-camellia-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-rsa-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-rsa-with-camellia-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-rsa-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-rsa-with-camellia-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-CAMELLIA-256-CBC-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-rsa-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-rsa-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-rsa-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-rsa-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-RSA-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-dss-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-dss-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-DSS-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-dss-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-dss-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-DSS-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-anon-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dh-anon-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DH-ANON-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-ecdsa-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-ecdsa-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-ecdsa-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-ecdsa-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-rsa-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-rsa-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-RSA-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-rsa-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdh-rsa-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDH-RSA-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-psk-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-psk-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-camellia-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-CAMELLIA-128-GCM-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-camellia-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-CAMELLIA-256-GCM-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + identity tls-psk-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-psk-with-camellia-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-CAMELLIA-256-CBC-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-camellia-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-PSK-WITH-CAMELLIA-256-CBC-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-camellia-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-CAMELLIA-256-CBC-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-camellia-128-cbc-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-CAMELLIA-128-CBC-SHA256"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-camellia-256-cbc-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-CAMELLIA-256-CBC-SHA384"; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to + Transport Layer Security (TLS)"; + } + + identity tls-rsa-with-aes-128-ccm { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-AES-128-CCM"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-rsa-with-aes-256-ccm { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-AES-256-CCM"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-dhe-rsa-with-aes-128-ccm { + base cipher-suite-alg-base; + description + "TLS-DHE-RSA-WITH-AES-128-CCM"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-dhe-rsa-with-aes-256-ccm { + base cipher-suite-alg-base; + description + "TLS-DHE-RSA-WITH-AES-256-CCM"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-rsa-with-aes-128-ccm-8 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-AES-128-CCM-8"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-rsa-with-aes-256-ccm-8 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-WITH-AES-256-CCM-8"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-dhe-rsa-with-aes-128-ccm-8 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-AES-128-CCM-8"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-dhe-rsa-with-aes-256-ccm-8 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-DHE-RSA-WITH-AES-256-CCM-8"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-psk-with-aes-128-ccm { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-AES-128-CCM"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-psk-with-aes-256-ccm { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-AES-256-CCM"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-dhe-psk-with-aes-128-ccm { + base cipher-suite-alg-base; + description + "TLS-DHE-PSK-WITH-AES-128-CCM"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-dhe-psk-with-aes-256-ccm { + base cipher-suite-alg-base; + description + "TLS-DHE-PSK-WITH-AES-256-CCM"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-psk-with-aes-128-ccm-8 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-AES-128-CCM-8"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-psk-with-aes-256-ccm-8 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-AES-256-CCM-8"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-psk-dhe-with-aes-128-ccm-8 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-DHE-WITH-AES-128-CCM-8"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-psk-dhe-with-aes-256-ccm-8 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-DHE-WITH-AES-256-CCM-8"; + reference + "RFC 6655: + AES-CCM Cipher Suites for TLS"; + } + + identity tls-ecdhe-ecdsa-with-aes-128-ccm { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-AES-128-CCM"; + reference + "RFC 7251: + AES-CCM ECC Cipher Suites for TLS"; + } + + identity tls-ecdhe-ecdsa-with-aes-256-ccm { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-AES-256-CCM"; + reference + "RFC 7251: + AES-CCM ECC Cipher Suites for TLS"; + } + + identity tls-ecdhe-ecdsa-with-aes-128-ccm-8 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8"; + reference + "RFC 7251: + AES-CCM ECC Cipher Suites for TLS"; + } + + identity tls-ecdhe-ecdsa-with-aes-256-ccm-8 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-ECDSA-WITH-AES-256-CCM-8"; + reference + "RFC 7251: + AES-CCM ECC Cipher Suites for TLS"; + } + + identity tls-eccpwd-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECCPWD-WITH-AES-128-GCM-SHA256"; + reference + "RFC 8492: + Secure Password Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-eccpwd-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECCPWD-WITH-AES-256-GCM-SHA384"; + reference + "RFC 8492: + Secure Password Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-eccpwd-with-aes-128-ccm-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECCPWD-WITH-AES-128-CCM-SHA256"; + reference + "RFC 8492: + Secure Password Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-eccpwd-with-aes-256-ccm-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECCPWD-WITH-AES-256-CCM-SHA384"; + reference + "RFC 8492: + Secure Password Ciphersuites for + Transport Layer Security (TLS)"; + } + + identity tls-sha256-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SHA256-SHA256"; + reference + "RFC 9150: + TLS 1.3 Authentication and Integrity-Only Cipher Suites"; + } + + identity tls-sha384-sha384 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-SHA384-SHA384"; + reference + "RFC 9150: + TLS 1.3 Authentication and Integrity-Only Cipher Suites"; + } + + identity tls-gostr341112-256-with-kuznyechik-ctr-omac { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-GOSTR341112-256-WITH-KUZNYECHIK-CTR-OMAC"; + reference + "RFC 9189: + GOST Cipher Suites for Transport Layer Security (TLS) + Protocol Version 1.2"; + } + + identity tls-gostr341112-256-with-magma-ctr-omac { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-GOSTR341112-256-WITH-MAGMA-CTR-OMAC"; + reference + "RFC 9189: + GOST Cipher Suites for Transport Layer Security (TLS) + Protocol Version 1.2"; + } + + identity tls-gostr341112-256-with-28147-cnt-imit { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-GOSTR341112-256-WITH-28147-CNT-IMIT"; + reference + "RFC 9189: + GOST Cipher Suites for Transport Layer Security (TLS) + Protocol Version 1.2"; + } + + identity tls-ecdhe-rsa-with-chacha20-poly1305-sha256 { + base cipher-suite-alg-base; + description + "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256"; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-ecdsa-with-chacha20-poly1305-sha256 { + base cipher-suite-alg-base; + description + "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256"; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-dhe-rsa-with-chacha20-poly1305-sha256 { + base cipher-suite-alg-base; + description + "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256"; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-psk-with-chacha20-poly1305-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-PSK-WITH-CHACHA20-POLY1305-SHA256"; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-chacha20-poly1305-sha256 { + base cipher-suite-alg-base; + description + "TLS-ECDHE-PSK-WITH-CHACHA20-POLY1305-SHA256"; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-dhe-psk-with-chacha20-poly1305-sha256 { + base cipher-suite-alg-base; + description + "TLS-DHE-PSK-WITH-CHACHA20-POLY1305-SHA256"; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-rsa-psk-with-chacha20-poly1305-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-RSA-PSK-WITH-CHACHA20-POLY1305-SHA256"; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for + Transport Layer Security (TLS)"; + } + + identity tls-ecdhe-psk-with-aes-128-gcm-sha256 { + base cipher-suite-alg-base; + description + "TLS-ECDHE-PSK-WITH-AES-128-GCM-SHA256"; + reference + "RFC 8442: + ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites"; + } + + identity tls-ecdhe-psk-with-aes-256-gcm-sha384 { + base cipher-suite-alg-base; + description + "TLS-ECDHE-PSK-WITH-AES-256-GCM-SHA384"; + reference + "RFC 8442: + ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites"; + } + + identity tls-ecdhe-psk-with-aes-128-ccm-8-sha256 { + base cipher-suite-alg-base; + status deprecated; + description + "TLS-ECDHE-PSK-WITH-AES-128-CCM-8-SHA256"; + reference + "RFC 8442: + ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites"; + } + identity tls-ecdhe-psk-with-aes-128-ccm-sha256 { + base cipher-suite-alg-base; + description + "TLS-ECDHE-PSK-WITH-AES-128-CCM-SHA256"; + reference + "RFC 8442: + ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites"; + } + + // Protocol-accessible Nodes + + container supported-algorithms { + config false; + description + "A container for a list of cipher suite algorithms supported + by the server."; + leaf-list supported-algorithm { + type cipher-suite-algorithm-ref; + description + "A cipher suite algorithm supported by the server."; + } + } + +} diff --git a/modules/ietf-crypto-types@2022-07-07.yang b/modules/ietf-crypto-types@2022-07-07.yang new file mode 100644 index 00000000..19b658d1 --- /dev/null +++ b/modules/ietf-crypto-types@2022-07-07.yang @@ -0,0 +1,1021 @@ +module ietf-crypto-types { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-crypto-types"; + prefix ct; + + import ietf-yang-types { + prefix yang; + reference + "RFC 6991: Common YANG Data Types"; + } + + import ietf-netconf-acm { + prefix nacm; + reference + "RFC 8341: Network Configuration Access Control Model"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: https://datatracker.ietf.org/wg/netconf + WG List: NETCONF WG list + Author: Kent Watsen "; + + description + "This module defines common YANG types for cryptographic + applications. + + Copyright (c) 2022 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC AAAA + (https://www.rfc-editor.org/info/rfcAAAA); see the RFC + itself for full legal notices. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2022-07-07 { + description + "Initial version"; + reference + "RFC AAAA: YANG Data Types and Groupings for Cryptography"; + } + + /****************/ + /* Features */ + /****************/ + + feature one-symmetric-key-format { + description + "Indicates that the server supports the + 'one-symmetric-key-format' identity."; + } + + feature one-asymmetric-key-format { + description + "Indicates that the server supports the + 'one-asymmetric-key-format' identity."; + } + + feature symmetrically-encrypted-value-format { + description + "Indicates that the server supports the + 'symmetrically-encrypted-value-format' identity."; + } + + feature asymmetrically-encrypted-value-format { + description + "Indicates that the server supports the + 'asymmetrically-encrypted-value-format' identity."; + } + + feature cms-enveloped-data-format { + description + "Indicates that the server supports the + 'cms-enveloped-data-format' identity."; + } + + feature cms-encrypted-data-format { + description + "Indicates that the server supports the + 'cms-encrypted-data-format' identity."; + } + feature csr-generation { + description + "Indicates that the server implements the + 'generate-csr' action."; + } + + feature p10-based-csrs { + description + "Indicates that the erver implements support + for generating P10-based CSRs, as defined + in RFC 2986."; + reference + "RFC 2986: PKCS #10: Certification Request Syntax + Specification Version 1.7"; + } + + feature certificate-expiration-notification { + description + "Indicates that the server implements the + 'certificate-expiration' notification."; + } + + feature hidden-keys { + description + "Indicates that the server supports hidden keys."; + } + + feature password-encryption { + description + "Indicates that the server supports password + encryption."; + } + + feature symmetric-key-encryption { + description + "Indicates that the server supports encryption + of symmetric keys."; + } + + feature private-key-encryption { + description + "Indicates that the server supports encryption + of private keys."; + } + + /*************************************************/ + /* Base Identities for Key Format Structures */ + /*************************************************/ + identity symmetric-key-format { + description + "Base key-format identity for symmetric keys."; + } + + identity public-key-format { + description + "Base key-format identity for public keys."; + } + + identity private-key-format { + description + "Base key-format identity for private keys."; + } + + /****************************************************/ + /* Identities for Private Key Format Structures */ + /****************************************************/ + + identity rsa-private-key-format { + base private-key-format; + description + "Indicates that the private key value is encoded + as an RSAPrivateKey (from RFC 3447)."; + reference + "RFC 3447: PKCS #1: RSA Cryptography + Specifications Version 2.2"; + } + + identity ec-private-key-format { + base private-key-format; + description + "Indicates that the private key value is encoded + as an ECPrivateKey (from RFC 5915)"; + reference + "RFC 5915: Elliptic Curve Private Key Structure"; + } + + identity one-asymmetric-key-format { + if-feature "one-asymmetric-key-format"; + base private-key-format; + description + "Indicates that the private key value is a CMS + OneAsymmetricKey structure, as defined in RFC 5958, + encoded using ASN.1 distinguished encoding rules + (DER), as specified in ITU-T X.690."; + reference + "RFC 5958: Asymmetric Key Packages + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + /***************************************************/ + /* Identities for Public Key Format Structures */ + /***************************************************/ + + identity ssh-public-key-format { + base public-key-format; + description + "Indicates that the public key value is an SSH public key, + as specified by RFC 4253, Section 6.6, i.e.: + + string certificate or public key format + identifier + byte[n] key/certificate data."; + reference + "RFC 4253: The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity subject-public-key-info-format { + base public-key-format; + description + "Indicates that the public key value is a SubjectPublicKeyInfo + structure, as described in RFC 5280 encoded using ASN.1 + distinguished encoding rules (DER), as specified in + ITU-T X.690."; + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + /******************************************************/ + /* Identities for Symmetric Key Format Structures */ + /******************************************************/ + + identity octet-string-key-format { + base symmetric-key-format; + description + "Indicates that the key is encoded as a raw octet string. + The length of the octet string MUST be appropriate for + the associated algorithm's block size. + + How the associated algorithm is known is outside the + scope of this module. This statement also applies when + the octet string has been encrypted."; + } + + identity one-symmetric-key-format { + if-feature "one-symmetric-key-format"; + base symmetric-key-format; + description + "Indicates that the private key value is a CMS + OneSymmetricKey structure, as defined in RFC 6031, + encoded using ASN.1 distinguished encoding rules + (DER), as specified in ITU-T X.690."; + reference + "RFC 6031: Cryptographic Message Syntax (CMS) + Symmetric Key Package Content Type + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + /*************************************************/ + /* Identities for Encrypted Value Structures */ + /*************************************************/ + + identity encrypted-value-format { + description + "Base format identity for encrypted values."; + } + + identity symmetrically-encrypted-value-format { + if-feature "symmetrically-encrypted-value-format"; + base encrypted-value-format; + description + "Base format identity for symmetrically encrypted + values."; + } + + identity asymmetrically-encrypted-value-format { + if-feature "asymmetrically-encrypted-value-format"; + base encrypted-value-format; + description + "Base format identity for asymmetrically encrypted + values."; + } + + identity cms-encrypted-data-format { + if-feature "cms-encrypted-data-format"; + base symmetrically-encrypted-value-format; + description + "Indicates that the encrypted value conforms to + the 'encrypted-data-cms' type with the constraint + that the 'unprotectedAttrs' value is not set."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS) + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + identity cms-enveloped-data-format { + if-feature "cms-enveloped-data-format"; + base asymmetrically-encrypted-value-format; + description + "Indicates that the encrypted value conforms to the + 'enveloped-data-cms' type with the following constraints: + + The EnvelopedData structure MUST have exactly one + 'RecipientInfo'. + + If the asymmetric key supports public key cryptography + (e.g., RSA), then the 'RecipientInfo' must be a + 'KeyTransRecipientInfo' with the 'RecipientIdentifier' + using a 'subjectKeyIdentifier' with the value set using + 'method 1' in RFC 7093 over the recipient's public key. + + Otherwise, if the asymmetric key supports key agreement + (e.g., ECC), then the 'RecipientInfo' must be a + 'KeyAgreeRecipientInfo'. The 'OriginatorIdentifierOrKey' + value must use the 'OriginatorPublicKey' alternative. + The 'UserKeyingMaterial' value must not be present. + There must be exactly one 'RecipientEncryptedKeys' value + having the 'KeyAgreeRecipientIdentifier' set to 'rKeyId' + with the value set using 'method 1' in RFC 7093 over the + recipient's public key."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS) + RFC 7093: + Additional Methods for Generating Key + Identifiers Values + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + /*********************************************************/ + /* Identities for Certificate Signing Request Formats */ + /*********************************************************/ + + identity csr-format { + description + "A base identity for the certificate signing request + formats. Additional derived identities MAY be defined + by future efforts."; + } + + identity p10-csr { + if-feature "p10-based-csrs"; + base csr-format; + description + "Indicates the 'CertificationRequest' structure + defined in RFC 2986."; + reference + "RFC 2986: PKCS #10: Certification Request Syntax + Specification Version 1.7"; + } + + /***************************************************/ + /* Typedefs for ASN.1 structures from RFC 2986 */ + /***************************************************/ + + typedef csr-info { + type binary; + description + "A CertificationRequestInfo structure, as defined in + RFC 2986, encoded using ASN.1 distinguished encoding + rules (DER), as specified in ITU-T X.690."; + reference + "RFC 2986: PKCS #10: Certification Request Syntax + Specification Version 1.7 + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + typedef p10-csr { + type binary; + description + "A CertificationRequest structure, as specified in + RFC 2986, encoded using ASN.1 distinguished encoding + rules (DER), as specified in ITU-T X.690."; + reference + "RFC 2986: + PKCS #10: Certification Request Syntax Specification + Version 1.7 + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + /***************************************************/ + /* Typedefs for ASN.1 structures from RFC 5280 */ + /***************************************************/ + + typedef x509 { + type binary; + description + "A Certificate structure, as specified in RFC 5280, + encoded using ASN.1 distinguished encoding rules (DER), + as specified in ITU-T X.690."; + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + typedef crl { + type binary; + description + "A CertificateList structure, as specified in RFC 5280, + encoded using ASN.1 distinguished encoding rules (DER), + as specified in ITU-T X.690."; + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + /***************************************************/ + /* Typedefs for ASN.1 structures from RFC 6960 */ + /***************************************************/ + + typedef oscp-request { + type binary; + description + "A OCSPRequest structure, as specified in RFC 6960, + encoded using ASN.1 distinguished encoding rules + (DER), as specified in ITU-T X.690."; + reference + "RFC 6960: + X.509 Internet Public Key Infrastructure Online + Certificate Status Protocol - OCSP + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + typedef oscp-response { + type binary; + description + "A OCSPResponse structure, as specified in RFC 6960, + encoded using ASN.1 distinguished encoding rules + (DER), as specified in ITU-T X.690."; + reference + "RFC 6960: + X.509 Internet Public Key Infrastructure Online + Certificate Status Protocol - OCSP + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + /***********************************************/ + /* Typedefs for ASN.1 structures from 5652 */ + /***********************************************/ + + typedef cms { + type binary; + description + "A ContentInfo structure, as specified in RFC 5652, + encoded using ASN.1 distinguished encoding rules (DER), + as specified in ITU-T X.690."; + reference + "RFC 5652: + Cryptographic Message Syntax (CMS) + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + typedef data-content-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + data content type, as described by Section 4 in RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + typedef signed-data-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + signed-data content type, as described by Section 5 in + RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + typedef enveloped-data-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + enveloped-data content type, as described by Section 6 + in RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + typedef digested-data-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + digested-data content type, as described by Section 7 + in RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + typedef encrypted-data-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + encrypted-data content type, as described by Section 8 + in RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + typedef authenticated-data-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + authenticated-data content type, as described by Section 9 + in RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + /*********************************************************/ + /* Typedefs for ASN.1 structures related to RFC 5280 */ + /*********************************************************/ + + typedef trust-anchor-cert-x509 { + type x509; + description + "A Certificate structure that MUST encode a self-signed + root certificate."; + } + + typedef end-entity-cert-x509 { + type x509; + description + "A Certificate structure that MUST encode a certificate + that is neither self-signed nor having Basic constraint + CA true."; + } + + /*********************************************************/ + /* Typedefs for ASN.1 structures related to RFC 5652 */ + /*********************************************************/ + + typedef trust-anchor-cert-cms { + type signed-data-cms; + description + "A CMS SignedData structure that MUST contain the chain of + X.509 certificates needed to authenticate the certificate + presented by a client or end-entity. + + The CMS MUST contain only a single chain of certificates. + The client or end-entity certificate MUST only authenticate + to last intermediate CA certificate listed in the chain. + + In all cases, the chain MUST include a self-signed root + certificate. In the case where the root certificate is + itself the issuer of the client or end-entity certificate, + only one certificate is present. + + This CMS structure MAY (as applicable where this type is + used) also contain suitably fresh (as defined by local + policy) revocation objects with which the device can + verify the revocation status of the certificates. + + This CMS encodes the degenerate form of the SignedData + structure that is commonly used to disseminate X.509 + certificates and revocation objects (RFC 5280)."; + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile."; + } + + typedef end-entity-cert-cms { + type signed-data-cms; + description + "A CMS SignedData structure that MUST contain the end + entity certificate itself, and MAY contain any number + of intermediate certificates leading up to a trust + anchor certificate. The trust anchor certificate + MAY be included as well. + + The CMS MUST contain a single end entity certificate. + The CMS MUST NOT contain any spurious certificates. + + This CMS structure MAY (as applicable where this type is + used) also contain suitably fresh (as defined by local + policy) revocation objects with which the device can + verify the revocation status of the certificates. + + This CMS encodes the degenerate form of the SignedData + structure that is commonly used to disseminate X.509 + certificates and revocation objects (RFC 5280)."; + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile."; + } + + /*****************/ + /* Groupings */ + /*****************/ + + grouping encrypted-value-grouping { + description + "A reusable grouping for a value that has been encrypted by + a referenced symmetric or asymmetric key."; + container encrypted-by { + nacm:default-deny-write; + description + "An empty container enabling a reference to the key that + encrypted the value to be augmented in. The referenced + key MUST be a symmetric key or an asymmetric key. + + A symmetric key MUST be referenced via a leaf node called + 'symmetric-key-ref'. An asymmetric key MUST be referenced + via a leaf node called 'asymmetric-key-ref'. + + The leaf nodes MUST be direct descendants in the data tree, + and MAY be direct descendants in the schema tree."; + } + leaf encrypted-value-format { + type identityref { + base encrypted-value-format; + } + mandatory true; + description + "Identifies the format of the 'encrypted-value' leaf. + + If 'encrypted-by' points to a symmetric key, then a + 'symmetrically-encrypted-value-format' based identity + MUST by set (e.g., cms-encrypted-data-format). + + If 'encrypted-by' points to an asymmetric key, then an + 'asymmetrically-encrypted-value-format' based identity + MUST by set (e.g., cms-enveloped-data-format)."; + } + leaf encrypted-value { + nacm:default-deny-write; + type binary; + must '../encrypted-by'; + mandatory true; + description + "The value, encrypted using the referenced symmetric + or asymmetric key. The value MUST be encoded using + the format associated with the 'encrypted-value-format' + leaf."; + } + } + + grouping password-grouping { + description + "A password that MAY be encrypted."; + choice password-type { + nacm:default-deny-write; + mandatory true; + description + "Choice between password types."; + case cleartext-password { + leaf cleartext-password { + nacm:default-deny-all; + type string; + description + "The cleartext value of the password."; + } + } + case encrypted-password { + if-feature "password-encryption"; + container encrypted-password { + description + "A container for the encrypted password value."; + uses encrypted-value-grouping; + } + } + } + } + + grouping symmetric-key-grouping { + description + "A symmetric key."; + leaf key-format { + nacm:default-deny-write; + type identityref { + base symmetric-key-format; + } + description + "Identifies the symmetric key's format. Implementations + SHOULD ensure that the incoming symmetric key value is + encoded in the specified format. + + For encrypted keys, the value is the same as it would + have been if the key were not encrypted."; + } + choice key-type { + nacm:default-deny-write; + mandatory true; + description + "Choice between key types."; + case cleartext-key { + leaf cleartext-key { + nacm:default-deny-all; + type binary; + must '../key-format'; + description + "The binary value of the key. The interpretation of + the value is defined by the 'key-format' field."; + } + } + case hidden-key { + if-feature "hidden-keys"; + leaf hidden-key { + type empty; + must 'not(../key-format)'; + description + "A hidden key. How such keys are created is outside + the scope of this module."; + } + } + case encrypted-key { + if-feature "symmetric-key-encryption"; + container encrypted-key { + must '../key-format'; + description + "A container for the encrypted symmetric key value. + The interpretation of the 'encrypted-value' node + is via the 'key-format' node"; + uses encrypted-value-grouping; + } + } + } + } + + grouping public-key-grouping { + description + "A public key."; + leaf public-key-format { + nacm:default-deny-write; + type identityref { + base public-key-format; + } + mandatory true; + description + "Identifies the public key's format. Implementations SHOULD + ensure that the incoming public key value is encoded in the + specified format."; + } + leaf public-key { + nacm:default-deny-write; + type binary; + mandatory true; + description + "The binary value of the public key. The interpretation + of the value is defined by 'public-key-format' field."; + } + } + + grouping asymmetric-key-pair-grouping { + description + "A private key and its associated public key. Implementations + SHOULD ensure that the two keys are a matching pair."; + uses public-key-grouping; + leaf private-key-format { + nacm:default-deny-write; + type identityref { + base private-key-format; + } + description + "Identifies the private key's format. Implementations SHOULD + ensure that the incoming private key value is encoded in the + specified format. + + For encrypted keys, the value is the same as it would have + been if the key were not encrypted."; + } + choice private-key-type { + nacm:default-deny-write; + mandatory true; + description + "Choice between key types."; + case cleartext-private-key { + leaf cleartext-private-key { + nacm:default-deny-all; + type binary; + must '../private-key-format'; + description + "The value of the binary key The key's value is + interpreted by the 'private-key-format' field."; + } + } + case hidden-private-key { + if-feature "hidden-keys"; + leaf hidden-private-key { + type empty; + must 'not(../private-key-format)'; + description + "A hidden key. How such keys are created is + outside the scope of this module."; + } + } + case encrypted-private-key { + if-feature "private-key-encryption"; + container encrypted-private-key { + must '../private-key-format'; + description + "A container for the encrypted asymmetric private key + value. The interpretation of the 'encrypted-value' + node is via the 'private-key-format' node"; + uses encrypted-value-grouping; + } + } + } + } + + grouping certificate-expiration-grouping { + description + "A notification for when a certificate is about to, or + already has, expired."; + notification certificate-expiration { + if-feature "certificate-expiration-notification"; + description + "A notification indicating that the configured certificate + is either about to expire or has already expired. When to + send notifications is an implementation specific decision, + but it is RECOMMENDED that a notification be sent once a + month for 3 months, then once a week for four weeks, and + then once a day thereafter until the issue is resolved."; + leaf expiration-date { + type yang:date-and-time; + mandatory true; + description + "Identifies the expiration date on the certificate."; + } + } + } + + grouping trust-anchor-cert-grouping { + description + "A trust anchor certificate, and a notification for when + it is about to (or already has) expire."; + leaf cert-data { + nacm:default-deny-write; + type trust-anchor-cert-cms; + description + "The binary certificate data for this certificate."; + } + uses certificate-expiration-grouping; + } + + grouping end-entity-cert-grouping { + description + "An end entity certificate, and a notification for when + it is about to (or already has) expire. Implementations + SHOULD assert that, where used, the end entity certificate + contains the expected public key."; + leaf cert-data { + nacm:default-deny-write; + type end-entity-cert-cms; + description + "The binary certificate data for this certificate."; + } + uses certificate-expiration-grouping; + } + + grouping generate-csr-grouping { + description + "Defines the 'generate-csr' action."; + action generate-csr { + if-feature "csr-generation"; + nacm:default-deny-all; + description + "Generates a certificate signing request structure for + the associated asymmetric key using the passed subject + and attribute values. + + This action statement is only available when the + associated 'public-key-format' node's value is + 'subject-public-key-info-format'."; + reference + "RFC 6125: + Representation and Verification of Domain-Based + Application Service Identity within Internet Public Key + Infrastructure Using X.509 (PKIX) Certificates in the + Context of Transport Layer Security (TLS)"; + input { + leaf csr-format { + type identityref { + base csr-format; + } + mandatory true; + description + "Specifies the format for the returned certifiacte."; + } + leaf csr-info { + type csr-info; + mandatory true; + description + "A CertificationRequestInfo structure, as defined in + RFC 2986. + + Enables the client to provide a fully-populated + CertificationRequestInfo structure that the server + only needs to sign in order to generate the complete + 'CertificationRequest' structure to return in the + 'output'. + + The 'AlgorithmIdentifier' field contained inside + the 'SubjectPublicKeyInfo' field MUST be one known + to be supported by the device."; + reference + "RFC 2986: + PKCS #10: Certification Request Syntax Specification + RFC AAAA: + YANG Data Types and Groupings for Cryptography"; + } + } + output { + choice csr-type { + mandatory true; + description + "A choice amongst certificate signing request formats. + Additional formats MAY be augmented into this 'choice' + statement by future efforts."; + case p10-csr { + leaf p10-csr { + type p10-csr; + description + "A CertificationRequest, as defined in RFC 2986."; + } + description + "A CertificationRequest, as defined in RFC 2986."; + reference + "RFC 2986: + PKCS #10: Certification Request Syntax Specification + RFC AAAA: + YANG Data Types and Groupings for Cryptography"; + } + } + } + } + } // generate-csr-grouping + + grouping asymmetric-key-pair-with-cert-grouping { + description + "A private/public key pair and an associated certificate. + Implementations SHOULD assert that certificates contain + the matching public key."; + uses asymmetric-key-pair-grouping; + uses end-entity-cert-grouping; + uses generate-csr-grouping; + } // asymmetric-key-pair-with-cert-grouping + + grouping asymmetric-key-pair-with-certs-grouping { + description + "A private/public key pair and associated certificates. + Implementations SHOULD assert that certificates contain + the matching public key."; + uses asymmetric-key-pair-grouping; + container certificates { + nacm:default-deny-write; + description + "Certificates associated with this asymmetric key."; + list certificate { + key "name"; + description + "A certificate for this asymmetric key."; + leaf name { + type string; + description + "An arbitrary name for the certificate."; + } + uses end-entity-cert-grouping { + refine "cert-data" { + mandatory true; + } + } + } + } + uses generate-csr-grouping; + } // asymmetric-key-pair-with-certs-grouping + +} diff --git a/modules/ietf-keystore@2022-05-24.yang b/modules/ietf-keystore@2022-05-24.yang new file mode 100644 index 00000000..345e0aa6 --- /dev/null +++ b/modules/ietf-keystore@2022-05-24.yang @@ -0,0 +1,412 @@ +module ietf-keystore { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-keystore"; + prefix ks; + + import ietf-netconf-acm { + prefix nacm; + reference + "RFC 8341: Network Configuration Access Control Model"; + } + + import ietf-crypto-types { + prefix ct; + reference + "RFC AAAA: YANG Data Types and Groupings for Cryptography"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: https://datatracker.ietf.org/wg/netconf + WG List: NETCONF WG list + Author: Kent Watsen "; + + description + "This module defines a 'keystore' to centralize management + of security credentials. + + Copyright (c) 2022 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC CCCC + (https://www.rfc-editor.org/info/rfcCCCC); see the RFC + itself for full legal notices. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2022-05-24 { + description + "Initial version"; + reference + "RFC CCCC: A YANG Data Model for a Keystore"; + } + + /****************/ + /* Features */ + /****************/ + + feature central-keystore-supported { + description + "The 'central-keystore-supported' feature indicates that + the server supports the keystore (i.e., implements the + 'ietf-keystore' module)."; + } + + feature local-definitions-supported { + description + "The 'local-definitions-supported' feature indicates that + the server supports locally-defined keys."; + } + + feature asymmetric-keys { + description + "The 'asymmetric-keys' feature indicates that the server + supports asymmetric keys in keystores."; + } + + feature symmetric-keys { + description + "The 'symmetric-keys' feature indicates that the server + supports symmetric keys in keystores."; + } + + /****************/ + /* Typedefs */ + /****************/ + + typedef symmetric-key-ref { + type leafref { + path "/ks:keystore/ks:symmetric-keys/ks:symmetric-key" + + "/ks:name"; + } + description + "This typedef enables modules to easily define a reference + to a symmetric key stored in the keystore, when this + module is implemented."; + } + + typedef asymmetric-key-ref { + type leafref { + path "/ks:keystore/ks:asymmetric-keys/ks:asymmetric-key" + + "/ks:name"; + } + description + "This typedef enables modules to easily define a reference + to an asymmetric key stored in the keystore, when this + module is implemented."; + } + + /*****************/ + /* Groupings */ + /*****************/ + + grouping encrypted-by-choice-grouping { + description + "A grouping that defines a 'choice' statement that can be + augmented into the 'encrypted-by' node, present in the + 'symmetric-key-grouping' and 'asymmetric-key-pair-grouping' + groupings defined in RFC AAAA, enabling references to keys + in the keystore, when this module is implemented."; + choice encrypted-by-choice { + nacm:default-deny-write; + mandatory true; + description + "A choice amongst other symmetric or asymmetric keys."; + case symmetric-key-ref { + if-feature "central-keystore-supported"; + if-feature "symmetric-keys"; + leaf symmetric-key-ref { + type ks:symmetric-key-ref; + description + "Identifies the symmetric key used to encrypt the + associated key."; + } + } + case asymmetric-key-ref { + if-feature "central-keystore-supported"; + if-feature "asymmetric-keys"; + leaf asymmetric-key-ref { + type ks:asymmetric-key-ref; + description + "Identifies the asymmetric key whose public key + encrypted the associated key."; + } + } + } + } + + grouping asymmetric-key-certificate-ref-grouping { + description + "This grouping defines a reference to a specific certificate + associated with an asymmetric key stored in the keystore, + when this module is implemented."; + leaf asymmetric-key { + nacm:default-deny-write; + if-feature "central-keystore-supported"; + if-feature "asymmetric-keys"; + type ks:asymmetric-key-ref; + must '../certificate'; + description + "A reference to an asymmetric key in the keystore."; + } + leaf certificate { + nacm:default-deny-write; + type leafref { + path "/ks:keystore/ks:asymmetric-keys/ks:asymmetric-key" + + "[ks:name = current()/../asymmetric-key]/" + + "ks:certificates/ks:certificate/ks:name"; + } + must '../asymmetric-key'; + description + "A reference to a specific certificate of the + asymmetric key in the keystore."; + } + } + + // local-or-keystore-* groupings + + grouping local-or-keystore-symmetric-key-grouping { + description + "A grouping that expands to allow the symmetric key to be + either stored locally, i.e., within the using data model, + or a reference to a symmetric key stored in the keystore. + + Servers that do not 'implement' this module, and hence + 'central-keystore-supported' is not defined, SHOULD + augment in custom 'case' statements enabling references + to the alternate keystore locations."; + choice local-or-keystore { + nacm:default-deny-write; + mandatory true; + description + "A choice between an inlined definition and a definition + that exists in the keystore."; + case local { + if-feature "local-definitions-supported"; + if-feature "symmetric-keys"; + container local-definition { + description + "Container to hold the local key definition."; + uses ct:symmetric-key-grouping; + } + } + case keystore { + if-feature "central-keystore-supported"; + if-feature "symmetric-keys"; + leaf keystore-reference { + type ks:symmetric-key-ref; + description + "A reference to an symmetric key that exists in + the keystore, when this module is implemented."; + } + } + } + } + grouping local-or-keystore-asymmetric-key-grouping { + description + "A grouping that expands to allow the asymmetric key to be + either stored locally, i.e., within the using data model, + or a reference to an asymmetric key stored in the keystore. + + Servers that do not 'implement' this module, and hence + 'central-keystore-supported' is not defined, SHOULD + augment in custom 'case' statements enabling references + to the alternate keystore locations."; + choice local-or-keystore { + nacm:default-deny-write; + mandatory true; + description + "A choice between an inlined definition and a definition + that exists in the keystore."; + case local { + if-feature "local-definitions-supported"; + if-feature "asymmetric-keys"; + container local-definition { + description + "Container to hold the local key definition."; + uses ct:asymmetric-key-pair-grouping; + } + } + case keystore { + if-feature "central-keystore-supported"; + if-feature "asymmetric-keys"; + leaf keystore-reference { + type ks:asymmetric-key-ref; + description + "A reference to an asymmetric key that exists in + the keystore, when this module is implemented. The + intent is to reference just the asymmetric key + without any regard for any certificates that may + be associated with it."; + } + } + } + } + + grouping local-or-keystore-asymmetric-key-with-certs-grouping { + description + "A grouping that expands to allow an asymmetric key and + its associated certificates to be either stored locally, + i.e., within the using data model, or a reference to an + asymmetric key (and its associated certificates) stored + in the keystore. + Servers that do not 'implement' this module, and hence + 'central-keystore-supported' is not defined, SHOULD + augment in custom 'case' statements enabling references + to the alternate keystore locations."; + choice local-or-keystore { + nacm:default-deny-write; + mandatory true; + description + "A choice between an inlined definition and a definition + that exists in the keystore."; + case local { + if-feature "local-definitions-supported"; + if-feature "asymmetric-keys"; + container local-definition { + description + "Container to hold the local key definition."; + uses ct:asymmetric-key-pair-with-certs-grouping; + } + } + case keystore { + if-feature "central-keystore-supported"; + if-feature "asymmetric-keys"; + leaf keystore-reference { + type ks:asymmetric-key-ref; + description + "A reference to an asymmetric-key (and all of its + associated certificates) in the keystore, when + this module is implemented."; + } + } + } + } + + grouping local-or-keystore-end-entity-cert-with-key-grouping { + description + "A grouping that expands to allow an end-entity certificate + (and its associated asymmetric key pair) to be either stored + locally, i.e., within the using data model, or a reference + to a specific certificate in the keystore. + + Servers that do not 'implement' this module, and hence + 'central-keystore-supported' is not defined, SHOULD + augment in custom 'case' statements enabling references + to the alternate keystore locations."; + choice local-or-keystore { + nacm:default-deny-write; + mandatory true; + description + "A choice between an inlined definition and a definition + that exists in the keystore."; + case local { + if-feature "local-definitions-supported"; + if-feature "asymmetric-keys"; + container local-definition { + description + "Container to hold the local key definition."; + uses ct:asymmetric-key-pair-with-cert-grouping; + } + } + case keystore { + if-feature "central-keystore-supported"; + if-feature "asymmetric-keys"; + container keystore-reference { + uses asymmetric-key-certificate-ref-grouping; + description + "A reference to a specific certificate associated with + an asymmetric key stored in the keystore, when this + module is implemented."; + } + } + } + } + + grouping keystore-grouping { + description + "Grouping definition enables use in other contexts. If ever + done, implementations MUST augment new 'case' statements + into the various local-or-keystore 'choice' statements to + supply leafrefs to the model-specific location(s)."; + container asymmetric-keys { + nacm:default-deny-write; + if-feature "asymmetric-keys"; + description + "A list of asymmetric keys."; + list asymmetric-key { + key "name"; + description + "An asymmetric key."; + leaf name { + type string; + description + "An arbitrary name for the asymmetric key."; + } + uses ct:asymmetric-key-pair-with-certs-grouping; + } + } + container symmetric-keys { + nacm:default-deny-write; + if-feature "symmetric-keys"; + description + "A list of symmetric keys."; + list symmetric-key { + key "name"; + description + "A symmetric key."; + leaf name { + type string; + description + "An arbitrary name for the symmetric key."; + } + uses ct:symmetric-key-grouping; + } + } + } + + /*********************************/ + /* Protocol accessible nodes */ + /*********************************/ + + container keystore { + if-feature central-keystore-supported; + description + "A central keystore containing a list of symmetric keys and + a list of asymmetric keys."; + nacm:default-deny-write; + uses keystore-grouping { + augment "symmetric-keys/symmetric-key/key-type/encrypted-key/" + + "encrypted-key/encrypted-by" { + description + "Augments in a choice statement enabling the encrypting + key to be any other symmetric or asymmetric key in the + central keystore."; + uses encrypted-by-choice-grouping; + } + augment "asymmetric-keys/asymmetric-key/private-key-type/" + + "encrypted-private-key/encrypted-private-key/" + + "encrypted-by" { + description + "Augments in a choice statement enabling the encrypting + key to be any other symmetric or asymmetric key in the + central keystore."; + uses encrypted-by-choice-grouping; + } + } + } +} diff --git a/modules/ietf-netconf-server@2022-05-24.yang b/modules/ietf-netconf-server@2022-05-24.yang new file mode 100644 index 00000000..c48d5841 --- /dev/null +++ b/modules/ietf-netconf-server@2022-05-24.yang @@ -0,0 +1,677 @@ +module ietf-netconf-server { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-server"; + prefix ncs; + + import ietf-yang-types { + prefix yang; + reference + "RFC 6991: Common YANG Data Types"; + } + + import ietf-x509-cert-to-name { + prefix x509c2n; + reference + "RFC 7407: A YANG Data Model for SNMP Configuration"; + } + + import ietf-tcp-client { + prefix tcpc; + reference + "RFC DDDD: YANG Groupings for TCP Clients and TCP Servers"; + } + + import ietf-tcp-server { + prefix tcps; + reference + "RFC DDDD: YANG Groupings for TCP Clients and TCP Servers"; + } + + import ietf-ssh-common { + prefix sshcmn; + revision-date 2022-07-18; // stable grouping definitions + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + import ietf-ssh-server { + prefix sshs; + revision-date 2022-07-18; // stable grouping definitions + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + import ietf-tls-server { + prefix tlss; + revision-date 2022-07-18; // stable grouping definitions + reference + "RFC FFFF: YANG Groupings for TLS Clients and TLS Servers"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: https://datatracker.ietf.org/wg/netconf + WG List: NETCONF WG list + Author: Kent Watsen + Author: Gary Wu + Author: Juergen Schoenwaelder + "; + + description + "This module contains a collection of YANG definitions + for configuring NETCONF servers. + + Copyright (c) 2022 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC HHHH + (https://www.rfc-editor.org/info/rfcHHHH); see the RFC + itself for full legal notices. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2022-05-24 { + description + "Initial version"; + reference + "RFC HHHH: NETCONF Client and Server Models"; + } + + // Features + + feature ssh-listen { + description + "The 'ssh-listen' feature indicates that the NETCONF server + supports opening a port to accept NETCONF over SSH + client connections."; + reference + "RFC 6242: + Using the NETCONF Protocol over Secure Shell (SSH)"; + } + + feature tls-listen { + description + "The 'tls-listen' feature indicates that the NETCONF server + supports opening a port to accept NETCONF over TLS + client connections."; + reference + "RFC 7589: Using the NETCONF Protocol over Transport + Layer Security (TLS) with Mutual X.509 + Authentication"; + } + + feature ssh-call-home { + description + "The 'ssh-call-home' feature indicates that the NETCONF + server supports initiating a NETCONF over SSH call + home connection to NETCONF clients."; + reference + "RFC 8071: NETCONF Call Home and RESTCONF Call Home"; + } + + feature tls-call-home { + description + "The 'tls-call-home' feature indicates that the NETCONF + server supports initiating a NETCONF over TLS call + home connection to NETCONF clients."; + reference + "RFC 8071: NETCONF Call Home and RESTCONF Call Home"; + } + + feature central-netconf-server-supported { + description + "The 'central-netconf-server-supported' feature indicates + that the server supports the top-level 'netconf-server' + node. + + This feature is needed as some servers may want to use + features defined in this module, which requires this + module to be implemented, without having to support + the top-level 'netconf-server' node."; + } + + // Groupings + + grouping netconf-server-grouping { + description + "A reusable grouping for configuring a NETCONF server + without any consideration for how underlying transport + sessions are established. + + Note that this grouping uses a fairly typical descendant + node name such that a stack of 'uses' statements will + have name conflicts. It is intended that the consuming + data model will resolve the issue by wrapping the 'uses' + statement in a container called, e.g., + 'netconf-server-parameters'. This model purposely does + not do this itself so as to provide maximum flexibility + to consuming models."; + + container client-identity-mappings { + description + "Specifies mappings through which NETCONF client X.509 + certificates are used to determine a NETCONF username, + per RFC 7407. + + For TLS-based transports, if no matching and valid + cert-to-name list entry can be found, then the NETCONF + server MUST close the connection, and MUST NOT accept + NETCONF messages over it, per Section 7 in RFC 7589. + + For SSH-based transports, a matching cert-to-name + entry overrides the username provided by the SSH + implementation, consistent with the second paragraph + of Section 3 in RFC 6242."; + reference + "RFC 6242: + Using the NETCONF Protocol over Secure Shell (SSH) + RFC 7589: + Using the NETCONF Protocol over Transport Layer + Security (TLS) with Mutual X.509 Authentication"; + uses x509c2n:cert-to-name { + refine "cert-to-name/fingerprint" { + mandatory false; + description + "A 'fingerprint' value does not need to be specified + when the 'cert-to-name' mapping is independent of + fingerprint matching. A 'cert-to-name' having no + fingerprint value will match any client certificate + and therefore should only be present at the end of + the user-ordered 'cert-to-name' list."; + } + } + } + } + + grouping netconf-server-listen-stack-grouping { + description + "A reusable grouping for configuring a NETCONF server + 'listen' protocol stack for a single connection."; + choice transport { + mandatory true; + description + "Selects between available transports."; + case ssh { + if-feature "ssh-listen"; + container ssh { + description + "SSH-specific listening configuration for inbound + connections."; + container tcp-server-parameters { + description + "A wrapper around the TCP client parameters + to avoid name collisions."; + uses tcps:tcp-server-grouping { + refine "local-port" { + default "830"; + description + "The NETCONF server will listen on the + IANA-assigned well-known port value + for 'netconf-ssh' (830) if no value + is specified."; + } + } + } + container ssh-server-parameters { + description + "A wrapper around the SSH server parameters + to avoid name collisions."; + uses sshs:ssh-server-grouping; + } + container netconf-server-parameters { + description + "A wrapper around the NETCONF server parameters + to avoid name collisions."; + uses ncs:netconf-server-grouping { + refine "client-identity-mappings" { + if-feature "sshcmn:ssh-x509-certs"; + description + "Augments in an 'if-feature' statement + ensuring the 'client-identity-mappings' + descendant is enabled only when SSH + supports X.509 certificates."; + } + augment "client-identity-mappings" { + description + "Adds a flag indicating if a cert-to-name + is required."; + leaf mapping-required { + type boolean; + description + "Indicates that the cert-to-name mapping + is required (i.e., the SSH-level username + is ignored)."; + } + } + } + } + } + } + case tls { + if-feature "tls-listen"; + container tls { + description + "TLS-specific listening configuration for inbound + connections."; + container tcp-server-parameters { + description + "A wrapper around the TCP client parameters + to avoid name collisions."; + uses tcps:tcp-server-grouping { + refine "local-port" { + default "6513"; + description + "The NETCONF server will listen on the + IANA-assigned well-known port value + for 'netconf-tls' (6513) if no value + is specified."; + } + } + } + container tls-server-parameters { + description + "A wrapper around the TLS server parameters to + avoid name collisions."; + uses tlss:tls-server-grouping { + refine "client-authentication" { + must 'ca-certs or ee-certs'; + description + "NETCONF/TLS servers MUST validate client + certificates. This configures certificates + at the socket-level (i.e. bags), more + discriminating client-certificate checks + SHOULD be implemented by the application."; + reference + "RFC 7589: + Using the NETCONF Protocol over Transport Layer + Security (TLS) with Mutual X.509 Authentication"; + } + } + } + container netconf-server-parameters { + description + "A wrapper around the NETCONF server parameters + to avoid name collisions."; + uses ncs:netconf-server-grouping { + refine "client-identity-mappings/cert-to-name" { + min-elements 1; + description + "The TLS transport requires a mapping."; + } + } + } + } + } + } + } + + grouping netconf-server-callhome-stack-grouping { + description + "A reusable grouping for configuring a NETCONF server + 'call-home' protocol stack, for a single connection."; + choice transport { + mandatory true; + description + "Selects between available transports."; + case ssh { + if-feature "ssh-call-home"; + container ssh { + description + "Specifies SSH-specific call-home transport + configuration."; + container tcp-client-parameters { + description + "A wrapper around the TCP client parameters + to avoid name collisions."; + uses tcpc:tcp-client-grouping { + refine "remote-port" { + default "4334"; + description + "The NETCONF server will attempt to connect + to the IANA-assigned well-known port for + 'netconf-ch-tls' (4334) if no value is + specified."; + } + } + } + container ssh-server-parameters { + description + "A wrapper around the SSH server parameters + to avoid name collisions."; + uses sshs:ssh-server-grouping; + } + container netconf-server-parameters { + description + "A wrapper around the NETCONF server parameters + to avoid name collisions."; + uses ncs:netconf-server-grouping { + refine "client-identity-mappings" { + if-feature "sshcmn:ssh-x509-certs"; + description + "Augments in an 'if-feature' statement + ensuring the 'client-identity-mappings' + descendant is enabled only when SSH + supports X.509 certificates."; + } + augment "client-identity-mappings" { + description + "Adds a flag indicating if a cert-to-name + is required."; + leaf mapping-required { + type boolean; + description + "Indicates that the cert-to-name mapping + is required (i.e., the SSH-level username + is ignored)."; + } + } + } + } + } + } + case tls { + if-feature "tls-call-home"; + container tls { + description + "Specifies TLS-specific call-home transport + configuration."; + container tcp-client-parameters { + description + "A wrapper around the TCP client parameters + to avoid name collisions."; + uses tcpc:tcp-client-grouping { + refine "remote-port" { + default "4335"; + description + "The NETCONF server will attempt to connect + to the IANA-assigned well-known port for + 'netconf-ch-tls' (4335) if no value is + specified."; + } + } + } + container tls-server-parameters { + description + "A wrapper around the TLS server parameters to + avoid name collisions."; + uses tlss:tls-server-grouping { + refine "client-authentication" { + must 'ca-certs or ee-certs'; + description + "NETCONF/TLS servers MUST validate client + certificates. This configures certificates + at the socket-level (i.e. bags), more + discriminating client-certificate checks + SHOULD be implemented by the application."; + reference + "RFC 7589: + Using the NETCONF Protocol over Transport Layer + Security (TLS) with Mutual X.509 Authentication"; + } + } + } + container netconf-server-parameters { + description + "A wrapper around the NETCONF server parameters + to avoid name collisions."; + uses ncs:netconf-server-grouping { + refine "client-identity-mappings/cert-to-name" { + min-elements 1; + description + "The TLS transport requires a mapping."; + } + } + } + } + } + } + } + + grouping netconf-server-app-grouping { + description + "A reusable grouping for configuring a NETCONF server + application that supports both 'listen' and 'call-home' + protocol stacks for a multiplicity of connections."; + container listen { + if-feature "ssh-listen or tls-listen"; + presence + "Indicates that server-listening ports have been configured. + This statement is present so the mandatory descendant + nodes do not imply that this node must be configured."; + description + "Configures listen behavior"; + leaf idle-timeout { + type uint16; + units "seconds"; + default "3600"; // one hour + description + "Specifies the maximum number of seconds that a NETCONF + session may remain idle. A NETCONF session will be + dropped if it is idle for an interval longer than this + number of seconds. If set to zero, then the server + will never drop a session because it is idle. Sessions + that have a notification subscription active are never + dropped."; + } + list endpoint { + key "name"; + min-elements 1; + description + "List of endpoints to listen for NETCONF connections."; + leaf name { + type string; + description + "An arbitrary name for the NETCONF listen endpoint."; + } + uses netconf-server-listen-stack-grouping; + } + } + container call-home { + if-feature "ssh-call-home or tls-call-home"; + presence + "Indicates that server-initiated call home connections have + been configured. This statement is present so the mandatory + descendant nodes do not imply that this node must be + configured."; + description + "Configures the NETCONF server to initiate the underlying + transport connection to NETCONF clients."; + list netconf-client { + key "name"; + min-elements 1; + description + "List of NETCONF clients the NETCONF server is to + maintain simultaneous call-home connections with."; + leaf name { + type string; + description + "An arbitrary name for the remote NETCONF client."; + } + container endpoints { + description + "Container for the list of endpoints."; + list endpoint { + key "name"; + min-elements 1; + ordered-by user; + description + "A non-empty user-ordered list of endpoints for this + NETCONF server to try to connect to in sequence. + Defining more than one enables high-availability."; + leaf name { + type string; + description + "An arbitrary name for this endpoint."; + } + uses netconf-server-callhome-stack-grouping; + } + } + container connection-type { + description + "Indicates the NETCONF server's preference for how the + NETCONF connection is maintained."; + choice connection-type { + mandatory true; + description + "Selects between available connection types."; + case persistent-connection { + container persistent { + presence + "Indicates that a persistent connection is to be + maintained."; + description + "Maintain a persistent connection to the NETCONF + client. If the connection goes down, immediately + start trying to reconnect to the NETCONF client, + using the reconnection strategy. + + This connection type minimizes any NETCONF client + to NETCONF server data-transfer delay, albeit at + the expense of holding resources longer."; + } + } + case periodic-connection { + container periodic { + presence "Indicates that a periodic connection is + to be maintained."; + description + "Periodically connect to the NETCONF client. + + This connection type increases resource + utilization, albeit with increased delay in + NETCONF client to NETCONF client interactions. + + The NETCONF client SHOULD gracefully close the + connection using upon completing + planned activities. If the NETCONF session is + not closed gracefully, the NETCONF server MUST + immediately attempt to reestablish the connection. + + In the case that the previous connection is still + active (i.e., the NETCONF client has not closed + it yet), establishing a new connection is NOT + RECOMMENDED."; + leaf period { + type uint16; + units "minutes"; + default "60"; + description + "Duration of time between periodic connections."; + } + leaf anchor-time { + type yang:date-and-time { + // constrained to minute-level granularity + pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}' + + '(Z|[\+\-]\d{2}:\d{2})'; + } + description + "Designates a timestamp before or after which a + series of periodic connections are determined. + The periodic connections occur at a whole + multiple interval from the anchor time. For + example, for an anchor time is 15 minutes past + midnight and a period interval of 24 hours, then + a periodic connection will occur 15 minutes past + midnight everyday."; + } + leaf idle-timeout { + type uint16; + units "seconds"; + default "120"; // two minutes + description + "Specifies the maximum number of seconds that + a NETCONF session may remain idle. A NETCONF + session will be dropped if it is idle for an + interval longer than this number of seconds. + If set to zero, then the server will never + drop a session because it is idle."; + } + } + } // case periodic-connection + } // choice connection-type + } // container connection-type + container reconnect-strategy { + description + "The reconnection strategy directs how a NETCONF server + reconnects to a NETCONF client, after discovering its + connection to the client has dropped, even if due to a + reboot. The NETCONF server starts with the specified + endpoint and tries to connect to it max-attempts times + before trying the next endpoint in the list (round + robin)."; + leaf start-with { + type enumeration { + enum first-listed { + description + "Indicates that reconnections should start with + the first endpoint listed."; + } + enum last-connected { + description + "Indicates that reconnections should start with + the endpoint last connected to. If no previous + connection has ever been established, then the + first endpoint configured is used. NETCONF + servers SHOULD be able to remember the last + endpoint connected to across reboots."; + } + enum random-selection { + description + "Indicates that reconnections should start with + a random endpoint."; + } + } + default "first-listed"; + description + "Specifies which of the NETCONF client's endpoints + the NETCONF server should start with when trying + to connect to the NETCONF client."; + } + leaf max-wait { + type uint16 { + range "1..max"; + } + units "seconds"; + default "5"; + description + "Specifies the amount of time in seconds after which, + if the connection is not established, an endpoint + connection attempt is considered unsuccessful."; + } + leaf max-attempts { + type uint8 { + range "1..max"; + } + default "3"; + description + "Specifies the number times the NETCONF server tries + to connect to a specific endpoint before moving on + to the next endpoint in the list (round robin)."; + } + } // container reconnect-strategy + } // list netconf-client + } // container call-home + } // grouping netconf-server-app-grouping + + // Protocol accessible node for servers that implement this module. + container netconf-server { + if-feature central-netconf-server-supported; + uses netconf-server-app-grouping; + description + "Top-level container for NETCONF server configuration."; + } +} diff --git a/modules/ietf-ssh-common@2022-07-18.yang b/modules/ietf-ssh-common@2022-07-18.yang new file mode 100644 index 00000000..00f32f4e --- /dev/null +++ b/modules/ietf-ssh-common@2022-07-18.yang @@ -0,0 +1,257 @@ +module ietf-ssh-common { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-ssh-common"; + prefix sshcmn; + + import iana-ssh-encryption-algs { + prefix sshea; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + import iana-ssh-key-exchange-algs { + prefix sshkea; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + import iana-ssh-mac-algs { + prefix sshma; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + import iana-ssh-public-key-algs { + prefix sshpka; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + import ietf-crypto-types { + prefix ct; + reference + "RFC AAAA: YANG Data Types and Groupings for Cryptography"; + } + + import ietf-keystore { + prefix ks; + reference + "RFC CCCC: A YANG Data Model for a Keystore"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: https://datatracker.ietf.org/wg/netconf + WG List: NETCONF WG list + Author: Kent Watsen + Author: Gary Wu "; + + description + "This module defines a common features and groupings for + Secure Shell (SSH). + + Copyright (c) 2022 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC EEEE + (https://www.rfc-editor.org/info/rfcEEEE); see the RFC + itself for full legal notices. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2022-07-18 { + description + "Initial version"; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + // Features + + feature ssh-x509-certs { + description + "X.509v3 certificates are supported for SSH."; + reference + "RFC 6187: X.509v3 Certificates for Secure Shell + Authentication"; + } + + feature transport-params { + description + "SSH transport layer parameters are configurable."; + } + + feature public-key-generation { + description + "Indicates that the server implements the + 'generate-public-key' RPC."; + } + + // Groupings + + grouping transport-params-grouping { + description + "A reusable grouping for SSH transport parameters."; + reference + "RFC 4253: The Secure Shell (SSH) Transport Layer Protocol"; + container host-key { + description + "Parameters regarding host key."; + leaf-list host-key-alg { + type identityref { + base sshpka:public-key-alg-base; + } + ordered-by user; + description + "Acceptable host key algorithms in order of descending + preference. The configured host key algorithms should + be compatible with the algorithm used by the configured + private key. Please see Section 5 of RFC EEEE for + valid combinations. + + If this leaf-list is not configured (has zero elements) + the acceptable host key algorithms are implementation- + defined."; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + } + container key-exchange { + description + "Parameters regarding key exchange."; + leaf-list key-exchange-alg { + type identityref { + base sshkea:key-exchange-alg-base; + } + ordered-by user; + description + "Acceptable key exchange algorithms in order of descending + preference. + + If this leaf-list is not configured (has zero elements) + the acceptable key exchange algorithms are implementation + defined."; + } + } + container encryption { + description + "Parameters regarding encryption."; + leaf-list encryption-alg { + type identityref { + base sshea:encryption-alg-base; + } + ordered-by user; + description + "Acceptable encryption algorithms in order of descending + preference. + + If this leaf-list is not configured (has zero elements) + the acceptable encryption algorithms are implementation + defined."; + } + } + container mac { + description + "Parameters regarding message authentication code (MAC)."; + leaf-list mac-alg { + type identityref { + base sshma:mac-alg-base; + } + ordered-by user; + description + "Acceptable MAC algorithms in order of descending + preference. + + If this leaf-list is not configured (has zero elements) + the acceptable MAC algorithms are implementation- + defined."; + } + } + } + + // Protocol-accessible Nodes + + rpc generate-public-key { + if-feature "public-key-generation"; + description + "Requests the device to generate an public key using + the specified key algorithm."; + input { + leaf algorithm { + type sshpka:public-key-algorithm-ref; + mandatory true; + description + "The algorithm to be used when generating the key."; + } + leaf bits { + type uint16; + description + "Specifies the number of bits in the key to create. + For RSA keys, the minimum size is 1024 bits and + the default is 3072 bits. Generally, 3072 bits is + considered sufficient. DSA keys must be exactly 1024 + bits as specified by FIPS 186-2. For ECDSA keys, the + 'bits' value determines the key length by selecting + from one of three elliptic curve sizes: 256, 384 or + 521 bits. Attempting to use bit lengths other than + these three values for ECDSA keys will fail. ECDSA-SK, + Ed25519 and Ed25519-SK keys have a fixed length and + the 'bits' value, if specified, will be ignored."; + } + choice private-key-encoding { + default cleartext; + description + "A choice amongst optional private key handling."; + case cleartext { + leaf cleartext { + type empty; + description + "Indicates that the private key is to be returned + as a cleartext value."; + } + } + case encrypt { + if-feature "ct:private-key-encryption"; + container encrypt-with { + description + "Indicates that the key is to be encrypted using + the specified symmetric or asymmetric key."; + uses ks:encrypted-by-choice-grouping; + } + } + case hide { + if-feature "ct:hidden-keys"; + leaf hide { + type empty; + description + "Indicates that the private key is to be hidden. + + Unlike the 'cleartext' and 'encrypt' options, the + key returned is a placeholder for an internally + stored key. See the 'Support for Built-in Keys' + section in RFC CCCC for information about hidden + keys."; + } + } + } + } + output { + uses ct:asymmetric-key-pair-grouping; + } + } // end generate-public-key + +} diff --git a/modules/ietf-ssh-server@2022-07-18.yang b/modules/ietf-ssh-server@2022-07-18.yang new file mode 100644 index 00000000..2dd04bd9 --- /dev/null +++ b/modules/ietf-ssh-server@2022-07-18.yang @@ -0,0 +1,414 @@ +module ietf-ssh-server { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-ssh-server"; + prefix sshs; + + import iana-crypt-hash { + prefix ianach; + reference + "RFC 7317: A YANG Data Model for System Management"; + } + + import ietf-netconf-acm { + prefix nacm; + reference + "RFC 8341: Network Configuration Access Control Model"; + } + + import ietf-crypto-types { + prefix ct; + reference + "RFC AAAA: YANG Data Types and Groupings for Cryptography"; + } + + import ietf-truststore { + prefix ts; + reference + "RFC BBBB: A YANG Data Model for a Truststore"; + } + + import ietf-keystore { + prefix ks; + reference + "RFC CCCC: A YANG Data Model for a Keystore"; + } + + import ietf-ssh-common { + prefix sshcmn; + revision-date 2022-07-18; // stable grouping definitions + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: https://datatracker.ietf.org/wg/netconf + WG List: NETCONF WG list + Author: Kent Watsen + Author: Gary Wu "; + + description + "This module defines reusable groupings for SSH servers that + can be used as a basis for specific SSH server instances. + + Copyright (c) 2022 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC EEEE + (https://www.rfc-editor.org/info/rfcEEEE); see the RFC + itself for full legal notices. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2022-07-18 { + description + "Initial version"; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + // Features + + feature ssh-server-keepalives { + description + "Per socket SSH keepalive parameters are configurable for + SSH servers on the server implementing this feature."; + } + + feature local-users-supported { + description + "Indicates that the configuration for users can be + configured herein, as opposed to in an application + specific location."; + } + + feature local-user-auth-publickey { + if-feature "local-users-supported"; + description + "Indicates that the 'publickey' authentication type, + per RFC 4252, is supported for locally-defined users. + + The 'publickey' authentication type is required by + RFC 4252, but common implementations enable it to + be disabled."; + reference + "RFC 4252: + The Secure Shell (SSH) Authentication Protocol"; + } + + feature local-user-auth-password { + if-feature "local-users-supported"; + description + "Indicates that the 'password' authentication type, + per RFC 4252, is supported for locally-defined users."; + reference + "RFC 4252: + The Secure Shell (SSH) Authentication Protocol"; + } + + feature local-user-auth-hostbased { + if-feature "local-users-supported"; + description + "Indicates that the 'hostbased' authentication type, + per RFC 4252, is supported for locally-defined users."; + reference + "RFC 4252: + The Secure Shell (SSH) Authentication Protocol"; + } + + feature local-user-auth-none { + if-feature "local-users-supported"; + description + "Indicates that the 'none' authentication type, per + RFC 4252, is supported. It is NOT RECOMMENDED to + enable this feature."; + reference + "RFC 4252: + The Secure Shell (SSH) Authentication Protocol"; + } + + // Groupings + + grouping ssh-server-grouping { + description + "A reusable grouping for configuring a SSH server without + any consideration for how underlying TCP sessions are + established. + + Note that this grouping uses fairly typical descendant + node names such that a stack of 'uses' statements will + have name conflicts. It is intended that the consuming + data model will resolve the issue (e.g., by wrapping + the 'uses' statement in a container called + 'ssh-server-parameters'). This model purposely does + not do this itself so as to provide maximum flexibility + to consuming models."; + + container server-identity { + nacm:default-deny-write; + description + "The list of host keys the SSH server will present when + establishing a SSH connection."; + list host-key { + key "name"; + min-elements 1; + ordered-by user; + description + "An ordered list of host keys the SSH server will use to + construct its ordered list of algorithms, when sending + its SSH_MSG_KEXINIT message, as defined in Section 7.1 + of RFC 4253."; + reference + "RFC 4253: The Secure Shell (SSH) Transport Layer + Protocol"; + leaf name { + type string; + description + "An arbitrary name for this host key"; + } + choice host-key-type { + mandatory true; + description + "The type of host key being specified"; + container public-key { + description + "A locally-defined or referenced asymmetric key pair + to be used for the SSH server's host key."; + reference + "RFC CCCC: A YANG Data Model for a Keystore"; + uses ks:local-or-keystore-asymmetric-key-grouping { + refine "local-or-keystore/local/local-definition" { + must + 'public-key-format = "ct:ssh-public-key-format"'; + } + refine "local-or-keystore/keystore/" + + "keystore-reference" { + must 'deref(.)/../ks:public-key-format' + + ' = "ct:ssh-public-key-format"'; + } + } + } + container certificate { + if-feature "sshcmn:ssh-x509-certs"; + description + "A locally-defined or referenced end-entity + certificate to be used for the SSH server's + host key."; + reference + "RFC CCCC: A YANG Data Model for a Keystore"; + uses + ks:local-or-keystore-end-entity-cert-with-key-grouping { + refine "local-or-keystore/local/local-definition" { + must 'public-key-format' + + ' = "ct:subject-public-key-info-format"'; + } + refine "local-or-keystore/keystore/keystore-reference" + + "/asymmetric-key" { + must 'deref(.)/../ks:public-key-format' + + ' = "ct:subject-public-key-info-format"'; + } + } + } + } + } + } // container server-identity + + container client-authentication { + nacm:default-deny-write; + description + "Specifies how the SSH server can authenticate SSH clients."; + container users { + if-feature "local-users-supported"; + description + "A list of locally configured users."; + list user { + key "name"; + description + "A locally configured user. + + The server SHOULD derive the list of authentication + 'method names' returned to the SSH client from the + descendant nodes configured herein, per Sections + 5.1 and 5.2 in RFC 4252. + + The authentication methods are unordered. Clients + must authenticate to all configured methods. + Whenever a choice amongst methods arises, + implementations SHOULD use a default ordering + that prioritizes automation over human-interaction."; + leaf name { + type string; + description + "The 'user name' for the SSH client, as defined in + the SSH_MSG_USERAUTH_REQUEST message in RFC 4253."; + } + container public-keys { + if-feature "local-user-auth-publickey"; + presence + "Indicates that public keys have been configured. + This statement is present so the mandatory descendant + nodes do not imply that this node must be + configured."; + description + "A set of SSH public keys may be used by the SSH + server to authenticate this user. A user is + authenticated if its public key is an exact + match to a configured public key."; + reference + "RFC BBBB: A YANG Data Model for a Truststore"; + uses ts:local-or-truststore-public-keys-grouping { + refine "local-or-truststore/local/local-definition" + + "/public-key" { + must 'public-key-format' + + ' = "ct:ssh-public-key-format"'; + } + refine "local-or-truststore/truststore/" + + "truststore-reference" { + must 'deref(.)/../*/ts:public-key-format' + + ' = "ct:ssh-public-key-format"'; + } + } + } + leaf password { + if-feature "local-user-auth-password"; + type ianach:crypt-hash; + description + "The password for this user."; + } + container hostbased { + if-feature "local-user-auth-hostbased"; + presence + "Indicates that hostbased keys have been configured. + This statement is present so the mandatory descendant + nodes do not imply that this node must be + configured."; + description + "A set of SSH host keys used by the SSH server to + authenticate this user's host. A user's host is + authenticated if its host key is an exact match + to a configured host key."; + reference + "RFC 4253: The Secure Shell (SSH) Transport Layer + RFC BBBB: A YANG Data Model for a Truststore"; + uses ts:local-or-truststore-public-keys-grouping { + refine "local-or-truststore/local/local-definition" + + "/public-key" { + must 'public-key-format' + + ' = "ct:ssh-public-key-format"'; + } + refine "local-or-truststore/truststore" + + "/truststore-reference" { + must 'deref(.)/../*/ts:public-key-format' + + ' = "ct:ssh-public-key-format"'; + } + } + } + leaf none { + if-feature "local-user-auth-none"; + type empty; + description + "Indicates that the 'none' method is configured + for this user."; + reference + "RFC 4252: The Secure Shell (SSH) Authentication + Protocol."; + } + } + } + container ca-certs { + if-feature "sshcmn:ssh-x509-certs"; + presence + "Indicates that CA certificates have been configured. + This statement is present so the mandatory descendant + nodes do not imply this node must be configured."; + description + "A set of certificate authority (CA) certificates used by + the SSH server to authenticate SSH client certificates. + A client certificate is authenticated if it has a valid + chain of trust to a configured CA certificate."; + reference + "RFC BBBB: A YANG Data Model for a Truststore"; + uses ts:local-or-truststore-certs-grouping; + } + container ee-certs { + if-feature "sshcmn:ssh-x509-certs"; + presence + "Indicates that EE certificates have been configured. + This statement is present so the mandatory descendant + nodes do not imply this node must be configured."; + description + "A set of client certificates (i.e., end entity + certificates) used by the SSH server to authenticate + the certificates presented by SSH clients. A client + certificate is authenticated if it is an exact match + to a configured end-entity certificate."; + reference + "RFC BBBB: A YANG Data Model for a Truststore"; + uses ts:local-or-truststore-certs-grouping; + } + } // container client-authentication + + container transport-params { + nacm:default-deny-write; + if-feature "sshcmn:transport-params"; + description + "Configurable parameters of the SSH transport layer."; + uses sshcmn:transport-params-grouping; + } // container transport-params + + container keepalives { + nacm:default-deny-write; + if-feature "ssh-server-keepalives"; + presence + "Indicates that the SSH server proactively tests the + aliveness of the remote SSH client."; + description + "Configures the keep-alive policy, to proactively test + the aliveness of the SSL client. An unresponsive SSL + client is dropped after approximately max-wait * + max-attempts seconds. Per Section 4 of RFC 4254, + the SSH server SHOULD send an SSH_MSG_GLOBAL_REQUEST + message with a purposely nonexistent 'request name' + value (e.g., keepalive@ietf.org) and the 'want reply' + value set to '1'."; + reference + "RFC 4254: The Secure Shell (SSH) Connection Protocol"; + leaf max-wait { + type uint16 { + range "1..max"; + } + units "seconds"; + default "30"; + description + "Sets the amount of time in seconds after which + if no data has been received from the SSL client, + a SSL-level message will be sent to test the + aliveness of the SSL client."; + } + leaf max-attempts { + type uint8; + default "3"; + description + "Sets the maximum number of sequential keep-alive + messages that can fail to obtain a response from + the SSL client before assuming the SSL client is + no longer alive."; + } + } + } // grouping ssh-server-grouping + +} diff --git a/modules/ietf-tcp-client@2022-05-24.yang b/modules/ietf-tcp-client@2022-05-24.yang new file mode 100644 index 00000000..4426353e --- /dev/null +++ b/modules/ietf-tcp-client@2022-05-24.yang @@ -0,0 +1,316 @@ +module ietf-tcp-client { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-tcp-client"; + prefix tcpc; + + import ietf-inet-types { + prefix inet; + reference + "RFC 6991: Common YANG Data Types"; + } + + import ietf-crypto-types { + prefix ct; + reference + "RFC AAAA: YANG Data Types and Groupings for Cryptography"; + } + + import ietf-tcp-common { + prefix tcpcmn; + reference + "RFC DDDD: YANG Groupings for TCP Clients and TCP Servers"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group and the + IETF TCP Maintenance and Minor Extensions (TCPM) Working Group"; + + contact + "WG Web: https://datatracker.ietf.org/wg/netconf + https://datatracker.ietf.org/wg/tcpm + WG List: NETCONF WG list + TCPM WG list + Authors: Kent Watsen + Michael Scharf + "; + + description + "This module defines reusable groupings for TCP clients that + can be used as a basis for specific TCP client instances. + + Copyright (c) 2022 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC DDDD + (https://www.rfc-editor.org/info/rfcDDDD); see the RFC + itself for full legal notices. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2022-05-24 { + description + "Initial version"; + reference + "RFC DDDD: YANG Groupings for TCP Clients and TCP Servers"; + } + + // Features + + feature local-binding-supported { + description + "Indicates that the server supports configuring local + bindings (i.e., the local address and local port) for + TCP clients."; + } + + feature tcp-client-keepalives { + description + "Per socket TCP keepalive parameters are configurable for + TCP clients on the server implementing this feature."; + } + + feature proxy-connect { + description + "Proxy connection configuration is configurable for + TCP clients on the server implementing this feature."; + } + + feature socks5-gss-api { + description + "Indicates that the server supports authenticating + using GSSAPI when initiating TCP connections via + and SOCKS Version 5 proxy server."; + reference + "RFC 1928: SOCKS Protocol Version 5"; + } + + feature socks5-username-password { + description + "Indicates that the server supports authenticating using + username/password when initiating TCP connections via + and SOCKS Version 5 proxy server."; + reference + "RFC 1928: SOCKS Protocol Version 5"; + } + + // Groupings + + grouping tcp-client-grouping { + description + "A reusable grouping for configuring a TCP client. + + Note that this grouping uses fairly typical descendant + node names such that a stack of 'uses' statements will + have name conflicts. It is intended that the consuming + data model will resolve the issue (e.g., by wrapping + the 'uses' statement in a container called + 'tcp-client-parameters'). This model purposely does + not do this itself so as to provide maximum flexibility + to consuming models."; + + leaf remote-address { + type inet:host; + mandatory true; + description + "The IP address or hostname of the remote peer to + establish a connection with. If a domain name is + configured, then the DNS resolution should happen on + each connection attempt. If the DNS resolution + results in multiple IP addresses, the IP addresses + are tried according to local preference order until + a connection has been established or until all IP + addresses have failed."; + } + leaf remote-port { + type inet:port-number; + default "0"; + description + "The IP port number for the remote peer to establish a + connection with. An invalid default value (0) is used + (instead of 'mandatory true') so that as application + level data model may 'refine' it with an application + specific default port number value."; + } + leaf local-address { + if-feature "local-binding-supported"; + type inet:ip-address; + description + "The local IP address/interface (VRF?) to bind to for when + connecting to the remote peer. INADDR_ANY ('0.0.0.0') or + INADDR6_ANY ('0:0:0:0:0:0:0:0' a.k.a. '::') MAY be used to + explicitly indicate the implicit default, that the server + can bind to any IPv4 or IPv6 addresses, respectively."; + } + leaf local-port { + if-feature "local-binding-supported"; + type inet:port-number; + default "0"; + description + "The local IP port number to bind to for when connecting + to the remote peer. The port number '0', which is the + default value, indicates that any available local port + number may be used."; + } + container proxy-server { + if-feature "proxy-connect"; + presence + "Indicates that a proxy connection has been configured. + Present so that the mandatory descendant nodes do not + imply that this node must be configured."; + choice proxy-type { + mandatory true; + description + "Selects a proxy connection protocol."; + case socks4 { + container socks4-parameters { + leaf remote-address { + type inet:ip-address; + mandatory true; + description + "The IP address of the proxy server."; + } + leaf remote-port { + type inet:port-number; + default "1080"; + description + "The IP port number for the proxy server."; + } + description + "Parameters for connecting to a TCP-based proxy + server using the SOCKS4 protocol."; + reference + "SOCKS, Proceedings: 1992 Usenix Security Symposium."; + } + } + case socks4a { + container socks4a-parameters { + leaf remote-address { + type inet:host; + mandatory true; + description + "The IP address or hostname of the proxy server."; + } + leaf remote-port { + type inet:port-number; + default "1080"; + description + "The IP port number for the proxy server."; + } + description + "Parameters for connecting to a TCP-based proxy + server using the SOCKS4a protocol."; + reference + "SOCKS Proceedings: + 1992 Usenix Security Symposium. + OpenSSH message: + SOCKS 4A: A Simple Extension to SOCKS 4 Protocol + https://www.openssh.com/txt/socks4a.protocol"; + } + } + case socks5 { + container socks5-parameters { + leaf remote-address { + type inet:host; + mandatory true; + description + "The IP address or hostname of the proxy server."; + } + leaf remote-port { + type inet:port-number; + default "1080"; + description + "The IP port number for the proxy server."; + } + container authentication-parameters { + presence + "Indicates that an authentication mechanism + has been configured. Present so that the + mandatory descendant nodes do not imply that + this node must be configured."; + description + "A container for SOCKS Version 5 authentication + mechanisms. + + A complete list of methods is defined at: + https://www.iana.org/assignments/socks-methods + /socks-methods.xhtml."; + reference + "RFC 1928: SOCKS Protocol Version 5"; + choice auth-type { + mandatory true; + description + "A choice amongst supported SOCKS Version 5 + authentication mechanisms."; + case gss-api { + if-feature "socks5-gss-api"; + container gss-api { + description + "Contains GSS-API configuration. Defines + as an empty container to enable specific + GSS-API configuration to be augmented in + by future modules."; + reference + "RFC 1928: SOCKS Protocol Version 5 + RFC 2743: Generic Security Service + Application Program Interface + Version 2, Update 1"; + } + } + case username-password { + if-feature "socks5-username-password"; + container username-password { + leaf username { + type string; + mandatory true; + description + "The 'username' value to use for client + identification."; + } + uses ct:password-grouping { + description + "The password to be used for client + authentication."; + } + description + "Contains Username/Password configuration."; + reference + "RFC 1929: Username/Password Authentication + for SOCKS V5"; + } + } + } + } + description + "Parameters for connecting to a TCP-based proxy server + using the SOCKS5 protocol."; + reference + "RFC 1928: SOCKS Protocol Version 5"; + } + } + } + description + "Proxy server settings."; + } + + uses tcpcmn:tcp-common-grouping { + augment "keepalives" { + if-feature "tcp-client-keepalives"; + description + "Add an if-feature statement so that implementations + can choose to support TCP client keepalives."; + } + } + } +} diff --git a/modules/ietf-tcp-common@2022-05-24.yang b/modules/ietf-tcp-common@2022-05-24.yang new file mode 100644 index 00000000..e9a927d5 --- /dev/null +++ b/modules/ietf-tcp-common@2022-05-24.yang @@ -0,0 +1,115 @@ +module ietf-tcp-common { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-tcp-common"; + prefix tcpcmn; + + organization + "IETF NETCONF (Network Configuration) Working Group and the + IETF TCP Maintenance and Minor Extensions (TCPM) Working Group"; + + contact + "WG Web: https://datatracker.ietf.org/wg/netconf + https://datatracker.ietf.org/wg/tcpm + WG List: NETCONF WG list + TCPM WG list + Authors: Kent Watsen + Michael Scharf + "; + + description + "This module defines reusable groupings for TCP commons that + can be used as a basis for specific TCP common instances. + + Copyright (c) 2022 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC DDDD + (https://www.rfc-editor.org/info/rfcDDDD); see the RFC + itself for full legal notices. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2022-05-24 { + description + "Initial version"; + reference + "RFC DDDD: YANG Groupings for TCP Clients and TCP Servers"; + } + + // Features + + feature keepalives-supported { + description + "Indicates that keepalives are supported."; + } + + // Groupings + + grouping tcp-common-grouping { + description + "A reusable grouping for configuring TCP parameters common + to TCP connections as well as the operating system as a + whole."; + container keepalives { + if-feature "keepalives-supported"; + presence + "Indicates that keepalives are enabled. This statement is + present so the mandatory descendant nodes do not imply that + this node must be configured."; + description + "Configures the keep-alive policy, to proactively test the + aliveness of the TCP peer. An unresponsive TCP peer is + dropped after approximately (idle-time + max-probes + * probe-interval) seconds."; + leaf idle-time { + type uint16 { + range "1..max"; + } + units "seconds"; + mandatory true; + description + "Sets the amount of time after which if no data has been + received from the TCP peer, a TCP-level probe message + will be sent to test the aliveness of the TCP peer. + Two hours (7200 seconds) is safe value, per RFC 1122."; + reference + "RFC 1122: + Requirements for Internet Hosts -- Communication Layers"; + } + leaf max-probes { + type uint16 { + range "1..max"; + } + mandatory true; + description + "Sets the maximum number of sequential keep-alive probes + that can fail to obtain a response from the TCP peer + before assuming the TCP peer is no longer alive."; + } + leaf probe-interval { + type uint16 { + range "1..max"; + } + units "seconds"; + mandatory true; + description + "Sets the time interval between failed probes. The interval + SHOULD be significantly longer than one second in order to + avoid harm on a congested link."; + } + } // container keepalives + } // grouping tcp-common-grouping + +} diff --git a/modules/ietf-tcp-server@2022-05-24.yang b/modules/ietf-tcp-server@2022-05-24.yang new file mode 100644 index 00000000..b465dfe5 --- /dev/null +++ b/modules/ietf-tcp-server@2022-05-24.yang @@ -0,0 +1,114 @@ +module ietf-tcp-server { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-tcp-server"; + prefix tcps; + + import ietf-inet-types { + prefix inet; + reference + "RFC 6991: Common YANG Data Types"; + } + + import ietf-tcp-common { + prefix tcpcmn; + reference + "RFC DDDD: YANG Groupings for TCP Clients and TCP Servers"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group and the + IETF TCP Maintenance and Minor Extensions (TCPM) Working Group"; + + contact + "WG Web: https://datatracker.ietf.org/wg/netconf + https://datatracker.ietf.org/wg/tcpm + WG List: NETCONF WG list + TCPM WG list + Authors: Kent Watsen + Michael Scharf + "; + + description + "This module defines reusable groupings for TCP servers that + can be used as a basis for specific TCP server instances. + + Copyright (c) 2022 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC DDDD + (https://www.rfc-editor.org/info/rfcDDDD); see the RFC + itself for full legal notices. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2022-05-24 { + description + "Initial version"; + reference + "RFC DDDD: YANG Groupings for TCP Clients and TCP Servers"; + } + + // Features + + feature tcp-server-keepalives { + description + "Per socket TCP keepalive parameters are configurable for + TCP servers on the server implementing this feature."; + } + + // Groupings + + grouping tcp-server-grouping { + description + "A reusable grouping for configuring a TCP server. + + Note that this grouping uses fairly typical descendant + node names such that a stack of 'uses' statements will + have name conflicts. It is intended that the consuming + data model will resolve the issue (e.g., by wrapping + the 'uses' statement in a container called + 'tcp-server-parameters'). This model purposely does + not do this itself so as to provide maximum flexibility + to consuming models."; + leaf local-address { + type inet:ip-address; + mandatory true; + description + "The local IP address to listen on for incoming + TCP client connections. INADDR_ANY (0.0.0.0) or + INADDR6_ANY (0:0:0:0:0:0:0:0 a.k.a. ::) MUST be + used when the server is to listen on all IPv4 or + IPv6 addresses, respectively."; + } + leaf local-port { + type inet:port-number; + default "0"; + description + "The local port number to listen on for incoming TCP + client connections. An invalid default value (0) + is used (instead of 'mandatory true') so that an + application level data model may 'refine' it with + an application specific default port number value."; + } + uses tcpcmn:tcp-common-grouping { + augment "keepalives" { + if-feature "tcp-server-keepalives"; + description + "Add an if-feature statement so that implementations + can choose to support TCP server keepalives."; + } + } + } +} diff --git a/modules/ietf-tls-common@2022-07-18.yang b/modules/ietf-tls-common@2022-07-18.yang new file mode 100644 index 00000000..fb48c4cd --- /dev/null +++ b/modules/ietf-tls-common@2022-07-18.yang @@ -0,0 +1,311 @@ +module ietf-tls-common { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-tls-common"; + prefix tlscmn; + + import iana-tls-cipher-suite-algs { + prefix tlscsa; + reference + "RFC FFFF: YANG Groupings for TLS Clients and SSH Servers"; + } + + import ietf-crypto-types { + prefix ct; + reference + "RFC AAAA: YANG Data Types and Groupings for Cryptography"; + } + + import ietf-keystore { + prefix ks; + reference + "RFC CCCC: A YANG Data Model for a Keystore"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG List: NETCONF WG list + WG Web: https://datatracker.ietf.org/wg/netconf + Author: Kent Watsen + Author: Jeff Hartley + Author: Gary Wu "; + + description + "This module defines a common features and groupings for + Transport Layer Security (TLS). + + Copyright (c) 2022 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC FFFF + (https://www.rfc-editor.org/info/rfcFFFF); see the RFC + itself for full legal notices. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2022-07-18 { + description + "Initial version"; + reference + "RFC FFFF: YANG Groupings for TLS Clients and TLS Servers"; + } + + // Features + + feature tls10 { + status "obsolete"; + description + "TLS Protocol Version 1.0 is supported. TLS 1.0 is obsolete + and thus it is NOT RECOMMENDED to enable this feature."; + reference + "RFC 2246: The TLS Protocol Version 1.0"; + } + + feature tls11 { + status "obsolete"; + description + "TLS Protocol Version 1.1 is supported. TLS 1.1 is obsolete + and thus it is NOT RECOMMENDED to enable this feature."; + reference + "RFC 4346: The Transport Layer Security (TLS) Protocol + Version 1.1"; + } + + feature tls12 { + status "deprecated"; + description + "TLS Protocol Version 1.2 is supported TLS 1.2 is obsolete + and thus it is NOT RECOMMENDED to enable this feature."; + reference + "RFC 5246: The Transport Layer Security (TLS) Protocol + Version 1.2"; + } + + feature tls13 { + description + "TLS Protocol Version 1.3 is supported."; + reference + "RFC 8446: The Transport Layer Security (TLS) + Protocol Version 1.3"; + } + + feature hello-params { + description + "TLS hello message parameters are configurable."; + } + + feature public-key-generation { + description + "Indicates that the server implements the + 'generate-public-key' RPC."; + } + + // Identities + + identity tls-version-base { + description + "Base identity used to identify TLS protocol versions."; + } + + identity tls10 { + if-feature "tls10"; + base tls-version-base; + status "obsolete"; + description + "TLS Protocol Version 1.0."; + reference + "RFC 2246: The TLS Protocol Version 1.0"; + } + + identity tls11 { + if-feature "tls11"; + base tls-version-base; + status "obsolete"; + description + "TLS Protocol Version 1.1."; + reference + "RFC 4346: The Transport Layer Security (TLS) Protocol + Version 1.1"; + } + + identity tls12 { + if-feature "tls12"; + base tls-version-base; + status "deprecated"; + description + "TLS Protocol Version 1.2."; + reference + "RFC 5246: The Transport Layer Security (TLS) Protocol + Version 1.2"; + } + + identity tls13 { + if-feature "tls13"; + base tls-version-base; + description + "TLS Protocol Version 1.3."; + reference + "RFC 8446: The Transport Layer Security (TLS) + Protocol Version 1.3"; + } + + typedef epsk-supported-hash { + type enumeration { + enum sha-256 { + description + "The SHA-256 Hash."; + } + enum sha-384 { + description + "The SHA-384 Hash."; + } + } + description + "As per Section 4.2.11 of RFC 8446, the hash algorithm + supported by an instance of an External Pre-Shared + Key (EPSK)."; + reference + "RFC 8446: The Transport Layer Security (TLS) + Protocol Version 1.3 + I-D.ietf-tls-external-psk-importer: Importing + External PSKs for TLS + I-D.ietf-tls-external-psk-guidance: Guidance + for External PSK Usage in TLS"; + } + + // Groupings + + grouping hello-params-grouping { + description + "A reusable grouping for TLS hello message parameters."; + reference + "RFC 5246: The Transport Layer Security (TLS) Protocol + Version 1.2 + RFC 8446: The Transport Layer Security (TLS) Protocol + Version 1.3"; + container tls-versions { + description + "Parameters regarding TLS versions."; + leaf-list tls-version { + type identityref { + base tls-version-base; + } + description + "Acceptable TLS protocol versions. + + If this leaf-list is not configured (has zero elements) + the acceptable TLS protocol versions are implementation- + defined."; + } + } + container cipher-suites { + description + "Parameters regarding cipher suites."; + leaf-list cipher-suite { + type identityref { + base tlscsa:cipher-suite-alg-base; + } + ordered-by user; + description + "Acceptable cipher suites in order of descending + preference. The configured host key algorithms should + be compatible with the algorithm used by the configured + private key. Please see Section 5 of RFC FFFF for + valid combinations. + + If this leaf-list is not configured (has zero elements) + the acceptable cipher suites are implementation- + defined."; + reference + "RFC FFFF: YANG Groupings for TLS Clients and TLS Servers"; + } + } + } // hello-params-grouping + + rpc generate-public-key { + if-feature "public-key-generation"; + description + "Requests the device to generate an public key using + the specified key algorithm."; + input { + leaf algorithm { + type tlscsa:cipher-suite-algorithm-ref; + mandatory true; + description + "The cipher suite algorithm that the generated key is + to work with. Implementations derive the public key + algorithm from the cipher suite algorithm. Example: + cipher suite 'tls-rsa-with-aes-256-cbc-sha256' maps + to the RSA public key."; + } + leaf bits { + type uint16; + description + "Specifies the number of bits in the key to create. + For RSA keys, the minimum size is 1024 bits and + the default is 3072 bits. Generally, 3072 bits is + considered sufficient. DSA keys must be exactly 1024 + bits as specified by FIPS 186-2. For elliptical + keys, the 'bits' value determines the key length + of the curve (e.g., 256, 384 or 521), where valid + values supported by the server are conveyed via an + unspecified mechanism. For some public algorithms, + the keys have a fixed length and the 'bits' value, + if specified, will be ignored."; + } + choice private-key-encoding { + default cleartext; + description + "A choice amongst optional private key handling."; + case cleartext { + leaf cleartext { + type empty; + description + "Indicates that the private key is to be returned + as a cleartext value."; + } + } + case encrypt { + if-feature "ct:private-key-encryption"; + container encrypt-with { + description + "Indicates that the key is to be encrypted using + the specified symmetric or asymmetric key."; + uses ks:encrypted-by-choice-grouping; + } + } + case hide { + if-feature "ct:hidden-keys"; + leaf hide { + type empty; + description + "Indicates that the private key is to be hidden. + + Unlike the 'cleartext' and 'encrypt' options, the + key returned is a placeholder for an internally + stored key. See the 'Support for Built-in Keys' + section in RFC CCCC for information about hidden + keys."; + } + } + } + } + output { + uses ct:asymmetric-key-pair-grouping; + } + } // end generate-public-key + +} diff --git a/modules/ietf-tls-server@2022-07-18.yang b/modules/ietf-tls-server@2022-07-18.yang new file mode 100644 index 00000000..971bd18c --- /dev/null +++ b/modules/ietf-tls-server@2022-07-18.yang @@ -0,0 +1,525 @@ +module ietf-tls-server { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-tls-server"; + prefix tlss; + + import ietf-netconf-acm { + prefix nacm; + reference + "RFC 8341: Network Configuration Access Control Model"; + } + + import ietf-crypto-types { + prefix ct; + reference + "RFC AAAA: YANG Data Types and Groupings for Cryptography"; + } + + import ietf-truststore { + prefix ts; + reference + "RFC BBBB: A YANG Data Model for a Truststore"; + } + + import ietf-keystore { + prefix ks; + reference + "RFC CCCC: A YANG Data Model for a Keystore"; + } + + import ietf-tls-common { + prefix tlscmn; + revision-date 2022-07-18; // stable grouping definitions + reference + "RFC FFFF: YANG Groupings for TLS Clients and TLS Servers"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG List: NETCONF WG list + WG Web: https://datatracker.ietf.org/wg/netconf + Author: Kent Watsen + Author: Jeff Hartley + Author: Gary Wu "; + + description + "This module defines reusable groupings for TLS servers that + can be used as a basis for specific TLS server instances. + + Copyright (c) 2022 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC FFFF + (https://www.rfc-editor.org/info/rfcFFFF); see the RFC + itself for full legal notices. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2022-07-18 { + description + "Initial version"; + reference + "RFC FFFF: YANG Groupings for TLS Clients and TLS Servers"; + } + + // Features + + feature tls-server-keepalives { + description + "Per socket TLS keepalive parameters are configurable for + TLS servers on the server implementing this feature."; + } + + feature server-ident-x509-cert { + description + "Indicates that the server supports identifying itself + using X.509 certificates."; + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile"; + } + + feature server-ident-raw-public-key { + description + "Indicates that the server supports identifying itself + using raw public keys."; + reference + "RFC 7250: + Using Raw Public Keys in Transport Layer Security (TLS) + and Datagram Transport Layer Security (DTLS)"; + } + + feature server-ident-tls12-psk { + description + "Indicates that the server supports identifying itself + using TLS-1.2 PSKs (pre-shared or pairwise-symmetric keys)."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS)"; + } + + feature server-ident-tls13-epsk { + description + "Indicates that the server supports identifying itself + using TLS-1.3 External PSKs (pre-shared keys)."; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + feature client-auth-supported { + description + "Indicates that the configuration for how to authenticate + clients can be configured herein. TLS-level client + authentication may not be needed when client authentication + is expected to occur only at another protocol layer."; + } + + feature client-auth-x509-cert { + description + "Indicates that the server supports authenticating clients + using X.509 certificates."; + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile"; + } + + feature client-auth-raw-public-key { + description + "Indicates that the server supports authenticating clients + using raw public keys."; + reference + "RFC 7250: + Using Raw Public Keys in Transport Layer Security (TLS) + and Datagram Transport Layer Security (DTLS)"; + } + + feature client-auth-tls12-psk { + description + "Indicates that the server supports authenticating clients + using PSKs (pre-shared or pairwise-symmetric keys)."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS)"; + } + + feature client-auth-tls13-epsk { + description + "Indicates that the server supports authenticating clients + using TLS-1.3 External PSKs (pre-shared keys)."; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + // Groupings + + grouping tls-server-grouping { + description + "A reusable grouping for configuring a TLS server without + any consideration for how underlying TCP sessions are + established. + + Note that this grouping uses fairly typical descendant + node names such that a stack of 'uses' statements will + have name conflicts. It is intended that the consuming + data model will resolve the issue (e.g., by wrapping + the 'uses' statement in a container called + 'tls-server-parameters'). This model purposely does + not do this itself so as to provide maximum flexibility + to consuming models."; + + container server-identity { + nacm:default-deny-write; + description + "A locally-defined or referenced end-entity certificate, + including any configured intermediate certificates, the + TLS server will present when establishing a TLS connection + in its Certificate message, as defined in Section 7.4.2 + in RFC 5246 and Section 4.4.2 in RFC 8446."; + reference + "RFC 5246: The Transport Layer Security (TLS) Protocol + Version 1.2 + RFC 8446: The Transport Layer Security (TLS) Protocol + Version 1.3 + RFC CCCC: A YANG Data Model for a Keystore"; + choice auth-type { + mandatory true; + description + "A choice amongst authentication types, of which one must + be enabled (via its associated 'feature') and selected."; + case certificate { + if-feature "server-ident-x509-cert"; + container certificate { + description + "Specifies the server identity using a certificate."; + uses + ks:local-or-keystore-end-entity-cert-with-key-grouping{ + refine "local-or-keystore/local/local-definition" { + must 'public-key-format' + + ' = "ct:subject-public-key-info-format"'; + } + refine "local-or-keystore/keystore/keystore-reference" + + "/asymmetric-key" { + must 'deref(.)/../ks:public-key-format' + + ' = "ct:subject-public-key-info-format"'; + } + } + } + } + case raw-private-key { + if-feature "server-ident-raw-public-key"; + container raw-private-key { + description + "Specifies the server identity using a raw + private key."; + uses ks:local-or-keystore-asymmetric-key-grouping { + refine "local-or-keystore/local/local-definition" { + must 'public-key-format' + + ' = "ct:subject-public-key-info-format"'; + } + refine "local-or-keystore/keystore/keystore-reference"{ + must 'deref(.)/../ks:public-key-format' + + ' = "ct:subject-public-key-info-format"'; + } + } + } + } + case tls12-psk { + if-feature "server-ident-tls12-psk"; + container tls12-psk { + description + "Specifies the server identity using a PSK (pre-shared + or pairwise-symmetric key)."; + uses ks:local-or-keystore-symmetric-key-grouping; + leaf id_hint { + type string; + description + "The key 'psk_identity_hint' value used in the TLS + 'ServerKeyExchange' message."; + reference + "RFC 4279: Pre-Shared Key Ciphersuites for + Transport Layer Security (TLS)"; + } + } + } + case tls13-epsk { + if-feature "server-ident-tls13-epsk"; + container tls13-epsk { + description + "An External Pre-Shared Key (EPSK) is established + or provisioned out-of-band, i.e., not from a TLS + connection. An EPSK is a tuple of (Base Key, + External Identity, Hash). External PSKs MUST + NOT be imported for (D)TLS 1.2 or prior versions. + When PSKs are provisioned out of band, the PSK + identity and the KDF hash algorithm to be used + with the PSK MUST also be provisioned. + + The structure of this container is designed + to satisfy the requirements of RFC 8446 + Section 4.2.11, the recommendations from + I-D ietf-tls-external-psk-guidance Section 6, + and the EPSK input fields detailed in + I-D draft-ietf-tls-external-psk-importer + Section 3.1. The base-key is based upon + ks:local-or-keystore-symmetric-key-grouping + in order to provide users with flexible and + secure storage options."; + reference + "RFC 8446: The Transport Layer Security (TLS) + Protocol Version 1.3 + I-D.ietf-tls-external-psk-importer: Importing + External PSKs for TLS + I-D.ietf-tls-external-psk-guidance: Guidance + for External PSK Usage in TLS"; + uses ks:local-or-keystore-symmetric-key-grouping; + leaf external-identity { + type string; + mandatory true; + description + "As per Section 4.2.11 of RFC 8446, and Section 4.1 + of I-D. ietf-tls-external-psk-guidance: A sequence + of bytes used to identify an EPSK. A label for a + pre-shared key established externally."; + reference + "RFC 8446: The Transport Layer Security (TLS) + Protocol Version 1.3 + I-D.ietf-tls-external-psk-guidance: + Guidance for External PSK Usage in TLS"; + } + leaf hash { + type tlscmn:epsk-supported-hash; + mandatory true; + description + "As per Section 4.2.11 of RFC 8446, for externally + established PSKs, the Hash algorithm MUST be set + when the PSK is established or default to SHA-256 + if no such algorithm is defined. The server MUST + ensure that it selects a compatible PSK (if any) + and cipher suite. Each PSK MUST only be used + with a single hash function."; + reference + "RFC 8446: The Transport Layer Security (TLS) + Protocol Version 1.3"; + } + leaf context { + type string; + description + "As per Section 4.1 of I-D. + ietf-tls-external-psk-guidance: Context + may include information about peer roles or + identities to mitigate Selfie-style reflection + attacks [Selfie]. If the EPSK is a key derived + from some other protocol or sequence of protocols, + context MUST include a channel binding for the + deriving protocols [RFC5056]. The details of + this binding are protocol specific."; + reference + "I-D.ietf-tls-external-psk-importer: + Importing External PSKs for TLS + I-D.ietf-tls-external-psk-guidance: + Guidance for External PSK Usage in TLS"; + } + leaf target-protocol { + type uint16; + description + "As per Section 3.1 of I-D. + ietf-tls-external-psk-guidance: The protocol + for which a PSK is imported for use."; + reference + "I-D.ietf-tls-external-psk-importer: + Importing External PSKs for TLS"; + } + leaf target-kdf { + type uint16; + description + "As per Section 3.1 of I-D. + ietf-tls-external-psk-guidance: The specific Key + Derivation Function (KDF) for which a PSK is + imported for use."; + reference + "I-D.ietf-tls-external-psk-importer: + Importing External PSKs for TLS"; + } + } + } + } + } // container server-identity + + container client-authentication { + if-feature "client-auth-supported"; + nacm:default-deny-write; + must 'ca-certs or ee-certs or raw-public-keys or tls12-psks + or tls13-epsks'; + presence + "Indicates that client authentication is supported (i.e., + that the server will request clients send certificates). + If not configured, the TLS server SHOULD NOT request the + TLS clients provide authentication credentials."; + description + "Specifies how the TLS server can authenticate TLS clients. + Any combination of credentials is additive and unordered. + + Note that no configuration is required for PSK (pre-shared + or pairwise-symmetric key) based authentication as the key + is necessarily the same as configured in the '../server- + identity' node."; + container ca-certs { + if-feature "client-auth-x509-cert"; + presence + "Indicates that CA certificates have been configured. + This statement is present so the mandatory descendant + nodes do not imply that this node must be configured."; + description + "A set of certificate authority (CA) certificates used by + the TLS server to authenticate TLS client certificates. + A client certificate is authenticated if it has a valid + chain of trust to a configured CA certificate."; + reference + "RFC BBBB: A YANG Data Model for a Truststore"; + uses ts:local-or-truststore-certs-grouping; + } + container ee-certs { + if-feature "client-auth-x509-cert"; + presence + "Indicates that EE certificates have been configured. + This statement is present so the mandatory descendant + nodes do not imply that this node must be configured."; + description + "A set of client certificates (i.e., end entity + certificates) used by the TLS server to authenticate + certificates presented by TLS clients. A client + certificate is authenticated if it is an exact + match to a configured client certificate."; + reference + "RFC BBBB: A YANG Data Model for a Truststore"; + uses ts:local-or-truststore-certs-grouping; + } + container raw-public-keys { + if-feature "client-auth-raw-public-key"; + presence + "Indicates that raw public keys have been configured. + This statement is present so the mandatory descendant + nodes do not imply that this node must be configured."; + description + "A set of raw public keys used by the TLS server to + authenticate raw public keys presented by the TLS + client. A raw public key is authenticated if it + is an exact match to a configured raw public key."; + reference + "RFC BBBB: A YANG Data Model for a Truststore"; + uses ts:local-or-truststore-public-keys-grouping { + refine "local-or-truststore/local/local-definition" + + "/public-key" { + must 'public-key-format' + + ' = "ct:subject-public-key-info-format"'; + } + refine "local-or-truststore/truststore" + + "/truststore-reference" { + must 'deref(.)/../*/ts:public-key-format' + + ' = "ct:subject-public-key-info-format"'; + } + } + } + leaf tls12-psks { + if-feature "client-auth-tls12-psk"; + type empty; + description + "Indicates that the TLS server can authenticate TLS clients + using configured PSKs (pre-shared or pairwise-symmetric + keys). + + No configuration is required since the PSK value is the + same as PSK value configured in the 'server-identity' + node."; + } + leaf tls13-epsks { + if-feature "client-auth-tls13-epsk"; + type empty; + description + "Indicates that the TLS 1.3 server can authenticate TLS + clients using configured external PSKs (pre-shared keys). + + No configuration is required since the PSK value is the + same as PSK value configured in the 'server-identity' + node."; + } + } // container client-authentication + + container hello-params { + nacm:default-deny-write; + if-feature "tlscmn:hello-params"; + uses tlscmn:hello-params-grouping; + description + "Configurable parameters for the TLS hello message."; + } // container hello-params + + container keepalives { + nacm:default-deny-write; + if-feature "tls-server-keepalives"; + description + "Configures the keepalive policy for the TLS server."; + leaf peer-allowed-to-send { + type empty; + description + "Indicates that the remote TLS client is allowed to send + HeartbeatRequest messages, as defined by RFC 6520 + to this TLS server."; + reference + "RFC 6520: Transport Layer Security (TLS) and Datagram + Transport Layer Security (DTLS) Heartbeat Extension"; + } + container test-peer-aliveness { + presence + "Indicates that the TLS server proactively tests the + aliveness of the remote TLS client."; + description + "Configures the keep-alive policy to proactively test + the aliveness of the TLS client. An unresponsive + TLS client is dropped after approximately max-wait + * max-attempts seconds."; + leaf max-wait { + type uint16 { + range "1..max"; + } + units "seconds"; + default "30"; + description + "Sets the amount of time in seconds after which if + no data has been received from the TLS client, a + TLS-level message will be sent to test the + aliveness of the TLS client."; + } + leaf max-attempts { + type uint8; + default "3"; + description + "Sets the maximum number of sequential keep-alive + messages that can fail to obtain a response from + the TLS client before assuming the TLS client is + no longer alive."; + } + } + } // container keepalives + } // grouping tls-server-grouping + +} diff --git a/modules/ietf-truststore@2022-05-24.yang b/modules/ietf-truststore@2022-05-24.yang new file mode 100644 index 00000000..7aaf7a29 --- /dev/null +++ b/modules/ietf-truststore@2022-05-24.yang @@ -0,0 +1,339 @@ +module ietf-truststore { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-truststore"; + prefix ts; + + import ietf-netconf-acm { + prefix nacm; + reference + "RFC 8341: Network Configuration Access Control Model"; + } + + import ietf-crypto-types { + prefix ct; + reference + "RFC AAAA: YANG Data Types and Groupings for Cryptography"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web : https://datatracker.ietf.org/wg/netconf + WG List : NETCONF WG list + Author : Kent Watsen "; + description + "This module defines a 'truststore' to centralize management + of trust anchors including certificates and public keys. + + Copyright (c) 2021 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Revised + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC BBBB + (https://www.rfc-editor.org/info/rfcBBBB); see the RFC + itself for full legal notices. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2022-05-24 { + description + "Initial version"; + reference + "RFC BBBB: A YANG Data Model for a Truststore"; + } + + /****************/ + /* Features */ + /****************/ + + feature central-truststore-supported { + description + "The 'central-truststore-supported' feature indicates that + the server supports the truststore (i.e., implements the + 'ietf-truststore' module)."; + } + + feature local-definitions-supported { + description + "The 'local-definitions-supported' feature indicates that + the server supports locally-defined trust anchors."; + } + feature certificates { + description + "The 'certificates' feature indicates that the server + implements the /truststore/certificate-bags subtree."; + } + + feature public-keys { + description + "The 'public-keys' feature indicates that the server + implements the /truststore/public-key-bags subtree."; + } + + /****************/ + /* Typedefs */ + /****************/ + + typedef certificate-bag-ref { + type leafref { + path "/ts:truststore/ts:certificate-bags/" + + "ts:certificate-bag/ts:name"; + } + description + "This typedef defines a reference to a certificate bag + in the truststore, when this module is implemented."; + } + + typedef certificate-ref { + type leafref { + path "/ts:truststore/ts:certificate-bags/ts:certificate-bag" + + "[ts:name = current()/../ts:certificate-bag]/" + + "ts:certificate/ts:name"; + } + description + "This typedef defines a reference to a specific certificate + in a certificate bag in the truststore, when this module + is implemented. This typedef requires that there exist a + sibling 'leaf' node called 'certificate-bag' that SHOULD + have the typedef 'certificate-bag-ref'."; + } + + typedef public-key-bag-ref { + type leafref { + path "/ts:truststore/ts:public-key-bags/" + + "ts:public-key-bag/ts:name"; + } + description + "This typedef defines a reference to a public key bag + in the truststore, when this module is implemented."; + } + + typedef public-key-ref { + type leafref { + path "/ts:truststore/ts:public-key-bags/ts:public-key-bag" + + "[ts:name = current()/../ts:public-key-bag]/" + + "ts:public-key/ts:name"; + } + description + "This typedef defines a reference to a specific public key + in a public key bag in the truststore, when this module is + implemented. This typedef requires that there exist a + sibling 'leaf' node called 'public-key-bag' that SHOULD + have the typedef 'public-key-bag-ref'."; + } + + /*****************/ + /* Groupings */ + /*****************/ + + grouping local-or-truststore-certs-grouping { + description + "A grouping that allows the certificates to be either + configured locally, within the using data model, or be a + reference to a certificate bag stored in the truststore. + + Servers that do not 'implement' this module, and hence + 'central-truststore-supported' is not defined, SHOULD + augment in custom 'case' statements enabling references + to the alternate truststore locations."; + choice local-or-truststore { + nacm:default-deny-write; + mandatory true; + description + "A choice between an inlined definition and a definition + that exists in the truststore."; + case local { + if-feature "local-definitions-supported"; + container local-definition { + description + "A container for locally configured trust anchor + certificates."; + list certificate { + key "name"; + min-elements 1; + description + "A trust anchor certificate."; + leaf name { + type string; + description + "An arbitrary name for this certificate."; + } + uses ct:trust-anchor-cert-grouping { + refine "cert-data" { + mandatory true; + } + } + } + } + } + case truststore { + if-feature "central-truststore-supported"; + if-feature "certificates"; + leaf truststore-reference { + type ts:certificate-bag-ref; + description + "A reference to a certificate bag that exists in the + truststore, when this module is implemented."; + } + } + } + } + + grouping local-or-truststore-public-keys-grouping { + description + "A grouping that allows the public keys to be either + configured locally, within the using data model, or be a + reference to a public key bag stored in the truststore. + + Servers that do not 'implement' this module, and hence + 'central-truststore-supported' is not defined, SHOULD + augment in custom 'case' statements enabling references + to the alternate truststore locations."; + choice local-or-truststore { + nacm:default-deny-write; + mandatory true; + description + "A choice between an inlined definition and a definition + that exists in the truststore."; + case local { + if-feature "local-definitions-supported"; + container local-definition { + description + "A container to hold local public key definitions."; + list public-key { + key "name"; + description + "A public key definition."; + leaf name { + type string; + description + "An arbitrary name for this public key."; + } + uses ct:public-key-grouping; + } + } + } + case truststore { + if-feature "central-truststore-supported"; + if-feature "public-keys"; + leaf truststore-reference { + type ts:public-key-bag-ref; + description + "A reference to a bag of public keys that exists + in the truststore, when this module is implemented."; + } + } + } + } + + grouping truststore-grouping { + description + "A grouping definition that enables use in other contexts. + Where used, implementations MUST augment new 'case' + statements into the various local-or-truststore 'choice' + statements to supply leafrefs to the model-specific + location(s)."; + container certificate-bags { + nacm:default-deny-write; + if-feature "certificates"; + description + "A collection of certificate bags."; + list certificate-bag { + key "name"; + description + "A bag of certificates. Each bag of certificates SHOULD + be for a specific purpose. For instance, one bag could + be used to authenticate a specific set of servers, while + another could be used to authenticate a specific set of + clients."; + leaf name { + type string; + description + "An arbitrary name for this bag of certificates."; + } + leaf description { + type string; + description + "A description for this bag of certificates. The + intended purpose for the bag SHOULD be described."; + } + list certificate { + key "name"; + description + "A trust anchor certificate."; + leaf name { + type string; + description + "An arbitrary name for this certificate."; + } + uses ct:trust-anchor-cert-grouping { + refine "cert-data" { + mandatory true; + } + } + } + } + } + container public-key-bags { + nacm:default-deny-write; + if-feature "public-keys"; + description + "A collection of public key bags."; + list public-key-bag { + key "name"; + description + "A bag of public keys. Each bag of keys SHOULD be for + a specific purpose. For instance, one bag could be used + authenticate a specific set of servers, while another + could be used to authenticate a specific set of clients."; + leaf name { + type string; + description + "An arbitrary name for this bag of public keys."; + } + leaf description { + type string; + description + "A description for this bag public keys. The + intended purpose for the bag SHOULD be described."; + } + list public-key { + key "name"; + description + "A public key."; + leaf name { + type string; + description + "An arbitrary name for this public key."; + } + uses ct:public-key-grouping; + } + } + } + } + + /*********************************/ + /* Protocol accessible nodes */ + /*********************************/ + + container truststore { + if-feature central-truststore-supported; + nacm:default-deny-write; + description + "The truststore contains bags of certificates and + public keys."; + uses truststore-grouping; + } +} diff --git a/modules/ietf-x509-cert-to-name.yang b/modules/ietf-x509-cert-to-name.yang new file mode 100644 index 00000000..53b5484a --- /dev/null +++ b/modules/ietf-x509-cert-to-name.yang @@ -0,0 +1,314 @@ + module ietf-x509-cert-to-name { + + yang-version 1; + + namespace + "urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name"; + + prefix x509c2n; + + import ietf-yang-types { + prefix yang; + } + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: +WG List: + +WG Chair: Thomas Nadeau + + +WG Chair: Juergen Schoenwaelder + + +Editor: Martin Bjorklund + + +Editor: Juergen Schoenwaelder + "; + + description + "This module contains a collection of YANG definitions for +extracting a name from an X.509 certificate. +The algorithm used to extract a name from an X.509 certificate +was first defined in RFC 6353. + +Copyright (c) 2014 IETF Trust and the persons identified as +authors of the code. All rights reserved. + +Redistribution and use in source and binary forms, with or +without modification, is permitted pursuant to, and subject +to the license terms contained in, the Simplified BSD License +set forth in Section 4.c of the IETF Trust's Legal Provisions +Relating to IETF Documents +(http://trustee.ietf.org/license-info). + +This version of this YANG module is part of RFC 7407; see +the RFC itself for full legal notices."; + + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model for + the Simple Network Management Protocol (SNMP)"; + + + revision "2014-12-10" { + description "Initial revision."; + reference + "RFC 7407: A YANG Data Model for SNMP Configuration"; + + } + + + typedef tls-fingerprint { + type yang:hex-string { + pattern + '([0-9a-fA-F]){2}(:([0-9a-fA-F]){2}){0,254}'; + } + description + "A fingerprint value that can be used to uniquely reference +other data of potentially arbitrary length. + +A tls-fingerprint value is composed of a 1-octet hashing +algorithm identifier followed by the fingerprint value. The +first octet value identifying the hashing algorithm is taken +from the IANA 'TLS HashAlgorithm Registry' (RFC 5246). The +remaining octets are filled using the results of the hashing +algorithm."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol (SNMP). + SNMP-TLS-TM-MIB.SnmpTLSFingerprint"; + + } + + identity cert-to-name { + description + "Base identity for algorithms to derive a name from a +certificate."; + } + + identity specified { + base cert-to-name; + description + "Directly specifies the name to be used for the certificate. +The value of the leaf 'name' in the cert-to-name list is +used."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol (SNMP). + SNMP-TLS-TM-MIB.snmpTlstmCertSpecified"; + + } + + identity san-rfc822-name { + base cert-to-name; + description + "Maps a subjectAltName's rfc822Name to a name. The local part +of the rfc822Name is passed unaltered, but the host-part of +the name must be passed in lowercase. For example, the +rfc822Name field FooBar@Example.COM is mapped to name +FooBar@example.com."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol (SNMP). + SNMP-TLS-TM-MIB.snmpTlstmCertSANRFC822Name"; + + } + + identity san-dns-name { + base cert-to-name; + description + "Maps a subjectAltName's dNSName to a name after first +converting it to all lowercase (RFC 5280 does not specify +converting to lowercase, so this involves an extra step). +This mapping results in a 1:1 correspondence between +subjectAltName dNSName values and the name values."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol (SNMP). + SNMP-TLS-TM-MIB.snmpTlstmCertSANDNSName"; + + } + + identity san-ip-address { + base cert-to-name; + description + "Maps a subjectAltName's iPAddress to a name by +transforming the binary-encoded address as follows: + + 1) for IPv4, the value is converted into a + decimal-dotted quad address (e.g., '192.0.2.1'). + + 2) for IPv6 addresses, the value is converted into a + 32-character, all-lowercase hexadecimal string + without any colon separators. + +This mapping results in a 1:1 correspondence between +subjectAltName iPAddress values and the name values."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol (SNMP). + SNMP-TLS-TM-MIB.snmpTlstmCertSANIpAddress"; + + } + + identity san-any { + base cert-to-name; + description + "Maps any of the following fields using the corresponding +mapping algorithms: + + +------------+-----------------+ + | Type | Algorithm | + |------------+-----------------| + | rfc822Name | san-rfc822-name | + | dNSName | san-dns-name | + | iPAddress | san-ip-address | + +------------+-----------------+ + +The first matching subjectAltName value found in the +certificate of the above types MUST be used when deriving +the name. The mapping algorithm specified in the +'Algorithm' column MUST be used to derive the name. + +This mapping results in a 1:1 correspondence between +subjectAltName values and name values. The three sub-mapping +algorithms produced by this combined algorithm cannot produce +conflicting results between themselves."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol (SNMP). + SNMP-TLS-TM-MIB.snmpTlstmCertSANAny"; + + } + + identity common-name { + base cert-to-name; + description + "Maps a certificate's CommonName to a name after converting +it to a UTF-8 encoding. The usage of CommonNames is +deprecated, and users are encouraged to use subjectAltName +mapping methods instead. This mapping results in a 1:1 +correspondence between certificate CommonName values and name +values."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol (SNMP). + SNMP-TLS-TM-MIB.snmpTlstmCertCommonName"; + + } + + grouping cert-to-name { + description + "Defines nodes for mapping certificates to names. Modules +that use this grouping should describe how the resulting +name is used."; + list cert-to-name { + key "id"; + description + "This list defines how certificates are mapped to names. +The name is derived by considering each cert-to-name +list entry in order. The cert-to-name entry's fingerprint +determines whether the list entry is a match: + +1) If the cert-to-name list entry's fingerprint value + matches that of the presented certificate, then consider + the list entry a successful match. + +2) If the cert-to-name list entry's fingerprint value + matches that of a locally held copy of a trusted CA + certificate, and that CA certificate was part of the CA + certificate chain to the presented certificate, then + consider the list entry a successful match. + +Once a matching cert-to-name list entry has been found, the +map-type is used to determine how the name associated with +the certificate should be determined. See the map-type +leaf's description for details on determining the name value. +If it is impossible to determine a name from the cert-to-name +list entry's data combined with the data presented in the +certificate, then additional cert-to-name list entries MUST +be searched to look for another potential match. + +Security administrators are encouraged to make use of +certificates with subjectAltName fields that can be mapped to +names so that a single root CA certificate can allow all +child certificates' subjectAltName fields to map directly to +a name via a 1:1 transformation."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol (SNMP). + SNMP-TLS-TM-MIB.snmpTlstmCertToTSNEntry"; + + leaf id { + type uint32; + description + "The id specifies the order in which the entries in the +cert-to-name list are searched. Entries with lower +numbers are searched first."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol + (SNMP). + SNMP-TLS-TM-MIB.snmpTlstmCertToTSNID"; + + } + + leaf fingerprint { + type tls-fingerprint; + mandatory true; + description + "Specifies a value with which the fingerprint of the +full certificate presented by the peer is compared. If +the fingerprint of the full certificate presented by the +peer does not match the fingerprint configured, then the +entry is skipped, and the search for a match continues."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol + (SNMP). + SNMP-TLS-TM-MIB.snmpTlstmCertToTSNFingerprint"; + + } + + leaf map-type { + type identityref { + base cert-to-name; + } + mandatory true; + description + "Specifies the algorithm used to map the certificate +presented by the peer to a name. + +Mappings that need additional configuration objects should +use the 'when' statement to make them conditional based on +the map-type."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol + (SNMP). + SNMP-TLS-TM-MIB.snmpTlstmCertToTSNMapType"; + + } + + leaf name { + when + "../map-type = 'x509c2n:specified'"; + type string; + mandatory true; + description + "Directly specifies the NETCONF username when the +map-type is 'specified'."; + reference + "RFC 6353: Transport Layer Security (TLS) Transport Model + for the Simple Network Management Protocol + (SNMP). + SNMP-TLS-TM-MIB.snmpTlstmCertToTSNData"; + + } + } // list cert-to-name + } // grouping cert-to-name + } // module ietf-x509-cert-to-name \ No newline at end of file diff --git a/modules/libnetconf2-netconf-server.yang b/modules/libnetconf2-netconf-server.yang new file mode 100644 index 00000000..f9b76253 --- /dev/null +++ b/modules/libnetconf2-netconf-server.yang @@ -0,0 +1,35 @@ +module libnetconf2-netconf-server { + yang-version 1.1; + namespace "urn:cesnet:libnetconf2-netconf-server"; + prefix np2; + + import ietf-netconf-server { + prefix ncs; + } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { + leaf auth-attempts { + type uint16; + default 3; + } + + leaf auth-timeout { + type uint16; + default 10; + units "seconds"; + } + } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" { + container keyboard-interactive { + presence ""; + leaf pam-config-file-name { + type string; + mandatory true; + } + leaf pam-config-file-dir { + type string; + } + } + } +} diff --git a/src/config.h.in b/src/config.h.in index 736eaee7..7f36b819 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -49,6 +49,11 @@ */ #cmakedefine LIBPAM_HAVE_CONFDIR +/* + * Location of installed YANG modules on the system + */ +#define NC_SERVER_SEARCH_DIR "@YANG_MODULE_DIR@" + /* * Location of installed YANG modules on the system */ diff --git a/src/config_server.c b/src/config_server.c new file mode 100644 index 00000000..d0aaedad --- /dev/null +++ b/src/config_server.c @@ -0,0 +1,2389 @@ +/** + * @file config_server.c + * @author Roman Janota + * @brief libnetconf2 server configuration functions + * + * @copyright + * Copyright (c) 2015 - 2021 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 + */ +#include +#include +#include + +#include "compat.h" +#include "config_server.h" +#include "libnetconf.h" +#include "session_server.h" +#include "session_server_ch.h" + +/* All libssh supported host-key, key-exchange, encryption and mac algorithms as of version 0.10.90 */ + +static const char *supported_hostkey_algs[] = { + "ssh-ed25519-cert-v01@openssh.com", "ecdsa-sha2-nistp521-cert-v01@openssh.com", + "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ecdsa-sha2-nistp256-cert-v01@openssh.com", + "rsa-sha2-512-cert-v01@openssh.com", "rsa-sha2-256-cert-v01@openssh.com", + "ssh-rsa-cert-v01@openssh.com", "ssh-dss-cert-v01@openssh.com", + "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256", + "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL +}; + +static const char *supported_kex_algs[] = { + "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "curve25519-sha256@libssh.org", + "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512", + "diffie-hellman-group16-sha512", "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL +}; + +static const char *supported_encryption_algs[] = { + "chacha20-poly1305@openssh.com", "aes256-gcm@openssh.com", "aes128-gcm@openssh.com", + "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc", + "blowfish-cbc", "3des-cbc", "none", NULL +}; + +static const char *supported_mac_algs[] = { + "hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha1-etm@openssh.com", + "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL +}; + +extern struct nc_server_opts server_opts; + +/** + * @brief Get the pointer to an endpoint structure based on node's location in the YANG data. + * + * @param[in] node Node from which the endpoint containing this node is derived. + * @param[out] endpt Endpoint containing the node. + * @param[out] bind Bind corresponding to the endpoint. Optional. + * @return 0 on success, 1 on error. + */ +static int +nc_server_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind) +{ + uint16_t i; + const char *endpt_name; + + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "endpoint")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in an endpoint subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + endpt_name = lyd_get_value(node); + + for (i = 0; i < server_opts.endpt_count; i++) { + if (!strcmp(server_opts.endpts[i].name, endpt_name)) { + *endpt = &server_opts.endpts[i]; + if (bind) { + *bind = &server_opts.binds[i]; + } + return 0; + } + } + + ERR(NULL, "Endpoint \"%s\" was not found.", endpt_name); + return 1; +} + +/** + * @brief Get the pointer to a hostkey structure based on node's location in the YANG data. + * + * @param[in] node Node from which the hotkey containing this node is derived. + * @param[in] opts Server SSH opts storing the array of the hostkey structures. + * @param[out] hostkey Hostkey containing the node. + * @return 0 on success, 1 on error. + */ +static int +nc_server_get_hostkey(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_hostkey **hostkey) +{ + uint16_t i; + const char *hostkey_name; + + assert(node && opts); + + while (node) { + if (!strcmp(LYD_NAME(node), "host-key")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a host-key subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + hostkey_name = lyd_get_value(node); + + for (i = 0; i < opts->hostkey_count; i++) { + if (!strcmp(opts->hostkeys[i].name, hostkey_name)) { + *hostkey = &opts->hostkeys[i]; + return 0; + } + } + + ERR(NULL, "Host-key \"%s\" was not found.", hostkey_name); + return 1; +} + +/** + * @brief Get the pointer to a client authentication structure based on node's location in the YANG data. + * + * @param[in] node Node from which the client-authentication structure containing this node is derived. + * @param[in] opts Server SSH opts storing the array of the client authentication structures. + * @param[out] auth_client Client authentication structure containing the node. + * @return 0 on success, 1 on error. + */ +static int +nc_server_get_auth_client(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_client_auth **auth_client) +{ + uint16_t i; + const char *authkey_name; + + assert(node && opts); + + while (node) { + if (!strcmp(LYD_NAME(node), "user")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a client-authentication subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + authkey_name = lyd_get_value(node); + + for (i = 0; i < opts->client_count; i++) { + if (!strcmp(opts->auth_clients[i].username, authkey_name)) { + *auth_client = &opts->auth_clients[i]; + return 0; + } + } + + ERR(NULL, "Authorized key \"%s\" was not found.", authkey_name); + return 1; +} + +/** + * @brief Get the pointer to a client authentication public key structure based on node's location in the YANG data. + * + * @param[in] node Node from which the ca-public key structure containing this node is derived. + * @param[in] auth_client Client authentication structure storing the array of the public key structures. + * @param[out] pubkey Public key structure containing the node. + * @return 0 on success, 1 on error. + */ +static int +nc_server_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_client_auth_pubkey **pubkey) +{ + uint16_t i; + const char *pubkey_name; + + assert(node && auth_client); + + node = lyd_parent(node); + while (node) { + if (!strcmp(LYD_NAME(node), "public-key")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + pubkey_name = lyd_get_value(node); + + for (i = 0; i < auth_client->pubkey_count; i++) { + if (!strcmp(auth_client->pubkeys[i].name, pubkey_name)) { + *pubkey = &auth_client->pubkeys[i]; + return 0; + } + } + + ERR(NULL, "Public key \"%s\" was not found.", pubkey_name); + return 1; +} + +/** + * @brief Compares the nth-parent name. + * + * @param[in] node Node of which nth-parent to compare. + * @param[in] parent_count Count of parents. + * @param[in] parent_name Expected name of the parent. + * @return 1 if the name matches, 0 otherwise. + */ +static int +equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name) +{ + uint16_t i; + + assert(node && parent_count > 0 && parent_name); + + node = lyd_parent(node); + for (i = 1; i < parent_count; i++) { + node = lyd_parent(node); + } + + if (!strcmp(LYD_NAME(node), parent_name)) { + return 1; + } + + return 0; +} + +static void +nc_server_del_auth_client_pam_name(struct nc_client_auth *auth_client) +{ + free(auth_client->pam_config_name); + auth_client->pam_config_name = NULL; +} + +static void +nc_server_del_auth_client_pam_dir(struct nc_client_auth *auth_client) +{ + free(auth_client->pam_config_dir); + auth_client->pam_config_dir = NULL; +} + +static void +nc_server_del_endpt_name(struct nc_endpt *endpt) +{ + free(endpt->name); + endpt->name = NULL; +} + +static void +nc_server_del_local_address(struct nc_bind *bind) +{ + free(bind->address); + bind->address = NULL; +} + +static void +nc_server_del_hostkey_name(struct nc_hostkey *hostkey) +{ + free(hostkey->name); + hostkey->name = NULL; +} + +static void +nc_server_del_public_key(struct nc_hostkey *hostkey) +{ + free(hostkey->pub_base64); + hostkey->pub_base64 = NULL; +} + +static void +nc_server_del_truststore_reference(struct nc_client_auth *client_auth) +{ + free(client_auth->ts_reference); + client_auth->ts_reference = NULL; +} + +static void +nc_server_del_private_key(struct nc_hostkey *hostkey) +{ + free(hostkey->priv_base64); + hostkey->priv_base64 = NULL; +} + +static void +nc_server_del_keystore_reference(struct nc_hostkey *hostkey) +{ + hostkey->keystore = NULL; +} + +static void +nc_server_del_auth_client_username(struct nc_client_auth *auth_client) +{ + free(auth_client->username); + auth_client->username = NULL; +} + +static void +nc_server_del_auth_client_pubkey_name(struct nc_client_auth_pubkey *pubkey) +{ + free(pubkey->name); + pubkey->name = NULL; +} + +static void +nc_server_del_auth_client_pubkey_pub_base64(struct nc_client_auth_pubkey *pubkey) +{ + free(pubkey->pub_base64); + pubkey->pub_base64 = NULL; +} + +static void +nc_server_del_auth_client_ts_reference(struct nc_client_auth *auth_client) +{ + free(auth_client->ts_reference); + auth_client->ts_reference = NULL; +} + +static void +nc_server_del_auth_client_password(struct nc_client_auth *auth_client) +{ + free(auth_client->password); + auth_client->password = NULL; +} + +static void +nc_server_del_hostkey_algs(struct nc_server_ssh_opts *opts) +{ + free(opts->hostkey_algs); + opts->hostkey_algs = NULL; +} + +static void +nc_server_del_kex_algs(struct nc_server_ssh_opts *opts) +{ + free(opts->kex_algs); + opts->kex_algs = NULL; +} + +static void +nc_server_del_encryption_algs(struct nc_server_ssh_opts *opts) +{ + free(opts->encryption_algs); + opts->encryption_algs = NULL; +} + +static void +nc_server_del_mac_algs(struct nc_server_ssh_opts *opts) +{ + free(opts->mac_algs); + opts->mac_algs = NULL; +} + +static void +nc_server_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey) +{ + assert(hostkey->ks_type == NC_STORE_LOCAL || hostkey->ks_type == NC_STORE_KEYSTORE); + + if (hostkey->ks_type == NC_STORE_LOCAL) { + nc_server_del_public_key(hostkey); + nc_server_del_private_key(hostkey); + } else if (hostkey->ks_type == NC_STORE_KEYSTORE) { + nc_server_del_keystore_reference(hostkey); + } + + nc_server_del_hostkey_name(hostkey); + opts->hostkey_count--; + if (!opts->hostkey_count) { + free(opts->hostkeys); + opts->hostkeys = NULL; + } +} + +static void +nc_server_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_client_auth_pubkey *pubkey) +{ + nc_server_del_auth_client_pubkey_name(pubkey); + nc_server_del_auth_client_pubkey_pub_base64(pubkey); + + auth_client->pubkey_count--; + if (!auth_client->pubkey_count) { + free(auth_client->pubkeys); + auth_client->pubkeys = NULL; + } +} + +static void +nc_server_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth *auth_client) +{ + uint16_t i, pubkey_count; + + if (auth_client->ks_type == NC_STORE_LOCAL) { + pubkey_count = auth_client->pubkey_count; + for (i = 0; i < pubkey_count; i++) { + nc_server_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]); + } + } else if (auth_client->ks_type == NC_STORE_TRUSTSTORE) { + nc_server_del_auth_client_ts_reference(auth_client); + } else { + return; + } + + nc_server_del_auth_client_password(auth_client); + nc_server_del_auth_client_pam_name(auth_client); + nc_server_del_auth_client_pam_dir(auth_client); + nc_server_del_auth_client_username(auth_client); + + opts->client_count--; + if (!opts->client_count) { + free(opts->auth_clients); + opts->auth_clients = NULL; + } +} + +static void +nc_server_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts) +{ + uint16_t i, hostkey_count, client_count; + + nc_server_del_local_address(bind); + if (bind->sock > -1) { + close(bind->sock); + } + + /* store in variable because it gets decremented in the function call */ + hostkey_count = opts->hostkey_count; + for (i = 0; i < hostkey_count; i++) { + nc_server_del_hostkey(opts, &opts->hostkeys[i]); + } + + client_count = opts->client_count; + for (i = 0; i < client_count; i++) { + nc_server_del_auth_client(opts, &opts->auth_clients[i]); + } + + nc_server_del_hostkey_algs(opts); + nc_server_del_kex_algs(opts); + nc_server_del_encryption_algs(opts); + nc_server_del_mac_algs(opts); + + free(opts); + opts = NULL; +} + +void +nc_server_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) +{ + nc_server_del_endpt_name(endpt); + nc_server_del_ssh(bind, endpt->opts.ssh); + + server_opts.endpt_count--; + if (!server_opts.endpt_count) { + free(server_opts.endpts); + free(server_opts.binds); + server_opts.endpts = NULL; + server_opts.binds = NULL; + } +} + +/* presence container */ +int +nc_server_configure_listen(NC_OPERATION op) +{ + uint16_t i; + + assert(op == NC_OP_CREATE || op == NC_OP_DELETE); + + if (op == NC_OP_DELETE) { + for (i = 0; i < server_opts.endpt_count; i++) { + nc_server_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]); + } + } + + return 0; +} + +/* default leaf */ +static int +nc_server_configure_idle_timeout(const struct lyd_node *node, NC_OPERATION op) +{ + assert(!strcmp(LYD_NAME(node), "idle-timeout")); + + if (equal_parent_name(node, 1, "listen")) { + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10); + } else { + /* default value */ + server_opts.idle_timeout = 3600; + } + } + + return 0; +} + +static int +nc_server_create_bind(void) +{ + int ret = 0; + void *tmp; + + tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + server_opts.binds = tmp; + memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds); + + server_opts.binds[server_opts.endpt_count].sock = -1; + +cleanup: + return ret; +} + +static int +nc_server_create_endpoint(const struct lyd_node *node) +{ + int ret = 0; + void *tmp; + + tmp = realloc(server_opts.endpts, (server_opts.endpt_count + 1) * sizeof *server_opts.endpts); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + server_opts.endpts = tmp; + memset(&server_opts.endpts[server_opts.endpt_count], 0, sizeof *server_opts.endpts); + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + server_opts.endpts[server_opts.endpt_count].name = strdup(lyd_get_value(node)); + if (!server_opts.endpts[server_opts.endpt_count].name) { + ERRMEM; + ret = 1; + goto cleanup; + } + + if (nc_server_create_bind()) { + ret = 1; + goto cleanup; + } + + server_opts.endpt_count++; + +cleanup: + return ret; +} + +/* list */ +static int +nc_server_configure_endpoint(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + struct nc_bind *bind; + + assert(!strcmp(LYD_NAME(node), "endpoint")); + + if (op == NC_OP_CREATE) { + ret = nc_server_create_endpoint(node); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + /* free all children */ + if (nc_server_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } + nc_server_del_endpt_ssh(endpt, bind); + } + +cleanup: + return ret; +} + +static int +nc_server_create_ssh(struct nc_endpt *endpt) +{ + endpt->ti = NC_TI_LIBSSH; + endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts)); + if (!endpt->opts.ssh) { + ERRMEM; + return 1; + } + + return 0; +} + +/* NP container */ +static int +nc_server_configure_ssh(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_bind *bind; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "ssh")); + + if (nc_server_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + ret = nc_server_create_ssh(endpt); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + nc_server_del_ssh(bind, endpt->opts.ssh); + } + +cleanup: + return ret; +} + +static int +nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port) +{ + int sock = -1, set_addr, ret = 0; + + assert((address && !port) || (!address && port)); + + if (address) { + set_addr = 1; + } else { + set_addr = 0; + } + + if (set_addr) { + port = bind->port; + } else { + address = bind->address; + } + + if (!set_addr && (endpt->ti == NC_TI_UNIX)) { + ret = 1; + goto cleanup; + } + + /* we have all the information we need to create a listening socket */ + if (address && port) { + /* create new socket, close the old one */ + sock = nc_sock_listen_inet(address, port, &endpt->ka); + if (sock == -1) { + ret = 1; + goto cleanup; + } + + if (bind->sock > -1) { + close(bind->sock); + } + bind->sock = sock; + } + + if (sock > -1) { + switch (endpt->ti) { +#ifdef NC_ENABLED_SSH + case NC_TI_LIBSSH: + VRB(NULL, "Listening on %s:%u for SSH connections.", address, port); + break; +#endif +#ifdef NC_ENABLED_TLS + case NC_TI_OPENSSL: + VRB(NULL, "Listening on %s:%u for TLS connections.", address, port); + break; +#endif + default: + ERRINT; + ret = 1; + break; + } + } + +cleanup: + return ret; +} + +/* mandatory leaf */ +static int +nc_server_configure_local_address(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_bind *bind; + int ret = 0; + + (void) op; + + assert(!strcmp(LYD_NAME(node), "local-address")); + + if (equal_parent_name(node, 4, "listen")) { + if (nc_server_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } + + nc_server_del_local_address(bind); + bind->address = strdup(lyd_get_value(node)); + if (!bind->address) { + ERRMEM; + ret = 1; + goto cleanup; + } + + ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0); + if (ret) { + goto cleanup; + } + } + +cleanup: + return ret; +} + +/* leaf with default value */ +static int +nc_server_configure_local_port(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_bind *bind; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "local-port")); + + if (equal_parent_name(node, 4, "listen")) { + if (nc_server_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + bind->port = strtoul(lyd_get_value(node), NULL, 10); + } else { + /* delete -> set to default */ + bind->port = 0; + } + + ret = nc_server_config_set_address_port(endpt, bind, NULL, bind->port); + if (ret) { + goto cleanup; + } + } + +cleanup: + return ret; +} + +/* P container */ +static int +nc_server_configure_keepalives(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_bind *bind; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "keepalives")); + + if (equal_parent_name(node, 4, "listen")) { + if (nc_server_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + endpt->ka.enabled = 1; + } else { + endpt->ka.enabled = 0; + } + ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka); + if (ret) { + goto cleanup; + } + } + +cleanup: + return ret; +} + +/* mandatory leaf */ +static int +nc_server_configure_idle_time(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_bind *bind; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "idle-time")); + + if (equal_parent_name(node, 4, "listen")) { + if (nc_server_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10); + } else { + endpt->ka.idle_time = 0; + } + ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka); + if (ret) { + goto cleanup; + } + } + +cleanup: + return ret; +} + +/* mandatory leaf */ +static int +nc_server_configure_max_probes(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_bind *bind; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "max-probes")); + + if (equal_parent_name(node, 4, "listen")) { + if (nc_server_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10); + } else { + endpt->ka.max_probes = 0; + } + ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka); + if (ret) { + goto cleanup; + } + } + +cleanup: + return ret; +} + +/* mandatory leaf */ +static int +nc_server_configure_probe_interval(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_bind *bind; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "probe-interval")); + + if (equal_parent_name(node, 4, "listen")) { + if (nc_server_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10); + } else { + endpt->ka.probe_interval = 0; + } + ret = nc_sock_configure_keepalive(bind->sock, &endpt->ka); + if (ret) { + goto cleanup; + } + } + +cleanup: + return ret; +} + +static int +nc_server_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts) +{ + int ret = 0; + void *tmp; + + tmp = realloc(opts->hostkeys, + (opts->hostkey_count + 1) * sizeof *opts->hostkeys); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + opts->hostkeys = tmp; + + memset(&opts->hostkeys[opts->hostkey_count], 0, sizeof *opts->hostkeys); + + opts->hostkeys[opts->hostkey_count].name = strdup(lyd_get_value(lyd_child(node))); + if (!opts->hostkeys[opts->hostkey_count].name) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* set union selector */ + lyd_find_path(node, "public-key", 0, (struct lyd_node **)&node); + assert(node); + + if (!lyd_find_path(node, "local-definition", 0, NULL)) { + opts->hostkeys[opts->hostkey_count].ks_type = NC_STORE_LOCAL; + } else { + opts->hostkeys[opts->hostkey_count].ks_type = NC_STORE_KEYSTORE; + } + + opts->hostkey_count++; + +cleanup: + return ret; +} + +/* list */ +static int +nc_server_configure_host_key(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_hostkey *hostkey; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "host-key")); + + if ((equal_parent_name(node, 1, "server-identity")) && (equal_parent_name(node, 5, "listen"))) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + ret = nc_server_create_host_key(node, endpt->opts.ssh); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; + } + + nc_server_del_hostkey(endpt->opts.ssh, hostkey); + } + } else if (equal_parent_name(node, 1, "transport-params")) { + /* just a container with the name host-key, nothing to be done */ + goto cleanup; + } else { + ERRINT; + ret = 1; + goto cleanup; + } + +cleanup: + return ret; +} + +/* mandatory leaf */ +int +nc_server_configure_public_key_format(const struct lyd_node *node, NC_OPERATION op) +{ + const char *format; + struct nc_endpt *endpt; + struct nc_client_auth *auth_client; + struct nc_client_auth_pubkey *pubkey; + struct nc_hostkey *hostkey; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "public-key-format")); + + format = ((struct lyd_node_term *)node)->value.ident->name; + + if ((equal_parent_name(node, 6, "client-authentication")) && (equal_parent_name(node, 10, "listen"))) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_pubkey(node, auth_client, &pubkey)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + if (!strcmp(format, "ssh-public-key-format")) { + pubkey->pubkey_type = NC_SSH_PUBKEY_X509; + } else if (!strcmp(format, "subject-public-key-info-format")) { + pubkey->pubkey_type = NC_SSH_PUBKEY_SSH2; + } else { + ERR(NULL, "Public key format (%s) not supported.", format); + } + } + } else if ((equal_parent_name(node, 5, "server-identity")) && (equal_parent_name(node, 11, "listen"))) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + if (!strcmp(format, "ssh-public-key-format")) { + hostkey->pubkey_type = NC_SSH_PUBKEY_X509; + } else if (!strcmp(format, "subject-public-key-info-format")) { + hostkey->pubkey_type = NC_SSH_PUBKEY_SSH2; + } else { + ERR(NULL, "Public key format (%s) not supported.", format); + } + } + } + +cleanup: + return ret; +} + +/* leaf */ +int +nc_server_configure_private_key_format(const struct lyd_node *node, NC_OPERATION op) +{ + const char *format; + struct nc_endpt *endpt; + struct nc_hostkey *hostkey; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "private-key-format")); + + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; + } + + format = ((struct lyd_node_term *)node)->value.ident->name; + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + if (!strcmp(format, "rsa-private-key-format")) { + hostkey->privkey_type = NC_SSH_KEY_RSA; + } else if (!strcmp(format, "ec-private-key-format")) { + hostkey->privkey_type = NC_SSH_KEY_ECDSA; + } else { + ERR(NULL, "Private key format (%s) not supported.", format); + } + } + +cleanup: + return ret; +} + +static int +nc_server_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey) +{ + nc_server_del_private_key(hostkey); + hostkey->priv_base64 = strdup(lyd_get_value(node)); + if (!hostkey->priv_base64) { + ERRMEM; + return 1; + } + + return 0; +} + +static int +nc_server_configure_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_hostkey *hostkey; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "cleartext-private-key")); + + if ((equal_parent_name(node, 6, "ssh")) && (equal_parent_name(node, 8, "listen"))) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_replace_cleartext_private_key(node, hostkey); + if (ret) { + goto cleanup; + } + } else { + nc_server_del_private_key(hostkey); + } + } + +cleanup: + return ret; +} + +static int +nc_server_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey) +{ + uint16_t i; + struct nc_keystore *ks = NULL; + + /* lookup name */ + for (i = 0; i < server_opts.keystore_count; i++) { + if (!strcmp(lyd_get_value(node), server_opts.keystore[i].name)) { + ks = &server_opts.keystore[i]; + break; + } + } + + if (!ks) { + ERR(NULL, "Keystore (%s) not found.", lyd_get_value(node)); + return 1; + } + + hostkey->keystore = ks; + + return 0; +} + +/* leaf */ +static int +nc_server_configure_keystore_reference(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_hostkey *hostkey; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "keystore-reference")); + + if ((equal_parent_name(node, 4, "server-identity")) && (equal_parent_name(node, 7, "listen"))) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_create_keystore_reference(node, hostkey); + if (ret) { + goto cleanup; + } + } else { + hostkey->keystore = NULL; + } + } + +cleanup: + return ret; +} + +static int +nc_server_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_client_auth *auth_client) +{ + int ret = 0; + void *tmp; + + assert(!strcmp(LYD_NAME(node), "public-key")); + + tmp = realloc(auth_client->pubkeys, (auth_client->pubkey_count + 1) * sizeof *auth_client->pubkeys); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + auth_client->pubkeys = tmp; + + memset(&auth_client->pubkeys[auth_client->pubkey_count], 0, sizeof *auth_client->pubkeys); + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + auth_client->pubkeys[auth_client->pubkey_count].name = strdup(lyd_get_value(node)); + if (!auth_client->pubkeys[auth_client->pubkey_count].name) { + ERRMEM; + ret = 1; + goto cleanup; + } + + ++auth_client->pubkey_count; + +cleanup: + return ret; +} + +static int +nc_server_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_client_auth_pubkey *pubkey) +{ + nc_server_del_auth_client_pubkey_pub_base64(pubkey); + + pubkey->pub_base64 = strdup(lyd_get_value(node)); + if (!pubkey->pub_base64) { + ERRMEM; + return 1; + } + + return 0; +} + +static int +nc_server_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey) +{ + nc_server_del_public_key(hostkey); + + hostkey->pub_base64 = strdup(lyd_get_value(node)); + if (!hostkey->pub_base64) { + ERRMEM; + return 1; + } + + return 0; +} + +static int +nc_server_configure_public_key(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_hostkey *hostkey; + struct nc_client_auth *auth_client; + struct nc_client_auth_pubkey *pubkey; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "public-key")); + + if ((equal_parent_name(node, 3, "host-key")) && (equal_parent_name(node, 8, "listen"))) { + /* server's public-key, mandatory leaf */ + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_replace_host_key_public_key(node, hostkey); + if (ret) { + goto cleanup; + } + } + } else if ((equal_parent_name(node, 5, "client-authentication")) && (equal_parent_name(node, 9, "listen"))) { + /* client auth pubkeys, list */ + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + ret = nc_server_create_auth_key_public_key_list(node, auth_client); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + if (nc_server_get_pubkey(node, auth_client, &pubkey)) { + ret = 1; + goto cleanup; + } + + nc_server_del_auth_client_pubkey(auth_client, pubkey); + } + } else if ((equal_parent_name(node, 6, "client-authentication")) && (equal_parent_name(node, 10, "listen"))) { + /* client auth pubkey, leaf */ + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_pubkey(node, auth_client, &pubkey)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_replace_auth_key_public_key_leaf(node, pubkey); + if (ret) { + goto cleanup; + } + } else { + nc_server_del_auth_client_pubkey_pub_base64(pubkey); + } + } + +cleanup: + return ret; +} + +static int +nc_server_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts) +{ + int ret = 0; + void *tmp; + + tmp = realloc(opts->auth_clients, (opts->client_count + 1) * sizeof *opts->auth_clients); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + opts->auth_clients = tmp; + + memset(&opts->auth_clients[opts->client_count], 0, sizeof *opts->auth_clients); + + opts->auth_clients[opts->client_count].username = strdup(lyd_get_value(lyd_child(node))); + if (!opts->auth_clients[opts->client_count].username) { + ERRMEM; + ret = 1; + goto cleanup; + } + + lyd_find_path(node, "public-keys", 0, (struct lyd_node **)&node); + + if (node) { + /* set union selector */ + if (!lyd_find_path(node, "local-definition", 0, NULL)) { + opts->auth_clients[opts->client_count].ks_type = NC_STORE_LOCAL; + } else { + opts->auth_clients[opts->client_count].ks_type = NC_STORE_TRUSTSTORE; + } + } + + ++opts->client_count; + +cleanup: + return ret; +} + +/* list */ +static int +nc_server_configure_user(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_client_auth *auth_client; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "user")); + + if (equal_parent_name(node, 6, "listen")) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + ret = nc_server_create_user(node, endpt->opts.ssh); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + nc_server_del_auth_client(endpt->opts.ssh, auth_client); + } + } + +cleanup: + return ret; +} + +static int +nc_server_configure_auth_attempts(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "auth-attempts")); + + if (equal_parent_name(node, 5, "listen")) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10); + } + } + +cleanup: + return ret; +} + +static int +nc_server_configure_auth_timeout(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "auth-timeout")); + + if (equal_parent_name(node, 5, "listen")) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10); + } + } + +cleanup: + return ret; +} + +static int +nc_server_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth) +{ + /*todo*/ + nc_server_del_truststore_reference(client_auth); + + client_auth->ts_reference = strdup(lyd_get_value(node)); + if (!client_auth->ts_reference) { + ERRMEM; + return 1; + } + + return 0; +} + +/* leaf */ +static int +nc_server_configure_truststore_reference(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_client_auth *auth_client; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "truststore-reference")); + + if ((equal_parent_name(node, 1, "public-keys")) && (equal_parent_name(node, 8, "listen"))) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_replace_truststore_reference(node, auth_client); + if (ret) { + goto cleanup; + } + } else { + nc_server_del_truststore_reference(auth_client); + } + } + +cleanup: + return ret; +} + +static int +nc_server_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client) +{ + nc_server_del_auth_client_password(auth_client); + + auth_client->password = strdup(lyd_get_value(node)); + if (!auth_client->password) { + ERRMEM; + return 1; + } + + return 0; +} + +/* leaf */ +static int +nc_server_configure_password(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_client_auth *auth_client; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "password")); + + if (equal_parent_name(node, 7, "listen")) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_replace_password(node, auth_client); + if (ret) { + goto cleanup; + } + } else { + nc_server_del_auth_client_password(auth_client); + } + } + +cleanup: + return ret; +} + +static int +nc_server_configure_pam_name(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_client_auth *auth_client; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "pam-config-file-name")); + + if (equal_parent_name(node, 8, "listen")) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + nc_server_del_auth_client_pam_name(auth_client); + + auth_client->pam_config_name = strdup(lyd_get_value(node)); + if (!auth_client->pam_config_name) { + ERRMEM; + ret = 1; + goto cleanup; + } + } + } + +cleanup: + return ret; +} + +static int +nc_server_configure_pam_dir(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_client_auth *auth_client; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "pam-config-file-dir")); + + if (equal_parent_name(node, 8, "listen")) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + nc_server_del_auth_client_pam_dir(auth_client); + auth_client->pam_config_dir = strdup(lyd_get_value(node)); + if (!auth_client->pam_config_dir) { + ERRMEM; + ret = 1; + goto cleanup; + } + } + } + +cleanup: + return ret; +} + +/* leaf */ +static int +nc_server_configure_none(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_client_auth *auth_client; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "none")); + + if (equal_parent_name(node, 7, "listen")) { + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + auth_client->supports_none = 1; + } else { + auth_client->supports_none = 0; + } + } + +cleanup: + return ret; +} + +static int +nc_server_configure_transport_params(const char *alg, char **alg_store, NC_OPERATION op) +{ + int ret = 0, alg_found = 0; + char *substr, *haystack; + size_t alg_len = strlen(alg); + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + if (!*alg_store) { + /* first call */ + *alg_store = strdup(alg); + if (!*alg_store) { + ERRMEM; + ret = 1; + goto cleanup; + } + } else { + /* +1 because of ',' between algorithms */ + *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + alg_len + 1 + 1); + if (!*alg_store) { + ERRMEM; + ret = 1; + goto cleanup; + } + sprintf(*alg_store, "%s,%s", *alg_store, alg); + } + } else { + /* delete */ + haystack = *alg_store; + while ((substr = strstr(haystack, alg))) { + /* iterate over all the substrings */ + if (((substr == haystack) && (*(substr + alg_len) == ',')) || + ((substr != haystack) && (*(substr - 1) == ',') && (*(substr + alg_len) == ','))) { + /* either the first element of the string or somewhere in the middle */ + memmove(substr, substr + alg_len + 1, strlen(substr + alg_len + 1)); + alg_found = 1; + break; + } else if ((*(substr - 1) == ',') && (*(substr + alg_len) == '\0')) { + /* the last element of the string */ + *(substr - 1) = '\0'; + alg_found = 1; + break; + } + haystack++; + } + if (!alg_found) { + ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg); + ret = 1; + } + } + +cleanup: + return ret; +} + +/* leaf-list */ +static int +nc_server_configure_host_key_alg(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + int ret = 0, listen = 0; + const char *alg; + uint8_t i; + + /* get the algorithm name and compare it with algs supported by libssh */ + alg = ((struct lyd_node_term *)node)->value.ident->name; + + if (equal_parent_name(node, 6, "listen")) { + listen = 1; + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + } + + i = 0; + while (supported_hostkey_algs[i]) { + if (!strcmp(supported_hostkey_algs[i], alg)) { + if (listen) { + if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->hostkey_algs, op)) { + ret = 1; + goto cleanup; + } + } + break; + } + i++; + } + if (!supported_hostkey_algs[i]) { + /* algorithm not supported */ + ERR(NULL, "Public key algorithm (%s) not supported by libssh.", alg); + ret = 1; + } + +cleanup: + return ret; +} + +/* leaf-list */ +static int +nc_server_configure_kex_alg(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + int ret = 0, listen = 0; + const char *alg; + uint8_t i; + + /* get the algorithm name and compare it with algs supported by libssh */ + alg = ((struct lyd_node_term *)node)->value.ident->name; + + if (equal_parent_name(node, 6, "listen")) { + listen = 1; + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + } + + i = 0; + while (supported_kex_algs[i]) { + if (!strcmp(supported_kex_algs[i], alg)) { + if (listen) { + if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->kex_algs, op)) { + ret = 1; + goto cleanup; + } + } + break; + } + i++; + } + if (!supported_kex_algs[i]) { + /* algorithm not supported */ + ERR(NULL, "Key exchange algorithm (%s) not supported by libssh.", alg); + ret = 1; + } + +cleanup: + return ret; +} + +/* leaf-list */ +static int +nc_server_configure_encryption_alg(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + int ret = 0, listen = 0; + const char *alg; + uint8_t i; + + /* get the algorithm name and compare it with algs supported by libssh */ + alg = ((struct lyd_node_term *)node)->value.ident->name; + + if (equal_parent_name(node, 6, "listen")) { + listen = 1; + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + } + + i = 0; + while (supported_encryption_algs[i]) { + if (!strcmp(supported_encryption_algs[i], alg)) { + if (listen) { + if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->encryption_algs, op)) { + ret = 1; + goto cleanup; + } + } + break; + } + i++; + } + if (!supported_encryption_algs[i]) { + /* algorithm not supported */ + ERR(NULL, "Encryption algorithm (%s) not supported by libssh.", alg); + ret = 1; + } + +cleanup: + return ret; +} + +/* leaf-list */ +static int +nc_server_configure_mac_alg(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + int ret = 0, listen = 0; + const char *alg; + uint8_t i; + + /* get the algorithm name and compare it with algs supported by libssh */ + alg = ((struct lyd_node_term *)node)->value.ident->name; + + if (equal_parent_name(node, 6, "listen")) { + listen = 1; + if (nc_server_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + } + + i = 0; + while (supported_mac_algs[i]) { + if (!strcmp(supported_mac_algs[i], alg)) { + if (listen) { + if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->mac_algs, op)) { + ret = 1; + goto cleanup; + } + } + break; + } + i++; + } + if (!supported_mac_algs[i]) { + /* algorithm not supported */ + ERR(NULL, "MAC algorithm (%s) not supported by libssh.", alg); + ret = 1; + } + +cleanup: + return ret; +} + +static int +nc_server_configure(const struct lyd_node *node, NC_OPERATION op) +{ + const char *name = LYD_NAME(node); + + if (!strcmp(name, "listen")) { + if (nc_server_configure_listen(op)) { + goto error; + } + } else if (!strcmp(name, "idle-timeout")) { + if (nc_server_configure_idle_timeout(node, op)) { + goto error; + } + } else if (!strcmp(name, "endpoint")) { + if (nc_server_configure_endpoint(node, op)) { + goto error; + } + } else if (!strcmp(name, "ssh")) { + if (nc_server_configure_ssh(node, op)) { + goto error; + } + } else if (!strcmp(name, "local-address")) { + if (nc_server_configure_local_address(node, op)) { + goto error; + } + } else if (!strcmp(name, "local-port")) { + if (nc_server_configure_local_port(node, op)) { + goto error; + } + } else if (!strcmp(name, "keepalives")) { + if (nc_server_configure_keepalives(node, op)) { + goto error; + } + } else if (!strcmp(name, "idle-time")) { + if (nc_server_configure_idle_time(node, op)) { + goto error; + } + } else if (!strcmp(name, "max-probes")) { + if (nc_server_configure_max_probes(node, op)) { + goto error; + } + } else if (!strcmp(name, "probe-interval")) { + if (nc_server_configure_probe_interval(node, op)) { + goto error; + } + } else if (!strcmp(name, "host-key")) { + if (nc_server_configure_host_key(node, op)) { + goto error; + } + } else if (!strcmp(name, "public-key-format")) { + if (nc_server_configure_public_key_format(node, op)) { + goto error; + } + } else if (!strcmp(name, "public-key")) { + if (nc_server_configure_public_key(node, op)) { + goto error; + } + } else if (!strcmp(name, "private-key-format")) { + if (nc_server_configure_private_key_format(node, op)) { + goto error; + } + } else if (!strcmp(name, "cleartext-private-key")) { + if (nc_server_configure_cleartext_private_key(node, op)) { + goto error; + } + } else if (!strcmp(name, "keystore-reference")) { + if (nc_server_configure_keystore_reference(node, op)) { + goto error; + } + } else if (!strcmp(name, "user")) { + if (nc_server_configure_user(node, op)) { + goto error; + } + } else if (!strcmp(name, "auth-attempts")) { + if (nc_server_configure_auth_attempts(node, op)) { + goto error; + } + } else if (!strcmp(name, "auth-timeout")) { + if (nc_server_configure_auth_timeout(node, op)) { + goto error; + } + } else if (!strcmp(name, "truststore-reference")) { + if (nc_server_configure_truststore_reference(node, op)) { + goto error; + } + } else if (!strcmp(name, "password")) { + if (nc_server_configure_password(node, op)) { + goto error; + } + } else if (!strcmp(name, "pam-config-file-name")) { + if (nc_server_configure_pam_name(node, op)) { + goto error; + } + } else if (!strcmp(name, "pam-config-file-dir")) { + if (nc_server_configure_pam_dir(node, op)) { + goto error; + } + } else if (!strcmp(name, "none")) { + if (nc_server_configure_none(node, op)) { + goto error; + } + } else if (!strcmp(name, "host-key-alg")) { + if (nc_server_configure_host_key_alg(node, op)) { + goto error; + } + } else if (!strcmp(name, "key-exchange-alg")) { + if (nc_server_configure_kex_alg(node, op)) { + goto error; + } + } else if (!strcmp(name, "encryption-alg")) { + if (nc_server_configure_encryption_alg(node, op)) { + goto error; + } + } else if (!strcmp(name, "mac-alg")) { + if (nc_server_configure_mac_alg(node, op)) { + goto error; + } + } else if (!strcmp(name, "cert-data")) {} else if (!strcmp(name, "expiration-date")) {} else if (!strcmp(name, "asymmetric-key")) {} else if (!strcmp(name, "certificate")) {} else if (!strcmp(name, "key-format")) {} else if (!strcmp(name, + "cleartext-key")) {} else if (!strcmp(name, "hidden-key")) {} else if (!strcmp(name, "id_hint")) {} else if (!strcmp(name, "external-identity")) {} else if (!strcmp(name, "hash")) {} else if (!strcmp(name, "context")) {} else if (!strcmp(name, + "target-protocol")) {} else if (!strcmp(name, "target-kdf")) {} else if (!strcmp(name, "client-authentication")) {} else if (!strcmp(name, "ca-certs")) {} else if (!strcmp(name, "ee-certs")) {} else if (!strcmp(name, + "raw-public-keys")) {} else if (!strcmp(name, "tls12-psks")) {} else if (!strcmp(name, "tls13-epsks")) {} else if (!strcmp(name, "tls-version")) {} else if (!strcmp(name, "cipher-suite")) {} else if (!strcmp(name, + "peer-allowed-to-send")) {} else if (!strcmp(name, "test-peer-aliveness")) {} else if (!strcmp(name, "max-wait")) {} else if (!strcmp(name, "max-attempts")) {} else if (!strcmp(name, "cert-to-name")) {} else if (!strcmp(name, + "id")) {} else if (!strcmp(name, "fingerprint")) {} else if (!strcmp(name, "map-type")) {} + + return 0; + +error: + ERR(NULL, "Configuring (%s) failed.", LYD_NAME(node)); + return 1; +} + +int +nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op) +{ + struct lyd_node *child; + struct lyd_meta *m; + NC_OPERATION current_op; + + assert(node); + + /* get current op */ + LY_LIST_FOR(node->meta, m) { + if (!strcmp(m->name, "operation")) { + if (!strcmp(lyd_get_meta_value(m), "create")) { + current_op = NC_OP_CREATE; + } else if (!strcmp(lyd_get_meta_value(m), "delete")) { + current_op = NC_OP_DELETE; + } else if (!strcmp(lyd_get_meta_value(m), "replace")) { + current_op = NC_OP_REPLACE; + } else if (!strcmp(lyd_get_meta_value(m), "none")) { + current_op = NC_OP_NONE; + } + break; + } + } + + /* node has no op, inherit from the parent */ + if (!m) { + current_op = parent_op; + } + + switch (current_op) { + case NC_OP_NONE: + break; + case NC_OP_CREATE: + case NC_OP_DELETE: + case NC_OP_REPLACE: + if (nc_server_configure(node, current_op)) { + return 1; + } + break; + default: + break; + } + + if (current_op != NC_OP_DELETE) { + LY_LIST_FOR(lyd_child(node), child) { + if (nc_session_server_parse_tree(child, current_op)) { + return 1; + } + } + } + return 0; +} + +static int +nc_server_configure_certificates(const struct lyd_node *node, struct nc_keystore *ks) +{ + int ret = 0; + uint16_t cert_count; + void *tmp; + + node = node->next; + if ((!node) || (strcmp(LYD_NAME(node), "certificate"))) { + WRN(NULL, "Certificates container is empty"); + goto cleanup; + } + + /* certificate list */ + while (node) { + cert_count = ks->cert_count; + tmp = realloc(ks->certs, cert_count + 1); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + ks->certs = tmp; + + ks->certs[cert_count].name = strdup(lyd_get_value(lyd_child(node))); + if (!ks->certs[cert_count].name) { + ERRMEM; + ret = 1; + goto cleanup; + } + + ks->certs[cert_count].cert_data = strdup(lyd_get_value(lyd_child(node)->next)); + if (!ks->certs[cert_count].cert_data) { + ERRMEM; + free(ks->certs[cert_count].name); + ret = 1; + goto cleanup; + } + + ks->cert_count++; + } + +cleanup: + if (ret) { + for (cert_count = 0; cert_count < ks->cert_count; cert_count++) { + free(ks->certs[cert_count].name); + free(ks->certs[cert_count].cert_data); + } + free(ks->certs); + } + return ret; +} + +static int +nc_fill_keystore(const struct lyd_node *data) +{ + int ret = 0; + uint32_t prev_lo; + struct lyd_node *tree, *node, *iter, *iter_tmp; + void *tmp; + struct nc_keystore *ks; + + /* silently search for keystore node */ + prev_lo = ly_log_options(0); + ret = lyd_find_path(data, "/ks:keystore", 0, &tree); + ly_log_options(prev_lo); + if (ret) { + WRN(NULL, "Keystore container not found in the YANG data."); + return 0; + } + + /* asymmetric keys container */ + lyd_find_path(tree, "asymmetric-keys", 0, (struct lyd_node **)&node); + if (!node) { + WRN(NULL, "Asymmetric keys container not found in the YANG data."); + return 0; + } + + /* asymmetric key list */ + lyd_find_path(node, "asymmetric-key", 0, (struct lyd_node **)&node); + if (!node) { + WRN(NULL, "Asymmetric keys container is empty."); + return 0; + } + + LY_LIST_FOR(node, iter) { + tmp = realloc(server_opts.keystore, server_opts.keystore_count + 1); + if (!tmp) { + ERRMEM; + goto fail; + } + server_opts.keystore = tmp; + ks = &server_opts.keystore[server_opts.keystore_count]; + + iter_tmp = iter; + /* name */ + iter_tmp = lyd_child(iter_tmp); + ks->name = strdup(lyd_get_value(iter_tmp)); + if (!ks->name) { + ERRMEM; + goto fail; + } + + /* mandatory public-key-format */ + iter_tmp = iter_tmp->next; + if (nc_server_configure_public_key_format(iter_tmp, 0)) { + free(ks->name); + goto fail; + } + + /* mandatory public-key */ + iter_tmp = iter_tmp->next; + ks->pub_base64 = strdup(lyd_get_value(iter_tmp)); + if (!ks->pub_base64) { + free(ks->name); + ERRMEM; + goto fail; + } + + iter_tmp = iter_tmp->next; + while (iter_tmp) { + if (!strcmp(LYD_NAME(iter_tmp), "private-key-format")) { + if (nc_server_configure_private_key_format(iter_tmp, 0)) { + goto fail; + } + } else if (!strcmp(LYD_NAME(iter_tmp), "private-key-type")) { + if ((!strcmp(LYD_NAME(lyd_child(iter_tmp)), "cleartext-private-key")) && + (!strcmp(LYD_NAME(lyd_child(lyd_child(iter_tmp))), "cleartext-private-key"))) { + ks->priv_base64 = strdup(lyd_get_value(lyd_child(lyd_child(iter_tmp)))); + if (!ks->priv_base64) { + ERRMEM; + goto fail; + } + } + } else if (!strcmp(LYD_NAME(iter_tmp), "certificates")) { + if (nc_server_configure_certificates(iter_tmp, ks)) { + goto fail; + } + } + /* todo CSR? */ + iter_tmp = iter_tmp->next; + } + + server_opts.keystore_count++; + } + + return 0; + +fail: + free(server_opts.keystore); + return 1; +} + +API int +nc_server_config_load_modules(struct ly_ctx **ctx) +{ + int i, new_ctx = 0; + + if (!*ctx) { + if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) { + ERR(NULL, "Couldn't create new libyang context.\n"); + goto error; + } + new_ctx = 1; + } + + /* all features */ + const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL}; + /* all features */ + const char *ietf_x509_cert_to_name[] = {NULL}; + /* no private-key-encryption and csr-generation */ + const char *ietf_crypto_types[] = { + "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format", + "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format", + "p10-based-csrs", "certificate-expiration-notification", "hidden-keys", "password-encryption", + "symmetric-key-encryption", NULL + }; + /* all features */ + const char *ietf_tcp_common[] = {"keepalives-supported", NULL}; + /* no ssh-x509-certs */ + const char *ietf_ssh_common[] = {"transport-params", "public-key-generation", NULL}; + /* all features */ + const char *iana_ssh_encryption_algs[] = {NULL}; + /* all features */ + const char *iana_ssh_key_exchange_algs[] = {NULL}; + /* all features */ + const char *iana_ssh_mac_algs[] = {NULL}; + /* all features */ + const char *iana_ssh_public_key_algs[] = {NULL}; + /* all features */ + const char *ietf_keystore[] = {"central-keystore-supported", "local-definitions-supported", "asymmetric-keys", "symmetric-keys", NULL}; + /* no ssh-server-keepalives and local-user-auth-hostbased */ + const char *ietf_ssh_server[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL}; + /* all features */ + const char *ietf_truststore[] = {"central-truststore-supported", "local-definitions-supported", "certificates", "public-keys", NULL}; + /* all features */ + const char *ietf_tls_server[] = { + "tls-server-keepalives", "server-ident-x509-cert", "server-ident-raw-public-key", "server-ident-tls12-psk", + "server-ident-tls13-epsk", "client-auth-supported", "client-auth-x509-cert", "client-auth-raw-public-key", + "client-auth-tls12-psk", "client-auth-tls13-epsk", NULL + }; + /* all features */ + const char *libnetconf2_netconf_server[] = {NULL}; + + const char *module_names[] = { + "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", + "ietf-tcp-common", "ietf-ssh-common", "iana-ssh-encryption-algs", + "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", + "ietf-keystore", "ietf-ssh-server", "ietf-truststore", + "ietf-tls-server", "libnetconf2-netconf-server", NULL + }; + + const char **module_features[] = { + ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, + ietf_tcp_common, ietf_ssh_common, iana_ssh_encryption_algs, + iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, + ietf_keystore, ietf_ssh_server, ietf_truststore, + ietf_tls_server, libnetconf2_netconf_server, NULL + }; + + for (i = 0; module_names[i] != NULL; i++) { + if (!ly_ctx_load_module(*ctx, module_names[i], NULL, module_features[i])) { + ERR(NULL, "Loading module \"%s\" failed.\n", module_names[i]); + goto error; + } + } + + return 0; + +error: + if (new_ctx) { + ly_ctx_destroy(*ctx); + *ctx = NULL; + } + return 1; +} + +API int +nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path) +{ + struct lyd_node *tree = NULL; + int ret = 0; + + if (!path) { + ERRARG("Missing path parameter."); + ret = 1; + goto cleanup; + } + + ret = lyd_parse_data_path(ctx, path, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_setup(tree); + if (ret) { + goto cleanup; + } + +cleanup: + lyd_free_all(tree); + return ret; +} + +API int +nc_server_config_setup(const struct lyd_node *data) +{ + int ret = 0; + struct lyd_node *tree; + struct lyd_meta *m; + NC_OPERATION op; + + /* LOCK */ + pthread_rwlock_wrlock(&server_opts.config_lock); + + ret = nc_fill_keystore(data); + if (ret) { + ERR(NULL, "Filling keystore failed."); + goto cleanup; + } + + ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree); + if (ret) { + ERR(NULL, "Unable to find the netconf-server container in the YANG data."); + goto cleanup; + } + + LY_LIST_FOR(tree->meta, m) { + if (!strcmp(m->name, "operation")) { + if (!strcmp(lyd_get_meta_value(m), "create")) { + op = NC_OP_CREATE; + } else if (!strcmp(lyd_get_meta_value(m), "delete")) { + op = NC_OP_DELETE; + } else if (!strcmp(lyd_get_meta_value(m), "replace")) { + op = NC_OP_REPLACE; + } else if (!strcmp(lyd_get_meta_value(m), "none")) { + op = NC_OP_NONE; + } else { + ERR(NULL, "Unexpected operation (%s).", lyd_get_meta_value(m)); + ret = 1; + goto cleanup; + } + } + } + + if (nc_session_server_parse_tree(tree, op)) { + ret = 1; + goto cleanup; + } + +cleanup: + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); + return ret; +} diff --git a/src/config_server.h b/src/config_server.h new file mode 100644 index 00000000..9adfede7 --- /dev/null +++ b/src/config_server.h @@ -0,0 +1,83 @@ +/** + * @file config_server.h + * @author Roman Janota + * @brief libnetconf2 server configuration + * + * @copyright + * Copyright (c) 2015 - 2021 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_H_ +#define NC_CONFIG_SERVER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "netconf.h" +#include "session.h" +#include "session_p.h" + +/** + * @brief Configure server based on the given data. + * + * Expected data is a validated instance of a ietf-netconf-server YANG data. + * The data must be in the diff format and supported operations are: create, replace, + * delete and none. Context must already have implemented the required modules, see + * ::nc_config_load_modules(). + * + * @param[in] data ietf-netconf-server YANG data. + * @return 0 on success, 1 on error. + */ +int nc_server_config_setup(const struct lyd_node *data); + +/** + * @brief Configure server based on the given ietf-netconf-server YANG data. + * Wrapper around ::nc_config_setup_server() hiding work with parsing the data. + * + * @param[in] ctx libyang context. + * @param[in] path Path to the file with YANG data in XML format. + * @return 0 on success, 1 on error. + */ +int nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path); + +/** + * @brief Implements all the required modules and their features in the context. + * Needs to be called before any other configuration functions. + * + * If ctx is : + * - NULL: a new context will be created and if the call is successful you have to free it, + * - non NULL: modules will simply be implemented. + * + * Implemented modules: ietf-netconf-server, ietf-x509-cert-to-name, ietf-crypto-types, + * ietf-tcp-common, ietf-ssh-common, iana-ssh-encryption-algs, iana-ssh-key-exchange-algs, + * iana-ssh-mac-algs, iana-ssh-public-key-algs, ietf-keystore, ietf-ssh-server, ietf-truststore, + * ietf-tls-server and libnetconf2-netconf-server. + * + * @param[in, out] ctx Optional context in which the modules will be implemented. Created if ctx is null. + * @return 0 on success, 1 on error. + */ +int nc_server_config_load_modules(struct ly_ctx **ctx); + +/** + * @brief Configures the listen subtree in the ietf-netconf-server module. + * + * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. + * @return 0 on success, 1 on error. + */ +int nc_server_configure_listen(NC_OPERATION op); + +#ifdef __cplusplus +} +#endif + +#endif /* NC_SESSION_SERVER_H_ */ diff --git a/src/log_p.h b/src/log_p.h index 5f772d49..0feb8cce 100644 --- a/src/log_p.h +++ b/src/log_p.h @@ -52,5 +52,11 @@ extern ATOMIC_T verbose_level; #define ERRARG(arg) ERR(NULL, "%s: invalid argument (%s).", __func__, arg) #define ERRINIT ERR(NULL, "%s: libnetconf2 not initialized.", __func__) #define ERRINT ERR(NULL, "%s: internal error (%s:%d).", __func__, __FILE__, __LINE__) +#define ERRNODE(name) ERR(NULL, "%s: missing node (%s) in the YANG data.", __func__, name) +#define UNEXNODE(name) VRB(NULL, "%s: unexpected node (%s) in the YANG data.", __func__, name) +#define CHECKNODE(node, name) if (strcmp(LYD_NAME(node), name)) { \ + ERR(NULL, "%s: missing node (%s) in the YANG data.", __func__, name); \ + return 1; \ + } #endif /* NC_LOG_PRIVATE_H_ */ diff --git a/src/session.c b/src/session.c index d148fcf8..1a7f1e5e 100644 --- a/src/session.c +++ b/src/session.c @@ -125,7 +125,7 @@ nc_keytype2str(NC_SSH_KEY_TYPE type) } int -nc_sock_enable_keepalive(int sock, struct nc_keepalives *ka) +nc_sock_configure_keepalive(int sock, struct nc_keepalives *ka) { int opt; @@ -754,24 +754,6 @@ nc_session_free_transport(struct nc_session *session, int *multisession) /* there are still multiple sessions, keep the ring list */ siter->ti.libssh.next = session->ti.libssh.next; } - - /* change nc_sshcb_msg() argument, we need a RUNNING session and this one will be freed */ - if (session->flags & NC_SESSION_SSH_MSG_CB) { - siter = session->ti.libssh.next; - while (siter && (siter->status != NC_STATUS_RUNNING)) { - if (siter->ti.libssh.next == session) { - ERRINT; - break; - } - siter = siter->ti.libssh.next; - } - /* siter may be NULL in case all the sessions terminated at the same time (socket was disconnected), - * we set session to NULL because we do not expect any new message to arrive */ - ssh_set_message_callback(session->ti.libssh.session, nc_sshcb_msg, siter); - if (siter) { - siter->flags |= NC_SESSION_SSH_MSG_CB; - } - } } /* SESSION IO UNLOCK */ @@ -1032,6 +1014,8 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version) uint32_t i, u; LY_ARRAY_COUNT_TYPE v; char *yl_content_id; + uint32_t wd_also_supported; + uint32_t wd_basic_mode; #define NC_CPBLT_BUF_LEN 4096 char str[NC_CPBLT_BUF_LEN]; @@ -1088,11 +1072,12 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version) mod = ly_ctx_get_module_implemented(ctx, "ietf-netconf-with-defaults"); if (mod) { - if (!server_opts.wd_basic_mode) { + wd_basic_mode = ATOMIC_LOAD_RELAXED(server_opts.wd_basic_mode); + if (!wd_basic_mode) { VRB(NULL, "with-defaults capability will not be advertised even though \"ietf-netconf-with-defaults\" model is present, unknown basic-mode."); } else { strcpy(str, "urn:ietf:params:netconf:capability:with-defaults:1.0"); - switch (server_opts.wd_basic_mode) { + switch (wd_basic_mode) { case NC_WD_ALL: strcat(str, "?basic-mode=report-all"); break; @@ -1107,18 +1092,19 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version) break; } - if (server_opts.wd_also_supported) { + wd_also_supported = ATOMIC_LOAD_RELAXED(server_opts.wd_also_supported); + if (wd_also_supported) { strcat(str, "&also-supported="); - if (server_opts.wd_also_supported & NC_WD_ALL) { + if (wd_also_supported & NC_WD_ALL) { strcat(str, "report-all,"); } - if (server_opts.wd_also_supported & NC_WD_ALL_TAG) { + if (wd_also_supported & NC_WD_ALL_TAG) { strcat(str, "report-all-tagged,"); } - if (server_opts.wd_also_supported & NC_WD_TRIM) { + if (wd_also_supported & NC_WD_TRIM) { strcat(str, "trim,"); } - if (server_opts.wd_also_supported & NC_WD_EXPLICIT) { + if (wd_also_supported & NC_WD_EXPLICIT) { strcat(str, "explicit,"); } str[strlen(str) - 1] = '\0'; diff --git a/src/session_client.c b/src/session_client.c index 00d78db4..e086fa21 100644 --- a/src/session_client.c +++ b/src/session_client.c @@ -1650,7 +1650,7 @@ sock_connect(int timeout_ms, int *sock_pending, struct addrinfo *res, struct nc_ } /* enable keep-alive */ - if (nc_sock_enable_keepalive(sock, ka)) { + if (nc_sock_configure_keepalive(sock, ka)) { goto cleanup; } diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c index 647a526d..bacfc139 100644 --- a/src/session_client_ssh.c +++ b/src/session_client_ssh.c @@ -167,6 +167,7 @@ _nc_client_ssh_destroy_opts(struct nc_client_ssh_opts *opts) } free(opts->keys); free(opts->username); + opts->key_count = 0; opts->keys = NULL; opts->username = NULL; } @@ -1213,7 +1214,6 @@ connect_ssh_session(struct nc_session *session, struct nc_client_ssh_opts *opts, ERR(session, "Authentication failed (%s).", ssh_get_error(ssh_sess)); return -1; } else if (ret_auth == SSH_AUTH_SUCCESS) { - WRN(session, "Server accepts \"none\" authentication method.") return 1; } diff --git a/src/session_p.h b/src/session_p.h index b352cc44..3db14574 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -43,6 +43,33 @@ /* number of all supported authentication methods */ # define NC_SSH_AUTH_COUNT 3 +/** + * Enumeration of diff operation types. + */ +typedef enum { + NC_OP_NONE, + NC_OP_CREATE, + NC_OP_DELETE, + NC_OP_REPLACE +} NC_OPERATION; + +/** + * Enumeration of key or certificate store type. + */ +typedef enum { + NC_STORE_LOCAL, /**< key/certificate is stored locally in the ietf-netconf-server YANG data */ + NC_STORE_KEYSTORE, /**< key/certificate is stored externally in a keystore module YANG data */ + NC_STORE_TRUSTSTORE /**< key/certificate is stored externally in a truststore module YANG data */ +} NC_STORE_TYPE; + +/** + * Enumeration of SSH public key representation types. + */ +typedef enum { + NC_SSH_PUBKEY_SSH2, /**< begins with BEGIN SSH2 PUBLICKEY, see RFC 4716 */ + NC_SSH_PUBKEY_X509 /**< begins with BEGIN PUBLICKEY, see RFC 5280 sec. 4.1.2.7 */ +} NC_SSH_PUBKEY_TYPE; + /* ACCESS unlocked */ struct nc_client_ssh_opts { /* SSH authentication method preferences */ @@ -74,13 +101,71 @@ struct nc_client_ssh_opts { char *username; }; +struct nc_certificate { + char *name; + char *cert_data; +}; + +struct nc_keystore { + char *name; + char *pub_base64; + char *priv_base64; + NC_SSH_KEY_TYPE privkey_type; + + struct nc_certificate *certs; + uint16_t cert_count; +}; + +struct nc_client_auth { + char *username; + + NC_STORE_TYPE ks_type; + union { + struct { + struct nc_client_auth_pubkey { + char *name; + char *pub_base64; + NC_SSH_PUBKEY_TYPE pubkey_type; + } *pubkeys; + uint16_t pubkey_count; + }; + char *ts_reference; + }; + + char *password; + char *pam_config_name; + char *pam_config_dir; + int supports_none; +}; + +struct nc_hostkey { + char *name; + + NC_STORE_TYPE ks_type; + union { + struct { + NC_SSH_PUBKEY_TYPE pubkey_type; + char *pub_base64; + NC_SSH_KEY_TYPE privkey_type; + char *priv_base64; + }; + struct nc_keystore *keystore; + }; +}; + /* ACCESS locked, separate locks */ struct nc_server_ssh_opts { - /* SSH bind options */ - char **hostkeys; - uint8_t hostkey_count; + struct nc_hostkey *hostkeys; /* everything in ks */ + uint16_t hostkey_count; + + struct nc_client_auth *auth_clients; + uint16_t client_count; + + char *hostkey_algs; + char *encryption_algs; + char *kex_algs; + char *mac_algs; - int auth_methods; uint16_t auth_attempts; uint16_t auth_timeout; }; @@ -142,6 +227,13 @@ struct nc_server_unix_opts { gid_t gid; }; +struct nc_bind { + char *address; + uint16_t port; + int sock; + int pollin; +}; + /* ACCESS unlocked */ struct nc_client_opts { char *schema_searchpath; @@ -150,12 +242,7 @@ struct nc_client_opts { void *schema_clb_data; struct nc_keepalives ka; - struct nc_bind { - char *address; - uint16_t port; - int sock; - int pollin; - } *ch_binds; + struct nc_bind *ch_binds; struct { NC_TRANSPORT_IMPL ti; @@ -181,8 +268,8 @@ struct nc_client_context { struct nc_server_opts { /* ACCESS unlocked */ - NC_WD_MODE wd_basic_mode; - int wd_also_supported; + ATOMIC_T wd_basic_mode; + ATOMIC_T wd_also_supported; uint32_t capabilities_count; char **capabilities; @@ -192,8 +279,8 @@ struct nc_server_opts { void (*content_id_data_free)(void *data); /* ACCESS unlocked */ - uint16_t hello_timeout; - uint16_t idle_timeout; + ATOMIC_T hello_timeout; + ATOMIC_T idle_timeout; #ifdef NC_ENABLED_SSH int (*passwd_auth_clb)(const struct nc_session *session, const char *password, void *user_data); @@ -211,8 +298,6 @@ struct nc_server_opts { int (*interactive_auth_clb)(const struct nc_session *session, ssh_message msg, void *user_data); void *interactive_auth_data; void (*interactive_auth_data_free)(void *data); - char *conf_name; - char *conf_dir; #endif #ifdef NC_ENABLED_TLS int (*user_verify_clb)(const struct nc_session *session); @@ -233,31 +318,14 @@ struct nc_server_opts { void (*trusted_cert_list_data_free)(void *data); #endif -#ifdef NC_ENABLED_SSH - /* ACCESS locked with authkey_lock */ - struct { - char *path; - char *base64; - NC_SSH_KEY_TYPE type; - char *username; - } *authkeys; - uint16_t authkey_count; - pthread_mutex_t authkey_lock; - - int (*hostkey_clb)(const char *name, void *user_data, char **privkey_path, char **privkey_data, - NC_SSH_KEY_TYPE *privkey_type); - void *hostkey_data; - void (*hostkey_data_free)(void *data); -#endif + pthread_rwlock_t config_lock; + struct nc_keystore *keystore; /**< store for keys/certificates */ + uint16_t keystore_count; - /* ACCESS locked, add/remove endpts/binds - bind_lock + WRITE endpt_lock (strict order!) - * modify endpts - WRITE endpt_lock - * access endpts - READ endpt_lock - * modify/poll binds - bind_lock */ struct nc_bind *binds; - pthread_mutex_t bind_lock; struct nc_endpt { char *name; + int changed; NC_TRANSPORT_IMPL ti; struct nc_keepalives ka; @@ -272,7 +340,6 @@ struct nc_server_opts { } opts; } *endpts; uint16_t endpt_count; - pthread_rwlock_t endpt_lock; /* ACCESS locked, add/remove CH clients - WRITE lock ch_client_lock * modify CH clients - READ lock ch_client_lock + ch_client_lock */ @@ -477,11 +544,6 @@ struct nc_session { # define NC_SESSION_SSH_AUTHENTICATED 0x10 /* netconf subsystem requested */ # define NC_SESSION_SSH_SUBSYS_NETCONF 0x20 - /* new SSH message arrived */ -# define NC_SESSION_SSH_NEW_MSG 0x40 - /* this session is passed to nc_sshcb_msg() */ -# define NC_SESSION_SSH_MSG_CB 0x80 - uint16_t ssh_auth_attempts; /**< number of failed SSH authentication attempts */ #endif #ifdef NC_ENABLED_TLS @@ -531,6 +593,7 @@ struct nc_ntf_thread_arg { struct nc_pam_thread_arg { ssh_message msg; /**< libssh message */ struct nc_session *session; /**< NETCONF session */ + struct nc_server_ssh_opts *opts; /**< SSH server opts */ }; #endif @@ -566,7 +629,7 @@ void nc_realtime_get(struct timespec *ts); const char *nc_keytype2str(NC_SSH_KEY_TYPE type); -int nc_sock_enable_keepalive(int sock, struct nc_keepalives *ka); +int nc_sock_configure_keepalive(int sock, struct nc_keepalives *ka); struct nc_session *nc_new_session(NC_SIDE side, int shared_ti); @@ -789,17 +852,17 @@ struct nc_session *nc_accept_callhome_ssh_sock(int sock, const char *host, uint1 * @param[in] timeout Transport operations timeout in msec (not SSH authentication one). * @return 1 on success, 0 on timeout, -1 on error. */ -int nc_accept_ssh_session(struct nc_session *session, int sock, int timeout); +int nc_accept_ssh_session(struct nc_session *session, struct nc_server_ssh_opts *opts, int sock, int timeout); /** - * @brief Callback called when a new SSH message is received. + * @brief Process a SSH message. * - * @param[in] sshsession SSH session the message arrived on. + * @param[in] session Session structure of the connection. + * @param[in] opts Endpoint SSH options on which the session was created. * @param[in] msg SSH message itself. - * @param[in] data NETCONF session running on @p sshsession. * @return 0 if the message was handled, 1 if it is left up to libssh. */ -int nc_sshcb_msg(ssh_session sshsession, ssh_message msg, void *data); +int nc_session_ssh_msg(struct nc_session *session, struct nc_server_ssh_opts *opts, ssh_message msg); void nc_server_ssh_clear_opts(struct nc_server_ssh_opts *opts); diff --git a/src/session_server_tls.c b/src/session_server_tls.c index 9b9b3f10..76b3c8ce 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -932,7 +932,7 @@ nc_server_tls_endpt_set_server_cert(const char *endpt_name, const char *name) } ret = nc_server_tls_set_server_cert(name, endpt->opts.tls); /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); + pthread_rwlock_unlock(&server_opts.config_lock); return ret; } @@ -1025,7 +1025,7 @@ nc_server_tls_endpt_add_trusted_cert_list(const char *endpt_name, const char *na } ret = nc_server_tls_add_trusted_cert_list(name, endpt->opts.tls); /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); + pthread_rwlock_unlock(&server_opts.config_lock); return ret; } @@ -1116,7 +1116,7 @@ nc_server_tls_endpt_del_trusted_cert_list(const char *endpt_name, const char *na } ret = nc_server_tls_del_trusted_cert_list(name, endpt->opts.tls); /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); + pthread_rwlock_unlock(&server_opts.config_lock); return ret; } @@ -1181,7 +1181,7 @@ nc_server_tls_endpt_set_trusted_ca_paths(const char *endpt_name, const char *ca_ } ret = nc_server_tls_set_trusted_ca_paths(ca_file, ca_dir, endpt->opts.tls); /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); + pthread_rwlock_unlock(&server_opts.config_lock); return ret; } @@ -1272,7 +1272,7 @@ nc_server_tls_endpt_set_crl_paths(const char *endpt_name, const char *crl_file, } ret = nc_server_tls_set_crl_paths(crl_file, crl_dir, endpt->opts.tls); /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); + pthread_rwlock_unlock(&server_opts.config_lock); return ret; } @@ -1327,7 +1327,7 @@ nc_server_tls_endpt_clear_crls(const char *endpt_name) } nc_server_tls_clear_crls(endpt->opts.tls); /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); + pthread_rwlock_unlock(&server_opts.config_lock); } API void @@ -1422,7 +1422,7 @@ nc_server_tls_endpt_add_ctn(const char *endpt_name, uint32_t id, const char *fin } ret = nc_server_tls_add_ctn(id, fingerprint, map_type, name, endpt->opts.tls); /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); + pthread_rwlock_unlock(&server_opts.config_lock); return ret; } @@ -1520,7 +1520,7 @@ nc_server_tls_endpt_del_ctn(const char *endpt_name, int64_t id, const char *fing } ret = nc_server_tls_del_ctn(id, fingerprint, map_type, name, endpt->opts.tls); /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); + pthread_rwlock_unlock(&server_opts.config_lock); return ret; } @@ -1608,7 +1608,7 @@ nc_server_tls_endpt_get_ctn(const char *endpt_name, uint32_t *id, char **fingerp } ret = nc_server_tls_get_ctn(id, fingerprint, map_type, name, endpt->opts.tls); /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); + pthread_rwlock_unlock(&server_opts.config_lock); return ret; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 663c0c44..8796d895 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,11 +8,11 @@ if(${SOURCE_FORMAT_ENABLED}) endif() # list of all the tests in each directory -set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages) +set(tests test_nc3) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) - list(APPEND tests test_pam) + list(APPEND tests test_auth test_two_channels) endif() set(client_tests test_client test_client_messages) @@ -37,7 +37,7 @@ endforeach() #append tests depending on SSH/TLS if(ENABLE_SSH OR ENABLE_TLS) - list(APPEND tests test_server_thread) + #list(APPEND tests test_server_thread) if(ENABLE_SSH) list(APPEND client_tests test_client_ssh) endif() diff --git a/tests/client/test_client_ssh.c b/tests/client/test_client_ssh.c index 8d50145d..175577bf 100644 --- a/tests/client/test_client_ssh.c +++ b/tests/client/test_client_ssh.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -34,6 +35,67 @@ #include #include +const char *data = + "\n" + " \n" + " 10\n" + " \n" + " default-ssh\n" + " \n" + " \n" + " 127.0.0.1\n" + " 10005\n" + " \n" + " \n" + " \n" + " \n" + " key\n" + " \n" + " \n" + " ct:ssh-public-key-format\n" + " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" + " ct:rsa-private-key-format\n" + " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " test\n" + " \n" + " \n" + " \n" + " client\n" + " ct:ssh-public-key-format\n" + " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " sshpka:rsa-sha2-512\n" + " \n" + " \n" + " sshkea:curve25519-sha256\n" + " \n" + " \n" + " sshea:aes256-ctr\n" + " \n" + " \n" + " sshma:hmac-sha2-512\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + static int ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) { @@ -596,7 +658,7 @@ test_nc_connect_ssh_password_succesfull(void **state) } static void -test_nc_connect_ssh_pubkey_succesfull(void **state) +test_nc_connect_ssh_pubkey_ecdsa_succesfull(void **state) { (void)state; struct nc_session *session; @@ -633,6 +695,65 @@ test_nc_connect_ssh_pubkey_succesfull(void **state) /* disconnect */ will_return(__wrap_ssh_channel_poll_timeout, 0); nc_session_free(session, NULL); + + /* delete the keypair */ + ret = nc_client_ssh_del_keypair(0); + assert_int_equal(ret, 0); +} + +static void +test_nc_connect_ssh_pubkey_succesfull(void **state) +{ + (void)state; + struct nc_session *session; + struct ly_ctx *ctx; + struct lyd_node *tree; + int ret = 0; + + /* set authentication method to use password authentication */ + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); + + /* add keypair for authentication */ + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + assert_int_equal(ret, 0); + + /* fake succesfull connection */ + will_return(__wrap_connect, 0); + will_return(__wrap_ssh_connect, 0); + /* do not authenticate using no authentication method */ + will_return(__wrap_ssh_userauth_none, 1); + will_return(__wrap_ssh_userauth_try_publickey, 0); + will_return(__wrap_ssh_userauth_publickey, 0); + will_return(__wrap_ssh_is_connected, 1); + will_return(__wrap_ssh_channel_open_session, 0); + will_return(__wrap_ssh_channel_request_subsystem, 0); + + /* fake ssh function for recieving hello message */ + will_return(__wrap_ssh_is_connected, 1); + + will_return(__wrap_nc_handshake_io, 3); + will_return(__wrap_nc_ctx_check_and_fill, 0); + + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup(tree); + assert_int_equal(ret, 0); + + session = nc_connect_ssh("127.0.0.1", 8080, NULL); + assert_non_null(session); + + /* disconnect */ + will_return(__wrap_ssh_channel_poll_timeout, 0); + nc_session_free(session, NULL); } static void @@ -816,6 +937,7 @@ main(void) cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_username, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_connect_ssh_interactive_succesfull, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_connect_ssh_password_succesfull, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_connect_ssh_pubkey_ecdsa_succesfull, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_connect_ssh_pubkey_succesfull, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_connect_connection_failed, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_connect_ssh_bad_hello, setup_f, teardown_f), diff --git a/tests/config.h.in b/tests/config.h.in index 42a80787..cf58c40c 100644 --- a/tests/config.h.in +++ b/tests/config.h.in @@ -19,6 +19,7 @@ #endif #define TESTS_DIR "@CMAKE_SOURCE_DIR@/tests" +#define MODULES_DIR "@CMAKE_SOURCE_DIR@/modules" #define BUILD_DIR "@CMAKE_BINARY_DIR@" @SSH_MACRO@ diff --git a/tests/pam/pam_netconf.c b/tests/pam/pam_netconf.c index dd30fe07..835f4832 100644 --- a/tests/pam/pam_netconf.c +++ b/tests/pam/pam_netconf.c @@ -259,7 +259,7 @@ pam_sm_acct_mgmt(pam_handle_t *pam_h, int flags, int argc, const char *argv[]) if (r != PAM_SUCCESS) { return r; } - if (!strcmp((const char *)username, "test")) { + if (!strcmp((const char *)username, "test_int")) { return PAM_NEW_AUTHTOK_REQD; } return PAM_SYSTEM_ERR; @@ -291,7 +291,7 @@ pam_sm_chauthtok(pam_handle_t *pam_h, int flags, int argc, const char *argv[]) if (r != PAM_SUCCESS) { return r; } - if (!strcmp((const char *)username, "test")) { + if (!strcmp((const char *)username, "test_int")) { return PAM_SUCCESS; } else { return PAM_SYSTEM_ERR; @@ -299,7 +299,7 @@ pam_sm_chauthtok(pam_handle_t *pam_h, int flags, int argc, const char *argv[]) /* change the authentication token in the second call */ } else if (flags & PAM_UPDATE_AUTHTOK) { - r = pam_set_item(pam_h, PAM_AUTHTOK, "test"); + r = pam_set_item(pam_h, PAM_AUTHTOK, "test_int"); if (r == PAM_SUCCESS) { printf("[TEST #6] Passed.\n\n"); } else { diff --git a/tests/test_auth.c b/tests/test_auth.c new file mode 100644 index 00000000..29b22b16 --- /dev/null +++ b/tests/test_auth.c @@ -0,0 +1,457 @@ +/** + * @file test_auth.c + * @author Roman Janota + * @brief libnetconf2 Linux PAM keyboard-interactive authentication test + * + * @copyright + * Copyright (c) 2022 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 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 100 +#define NC_PS_POLL_TIMEOUT 100 + +struct ly_ctx *ctx; + +struct test_state { + // bariera + pthread_barrier_t barrier; +}; + +const char *data = + "\n" + " \n" + " 10\n" + " \n" + " default-ssh\n" + " \n" + " \n" + " 127.0.0.1\n" + " 10005\n" + " \n" + " \n" + " \n" + " \n" + " key\n" + " \n" + " \n" + " ct:ssh-public-key-format\n" + " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" + " ct:rsa-private-key-format\n" + " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " test_pk\n" + " \n" + " \n" + " \n" + " test\n" + " ct:ssh-public-key-format\n" + " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " test_int\n" + " \n" + " netconf.conf\n" + " " BUILD_DIR "/tests\n" + " \n" + " \n" + " \n" + " test_pw\n" + " $6$xyz$lomVe5tZ2Gz9uSKKywzXuPcHhqjIByhBbqdUTx/jAwUnw7JRp7QHd4ORiEVqxeZg1NEJkHux.mETo9BFPSh1x.\n" + " \n" + " \n" + " test_none\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " sshpka:rsa-sha2-512\n" + " \n" + " \n" + " sshkea:curve25519-sha256\n" + " \n" + " \n" + " sshea:aes256-ctr\n" + " \n" + " \n" + " sshma:hmac-sha2-512\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + (void) arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_thread_destroy(); + return NULL; +} + +static int +ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) +{ + (void)hostname; + (void)session; + (void)priv; + /* skip the knownhost check */ + + return 0; +} + +static char * +auth_interactive(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv) +{ + (void) instruction; + (void) echo; + (void) auth_name; + (void) priv; + + /* send the replies to keyboard-interactive authentication */ + if (strstr(prompt, "backwards")) { + return strdup("tni_tset"); + } else if (strstr(prompt, "1+1")) { + return strdup("2"); + } else { + return NULL; + } +} + +static void * +client_thread_interactive(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + ret = nc_client_ssh_set_username("test_int"); + assert_int_equal(ret, 0); + + /* set keyboard-interactive authentication callback */ + nc_client_ssh_set_auth_interactive_clb(auth_interactive, NULL); + + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 1); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_auth_interactive(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread_interactive, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static char * +auth_password(const char *username, const char *hostname, void *priv) +{ + (void) hostname; + (void) priv; + + /* send the replies to keyboard-interactive authentication */ + if (!strcmp(username, "test_pw")) { + return strdup("testpw"); + } else { + return NULL; + } +} + +static void * +client_thread_password(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + ret = nc_client_ssh_set_username("test_pw"); + assert_int_equal(ret, 0); + + nc_client_ssh_set_auth_password_clb(auth_password, NULL); + + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, 1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_auth_password(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread_password, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void * +client_thread_pubkey(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + ret = nc_client_ssh_set_username("test_pk"); + assert_int_equal(ret, 0); + + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); + + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_auth_pubkey(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread_pubkey, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void * +client_thread_none(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + ret = nc_client_ssh_set_username("test_none"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_auth_none(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread_none, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* parse yang data */ + ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup(tree); + assert_int_equal(ret, 0); + + /* initialize client */ + nc_client_init(); + + ret = nc_server_init(); + assert_int_equal(ret, 0); + + /* skip the knownhost check */ + nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_auth_interactive, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_auth_pubkey, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_auth_password, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_auth_none, setup_f, teardown_f) + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/test_nc3.c b/tests/test_nc3.c new file mode 100644 index 00000000..f74ab250 --- /dev/null +++ b/tests/test_nc3.c @@ -0,0 +1,243 @@ +/** + * @file test_pam.c + * @author Roman Janota + * @brief libnetconf2 Linux PAM keyboard-interactive authentication test + * + * @copyright + * Copyright (c) 2022 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 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "config_server.h" + +#include "tests/config.h" + +#define nc_assert(cond) if (!(cond)) { fprintf(stderr, "assert failed (%s:%d)\n", __FILE__, __LINE__); abort(); } + +#define NC_ACCEPT_TIMEOUT 5000 +#define NC_PS_POLL_TIMEOUT 5000 + +const char *data = + "" + "" + "10" + "" + "default-ssh" + "" + "" + "127.0.0.1" + "10005" + "" + "" + "" + "" + "key" + "" + "" + "ct:ssh-public-key-format" + "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr" + "97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeV" + "n6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FT" + "irzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6w" + "NmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCU" + "UGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrz" + "ARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rf" + "WZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKv" + "Ya1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3" + "u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMa" + "OQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMh" + "jufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==" + "ct:rsa-private-key-format" + "MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1V" + "ArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6al" + "wf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4g" + "fNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+Zc" + "zSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+d" + "KYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FK" + "tGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo" + "4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/f" + "t1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBT" + "oE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yV" + "ONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEA" + "AQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj" + "1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAH" + "X8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXB" + "RgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMk" + "cjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk" + "2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rED" + "MlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5" + "R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuar" + "AhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNt" + "xZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2Rn" + "LkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH" + "/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+U" + "XA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmG" + "vWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+" + "31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3" + "ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRL" + "ZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7" + "YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7v" + "IQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bf" + "JAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhg" + "W4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y" + "8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFy" + "fSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+" + "N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/b" + "BY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu" + "8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SR" + "q7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu" + "3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJv" + "nwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcai" + "rBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM" + "3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4S" + "SBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinb" + "Tsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW" + "8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPo" + "Swr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JB" + "dOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/K" + "qDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8T" + "bstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=" + "" + "" + "" + "" + "" + "" + "" + "test" + "" + "" + "" + "client" + "ct:ssh-public-key-format" + "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvpKj6gy/Rm1pqlUIaeKp" + "WuL2KOJBbodhxuPG+0S6f+Jf4LopOB76tmg1RQ/bAXLNxXkG46Cx9UOHaFK/Ixul" + "cCbH6LxOUg90/HVS7NnbaVtDsl03HG9CPZTlQzM+n+iFAXv5ub5PFzW3VCCNDSfM" + "tXUOdVR93u/OAc7uz0nWjGhWnOH5MPJCQPS8ZFpL9hQxQuyAXFY0YLW/9eRMDgx/" + "OPTuvlTxIF+YHaMzY+Wy+Oaygwb78dCow+3RQRgCB20o5o6exx2nX2Cqr7UJzG/N" + "30XCusKIcTT978td8AU7UjpbzoNehm/tmQdDq+8IDsNfWbxCHDYLMD8IR32UDXGD" + "DVSwrtNgUs8HWNNCBKjTNCeQf1v/yiRd7hRf2aj+w9sDu8PI+VC9pabsRe2KxnnD" + "U9Sq+4IB3ZM3C5XpJDbu8DVigGZSevim7p/D6mW2phlyxtlK9WmQ5Misg/Z8jM7E" + "Z3gJcTvh20IS6I4plG7DJvsIC/Pc3IS2JC/w0prCZa8gOKob8x2mjjQcOA1eVIUm" + "yw6WbV1X65/jAJvIS6an/oFAk4bBTfJA6fYfU4Pb9NWovYxm/eNR5BbRmFFh0uXa" + "0s92S50iOotf8CnW7PZ7PWKgzKqtnN9Ob+Ye7WjDdG+NCrhkiDBOCuHDrHXwqaxW" + "BmUICo2mnUMK7JuJNSZe5DMCAwEAAQ==" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "sshpka:ssh-rsa" + "sshpka:rsa-sha2-512" + "" + "" + "sshkea:diffie-hellman-group18-sha512" + "" + "" + "sshea:aes256-cbc" + "" + "" + "sshma:hmac-sha1" + "" + "" + "" + "" + "" + "" + ""; + +static int +setup(struct ly_ctx *ctx) +{ + int i; + const char *all_features[] = {"*", NULL}; + /* no ssh-x509-certs */ + const char *ssh_common_features[] = {"transport-params", "public-key-generation", NULL}; + /* no ssh-server-keepalives and local-user-auth-hostbased */ + const char *ssh_server_features[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL}; + /* no private-key-encryption and csr-generation */ + const char *crypto_types_features[] = { + "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format", + "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format", + "p10-based-csrs", "certificate-expiration-notification", "hidden-keys", "password-encryption", + "symmetric-key-encryption", NULL + }; + + const char *module_names[] = { + "ietf-netconf-server", "ietf-tls-common", "ietf-tls-server", "ietf-truststore", "iana-crypt-hash", "ietf-keystore", + "ietf-tcp-server", "ietf-tcp-common", "ietf-tcp-client", "iana-ssh-public-key-algs", + "iana-ssh-key-exchange-algs", "iana-ssh-encryption-algs", "iana-ssh-mac-algs", NULL + }; + + for (i = 0; module_names[i] != NULL; i++) { + if (!ly_ctx_load_module(ctx, module_names[i], NULL, all_features)) { + fprintf(stderr, "Loading module (%s) failed.\n", module_names[i]); + goto error; + } + } + + if (!ly_ctx_load_module(ctx, "ietf-ssh-common", NULL, ssh_common_features)) { + fprintf(stderr, "Loading module (ietf-ssh-common) failed.\n"); + goto error; + } + if (!ly_ctx_load_module(ctx, "ietf-ssh-server", NULL, ssh_server_features)) { + fprintf(stderr, "Loading module (ietf-ssh-server) failed.\n"); + goto error; + } + if (!ly_ctx_load_module(ctx, "ietf-crypto-types", NULL, crypto_types_features)) { + fprintf(stderr, "Loading module (ietf-crypto-types) failed.\n"); + goto error; + } + + return 0; + +error: + return 1; +} + +int +main(void) +{ + int ret; + struct ly_ctx *ctx; + struct lyd_node *tree; + + nc_verbosity(NC_VERB_VERBOSE); + + ret = ly_ctx_new("/home/roman/Downloads/yang", 0, &ctx); + nc_assert(!ret); + + ret = setup(ctx); + nc_assert(!ret); + + ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + nc_assert(!ret); + + ret = nc_server_config_setup(tree); + nc_assert(!ret); + + nc_server_init(); + + nc_server_destroy(); + lyd_free_all(tree); + ly_ctx_destroy(ctx); + return 0; +} diff --git a/tests/test_pam.c b/tests/test_pam.c deleted file mode 100644 index 8fce4782..00000000 --- a/tests/test_pam.c +++ /dev/null @@ -1,193 +0,0 @@ -/** - * @file test_pam.c - * @author Roman Janota - * @brief libnetconf2 Linux PAM keyboard-interactive authentication test - * - * @copyright - * Copyright (c) 2022 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 - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "tests/config.h" - -#define nc_assert(cond) if (!(cond)) { fprintf(stderr, "assert failed (%s:%d)\n", __FILE__, __LINE__); abort(); } - -#define NC_ACCEPT_TIMEOUT 5000 -#define NC_PS_POLL_TIMEOUT 5000 - -struct ly_ctx *ctx; - -static void * -server_thread(void *arg) -{ - int ret; - NC_MSG_TYPE msgtype; - struct nc_session *session; - struct nc_pollsession *ps; - - (void) arg; - ps = nc_ps_new(); - nc_assert(ps); - - /* accept a session and add it to the poll session structure */ - msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); - nc_assert(msgtype == NC_MSG_HELLO); - ret = nc_ps_add_session(ps, session); - nc_assert(!ret); - ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); - nc_assert(ret & NC_PSPOLL_RPC); - ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); - nc_assert(ret & NC_PSPOLL_RPC); - nc_ps_clear(ps, 1, NULL); - - nc_ps_free(ps); - nc_thread_destroy(); - return NULL; -} - -static int -clb_hostkeys(const char *name, void *user_data, char **privkey_path, char **privkey_data, - NC_SSH_KEY_TYPE *privkey_type) -{ - (void) user_data; - (void) privkey_data; - (void) privkey_type; - - /* set the path to the testing private keys */ - if (!strcmp(name, "key_rsa")) { - *privkey_path = strdup(TESTS_DIR "/data/key_rsa"); - return 0; - } else if (!strcmp(name, "key_dsa")) { - *privkey_path = strdup(TESTS_DIR "/data/key_dsa"); - return 0; - } - - return 1; -} - -static char * -auth_interactive(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv) -{ - (void) instruction; - (void) echo; - (void) auth_name; - (void) priv; - - /* send the replies to keyboard-interactive authentication */ - if (strstr(prompt, "backwards")) { - return strdup("tset"); - } else if (strstr(prompt, "1+1")) { - return strdup("2"); - } else { - return NULL; - } -} - -static int -ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) -{ - (void)hostname; - (void)session; - (void)priv; - /* redundant in this test, nonetheless this callback has to be set */ - - return 0; -} - -static void * -client_thread(void *arg) -{ - (void) arg; - int ret; - struct nc_session *session = NULL; - - printf("SSH client started.\n"); - - /* initialize client */ - nc_client_init(); - ret = nc_client_set_schema_searchpath(TESTS_DIR "/data/modules"); - nc_assert(!ret); - /* skip the knownhost check */ - nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); - - ret = nc_client_ssh_set_username("test"); - nc_assert(!ret); - - /* set keyboard-interactive authentication callback */ - nc_client_ssh_set_auth_interactive_clb(auth_interactive, NULL); - session = nc_connect_ssh("0.0.0.0", 6002, NULL); - nc_assert(session); - - printf("SSH client finished.\n"); - nc_client_destroy(); - - nc_session_free(session, NULL); - nc_thread_destroy(); - return NULL; -} - -int -main(void) -{ - int ret, i; - pthread_t tids[2]; - - ly_ctx_new(TESTS_DIR "/data/modules", 0, &ctx); - nc_assert(ctx); - ly_ctx_load_module(ctx, "ietf-netconf", NULL, NULL); - - nc_verbosity(NC_VERB_VERBOSE); - nc_server_init(); - - /* set callback */ - nc_server_ssh_set_hostkey_clb(clb_hostkeys, NULL, NULL); - - /* do first, so that client can connect on SSH */ - ret = nc_server_add_endpt("main_ssh", NC_TI_LIBSSH); - nc_assert(!ret); - ret = nc_server_endpt_set_address("main_ssh", "0.0.0.0"); - nc_assert(!ret); - ret = nc_server_endpt_set_port("main_ssh", 6002); - nc_assert(!ret); - ret = nc_server_ssh_endpt_add_hostkey("main_ssh", "key_rsa", -1); - nc_assert(!ret); - - /* in order to use the Linux PAM keyboard-interactive method, - * the PAM module has to know where to find the desired configuration file */ - ret = nc_server_ssh_set_pam_conf_path("netconf.conf", BUILD_DIR "/tests"); - nc_assert(!ret); - - /* only want to test keyboard-interactive auth method */ - ret = nc_server_ssh_endpt_set_auth_methods("main_ssh", NC_SSH_AUTH_INTERACTIVE); - nc_assert(!ret); - - ret = pthread_create(&tids[0], NULL, client_thread, NULL); - nc_assert(!ret); - ret = pthread_create(&tids[1], NULL, server_thread, NULL); - nc_assert(!ret); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } - - nc_server_destroy(); - ly_ctx_destroy(ctx); - return 0; -} diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c new file mode 100644 index 00000000..37ac20cc --- /dev/null +++ b/tests/test_two_channels.c @@ -0,0 +1,282 @@ +/** + * @file test_pam.c + * @author Roman Janota + * @brief libnetconf2 Linux PAM keyboard-interactive authentication test + * + * @copyright + * Copyright (c) 2022 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 5000 +#define NC_PS_POLL_TIMEOUT 500 +#define BACKOFF_TIMEOUT_USECS 100 + +struct ly_ctx *ctx; +int flag = 0; + +const char *data = + "\n" + " \n" + " 10\n" + " \n" + " default-ssh\n" + " \n" + " \n" + " 127.0.0.1\n" + " 10005\n" + " \n" + " \n" + " \n" + " \n" + " key\n" + " \n" + " \n" + " ct:ssh-public-key-format\n" + " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" + " ct:rsa-private-key-format\n" + " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " test1\n" + " \n" + " \n" + " \n" + " client\n" + " ct:ssh-public-key-format\n" + " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " test2\n" + " \n" + " \n" + " \n" + " client\n" + " ct:ssh-public-key-format\n" + " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " sshpka:rsa-sha2-512\n" + " \n" + " \n" + " sshkea:curve25519-sha256\n" + " \n" + " \n" + " sshea:aes256-ctr\n" + " \n" + " \n" + " sshma:hmac-sha2-512\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static void * +server_thread(void *arg) +{ + int ret, del_session_count = 0, sleep_count = 0; + NC_MSG_TYPE msgtype; + struct nc_session *session, *new_session; + struct nc_pollsession *ps; + + (void) arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + while (del_session_count < 2) { + msgtype = nc_accept(0, ctx, &session); + + if (msgtype == NC_MSG_HELLO) { + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + } + + ret = nc_ps_poll(ps, 0, &new_session); + + if (ret & NC_PSPOLL_SESSION_TERM) { + nc_ps_del_session(ps, new_session); + nc_session_free(new_session, NULL); + del_session_count++; + } else if (ret & NC_PSPOLL_SSH_CHANNEL) { + msgtype = nc_session_accept_ssh_channel(session, &new_session); + if (msgtype == NC_MSG_HELLO) { + ret = nc_ps_add_session(ps, new_session); + assert_int_equal(ret, 0); + } + } else if (ret & NC_PS_POLL_TIMEOUT) { + usleep(BACKOFF_TIMEOUT_USECS); + sleep_count++; + assert_int_not_equal(sleep_count, 50000); + } + } + + nc_ps_free(ps); + nc_thread_destroy(); + return NULL; +} + +static int +ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) +{ + (void)hostname; + (void)session; + (void)priv; + /* redundant in this test, nonetheless this callback has to be set */ + + return 0; +} + +static void * +client_thread(void *arg) +{ + (void) arg; + int ret; + struct nc_session *session_cl1, *session_cl2; + + /* initialize client */ + nc_client_init(); + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + /* skip the knownhost check */ + nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); + + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); + + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + assert_int_equal(ret, 0); + + ret = nc_client_ssh_set_username("test1"); + assert_int_equal(ret, 0); + + session_cl1 = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session_cl1); + + ret = nc_client_ssh_set_username("test2"); + assert_int_equal(ret, 0); + + session_cl2 = nc_connect_ssh_channel(session_cl1, NULL); + assert_non_null(session_cl2); + + nc_client_destroy(); + nc_session_free(session_cl1, NULL); + nc_session_free(session_cl2, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_two_channels(void **state) +{ + int ret, i; + pthread_t tids[2]; + + (void) state; + + ret = pthread_create(&tids[0], NULL, client_thread, NULL); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, NULL); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree; + + (void) state; + + nc_verbosity(NC_VERB_VERBOSE); + + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup(tree); + assert_int_equal(ret, 0); + + ret = nc_server_init(); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + (void) state; + + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_two_channels, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} From b9f25d371fe34d67945a29a011d66329639cf9d6 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 17 Feb 2023 10:21:39 +0100 Subject: [PATCH 002/134] keystore UPDATE use keys stored in keystore module Keystore is a module, which stores asymmetric and symmetric keys. This commit implements using asymmetric keys stored in the keystore for authentication over SSH. --- src/config_server.c | 382 ++++++++++++++++++++++++++++-------------- src/config_server.h | 5 + src/session_p.h | 31 ++-- tests/CMakeLists.txt | 5 +- tests/test_keystore.c | 280 +++++++++++++++++++++++++++++++ 5 files changed, 565 insertions(+), 138 deletions(-) create mode 100644 tests/test_keystore.c diff --git a/src/config_server.c b/src/config_server.c index d0aaedad..2c41ee07 100644 --- a/src/config_server.c +++ b/src/config_server.c @@ -311,12 +311,6 @@ nc_server_del_private_key(struct nc_hostkey *hostkey) hostkey->priv_base64 = NULL; } -static void -nc_server_del_keystore_reference(struct nc_hostkey *hostkey) -{ - hostkey->keystore = NULL; -} - static void nc_server_del_auth_client_username(struct nc_client_auth *auth_client) { @@ -388,8 +382,6 @@ nc_server_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostke if (hostkey->ks_type == NC_STORE_LOCAL) { nc_server_del_public_key(hostkey); nc_server_del_private_key(hostkey); - } else if (hostkey->ks_type == NC_STORE_KEYSTORE) { - nc_server_del_keystore_reference(hostkey); } nc_server_del_hostkey_name(hostkey); @@ -486,6 +478,38 @@ nc_server_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) } } +void +nc_server_config_del_keystore(void) +{ + int i, j; + struct nc_keystore *ks = &server_opts.keystore; + + /* delete all asymmetric keys */ + for (i = 0; i < ks->asym_key_count; i++) { + free(ks->asym_keys[i].name); + free(ks->asym_keys[i].pub_base64); + free(ks->asym_keys[i].priv_base64); + + for (j = 0; j < ks->asym_keys[i].cert_count; j++) { + /* free associated certificates */ + free(ks->asym_keys[i].certs[j].name); + free(ks->asym_keys[i].certs[j].cert_base64); + } + free(ks->asym_keys[i].certs); + ks->asym_keys[i].cert_count = 0; + } + free(ks->asym_keys); + ks->asym_key_count = 0; + + /* delete all symmetric keys */ + for (i = 0; i < ks->sym_key_count; i++) { + free(ks->sym_keys[i].name); + free(ks->sym_keys[i].base64); + } + free(ks->sym_keys); + ks->sym_key_count = 0; +} + /* presence container */ int nc_server_configure_listen(NC_OPERATION op) @@ -1136,22 +1160,21 @@ static int nc_server_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey) { uint16_t i; - struct nc_keystore *ks = NULL; + struct nc_keystore *ks = &server_opts.keystore; /* lookup name */ - for (i = 0; i < server_opts.keystore_count; i++) { - if (!strcmp(lyd_get_value(node), server_opts.keystore[i].name)) { - ks = &server_opts.keystore[i]; + for (i = 0; i < ks->asym_key_count; i++) { + if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) { break; } } - if (!ks) { - ERR(NULL, "Keystore (%s) not found.", lyd_get_value(node)); + if (i == ks->asym_key_count) { + ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node)); return 1; } - hostkey->keystore = ks; + hostkey->ks_ref = &ks->asym_keys[i]; return 0; } @@ -1166,7 +1189,7 @@ nc_server_configure_keystore_reference(const struct lyd_node *node, NC_OPERATION assert(!strcmp(LYD_NAME(node), "keystore-reference")); - if ((equal_parent_name(node, 4, "server-identity")) && (equal_parent_name(node, 7, "listen"))) { + if ((equal_parent_name(node, 3, "server-identity")) && (equal_parent_name(node, 7, "listen"))) { if (nc_server_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -1182,7 +1205,7 @@ nc_server_configure_keystore_reference(const struct lyd_node *node, NC_OPERATION goto cleanup; } } else { - hostkey->keystore = NULL; + hostkey->ks_ref = NULL; } } @@ -2073,156 +2096,263 @@ nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op } static int -nc_server_configure_certificates(const struct lyd_node *node, struct nc_keystore *ks) +nc_server_configure_asymmetric_key_certificate(const struct lyd_node *tree, struct nc_ks_asym_key *key) { int ret = 0; - uint16_t cert_count; + struct lyd_node *node; void *tmp; - node = node->next; - if ((!node) || (strcmp(LYD_NAME(node), "certificate"))) { - WRN(NULL, "Certificates container is empty"); + /* create new certificate */ + tmp = realloc(key->certs, (key->cert_count + 1) * sizeof *key->certs); + if (!tmp) { + ERRMEM; + ret = 1; goto cleanup; } + key->certs = tmp; + key->cert_count++; - /* certificate list */ - while (node) { - cert_count = ks->cert_count; - tmp = realloc(ks->certs, cert_count + 1); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - ks->certs = tmp; + /* set name */ + lyd_find_path(tree, "name", 0, &node); + assert(node); - ks->certs[cert_count].name = strdup(lyd_get_value(lyd_child(node))); - if (!ks->certs[cert_count].name) { - ERRMEM; - ret = 1; - goto cleanup; - } + key->certs[key->cert_count - 1].name = strdup(lyd_get_value(node)); + if (!key->certs[key->cert_count - 1].name) { + ERRMEM; + ret = 1; + goto cleanup; + } - ks->certs[cert_count].cert_data = strdup(lyd_get_value(lyd_child(node)->next)); - if (!ks->certs[cert_count].cert_data) { - ERRMEM; - free(ks->certs[cert_count].name); + /* set certificate data */ + lyd_find_path(tree, "cert-data", 0, &node); + assert(node); + + key->certs[key->cert_count - 1].cert_base64 = strdup(lyd_get_value(node)); + if (!key->certs[key->cert_count - 1].cert_base64) { + ERRMEM; + ret = 1; + goto cleanup; + } + +cleanup: + return ret; +} + +static int +nc_server_configure_asymmetric_key(const struct lyd_node *tree) +{ + int ret = 0; + struct lyd_node *node = NULL, *iter; + void *tmp; + struct nc_keystore *ks = &server_opts.keystore; + struct nc_ks_asym_key *key; + const char *format; + + /* create new asymmetric key */ + tmp = realloc(ks->asym_keys, (ks->asym_key_count + 1) * sizeof *ks->asym_keys); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + ks->asym_keys = tmp; + memset(&ks->asym_keys[ks->asym_key_count], 0, sizeof *ks->asym_keys); + key = &ks->asym_keys[ks->asym_key_count]; + ks->asym_key_count++; + + /* set name */ + lyd_find_path(tree, "name", 0, &node); + assert(node); + + key->name = strdup(lyd_get_value(node)); + if (!key->name) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* set public-key-format, mandatory */ + lyd_find_path(tree, "public-key-format", 0, &node); + assert(node); + + format = ((struct lyd_node_term *)node)->value.ident->name; + if (!strcmp(format, "ssh-public-key-format")) { + key->pubkey_type = NC_SSH_PUBKEY_X509; + } else if (!strcmp(format, "subject-public-key-info-format")) { + key->pubkey_type = NC_SSH_PUBKEY_SSH2; + } else { + ERR(NULL, "Public key format \"%s\" not supported.", format); + ret = 1; + goto cleanup; + } + + /* set public-key, mandatory */ + lyd_find_path(tree, "public-key", 0, &node); + assert(node); + + key->pub_base64 = strdup(lyd_get_value(node)); + if (!key->pub_base64) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* set private-key-format */ + ret = lyd_find_path(tree, "private-key-format", 0, &node); + if (!ret) { + format = ((struct lyd_node_term *)node)->value.ident->name; + if (!strcmp(format, "rsa-private-key-format")) { + key->privkey_type = NC_SSH_KEY_RSA; + } else if (!strcmp(format, "ec-private-key-format")) { + key->privkey_type = NC_SSH_KEY_ECDSA; + } else { + ERR(NULL, "Private key format (%s) not supported.", format); ret = 1; goto cleanup; } + } - ks->cert_count++; + /* set private key, mandatory */ + lyd_find_path(tree, "cleartext-private-key", 0, &node); + assert(node); + + key->priv_base64 = strdup(lyd_get_value(node)); + if (!key->priv_base64) { + ERRMEM; + ret = 1; + goto cleanup; } -cleanup: - if (ret) { - for (cert_count = 0; cert_count < ks->cert_count; cert_count++) { - free(ks->certs[cert_count].name); - free(ks->certs[cert_count].cert_data); + /* set certificates associated with the key pair */ + ret = lyd_find_path(tree, "certificates", 0, &node); + if (!ret) { + node = lyd_child(node); + if (node) { + /* certificate list instance */ + LY_LIST_FOR(node, iter) { + if (nc_server_configure_asymmetric_key_certificate(iter, key)) { + ret = 1; + goto cleanup; + } + } } - free(ks->certs); + } else if (ret == LY_ENOTFOUND) { + /* certificates container not present, but it's ok */ + ret = 0; } + +cleanup: return ret; } static int -nc_fill_keystore(const struct lyd_node *data) +nc_server_configure_symmetric_key(const struct lyd_node *tree) { int ret = 0; - uint32_t prev_lo; - struct lyd_node *tree, *node, *iter, *iter_tmp; + const char *format; + struct lyd_node *node; + struct nc_keystore *ks = &server_opts.keystore; + struct nc_ks_sym_key *key; void *tmp; - struct nc_keystore *ks; - /* silently search for keystore node */ - prev_lo = ly_log_options(0); - ret = lyd_find_path(data, "/ks:keystore", 0, &tree); - ly_log_options(prev_lo); - if (ret) { - WRN(NULL, "Keystore container not found in the YANG data."); - return 0; + /* create new symmetric key */ + tmp = realloc(ks->sym_keys, (ks->sym_key_count + 1) * sizeof *ks->sym_keys); + if (tmp) { + ERRMEM; + ret = 1; + goto cleanup; } + memset(&ks->sym_keys[ks->sym_key_count], 0, sizeof *ks->sym_keys); + ks->sym_keys = tmp; + key = &ks->sym_keys[ks->sym_key_count]; + ks->sym_key_count++; - /* asymmetric keys container */ - lyd_find_path(tree, "asymmetric-keys", 0, (struct lyd_node **)&node); - if (!node) { - WRN(NULL, "Asymmetric keys container not found in the YANG data."); - return 0; + /* set name */ + lyd_find_path(tree, "name", 0, &node); + assert(node); + + key->name = strdup(lyd_get_value(node)); + if (!key->name) { + ERRMEM; + ret = 1; + goto cleanup; } - /* asymmetric key list */ - lyd_find_path(node, "asymmetric-key", 0, (struct lyd_node **)&node); - if (!node) { - WRN(NULL, "Asymmetric keys container is empty."); - return 0; + /* check if the identity matches with the supported one */ + lyd_find_path(tree, "key-format", 0, &node); + assert(node); + + format = ((struct lyd_node_term *)node)->value.ident->name; + if (strcmp(format, "symmetric-key-format")) { + ret = 1; + goto cleanup; } - LY_LIST_FOR(node, iter) { - tmp = realloc(server_opts.keystore, server_opts.keystore_count + 1); - if (!tmp) { - ERRMEM; - goto fail; - } - server_opts.keystore = tmp; - ks = &server_opts.keystore[server_opts.keystore_count]; + /* set key data */ + lyd_find_path(tree, "cleartext-key", 0, &node); + assert(node); - iter_tmp = iter; - /* name */ - iter_tmp = lyd_child(iter_tmp); - ks->name = strdup(lyd_get_value(iter_tmp)); - if (!ks->name) { - ERRMEM; - goto fail; - } + key->base64 = strdup(lyd_get_value(node)); + if (!key->base64) { + ERRMEM; + ret = 1; + goto cleanup; + } - /* mandatory public-key-format */ - iter_tmp = iter_tmp->next; - if (nc_server_configure_public_key_format(iter_tmp, 0)) { - free(ks->name); - goto fail; - } +cleanup: + return ret; +} - /* mandatory public-key */ - iter_tmp = iter_tmp->next; - ks->pub_base64 = strdup(lyd_get_value(iter_tmp)); - if (!ks->pub_base64) { - free(ks->name); - ERRMEM; - goto fail; - } +static int +nc_fill_keystore(const struct lyd_node *data) +{ + int ret = 0; + uint32_t prev_lo; + struct lyd_node *tree, *as_keys, *s_keys, *iter; - iter_tmp = iter_tmp->next; - while (iter_tmp) { - if (!strcmp(LYD_NAME(iter_tmp), "private-key-format")) { - if (nc_server_configure_private_key_format(iter_tmp, 0)) { - goto fail; - } - } else if (!strcmp(LYD_NAME(iter_tmp), "private-key-type")) { - if ((!strcmp(LYD_NAME(lyd_child(iter_tmp)), "cleartext-private-key")) && - (!strcmp(LYD_NAME(lyd_child(lyd_child(iter_tmp))), "cleartext-private-key"))) { - ks->priv_base64 = strdup(lyd_get_value(lyd_child(lyd_child(iter_tmp)))); - if (!ks->priv_base64) { - ERRMEM; - goto fail; - } - } - } else if (!strcmp(LYD_NAME(iter_tmp), "certificates")) { - if (nc_server_configure_certificates(iter_tmp, ks)) { - goto fail; + /* silently search for nodes, some of them may not be present */ + prev_lo = ly_log_options(0); + + ret = lyd_find_path(data, "/ietf-keystore:keystore", 0, &tree); + if (ret) { + WRN(NULL, "Keystore container not found in the YANG data."); + goto cleanup; + } + + ret = lyd_find_path(tree, "asymmetric-keys", 0, &as_keys); + if (!ret) { + /* asymmetric keys container is present */ + as_keys = lyd_child(as_keys); + if (as_keys && !strcmp(LYD_NAME(as_keys), "asymmetric-key")) { + /* asymmetric key list */ + LY_LIST_FOR(as_keys, iter) { + if (nc_server_configure_asymmetric_key(iter)) { + ret = 1; + goto cleanup; } } - /* todo CSR? */ - iter_tmp = iter_tmp->next; } - - server_opts.keystore_count++; } - return 0; + ret = lyd_find_path(tree, "symmetric-keys", 0, &s_keys); + if (!ret) { + /* symmetric keys container is present */ + s_keys = lyd_child(s_keys); + if (s_keys && !strcmp(LYD_NAME(s_keys), "symmetric-key")) { + /* symmetric key list */ + LY_LIST_FOR(s_keys, iter) { + if (nc_server_configure_symmetric_key(iter)) { + ret = 1; + goto cleanup; + } + } + } + } -fail: - free(server_opts.keystore); - return 1; +cleanup: + /* reset the logging options back to what they were */ + ly_log_options(prev_lo); + return ret; } API int diff --git a/src/config_server.h b/src/config_server.h index 9adfede7..9397f662 100644 --- a/src/config_server.h +++ b/src/config_server.h @@ -76,6 +76,11 @@ int nc_server_config_load_modules(struct ly_ctx **ctx); */ int nc_server_configure_listen(NC_OPERATION op); +/** + * @brief Deletes every key stored in the keystore. + */ +void nc_server_config_del_keystore(void); + #ifdef __cplusplus } #endif diff --git a/src/session_p.h b/src/session_p.h index 3db14574..6818ed11 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -107,13 +107,25 @@ struct nc_certificate { }; struct nc_keystore { - char *name; - char *pub_base64; - char *priv_base64; - NC_SSH_KEY_TYPE privkey_type; + struct nc_ks_asym_key { + char *name; + NC_SSH_PUBKEY_TYPE pubkey_type; + char *pub_base64; + NC_SSH_KEY_TYPE privkey_type; + char *priv_base64; + struct { + char *name; + char *cert_base64; + } *certs; + uint16_t cert_count; + } *asym_keys; + uint16_t asym_key_count; - struct nc_certificate *certs; - uint16_t cert_count; + struct nc_ks_sym_key { + char *name; + char *base64; + } *sym_keys; + uint16_t sym_key_count; }; struct nc_client_auth { @@ -124,8 +136,8 @@ struct nc_client_auth { struct { struct nc_client_auth_pubkey { char *name; - char *pub_base64; NC_SSH_PUBKEY_TYPE pubkey_type; + char *pub_base64; } *pubkeys; uint16_t pubkey_count; }; @@ -149,7 +161,7 @@ struct nc_hostkey { NC_SSH_KEY_TYPE privkey_type; char *priv_base64; }; - struct nc_keystore *keystore; + struct nc_ks_asym_key *ks_ref; }; }; @@ -319,8 +331,7 @@ struct nc_server_opts { #endif pthread_rwlock_t config_lock; - struct nc_keystore *keystore; /**< store for keys/certificates */ - uint16_t keystore_count; + struct nc_keystore keystore; /**< store for keys/certificates */ struct nc_bind *binds; struct nc_endpt { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8796d895..ca850678 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,11 +8,12 @@ if(${SOURCE_FORMAT_ENABLED}) endif() # list of all the tests in each directory -set(tests test_nc3) +#set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages) +set(tests test_two_channels test_keystore) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) - list(APPEND tests test_auth test_two_channels) + list(APPEND tests test_auth) endif() set(client_tests test_client test_client_messages) diff --git a/tests/test_keystore.c b/tests/test_keystore.c new file mode 100644 index 00000000..5f583add --- /dev/null +++ b/tests/test_keystore.c @@ -0,0 +1,280 @@ +/** + * @file test_keystore.c + * @author Roman Janota + * @brief libnetconf2 Linux PAM keyboard-interactive authentication test + * + * @copyright + * Copyright (c) 2022 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 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 100 +#define NC_PS_POLL_TIMEOUT 100 + +struct ly_ctx *ctx; + +struct test_state { + // bariera + pthread_barrier_t barrier; +}; + +const char *data = + "\n" + " \n" + " 10\n" + " \n" + " default-ssh\n" + " \n" + " \n" + " 127.0.0.1\n" + " 10005\n" + " \n" + " \n" + " \n" + " \n" + " key\n" + " \n" + " test_keystore\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " test_ts\n" + " \n" + " \n" + " \n" + " test\n" + " ct:ssh-public-key-format\n" + " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " sshpka:rsa-sha2-512\n" + " \n" + " \n" + " sshkea:curve25519-sha256\n" + " \n" + " \n" + " sshea:aes256-ctr\n" + " \n" + " \n" + " sshma:hmac-sha2-512\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n" + "\n" + "\n" + " \n" + " \n" + " test_keystore\n" + " ct:ssh-public-key-format\n" + " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" + " ct:rsa-private-key-format\n" + " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" + " \n" + " \n" + " \n" + "\n"; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_thread_destroy(); + return NULL; +} + +static int +ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) +{ + (void)hostname; + (void)session; + (void)priv; + /* skip the knownhost check */ + + return 0; +} + +static void * +client_thread_pubkey(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + ret = nc_client_ssh_set_username("test_ts"); + assert_int_equal(ret, 0); + + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); + + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_auth_pubkey(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread_pubkey, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* parse yang data */ + ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup(tree); + assert_int_equal(ret, 0); + + /* initialize client */ + nc_client_init(); + + ret = nc_server_init(); + assert_int_equal(ret, 0); + + /* skip the knownhost check */ + nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_auth_pubkey, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} From cbe5d4c7fdc92b3d830788d6ff4da20295b6881b Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 17 Feb 2023 10:25:12 +0100 Subject: [PATCH 003/134] test_client_ssh BUGFIX memory leaks --- tests/client/test_client_ssh.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/client/test_client_ssh.c b/tests/client/test_client_ssh.c index 175577bf..20c546b1 100644 --- a/tests/client/test_client_ssh.c +++ b/tests/client/test_client_ssh.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "tests/config.h" #include @@ -127,6 +128,7 @@ static int teardown_f(void **state) { (void)state; + nc_client_destroy(); return 0; } @@ -722,6 +724,7 @@ test_nc_connect_ssh_pubkey_succesfull(void **state) /* fake succesfull connection */ will_return(__wrap_connect, 0); will_return(__wrap_ssh_connect, 0); + will_return(__wrap_nc_sock_listen_inet, 0); /* do not authenticate using no authentication method */ will_return(__wrap_ssh_userauth_none, 1); will_return(__wrap_ssh_userauth_try_publickey, 0); @@ -753,7 +756,12 @@ test_nc_connect_ssh_pubkey_succesfull(void **state) /* disconnect */ will_return(__wrap_ssh_channel_poll_timeout, 0); + + /* free everything used */ nc_session_free(session, NULL); + lyd_free_all(tree); + nc_server_destroy(); + ly_ctx_destroy(ctx); } static void From 3d6fdc07ba2867bd733c3049423bad1ec47feeb7 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 24 Feb 2023 09:15:23 +0100 Subject: [PATCH 004/134] UNIX socket UPDATE configurable with YANG data Implemented the ability to create a UNIX socket server with YANG data. Additionally all new tests timeouts are now unified. --- modules/libnetconf2-netconf-server.yang | 20 ++ src/config_server.c | 146 +++++++++++++- src/session_p.h | 6 +- src/session_server.c | 12 +- tests/CMakeLists.txt | 2 +- tests/test_auth.c | 5 +- tests/test_keystore.c | 5 +- tests/test_nc3.c | 243 ------------------------ tests/test_two_channels.c | 4 +- tests/test_unix_socket.c | 198 +++++++++++++++++++ 10 files changed, 371 insertions(+), 270 deletions(-) delete mode 100644 tests/test_nc3.c create mode 100644 tests/test_unix_socket.c diff --git a/modules/libnetconf2-netconf-server.yang b/modules/libnetconf2-netconf-server.yang index f9b76253..9d8bbb9b 100644 --- a/modules/libnetconf2-netconf-server.yang +++ b/modules/libnetconf2-netconf-server.yang @@ -32,4 +32,24 @@ module libnetconf2-netconf-server { } } } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport" { + case unix-socket { + container unix-socket { + leaf path { + type string; + mandatory true; + } + leaf mode { + type uint16; + } + leaf uid { + type uint16; + } + leaf gid { + type uint16; + } + } + } + } } diff --git a/src/config_server.c b/src/config_server.c index 2c41ee07..50e3c1bf 100644 --- a/src/config_server.c +++ b/src/config_server.c @@ -478,6 +478,35 @@ nc_server_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) } } +void +nc_server_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts) +{ + if (bind->sock > -1) { + close(bind->sock); + } + + free(bind->address); + free(opts->address); + + free(opts); + opts = NULL; +} + +void +nc_server_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind) +{ + nc_server_del_endpt_name(endpt); + nc_server_del_unix_socket(bind, endpt->opts.unixsock); + + server_opts.endpt_count--; + if (!server_opts.endpt_count) { + free(server_opts.endpts); + free(server_opts.binds); + server_opts.endpts = NULL; + server_opts.binds = NULL; + } +} + void nc_server_config_del_keystore(void) { @@ -520,7 +549,13 @@ nc_server_configure_listen(NC_OPERATION op) if (op == NC_OP_DELETE) { for (i = 0; i < server_opts.endpt_count; i++) { - nc_server_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]); + if (server_opts.endpts[i].ti == NC_TI_LIBSSH) { + nc_server_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]); + } else if (server_opts.endpts[i].ti == NC_TI_OPENSSL) { + /* todo */ + } else { + nc_server_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]); + } } } @@ -676,7 +711,7 @@ nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, { int sock = -1, set_addr, ret = 0; - assert((address && !port) || (!address && port)); + assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX)); if (address) { set_addr = 1; @@ -690,15 +725,15 @@ nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, address = bind->address; } - if (!set_addr && (endpt->ti == NC_TI_UNIX)) { - ret = 1; - goto cleanup; - } - /* we have all the information we need to create a listening socket */ - if (address && port) { + if ((address && port) || (endpt->ti == NC_TI_UNIX)) { /* create new socket, close the old one */ - sock = nc_sock_listen_inet(address, port, &endpt->ka); + if (endpt->ti == NC_TI_UNIX) { + sock = nc_sock_listen_unix(endpt->opts.unixsock); + } else { + sock = nc_sock_listen_inet(address, port, &endpt->ka); + } + if (sock == -1) { ret = 1; goto cleanup; @@ -712,6 +747,9 @@ nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, if (sock > -1) { switch (endpt->ti) { + case NC_TI_UNIX: + VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address); + break; #ifdef NC_ENABLED_SSH case NC_TI_LIBSSH: VRB(NULL, "Listening on %s:%u for SSH connections.", address, port); @@ -1910,6 +1948,92 @@ nc_server_configure_mac_alg(const struct lyd_node *node, NC_OPERATION op) return ret; } +static int +nc_server_create_unix_socket(struct nc_endpt *endpt) +{ + endpt->ti = NC_TI_UNIX; + endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock); + if (!endpt->opts.unixsock) { + ERRMEM; + return 1; + } + + /* set default values */ + endpt->opts.unixsock->mode = -1; + endpt->opts.unixsock->uid = -1; + endpt->opts.unixsock->gid = -1; + + return 0; +} + +static int +nc_server_configure_unix_socket(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + uint32_t prev_lo; + struct nc_endpt *endpt; + struct nc_bind *bind; + struct nc_server_unix_opts *opts; + struct lyd_node *data = NULL; + + assert(!strcmp(LYD_NAME(node), "unix-socket")); + + if (nc_server_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + if (nc_server_create_unix_socket(endpt)) { + ret = 1; + goto cleanup; + } + + opts = endpt->opts.unixsock; + + lyd_find_path(node, "path", 0, &data); + assert(data); + + opts->address = strdup(lyd_get_value(data)); + bind->address = strdup(lyd_get_value(data)); + if (!opts->address || !bind->address) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* silently search for non-mandatory parameters */ + prev_lo = ly_log_options(0); + ret = lyd_find_path(node, "mode", 0, &data); + if (!ret) { + opts->mode = strtol(lyd_get_value(data), NULL, 8); + } + + ret = lyd_find_path(node, "uid", 0, &data); + if (!ret) { + opts->uid = strtol(lyd_get_value(data), NULL, 10); + } + + ret = lyd_find_path(node, "gid", 0, &data); + if (!ret) { + opts->gid = strtol(lyd_get_value(data), NULL, 10); + } + + /* reset the logging options */ + ly_log_options(prev_lo); + + ret = nc_server_config_set_address_port(endpt, bind, NULL, 0); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + nc_server_del_unix_socket(bind, endpt->opts.unixsock); + } + +cleanup: + return ret; +} + static int nc_server_configure(const struct lyd_node *node, NC_OPERATION op) { @@ -2027,6 +2151,10 @@ nc_server_configure(const struct lyd_node *node, NC_OPERATION op) if (nc_server_configure_mac_alg(node, op)) { goto error; } + } else if (!strcmp(name, "unix-socket")) { + if (nc_server_configure_unix_socket(node, op)) { + goto error; + } } else if (!strcmp(name, "cert-data")) {} else if (!strcmp(name, "expiration-date")) {} else if (!strcmp(name, "asymmetric-key")) {} else if (!strcmp(name, "certificate")) {} else if (!strcmp(name, "key-format")) {} else if (!strcmp(name, "cleartext-key")) {} else if (!strcmp(name, "hidden-key")) {} else if (!strcmp(name, "id_hint")) {} else if (!strcmp(name, "external-identity")) {} else if (!strcmp(name, "hash")) {} else if (!strcmp(name, "context")) {} else if (!strcmp(name, "target-protocol")) {} else if (!strcmp(name, "target-kdf")) {} else if (!strcmp(name, "client-authentication")) {} else if (!strcmp(name, "ca-certs")) {} else if (!strcmp(name, "ee-certs")) {} else if (!strcmp(name, diff --git a/src/session_p.h b/src/session_p.h index 6818ed11..e75dc346 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -234,6 +234,7 @@ struct nc_keepalives { /* ACCESS unlocked */ struct nc_server_unix_opts { + char *address; mode_t mode; uid_t uid; gid_t gid; @@ -756,11 +757,10 @@ int nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepalives /** * @brief Create a listening socket (AF_UNIX). * - * @param[in] address UNIX address to listen on. - * @param[in] opts The server options (unix permissions). + * @param[in] opts The server options (unix permissions and address of the socket). * @return Listening socket, -1 on error. */ -int nc_sock_listen_unix(const char *address, const struct nc_server_unix_opts *opts); +int nc_sock_listen_unix(const struct nc_server_unix_opts *opts); /** * @brief Accept a new connection on a listening socket. diff --git a/src/session_server.c b/src/session_server.c index 9f013036..e0514e68 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -282,13 +282,13 @@ nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepalives *ka } int -nc_sock_listen_unix(const char *address, const struct nc_server_unix_opts *opts) +nc_sock_listen_unix(const struct nc_server_unix_opts *opts) { struct sockaddr_un sun; int sock = -1; - if (strlen(address) > sizeof(sun.sun_path) - 1) { - ERR(NULL, "Socket path \"%s\" is longer than maximum length %d.", address, (int)(sizeof(sun.sun_path) - 1)); + if (strlen(opts->address) > sizeof(sun.sun_path) - 1) { + ERR(NULL, "Socket path \"%s\" is longer than maximum length %d.", opts->address, (int)(sizeof(sun.sun_path) - 1)); goto fail; } @@ -300,11 +300,11 @@ nc_sock_listen_unix(const char *address, const struct nc_server_unix_opts *opts) memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; - snprintf(sun.sun_path, sizeof(sun.sun_path) - 1, "%s", address); + snprintf(sun.sun_path, sizeof(sun.sun_path) - 1, "%s", opts->address); unlink(sun.sun_path); if (bind(sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) { - ERR(NULL, "Could not bind \"%s\" (%s).", address, strerror(errno)); + ERR(NULL, "Could not bind \"%s\" (%s).", opts->address, strerror(errno)); goto fail; } @@ -323,7 +323,7 @@ nc_sock_listen_unix(const char *address, const struct nc_server_unix_opts *opts) } if (listen(sock, NC_REVERSE_QUEUE) == -1) { - ERR(NULL, "Unable to start listening on \"%s\" (%s).", address, strerror(errno)); + ERR(NULL, "Unable to start listening on \"%s\" (%s).", opts->address, strerror(errno)); goto fail; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ca850678..2a13145e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,7 @@ endif() # list of all the tests in each directory #set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages) -set(tests test_two_channels test_keystore) +set(tests test_two_channels test_keystore test_unix_socket) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) diff --git a/tests/test_auth.c b/tests/test_auth.c index 29b22b16..5511da94 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -31,13 +31,12 @@ #include "tests/config.h" -#define NC_ACCEPT_TIMEOUT 100 -#define NC_PS_POLL_TIMEOUT 100 +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 struct ly_ctx *ctx; struct test_state { - // bariera pthread_barrier_t barrier; }; diff --git a/tests/test_keystore.c b/tests/test_keystore.c index 5f583add..c7e8af86 100644 --- a/tests/test_keystore.c +++ b/tests/test_keystore.c @@ -31,13 +31,12 @@ #include "tests/config.h" -#define NC_ACCEPT_TIMEOUT 100 -#define NC_PS_POLL_TIMEOUT 100 +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 struct ly_ctx *ctx; struct test_state { - // bariera pthread_barrier_t barrier; }; diff --git a/tests/test_nc3.c b/tests/test_nc3.c deleted file mode 100644 index f74ab250..00000000 --- a/tests/test_nc3.c +++ /dev/null @@ -1,243 +0,0 @@ -/** - * @file test_pam.c - * @author Roman Janota - * @brief libnetconf2 Linux PAM keyboard-interactive authentication test - * - * @copyright - * Copyright (c) 2022 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 - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include "config_server.h" - -#include "tests/config.h" - -#define nc_assert(cond) if (!(cond)) { fprintf(stderr, "assert failed (%s:%d)\n", __FILE__, __LINE__); abort(); } - -#define NC_ACCEPT_TIMEOUT 5000 -#define NC_PS_POLL_TIMEOUT 5000 - -const char *data = - "" - "" - "10" - "" - "default-ssh" - "" - "" - "127.0.0.1" - "10005" - "" - "" - "" - "" - "key" - "" - "" - "ct:ssh-public-key-format" - "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr" - "97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeV" - "n6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FT" - "irzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6w" - "NmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCU" - "UGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrz" - "ARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rf" - "WZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKv" - "Ya1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3" - "u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMa" - "OQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMh" - "jufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==" - "ct:rsa-private-key-format" - "MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1V" - "ArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6al" - "wf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4g" - "fNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+Zc" - "zSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+d" - "KYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FK" - "tGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo" - "4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/f" - "t1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBT" - "oE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yV" - "ONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEA" - "AQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj" - "1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAH" - "X8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXB" - "RgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMk" - "cjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk" - "2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rED" - "MlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5" - "R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuar" - "AhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNt" - "xZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2Rn" - "LkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH" - "/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+U" - "XA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmG" - "vWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+" - "31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3" - "ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRL" - "ZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7" - "YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7v" - "IQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bf" - "JAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhg" - "W4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y" - "8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFy" - "fSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+" - "N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/b" - "BY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu" - "8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SR" - "q7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu" - "3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJv" - "nwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcai" - "rBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM" - "3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4S" - "SBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinb" - "Tsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW" - "8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPo" - "Swr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JB" - "dOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/K" - "qDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8T" - "bstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=" - "" - "" - "" - "" - "" - "" - "" - "test" - "" - "" - "" - "client" - "ct:ssh-public-key-format" - "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvpKj6gy/Rm1pqlUIaeKp" - "WuL2KOJBbodhxuPG+0S6f+Jf4LopOB76tmg1RQ/bAXLNxXkG46Cx9UOHaFK/Ixul" - "cCbH6LxOUg90/HVS7NnbaVtDsl03HG9CPZTlQzM+n+iFAXv5ub5PFzW3VCCNDSfM" - "tXUOdVR93u/OAc7uz0nWjGhWnOH5MPJCQPS8ZFpL9hQxQuyAXFY0YLW/9eRMDgx/" - "OPTuvlTxIF+YHaMzY+Wy+Oaygwb78dCow+3RQRgCB20o5o6exx2nX2Cqr7UJzG/N" - "30XCusKIcTT978td8AU7UjpbzoNehm/tmQdDq+8IDsNfWbxCHDYLMD8IR32UDXGD" - "DVSwrtNgUs8HWNNCBKjTNCeQf1v/yiRd7hRf2aj+w9sDu8PI+VC9pabsRe2KxnnD" - "U9Sq+4IB3ZM3C5XpJDbu8DVigGZSevim7p/D6mW2phlyxtlK9WmQ5Misg/Z8jM7E" - "Z3gJcTvh20IS6I4plG7DJvsIC/Pc3IS2JC/w0prCZa8gOKob8x2mjjQcOA1eVIUm" - "yw6WbV1X65/jAJvIS6an/oFAk4bBTfJA6fYfU4Pb9NWovYxm/eNR5BbRmFFh0uXa" - "0s92S50iOotf8CnW7PZ7PWKgzKqtnN9Ob+Ye7WjDdG+NCrhkiDBOCuHDrHXwqaxW" - "BmUICo2mnUMK7JuJNSZe5DMCAwEAAQ==" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "sshpka:ssh-rsa" - "sshpka:rsa-sha2-512" - "" - "" - "sshkea:diffie-hellman-group18-sha512" - "" - "" - "sshea:aes256-cbc" - "" - "" - "sshma:hmac-sha1" - "" - "" - "" - "" - "" - "" - ""; - -static int -setup(struct ly_ctx *ctx) -{ - int i; - const char *all_features[] = {"*", NULL}; - /* no ssh-x509-certs */ - const char *ssh_common_features[] = {"transport-params", "public-key-generation", NULL}; - /* no ssh-server-keepalives and local-user-auth-hostbased */ - const char *ssh_server_features[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL}; - /* no private-key-encryption and csr-generation */ - const char *crypto_types_features[] = { - "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format", - "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format", - "p10-based-csrs", "certificate-expiration-notification", "hidden-keys", "password-encryption", - "symmetric-key-encryption", NULL - }; - - const char *module_names[] = { - "ietf-netconf-server", "ietf-tls-common", "ietf-tls-server", "ietf-truststore", "iana-crypt-hash", "ietf-keystore", - "ietf-tcp-server", "ietf-tcp-common", "ietf-tcp-client", "iana-ssh-public-key-algs", - "iana-ssh-key-exchange-algs", "iana-ssh-encryption-algs", "iana-ssh-mac-algs", NULL - }; - - for (i = 0; module_names[i] != NULL; i++) { - if (!ly_ctx_load_module(ctx, module_names[i], NULL, all_features)) { - fprintf(stderr, "Loading module (%s) failed.\n", module_names[i]); - goto error; - } - } - - if (!ly_ctx_load_module(ctx, "ietf-ssh-common", NULL, ssh_common_features)) { - fprintf(stderr, "Loading module (ietf-ssh-common) failed.\n"); - goto error; - } - if (!ly_ctx_load_module(ctx, "ietf-ssh-server", NULL, ssh_server_features)) { - fprintf(stderr, "Loading module (ietf-ssh-server) failed.\n"); - goto error; - } - if (!ly_ctx_load_module(ctx, "ietf-crypto-types", NULL, crypto_types_features)) { - fprintf(stderr, "Loading module (ietf-crypto-types) failed.\n"); - goto error; - } - - return 0; - -error: - return 1; -} - -int -main(void) -{ - int ret; - struct ly_ctx *ctx; - struct lyd_node *tree; - - nc_verbosity(NC_VERB_VERBOSE); - - ret = ly_ctx_new("/home/roman/Downloads/yang", 0, &ctx); - nc_assert(!ret); - - ret = setup(ctx); - nc_assert(!ret); - - ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); - nc_assert(!ret); - - ret = nc_server_config_setup(tree); - nc_assert(!ret); - - nc_server_init(); - - nc_server_destroy(); - lyd_free_all(tree); - ly_ctx_destroy(ctx); - return 0; -} diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c index 37ac20cc..ac7550e0 100644 --- a/tests/test_two_channels.c +++ b/tests/test_two_channels.c @@ -32,8 +32,8 @@ #include "tests/config.h" -#define NC_ACCEPT_TIMEOUT 5000 -#define NC_PS_POLL_TIMEOUT 500 +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 #define BACKOFF_TIMEOUT_USECS 100 struct ly_ctx *ctx; diff --git a/tests/test_unix_socket.c b/tests/test_unix_socket.c new file mode 100644 index 00000000..56c1f127 --- /dev/null +++ b/tests/test_unix_socket.c @@ -0,0 +1,198 @@ +/** + * @file test_keystore.c + * @author Roman Janota + * @brief libnetconf2 Linux PAM keyboard-interactive authentication test + * + * @copyright + * Copyright (c) 2022 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 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 + +struct ly_ctx *ctx; + +struct test_state { + pthread_barrier_t barrier; +}; + +const char *data = + "\n" + " \n" + " 10\n" + " \n" + " default-unix-socket\n" + " \n" + " /tmp/nc2_test_unix_sock\n" + " \n" + " \n" + " \n" + "\n"; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_thread_destroy(); + return NULL; +} + +static void * +client_thread(void *arg) +{ + struct nc_session *session = NULL; + struct test_state *state = arg; + + pthread_barrier_wait(&state->barrier); + session = nc_connect_unix("/tmp/nc2_test_unix_sock", NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_connect_unix_socket(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* initialize context */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf-netconf-server module and it's dependencies into context */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* parse yang data */ + ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup(tree); + assert_int_equal(ret, 0); + + /* initialize client */ + nc_client_init(); + + /* initialize server */ + ret = nc_server_init(); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_connect_unix_socket, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} From eb9f1d9736ff642c56427ce4401bceec90089214 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 24 Feb 2023 16:33:08 +0100 Subject: [PATCH 005/134] configuration UPDATE file and func names unified --- CMakeLists.txt | 4 +- examples/server.c | 2 +- src/{config_server.c => server_config.c} | 150 +++++++++++------------ src/{config_server.h => server_config.h} | 4 +- tests/client/test_client_ssh.c | 2 +- tests/test_auth.c | 2 +- tests/test_keystore.c | 2 +- tests/test_two_channels.c | 2 +- tests/test_unix_socket.c | 2 +- 9 files changed, 85 insertions(+), 85 deletions(-) rename src/{config_server.c => server_config.c} (93%) rename src/{config_server.h => server_config.h} (97%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47405677..3bd17140 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,7 +112,7 @@ set(libsrc src/session.c src/session_client.c src/session_server.c - src/config_server.c) + src/server_config.c) if(ENABLE_SSH) list(APPEND libsrc @@ -138,7 +138,7 @@ set(headers src/session_client_ch.h src/session_server.h src/session_server_ch.h - src/config_server.h) + src/server_config.h) # files to generate doxygen from set(doxy_files diff --git a/examples/server.c b/examples/server.c index c0e7cc57..d30dfc87 100644 --- a/examples/server.c +++ b/examples/server.c @@ -27,10 +27,10 @@ #include -#include "config_server.h" #include "log.h" #include "messages_server.h" #include "netconf.h" +#include "server_config.h" #include "session_server.h" #include "session_server_ch.h" diff --git a/src/config_server.c b/src/server_config.c similarity index 93% rename from src/config_server.c rename to src/server_config.c index 50e3c1bf..58fe2556 100644 --- a/src/config_server.c +++ b/src/server_config.c @@ -1,5 +1,5 @@ /** - * @file config_server.c + * @file server_config.c * @author Roman Janota * @brief libnetconf2 server configuration functions * @@ -17,8 +17,8 @@ #include #include "compat.h" -#include "config_server.h" #include "libnetconf.h" +#include "server_config.h" #include "session_server.h" #include "session_server_ch.h" @@ -541,7 +541,7 @@ nc_server_config_del_keystore(void) /* presence container */ int -nc_server_configure_listen(NC_OPERATION op) +nc_server_config_listen(NC_OPERATION op) { uint16_t i; @@ -564,7 +564,7 @@ nc_server_configure_listen(NC_OPERATION op) /* default leaf */ static int -nc_server_configure_idle_timeout(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op) { assert(!strcmp(LYD_NAME(node), "idle-timeout")); @@ -639,7 +639,7 @@ nc_server_create_endpoint(const struct lyd_node *node) /* list */ static int -nc_server_configure_endpoint(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_endpt *endpt; @@ -680,7 +680,7 @@ nc_server_create_ssh(struct nc_endpt *endpt) /* NP container */ static int -nc_server_configure_ssh(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_bind *bind; @@ -773,7 +773,7 @@ nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, /* mandatory leaf */ static int -nc_server_configure_local_address(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_bind *bind; @@ -809,7 +809,7 @@ nc_server_configure_local_address(const struct lyd_node *node, NC_OPERATION op) /* leaf with default value */ static int -nc_server_configure_local_port(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_bind *bind; @@ -842,7 +842,7 @@ nc_server_configure_local_port(const struct lyd_node *node, NC_OPERATION op) /* P container */ static int -nc_server_configure_keepalives(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_bind *bind; @@ -873,7 +873,7 @@ nc_server_configure_keepalives(const struct lyd_node *node, NC_OPERATION op) /* mandatory leaf */ static int -nc_server_configure_idle_time(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_bind *bind; @@ -904,7 +904,7 @@ nc_server_configure_idle_time(const struct lyd_node *node, NC_OPERATION op) /* mandatory leaf */ static int -nc_server_configure_max_probes(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_bind *bind; @@ -935,7 +935,7 @@ nc_server_configure_max_probes(const struct lyd_node *node, NC_OPERATION op) /* mandatory leaf */ static int -nc_server_configure_probe_interval(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_bind *bind; @@ -1006,7 +1006,7 @@ nc_server_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts /* list */ static int -nc_server_configure_host_key(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_hostkey *hostkey; @@ -1047,8 +1047,8 @@ nc_server_configure_host_key(const struct lyd_node *node, NC_OPERATION op) } /* mandatory leaf */ -int -nc_server_configure_public_key_format(const struct lyd_node *node, NC_OPERATION op) +static int +nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) { const char *format; struct nc_endpt *endpt; @@ -1099,9 +1099,9 @@ nc_server_configure_public_key_format(const struct lyd_node *node, NC_OPERATION if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { if (!strcmp(format, "ssh-public-key-format")) { - hostkey->pubkey_type = NC_SSH_PUBKEY_X509; - } else if (!strcmp(format, "subject-public-key-info-format")) { hostkey->pubkey_type = NC_SSH_PUBKEY_SSH2; + } else if (!strcmp(format, "subject-public-key-info-format")) { + hostkey->pubkey_type = NC_SSH_PUBKEY_X509; } else { ERR(NULL, "Public key format (%s) not supported.", format); } @@ -1113,8 +1113,8 @@ nc_server_configure_public_key_format(const struct lyd_node *node, NC_OPERATION } /* leaf */ -int -nc_server_configure_private_key_format(const struct lyd_node *node, NC_OPERATION op) +static int +nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op) { const char *format; struct nc_endpt *endpt; @@ -1162,7 +1162,7 @@ nc_server_replace_cleartext_private_key(const struct lyd_node *node, struct nc_h } static int -nc_server_configure_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_hostkey *hostkey; @@ -1219,7 +1219,7 @@ nc_server_create_keystore_reference(const struct lyd_node *node, struct nc_hostk /* leaf */ static int -nc_server_configure_keystore_reference(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_hostkey *hostkey; @@ -1314,7 +1314,7 @@ nc_server_replace_host_key_public_key(const struct lyd_node *node, struct nc_hos } static int -nc_server_configure_public_key(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_hostkey *hostkey; @@ -1440,7 +1440,7 @@ nc_server_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *op /* list */ static int -nc_server_configure_user(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_client_auth *auth_client; @@ -1474,7 +1474,7 @@ nc_server_configure_user(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_configure_auth_attempts(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; int ret = 0; @@ -1497,7 +1497,7 @@ nc_server_configure_auth_attempts(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_configure_auth_timeout(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; int ret = 0; @@ -1536,7 +1536,7 @@ nc_server_replace_truststore_reference(const struct lyd_node *node, struct nc_cl /* leaf */ static int -nc_server_configure_truststore_reference(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_client_auth *auth_client; @@ -1585,7 +1585,7 @@ nc_server_replace_password(const struct lyd_node *node, struct nc_client_auth *a /* leaf */ static int -nc_server_configure_password(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_client_auth *auth_client; @@ -1619,7 +1619,7 @@ nc_server_configure_password(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_configure_pam_name(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_client_auth *auth_client; @@ -1655,7 +1655,7 @@ nc_server_configure_pam_name(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_configure_pam_dir(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_client_auth *auth_client; @@ -1691,7 +1691,7 @@ nc_server_configure_pam_dir(const struct lyd_node *node, NC_OPERATION op) /* leaf */ static int -nc_server_configure_none(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_none(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_client_auth *auth_client; @@ -1722,7 +1722,7 @@ nc_server_configure_none(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_configure_transport_params(const char *alg, char **alg_store, NC_OPERATION op) +nc_server_config_transport_params(const char *alg, char **alg_store, NC_OPERATION op) { int ret = 0, alg_found = 0; char *substr, *haystack; @@ -1778,7 +1778,7 @@ nc_server_configure_transport_params(const char *alg, char **alg_store, NC_OPERA /* leaf-list */ static int -nc_server_configure_host_key_alg(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; int ret = 0, listen = 0; @@ -1800,7 +1800,7 @@ nc_server_configure_host_key_alg(const struct lyd_node *node, NC_OPERATION op) while (supported_hostkey_algs[i]) { if (!strcmp(supported_hostkey_algs[i], alg)) { if (listen) { - if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->hostkey_algs, op)) { + if (nc_server_config_transport_params(alg, &endpt->opts.ssh->hostkey_algs, op)) { ret = 1; goto cleanup; } @@ -1821,7 +1821,7 @@ nc_server_configure_host_key_alg(const struct lyd_node *node, NC_OPERATION op) /* leaf-list */ static int -nc_server_configure_kex_alg(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; int ret = 0, listen = 0; @@ -1843,7 +1843,7 @@ nc_server_configure_kex_alg(const struct lyd_node *node, NC_OPERATION op) while (supported_kex_algs[i]) { if (!strcmp(supported_kex_algs[i], alg)) { if (listen) { - if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->kex_algs, op)) { + if (nc_server_config_transport_params(alg, &endpt->opts.ssh->kex_algs, op)) { ret = 1; goto cleanup; } @@ -1864,7 +1864,7 @@ nc_server_configure_kex_alg(const struct lyd_node *node, NC_OPERATION op) /* leaf-list */ static int -nc_server_configure_encryption_alg(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; int ret = 0, listen = 0; @@ -1886,7 +1886,7 @@ nc_server_configure_encryption_alg(const struct lyd_node *node, NC_OPERATION op) while (supported_encryption_algs[i]) { if (!strcmp(supported_encryption_algs[i], alg)) { if (listen) { - if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->encryption_algs, op)) { + if (nc_server_config_transport_params(alg, &endpt->opts.ssh->encryption_algs, op)) { ret = 1; goto cleanup; } @@ -1907,7 +1907,7 @@ nc_server_configure_encryption_alg(const struct lyd_node *node, NC_OPERATION op) /* leaf-list */ static int -nc_server_configure_mac_alg(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; int ret = 0, listen = 0; @@ -1929,7 +1929,7 @@ nc_server_configure_mac_alg(const struct lyd_node *node, NC_OPERATION op) while (supported_mac_algs[i]) { if (!strcmp(supported_mac_algs[i], alg)) { if (listen) { - if (nc_server_configure_transport_params(alg, &endpt->opts.ssh->mac_algs, op)) { + if (nc_server_config_transport_params(alg, &endpt->opts.ssh->mac_algs, op)) { ret = 1; goto cleanup; } @@ -1967,7 +1967,7 @@ nc_server_create_unix_socket(struct nc_endpt *endpt) } static int -nc_server_configure_unix_socket(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; uint32_t prev_lo; @@ -2040,119 +2040,119 @@ nc_server_configure(const struct lyd_node *node, NC_OPERATION op) const char *name = LYD_NAME(node); if (!strcmp(name, "listen")) { - if (nc_server_configure_listen(op)) { + if (nc_server_config_listen(op)) { goto error; } } else if (!strcmp(name, "idle-timeout")) { - if (nc_server_configure_idle_timeout(node, op)) { + if (nc_server_config_idle_timeout(node, op)) { goto error; } } else if (!strcmp(name, "endpoint")) { - if (nc_server_configure_endpoint(node, op)) { + if (nc_server_config_endpoint(node, op)) { goto error; } } else if (!strcmp(name, "ssh")) { - if (nc_server_configure_ssh(node, op)) { + if (nc_server_config_ssh(node, op)) { goto error; } } else if (!strcmp(name, "local-address")) { - if (nc_server_configure_local_address(node, op)) { + if (nc_server_config_local_address(node, op)) { goto error; } } else if (!strcmp(name, "local-port")) { - if (nc_server_configure_local_port(node, op)) { + if (nc_server_config_local_port(node, op)) { goto error; } } else if (!strcmp(name, "keepalives")) { - if (nc_server_configure_keepalives(node, op)) { + if (nc_server_config_keepalives(node, op)) { goto error; } } else if (!strcmp(name, "idle-time")) { - if (nc_server_configure_idle_time(node, op)) { + if (nc_server_config_idle_time(node, op)) { goto error; } } else if (!strcmp(name, "max-probes")) { - if (nc_server_configure_max_probes(node, op)) { + if (nc_server_config_max_probes(node, op)) { goto error; } } else if (!strcmp(name, "probe-interval")) { - if (nc_server_configure_probe_interval(node, op)) { + if (nc_server_config_probe_interval(node, op)) { goto error; } } else if (!strcmp(name, "host-key")) { - if (nc_server_configure_host_key(node, op)) { + if (nc_server_config_host_key(node, op)) { goto error; } } else if (!strcmp(name, "public-key-format")) { - if (nc_server_configure_public_key_format(node, op)) { + if (nc_server_config_public_key_format(node, op)) { goto error; } } else if (!strcmp(name, "public-key")) { - if (nc_server_configure_public_key(node, op)) { + if (nc_server_config_public_key(node, op)) { goto error; } } else if (!strcmp(name, "private-key-format")) { - if (nc_server_configure_private_key_format(node, op)) { + if (nc_server_config_private_key_format(node, op)) { goto error; } } else if (!strcmp(name, "cleartext-private-key")) { - if (nc_server_configure_cleartext_private_key(node, op)) { + if (nc_server_config_cleartext_private_key(node, op)) { goto error; } } else if (!strcmp(name, "keystore-reference")) { - if (nc_server_configure_keystore_reference(node, op)) { + if (nc_server_config_keystore_reference(node, op)) { goto error; } } else if (!strcmp(name, "user")) { - if (nc_server_configure_user(node, op)) { + if (nc_server_config_user(node, op)) { goto error; } } else if (!strcmp(name, "auth-attempts")) { - if (nc_server_configure_auth_attempts(node, op)) { + if (nc_server_config_auth_attempts(node, op)) { goto error; } } else if (!strcmp(name, "auth-timeout")) { - if (nc_server_configure_auth_timeout(node, op)) { + if (nc_server_config_auth_timeout(node, op)) { goto error; } } else if (!strcmp(name, "truststore-reference")) { - if (nc_server_configure_truststore_reference(node, op)) { + if (nc_server_config_truststore_reference(node, op)) { goto error; } } else if (!strcmp(name, "password")) { - if (nc_server_configure_password(node, op)) { + if (nc_server_config_password(node, op)) { goto error; } } else if (!strcmp(name, "pam-config-file-name")) { - if (nc_server_configure_pam_name(node, op)) { + if (nc_server_config_pam_name(node, op)) { goto error; } } else if (!strcmp(name, "pam-config-file-dir")) { - if (nc_server_configure_pam_dir(node, op)) { + if (nc_server_config_pam_dir(node, op)) { goto error; } } else if (!strcmp(name, "none")) { - if (nc_server_configure_none(node, op)) { + if (nc_server_config_none(node, op)) { goto error; } } else if (!strcmp(name, "host-key-alg")) { - if (nc_server_configure_host_key_alg(node, op)) { + if (nc_server_config_host_key_alg(node, op)) { goto error; } } else if (!strcmp(name, "key-exchange-alg")) { - if (nc_server_configure_kex_alg(node, op)) { + if (nc_server_config_kex_alg(node, op)) { goto error; } } else if (!strcmp(name, "encryption-alg")) { - if (nc_server_configure_encryption_alg(node, op)) { + if (nc_server_config_encryption_alg(node, op)) { goto error; } } else if (!strcmp(name, "mac-alg")) { - if (nc_server_configure_mac_alg(node, op)) { + if (nc_server_config_mac_alg(node, op)) { goto error; } } else if (!strcmp(name, "unix-socket")) { - if (nc_server_configure_unix_socket(node, op)) { + if (nc_server_config_unix_socket(node, op)) { goto error; } } else if (!strcmp(name, "cert-data")) {} else if (!strcmp(name, "expiration-date")) {} else if (!strcmp(name, "asymmetric-key")) {} else if (!strcmp(name, "certificate")) {} else if (!strcmp(name, "key-format")) {} else if (!strcmp(name, @@ -2224,7 +2224,7 @@ nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op } static int -nc_server_configure_asymmetric_key_certificate(const struct lyd_node *tree, struct nc_ks_asym_key *key) +nc_server_config_asymmetric_key_certificate(const struct lyd_node *tree, struct nc_ks_asym_key *key) { int ret = 0; struct lyd_node *node; @@ -2267,7 +2267,7 @@ nc_server_configure_asymmetric_key_certificate(const struct lyd_node *tree, stru } static int -nc_server_configure_asymmetric_key(const struct lyd_node *tree) +nc_server_config_asymmetric_key(const struct lyd_node *tree) { int ret = 0; struct lyd_node *node = NULL, *iter; @@ -2358,7 +2358,7 @@ nc_server_configure_asymmetric_key(const struct lyd_node *tree) if (node) { /* certificate list instance */ LY_LIST_FOR(node, iter) { - if (nc_server_configure_asymmetric_key_certificate(iter, key)) { + if (nc_server_config_asymmetric_key_certificate(iter, key)) { ret = 1; goto cleanup; } @@ -2374,7 +2374,7 @@ nc_server_configure_asymmetric_key(const struct lyd_node *tree) } static int -nc_server_configure_symmetric_key(const struct lyd_node *tree) +nc_server_config_symmetric_key(const struct lyd_node *tree) { int ret = 0; const char *format; @@ -2454,7 +2454,7 @@ nc_fill_keystore(const struct lyd_node *data) if (as_keys && !strcmp(LYD_NAME(as_keys), "asymmetric-key")) { /* asymmetric key list */ LY_LIST_FOR(as_keys, iter) { - if (nc_server_configure_asymmetric_key(iter)) { + if (nc_server_config_asymmetric_key(iter)) { ret = 1; goto cleanup; } @@ -2469,7 +2469,7 @@ nc_fill_keystore(const struct lyd_node *data) if (s_keys && !strcmp(LYD_NAME(s_keys), "symmetric-key")) { /* symmetric key list */ LY_LIST_FOR(s_keys, iter) { - if (nc_server_configure_symmetric_key(iter)) { + if (nc_server_config_symmetric_key(iter)) { ret = 1; goto cleanup; } diff --git a/src/config_server.h b/src/server_config.h similarity index 97% rename from src/config_server.h rename to src/server_config.h index 9397f662..189431b5 100644 --- a/src/config_server.h +++ b/src/server_config.h @@ -1,5 +1,5 @@ /** - * @file config_server.h + * @file server_config.h * @author Roman Janota * @brief libnetconf2 server configuration * @@ -74,7 +74,7 @@ int nc_server_config_load_modules(struct ly_ctx **ctx); * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. * @return 0 on success, 1 on error. */ -int nc_server_configure_listen(NC_OPERATION op); +int nc_server_config_listen(NC_OPERATION op); /** * @brief Deletes every key stored in the keystore. diff --git a/tests/client/test_client_ssh.c b/tests/client/test_client_ssh.c index 20c546b1..e9a21655 100644 --- a/tests/client/test_client_ssh.c +++ b/tests/client/test_client_ssh.c @@ -23,9 +23,9 @@ #include #include -#include #include #include +#include #include #include #include diff --git a/tests/test_auth.c b/tests/test_auth.c index 5511da94..c6bfae99 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -22,10 +22,10 @@ #include -#include #include #include #include +#include #include #include diff --git a/tests/test_keystore.c b/tests/test_keystore.c index c7e8af86..7c20577a 100644 --- a/tests/test_keystore.c +++ b/tests/test_keystore.c @@ -22,10 +22,10 @@ #include -#include #include #include #include +#include #include #include diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c index ac7550e0..fb85bbf9 100644 --- a/tests/test_two_channels.c +++ b/tests/test_two_channels.c @@ -23,10 +23,10 @@ #include -#include #include #include #include +#include #include #include diff --git a/tests/test_unix_socket.c b/tests/test_unix_socket.c index 56c1f127..e698e7be 100644 --- a/tests/test_unix_socket.c +++ b/tests/test_unix_socket.c @@ -22,10 +22,10 @@ #include -#include #include #include #include +#include #include #include From 4fab7163ee5a36d0e8dcd4fb317ed9f9e82e3f0c Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 10 Mar 2023 14:55:00 +0100 Subject: [PATCH 006/134] configuration UPDATE new config YANG data creation Hostkey, address, port (mandatory nodes) and SSH algorithms ietf-netconf-server YANG nodes now have functions, through which their YANG data can be created. This data can be used for server configuration. Test which fails at authentication (as expected) is provided. Minor bugfixes in server_config. --- CMakeLists.txt | 6 +- src/config_new.c | 529 ++++++++++++++++++++++++++++++++++++++++ src/config_new.h | 142 +++++++++++ src/server_config.c | 8 +- tests/CMakeLists.txt | 2 +- tests/test_config_new.c | 216 ++++++++++++++++ 6 files changed, 898 insertions(+), 5 deletions(-) create mode 100644 src/config_new.c create mode 100644 src/config_new.h create mode 100644 tests/test_config_new.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bd17140..0758aa78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,7 +112,8 @@ set(libsrc src/session.c src/session_client.c src/session_server.c - src/server_config.c) + src/server_config.c + src/config_new.c) if(ENABLE_SSH) list(APPEND libsrc @@ -138,7 +139,8 @@ set(headers src/session_client_ch.h src/session_server.h src/session_server_ch.h - src/server_config.h) + src/server_config.h + src/config_new.h) # files to generate doxygen from set(doxy_files diff --git a/src/config_new.c b/src/config_new.c new file mode 100644 index 00000000..24db6f03 --- /dev/null +++ b/src/config_new.c @@ -0,0 +1,529 @@ +/** + * @file config_new.c + * @author Roman Janota + * @brief libnetconf2 server new configuration creation functions + * + * @copyright + * Copyright (c) 2015 - 2021 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "compat.h" +#include "config_new.h" +#include "libnetconf.h" +#include "server_config.h" + +static int +nc_server_config_ssh_new_get_keys(const char *privkey_path, const char *pubkey_path, + char **privkey, char **pubkey, EVP_PKEY **priv_pkey_p) +{ + int ret = 0; + EVP_PKEY *priv_pkey = NULL, *pub_pkey = NULL; + FILE *f_privkey = NULL, *f_pubkey = NULL; + BIO *bio_pub = NULL, *bio_priv = NULL; + int pub_len, priv_len; + + assert(privkey_path); + assert(privkey); + assert(pubkey); + assert(priv_pkey_p); + *privkey = NULL; + *pubkey = NULL; + *priv_pkey_p = NULL; + + /* get private key first */ + f_privkey = fopen(privkey_path, "r"); + if (!f_privkey) { + ERR(NULL, "Unable to open file \"%s\".", privkey_path); + ret = 1; + goto cleanup; + } + + priv_pkey = PEM_read_PrivateKey(f_privkey, NULL, NULL, NULL); + if (!priv_pkey) { + ret = -1; + goto cleanup; + } + /* set out param */ + *priv_pkey_p = priv_pkey; + + bio_priv = BIO_new(BIO_s_mem()); + if (!bio_priv) { + ret = -1; + goto cleanup; + } + + ret = PEM_write_bio_PrivateKey(bio_priv, priv_pkey, NULL, NULL, 0, NULL, NULL); + if (!ret) { + ret = -1; + goto cleanup; + } + + priv_len = BIO_pending(bio_priv); + if (priv_len <= 0) { + ret = -1; + goto cleanup; + } + + *privkey = malloc(priv_len + 1); + if (!*privkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + + ret = BIO_read(bio_priv, *privkey, priv_len); + if (ret <= 0) { + ret = -1; + goto cleanup; + } + (*privkey)[priv_len] = '\0'; + + /* if public key is supplied, then read it */ + if (pubkey_path) { + f_pubkey = fopen(pubkey_path, "r"); + if (!f_pubkey) { + ERR(NULL, "Unable to open file \"%s\"", pubkey_path); + ret = 1; + goto cleanup; + } + pub_pkey = PEM_read_PUBKEY(f_pubkey, NULL, NULL, NULL); + if (!pub_pkey) { + ret = -1; + goto cleanup; + } + } + + bio_pub = BIO_new(BIO_s_mem()); + if (!bio_pub) { + ret = -1; + goto cleanup; + } + + /* get public key either from the private key or from the given file */ + if (pubkey_path) { + ret = PEM_write_bio_PUBKEY(bio_pub, pub_pkey); + } else { + ret = PEM_write_bio_PUBKEY(bio_pub, priv_pkey); + } + if (!ret) { + ret = -1; + goto cleanup; + } + + pub_len = BIO_pending(bio_pub); + if (pub_len <= 0) { + ret = -1; + goto cleanup; + } + + *pubkey = malloc(pub_len + 1); + if (!*pubkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + + ret = BIO_read(bio_pub, *pubkey, pub_len); + if (ret <= 0) { + ret = -1; + goto cleanup; + } + (*pubkey)[pub_len] = '\0'; + + ret = 0; +cleanup: + if (ret < 0) { + ERR(NULL, "Error getting keys from file: \"%s\".", ERR_reason_error_string(ERR_get_error())); + ret = 1; + } + EVP_PKEY_free(pub_pkey); + if (f_privkey) { + fclose(f_privkey); + } + if (f_pubkey) { + fclose(f_pubkey); + } + BIO_free(bio_priv); + BIO_free(bio_pub); + return ret; +} + +API int +nc_server_config_ssh_new_hostkey(const char *privkey_path, const char *pubkey_path, const struct ly_ctx *ctx, + const char *endpt_name, const char *hostkey_name, struct lyd_node **config) +{ + int ret = 0; + char *pub_key = NULL, *priv_key = NULL, *pub_key_stripped, *priv_key_stripped; + struct lyd_node *new_tree; + char *tree_path = NULL; + EVP_PKEY *priv_pkey = NULL; + + if (!privkey_path || !config || !ctx || !endpt_name || !hostkey_name) { + ERRARG("privkey_path or config or ctx or endpt_name or hostkey_name"); + } + + /* get the keys as a string from the given files */ + ret = nc_server_config_ssh_new_get_keys(privkey_path, pubkey_path, &priv_key, &pub_key, &priv_pkey); + if (ret) { + ERR(NULL, "Getting keys from file(s) failed."); + goto cleanup; + } + + /* prepare path where leaves will get inserted */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key[name='%s']/public-key/local-definition", endpt_name, hostkey_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path if they weren't there */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + /* give the top level container create operation */ + ret = lyd_new_meta(ctx, *config, NULL, "yang:operation", "create", 0, NULL); + if (ret) { + goto cleanup; + } + + /* find the node where leaves will get inserted */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + if (ret) { + goto cleanup; + } + + /* insert pubkey format */ + if (!strstr(pub_key, "---- BEGIN SSH2 PUBLIC KEY ----")) { + ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:ssh-public-key-format", 0, NULL); + } else { + ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:subject-public-key-info-format", 0, NULL); + } + if (ret) { + goto cleanup; + } + + /* strip pubkey's header and footer */ + pub_key_stripped = pub_key + strlen("-----BEGIN PUBLIC KEY-----") + 1; + pub_key_stripped[strlen(pub_key_stripped) - strlen("-----END PUBLIC KEY-----") - 2] = '\0'; + + /* insert pubkey b64 */ + ret = lyd_new_term(new_tree, NULL, "public-key", pub_key_stripped, 0, NULL); + if (ret) { + goto cleanup; + } + + /* do the same for private key */ + if (EVP_PKEY_is_a(priv_pkey, "RSA")) { + ret = lyd_new_term(new_tree, NULL, "private-key-format", "ietf-crypto-types:rsa-private-key-format", 0, NULL); + } else if (EVP_PKEY_is_a(priv_pkey, "EC")) { + ret = lyd_new_term(new_tree, NULL, "private-key-format", "ietf-crypto-types:ec-private-key-format", 0, NULL); + } else { + ERR(NULL, "Private key type not supported."); + ret = 1; + } + if (ret) { + goto cleanup; + } + + priv_key_stripped = priv_key + strlen("-----BEGIN PRIVATE KEY-----") + 1; + priv_key_stripped[strlen(priv_key_stripped) - strlen("-----END PRIVATE KEY-----") - 2] = '\0'; + + ret = lyd_new_term(new_tree, NULL, "cleartext-private-key", priv_key_stripped, 0, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + EVP_PKEY_free(priv_pkey); + free(priv_key); + free(pub_key); + free(tree_path); + return ret; +} + +API int +nc_server_config_ssh_new_address_port(const char *address, const char *port, const struct ly_ctx *ctx, + const char *endpt_name, struct lyd_node **config) +{ + int ret = 0; + char *tree_path = NULL; + struct lyd_node *new_tree; + + if (!address || !port || !ctx || !endpt_name || !config) { + ERRARG("args"); + ret = 1; + goto cleanup; + } + + /* prepare path for instertion of leaves later */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/tcp-server-parameters", endpt_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + /* lyd_new_path sets the out param to the first node created, + * so in case the original tree was empty new_tree has to be set correctly */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + if (ret) { + ERR(NULL, "Unable to find tcp-server-parameters container."); + goto cleanup; + } + + ret = lyd_new_term(new_tree, NULL, "local-address", address, 0, NULL); + if (ret) { + goto cleanup; + } + + ret = lyd_new_term(new_tree, NULL, "local-port", port, 0, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(tree_path); + return ret; +} + +static int +nc_server_config_ssh_new_transport_params_prep(const struct ly_ctx *ctx, const char *endpt_name, + struct lyd_node *config, struct lyd_node **new_tree, struct lyd_node **alg_tree) +{ + int ret = 0; + char *tree_path = NULL; + + /* prepare path */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params", endpt_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path2(config, ctx, tree_path, NULL, 0, 0, LYD_NEW_PATH_UPDATE, new_tree, alg_tree); + if (ret) { + ERR(NULL, "Creating new path to transport-params failed."); + goto cleanup; + } + +cleanup: + free(tree_path); + return ret; +} + +static int +nc_server_config_ssh_new_transport_params(const struct ly_ctx *ctx, NC_ALG_TYPE alg_type, int alg_count, va_list ap, + struct lyd_node *tree) +{ + int i, ret = 0; + char *alg, *alg_ident; + const char *module, *alg_path, *old_path; + struct lyd_node *old = NULL; + + /* get the correct module with the indentity base and the path in the ietf-netconf-server module */ + switch (alg_type) { + case NC_ALG_HOSTKEY: + module = "iana-ssh-public-key-algs"; + alg_path = "host-key/host-key-alg"; + old_path = "host-key"; + break; + case NC_ALG_KEY_EXCHANGE: + module = "iana-ssh-key-exchange-algs"; + alg_path = "key-exchange/key-exchange-alg"; + old_path = "key-exchange"; + break; + case NC_ALG_ENCRYPTION: + module = "iana-ssh-encryption-algs"; + alg_path = "encryption/encryption-alg"; + old_path = "encryption"; + break; + case NC_ALG_MAC: + module = "iana-ssh-mac-algs"; + alg_path = "mac/mac-alg"; + old_path = "mac"; + break; + default: + ret = 1; + ERR(NULL, "Unknown algorithm type."); + goto cleanup; + } + + /* delete all older algorithms (if any) se they can be replaced by the new ones */ + lyd_find_path(tree, old_path, 0, &old); + if (old) { + lyd_free_tree(old); + } + + for (i = 0; i < alg_count; i++) { + alg = va_arg(ap, char *); + + asprintf(&alg_ident, "%s:%s", module, alg); + if (!alg_ident) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create the leaf list */ + ret = lyd_new_path(tree, ctx, alg_path, alg_ident, 0, NULL); + if (ret) { + ERR(NULL, "Creating new algorithm leaf-list failed."); + goto cleanup; + } + + free(alg_ident); + } + +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_ssh_new_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) +{ + int ret = 0; + struct lyd_node *new_tree, *alg_tree; + va_list ap; + + ret = nc_server_config_ssh_new_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + if (ret) { + goto cleanup; + } + + if (!*config) { + *config = new_tree; + } + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_new_transport_params(ctx, NC_ALG_HOSTKEY, alg_count, ap, alg_tree); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) +{ + int ret = 0; + struct lyd_node *new_tree, *alg_tree; + va_list ap; + + ret = nc_server_config_ssh_new_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + if (ret) { + goto cleanup; + } + + if (!*config) { + *config = new_tree; + } + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_new_transport_params(ctx, NC_ALG_KEY_EXCHANGE, alg_count, ap, alg_tree); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_ssh_new_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) +{ + int ret = 0; + struct lyd_node *new_tree, *alg_tree; + va_list ap; + + ret = nc_server_config_ssh_new_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + if (ret) { + goto cleanup; + } + + if (!*config) { + *config = new_tree; + } + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_new_transport_params(ctx, NC_ALG_ENCRYPTION, alg_count, ap, alg_tree); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) +{ + int ret = 0; + struct lyd_node *new_tree, *alg_tree; + va_list ap; + + ret = nc_server_config_ssh_new_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + if (ret) { + goto cleanup; + } + + if (!*config) { + *config = new_tree; + } + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_new_transport_params(ctx, NC_ALG_MAC, alg_count, ap, alg_tree); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} diff --git a/src/config_new.h b/src/config_new.h new file mode 100644 index 00000000..82a79d33 --- /dev/null +++ b/src/config_new.h @@ -0,0 +1,142 @@ +/** + * @file config_new.h + * @author Roman Janota + * @brief libnetconf2 server new configuration creation + * + * @copyright + * Copyright (c) 2015 - 2021 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_NEW_H_ +#define NC_CONFIG_NEW_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + NC_ALG_HOSTKEY, + NC_ALG_KEY_EXCHANGE, + NC_ALG_ENCRYPTION, + NC_ALG_MAC +} NC_ALG_TYPE; + +/** + * @brief Creates new YANG configuration data nodes for a hostkey. + * + * @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] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's hostkey might be changed. + * @param[in] hostkey_name Arbitrary identifier of the hostkey. + * If a hostkey with this identifier already exists, it's 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_ssh_new_hostkey(const char *privkey_path, const char *pubkey_path, const struct ly_ctx *ctx, + const char *endpt_name, const char *hostkey_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a local-address and local-port. + * + * @param[in] address New listening address. + * @param[in] port New listening port. + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's address and port will be overriden. + * @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_ssh_new_address_port(const char *address, const char *port, const struct ly_ctx *ctx, + const char *endpt_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for host-key algorithms replacing any previous ones. + * + * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, + * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's host-key algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_ssh_new_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); + +/** + * @brief Creates new YANG configuration data nodes for key exchange algorithms replacing any previous ones. + * + * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, + * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, + * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's key exchange algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +/** + * @brief Creates new YANG configuration data nodes for encryption algorithms replacing any previous ones. + * + * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc + * triple-des-cbc and none. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's encryption algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_ssh_new_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +/** + * @brief Creates new YANG configuration data nodes for mac algorithms replacing any previous ones. + * + * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's mac algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of mac algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* NC_CONFIG_NEW_H_ */ diff --git a/src/server_config.c b/src/server_config.c index 58fe2556..f11d2899 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -12,6 +12,9 @@ * * https://opensource.org/licenses/BSD-3-Clause */ + +#define _GNU_SOURCE + #include #include #include @@ -42,7 +45,7 @@ static const char *supported_kex_algs[] = { static const char *supported_encryption_algs[] = { "chacha20-poly1305@openssh.com", "aes256-gcm@openssh.com", "aes128-gcm@openssh.com", "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc", - "blowfish-cbc", "3des-cbc", "none", NULL + "blowfish-cbc", "triple-des-cbc", "none", NULL }; static const char *supported_mac_algs[] = { @@ -2444,6 +2447,7 @@ nc_fill_keystore(const struct lyd_node *data) ret = lyd_find_path(data, "/ietf-keystore:keystore", 0, &tree); if (ret) { WRN(NULL, "Keystore container not found in the YANG data."); + ret = 0; goto cleanup; } @@ -2600,7 +2604,7 @@ nc_server_config_setup(const struct lyd_node *data) int ret = 0; struct lyd_node *tree; struct lyd_meta *m; - NC_OPERATION op; + NC_OPERATION op = NC_OP_NONE; /* LOCK */ pthread_rwlock_wrlock(&server_opts.config_lock); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2a13145e..eb413456 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,7 @@ endif() # list of all the tests in each directory #set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages) -set(tests test_two_channels test_keystore test_unix_socket) +set(tests test_two_channels test_keystore test_unix_socket test_config_new) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) diff --git a/tests/test_config_new.c b/tests/test_config_new.c new file mode 100644 index 00000000..1dc4589f --- /dev/null +++ b/tests/test_config_new.c @@ -0,0 +1,216 @@ +/** + * @file test_keystore.c + * @author Roman Janota + * @brief libnetconf2 Linux PAM keyboard-interactive authentication test + * + * @copyright + * Copyright (c) 2022 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 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include "config_new.h" + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 + +struct ly_ctx *ctx; + +struct test_state { + pthread_barrier_t barrier; +}; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_thread_destroy(); + return NULL; +} + +static int +ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) +{ + (void)hostname; + (void)session; + (void)priv; + /* skip the knownhost check */ + + return 0; +} + +static void * +client_thread_pubkey(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + ret = nc_client_ssh_set_username("test_ts"); + assert_int_equal(ret, 0); + + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); + + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_auth_pubkey(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread_pubkey, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + ret = nc_server_config_ssh_new_hostkey(TESTS_DIR "/data/server.key", NULL, ctx, "endpt", "hostkey", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_ssh_new_address_port("127.0.0.1", "10005", ctx, "endpt", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_ssh_new_host_key_algs(ctx, "endpt", &tree, 1, "rsa-sha2-512"); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup(tree); + assert_int_equal(ret, 0); + + /* initialize client */ + nc_client_init(); + + ret = nc_server_init(); + assert_int_equal(ret, 0); + + /* skip the knownhost check */ + nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_auth_pubkey, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} From 751dbad2541f724edc108c1f842778f5fe3693d3 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 24 Mar 2023 09:05:37 +0100 Subject: [PATCH 007/134] configuration UPDATE auth user YANG data creation New API function, which creates the 'client-authentication' subtree of ietf-netconf-server module, added. Only public key configuration is supported for now. SSH authentication bugfix. --- src/config_new.c | 326 +++++++++++++++++++++++++++++++++++++++- src/config_new.h | 18 +++ tests/test_config_new.c | 5 +- 3 files changed, 343 insertions(+), 6 deletions(-) diff --git a/src/config_new.c b/src/config_new.c index 24db6f03..b3ba1d24 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -22,13 +22,16 @@ #include #include +#include #include +#include #include #include "compat.h" #include "config_new.h" #include "libnetconf.h" #include "server_config.h" +#include "session_server.h" static int nc_server_config_ssh_new_get_keys(const char *privkey_path, const char *pubkey_path, @@ -258,6 +261,12 @@ nc_server_config_ssh_new_hostkey(const char *privkey_path, const char *pubkey_pa goto cleanup; } + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + cleanup: EVP_PKEY_free(priv_pkey); free(priv_key); @@ -272,7 +281,7 @@ nc_server_config_ssh_new_address_port(const char *address, const char *port, con { int ret = 0; char *tree_path = NULL; - struct lyd_node *new_tree; + struct lyd_node *new_tree, *port_node; if (!address || !port || !ctx || !endpt_name || !config) { ERRARG("args"); @@ -297,9 +306,13 @@ nc_server_config_ssh_new_address_port(const char *address, const char *port, con *config = new_tree; } - /* lyd_new_path sets the out param to the first node created, - * so in case the original tree was empty new_tree has to be set correctly */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } if (ret) { ERR(NULL, "Unable to find tcp-server-parameters container."); goto cleanup; @@ -310,11 +323,22 @@ nc_server_config_ssh_new_address_port(const char *address, const char *port, con goto cleanup; } - ret = lyd_new_term(new_tree, NULL, "local-port", port, 0, NULL); + ret = lyd_find_path(new_tree, "local-port", 0, &port_node); + if (!ret) { + ret = lyd_change_term(port_node, port); + } else if (ret == LY_ENOTFOUND) { + ret = lyd_new_term(new_tree, NULL, "local-port", port, 0, NULL); + } + if (ret) { goto cleanup; } + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } cleanup: free(tree_path); return ret; @@ -343,6 +367,14 @@ nc_server_config_ssh_new_transport_params_prep(const struct ly_ctx *ctx, const c goto cleanup; } + if (!*alg_tree) { + /* no new nodes added */ + ret = lyd_find_path(config, tree_path, 0, alg_tree); + if (ret) { + goto cleanup; + } + } + cleanup: free(tree_path); return ret; @@ -440,6 +472,11 @@ nc_server_config_ssh_new_host_key_algs(const struct ly_ctx *ctx, const char *end goto cleanup; } + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } cleanup: return ret; } @@ -468,6 +505,11 @@ nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char goto cleanup; } + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } cleanup: return ret; } @@ -496,6 +538,11 @@ nc_server_config_ssh_new_encryption_algs(const struct ly_ctx *ctx, const char *e goto cleanup; } + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } cleanup: return ret; } @@ -524,6 +571,275 @@ nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_na goto cleanup; } + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } +cleanup: + return ret; +} + +static int +nc_server_config_ssh_read_openssh_pubkey(FILE *f, char **pubkey) +{ + int ret = 0; + char *buffer = NULL; + size_t len = 0; + char *start, *end; + + if (getline(&buffer, &len, f) < 0) { + ERR(NULL, "Reading line from file failed."); + return 1; + } + + if (len < 8) { + ERR(NULL, "Unexpected public key format."); + ret = 1; + goto cleanup; + } + + start = buffer; + if (!strncmp(buffer, "ssh-rsa ", 8)) { + start += strlen("ssh-rsa "); + end = strchr(start, ' '); + if (!end) { + ERR(NULL, "Unexpected public key format."); + ret = 1; + goto cleanup; + } + + *pubkey = strdup(start); + if (!*pubkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + + (*pubkey)[strlen(*pubkey) - strlen(end)] = '\0'; + } + cleanup: + free(buffer); + return ret; +} + +static int +nc_server_config_ssh_read_ssh2_pubkey(FILE *f, char **pubkey) +{ + char *buffer = NULL; + size_t len = 0; + size_t pubkey_len = 0; + void *tmp; + + while (getline(&buffer, &len, f) > 0) { + if (!strncmp(buffer, "----", 4)) { + free(buffer); + buffer = NULL; + continue; + } + + if (!strncmp(buffer, "Comment:", 8)) { + free(buffer); + buffer = NULL; + continue; + } + + len = strlen(buffer); + + tmp = realloc(*pubkey, pubkey_len + len + 1); + if (!tmp) { + ERRMEM; + free(buffer); + buffer = NULL; + return 1; + } + + *pubkey = tmp; + memcpy(*pubkey + pubkey_len, buffer, len); + pubkey_len += len; + free(buffer); + buffer = NULL; + } + + if (!pubkey_len) { + ERR(NULL, "Unexpected public key format."); + return 1; + } + + (*pubkey)[pubkey_len - 1] = '\0'; + free(buffer); + return 0; +} + +static int +nc_server_config_ssh_read_subject_pubkey(FILE *f, char **pubkey) +{ + int ret = 0; + EVP_PKEY *pkey; + BIO *bio; + BUF_MEM *mem; + char *tmp; + + pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL); + if (!pkey) { + ret = -1; + goto cleanup; + } + + bio = BIO_new(BIO_s_mem()); + if (!bio) { + ret = -1; + goto cleanup; + } + + ret = PEM_write_bio_PUBKEY(bio, pkey); + if (!ret) { + ret = -1; + goto cleanup; + } + ret = 0; + + BIO_get_mem_ptr(bio, &mem); + tmp = malloc(mem->length + 1); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + + memcpy(tmp, mem->data, mem->length); + tmp[mem->length] = '\0'; + + *pubkey = strdup(tmp + strlen("-----BEGIN PUBLIC KEY-----\n")); + (*pubkey)[strlen(*pubkey) - strlen("\n-----END PUBLIC KEY-----\n")] = '\0'; + +cleanup: + if (ret == -1) { + ERR(NULL, "Error getting public key from file (OpenSSL Error): \"%s\".", ERR_reason_error_string(ERR_get_error())); + ret = 1; + } + + BIO_free(bio); + EVP_PKEY_free(pkey); + free(tmp); + + return ret; +} + +static int +nc_server_config_ssh_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_SSH_PUBKEY_TYPE *pubkey_type) +{ + int ret = 0; + FILE *f = NULL; + char *buffer = NULL; + size_t len = 0; + + *pubkey = NULL; + + f = fopen(pubkey_path, "r"); + if (!f) { + ERR(NULL, "Unable to open file \"%s\".", pubkey_path); + ret = 1; + goto cleanup; + } + + if (getline(&buffer, &len, f) < 0) { + ERR(NULL, "Error reading header from file \"%s\".", pubkey_path); + ret = 1; + goto cleanup; + } + + rewind(f); + + if (!strncmp(buffer, "-----BEGIN PUBLIC KEY-----\n", strlen("-----BEGIN PUBLIC KEY-----\n"))) { + ret = nc_server_config_ssh_read_subject_pubkey(f, pubkey); + *pubkey_type = NC_SSH_PUBKEY_X509; + } else if (!strncmp(buffer, "---- BEGIN SSH2 PUBLIC KEY ----\n", strlen("---- BEGIN SSH2 PUBLIC KEY ----\n"))) { + ret = nc_server_config_ssh_read_ssh2_pubkey(f, pubkey); + *pubkey_type = NC_SSH_PUBKEY_SSH2; + } else { + ret = nc_server_config_ssh_read_openssh_pubkey(f, pubkey); + *pubkey_type = NC_SSH_PUBKEY_SSH2; + } + + if (ret) { + ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path); + goto cleanup; + } + +cleanup: + if (f) { + fclose(f); + } + + free(buffer); + + return ret; +} + +API int +nc_server_config_ssh_new_user(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *pubkey_name, struct lyd_node **config) +{ + int ret = 0; + char *pubkey = NULL, *tree_path = NULL; + struct lyd_node *new_tree; + NC_SSH_PUBKEY_TYPE pubkey_type; + + ret = nc_server_config_ssh_new_get_pubkey(pubkey_path, &pubkey, &pubkey_type); + if (ret) { + goto cleanup; + } + + /* prepare path where leaves will get inserted */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/local-definition/public-key[name='%s']", endpt_name, user_name, pubkey_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path if they weren't there */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + /* find the node where leaves will get inserted */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + if (ret) { + goto cleanup; + } + + /* insert pubkey format */ + if (pubkey_type == NC_SSH_PUBKEY_SSH2) { + ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:ssh-public-key-format", 0, NULL); + } else { + ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:subject-public-key-info-format", 0, NULL); + } + if (ret) { + goto cleanup; + } + + /* insert pubkey b64 */ + ret = lyd_new_term(new_tree, NULL, "public-key", pubkey, 0, NULL); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(tree_path); + free(pubkey); return ret; } diff --git a/src/config_new.h b/src/config_new.h index 82a79d33..3300256c 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -135,6 +135,24 @@ int nc_server_config_ssh_new_encryption_algs(const struct ly_ctx *ctx, const cha int nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...); +/** + * @brief Creates new YANG configuration data nodes for a user. + * + * @param[in] pubkey_path Path to a file containing the user's public key. + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, it's 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, it's 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_ssh_new_user(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *pubkey_name, struct lyd_node **config); + #ifdef __cplusplus } #endif diff --git a/tests/test_config_new.c b/tests/test_config_new.c index 1dc4589f..0b10c1bb 100644 --- a/tests/test_config_new.c +++ b/tests/test_config_new.c @@ -93,7 +93,7 @@ client_thread_pubkey(void *arg) ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); - ret = nc_client_ssh_set_username("test_ts"); + ret = nc_client_ssh_set_username("test_config_new_openssh"); assert_int_equal(ret, 0); nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); @@ -166,6 +166,9 @@ setup_f(void **state) ret = nc_server_config_ssh_new_host_key_algs(ctx, "endpt", &tree, 1, "rsa-sha2-512"); assert_int_equal(ret, 0); + ret = nc_server_config_ssh_new_user(TESTS_DIR "/data/key_rsa.pub", ctx, "endpt", "test_config_new_openssh", "pubkey", &tree); + assert_int_equal(ret, 0); + /* configure the server based on the data */ ret = nc_server_config_setup(tree); assert_int_equal(ret, 0); From cb93834ad260ba87c1050efdb634666cd5f95a05 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 24 Mar 2023 15:26:21 +0100 Subject: [PATCH 008/134] configuration UPDATE password, none & interactive Added the API calls to create password, none and interactive YANG data nodes for the client-authentication subtree. --- src/config_new.c | 184 +++++++++++++++++++++++++++++++++++++++- src/config_new.h | 57 ++++++++++++- tests/test_config_new.c | 6 +- 3 files changed, 240 insertions(+), 7 deletions(-) diff --git a/src/config_new.c b/src/config_new.c index b3ba1d24..edf290a5 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -16,11 +16,13 @@ #define _GNU_SOURCE #include +#include #include #include #include #include #include +#include #include #include @@ -33,6 +35,10 @@ #include "server_config.h" #include "session_server.h" +#if !defined (HAVE_CRYPT_R) +extern pthread_mutex_t crypt_lock; +#endif + static int nc_server_config_ssh_new_get_keys(const char *privkey_path, const char *pubkey_path, char **privkey, char **pubkey, EVP_PKEY **priv_pkey_p) @@ -779,7 +785,7 @@ nc_server_config_ssh_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_S } API int -nc_server_config_ssh_new_user(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, +nc_server_config_ssh_new_client_auth_pubkey(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *pubkey_name, struct lyd_node **config) { int ret = 0; @@ -843,3 +849,179 @@ nc_server_config_ssh_new_user(const char *pubkey_path, const struct ly_ctx *ctx, free(pubkey); return ret; } + +API int +nc_server_config_ssh_new_client_auth_password(const char *password, const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + int ret = 0; + char *tree_path = NULL, *hashed_pw = NULL; + struct lyd_node *new_tree; + const char *salt = "$6$idsizuippipk$"; + +#ifdef HAVE_CRYPT_R + struct crypt_data cdata; +#endif + + /* prepare path where the leaf will get inserted */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']", endpt_name, user_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path if they weren't there */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + /* find the node where the leaf will get inserted */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + if (ret) { + goto cleanup; + } + +#ifdef HAVE_CRYPT_R + cdata.initialized = 0; + hashed_pw = crypt_r(password, salt, &data); +#else + pthread_mutex_lock(&crypt_lock); + hashed_pw = crypt(password, salt); + pthread_mutex_unlock(&crypt_lock); +#endif + + if (!hashed_pw) { + ERR(NULL, "Hashing password failed."); + ret = 1; + goto cleanup; + } + + /* insert SHA-512 hashed password */ + ret = lyd_new_term(new_tree, NULL, "password", hashed_pw, 0, NULL); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(tree_path); + return ret; +} + +API int +nc_server_config_ssh_new_client_auth_none(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + int ret = 0; + char *tree_path = NULL; + struct lyd_node *new_tree; + + /* prepare path where the leaf will get inserted */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']", endpt_name, user_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path if they weren't there */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + /* find the node where the leaf will get inserted */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + if (ret) { + goto cleanup; + } + + /* insert none leaf */ + ret = lyd_new_term(new_tree, NULL, "none", NULL, 0, NULL); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(tree_path); + return ret; +} + +API int +nc_server_config_ssh_new_client_auth_interactive(const char *pam_config_name, const char *pam_config_dir, + const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + int ret = 0; + char *tree_path = NULL; + struct lyd_node *new_tree; + + /* prepare path where the leaf will get inserted */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path if they weren't there */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + /* find the node where the leaf will get inserted */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + if (ret) { + goto cleanup; + } + + /* insert file-name leaf */ + ret = lyd_new_term(new_tree, NULL, "pam-config-file-name", pam_config_name, 0, NULL); + if (ret) { + goto cleanup; + } + + if (pam_config_dir) { + /* insert file-path leaf */ + ret = lyd_new_term(new_tree, NULL, "pam-config-file-dir", pam_config_dir, 0, NULL); + if (ret) { + goto cleanup; + } + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(tree_path); + return ret; +} diff --git a/src/config_new.h b/src/config_new.h index 3300256c..cccda4dd 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -136,7 +136,7 @@ int nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endp int alg_count, ...); /** - * @brief Creates new YANG configuration data nodes for a user. + * @brief Creates new YANG configuration data nodes for a client, which supports the public key authentication method. * * @param[in] pubkey_path Path to a file containing the user's public key. * @param[in] ctx libyang context. @@ -150,9 +150,62 @@ int nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endp * 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_ssh_new_user(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, +int nc_server_config_ssh_new_client_auth_pubkey(const char *pubkey_path, const struct ly_ctx *ctx, 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 client, which supports the password authentication method. + * + * This function sets the password for the given user. + * + * @param[in] password Cleartext user's password. + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, it's 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_ssh_new_client_auth_password(const char *password, const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a client, which supports the none authentication method. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, it's 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_ssh_new_client_auth_none(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a client, which supports the interactive authentication method. + * + * @param[in] pam_config_name Name of the PAM configuration file. + * @param[in] pam_config_name Optional. The absolute path to the directory in which the configuration file + * with the name conf_name is located. A newer version (>= 1.4) of PAM library is required to be able to specify + * the path. If NULL is passed, then the PAM's system directories will be searched (usually /etc/pam.d/). + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, it's 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_ssh_new_client_auth_interactive(const char *pam_config_name, const char *pam_config_dir, + const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config); + #ifdef __cplusplus } #endif diff --git a/tests/test_config_new.c b/tests/test_config_new.c index 0b10c1bb..03c60984 100644 --- a/tests/test_config_new.c +++ b/tests/test_config_new.c @@ -93,12 +93,10 @@ client_thread_pubkey(void *arg) ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); - ret = nc_client_ssh_set_username("test_config_new_openssh"); + ret = nc_client_ssh_set_username("test"); assert_int_equal(ret, 0); nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); assert_int_equal(ret, 0); @@ -166,7 +164,7 @@ setup_f(void **state) ret = nc_server_config_ssh_new_host_key_algs(ctx, "endpt", &tree, 1, "rsa-sha2-512"); assert_int_equal(ret, 0); - ret = nc_server_config_ssh_new_user(TESTS_DIR "/data/key_rsa.pub", ctx, "endpt", "test_config_new_openssh", "pubkey", &tree); + ret = nc_server_config_ssh_new_client_auth_pubkey(TESTS_DIR "/data/key_rsa.pub", ctx, "endpt", "test", "pubkey", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ From 1a5dc4f7baa2be2a9f8c797ad0d9d81f3a9736cb Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 24 Mar 2023 15:53:12 +0100 Subject: [PATCH 009/134] server ssh UPDATE require all set auth methods Clients now have to authenticate via all of their configured SSH authentication method as specified by the ietf-netconf-server module. --- src/session_p.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/session_p.h b/src/session_p.h index e75dc346..8e95a04d 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -128,6 +128,11 @@ struct nc_keystore { uint16_t sym_key_count; }; +struct nc_auth_state { + int auth_method_count; + int auth_success_count; +}; + struct nc_client_auth { char *username; @@ -871,9 +876,10 @@ int nc_accept_ssh_session(struct nc_session *session, struct nc_server_ssh_opts * @param[in] session Session structure of the connection. * @param[in] opts Endpoint SSH options on which the session was created. * @param[in] msg SSH message itself. + * @param[in] state State of the authentication. * @return 0 if the message was handled, 1 if it is left up to libssh. */ -int nc_session_ssh_msg(struct nc_session *session, struct nc_server_ssh_opts *opts, ssh_message msg); +int nc_session_ssh_msg(struct nc_session *session, struct nc_server_ssh_opts *opts, ssh_message msg, struct nc_auth_state *state); void nc_server_ssh_clear_opts(struct nc_server_ssh_opts *opts); From dc388afcb092222f66f8d3ca39165eb38a5d160f Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 31 Mar 2023 10:11:10 +0200 Subject: [PATCH 010/134] configuration UPDATE headers reorganized config_new now made an internal header, server_config added to installed ones. Includes reworked. --- CMakeLists.txt | 6 +- src/config_new.h | 178 ++------------------------------------ src/server_config.h | 176 +++++++++++++++++++++++++++++++++++-- src/session_server.c | 1 + tests/config.h.in | 13 +++ tests/test_auth.c | 12 +-- tests/test_config_new.c | 46 ++++++---- tests/test_keystore.c | 10 +-- tests/test_two_channels.c | 11 +-- tests/test_unix_socket.c | 10 +-- 10 files changed, 235 insertions(+), 228 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0758aa78..e20d2907 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,8 +139,7 @@ set(headers src/session_client_ch.h src/session_server.h src/session_server_ch.h - src/server_config.h - src/config_new.h) + src/server_config.h) # files to generate doxygen from set(doxy_files @@ -153,7 +152,8 @@ set(doxy_files src/session_client.h src/session_client_ch.h src/session_server.h - src/session_server_ch.h) + src/session_server_ch.h + src/server_config.h) # source files to be covered by the 'format' target set(format_sources diff --git a/src/config_new.h b/src/config_new.h index cccda4dd..bbaab142 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -18,6 +18,8 @@ #include +#include "session_p.h" + #ifdef __cplusplus extern "C" { #endif @@ -30,181 +32,17 @@ typedef enum { } NC_ALG_TYPE; /** - * @brief Creates new YANG configuration data nodes for a hostkey. - * - * @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] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's hostkey might be changed. - * @param[in] hostkey_name Arbitrary identifier of the hostkey. - * If a hostkey with this identifier already exists, it's 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_ssh_new_hostkey(const char *privkey_path, const char *pubkey_path, const struct ly_ctx *ctx, - const char *endpt_name, const char *hostkey_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a local-address and local-port. - * - * @param[in] address New listening address. - * @param[in] port New listening port. - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's address and port will be overriden. - * @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_ssh_new_address_port(const char *address, const char *port, const struct ly_ctx *ctx, - const char *endpt_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for host-key algorithms replacing any previous ones. - * - * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, - * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's host-key algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_ssh_new_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); - -/** - * @brief Creates new YANG configuration data nodes for key exchange algorithms replacing any previous ones. - * - * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, - * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, - * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's key exchange algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); - -/** - * @brief Creates new YANG configuration data nodes for encryption algorithms replacing any previous ones. - * - * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc - * triple-des-cbc and none. + * @brief Configures the listen subtree in the ietf-netconf-server module. * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's encryption algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. + * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. + * @return 0 on success, 1 on error. */ -int nc_server_config_ssh_new_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); +int nc_server_config_listen(NC_OPERATION op); /** - * @brief Creates new YANG configuration data nodes for mac algorithms replacing any previous ones. - * - * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's mac algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of mac algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); - -/** - * @brief Creates new YANG configuration data nodes for a client, which supports the public key authentication method. - * - * @param[in] pubkey_path Path to a file containing the user's public key. - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's user might be changed. - * @param[in] user_name Arbitrary identifier of the user. - * If an user with this identifier already exists, it's 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, it's 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_ssh_new_client_auth_pubkey(const char *pubkey_path, const struct ly_ctx *ctx, 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 client, which supports the password authentication method. - * - * This function sets the password for the given user. - * - * @param[in] password Cleartext user's password. - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's user might be changed. - * @param[in] user_name Arbitrary identifier of the user. - * If an user with this identifier already exists, it's 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_ssh_new_client_auth_password(const char *password, const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a client, which supports the none authentication method. - * - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's user might be changed. - * @param[in] user_name Arbitrary identifier of the user. - * If an user with this identifier already exists, it's 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_ssh_new_client_auth_none(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a client, which supports the interactive authentication method. - * - * @param[in] pam_config_name Name of the PAM configuration file. - * @param[in] pam_config_name Optional. The absolute path to the directory in which the configuration file - * with the name conf_name is located. A newer version (>= 1.4) of PAM library is required to be able to specify - * the path. If NULL is passed, then the PAM's system directories will be searched (usually /etc/pam.d/). - * @param[in] ctx libyang context. - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's user might be changed. - * @param[in] user_name Arbitrary identifier of the user. - * If an user with this identifier already exists, it's 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 Deletes every key stored in the keystore. */ -int nc_server_config_ssh_new_client_auth_interactive(const char *pam_config_name, const char *pam_config_dir, - const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config); +void nc_server_config_del_keystore(void); #ifdef __cplusplus } diff --git a/src/server_config.h b/src/server_config.h index 189431b5..3af4772c 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -69,17 +69,181 @@ int nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path); int nc_server_config_load_modules(struct ly_ctx **ctx); /** - * @brief Configures the listen subtree in the ietf-netconf-server module. + * @brief Creates new YANG configuration data nodes for a hostkey. * - * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. - * @return 0 on success, 1 on error. + * @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] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's hostkey might be changed. + * @param[in] hostkey_name Arbitrary identifier of the hostkey. + * If a hostkey with this identifier already exists, it's 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_ssh_new_hostkey(const char *privkey_path, const char *pubkey_path, const struct ly_ctx *ctx, + const char *endpt_name, const char *hostkey_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a local-address and local-port. + * + * @param[in] address New listening address. + * @param[in] port New listening port. + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's address and port will be overriden. + * @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_ssh_new_address_port(const char *address, const char *port, const struct ly_ctx *ctx, + const char *endpt_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for host-key algorithms replacing any previous ones. + * + * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, + * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's host-key algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. */ -int nc_server_config_listen(NC_OPERATION op); +int nc_server_config_ssh_new_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); /** - * @brief Deletes every key stored in the keystore. + * @brief Creates new YANG configuration data nodes for key exchange algorithms replacing any previous ones. + * + * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, + * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, + * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's key exchange algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +/** + * @brief Creates new YANG configuration data nodes for encryption algorithms replacing any previous ones. + * + * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc + * triple-des-cbc and none. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's encryption algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_ssh_new_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +/** + * @brief Creates new YANG configuration data nodes for mac algorithms replacing any previous ones. + * + * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's mac algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of mac algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +/** + * @brief Creates new YANG configuration data nodes for a client, which supports the public key authentication method. + * + * @param[in] pubkey_path Path to a file containing the user's public key. + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, it's 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, it's 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_ssh_new_client_auth_pubkey(const char *pubkey_path, const struct ly_ctx *ctx, 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 client, which supports the password authentication method. + * + * This function sets the password for the given user. + * + * @param[in] password Cleartext user's password. + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, it's 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_ssh_new_client_auth_password(const char *password, const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a client, which supports the none authentication method. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, it's 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_ssh_new_client_auth_none(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a client, which supports the interactive authentication method. + * + * @param[in] pam_config_name Name of the PAM configuration file. + * @param[in] pam_config_name Optional. The absolute path to the directory in which the configuration file + * with the name conf_name is located. A newer version (>= 1.4) of PAM library is required to be able to specify + * the path. If NULL is passed, then the PAM's system directories will be searched (usually /etc/pam.d/). + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, it's 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. */ -void nc_server_config_del_keystore(void); +int nc_server_config_ssh_new_client_auth_interactive(const char *pam_config_name, const char *pam_config_dir, + const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config); #ifdef __cplusplus } diff --git a/src/session_server.c b/src/session_server.c index e0514e68..cd583cda 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -35,6 +35,7 @@ #include #include "compat.h" +#include "config_new.h" #include "libnetconf.h" #include "session_server.h" #include "session_server_ch.h" diff --git a/tests/config.h.in b/tests/config.h.in index cf58c40c..79b5f573 100644 --- a/tests/config.h.in +++ b/tests/config.h.in @@ -24,3 +24,16 @@ @SSH_MACRO@ @TLS_MACRO@ + +/* nc_server.h local includes (not to use the installed ones) */ +#include "netconf.h" +#include "log.h" +#include "messages_server.h" +#include "server_config.h" +#include "session_server.h" +#include "session_server_ch.h" + +/* nc_client.h local includes (not to use the installed ones) */ +#include "messages_client.h" +#include "session_client.h" +#include "session_client_ch.h" diff --git a/tests/test_auth.c b/tests/test_auth.c index c6bfae99..63d75474 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -13,22 +13,18 @@ * https://opensource.org/licenses/BSD-3-Clause */ +#define _GNU_SOURCE + #include #include #include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include - #include "tests/config.h" #define NC_ACCEPT_TIMEOUT 2000 @@ -231,7 +227,7 @@ auth_password(const char *username, const char *hostname, void *priv) (void) hostname; (void) priv; - /* send the replies to keyboard-interactive authentication */ + /* set the reply to password authentication */ if (!strcmp(username, "test_pw")) { return strdup("testpw"); } else { diff --git a/tests/test_config_new.c b/tests/test_config_new.c index 03c60984..42e8ded0 100644 --- a/tests/test_config_new.c +++ b/tests/test_config_new.c @@ -13,7 +13,8 @@ * https://opensource.org/licenses/BSD-3-Clause */ -#include +#define _GNU_SOURCE + #include #include #include @@ -22,14 +23,6 @@ #include -#include -#include -#include -#include -#include -#include -#include "config_new.h" - #include "tests/config.h" #define NC_ACCEPT_TIMEOUT 2000 @@ -83,8 +76,19 @@ ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) return 0; } +static char * +auth_password(const char *username, const char *hostname, void *priv) +{ + (void) username; + (void) hostname; + (void) priv; + + /* set the reply to password authentication */ + return strdup("testpassword123"); +} + static void * -client_thread_pubkey(void *arg) +client_thread(void *arg) { int ret; struct nc_session *session = NULL; @@ -93,13 +97,10 @@ client_thread_pubkey(void *arg) ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); - ret = nc_client_ssh_set_username("test"); + ret = nc_client_ssh_set_username("client"); assert_int_equal(ret, 0); - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); - - ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); - assert_int_equal(ret, 0); + nc_client_ssh_set_auth_password_clb(auth_password, NULL); pthread_barrier_wait(&state->barrier); session = nc_connect_ssh("127.0.0.1", 10005, NULL); @@ -111,14 +112,14 @@ client_thread_pubkey(void *arg) } static void -test_nc_auth_pubkey(void **state) +test_nc_config_new(void **state) { int ret, i; pthread_t tids[2]; assert_non_null(state); - ret = pthread_create(&tids[0], NULL, client_thread_pubkey, *state); + ret = pthread_create(&tids[0], NULL, client_thread, *state); assert_int_equal(ret, 0); ret = pthread_create(&tids[1], NULL, server_thread, *state); assert_int_equal(ret, 0); @@ -146,25 +147,32 @@ setup_f(void **state) *state = test_state; + /* new context */ ret = ly_ctx_new(MODULES_DIR, 0, &ctx); assert_int_equal(ret, 0); + /* initialize the context by loading default modules */ ret = nc_server_init_ctx(&ctx); assert_int_equal(ret, 0); + /* load ietf-netconf-server module and it's imports */ ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); + /* create new hostkey data */ ret = nc_server_config_ssh_new_hostkey(TESTS_DIR "/data/server.key", NULL, ctx, "endpt", "hostkey", &tree); assert_int_equal(ret, 0); + /* create new address and port data */ ret = nc_server_config_ssh_new_address_port("127.0.0.1", "10005", ctx, "endpt", &tree); assert_int_equal(ret, 0); + /* create the host-key algorithms data */ ret = nc_server_config_ssh_new_host_key_algs(ctx, "endpt", &tree, 1, "rsa-sha2-512"); assert_int_equal(ret, 0); - ret = nc_server_config_ssh_new_client_auth_pubkey(TESTS_DIR "/data/key_rsa.pub", ctx, "endpt", "test", "pubkey", &tree); + /* create the client authentication data, password only */ + ret = nc_server_config_ssh_new_client_auth_password("testpassword123", ctx, "endpt", "client", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ @@ -209,7 +217,7 @@ int main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_nc_auth_pubkey, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_config_new, setup_f, teardown_f), }; setenv("CMOCKA_TEST_ABORT", "1", 1); diff --git a/tests/test_keystore.c b/tests/test_keystore.c index 7c20577a..8b966b0a 100644 --- a/tests/test_keystore.c +++ b/tests/test_keystore.c @@ -13,22 +13,18 @@ * https://opensource.org/licenses/BSD-3-Clause */ +#define _GNU_SOURCE + #include #include #include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include - #include "tests/config.h" #define NC_ACCEPT_TIMEOUT 2000 diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c index fb85bbf9..8c24a690 100644 --- a/tests/test_two_channels.c +++ b/tests/test_two_channels.c @@ -12,24 +12,19 @@ * * https://opensource.org/licenses/BSD-3-Clause */ +#define _GNU_SOURCE #include #include -#include #include +#include #include #include #include +#include #include -#include -#include -#include -#include -#include -#include - #include "tests/config.h" #define NC_ACCEPT_TIMEOUT 2000 diff --git a/tests/test_unix_socket.c b/tests/test_unix_socket.c index e698e7be..e1069821 100644 --- a/tests/test_unix_socket.c +++ b/tests/test_unix_socket.c @@ -13,22 +13,18 @@ * https://opensource.org/licenses/BSD-3-Clause */ +#define _GNU_SOURCE + #include #include #include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include - #include "tests/config.h" #define NC_ACCEPT_TIMEOUT 2000 From 68a8cdad1906a190f23d93920bd6bf85fced0591 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 31 Mar 2023 13:25:48 +0200 Subject: [PATCH 011/134] configuration REFACTOR struct names and defs + doc --- src/server_config.c | 44 ++++++------ src/session_p.h | 171 ++++++++++++++++++++++++++------------------ 2 files changed, 124 insertions(+), 91 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index f11d2899..eaedeb56 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -196,7 +196,7 @@ nc_server_get_auth_client(const struct lyd_node *node, const struct nc_server_ss * @return 0 on success, 1 on error. */ static int -nc_server_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_client_auth_pubkey **pubkey) +nc_server_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_public_key **pubkey) { uint16_t i; const char *pubkey_name; @@ -296,8 +296,8 @@ nc_server_del_hostkey_name(struct nc_hostkey *hostkey) static void nc_server_del_public_key(struct nc_hostkey *hostkey) { - free(hostkey->pub_base64); - hostkey->pub_base64 = NULL; + free(hostkey->key.pub_base64); + hostkey->key.pub_base64 = NULL; } static void @@ -310,8 +310,8 @@ nc_server_del_truststore_reference(struct nc_client_auth *client_auth) static void nc_server_del_private_key(struct nc_hostkey *hostkey) { - free(hostkey->priv_base64); - hostkey->priv_base64 = NULL; + free(hostkey->key.priv_base64); + hostkey->key.priv_base64 = NULL; } static void @@ -322,14 +322,14 @@ nc_server_del_auth_client_username(struct nc_client_auth *auth_client) } static void -nc_server_del_auth_client_pubkey_name(struct nc_client_auth_pubkey *pubkey) +nc_server_del_auth_client_pubkey_name(struct nc_public_key *pubkey) { free(pubkey->name); pubkey->name = NULL; } static void -nc_server_del_auth_client_pubkey_pub_base64(struct nc_client_auth_pubkey *pubkey) +nc_server_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey) { free(pubkey->pub_base64); pubkey->pub_base64 = NULL; @@ -396,7 +396,7 @@ nc_server_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostke } static void -nc_server_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_client_auth_pubkey *pubkey) +nc_server_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_public_key *pubkey) { nc_server_del_auth_client_pubkey_name(pubkey); nc_server_del_auth_client_pubkey_pub_base64(pubkey); @@ -1056,7 +1056,7 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) const char *format; struct nc_endpt *endpt; struct nc_client_auth *auth_client; - struct nc_client_auth_pubkey *pubkey; + struct nc_public_key *pubkey; struct nc_hostkey *hostkey; int ret = 0; @@ -1102,9 +1102,9 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { if (!strcmp(format, "ssh-public-key-format")) { - hostkey->pubkey_type = NC_SSH_PUBKEY_SSH2; + hostkey->key.pubkey_type = NC_SSH_PUBKEY_SSH2; } else if (!strcmp(format, "subject-public-key-info-format")) { - hostkey->pubkey_type = NC_SSH_PUBKEY_X509; + hostkey->key.pubkey_type = NC_SSH_PUBKEY_X509; } else { ERR(NULL, "Public key format (%s) not supported.", format); } @@ -1139,9 +1139,9 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op format = ((struct lyd_node_term *)node)->value.ident->name; if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { if (!strcmp(format, "rsa-private-key-format")) { - hostkey->privkey_type = NC_SSH_KEY_RSA; + hostkey->key.privkey_type = NC_SSH_KEY_RSA; } else if (!strcmp(format, "ec-private-key-format")) { - hostkey->privkey_type = NC_SSH_KEY_ECDSA; + hostkey->key.privkey_type = NC_SSH_KEY_ECDSA; } else { ERR(NULL, "Private key format (%s) not supported.", format); } @@ -1155,8 +1155,8 @@ static int nc_server_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey) { nc_server_del_private_key(hostkey); - hostkey->priv_base64 = strdup(lyd_get_value(node)); - if (!hostkey->priv_base64) { + hostkey->key.priv_base64 = strdup(lyd_get_value(node)); + if (!hostkey->key.priv_base64) { ERRMEM; return 1; } @@ -1289,7 +1289,7 @@ nc_server_create_auth_key_public_key_list(const struct lyd_node *node, struct nc } static int -nc_server_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_client_auth_pubkey *pubkey) +nc_server_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey) { nc_server_del_auth_client_pubkey_pub_base64(pubkey); @@ -1307,8 +1307,8 @@ nc_server_replace_host_key_public_key(const struct lyd_node *node, struct nc_hos { nc_server_del_public_key(hostkey); - hostkey->pub_base64 = strdup(lyd_get_value(node)); - if (!hostkey->pub_base64) { + hostkey->key.pub_base64 = strdup(lyd_get_value(node)); + if (!hostkey->key.pub_base64) { ERRMEM; return 1; } @@ -1322,7 +1322,7 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) struct nc_endpt *endpt; struct nc_hostkey *hostkey; struct nc_client_auth *auth_client; - struct nc_client_auth_pubkey *pubkey; + struct nc_public_key *pubkey; int ret = 0; assert(!strcmp(LYD_NAME(node), "public-key")); @@ -2227,7 +2227,7 @@ nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op } static int -nc_server_config_asymmetric_key_certificate(const struct lyd_node *tree, struct nc_ks_asym_key *key) +nc_server_config_asymmetric_key_certificate(const struct lyd_node *tree, struct nc_asymmetric_key *key) { int ret = 0; struct lyd_node *node; @@ -2276,7 +2276,7 @@ nc_server_config_asymmetric_key(const struct lyd_node *tree) struct lyd_node *node = NULL, *iter; void *tmp; struct nc_keystore *ks = &server_opts.keystore; - struct nc_ks_asym_key *key; + struct nc_asymmetric_key *key; const char *format; /* create new asymmetric key */ @@ -2383,7 +2383,7 @@ nc_server_config_symmetric_key(const struct lyd_node *tree) const char *format; struct lyd_node *node; struct nc_keystore *ks = &server_opts.keystore; - struct nc_ks_sym_key *key; + struct nc_symmetric_key *key; void *tmp; /* create new symmetric key */ diff --git a/src/session_p.h b/src/session_p.h index 8e95a04d..899f9d13 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -101,90 +101,116 @@ struct nc_client_ssh_opts { char *username; }; +/** + * @brief A basic certificate. + */ struct nc_certificate { - char *name; - char *cert_data; + char *name; /**< Arbitrary name of the certificate. */ + char *cert_base64; /**< Base-64 encoded certificate. */ +}; + +/** + * @brief An asymmetric key. + */ +struct nc_asymmetric_key { + char *name; /**< Arbitrary name of the key. */ + + NC_SSH_PUBKEY_TYPE pubkey_type; /**< Type of the public key. */ + char *pub_base64; /**< Base-64 encoded public key. */ + NC_SSH_KEY_TYPE privkey_type; /**< Type of the private key. */ + char *priv_base64; /**< Base-64 encoded private key. */ + + struct nc_certificate *certs; /**< The certificates associated with this key. */ + uint16_t cert_count; /**< Number of certificates associated with this key. */ +}; + +/** + * @brief A symmetric key. + */ +struct nc_symmetric_key { + char *name; /**< Arbitrary name of the key. */ + char *base64; /**< Base-64 encoded key. */ +}; + +/** + * @brief A public key. + */ +struct nc_public_key { + char *name; /**< Arbitrary name of the public key. */ + NC_SSH_PUBKEY_TYPE pubkey_type; /**< Type of the public key. */ + char *pub_base64; /**< Base-64 encoded public key. */ }; +/** + * @brief Keystore YANG module representation. + */ struct nc_keystore { - struct nc_ks_asym_key { - char *name; - NC_SSH_PUBKEY_TYPE pubkey_type; - char *pub_base64; - NC_SSH_KEY_TYPE privkey_type; - char *priv_base64; - struct { - char *name; - char *cert_base64; - } *certs; - uint16_t cert_count; - } *asym_keys; - uint16_t asym_key_count; + struct nc_asymmetric_key *asym_keys; /**< Stored asymmetric keys. */ + uint16_t asym_key_count; /**< Count of stored asymmetric keys. */ - struct nc_ks_sym_key { - char *name; - char *base64; - } *sym_keys; - uint16_t sym_key_count; + struct nc_symmetric_key *sym_keys; /**< Stored symmetric keys. */ + uint16_t sym_key_count; /**< Count of stored symmetric keys. */ }; +/** + * @brief Tracks the state of a client's authentication. + */ struct nc_auth_state { - int auth_method_count; - int auth_success_count; + int auth_method_count; /**< The number of auth. methods that the user supports. */ + int auth_success_count; /**< The number of auth. methods that ended successfully. */ }; +/** + * @brief A server's authorized client. + */ struct nc_client_auth { - char *username; + char *username; /**< Arbitrary username. */ - NC_STORE_TYPE ks_type; + NC_STORE_TYPE ks_type; /**< Specifies how/where the client's public key is stored. */ union { struct { - struct nc_client_auth_pubkey { - char *name; - NC_SSH_PUBKEY_TYPE pubkey_type; - char *pub_base64; - } *pubkeys; - uint16_t pubkey_count; + struct nc_public_key *pubkeys; /**< The client's public keys. */ + uint16_t pubkey_count; /**< The number of client's public keys. */ }; - char *ts_reference; + char *ts_reference; /**< Reference to a trust-store. */ }; - char *password; - char *pam_config_name; - char *pam_config_dir; - int supports_none; + char *password; /**< Client's password */ + char *pam_config_name; /**< Client's PAM configuration file name. */ + char *pam_config_dir; /**< Client's PAM configuration file directory. */ + int supports_none; /**< Implies that the client supports the none authentication method. */ }; +/** + * @brief The server's hostkey. + */ struct nc_hostkey { - char *name; + char *name; /**< Arbitrary name of the host key. */ - NC_STORE_TYPE ks_type; + NC_STORE_TYPE ks_type; /**< Specifies how/where the key is stored. */ union { - struct { - NC_SSH_PUBKEY_TYPE pubkey_type; - char *pub_base64; - NC_SSH_KEY_TYPE privkey_type; - char *priv_base64; - }; - struct nc_ks_asym_key *ks_ref; + struct nc_asymmetric_key key; /**< The server's hostkey. */ + struct nc_asymmetric_key *ks_ref; /**< Reference to a key-store. */ }; }; -/* ACCESS locked, separate locks */ +/** + * @brief Server options for configuring the SSH transport protocol. + */ struct nc_server_ssh_opts { - struct nc_hostkey *hostkeys; /* everything in ks */ - uint16_t hostkey_count; + struct nc_hostkey *hostkeys; /**< Server's hostkeys. */ + uint16_t hostkey_count; /**< Number of server's hostkeys. */ - struct nc_client_auth *auth_clients; - uint16_t client_count; + struct nc_client_auth *auth_clients; /**< Server's authorized clients. */ + uint16_t client_count; /**< Number of server's authorized clients. */ - char *hostkey_algs; - char *encryption_algs; - char *kex_algs; - char *mac_algs; + char *hostkey_algs; /**< Hostkey algorithms supported by the server. */ + char *encryption_algs; /**< Encryption algorithms supported by the server. */ + char *kex_algs; /**< Key exchange algorithms supported by the server. */ + char *mac_algs; /**< MAC algorithms supported by the server. */ - uint16_t auth_attempts; - uint16_t auth_timeout; + uint16_t auth_attempts; /**< Number of allowed authentication attempts. */ + uint16_t auth_timeout; /**< Authentication timeout. */ }; #endif /* NC_ENABLED_SSH */ @@ -229,27 +255,34 @@ struct nc_server_tls_opts { #endif /* NC_ENABLED_TLS */ -/* ACCESS unlocked */ +/** + * @brief Keepalives configuration data. + */ struct nc_keepalives { - int enabled; - uint16_t idle_time; - uint16_t max_probes; - uint16_t probe_interval; + int enabled; /**< Indicates that keepalives are enabled. */ + uint16_t idle_time; /**< Idle timeout. */ + uint16_t max_probes; /**< Maximum number of probes. */ + uint16_t probe_interval; /**< Probe interval. */ }; -/* ACCESS unlocked */ +/** + * @brief UNIX socket connection configuration. + */ struct nc_server_unix_opts { - char *address; - mode_t mode; - uid_t uid; - gid_t gid; + char *address; /**< Address of the socket. */ + mode_t mode; /**< Socket's mode. */ + uid_t uid; /**< Socket's uid. */ + gid_t gid; /**< Socket's gid. */ }; +/** + * @brief Stores information about a bind. + */ struct nc_bind { - char *address; - uint16_t port; - int sock; - int pollin; + char *address; /**< Bind's address. */ + uint16_t port; /**< Bind's port. */ + int sock; /**< Bind's socket. */ + int pollin; /**< Specifies, which sockets to poll on. */ }; /* ACCESS unlocked */ From 329305559287e333288cd70180d5c44e8de538c3 Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 5 Apr 2023 11:26:25 +0200 Subject: [PATCH 012/134] configuration UPDATE truststore support added Client's keys can now be stored in the truststore module and used for the SSH authentication. --- src/config_new.h | 7 +- src/server_config.c | 355 ++++++++++++++++++++++++++++++++++++---- src/session_p.h | 25 ++- tests/CMakeLists.txt | 2 +- tests/test_truststore.c | 280 +++++++++++++++++++++++++++++++ 5 files changed, 637 insertions(+), 32 deletions(-) create mode 100644 tests/test_truststore.c diff --git a/src/config_new.h b/src/config_new.h index bbaab142..457be852 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -40,10 +40,15 @@ typedef enum { int nc_server_config_listen(NC_OPERATION op); /** - * @brief Deletes every key stored in the keystore. + * @brief Deletes everything stored in the keystore. */ void nc_server_config_del_keystore(void); +/** + * @brief Deletes everything stored in the truststore. + */ +void nc_server_config_del_trustore(void); + #ifdef __cplusplus } #endif diff --git a/src/server_config.c b/src/server_config.c index eaedeb56..929209e8 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -300,13 +300,6 @@ nc_server_del_public_key(struct nc_hostkey *hostkey) hostkey->key.pub_base64 = NULL; } -static void -nc_server_del_truststore_reference(struct nc_client_auth *client_auth) -{ - free(client_auth->ts_reference); - client_auth->ts_reference = NULL; -} - static void nc_server_del_private_key(struct nc_hostkey *hostkey) { @@ -335,13 +328,6 @@ nc_server_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey) pubkey->pub_base64 = NULL; } -static void -nc_server_del_auth_client_ts_reference(struct nc_client_auth *auth_client) -{ - free(auth_client->ts_reference); - auth_client->ts_reference = NULL; -} - static void nc_server_del_auth_client_password(struct nc_client_auth *auth_client) { @@ -418,10 +404,6 @@ nc_server_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth for (i = 0; i < pubkey_count; i++) { nc_server_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]); } - } else if (auth_client->ks_type == NC_STORE_TRUSTSTORE) { - nc_server_del_auth_client_ts_reference(auth_client); - } else { - return; } nc_server_del_auth_client_password(auth_client); @@ -528,9 +510,11 @@ nc_server_config_del_keystore(void) free(ks->asym_keys[i].certs[j].cert_base64); } free(ks->asym_keys[i].certs); + ks->asym_keys[i].certs = NULL; ks->asym_keys[i].cert_count = 0; } free(ks->asym_keys); + ks->asym_keys = NULL; ks->asym_key_count = 0; /* delete all symmetric keys */ @@ -539,9 +523,49 @@ nc_server_config_del_keystore(void) free(ks->sym_keys[i].base64); } free(ks->sym_keys); + ks->sym_keys = NULL; ks->sym_key_count = 0; } +void +nc_server_config_del_trustore(void) +{ + int i, j; + struct nc_truststore *ts = &server_opts.truststore; + + /* delete all cert bags */ + for (i = 0; i < ts->cert_bag_count; i++) { + free(ts->cert_bags[i].name); + for (j = 0; j < ts->cert_bags[i].cert_count; j++) { + /* free associated certificates */ + free(ts->cert_bags[i].certs[j].name); + free(ts->cert_bags[i].certs[j].cert_base64); + } + free(ts->cert_bags[i].certs); + ts->cert_bags[i].certs = NULL; + ts->cert_bags[i].cert_count = 0; + } + free(ts->cert_bags); + ts->cert_bags = NULL; + ts->cert_bag_count = 0; + + /* delete all pubkey bags */ + for (i = 0; i < ts->pub_bag_count; i++) { + free(ts->pub_bags[i].name); + for (j = 0; j < ts->pub_bags[i].pubkey_count; j++) { + /* free associated pubkeys */ + free(ts->pub_bags[i].pubkeys[j].name); + free(ts->pub_bags[i].pubkeys[j].pub_base64); + } + free(ts->pub_bags[i].pubkeys); + ts->pub_bags[i].pubkeys = NULL; + ts->pub_bags[i].pubkey_count = 0; + } + free(ts->pub_bags); + ts->pub_bags = NULL; + ts->pub_bag_count = 0; +} + /* presence container */ int nc_server_config_listen(NC_OPERATION op) @@ -1525,15 +1549,23 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) static int nc_server_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth) { - /*todo*/ - nc_server_del_truststore_reference(client_auth); + uint16_t i; + struct nc_truststore *ts = &server_opts.truststore; - client_auth->ts_reference = strdup(lyd_get_value(node)); - if (!client_auth->ts_reference) { - ERRMEM; + /* lookup name */ + for (i = 0; i < ts->pub_bag_count; i++) { + if (!strcmp(lyd_get_value(node), ts->pub_bags[i].name)) { + break; + } + } + + if (i == ts->pub_bag_count) { + ERR(NULL, "Truststore \"%s\" not found.", lyd_get_value(node)); return 1; } + client_auth->ts_ref = &ts->pub_bags[i]; + return 0; } @@ -1564,7 +1596,7 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION goto cleanup; } } else { - nc_server_del_truststore_reference(auth_client); + auth_client->ts_ref = NULL; } } @@ -2308,9 +2340,9 @@ nc_server_config_asymmetric_key(const struct lyd_node *tree) format = ((struct lyd_node_term *)node)->value.ident->name; if (!strcmp(format, "ssh-public-key-format")) { - key->pubkey_type = NC_SSH_PUBKEY_X509; - } else if (!strcmp(format, "subject-public-key-info-format")) { key->pubkey_type = NC_SSH_PUBKEY_SSH2; + } else if (!strcmp(format, "subject-public-key-info-format")) { + key->pubkey_type = NC_SSH_PUBKEY_X509; } else { ERR(NULL, "Public key format \"%s\" not supported.", format); ret = 1; @@ -2388,7 +2420,7 @@ nc_server_config_symmetric_key(const struct lyd_node *tree) /* create new symmetric key */ tmp = realloc(ks->sym_keys, (ks->sym_key_count + 1) * sizeof *ks->sym_keys); - if (tmp) { + if (!tmp) { ERRMEM; ret = 1; goto cleanup; @@ -2446,7 +2478,7 @@ nc_fill_keystore(const struct lyd_node *data) ret = lyd_find_path(data, "/ietf-keystore:keystore", 0, &tree); if (ret) { - WRN(NULL, "Keystore container not found in the YANG data."); + VRB(NULL, "Keystore container not found in the YANG data."); ret = 0; goto cleanup; } @@ -2487,6 +2519,267 @@ nc_fill_keystore(const struct lyd_node *data) return ret; } +static int +nc_server_config_create_truststore_certificate(const struct lyd_node *tree, struct nc_certificate_bag *bag) +{ + int ret = 0; + struct lyd_node *node; + void *tmp; + struct nc_certificate *cert; + + /* create new certificate */ + tmp = realloc(bag->certs, (bag->cert_count + 1) * sizeof *bag->certs); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + memset(&bag->certs[bag->cert_count], 0, sizeof *bag->certs); + bag->certs = tmp; + cert = &bag->certs[bag->cert_count]; + bag->cert_count++; + + /* set name */ + lyd_find_path(tree, "name", 0, &node); + assert(node); + + cert->name = strdup(lyd_get_value(node)); + if (!cert->name) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* set cert data */ + lyd_find_path(tree, "cert-data", 0, &node); + assert(node); + + cert->cert_base64 = strdup(lyd_get_value(node)); + if (!cert->cert_base64) { + ERRMEM; + ret = 1; + goto cleanup; + } + +cleanup: + return ret; +} + +static int +nc_server_config_certificate_bag(const struct lyd_node *tree) +{ + int ret = 0; + struct lyd_node *node = NULL, *iter; + void *tmp; + struct nc_truststore *ts = &server_opts.truststore; + struct nc_certificate_bag *bag; + + /* create new certificate bag */ + tmp = realloc(ts->cert_bags, (ts->cert_bag_count + 1) * sizeof *ts->cert_bags); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + ts->cert_bags = tmp; + memset(&ts->cert_bags[ts->cert_bag_count], 0, sizeof *ts->cert_bags); + bag = &ts->cert_bags[ts->cert_bag_count]; + ts->cert_bag_count++; + + /* set name */ + lyd_find_path(tree, "name", 0, &node); + assert(node); + + bag->name = strdup(lyd_get_value(node)); + if (!bag->name) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* set certificates associated with this bag */ + ret = lyd_find_path(tree, "certificate", 0, &node); + if (!ret) { + LY_LIST_FOR(node, iter) { + if (nc_server_config_create_truststore_certificate(iter, bag)) { + ret = 1; + goto cleanup; + } + } + } else if (ret == LY_ENOTFOUND) { + /* certificate list not present, but it's ok */ + ret = 0; + } + +cleanup: + return ret; +} + +static int +nc_server_config_create_truststore_public_key(const struct lyd_node *tree, struct nc_public_key_bag *bag) +{ + int ret = 0; + struct lyd_node *node; + void *tmp; + struct nc_public_key *key; + const char *format; + + /* create new public key */ + tmp = realloc(bag->pubkeys, (bag->pubkey_count + 1) * sizeof *bag->pubkeys); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + bag->pubkeys = tmp; + memset(&bag->pubkeys[bag->pubkey_count], 0, sizeof *bag->pubkeys); + key = &bag->pubkeys[bag->pubkey_count]; + bag->pubkey_count++; + + /* set name */ + lyd_find_path(tree, "name", 0, &node); + assert(node); + + key->name = strdup(lyd_get_value(node)); + if (!key->name) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* set public-key-format, mandatory */ + lyd_find_path(tree, "public-key-format", 0, &node); + assert(node); + + format = ((struct lyd_node_term *)node)->value.ident->name; + if (!strcmp(format, "ssh-public-key-format")) { + key->pubkey_type = NC_SSH_PUBKEY_SSH2; + } else if (!strcmp(format, "subject-public-key-info-format")) { + key->pubkey_type = NC_SSH_PUBKEY_X509; + } else { + ERR(NULL, "Public key format \"%s\" not supported.", format); + ret = 1; + goto cleanup; + } + + /* set public key data */ + lyd_find_path(tree, "public-key", 0, &node); + assert(node); + + key->pub_base64 = strdup(lyd_get_value(node)); + if (!key->pub_base64) { + ERRMEM; + ret = 1; + goto cleanup; + } + +cleanup: + return ret; +} + +static int +nc_server_config_public_key_bag(const struct lyd_node *tree) +{ + int ret = 0; + struct lyd_node *node = NULL, *iter; + void *tmp; + struct nc_truststore *ts = &server_opts.truststore; + struct nc_public_key_bag *bag; + const struct lysc_node *schema; + + /* create new public key bag */ + tmp = realloc(ts->pub_bags, (ts->pub_bag_count + 1) * sizeof *ts->pub_bags); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + ts->pub_bags = tmp; + memset(&ts->pub_bags[ts->pub_bag_count], 0, sizeof *ts->pub_bags); + bag = &ts->pub_bags[ts->pub_bag_count]; + ts->pub_bag_count++; + + /* set name */ + lyd_find_path(tree, "name", 0, &node); + assert(node); + + bag->name = strdup(lyd_get_value(node)); + if (!bag->name) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* get the schema node of public key so we can iterate over it's list */ + schema = lys_find_path(NULL, tree->schema, "public-key", 0); + LYD_LIST_FOR_INST(node, schema, iter) { + /* set public keys associated with this bag */ + if (nc_server_config_create_truststore_public_key(iter, bag)) { + ret = 1; + goto cleanup; + } + } + +cleanup: + return ret; +} + +static int +nc_fill_truststore(const struct lyd_node *data) +{ + int ret = 0; + struct lyd_node *tree, *cert_bags, *pub_bags, *iter; + uint32_t prev_lo; + + /* silently search for nodes, some of them may not be present */ + prev_lo = ly_log_options(0); + + ret = lyd_find_path(data, "/ietf-truststore:truststore", 0, &tree); + if (ret) { + VRB(NULL, "Truststore container not found in the YANG data."); + ret = 0; + goto cleanup; + } + + ret = lyd_find_path(tree, "certificate-bags", 0, &cert_bags); + if (!ret) { + /* certificate bags container is present */ + cert_bags = lyd_child(cert_bags); + if (cert_bags && !strcmp(LYD_NAME(cert_bags), "certificate-bag")) { + /* certificate bag list */ + LY_LIST_FOR(cert_bags, iter) { + if (nc_server_config_certificate_bag(iter)) { + ret = 1; + goto cleanup; + } + } + } + } + + ret = lyd_find_path(tree, "public-key-bags", 0, &pub_bags); + if (!ret) { + /* public key bags container is present */ + pub_bags = lyd_child(pub_bags); + if (pub_bags && !strcmp(LYD_NAME(pub_bags), "public-key-bag")) { + /* public key bag list */ + LY_LIST_FOR(pub_bags, iter) { + if (nc_server_config_public_key_bag(iter)) { + ret = 1; + goto cleanup; + } + } + } + } else if (ret == LY_ENOTFOUND) { + /* it's not mandatory so it's ok */ + ret = 0; + } + +cleanup: + /* reset the logging options back to what they were */ + ly_log_options(prev_lo); + return ret; +} + API int nc_server_config_load_modules(struct ly_ctx **ctx) { @@ -2615,6 +2908,12 @@ nc_server_config_setup(const struct lyd_node *data) goto cleanup; } + ret = nc_fill_truststore(data); + if (ret) { + ERR(NULL, "Filling truststore failed."); + goto cleanup; + } + ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree); if (ret) { ERR(NULL, "Unable to find the netconf-server container in the YANG data."); diff --git a/src/session_p.h b/src/session_p.h index 899f9d13..1995d050 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -109,6 +109,12 @@ struct nc_certificate { char *cert_base64; /**< Base-64 encoded certificate. */ }; +struct nc_certificate_bag { + char *name; + struct nc_certificate *certs; + uint16_t cert_count; +}; + /** * @brief An asymmetric key. */ @@ -141,6 +147,20 @@ struct nc_public_key { char *pub_base64; /**< Base-64 encoded public key. */ }; +struct nc_public_key_bag { + char *name; + struct nc_public_key *pubkeys; + uint16_t pubkey_count; +}; + +struct nc_truststore { + struct nc_certificate_bag *cert_bags; + uint16_t cert_bag_count; + + struct nc_public_key_bag *pub_bags; + uint16_t pub_bag_count; +}; + /** * @brief Keystore YANG module representation. */ @@ -172,7 +192,7 @@ struct nc_client_auth { struct nc_public_key *pubkeys; /**< The client's public keys. */ uint16_t pubkey_count; /**< The number of client's public keys. */ }; - char *ts_reference; /**< Reference to a trust-store. */ + struct nc_public_key_bag *ts_ref; /**< Reference to a truststore. */ }; char *password; /**< Client's password */ @@ -370,7 +390,8 @@ struct nc_server_opts { #endif pthread_rwlock_t config_lock; - struct nc_keystore keystore; /**< store for keys/certificates */ + struct nc_keystore keystore; /**< store for server's keys/certificates */ + struct nc_truststore truststore; /**< store for server client's keys/certificates */ struct nc_bind *binds; struct nc_endpt { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index eb413456..ff065dbe 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,7 @@ endif() # list of all the tests in each directory #set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages) -set(tests test_two_channels test_keystore test_unix_socket test_config_new) +set(tests test_two_channels test_keystore test_unix_socket test_config_new test_truststore) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) diff --git a/tests/test_truststore.c b/tests/test_truststore.c new file mode 100644 index 00000000..8d2e0ce5 --- /dev/null +++ b/tests/test_truststore.c @@ -0,0 +1,280 @@ +/** + * @file test_truststore.c + * @author Roman Janota + * @brief libnetconf2 Truststore configuration and authentication test. + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 + +struct ly_ctx *ctx; + +struct test_state { + pthread_barrier_t barrier; +}; + +const char *data = + "\n" + " \n" + " 10\n" + " \n" + " default-ssh\n" + " \n" + " \n" + " 127.0.0.1\n" + " 10005\n" + " \n" + " \n" + " \n" + " \n" + " key\n" + " \n" + " \n" + " ct:ssh-public-key-format\n" + " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" + " ct:rsa-private-key-format\n" + " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " test_truststore\n" + " \n" + " test_truststore\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " sshpka:rsa-sha2-512\n" + " \n" + " \n" + " sshkea:curve25519-sha256\n" + " \n" + " \n" + " sshea:aes256-ctr\n" + " \n" + " \n" + " sshma:hmac-sha2-512\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n" + "\n" + "\n" + " \n" + " \n" + " test_truststore\n" + " Let's hope this works\n" + " \n" + " pubkey\n" + " ct:ssh-public-key-format\n" + " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" + " \n" + " \n" + " \n" + "\n" +; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_thread_destroy(); + return NULL; +} + +static int +ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) +{ + (void)hostname; + (void)session; + (void)priv; + /* skip the knownhost check */ + + return 0; +} + +static void * +client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + /* set directory where to search for modules */ + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set ssh username */ + ret = nc_client_ssh_set_username("test_truststore"); + assert_int_equal(ret, 0); + + /* add client's key pair */ + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + /* connect */ + session = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_auth_truststore(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + /* create new context */ + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* load default modules into context */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf-netconf-server module and it's imports into context */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* parse yang data */ + ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup(tree); + assert_int_equal(ret, 0); + + /* initialize client */ + nc_client_init(); + + /* initialize server */ + ret = nc_server_init(); + assert_int_equal(ret, 0); + + /* skip the knownhost check */ + nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_auth_truststore, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} From 8c5ddd241f9357588439e11eebabaff8a8a617eb Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 5 Apr 2023 14:46:29 +0200 Subject: [PATCH 013/134] examples UPDATE use new api Example server now uses the new API for SSH connection. Minor bugfix in nc_server_config_ssh_new_address_port. --- examples/client.c | 2 +- examples/config.xml | 119 ++++++++++++++++++++++++++++++++++++++++++ examples/example.h.in | 5 +- examples/server.c | 37 ++++++++++--- src/config_new.c | 3 +- 5 files changed, 155 insertions(+), 11 deletions(-) create mode 100644 examples/config.xml diff --git a/examples/client.c b/examples/client.c index 1ebf11c2..88c38ff8 100644 --- a/examples/client.c +++ b/examples/client.c @@ -196,7 +196,7 @@ main(int argc, char **argv) break; case SSH: - session = nc_connect_ssh(SSH_ADDRESS, SSH_PORT, NULL); + session = nc_connect_ssh(SSH_ADDRESS, atoi(SSH_PORT), NULL); break; case NONE: diff --git a/examples/config.xml b/examples/config.xml new file mode 100644 index 00000000..2bf7598c --- /dev/null +++ b/examples/config.xml @@ -0,0 +1,119 @@ + + + 10 + + default-ssh + + + 127.0.0.1 + 830 + + + + + key + + + ct:ssh-public-key-format + MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr +97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeV +n6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FT +irzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6w +NmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCU +UGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrz +ARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rf +WZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKv +Ya1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3 +u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMa +OQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMh +jufl2qE2Q7fQIaav/1NqBVkCAwEAAQ== + ct:rsa-private-key-format + MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1V +ArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6al +wf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4g +fNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+Zc +zSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+d +KYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FK +tGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo +4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/f +t1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBT +oE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yV +ONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEA +AQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj +1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAH +X8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXB +RgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMk +cjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk +2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rED +MlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5 +R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuar +AhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNt +xZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2Rn +LkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH +/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+U +XA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmG +vWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+ +31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3 +ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRL +ZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7 +YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7v +IQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bf +JAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhg +W4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y +8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFy +fSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+ +N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/b +BY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu +8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SR +q7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu +3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJv +nwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcai +rBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM +3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4S +SBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinb +Tsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW +8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPo +Swr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JB +dOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/K +qDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8T +bstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o= + + + + + + + + admin + $6$xyz$WwFC0nTow5jwJwMYeOZItipYgZidye/O7Z2kxRP3cPttku.GHre0y/51bO2uJlRjQwLNRddSA5fuJG5X1F8Dd1 + + + + client + ct:ssh-public-key-format + AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl + + + + + + + + + sshpka:rsa-sha2-512 + + + sshkea:curve25519-sha256 + + + sshea:aes256-ctr + + + sshma:hmac-sha2-512 + + + + + + + \ No newline at end of file diff --git a/examples/example.h.in b/examples/example.h.in index 5aa11f33..6e214f0b 100644 --- a/examples/example.h.in +++ b/examples/example.h.in @@ -24,11 +24,14 @@ /* directory with examples source code and this header */ #define EXAMPLES_DIR "@CMAKE_SOURCE_DIR@/examples" +/* directory with tests and more importantly test key pairs */ +#define TESTS_DIR "@CMAKE_SOURCE_DIR@/tests" + /* SSH listening IP address */ #define SSH_ADDRESS "127.0.0.1" /* SSH listening port */ -#define SSH_PORT 830 +#define SSH_PORT "830" /* SSH 'password' authentication exptected username and password */ #define SSH_USERNAME "admin" diff --git a/examples/server.c b/examples/server.c index d30dfc87..6c94b8ec 100644 --- a/examples/server.c +++ b/examples/server.c @@ -206,11 +206,12 @@ static int init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_TRANSPORT_IMPL server_type) { int rc = 0; - const char *config_file_path = EXAMPLES_DIR "/config.xml"; + const char *hostkey_path = TESTS_DIR "/data/server.key"; + struct lyd_node *config = NULL; if (path) { /* if a path is supplied, then use it */ - config_file_path = path; + hostkey_path = path; } if (server_type == NC_TI_UNIX) { @@ -235,10 +236,29 @@ init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_T ERR_MSG_CLEANUP("Error loading modules required for configuration of the server.\n"); } - /* parse YANG data from a file, configure the server based on the parsed YANG configuration data */ - rc = nc_server_config_setup_path(*context, config_file_path); + /* this is where the YANG configuration data gets generated, + * start by creating hostkey configuration data */ + rc = nc_server_config_ssh_new_hostkey(hostkey_path, NULL, *context, "endpt", "hostkey", &config); if (rc) { - ERR_MSG_CLEANUP("Error setting the path to the configuration data.\n"); + ERR_MSG_CLEANUP("Error creating new hostkey configuration data.\n"); + } + + /* create address and port configuration data */ + rc = nc_server_config_ssh_new_address_port(SSH_ADDRESS, SSH_PORT, *context, "endpt", &config); + if (rc) { + ERR_MSG_CLEANUP("Error creating new address and port configuration data.\n"); + } + + /* create client authentication configuration data */ + rc = nc_server_config_ssh_new_client_auth_password(SSH_PASSWORD, *context, "endpt", SSH_USERNAME, &config); + if (rc) { + ERR_MSG_CLEANUP("Error creating client authentication configuration data.\n"); + } + + /* apply the created configuration data */ + rc = nc_server_config_setup(config); + if (rc) { + ERR_MSG_CLEANUP("Application of configuration data failed.\n"); } /* initialize the server */ @@ -259,6 +279,7 @@ init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_T signal(SIGINT, sigint_handler); cleanup: + lyd_free_all(config); return rc; } @@ -269,7 +290,7 @@ main(int argc, char **argv) struct ly_ctx *context = NULL; struct nc_session *session, *new_session; struct nc_pollsession *ps = NULL; - const char *unix_socket_path = NULL, *config_file_path = NULL; + const char *unix_socket_path = NULL, *hostkey_path = NULL; struct option options[] = { {"help", no_argument, NULL, 'h'}, @@ -301,8 +322,8 @@ main(int argc, char **argv) break; case 's': - config_file_path = optarg; - if (init(&context, &ps, config_file_path, NC_TI_LIBSSH)) { + hostkey_path = optarg; + if (init(&context, &ps, hostkey_path, NC_TI_LIBSSH)) { ERR_MSG_CLEANUP("Failed to initialize a SSH server\n"); goto cleanup; } diff --git a/src/config_new.c b/src/config_new.c index edf290a5..0224a009 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -336,7 +336,8 @@ nc_server_config_ssh_new_address_port(const char *address, const char *port, con ret = lyd_new_term(new_tree, NULL, "local-port", port, 0, NULL); } - if (ret) { + if (ret && (ret != LY_EEXIST) && (ret != LY_ENOT)) { + /* only fail if there was actually an error */ goto cleanup; } From ac44c175cc6c14a3f315695f5489fface3325bb6 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 14 Apr 2023 09:12:29 +0200 Subject: [PATCH 014/134] server ssh UPDATE print more informative err msg --- src/session_server_ssh.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index c6b744d9..34db6585 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -1859,6 +1859,7 @@ nc_accept_ssh_session(struct nc_session *session, int sock, int timeout) struct nc_server_ssh_opts *opts; int rc = 1, r; struct timespec ts_timeout; + const char *err_msg; opts = session->data; @@ -1909,7 +1910,11 @@ nc_accept_ssh_session(struct nc_session *session, int sock, int timeout) rc = 0; goto cleanup; } else if (r != SSH_OK) { - ERR(session, "SSH key exchange error (%s).", ssh_get_error(session->ti.libssh.session)); + err_msg = ssh_get_error(session->ti.libssh.session); + if (err_msg[0] == '\0') { + err_msg = "hostkey algorithm generated from the hostkey most likely not found in the set of configured hostkey algorithms"; + } + ERR(session, "SSH key exchange error (%s).", err_msg); rc = -1; goto cleanup; } From fc8bd7d50028f440cc63147c6d5d155639e49fac Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 14 Apr 2023 09:13:57 +0200 Subject: [PATCH 015/134] tests UPDATE add test for ECDSA hostkey --- tests/CMakeLists.txt | 2 +- tests/test_ec.c | 273 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 tests/test_ec.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ff065dbe..b1ad7815 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,7 @@ endif() # list of all the tests in each directory #set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages) -set(tests test_two_channels test_keystore test_unix_socket test_config_new test_truststore) +set(tests test_two_channels test_keystore test_unix_socket test_config_new test_truststore test_ec) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) diff --git a/tests/test_ec.c b/tests/test_ec.c new file mode 100644 index 00000000..c9f19002 --- /dev/null +++ b/tests/test_ec.c @@ -0,0 +1,273 @@ +/** + * @file test_ec.c + * @author Roman Janota + * @brief libnetconf2 EC hostkey test + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 + +struct ly_ctx *ctx; + +struct test_state { + pthread_barrier_t barrier; +}; + +const char *data = + "\n" + " \n" + " 10\n" + " \n" + " default-ssh\n" + " \n" + " \n" + " 127.0.0.1\n" + " 10005\n" + " \n" + " \n" + " \n" + " \n" + " key\n" + " \n" + " \n" + " ct:ssh-public-key-format\n" + " MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEje+TM7/KHx8zJ4HtVcehRNg6ZXLjeWpXWI7m2x9EeKBX+TgYElq0mIESw88s1HnPrT5AdaWeZymD+MSxd4dzwA==\n" + " ct:ec-private-key-format\n" + " MHcCAQEEIGAq2oW59feizNqqUDqDyuLLQ7f1Y1WQHo5KGVuFhwQ/oAoGCCqGSM49AwEHoUQDQgAEje+TM7/KHx8zJ4HtVcehRNg6ZXLjeWpXWI7m2x9EeKBX+TgYElq0mIESw88s1HnPrT5AdaWeZymD+MSxd4dzwA==\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " test_ec\n" + " \n" + " \n" + " \n" + " test\n" + " ct:ssh-public-key-format\n" + " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " sshpka:ecdsa-sha2-nistp256\n" + " \n" + " \n" + " sshkea:curve25519-sha256\n" + " \n" + " \n" + " sshea:aes256-ctr\n" + " \n" + " \n" + " sshma:hmac-sha2-512\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + (void) arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_thread_destroy(); + return NULL; +} + +static int +ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) +{ + (void)hostname; + (void)session; + (void)priv; + /* skip the knownhost check */ + + return 0; +} + +static void * +client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + /* set directory where to search for modules */ + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set ssh username */ + ret = nc_client_ssh_set_username("test_ec"); + assert_int_equal(ret, 0); + + /* add client's key pair */ + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + /* connect */ + session = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_ec(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + /* create new context */ + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* load default modules into context */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf-netconf-server module and it's imports into context */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* parse yang data */ + ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup(tree); + assert_int_equal(ret, 0); + + /* initialize client */ + nc_client_init(); + + /* initialize server */ + ret = nc_server_init(); + assert_int_equal(ret, 0); + + /* skip the knownhost check */ + nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_ec, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} From d4db2c1c6f20cf49fc41e2f1900fd6c11533c5e9 Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 24 Apr 2023 15:51:26 +0200 Subject: [PATCH 016/134] client UPDATE set known_hosts file/mode Added two new API calls, one of them sets the path to the known_hosts file and the other sets the behaviour of host key checking. Now the client's host key checking functionality is similar to the one described in man ssh_config under StrictHostKeyChecking. --- src/io.c | 14 +- src/libnetconf.h | 2 - src/session.h | 11 ++ src/session_client.c | 6 +- src/session_client.h | 27 ++-- src/session_client_ssh.c | 270 +++++++++++++++++++++++++-------------- src/session_p.h | 65 +++++----- src/session_server.c | 2 +- 8 files changed, 240 insertions(+), 157 deletions(-) diff --git a/src/io.c b/src/io.c index b2cf495f..d9b5c54a 100644 --- a/src/io.c +++ b/src/io.c @@ -1177,7 +1177,7 @@ nc_realloc(void *ptr, size_t size) } struct passwd * -nc_getpwuid(uid_t uid, struct passwd *pwd_buf, char **buf, size_t *buf_size) +nc_getpw(uid_t uid, const char *username, struct passwd *pwd_buf, char **buf, size_t *buf_size) { struct passwd *pwd = NULL; long sys_size; @@ -1200,11 +1200,19 @@ nc_getpwuid(uid_t uid, struct passwd *pwd_buf, char **buf, size_t *buf_size) return NULL; } - ret = getpwuid_r(uid, pwd_buf, *buf, *buf_size, &pwd); + if (username) { + ret = getpwnam_r(username, pwd_buf, *buf, *buf_size, &pwd); + } else { + ret = getpwuid_r(uid, pwd_buf, *buf, *buf_size, &pwd); + } } while (ret && (ret == ERANGE)); if (ret) { - ERR(NULL, "Retrieving UID \"%lu\" passwd entry failed (%s).", (unsigned long)uid, strerror(ret)); + if (username) { + ERR(NULL, "Retrieving username \"%s\" passwd entry failed (%s).", username, strerror(ret)); + } else { + ERR(NULL, "Retrieving UID \"%lu\" passwd entry failed (%s).", (unsigned long)uid, strerror(ret)); + } } return pwd; } diff --git a/src/libnetconf.h b/src/libnetconf.h index 27ba007f..a09c1983 100644 --- a/src/libnetconf.h +++ b/src/libnetconf.h @@ -198,8 +198,6 @@ * * Available in __nc_client.h__. * - * - ::nc_client_ssh_set_auth_hostkey_check_clb() - * - ::nc_client_ssh_get_auth_hostkey_check_clb() * - ::nc_client_ssh_set_auth_password_clb() * - ::nc_client_ssh_get_auth_password_clb() * - ::nc_client_ssh_set_auth_interactive_clb() diff --git a/src/session.h b/src/session.h index a533477f..55f4a0d8 100644 --- a/src/session.h +++ b/src/session.h @@ -34,6 +34,17 @@ typedef enum { NC_SSH_AUTH_INTERACTIVE = 0x04 /**< interactive SSH authentication */ } NC_SSH_AUTH_TYPE; +/** + * @brief Enumeration of host key checking and known_hosts entry adding modes + */ +typedef enum { + NC_SSH_KNOWNHOSTS_ASK = 0, /**< add a known_hosts entry, but with a prompt */ + NC_SSH_KNOWNHOSTS_STRICT, /**< do not add a known_hosts entry and the server's host key must be present in the configured known_hosts file */ + NC_SSH_KNOWNHOSTS_ACCEPT_NEW, /**< add a known_hosts entry without a prompt */ + NC_SSH_KNOWNHOSTS_ACCEPT, /**< add a known_hosts entry without a prompt and allow connections to servers which changed their host key */ + NC_SSH_KNOWNHOSTS_SKIP /**< do not add a known_hosts entry and skip all host key checks */ +} NC_SSH_KNOWNHOSTS_MODE; + #endif /* NC_ENABLED_SSH */ #ifdef NC_ENABLED_TLS diff --git a/src/session_client.c b/src/session_client.c index e086fa21..c850a847 100644 --- a/src/session_client.c +++ b/src/session_client.c @@ -52,7 +52,6 @@ static const char *ncds2str[] = {NULL, "config", "url", "running", "startup", "candidate"}; #ifdef NC_ENABLED_SSH -int sshauth_hostkey_check(const char *hostname, ssh_session session, void *priv); 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); @@ -71,14 +70,12 @@ static struct nc_client_context context_main = { #ifdef NC_ENABLED_SSH .ssh_opts = { .auth_pref = {{NC_SSH_AUTH_INTERACTIVE, 1}, {NC_SSH_AUTH_PASSWORD, 2}, {NC_SSH_AUTH_PUBLICKEY, 3}}, - .auth_hostkey_check = sshauth_hostkey_check, .auth_password = sshauth_password, .auth_interactive = sshauth_interactive, .auth_privkey_passphrase = sshauth_privkey_passphrase }, .ssh_ch_opts = { .auth_pref = {{NC_SSH_AUTH_INTERACTIVE, 1}, {NC_SSH_AUTH_PASSWORD, 2}, {NC_SSH_AUTH_PUBLICKEY, 3}}, - .auth_hostkey_check = sshauth_hostkey_check, .auth_password = sshauth_password, .auth_interactive = sshauth_interactive, .auth_privkey_passphrase = sshauth_privkey_passphrase @@ -169,7 +166,6 @@ nc_client_context_location(void) e->ssh_opts.auth_pref[1].value = 2; e->ssh_opts.auth_pref[2].type = NC_SSH_AUTH_PUBLICKEY; e->ssh_opts.auth_pref[2].value = 3; - e->ssh_opts.auth_hostkey_check = sshauth_hostkey_check; e->ssh_opts.auth_password = sshauth_password; e->ssh_opts.auth_interactive = sshauth_interactive; e->ssh_opts.auth_privkey_passphrase = sshauth_privkey_passphrase; @@ -1486,7 +1482,7 @@ nc_connect_unix(const char *address, struct ly_ctx *ctx) session->path = strdup(address); - pw = nc_getpwuid(geteuid(), &pw_buf, &buf, &buf_size); + pw = nc_getpw(geteuid(), NULL, &pw_buf, &buf, &buf_size); if (!pw) { ERR(NULL, "Failed to find username for UID %u.", (unsigned int)geteuid()); goto fail; diff --git a/src/session_client.h b/src/session_client.h index 6115fcbb..84e3ce8c 100644 --- a/src/session_client.h +++ b/src/session_client.h @@ -180,28 +180,23 @@ struct nc_session *nc_connect_unix(const char *address, struct ly_ctx *ctx); */ /** - * @brief Set SSH authentication hostkey check (knownhosts) callback. + * @brief Set the behaviour of checking the host key and adding/reading entries to/from the known_hosts file. * - * Repetitive calling causes replacing of the previous callback and its private data. Caller is responsible for - * freeing the private data when necessary (the private data can be obtained by - * nc_client_ssh_get_auth_hostkey_check_clb()). - * - * @param[in] auth_hostkey_check Function to call, returns 0 on success, non-zero in error. - * If NULL, the default callback is set. - * @param[in] priv Optional private data to be passed to the callback function. + * @param[in] mode Server host key checking mode. */ -void nc_client_ssh_set_auth_hostkey_check_clb(int (*auth_hostkey_check)(const char *hostname, ssh_session session, void *priv), - void *priv); +void nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_MODE mode); /** - * @brief Get currently set SSH authentication hostkey check (knownhosts) callback and its private data previously set - * by nc_client_ssh_set_auth_hostkey_check_clb(). + * @brief Set the path to the known_hosts file. * - * @param[out] auth_hostkey_check Currently set callback, NULL in case of the default callback. - * @param[out] priv Currently set (optional) private data to be passed to the callback function. + * Repetetive calling replaces the value. If the given file doesn't exist and the process has sufficient + * rights, it gets created whenever the file is needed, otherwise an error occurs. If NULL is passed or the + * path isn't set, the default known_hosts file will be used. + * + * @param[in] path Path to the known_hosts file. + * @return 0 on success, 1 on error. */ -void nc_client_ssh_get_auth_hostkey_check_clb(int (**auth_hostkey_check)(const char *hostname, ssh_session session, void *priv), - void **priv); +int nc_client_ssh_set_knownhosts_path(const char *path); /** * @brief Set SSH password authentication callback. diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c index bacfc139..23ee58c6 100644 --- a/src/session_client_ssh.c +++ b/src/session_client_ssh.c @@ -167,9 +167,11 @@ _nc_client_ssh_destroy_opts(struct nc_client_ssh_opts *opts) } free(opts->keys); free(opts->username); + free(opts->knownhosts_path); opts->key_count = 0; opts->keys = NULL; opts->username = NULL; + opts->knownhosts_path = NULL; } void @@ -275,29 +277,33 @@ sshauth_hostkey_hash_dnssec_check(const char *hostname, const unsigned char *sha #endif /* ENABLE_DNSSEC */ -int -sshauth_hostkey_check(const char *hostname, ssh_session session, void *UNUSED(priv)) +static int +nc_client_ssh_update_known_hosts(ssh_session session, const char *hostname) { - char *hexa = NULL; + int ret; #if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) - int c, ret; - enum ssh_known_hosts_e state; + ret = ssh_session_update_known_hosts(session); #else - int c, state, ret; + ret = ssh_write_knownhost(session); #endif + + if (ret != SSH_OK) { + WRN(NULL, "Adding the known host \"%s\" failed (%s).", hostname, ssh_get_error(session)); + } + + return ret; +} + +static int +nc_client_ssh_get_srv_pubkey_data(ssh_session session, enum ssh_keytypes_e *srv_pubkey_type, char **hexa, unsigned char **hash_sha1) +{ + int ret; ssh_key srv_pubkey; - unsigned char *hash_sha1 = NULL; size_t hlen; - enum ssh_keytypes_e srv_pubkey_type; - char answer[5]; - FILE *out = NULL, *in = NULL; -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) - state = ssh_session_is_known_server(session); -#else - state = ssh_is_server_known(session); -#endif + *hexa = NULL; + *hash_sha1 = NULL; #if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 8, 0)) ret = ssh_get_server_publickey(session, &srv_pubkey); @@ -309,15 +315,86 @@ sshauth_hostkey_check(const char *hostname, ssh_session session, void *UNUSED(pr return -1; } - srv_pubkey_type = ssh_key_type(srv_pubkey); - ret = ssh_get_publickey_hash(srv_pubkey, SSH_PUBLICKEY_HASH_SHA1, &hash_sha1, &hlen); + *srv_pubkey_type = ssh_key_type(srv_pubkey); + ret = ssh_get_publickey_hash(srv_pubkey, SSH_PUBLICKEY_HASH_SHA1, hash_sha1, &hlen); ssh_key_free(srv_pubkey); if (ret < 0) { ERR(NULL, "Failed to calculate SHA1 hash of the server public key."); return -1; } - hexa = ssh_get_hexa(hash_sha1, hlen); + *hexa = ssh_get_hexa(*hash_sha1, hlen); + if (!*hexa) { + ERR(NULL, "Getting the hostkey's hex string failed."); + return -1; + } + + return 0; +} + +#ifdef ENABLE_DNSSEC +static int +nc_client_ssh_do_dnssec_sshfp_check(ssh_session session, enum ssh_keytypes_e srv_pubkey_type, const char *hostname, unsigned char *hash_sha1) +{ + int ret; + + if ((srv_pubkey_type != SSH_KEYTYPE_UNKNOWN) && (srv_pubkey_type != SSH_KEYTYPE_RSA1)) { + if (srv_pubkey_type == SSH_KEYTYPE_DSS) { + /* TODO else branch? */ + ret = sshauth_hostkey_hash_dnssec_check(hostname, hash_sha1, 2, 1); + } else if (srv_pubkey_type == SSH_KEYTYPE_RSA) { + ret = sshauth_hostkey_hash_dnssec_check(hostname, hash_sha1, 1, 1); + } else if (srv_pubkey_type == SSH_KEYTYPE_ECDSA) { + ret = sshauth_hostkey_hash_dnssec_check(hostname, hash_sha1, 3, 1); + } + + /* DNSSEC SSHFP check successful, that's enough */ + if (!ret) { + VRB(NULL, "DNSSEC SSHFP check successful."); +#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) + ssh_session_update_known_hosts(session); +#else + ssh_write_knownhost(session); +#endif + } + + return ret; + } + + return 1; +} + +#endif + +static int +nc_client_ssh_auth_hostkey_check(const char *hostname, uint16_t port, ssh_session session) +{ + char *hexa = NULL; + unsigned char *hash_sha1 = NULL; + NC_SSH_KNOWNHOSTS_MODE knownhosts_mode = ssh_opts.knownhosts_mode; + enum ssh_keytypes_e srv_pubkey_type; + char answer[5]; + FILE *out = NULL, *in = NULL; + int c, state; + +#ifdef ENABLE_DNSSEC + int dnssec_ret; +#endif + + if (knownhosts_mode == NC_SSH_KNOWNHOSTS_SKIP) { + /* skip all hostkey checks */ + return 0; + } + + if (nc_client_ssh_get_srv_pubkey_data(session, &srv_pubkey_type, &hexa, &hash_sha1)) { + goto error; + } + +#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) + state = ssh_session_is_known_server(session); +#else + state = ssh_is_server_known(session); +#endif switch (state) { #if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) @@ -332,8 +409,14 @@ sshauth_hostkey_check(const char *hostname, ssh_session session, void *UNUSED(pr #else case SSH_SERVER_KNOWN_CHANGED: #endif - ERR(NULL, "Remote host key changed, the connection will be terminated!"); - goto error; + if (knownhosts_mode == NC_SSH_KNOWNHOSTS_ACCEPT) { + /* is the mode is set to accept, then accept any connection even if the remote key changed */ + WRN(NULL, "Remote host key changed, but you have requested accept mode so the connection will not be terminated."); + break; + } else { + ERR(NULL, "Remote host key changed, the connection will be terminated!"); + goto error; + } #if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) case SSH_KNOWN_HOSTS_OTHER: @@ -358,37 +441,39 @@ sshauth_hostkey_check(const char *hostname, ssh_session session, void *UNUSED(pr #endif hostkey_not_known: #ifdef ENABLE_DNSSEC - if ((srv_pubkey_type != SSH_KEYTYPE_UNKNOWN) && (srv_pubkey_type != SSH_KEYTYPE_RSA1)) { - if (srv_pubkey_type == SSH_KEYTYPE_DSS) { - ret = sshauth_hostkey_hash_dnssec_check(hostname, hash_sha1, 2, 1); - } else if (srv_pubkey_type == SSH_KEYTYPE_RSA) { - ret = sshauth_hostkey_hash_dnssec_check(hostname, hash_sha1, 1, 1); - } else if (srv_pubkey_type == SSH_KEYTYPE_ECDSA) { - ret = sshauth_hostkey_hash_dnssec_check(hostname, hash_sha1, 3, 1); - } - - /* DNSSEC SSHFP check successful, that's enough */ - if (!ret) { - VRB(NULL, "DNSSEC SSHFP check successful."); -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) - ssh_session_update_known_hosts(session); -#else - ssh_write_knownhost(session); -#endif - ssh_clean_pubkey_hash(&hash_sha1); - ssh_string_free_char(hexa); - return 0; - } + /* do dnssec check, if it's ok then we're done otherwise continue */ + dnssec_ret = nc_client_ssh_do_dnssec_sshfp_check(session, srv_pubkey_type, hostname, hash_sha1); + if (!dnssec_ret) { + ssh_clean_pubkey_hash(&hash_sha1); + ssh_string_free_char(hexa); + return 0; } #endif + /* open the files for reading/writing */ if (!(in = nc_open_in(1, NULL))) { goto error; } + if (!(out = nc_open_out())) { goto error; } + if (knownhosts_mode == NC_SSH_KNOWNHOSTS_STRICT) { + /* do not connect if the hostkey is not present in known_hosts file in this mode */ + ERR(NULL, "No %s host key is known for [%s]:%hu and you have requested strict checking.\n", ssh_key_type_to_char(srv_pubkey_type), hostname, port); + goto error; + } else if ((knownhosts_mode == NC_SSH_KNOWNHOSTS_ACCEPT_NEW) || (knownhosts_mode == NC_SSH_KNOWNHOSTS_ACCEPT)) { + /* add a new entry to the known_hosts file without prompting */ + if (nc_client_ssh_update_known_hosts(session, hostname)) { + goto error; + } + + VRB(NULL, "Permanently added '[%s]:%hu' (%s) to the list of known hosts.", hostname, port, ssh_key_type_to_char(srv_pubkey_type)); + + break; + } + /* try to get result from user */ if (fprintf(out, "The authenticity of the host \'%s\' cannot be established.\n", hostname) < 1) { ERR(NULL, "Writing into output failed (%s).", feof(out) ? "EOF" : strerror(errno)); @@ -400,12 +485,12 @@ sshauth_hostkey_check(const char *hostname, ssh_session session, void *UNUSED(pr } #ifdef ENABLE_DNSSEC - if (ret == 2) { + if (dnssec_ret == 2) { if (fprintf(out, "No matching host key fingerprint found using DNS.\n") < 1) { ERR(NULL, "Writing into output failed (%s).", feof(out) ? "EOF" : strerror(errno)); goto error; } - } else if (ret == 1) { + } else if (dnssec_ret == 1) { if (fprintf(out, "Matching host key fingerprint found using DNS.\n") < 1) { ERR(NULL, "Writing into output failed (%s).", feof(out) ? "EOF" : strerror(errno)); goto error; @@ -428,15 +513,8 @@ sshauth_hostkey_check(const char *hostname, ssh_session session, void *UNUSED(pr fflush(in); if (!strcmp("yes", answer)) { - /* store the key into the host file */ -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) - ret = ssh_session_update_known_hosts(session); -#else - ret = ssh_write_knownhost(session); -#endif - if (ret != SSH_OK) { - WRN(NULL, "Adding the known host \"%s\" failed (%s).", hostname, ssh_get_error(session)); - } + /* store the key into the known_hosts file */ + nc_client_ssh_update_known_hosts(session, hostname); } else if (!strcmp("no", answer)) { goto error; } else { @@ -645,57 +723,29 @@ sshauth_privkey_passphrase(const char *privkey_path, void *UNUSED(priv)) return NULL; } -static void -_nc_client_ssh_set_auth_hostkey_check_clb(int (*auth_hostkey_check)(const char *hostname, ssh_session session, void *priv), - void *priv, struct nc_client_ssh_opts *opts) +API int +nc_client_ssh_set_knownhosts_path(const char *path) { - if (auth_hostkey_check) { - opts->auth_hostkey_check = auth_hostkey_check; - opts->auth_hostkey_check_priv = priv; - } else { - opts->auth_hostkey_check = sshauth_hostkey_check; - opts->auth_hostkey_check_priv = NULL; - } -} + free(ssh_opts.knownhosts_path); -static void -_nc_client_ssh_get_auth_hostkey_check_clb(int (**auth_hostkey_check)(const char *hostname, ssh_session session, void *priv), - void **priv, struct nc_client_ssh_opts *opts) -{ - if (auth_hostkey_check) { - (*auth_hostkey_check) = opts->auth_hostkey_check == sshauth_hostkey_check ? NULL : opts->auth_hostkey_check; - } - if (priv) { - (*priv) = opts->auth_hostkey_check_priv; + if (!path) { + ssh_opts.knownhosts_path = NULL; + return 0; } -} -API void -nc_client_ssh_set_auth_hostkey_check_clb(int (*auth_hostkey_check)(const char *hostname, ssh_session session, void *priv), - void *priv) -{ - _nc_client_ssh_set_auth_hostkey_check_clb(auth_hostkey_check, priv, &ssh_opts); -} - -API void -nc_client_ssh_ch_set_auth_hostkey_check_clb(int (*auth_hostkey_check)(const char *hostname, ssh_session session, void *priv), - void *priv) -{ - _nc_client_ssh_set_auth_hostkey_check_clb(auth_hostkey_check, priv, &ssh_ch_opts); -} + ssh_opts.knownhosts_path = strdup(path); + if (!ssh_opts.knownhosts_path) { + ERRMEM; + return 1; + } -API void -nc_client_ssh_get_auth_hostkey_check_clb(int (**auth_hostkey_check)(const char *hostname, ssh_session session, void *priv), - void **priv) -{ - _nc_client_ssh_get_auth_hostkey_check_clb(auth_hostkey_check, priv, &ssh_opts); + return 0; } API void -nc_client_ssh_ch_get_auth_hostkey_check_clb(int (**auth_hostkey_check)(const char *hostname, ssh_session session, void *priv), - void **priv) +nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_MODE mode) { - _nc_client_ssh_get_auth_hostkey_check_clb(auth_hostkey_check, priv, &ssh_ch_opts); + ssh_opts.knownhosts_mode = mode; } static void @@ -1193,7 +1243,7 @@ connect_ssh_session(struct nc_session *session, struct nc_client_ssh_opts *opts, return -1; } - if (opts->auth_hostkey_check(session->host, ssh_sess, opts->auth_hostkey_check_priv)) { + if (nc_client_ssh_auth_hostkey_check(session->host, session->port, ssh_sess)) { ERR(session, "Checking the host key failed."); return -1; } @@ -1572,7 +1622,7 @@ _nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx, struct nc_keepal /* remember username */ if (!username) { if (!opts->username) { - pw = nc_getpwuid(getuid(), &pw_buf, &buf, &buf_len); + pw = nc_getpw(getuid(), NULL, &pw_buf, &buf, &buf_len); if (!pw) { ERR(NULL, "Unknown username for the SSH connection (%s).", strerror(errno)); goto fail; @@ -1646,6 +1696,7 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx) struct nc_session *session = NULL; char *buf = NULL; size_t buf_len = 0; + char *known_hosts_path = NULL; /* process parameters */ if (!host || strisempty(host)) { @@ -1658,7 +1709,7 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx) port_uint = port; if (!ssh_opts.username) { - pw = nc_getpwuid(getuid(), &pw_buf, &buf, &buf_len); + pw = nc_getpw(getuid(), NULL, &pw_buf, &buf, &buf_len); if (!pw) { ERR(session, "Unknown username for the SSH connection (%s).", strerror(errno)); goto fail; @@ -1667,6 +1718,23 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx) } } else { username = ssh_opts.username; + + pw = nc_getpw(0, username, &pw_buf, &buf, &buf_len); + } + + if (ssh_opts.knownhosts_path) { + /* known_hosts file path was set so use it */ + known_hosts_path = strdup(ssh_opts.knownhosts_path); + if (!known_hosts_path) { + ERRMEM; + goto fail; + } + } else if (pw) { + /* path not set explicitly, but current user's username found in /etc/passwd, so create the path */ + if (asprintf(&known_hosts_path, "%s/.ssh/known_hosts", pw->pw_dir) == -1) { + ERRMEM; + goto fail; + } } /* prepare session structure */ @@ -1690,6 +1758,9 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx) ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_PORT, &port_uint); ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_USER, username); ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_TIMEOUT, &timeout); + if (known_hosts_path) { + ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_path); + } /* create and assign communication socket */ sock = nc_sock_connect(host, port, -1, &client_opts.ka, NULL, &ip_host); @@ -1703,6 +1774,7 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx) /* store information for session connection */ session->host = strdup(host); session->username = strdup(username); + session->port = port; if ((connect_ssh_session(session, &ssh_opts, NC_TRANSPORT_TIMEOUT) != 1) || (open_netconf_channel(session, NC_TRANSPORT_TIMEOUT) != 1)) { goto fail; @@ -1729,10 +1801,12 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx) session->port = port; free(buf); + free(known_hosts_path); return session; fail: free(buf); + free(known_hosts_path); free(ip_host); nc_session_free(session, NULL); return NULL; @@ -1838,7 +1912,7 @@ nc_accept_callhome_ssh_sock(int sock, const char *host, uint16_t port, struct ly ssh_options_set(sess, SSH_OPTIONS_PORT, &uint_port); ssh_options_set(sess, SSH_OPTIONS_TIMEOUT, &ssh_timeout); if (!ssh_ch_opts.username) { - pw = nc_getpwuid(getuid(), &pw_buf, &buf, &buf_len); + pw = nc_getpw(getuid(), NULL, &pw_buf, &buf, &buf_len); if (!pw) { ERR(NULL, "Unknown username for the SSH connection (%s).", strerror(errno)); ssh_free(sess); diff --git a/src/session_p.h b/src/session_p.h index 1995d050..4ac237e3 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -70,37 +70,6 @@ typedef enum { NC_SSH_PUBKEY_X509 /**< begins with BEGIN PUBLICKEY, see RFC 5280 sec. 4.1.2.7 */ } NC_SSH_PUBKEY_TYPE; -/* ACCESS unlocked */ -struct nc_client_ssh_opts { - /* SSH authentication method preferences */ - struct { - NC_SSH_AUTH_TYPE type; - int16_t value; - } auth_pref[NC_SSH_AUTH_COUNT]; - - /* SSH key pairs */ - struct { - char *pubkey_path; - char *privkey_path; - int8_t privkey_crypt; - } *keys; - uint16_t key_count; - - /* SSH authentication callbacks */ - int (*auth_hostkey_check)(const char *, ssh_session, void *); - char *(*auth_password)(const char *, const char *, void *); - char *(*auth_interactive)(const char *, const char *, const char *, int, void *); - char *(*auth_privkey_passphrase)(const char *, void *); - - /* private data for the callbacks */ - void *auth_hostkey_check_priv; - void *auth_password_priv; - void *auth_interactive_priv; - void *auth_privkey_passphrase_priv; - - char *username; -}; - /** * @brief A basic certificate. */ @@ -305,6 +274,38 @@ struct nc_bind { int pollin; /**< Specifies, which sockets to poll on. */ }; +/* ACCESS unlocked */ +struct nc_client_ssh_opts { + char *knownhosts_path; /**< path to known_hosts file */ + NC_KNOWNHOSTS_MODE knownhosts_mode; /**< implies whether to check known_hosts or not */ + + /* SSH authentication method preferences */ + struct { + NC_SSH_AUTH_TYPE type; + int16_t value; + } auth_pref[NC_SSH_AUTH_COUNT]; + + /* SSH key pairs */ + struct { + char *pubkey_path; + char *privkey_path; + int8_t privkey_crypt; + } *keys; + uint16_t key_count; + + /* SSH authentication callbacks */ + char *(*auth_password)(const char *, const char *, void *); + char *(*auth_interactive)(const char *, const char *, const char *, int, void *); + char *(*auth_privkey_passphrase)(const char *, void *); + + /* private data for the callbacks */ + void *auth_password_priv; + void *auth_interactive_priv; + void *auth_privkey_passphrase_priv; + + char *username; +}; + /* ACCESS unlocked */ struct nc_client_opts { char *schema_searchpath; @@ -671,7 +672,7 @@ struct nc_pam_thread_arg { void *nc_realloc(void *ptr, size_t size); -struct passwd *nc_getpwuid(uid_t uid, struct passwd *pwd_buf, char **buf, size_t *buf_size); +struct passwd *nc_getpw(uid_t uid, const char *username, struct passwd *pwd_buf, char **buf, size_t *buf_size); NC_MSG_TYPE nc_send_msg_io(struct nc_session *session, int io_timeout, struct lyd_node *op); diff --git a/src/session_server.c b/src/session_server.c index cd583cda..4a646b46 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -2007,7 +2007,7 @@ nc_accept_unix(struct nc_session *session, int sock) return -1; } - pw = nc_getpwuid(uid, &pw_buf, &buf, &buf_len); + pw = nc_getpw(uid, NULL, &pw_buf, &buf, &buf_len); if (pw == NULL) { ERR(NULL, "Failed to find username for uid=%u (%s).\n", uid, strerror(errno)); close(sock); From f2db560efa09869ad981b4b144679102930e0ce7 Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 24 Apr 2023 16:28:09 +0200 Subject: [PATCH 017/134] tests UPDATE use new known_hosts API Stop using the client tests for now, might be added back later. --- tests/CMakeLists.txt | 22 ++++++++-------- tests/client/test_client_ssh.c | 47 ++++++++++------------------------ tests/test_auth.c | 26 +++++++++---------- tests/test_config_new.c | 17 +++--------- tests/test_keystore.c | 17 +++--------- tests/test_truststore.c | 17 +++--------- tests/test_two_channels.c | 17 +++--------- 7 files changed, 49 insertions(+), 114 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b1ad7815..c76bc2fb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -61,13 +61,13 @@ foreach(test_name IN LISTS tests) add_test(NAME ${test_name} COMMAND $) endforeach() -foreach(test_name IN LISTS client_tests) - add_executable(${test_name} $ ./client/${test_name}.c) - target_link_libraries(${test_name} ${CMOCKA_LIBRARIES} ${LIBYANG_LIBRARIES} netconf2) - target_include_directories(${test_name} PRIVATE ${CMOCKA_INCLUDE_DIR}) - set_target_properties(${test_name} PROPERTIES LINK_FLAGS "${${test_name}_wrap_link_flags}") - add_test(NAME ${test_name} COMMAND $) -endforeach() +# foreach(test_name IN LISTS client_tests) +# add_executable(${test_name} $ ./client/${test_name}.c) +# target_link_libraries(${test_name} ${CMOCKA_LIBRARIES} ${LIBYANG_LIBRARIES} netconf2) +# target_include_directories(${test_name} PRIVATE ${CMOCKA_INCLUDE_DIR}) +# set_target_properties(${test_name} PROPERTIES LINK_FLAGS "${${test_name}_wrap_link_flags}") +# add_test(NAME ${test_name} COMMAND $) +# endforeach() if(ENABLE_VALGRIND_TESTS) foreach(test_name IN LISTS tests) @@ -75,10 +75,10 @@ if(ENABLE_VALGRIND_TESTS) --suppressions=${PROJECT_SOURCE_DIR}/tests/library_valgrind.supp ${CMAKE_BINARY_DIR}/tests/${test_name}) endforeach() - foreach(test_name IN LISTS client_tests) - add_test(${test_name}_valgrind valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 - --suppressions=${PROJECT_SOURCE_DIR}/tests/library_valgrind.supp ${CMAKE_BINARY_DIR}/tests/${test_name}) - endforeach() + # foreach(test_name IN LISTS client_tests) + # add_test(${test_name}_valgrind valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 + # --suppressions=${PROJECT_SOURCE_DIR}/tests/library_valgrind.supp ${CMAKE_BINARY_DIR}/tests/${test_name}) + # endforeach() endif() include_directories(${CMAKE_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}) diff --git a/tests/client/test_client_ssh.c b/tests/client/test_client_ssh.c index e9a21655..0a66e597 100644 --- a/tests/client/test_client_ssh.c +++ b/tests/client/test_client_ssh.c @@ -97,16 +97,6 @@ const char *data = " \n" "\n"; -static int -ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) -{ - (void)hostname; - (void)session; - (void)priv; - - return 0; -} - static int setup_f(void **state) { @@ -119,7 +109,6 @@ setup_f(void **state) assert_int_equal(ret, 0); ret = nc_client_ssh_ch_set_username("ch_username"); assert_int_equal(ret, 0); - nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); return 0; } @@ -304,33 +293,23 @@ __wrap_nc_accept_callhome_ssh_sock(int sock, const char *host, uint16_t port, st return mock_ptr_type(struct nc_session *); } -static int -test_hostkey_clb(const char *hostname, ssh_session session, void *priv) -{ - (void)hostname; - (void)session; - (void)priv; - - return 0; -} - static void test_nc_client_ssh_setting_auth_hostkey_check_clb(void **state) { (void)state; - int (*ret_f)(const char *hostname, ssh_session session, void *priv); - char *priv_data_ret; - - /* ssh_hostkey_check_clb is set in setup_f */ - nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret); - assert_ptr_equal(ret_f, ssh_hostkey_check_clb); - assert_null(priv_data_ret); - - /* set different callback and private data */ - nc_client_ssh_set_auth_hostkey_check_clb(test_hostkey_clb, "DATA"); - nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret); - assert_ptr_equal(ret_f, test_hostkey_clb); - assert_string_equal(priv_data_ret, "DATA"); + // int (*ret_f)(const char *hostname, ssh_session session, void *priv); + // char *priv_data_ret; + + /// * ssh_hostkey_check_clb is set in setup_f */ + // nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret); + // assert_ptr_equal(ret_f, ssh_hostkey_check_clb); + // assert_null(priv_data_ret); + + /// * set different callback and private data */ + // nc_client_ssh_set_auth_hostkey_check_clb(test_hostkey_clb, "DATA"); + // nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret); + // assert_ptr_equal(ret_f, test_hostkey_clb); + // assert_string_equal(priv_data_ret, "DATA"); } char * diff --git a/tests/test_auth.c b/tests/test_auth.c index 63d75474..cdd14db9 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -145,17 +145,6 @@ server_thread(void *arg) return NULL; } -static int -ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) -{ - (void)hostname; - (void)session; - (void)priv; - /* skip the knownhost check */ - - return 0; -} - static char * auth_interactive(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv) { @@ -181,6 +170,9 @@ client_thread_interactive(void *arg) struct nc_session *session = NULL; struct test_state *state = arg; + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); @@ -242,6 +234,9 @@ client_thread_password(void *arg) struct nc_session *session = NULL; struct test_state *state = arg; + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); @@ -288,6 +283,9 @@ client_thread_pubkey(void *arg) struct nc_session *session = NULL; struct test_state *state = arg; + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); @@ -335,6 +333,9 @@ client_thread_none(void *arg) struct nc_session *session = NULL; struct test_state *state = arg; + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); @@ -409,9 +410,6 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); - /* skip the knownhost check */ - nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); - lyd_free_all(tree); return 0; diff --git a/tests/test_config_new.c b/tests/test_config_new.c index 42e8ded0..cb4948b5 100644 --- a/tests/test_config_new.c +++ b/tests/test_config_new.c @@ -65,17 +65,6 @@ server_thread(void *arg) return NULL; } -static int -ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) -{ - (void)hostname; - (void)session; - (void)priv; - /* skip the knownhost check */ - - return 0; -} - static char * auth_password(const char *username, const char *hostname, void *priv) { @@ -94,6 +83,9 @@ client_thread(void *arg) struct nc_session *session = NULL; struct test_state *state = arg; + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); @@ -185,9 +177,6 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); - /* skip the knownhost check */ - nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); - lyd_free_all(tree); return 0; diff --git a/tests/test_keystore.c b/tests/test_keystore.c index 8b966b0a..f9821d81 100644 --- a/tests/test_keystore.c +++ b/tests/test_keystore.c @@ -136,17 +136,6 @@ server_thread(void *arg) return NULL; } -static int -ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) -{ - (void)hostname; - (void)session; - (void)priv; - /* skip the knownhost check */ - - return 0; -} - static void * client_thread_pubkey(void *arg) { @@ -154,6 +143,9 @@ client_thread_pubkey(void *arg) struct nc_session *session = NULL; struct test_state *state = arg; + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); @@ -235,9 +227,6 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); - /* skip the knownhost check */ - nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); - lyd_free_all(tree); return 0; diff --git a/tests/test_truststore.c b/tests/test_truststore.c index 8d2e0ce5..90bc882a 100644 --- a/tests/test_truststore.c +++ b/tests/test_truststore.c @@ -137,17 +137,6 @@ server_thread(void *arg) return NULL; } -static int -ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) -{ - (void)hostname; - (void)session; - (void)priv; - /* skip the knownhost check */ - - return 0; -} - static void * client_thread(void *arg) { @@ -155,6 +144,9 @@ client_thread(void *arg) struct nc_session *session = NULL; struct test_state *state = arg; + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + /* set directory where to search for modules */ ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); @@ -240,9 +232,6 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); - /* skip the knownhost check */ - nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); - lyd_free_all(tree); return 0; diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c index 8c24a690..85ee4385 100644 --- a/tests/test_two_channels.c +++ b/tests/test_two_channels.c @@ -152,17 +152,6 @@ server_thread(void *arg) return NULL; } -static int -ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) -{ - (void)hostname; - (void)session; - (void)priv; - /* redundant in this test, nonetheless this callback has to be set */ - - return 0; -} - static void * client_thread(void *arg) { @@ -172,10 +161,12 @@ client_thread(void *arg) /* initialize client */ nc_client_init(); + + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); - /* skip the knownhost check */ - nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); From 74073452379fb1ed32696904ff813d30793e6287 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 27 Apr 2023 14:30:27 +0200 Subject: [PATCH 018/134] server ssh UPDATE authentication with ECDSA keys ECDSA keys can now be used both as a hostkey and for client authentication. Three key pairs added for a new test. --- src/config_new.c | 43 ++++++--- src/session.c | 14 +++ src/session.h | 5 +- src/session_client_ssh.c | 2 +- tests/data/id_ecdsa256 | 9 ++ tests/data/id_ecdsa256.pub | 1 + tests/data/id_ecdsa384 | 10 +++ tests/data/id_ecdsa384.pub | 1 + tests/data/id_ecdsa521 | 12 +++ tests/data/id_ecdsa521.pub | 1 + tests/test_ec.c | 177 +++++++++++++++++++------------------ 11 files changed, 174 insertions(+), 101 deletions(-) create mode 100644 tests/data/id_ecdsa256 create mode 100644 tests/data/id_ecdsa256.pub create mode 100644 tests/data/id_ecdsa384 create mode 100644 tests/data/id_ecdsa384.pub create mode 100644 tests/data/id_ecdsa521 create mode 100644 tests/data/id_ecdsa521.pub diff --git a/src/config_new.c b/src/config_new.c index 0224a009..f8db1da0 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -607,25 +607,40 @@ nc_server_config_ssh_read_openssh_pubkey(FILE *f, char **pubkey) } start = buffer; - if (!strncmp(buffer, "ssh-rsa ", 8)) { + if (!strncmp(buffer, "ssh-dss ", 8)) { + ERR(NULL, "DSA public keys not supported."); + ret = 1; + goto cleanup; + } else if (!strncmp(buffer, "ssh-rsa ", 8)) { start += strlen("ssh-rsa "); - end = strchr(start, ' '); - if (!end) { - ERR(NULL, "Unexpected public key format."); - ret = 1; - goto cleanup; - } + } else if (!strncmp(buffer, "ecdsa-sha2-nistp256 ", 20)) { + start += strlen("ecdsa-sha2-nistp256 "); + } else if (!strncmp(buffer, "ecdsa-sha2-nistp384 ", 20)) { + start += strlen("ecdsa-sha2-nistp384 "); + } else if (!strncmp(buffer, "ecdsa-sha2-nistp521 ", 20)) { + start += strlen("ecdsa-sha2-nistp521 "); + } else { + ERR(NULL, "Unknown public key type."); + ret = 1; + goto cleanup; + } - *pubkey = strdup(start); - if (!*pubkey) { - ERRMEM; - ret = 1; - goto cleanup; - } + end = strchr(start, ' '); + if (!end) { + ERR(NULL, "Unexpected public key format."); + ret = 1; + goto cleanup; + } - (*pubkey)[strlen(*pubkey) - strlen(end)] = '\0'; + *pubkey = strdup(start); + if (!*pubkey) { + ERRMEM; + ret = 1; + goto cleanup; } + (*pubkey)[strlen(*pubkey) - strlen(end)] = '\0'; + cleanup: free(buffer); return ret; diff --git a/src/session.c b/src/session.c index 1a7f1e5e..d5d48867 100644 --- a/src/session.c +++ b/src/session.c @@ -107,16 +107,30 @@ nc_realtime_get(struct timespec *ts) } } +/** + * @brief Convert key type to string. + * + * @param[in] type Type of the key. + * @return String literal representing the key type or NULL. + */ const char * nc_keytype2str(NC_SSH_KEY_TYPE type) { switch (type) { + case NC_SSH_KEY_UNKNOWN: + return "unknown"; case NC_SSH_KEY_DSA: return "DSA"; case NC_SSH_KEY_RSA: return "RSA"; case NC_SSH_KEY_ECDSA: return "EC"; + case NC_SSH_KEY_ECDSA_P256: + return "ECDSA_P256"; + case NC_SSH_KEY_ECDSA_P384: + return "ECDSA_P384"; + case NC_SSH_KEY_ECDSA_P521: + return "ECDSA_P521"; default: break; } diff --git a/src/session.h b/src/session.h index 55f4a0d8..d487ea40 100644 --- a/src/session.h +++ b/src/session.h @@ -116,7 +116,10 @@ typedef enum { NC_SSH_KEY_UNKNOWN = 0, NC_SSH_KEY_DSA, NC_SSH_KEY_RSA, - NC_SSH_KEY_ECDSA + NC_SSH_KEY_ECDSA, /**< only for private key */ + NC_SSH_KEY_ECDSA_P256, + NC_SSH_KEY_ECDSA_P384, + NC_SSH_KEY_ECDSA_P521 } NC_SSH_KEY_TYPE; /** diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c index 23ee58c6..3bb5faf4 100644 --- a/src/session_client_ssh.c +++ b/src/session_client_ssh.c @@ -311,7 +311,7 @@ nc_client_ssh_get_srv_pubkey_data(ssh_session session, enum ssh_keytypes_e *srv_ ret = ssh_get_publickey(session, &srv_pubkey); #endif if (ret < 0) { - ERR(NULL, "Unable to get server public key."); + ERR(NULL, "Unable to get server's public key."); return -1; } diff --git a/tests/data/id_ecdsa256 b/tests/data/id_ecdsa256 new file mode 100644 index 00000000..6c01edb1 --- /dev/null +++ b/tests/data/id_ecdsa256 @@ -0,0 +1,9 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSGOtimPvmp8jbsK5kLto0HcgfaWGTB +hBsn+c5deY0SQuzhj6vkxqkYMBTqAcpWLbj6xVhpTPs5LalDJ9ffuaj6AAAAqCh4tAQoeL +QEAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIY62KY++anyNuwr +mQu2jQdyB9pYZMGEGyf5zl15jRJC7OGPq+TGqRgwFOoBylYtuPrFWGlM+zktqUMn19+5qP +oAAAAgBf3u7SBWmpDCm7esp1VnpoflXGytRAxp85nsb4Hhbd0AAAANcm9tYW5AcGN2YXNr +bwECAw== +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/data/id_ecdsa256.pub b/tests/data/id_ecdsa256.pub new file mode 100644 index 00000000..169840d0 --- /dev/null +++ b/tests/data/id_ecdsa256.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIY62KY++anyNuwrmQu2jQdyB9pYZMGEGyf5zl15jRJC7OGPq+TGqRgwFOoBylYtuPrFWGlM+zktqUMn19+5qPo= test@libnetconf2 diff --git a/tests/data/id_ecdsa384 b/tests/data/id_ecdsa384 new file mode 100644 index 00000000..38211c73 --- /dev/null +++ b/tests/data/id_ecdsa384 @@ -0,0 +1,10 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS +1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQQSz1JFAWiAmtKwWSyCXdZUwNTS/m+c +CpiUPC3vHZ82S1g2ihbQpN4IAIAAfRTER+rnV5/qClDmCjBsOSIaw86VcIykwAqcNy0x0i +vGoyfpVL4/9CZfVSf/hwITxfbCK5MAAADYCMDKzgjAys4AAAATZWNkc2Etc2hhMi1uaXN0 +cDM4NAAAAAhuaXN0cDM4NAAAAGEEEs9SRQFogJrSsFksgl3WVMDU0v5vnAqYlDwt7x2fNk +tYNooW0KTeCACAAH0UxEfq51ef6gpQ5gowbDkiGsPOlXCMpMAKnDctMdIrxqMn6VS+P/Qm +X1Un/4cCE8X2wiuTAAAAMCpWDy26Bm4HFbLLgn/Jf8iJ/V5V5RXOnW994Jbh2w2b0gT9c5 +CfLHjENUhHF3zI9QAAAA1yb21hbkBwY3Zhc2tvAQID +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/data/id_ecdsa384.pub b/tests/data/id_ecdsa384.pub new file mode 100644 index 00000000..5dbf598b --- /dev/null +++ b/tests/data/id_ecdsa384.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBBLPUkUBaICa0rBZLIJd1lTA1NL+b5wKmJQ8Le8dnzZLWDaKFtCk3ggAgAB9FMRH6udXn+oKUOYKMGw5IhrDzpVwjKTACpw3LTHSK8ajJ+lUvj/0Jl9VJ/+HAhPF9sIrkw== test@libnetconf2 diff --git a/tests/data/id_ecdsa521 b/tests/data/id_ecdsa521 new file mode 100644 index 00000000..1c43f0a8 --- /dev/null +++ b/tests/data/id_ecdsa521 @@ -0,0 +1,12 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS +1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQBdWbNJ1cbOVb9jkjFVe3ef8hM2Jc3 +Fgrx1uScbWjzRyLFELbVxgMdQhVShobGyl28Sw4tQPXBPk2iJuZ1is8Jk0gA89GJqKLAbI +O6MVOc6Swx3jR9VP0jOxEWN0dt+swYkZYPNsmSCtVl49w+li+759b5jIWUKNX+jwLua0DG +oykzIy4AAAEQGOm95hjpveYAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ +AAAIUEAXVmzSdXGzlW/Y5IxVXt3n/ITNiXNxYK8dbknG1o80cixRC21cYDHUIVUoaGxspd +vEsOLUD1wT5NoibmdYrPCZNIAPPRiaiiwGyDujFTnOksMd40fVT9IzsRFjdHbfrMGJGWDz +bJkgrVZePcPpYvu+fW+YyFlCjV/o8C7mtAxqMpMyMuAAAAQgG2S26e7KJI+Old8/A2JPPz +9Lbtwgjb09LYZhkRzCELq/9yjY3HvBEOFF3c5WbEn+Opn+MJP1JmQ5UxEUPybDl+egAAAA +1yb21hbkBwY3Zhc2tvAQIDBAU= +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/data/id_ecdsa521.pub b/tests/data/id_ecdsa521.pub new file mode 100644 index 00000000..f49132a9 --- /dev/null +++ b/tests/data/id_ecdsa521.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAF1Zs0nVxs5Vv2OSMVV7d5/yEzYlzcWCvHW5JxtaPNHIsUQttXGAx1CFVKGhsbKXbxLDi1A9cE+TaIm5nWKzwmTSADz0YmoosBsg7oxU5zpLDHeNH1U/SM7ERY3R236zBiRlg82yZIK1WXj3D6WL7vn1vmMhZQo1f6PAu5rQMajKTMjLg== test@libnetconf2 diff --git a/tests/test_ec.c b/tests/test_ec.c index c9f19002..c8d00058 100644 --- a/tests/test_ec.c +++ b/tests/test_ec.c @@ -1,7 +1,7 @@ /** * @file test_ec.c * @author Roman Janota - * @brief libnetconf2 EC hostkey test + * @brief libnetconf2 EC keys authentication test * * @copyright * Copyright (c) 2023 CESNET, z.s.p.o. @@ -34,69 +34,11 @@ struct ly_ctx *ctx; struct test_state { pthread_barrier_t barrier; + const char *client_username; + const char *client_privkey; + const char *client_pubkey; }; -const char *data = - "\n" - " \n" - " 10\n" - " \n" - " default-ssh\n" - " \n" - " \n" - " 127.0.0.1\n" - " 10005\n" - " \n" - " \n" - " \n" - " \n" - " key\n" - " \n" - " \n" - " ct:ssh-public-key-format\n" - " MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEje+TM7/KHx8zJ4HtVcehRNg6ZXLjeWpXWI7m2x9EeKBX+TgYElq0mIESw88s1HnPrT5AdaWeZymD+MSxd4dzwA==\n" - " ct:ec-private-key-format\n" - " MHcCAQEEIGAq2oW59feizNqqUDqDyuLLQ7f1Y1WQHo5KGVuFhwQ/oAoGCCqGSM49AwEHoUQDQgAEje+TM7/KHx8zJ4HtVcehRNg6ZXLjeWpXWI7m2x9EeKBX+TgYElq0mIESw88s1HnPrT5AdaWeZymD+MSxd4dzwA==\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " test_ec\n" - " \n" - " \n" - " \n" - " test\n" - " ct:ssh-public-key-format\n" - " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " sshpka:ecdsa-sha2-nistp256\n" - " \n" - " \n" - " sshkea:curve25519-sha256\n" - " \n" - " \n" - " sshea:aes256-ctr\n" - " \n" - " \n" - " sshma:hmac-sha2-512\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n"; - static void * server_thread(void *arg) { @@ -130,17 +72,6 @@ server_thread(void *arg) return NULL; } -static int -ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv) -{ - (void)hostname; - (void)session; - (void)priv; - /* skip the knownhost check */ - - return 0; -} - static void * client_thread(void *arg) { @@ -148,21 +79,24 @@ client_thread(void *arg) struct nc_session *session = NULL; struct test_state *state = arg; + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + /* set directory where to search for modules */ ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); /* set ssh username */ - ret = nc_client_ssh_set_username("test_ec"); + ret = nc_client_ssh_set_username(state->client_username); assert_int_equal(ret, 0); /* add client's key pair */ - ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + ret = nc_client_ssh_add_keypair(state->client_pubkey, state->client_privkey); assert_int_equal(ret, 0); pthread_barrier_wait(&state->barrier); /* connect */ - session = nc_connect_ssh("127.0.0.1", 10005, NULL); + session = nc_connect_ssh("127.0.0.1", 10009, NULL); assert_non_null(session); nc_session_free(session, NULL); @@ -171,15 +105,78 @@ client_thread(void *arg) } static void -test_nc_ec(void **state) +test_nc_ec256(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *client; + + /* set specific data for the client */ + assert_non_null(state); + client = *state; + + /* client */ + client->client_username = "test_ec256"; + client->client_pubkey = TESTS_DIR "/data/id_ecdsa256.pub"; + client->client_privkey = TESTS_DIR "/data/id_ecdsa256"; + ret = pthread_create(&tids[0], NULL, client_thread, client); + assert_int_equal(ret, 0); + + /* server */ + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_nc_ec384(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *client; + + /* set specific data for the client */ + assert_non_null(state); + client = *state; + + /* client */ + client->client_username = "test_ec384"; + client->client_pubkey = TESTS_DIR "/data/id_ecdsa384.pub"; + client->client_privkey = TESTS_DIR "/data/id_ecdsa384"; + ret = pthread_create(&tids[0], NULL, client_thread, client); + assert_int_equal(ret, 0); + + /* server */ + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_nc_ec521(void **state) { int ret, i; pthread_t tids[2]; + struct test_state *client; + /* set specific data for the client */ assert_non_null(state); + client = *state; - ret = pthread_create(&tids[0], NULL, client_thread, *state); + /* client */ + client->client_username = "test_ec521"; + client->client_pubkey = TESTS_DIR "/data/id_ecdsa521.pub"; + client->client_privkey = TESTS_DIR "/data/id_ecdsa521"; + ret = pthread_create(&tids[0], NULL, client_thread, client); assert_int_equal(ret, 0); + + /* server */ ret = pthread_create(&tids[1], NULL, server_thread, *state); assert_int_equal(ret, 0); @@ -192,7 +189,7 @@ static int setup_f(void **state) { int ret; - struct lyd_node *tree; + struct lyd_node *tree = NULL; struct test_state *test_state; nc_verbosity(NC_VERB_VERBOSE); @@ -218,8 +215,19 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - /* parse yang data */ - ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + ret = nc_server_config_ssh_new_hostkey(TESTS_DIR "/data/key_ecdsa", NULL, ctx, "endpt", "hostkey", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_ssh_new_address_port("127.0.0.1", "10009", ctx, "endpt", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_ssh_new_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa256.pub", ctx, "endpt", "test_ec256", "pubkey", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_ssh_new_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa384.pub", ctx, "endpt", "test_ec384", "pubkey", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_ssh_new_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa521.pub", ctx, "endpt", "test_ec521", "pubkey", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ @@ -233,9 +241,6 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); - /* skip the knownhost check */ - nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL); - lyd_free_all(tree); return 0; @@ -265,7 +270,9 @@ int main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_nc_ec, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_ec256, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_ec384, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_ec521, setup_f, teardown_f), }; setenv("CMOCKA_TEST_ABORT", "1", 1); From d5f61cbb7534221ea964d614ed8497eda3e40c2c Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 28 Apr 2023 09:03:31 +0200 Subject: [PATCH 019/134] ci UPDATE add workflow for libnetconf3 branch --- .github/workflows/libnetconf3-ci.yml | 185 +++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 .github/workflows/libnetconf3-ci.yml diff --git a/.github/workflows/libnetconf3-ci.yml b/.github/workflows/libnetconf3-ci.yml new file mode 100644 index 00000000..9db5445c --- /dev/null +++ b/.github/workflows/libnetconf3-ci.yml @@ -0,0 +1,185 @@ +name: libnetconf2 CI +on: + push: + branches: + - libnetconf3 + pull_request: + branches: + - libnetconf3 + +env: + DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev + +jobs: + build: + name: ${{ matrix.config.name }} + runs-on: ${{ matrix.config.os }} + strategy: + fail-fast: false + matrix: + config: + - { + name: "Release, gcc", + os: "ubuntu-22.04", + build-type: "Release", + dep-build-type: "Release", + cc: "gcc", + options: "-DENABLE_TESTS=ON -DENABLE_DNSSEC=ON", + packages: "", + snaps: "", + make-prepend: "", + make-target: "" + } + - { + name: "Release, clang", + os: "ubuntu-22.04", + build-type: "Release", + dep-build-type: "Release", + cc: "clang", + options: "-DENABLE_TESTS=ON -DENABLE_DNSSEC=ON", + packages: "", + snaps: "", + make-prepend: "", + make-target: "" + } + - { + name: "Debug, gcc", + os: "ubuntu-22.04", + build-type: "Debug", + dep-build-type: "Release", + cc: "gcc", + options: "-DENABLE_DNSSEC=ON", + packages: "valgrind", + snaps: "", + make-prepend: "", + make-target: "" + } + - { + name: "Debug, clang", + os: "ubuntu-22.04", + build-type: "Debug", + dep-build-type: "Release", + cc: "clang", + options: "-DENABLE_DNSSEC=ON", + # no valgrind because it does not support DWARF5 yet generated by clang 14 + packages: "", + snaps: "", + make-prepend: "", + make-target: "" + } + - { + name: "SSH Only", + os: "ubuntu-22.04", + build-type: "Debug", + dep-build-type: "Release", + cc: "gcc", + options: "-DENABLE_TLS=OFF -DENABLE_SSH=ON", + packages: "valgrind", + snaps: "", + make-prepend: "", + make-target: "" + } + # - { + # name: "TLS Only", + # os: "ubuntu-22.04", + # build-type: "Debug", + # dep-build-type: "Release", + # cc: "gcc", + # options: "-DENABLE_TLS=ON -DENABLE_SSH=OFF", + # packages: "valgrind", + # snaps: "", + # make-prepend: "", + # make-target: "" + # } + # - { + # name: "No SSH nor TLS", + # os: "ubuntu-22.04", + # build-type: "Debug", + # dep-build-type: "Release", + # cc: "gcc", + # options: "-DENABLE_TLS=OFF -DENABLE_SSH=OFF", + # packages: "valgrind", + # snaps: "", + # make-prepend: "", + # make-target: "" + # } + - { + name: "ASAN and UBSAN", + os: "ubuntu-22.04", + build-type: "Debug", + dep-build-type: "Release", + cc: "clang", + options: "-DCMAKE_C_FLAGS=-fsanitize=address,undefined -DENABLE_VALGRIND_TESTS=OFF", + packages: "", + snaps: "", + make-prepend: "", + make-target: "" + } + + steps: + - uses: actions/checkout@v3 + + - name: Deps-packages + shell: bash + run: | + sudo apt-get update + sudo apt-get install $DEFAULT_PACKAGES ${{ matrix.config.packages }} + if ${{ matrix.config.snaps != '' }} + then sudo snap refresh; sudo snap install ${{ matrix.config.snaps }} + fi + + - name: Deps-uncrustify + shell: bash + working-directory: ${{ github.workspace }} + run: | + git clone --branch uncrustify-0.75.1 https://github.com/uncrustify/uncrustify + cd uncrustify + mkdir build + cd build + CC=${{ matrix.config.cc }} cmake .. + make + sudo make install + if: ${{ matrix.config.name == 'Debug, gcc' }} + + - name: Deps-libyang + shell: bash + run: | + git clone -b devel https://github.com/CESNET/libyang.git + cd libyang + mkdir build + cd build + CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.dep-build-type }} -DENABLE_TESTS=OFF .. + make -j2 + sudo make install + + - name: Deps-libval + shell: bash + run: | + git clone https://github.com/DNSSEC-Tools/DNSSEC-Tools.git dnssec-tools + cd dnssec-tools/dnssec-tools/validator + ./configure + make -j2 + sudo make install + + - name: Configure + shell: bash + working-directory: ${{ github.workspace }} + run: | + mkdir build + cd build + CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.build-type }} ${{ matrix.config.options }} .. + + - name: Build + shell: bash + working-directory: ${{ github.workspace }}/build + run: | + export LC_ALL=C.UTF-8 + export PATH=/snap/bin:${{ github.workspace }}/coverity-tools/bin:$PATH + ${{ matrix.config.make-prepend }} make ${{ matrix.config.make-target }} + + - name: Test + shell: bash + working-directory: ${{ github.workspace }}/build + run: | + export LSAN_OPTIONS=suppressions=${{ github.workspace }}/tests/library_lsan.supp + ctest --output-on-failure From efdbb2a31b12588e969df87a5a6ab1a63f56996d Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 28 Apr 2023 10:28:12 +0200 Subject: [PATCH 020/134] configuration UPDATE add transport ifdefs --- src/server_config.c | 18 +++++++++++++++--- src/session_p.h | 35 +++++++++++++++++++++++------------ src/session_server.c | 1 + 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 929209e8..9d4479d8 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -576,12 +576,24 @@ nc_server_config_listen(NC_OPERATION op) if (op == NC_OP_DELETE) { for (i = 0; i < server_opts.endpt_count; i++) { - if (server_opts.endpts[i].ti == NC_TI_LIBSSH) { + switch (server_opts.endpts[i].ti) { +#ifdef NC_ENABLED_SSH + case NC_TI_LIBSSH: nc_server_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]); - } else if (server_opts.endpts[i].ti == NC_TI_OPENSSL) { + break; +#endif +#ifdef NC_ENABLED_TLS + case NC_TI_OPENSSL: /* todo */ - } else { + break; +#endif + case NC_TI_UNIX: nc_server_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]); + break; + case NC_TI_NONE: + case NC_TI_FD: + ERRINT; + return 1; } } } diff --git a/src/session_p.h b/src/session_p.h index 4ac237e3..5ef0e29e 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -32,17 +32,6 @@ #include "session.h" #include "session_client.h" -#ifdef NC_ENABLED_SSH - -# include -# include -# include - -/* seconds */ -# define NC_SSH_TIMEOUT 10 -/* number of all supported authentication methods */ -# define NC_SSH_AUTH_COUNT 3 - /** * Enumeration of diff operation types. */ @@ -53,6 +42,8 @@ typedef enum { NC_OP_REPLACE } NC_OPERATION; +#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) + /** * Enumeration of key or certificate store type. */ @@ -141,6 +132,19 @@ struct nc_keystore { uint16_t sym_key_count; /**< Count of stored symmetric keys. */ }; +#endif + +#ifdef NC_ENABLED_SSH + +# include +# include +# include + +/* seconds */ +# define NC_SSH_TIMEOUT 10 +/* number of all supported authentication methods */ +# define NC_SSH_AUTH_COUNT 3 + /** * @brief Tracks the state of a client's authentication. */ @@ -274,10 +278,12 @@ struct nc_bind { int pollin; /**< Specifies, which sockets to poll on. */ }; +#ifdef NC_ENABLED_SSH + /* ACCESS unlocked */ struct nc_client_ssh_opts { char *knownhosts_path; /**< path to known_hosts file */ - NC_KNOWNHOSTS_MODE knownhosts_mode; /**< implies whether to check known_hosts or not */ + NC_SSH_KNOWNHOSTS_MODE knownhosts_mode; /**< implies whether to check known_hosts or not */ /* SSH authentication method preferences */ struct { @@ -306,6 +312,8 @@ struct nc_client_ssh_opts { char *username; }; +#endif + /* ACCESS unlocked */ struct nc_client_opts { char *schema_searchpath; @@ -391,8 +399,11 @@ struct nc_server_opts { #endif pthread_rwlock_t config_lock; + +#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) struct nc_keystore keystore; /**< store for server's keys/certificates */ struct nc_truststore truststore; /**< store for server client's keys/certificates */ +#endif struct nc_bind *binds; struct nc_endpt { diff --git a/src/session_server.c b/src/session_server.c index 4a646b46..5928b0ba 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -1593,6 +1593,7 @@ nc_ps_poll_session_io(struct nc_session *session, int io_timeout, time_t now_mon int r, ret = 0; #ifdef NC_ENABLED_SSH + ssh_message ssh_msg; struct nc_session *new; #endif From 3fc551c6e591c92f8d491ba47b3a4b5dc3515651 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 28 Apr 2023 15:54:27 +0200 Subject: [PATCH 021/134] server ssh UPDATE client auth with ED25519 keys --- modules/libnetconf2-netconf-server.yang | 8 + src/config_new.c | 4 + src/server_config.c | 2 + src/session.c | 2 + src/session.h | 3 +- tests/CMakeLists.txt | 2 +- tests/data/id_ed25519 | 7 + tests/data/id_ed25519.pub | 1 + tests/test_ed25519.c | 209 ++++++++++++++++++++++++ 9 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 tests/data/id_ed25519 create mode 100644 tests/data/id_ed25519.pub create mode 100644 tests/test_ed25519.c diff --git a/modules/libnetconf2-netconf-server.yang b/modules/libnetconf2-netconf-server.yang index 9d8bbb9b..e38232d1 100644 --- a/modules/libnetconf2-netconf-server.yang +++ b/modules/libnetconf2-netconf-server.yang @@ -7,6 +7,10 @@ module libnetconf2-netconf-server { prefix ncs; } + import ietf-crypto-types { + prefix ct; + } + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { leaf auth-attempts { type uint16; @@ -52,4 +56,8 @@ module libnetconf2-netconf-server { } } } + + identity ed25519-private-key-format { + base ct:private-key-format; + } } diff --git a/src/config_new.c b/src/config_new.c index f8db1da0..e08c58dd 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -251,6 +251,8 @@ nc_server_config_ssh_new_hostkey(const char *privkey_path, const char *pubkey_pa ret = lyd_new_term(new_tree, NULL, "private-key-format", "ietf-crypto-types:rsa-private-key-format", 0, NULL); } else if (EVP_PKEY_is_a(priv_pkey, "EC")) { ret = lyd_new_term(new_tree, NULL, "private-key-format", "ietf-crypto-types:ec-private-key-format", 0, NULL); + } else if (EVP_PKEY_is_a(priv_pkey, "ED25519")) { + ret = lyd_new_term(new_tree, NULL, "private-key-format", "libnetconf2-netconf-server:ed25519-private-key-format", 0, NULL); } else { ERR(NULL, "Private key type not supported."); ret = 1; @@ -619,6 +621,8 @@ nc_server_config_ssh_read_openssh_pubkey(FILE *f, char **pubkey) start += strlen("ecdsa-sha2-nistp384 "); } else if (!strncmp(buffer, "ecdsa-sha2-nistp521 ", 20)) { start += strlen("ecdsa-sha2-nistp521 "); + } else if (!strncmp(buffer, "ssh-ed25519 ", 12)) { + start += strlen("ssh-ed25519 "); } else { ERR(NULL, "Unknown public key type."); ret = 1; diff --git a/src/server_config.c b/src/server_config.c index 9d4479d8..16a635e0 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -1178,6 +1178,8 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op hostkey->key.privkey_type = NC_SSH_KEY_RSA; } else if (!strcmp(format, "ec-private-key-format")) { hostkey->key.privkey_type = NC_SSH_KEY_ECDSA; + } else if (!strcmp(format, "ed25519-private-key-format")) { + hostkey->key.privkey_type = NC_SSH_KEY_ED25519; } else { ERR(NULL, "Private key format (%s) not supported.", format); } diff --git a/src/session.c b/src/session.c index d5d48867..91f996e7 100644 --- a/src/session.c +++ b/src/session.c @@ -131,6 +131,8 @@ nc_keytype2str(NC_SSH_KEY_TYPE type) return "ECDSA_P384"; case NC_SSH_KEY_ECDSA_P521: return "ECDSA_P521"; + case NC_SSH_KEY_ED25519: + return NULL; default: break; } diff --git a/src/session.h b/src/session.h index d487ea40..aab4cac6 100644 --- a/src/session.h +++ b/src/session.h @@ -119,7 +119,8 @@ typedef enum { NC_SSH_KEY_ECDSA, /**< only for private key */ NC_SSH_KEY_ECDSA_P256, NC_SSH_KEY_ECDSA_P384, - NC_SSH_KEY_ECDSA_P521 + NC_SSH_KEY_ECDSA_P521, + NC_SSH_KEY_ED25519 } NC_SSH_KEY_TYPE; /** diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c76bc2fb..2fee7768 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,7 @@ endif() # list of all the tests in each directory #set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages) -set(tests test_two_channels test_keystore test_unix_socket test_config_new test_truststore test_ec) +set(tests test_two_channels test_keystore test_unix_socket test_config_new test_truststore test_ec test_ed25519) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) diff --git a/tests/data/id_ed25519 b/tests/data/id_ed25519 new file mode 100644 index 00000000..df71976d --- /dev/null +++ b/tests/data/id_ed25519 @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACDq+Oq6bYOgbFoTtSTKJrod3LgmJnrjuiXzlD7P2Dt+cAAAAJC1rL1gtay9 +YAAAAAtzc2gtZWQyNTUxOQAAACDq+Oq6bYOgbFoTtSTKJrod3LgmJnrjuiXzlD7P2Dt+cA +AAAEAQm84SEphEUZEbuCRmXrMcYyv70wNEVziE/SbBC6+trOr46rptg6BsWhO1JMomuh3c +uCYmeuO6JfOUPs/YO35wAAAADXJvbWFuQHBjdmFza28= +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/data/id_ed25519.pub b/tests/data/id_ed25519.pub new file mode 100644 index 00000000..533f33f7 --- /dev/null +++ b/tests/data/id_ed25519.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOr46rptg6BsWhO1JMomuh3cuCYmeuO6JfOUPs/YO35w test@libnetconf2 diff --git a/tests/test_ed25519.c b/tests/test_ed25519.c new file mode 100644 index 00000000..08c73256 --- /dev/null +++ b/tests/test_ed25519.c @@ -0,0 +1,209 @@ +/** + * @file test_ed25519.c + * @author Roman Janota + * @brief libnetconf2 ED25519 key authentication test + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 + +struct ly_ctx *ctx; + +struct test_state { + pthread_barrier_t barrier; +}; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + (void) arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_thread_destroy(); + return NULL; +} + +static void * +client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + + /* set directory where to search for modules */ + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set ssh username */ + ret = nc_client_ssh_set_username("test_ed25519"); + assert_int_equal(ret, 0); + + /* add client's key pair */ + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/id_ed25519.pub", TESTS_DIR "/data/id_ed25519"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + /* connect */ + session = nc_connect_ssh("127.0.0.1", 10009, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_ed25519(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + /* client */ + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + + /* server */ + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + /* create new context */ + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* load default modules into context */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf-netconf-server module and it's imports into context */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + ret = nc_server_config_ssh_new_hostkey(TESTS_DIR "/data/server.key", NULL, ctx, "endpt", "hostkey", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_ssh_new_address_port("127.0.0.1", "10009", ctx, "endpt", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_ssh_new_client_auth_pubkey(TESTS_DIR "/data/id_ed25519.pub", ctx, "endpt", "test_ed25519", "pubkey", &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup(tree); + assert_int_equal(ret, 0); + + /* initialize client */ + nc_client_init(); + + /* initialize server */ + ret = nc_server_init(); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_ed25519, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} From 7903e4fa85fe07ce380a80cadd8db07956e6ada4 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 4 May 2023 11:10:22 +0200 Subject: [PATCH 022/134] log UPDATE partially replace ERRARG macro Added new macro, which works just like ERRARG did before, but it can take variadic number (up to 5) of arguments and a session the error happened on. ERRARG still remains and has an extra session argument. --- src/config_new.c | 10 +-- src/log_p.h | 41 ++++++++--- src/messages_client.c | 133 +++++++---------------------------- src/messages_server.c | 148 ++++++++++----------------------------- src/server_config.c | 6 +- src/session.c | 73 +++++-------------- src/session_client.c | 97 +++++++------------------ src/session_client_ssh.c | 24 ++----- src/session_client_tls.c | 22 +++--- src/session_server_ssh.c | 26 ++----- src/session_server_tls.c | 59 +++++----------- 11 files changed, 174 insertions(+), 465 deletions(-) diff --git a/src/config_new.c b/src/config_new.c index e08c58dd..4c30382b 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -185,9 +185,7 @@ nc_server_config_ssh_new_hostkey(const char *privkey_path, const char *pubkey_pa char *tree_path = NULL; EVP_PKEY *priv_pkey = NULL; - if (!privkey_path || !config || !ctx || !endpt_name || !hostkey_name) { - ERRARG("privkey_path or config or ctx or endpt_name or hostkey_name"); - } + NC_CHECK_ARG_RET(NULL, privkey_path, config, ctx, endpt_name, hostkey_name, 1); /* get the keys as a string from the given files */ ret = nc_server_config_ssh_new_get_keys(privkey_path, pubkey_path, &priv_key, &pub_key, &priv_pkey); @@ -291,11 +289,7 @@ nc_server_config_ssh_new_address_port(const char *address, const char *port, con char *tree_path = NULL; struct lyd_node *new_tree, *port_node; - if (!address || !port || !ctx || !endpt_name || !config) { - ERRARG("args"); - ret = 1; - goto cleanup; - } + NC_CHECK_ARG_RET(NULL, address, port, ctx, endpt_name, config, 1); /* prepare path for instertion of leaves later */ asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/tcp-server-parameters", endpt_name); diff --git a/src/log_p.h b/src/log_p.h index 0feb8cce..8bd57c0b 100644 --- a/src/log_p.h +++ b/src/log_p.h @@ -42,21 +42,40 @@ extern ATOMIC_T verbose_level; /* * Verbose printing macros */ -#define ERR(session, format, args ...) prv_printf(session,NC_VERB_ERROR,format,##args) -#define WRN(session, format, args ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_WARNING){prv_printf(session,NC_VERB_WARNING,format,##args);} -#define VRB(session, format, args ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_VERBOSE){prv_printf(session,NC_VERB_VERBOSE,format,##args);} -#define DBG(session, format, args ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_DEBUG){prv_printf(session,NC_VERB_DEBUG,format,##args);} -#define DBL(session, format, args ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_DEBUG_LOWLVL){prv_printf(session,NC_VERB_DEBUG_LOWLVL,format,##args);} +#define ERR(session, ...) prv_printf(session, NC_VERB_ERROR, __VA_ARGS__) +#define WRN(session, ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_WARNING){prv_printf(session, NC_VERB_WARNING, __VA_ARGS__);} +#define VRB(session, ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_VERBOSE){prv_printf(session, NC_VERB_VERBOSE, __VA_ARGS__);} +#define DBG(session, ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_DEBUG){prv_printf(session, NC_VERB_DEBUG, __VA_ARGS__);} +#define DBL(session, ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_DEBUG_LOWLVL){prv_printf(session, NC_VERB_DEBUG_LOWLVL, __VA_ARGS__);} #define ERRMEM ERR(NULL, "%s: memory reallocation failed (%s:%d).", __func__, __FILE__, __LINE__) -#define ERRARG(arg) ERR(NULL, "%s: invalid argument (%s).", __func__, arg) #define ERRINIT ERR(NULL, "%s: libnetconf2 not initialized.", __func__) #define ERRINT ERR(NULL, "%s: internal error (%s:%d).", __func__, __FILE__, __LINE__) #define ERRNODE(name) ERR(NULL, "%s: missing node (%s) in the YANG data.", __func__, name) -#define UNEXNODE(name) VRB(NULL, "%s: unexpected node (%s) in the YANG data.", __func__, name) -#define CHECKNODE(node, name) if (strcmp(LYD_NAME(node), name)) { \ - ERR(NULL, "%s: missing node (%s) in the YANG data.", __func__, name); \ - return 1; \ - } +#define ERRARG(session, ARG) ERR(session, "Invalid argument %s (%s()).", #ARG, __func__) + +#define GETMACRO1(_1, NAME, ...) NAME +#define GETMACRO2(_1, _2, NAME, ...) NAME +#define GETMACRO3(_1, _2, _3, NAME, ...) NAME +#define GETMACRO4(_1, _2, _3, _4, NAME, ...) NAME +#define GETMACRO5(_1, _2, _3, _4, _5, NAME, ...) NAME +#define GETMACRO6(_1, _2, _3, _4, _5, _6, NAME, ...) NAME + +#define NC_CHECK_ARG_RET1(session, ARG, RETVAL) if (!(ARG)) {ERRARG(session, ARG);return RETVAL;} +#define NC_CHECK_ARG_RET2(session, ARG1, ARG2, RETVAL) NC_CHECK_ARG_RET1(session, ARG1, RETVAL);NC_CHECK_ARG_RET1(session, ARG2, RETVAL) +#define NC_CHECK_ARG_RET3(session, ARG1, ARG2, ARG3, RETVAL) NC_CHECK_ARG_RET2(session, ARG1, ARG2, RETVAL);NC_CHECK_ARG_RET1(session, ARG3, RETVAL) +#define NC_CHECK_ARG_RET4(session, ARG1, ARG2, ARG3, ARG4, RETVAL) NC_CHECK_ARG_RET3(session, ARG1, ARG2, ARG3, RETVAL);\ + NC_CHECK_ARG_RET1(session, ARG4, RETVAL) +#define NC_CHECK_ARG_RET5(session, ARG1, ARG2, ARG3, ARG4, ARG5, RETVAL) NC_CHECK_ARG_RET4(session, ARG1, ARG2, ARG3, ARG4, RETVAL);\ + NC_CHECK_ARG_RET1(session, ARG5, RETVAL) + +/** + * @brief Function's parameters checking macro + * + * @param session Session that is logged. + * @param ... Parameters of the function to check. The last parameter is the value that is returned on error. + */ +#define NC_CHECK_ARG_RET(session, ...) GETMACRO6(__VA_ARGS__, NC_CHECK_ARG_RET5, NC_CHECK_ARG_RET4, NC_CHECK_ARG_RET3, \ + NC_CHECK_ARG_RET2, NC_CHECK_ARG_RET1, DUMMY) (session, __VA_ARGS__) #endif /* NC_LOG_PRIVATE_H_ */ diff --git a/src/messages_client.c b/src/messages_client.c index 04c0b3c0..e222dbef 100644 --- a/src/messages_client.c +++ b/src/messages_client.c @@ -32,10 +32,7 @@ const char *rpcedit_erropt2str[] = {NULL, "stop-on-error", "continue-on-error", API NC_RPC_TYPE nc_rpc_get_type(const struct nc_rpc *rpc) { - if (!rpc) { - ERRARG("rpc"); - return 0; - } + NC_CHECK_ARG_RET(NULL, rpc, 0); return rpc->type; } @@ -45,8 +42,9 @@ nc_rpc_act_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype) { struct nc_rpc_act_generic *rpc; - if (!data || data->next || (data->prev != data)) { - ERRARG("data"); + NC_CHECK_ARG_RET(NULL, data, data->next, NULL); + if (data->prev != data) { + ERR(NULL, "nc_rpc_act_generic missing data"); return NULL; } @@ -76,10 +74,7 @@ nc_rpc_act_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype) { struct nc_rpc_act_generic *rpc; - if (!xml_str) { - ERRARG("xml_str"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, xml_str, NULL); rpc = malloc(sizeof *rpc); if (!rpc) { @@ -104,10 +99,7 @@ nc_rpc_getconfig(NC_DATASTORE source, const char *filter, NC_WD_MODE wd_mode, NC { struct nc_rpc_getconfig *rpc; - if (!source) { - ERRARG("source"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, source, NULL); if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) { ERR(NULL, "Filter is neither an XML subtree nor an XPath expression (invalid first char '%c').", filter[0]); @@ -139,13 +131,7 @@ nc_rpc_edit(NC_DATASTORE target, NC_RPC_EDIT_DFLTOP default_op, NC_RPC_EDIT_TEST { struct nc_rpc_edit *rpc; - if (!target) { - ERRARG("target"); - return NULL; - } else if (!edit_content) { - ERRARG("edit_content"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, target, edit_content, NULL); if (edit_content[0] && (edit_content[0] != '<') && !isalpha(edit_content[0])) { ERR(NULL, " content is neither a URL nor an XML config (invalid first char '%c').", edit_content[0]); @@ -179,13 +165,7 @@ nc_rpc_copy(NC_DATASTORE target, const char *url_trg, NC_DATASTORE source, const { struct nc_rpc_copy *rpc; - if (!target) { - ERRARG("target"); - return NULL; - } else if (!source) { - ERRARG("source"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, target, source, NULL); if (url_or_config_src && url_or_config_src[0] && (url_or_config_src[0] != '<') && !isalpha(url_or_config_src[0])) { ERR(NULL, " source is neither a URL nor an XML config (invalid first char '%c').", url_or_config_src[0]); @@ -222,10 +202,7 @@ nc_rpc_delete(NC_DATASTORE target, const char *url, NC_PARAMTYPE paramtype) { struct nc_rpc_delete *rpc; - if (!target) { - ERRARG("target"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, target, NULL); rpc = malloc(sizeof *rpc); if (!rpc) { @@ -250,10 +227,7 @@ nc_rpc_lock(NC_DATASTORE target) { struct nc_rpc_lock *rpc; - if (!target) { - ERRARG("target"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, target, NULL); rpc = malloc(sizeof *rpc); if (!rpc) { @@ -272,10 +246,7 @@ nc_rpc_unlock(NC_DATASTORE target) { struct nc_rpc_lock *rpc; - if (!target) { - ERRARG("target"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, target, NULL); rpc = malloc(sizeof *rpc); if (!rpc) { @@ -322,10 +293,7 @@ nc_rpc_kill(uint32_t session_id) { struct nc_rpc_kill *rpc; - if (!session_id) { - ERRARG("session_id"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, session_id, NULL); rpc = malloc(sizeof *rpc); if (!rpc) { @@ -412,10 +380,7 @@ nc_rpc_validate(NC_DATASTORE source, const char *url_or_config, NC_PARAMTYPE par { struct nc_rpc_validate *rpc; - if (!source) { - ERRARG("source"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, source, NULL); if (url_or_config && url_or_config[0] && (url_or_config[0] != '<') && !isalpha(url_or_config[0])) { ERR(NULL, " source is neither a URL nor an XML config (invalid first char '%c').", url_or_config[0]); @@ -445,10 +410,7 @@ nc_rpc_getschema(const char *identifier, const char *version, const char *format { struct nc_rpc_getschema *rpc; - if (!identifier) { - ERRARG("identifier"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, identifier, NULL); rpc = malloc(sizeof *rpc); if (!rpc) { @@ -528,12 +490,11 @@ nc_rpc_getdata(const char *datastore, const char *filter, const char *config_fil struct nc_rpc_getdata *rpc = NULL; int i; + NC_CHECK_ARG_RET(NULL, datastore, NULL); + if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) { ERR(NULL, "Filter is neither an XML subtree nor an XPath expression (invalid first char '%c').", filter[0]); return NULL; - } else if (!datastore) { - ERRARG("datastore"); - return NULL; } rpc = calloc(1, sizeof *rpc); @@ -594,13 +555,7 @@ nc_rpc_editdata(const char *datastore, NC_RPC_EDIT_DFLTOP default_op, const char { struct nc_rpc_editdata *rpc; - if (!datastore) { - ERRARG("datastore"); - return NULL; - } else if (!edit_content) { - ERRARG("edit_content"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, datastore, edit_content, NULL); if (edit_content[0] && (edit_content[0] != '<') && !isalpha(edit_content[0])) { ERR(NULL, " content is neither a URL nor an XML config (invalid first char '%c').", edit_content[0]); @@ -636,10 +591,7 @@ nc_rpc_establishsub(const char *filter, const char *stream_name, const char *sta { struct nc_rpc_establishsub *rpc; - if (!stream_name) { - ERRARG("stream_name"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, stream_name, NULL); if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) { ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').", @@ -689,10 +641,7 @@ nc_rpc_modifysub(uint32_t id, const char *filter, const char *stop_time, NC_PARA { struct nc_rpc_modifysub *rpc; - if (!id) { - ERRARG("id"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, id, NULL); if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) { ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').", @@ -728,10 +677,7 @@ nc_rpc_deletesub(uint32_t id) { struct nc_rpc_deletesub *rpc; - if (!id) { - ERRARG("id"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, id, NULL); rpc = malloc(sizeof *rpc); if (!rpc) { @@ -750,10 +696,7 @@ nc_rpc_killsub(uint32_t id) { struct nc_rpc_killsub *rpc; - if (!id) { - ERRARG("id"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, id, NULL); rpc = malloc(sizeof *rpc); if (!rpc) { @@ -773,13 +716,7 @@ nc_rpc_establishpush_periodic(const char *datastore, const char *filter, const c { struct nc_rpc_establishpush *rpc; - if (!datastore) { - ERRARG("datastore"); - return NULL; - } else if (!period) { - ERRARG("period"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, datastore, period, NULL); if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) { ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').", @@ -833,10 +770,7 @@ nc_rpc_establishpush_onchange(const char *datastore, const char *filter, const c struct nc_rpc_establishpush *rpc; uint32_t i; - if (!datastore) { - ERRARG("datastore"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, datastore, NULL); if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) { ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').", @@ -895,13 +829,7 @@ nc_rpc_modifypush_periodic(uint32_t id, const char *datastore, const char *filte { struct nc_rpc_modifypush *rpc; - if (!id) { - ERRARG("id"); - return NULL; - } else if (!datastore) { - ERRARG("datastore"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, id, datastore, NULL); if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) { ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').", @@ -950,13 +878,7 @@ nc_rpc_modifypush_onchange(uint32_t id, const char *datastore, const char *filte { struct nc_rpc_modifypush *rpc; - if (!id) { - ERRARG("id"); - return NULL; - } else if (!datastore) { - ERRARG("datastore"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, id, datastore, NULL); if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) { ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').", @@ -999,10 +921,7 @@ nc_rpc_resyncsub(uint32_t id) { struct nc_rpc_resyncsub *rpc; - if (!id) { - ERRARG("id"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, id, NULL); rpc = malloc(sizeof *rpc); if (!rpc) { diff --git a/src/messages_server.c b/src/messages_server.c index 078d0419..7864ebfc 100644 --- a/src/messages_server.c +++ b/src/messages_server.c @@ -49,8 +49,10 @@ nc_server_reply_data(struct lyd_node *data, NC_WD_MODE wd, NC_PARAMTYPE paramtyp { struct nc_server_reply_data *ret; - if (!data || !(data->schema->nodetype & (LYS_RPC | LYS_ACTION))) { - ERRARG("data"); + NC_CHECK_ARG_RET(NULL, data, NULL); + + if (!(data->schema->nodetype & (LYS_RPC | LYS_ACTION))) { + ERR(NULL, "nc_server_reply_data bad data"); return NULL; } @@ -83,10 +85,7 @@ nc_server_reply_err(struct lyd_node *err) { struct nc_server_reply_error *ret; - if (!err) { - ERRARG("err"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, err, NULL); ret = malloc(sizeof *ret); if (!ret) { @@ -104,11 +103,10 @@ nc_server_reply_add_err(struct nc_server_reply *reply, struct lyd_node *err) { struct nc_server_reply_error *err_rpl; - if (!reply || (reply->type != NC_RPL_ERROR)) { - ERRARG("reply"); - return -1; - } else if (!err) { - ERRARG("err"); + NC_CHECK_ARG_RET(NULL, reply, err, -1); + + if (reply->type != NC_RPL_ERROR) { + ERR(NULL, "nc_server_reply_add_err: bad reply type"); return -1; } @@ -122,8 +120,10 @@ nc_server_reply_get_last_err(const struct nc_server_reply *reply) { struct nc_server_reply_error *err_rpl; - if (!reply || (reply->type != NC_RPL_ERROR)) { - ERRARG("reply"); + NC_CHECK_ARG_RET(NULL, reply, NULL); + + if (reply->type != NC_RPL_ERROR) { + ERR(NULL, "nc_server_reply_get_last_err: bad reply type"); return NULL; } @@ -273,10 +273,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...) const char *arg1, *arg2; uint32_t sid; - if (!tag) { - ERRARG("tag"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, tag, NULL); /* rpc-error */ if (lyd_new_opaq2(NULL, ctx, "rpc-error", NULL, NULL, NC_NS_BASE, &err)) { @@ -294,7 +291,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...) case NC_ERR_OP_NOT_SUPPORTED: type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */ if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) { - ERRARG("type"); + ERRARG(NULL, "type"); goto fail; } break; @@ -307,7 +304,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...) case NC_ERR_UNKNOWN_ATTR: type = (NC_ERR_TYPE)va_arg(ap, int); if (type == NC_ERR_TYPE_TRAN) { - ERRARG("type"); + ERRARG(NULL, "type"); goto fail; } break; @@ -316,14 +313,14 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...) case NC_ERR_UNKNOWN_ELEM: type = (NC_ERR_TYPE)va_arg(ap, int); if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) { - ERRARG("type"); + ERRARG(NULL, "type"); goto fail; } break; case NC_ERR_UNKNOWN_NS: type = (NC_ERR_TYPE)va_arg(ap, int); if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) { - ERRARG("type"); + ERRARG(NULL, "type"); goto fail; } break; @@ -337,7 +334,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...) case NC_ERR_OP_FAILED: type = (NC_ERR_TYPE)va_arg(ap, int); if (type == NC_ERR_TYPE_TRAN) { - ERRARG("type"); + ERRARG(NULL, "type"); goto fail; } break; @@ -345,7 +342,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...) type = NC_ERR_TYPE_RPC; break; default: - ERRARG("tag"); + ERRARG(NULL, "tag"); goto fail; } if (lyd_new_opaq2(err, NULL, "error-type", nc_err_type2str(type), NULL, NC_NS_BASE, NULL)) { @@ -422,7 +419,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...) nc_err_set_msg(err, "A message could not be handled because it failed to be parsed correctly.", "en"); break; default: - ERRARG("tag"); + ERRARG(NULL, "tag"); goto fail; } @@ -469,7 +466,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...) nc_err_set_sid(err, sid); break; default: - ERRARG("tag"); + ERRARG(NULL, "tag"); goto fail; } @@ -487,10 +484,7 @@ nc_err_get_type(const struct lyd_node *err) { struct lyd_node *match; - if (!err) { - ERRARG("err"); - return 0; - } + NC_CHECK_ARG_RET(NULL, err, 0); lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &match); if (match) { @@ -505,10 +499,7 @@ nc_err_get_tag(const struct lyd_node *err) { struct lyd_node *match; - if (!err) { - ERRARG("err"); - return 0; - } + NC_CHECK_ARG_RET(NULL, err, 0); lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &match); if (match) { @@ -523,13 +514,7 @@ nc_err_set_app_tag(struct lyd_node *err, const char *error_app_tag) { struct lyd_node *match; - if (!err) { - ERRARG("err"); - return -1; - } else if (!error_app_tag) { - ERRARG("error_app_tag"); - return -1; - } + NC_CHECK_ARG_RET(NULL, err, error_app_tag, -1); /* remove previous node */ lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match); @@ -549,10 +534,7 @@ nc_err_get_app_tag(const struct lyd_node *err) { struct lyd_node *match; - if (!err) { - ERRARG("err"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, err, NULL); lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match); if (match) { @@ -567,13 +549,7 @@ nc_err_set_path(struct lyd_node *err, const char *error_path) { struct lyd_node *match; - if (!err) { - ERRARG("err"); - return -1; - } else if (!error_path) { - ERRARG("error_path"); - return -1; - } + NC_CHECK_ARG_RET(NULL, err, error_path, -1); /* remove previous node */ lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match); @@ -593,10 +569,7 @@ nc_err_get_path(const struct lyd_node *err) { struct lyd_node *match; - if (!err) { - ERRARG("err"); - return 0; - } + NC_CHECK_ARG_RET(NULL, err, NULL); lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match); if (match) { @@ -612,13 +585,7 @@ nc_err_set_msg(struct lyd_node *err, const char *error_message, const char *lang struct lyd_node *match; struct lyd_attr *attr; - if (!err) { - ERRARG("err"); - return -1; - } else if (!error_message) { - ERRARG("error_message"); - return -1; - } + NC_CHECK_ARG_RET(NULL, err, error_message, -1); /* remove previous message */ lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match); @@ -642,10 +609,7 @@ nc_err_get_msg(const struct lyd_node *err) { struct lyd_node *match; - if (!err) { - ERRARG("err"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, err, NULL); lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match); if (match) { @@ -661,10 +625,7 @@ nc_err_set_sid(struct lyd_node *err, uint32_t session_id) struct lyd_node *match, *info; char buf[22]; - if (!err) { - ERRARG("err"); - return -1; - } + NC_CHECK_ARG_RET(NULL, err, -1); /* find error-info */ lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info); @@ -691,13 +652,7 @@ nc_err_add_bad_attr(struct lyd_node *err, const char *attr_name) { struct lyd_node *info; - if (!err) { - ERRARG("err"); - return -1; - } else if (!attr_name) { - ERRARG("attr_name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, err, attr_name, -1); /* find error-info */ lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info); @@ -717,13 +672,7 @@ nc_err_add_bad_elem(struct lyd_node *err, const char *elem_name) { struct lyd_node *info; - if (!err) { - ERRARG("err"); - return -1; - } else if (!elem_name) { - ERRARG("elem_name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, err, elem_name, -1); /* find error-info */ lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info); @@ -743,13 +692,7 @@ nc_err_add_bad_ns(struct lyd_node *err, const char *ns_name) { struct lyd_node *info; - if (!err) { - ERRARG("err"); - return -1; - } else if (!ns_name) { - ERRARG("ns_name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, err, ns_name, -1); /* find error-info */ lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info); @@ -769,13 +712,7 @@ nc_err_add_info_other(struct lyd_node *err, struct lyd_node *other) { struct lyd_node *info; - if (!err) { - ERRARG("err"); - return -1; - } else if (!other) { - ERRARG("other"); - return -1; - } + NC_CHECK_ARG_RET(NULL, err, other, -1); /* find error-info */ lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info); @@ -840,13 +777,7 @@ nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramt struct lyd_node *elem; int found; - if (!event) { - ERRARG("event"); - return NULL; - } else if (!eventtime) { - ERRARG("eventtime"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, event, eventtime, NULL); /* check that there is a notification */ found = 0; @@ -858,7 +789,7 @@ nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramt LYD_TREE_DFS_END(event, elem); } if (!found) { - ERRARG("event"); + ERRARG(NULL, "event"); return NULL; } @@ -900,10 +831,7 @@ nc_server_notif_free(struct nc_server_notif *notif) API const char * nc_server_notif_get_time(const struct nc_server_notif *notif) { - if (!notif) { - ERRARG("notif"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, notif, NULL); return notif->eventtime; } diff --git a/src/server_config.c b/src/server_config.c index 16a635e0..b3ffefe8 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -2884,11 +2884,7 @@ nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path) struct lyd_node *tree = NULL; int ret = 0; - if (!path) { - ERRARG("Missing path parameter."); - ret = 1; - goto cleanup; - } + NC_CHECK_ARG_RET(NULL, path, 1); ret = lyd_parse_data_path(ctx, path, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); if (ret) { diff --git a/src/session.c b/src/session.c index 91f996e7..17c6bea3 100644 --- a/src/session.c +++ b/src/session.c @@ -455,10 +455,7 @@ nc_session_client_msgs_unlock(struct nc_session *session, const char *func) API NC_STATUS nc_session_get_status(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return NC_STATUS_ERR; - } + NC_CHECK_ARG_RET(session, session, NC_STATUS_ERR); return session->status; } @@ -466,10 +463,7 @@ nc_session_get_status(const struct nc_session *session) API NC_SESSION_TERM_REASON nc_session_get_term_reason(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return NC_SESSION_TERM_ERR; - } + NC_CHECK_ARG_RET(session, session, NC_SESSION_TERM_ERR); return session->term_reason; } @@ -477,10 +471,7 @@ nc_session_get_term_reason(const struct nc_session *session) API uint32_t nc_session_get_killed_by(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return 0; - } + NC_CHECK_ARG_RET(session, session, 0); return session->killed_by; } @@ -488,10 +479,7 @@ nc_session_get_killed_by(const struct nc_session *session) API uint32_t nc_session_get_id(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return 0; - } + NC_CHECK_ARG_RET(session, session, 0); return session->id; } @@ -499,10 +487,7 @@ nc_session_get_id(const struct nc_session *session) API int nc_session_get_version(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return -1; - } + NC_CHECK_ARG_RET(session, session, -1); return session->version == NC_VERSION_10 ? 0 : 1; } @@ -510,10 +495,7 @@ nc_session_get_version(const struct nc_session *session) API NC_TRANSPORT_IMPL nc_session_get_ti(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return 0; - } + NC_CHECK_ARG_RET(session, session, 0); return session->ti_type; } @@ -521,10 +503,7 @@ nc_session_get_ti(const struct nc_session *session) API const char * nc_session_get_username(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return NULL; - } + NC_CHECK_ARG_RET(session, session, NULL); return session->username; } @@ -532,10 +511,7 @@ nc_session_get_username(const struct nc_session *session) API const char * nc_session_get_host(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return NULL; - } + NC_CHECK_ARG_RET(session, session, NULL); return session->host; } @@ -543,10 +519,8 @@ nc_session_get_host(const struct nc_session *session) API const char * nc_session_get_path(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return NULL; - } + NC_CHECK_ARG_RET(session, session, NULL); + if (session->ti_type != NC_TI_UNIX) { return NULL; } @@ -557,10 +531,7 @@ nc_session_get_path(const struct nc_session *session) API uint16_t nc_session_get_port(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return 0; - } + NC_CHECK_ARG_RET(session, session, 0); return session->port; } @@ -568,10 +539,7 @@ nc_session_get_port(const struct nc_session *session) API const struct ly_ctx * nc_session_get_ctx(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return NULL; - } + NC_CHECK_ARG_RET(session, session, NULL); return session->ctx; } @@ -580,7 +548,7 @@ API void nc_session_set_data(struct nc_session *session, void *data) { if (!session) { - ERRARG("session"); + ERRARG(NULL, "session"); return; } @@ -590,10 +558,7 @@ nc_session_set_data(struct nc_session *session, void *data) API void * nc_session_get_data(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return NULL; - } + NC_CHECK_ARG_RET(session, session, NULL); return session->data; } @@ -601,10 +566,7 @@ nc_session_get_data(const struct nc_session *session) API int nc_session_is_callhome(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return 0; - } + NC_CHECK_ARG_RET(session, session, 0); if (session->flags & NC_SESSION_CALLHOME) { return 1; @@ -1036,10 +998,7 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version) #define NC_CPBLT_BUF_LEN 4096 char str[NC_CPBLT_BUF_LEN]; - if (!ctx) { - ERRARG("ctx"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, ctx, NULL); cpblts = malloc(size * sizeof *cpblts); if (!cpblts) { diff --git a/src/session_client.c b/src/session_client.c index c850a847..c7ff7ccd 100644 --- a/src/session_client.c +++ b/src/session_client.c @@ -197,7 +197,7 @@ nc_client_set_thread_context(void *context) struct nc_client_context *old, *new; if (!context) { - ERRARG(context); + ERRARG(NULL, "context"); return; } @@ -1384,10 +1384,10 @@ nc_connect_inout(int fdin, int fdout, struct ly_ctx *ctx) struct nc_session *session; if (fdin < 0) { - ERRARG("fdin"); + ERRARG(NULL, "fdin"); return NULL; } else if (fdout < 0) { - ERRARG("fdout"); + ERRARG(NULL, "fdout"); return NULL; } @@ -1437,10 +1437,7 @@ nc_connect_unix(const char *address, struct ly_ctx *ctx) char *buf = NULL; size_t buf_size = 0; - if (address == NULL) { - ERRARG("address"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, address, NULL); sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { @@ -1757,13 +1754,7 @@ nc_client_ch_add_bind_listen(const char *address, uint16_t port, const char *hos { int sock; - if (!address) { - ERRARG("address"); - return -1; - } else if (!port) { - ERRARG("port"); - return -1; - } + NC_CHECK_ARG_RET(NULL, address, port, -1); sock = nc_sock_listen_inet(address, port, &client_opts.ka); if (sock == -1) { @@ -1855,12 +1846,11 @@ nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **session) char *host = NULL; uint16_t port, idx; + NC_CHECK_ARG_RET(NULL, session, -1); + if (!client_opts.ch_binds) { ERRINIT; return -1; - } else if (!session) { - ERRARG("session"); - return -1; } sock = nc_sock_accept_binds(client_opts.ch_binds, client_opts.ch_bind_count, timeout, &host, &port, &idx); @@ -1899,10 +1889,7 @@ nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **session) API const char * const * nc_session_get_cpblts(const struct nc_session *session) { - if (!session) { - ERRARG("session"); - return NULL; - } + NC_CHECK_ARG_RET(session, session, NULL); return (const char * const *)session->opts.client.cpblts; } @@ -1912,13 +1899,7 @@ nc_session_cpblt(const struct nc_session *session, const char *capab) { int i, len; - if (!session) { - ERRARG("session"); - return NULL; - } else if (!capab) { - ERRARG("capab"); - return NULL; - } + NC_CHECK_ARG_RET(session, session, capab, NULL); len = strlen(capab); for (i = 0; session->opts.client.cpblts[i]; ++i) { @@ -1933,8 +1914,10 @@ nc_session_cpblt(const struct nc_session *session, const char *capab) API int nc_session_ntf_thread_running(const struct nc_session *session) { - if (!session || (session->side != NC_CLIENT)) { - ERRARG("session"); + NC_CHECK_ARG_RET(session, session, 0); + + if (session->side != NC_CLIENT) { + ERRARG(NULL, "session"); return 0; } @@ -2356,19 +2339,9 @@ nc_recv_reply(struct nc_session *session, struct nc_rpc *rpc, uint64_t msgid, in { NC_MSG_TYPE ret; - if (!session) { - ERRARG("session"); - return NC_MSG_ERROR; - } else if (!rpc) { - ERRARG("rpc"); - return NC_MSG_ERROR; - } else if (!envp) { - ERRARG("envp"); - return NC_MSG_ERROR; - } else if (!op) { - ERRARG("op"); - return NC_MSG_ERROR; - } else if ((session->status != NC_STATUS_RUNNING) || (session->side != NC_CLIENT)) { + NC_CHECK_ARG_RET(session, session, rpc, envp, op, NC_MSG_ERROR); + + if ((session->status != NC_STATUS_RUNNING) || (session->side != NC_CLIENT)) { ERR(session, "Invalid session to receive RPC replies."); return NC_MSG_ERROR; } @@ -2425,16 +2398,9 @@ recv_notif(struct nc_session *session, int timeout, struct lyd_node **envp, stru API NC_MSG_TYPE nc_recv_notif(struct nc_session *session, int timeout, struct lyd_node **envp, struct lyd_node **op) { - if (!session) { - ERRARG("session"); - return NC_MSG_ERROR; - } else if (!envp) { - ERRARG("envp"); - return NC_MSG_ERROR; - } else if (!op) { - ERRARG("op"); - return NC_MSG_ERROR; - } else if ((session->status != NC_STATUS_RUNNING) || (session->side != NC_CLIENT)) { + NC_CHECK_ARG_RET(session, session, envp, op, NC_MSG_ERROR); + + if ((session->status != NC_STATUS_RUNNING) || (session->side != NC_CLIENT)) { ERR(session, "Invalid session to receive Notifications."); return NC_MSG_ERROR; } @@ -2507,13 +2473,9 @@ nc_recv_notif_dispatch_data(struct nc_session *session, nc_notif_dispatch_clb no pthread_t tid; int ret; - if (!session) { - ERRARG("session"); - return -1; - } else if (!notif_clb) { - ERRARG("notif_clb"); - return -1; - } else if ((session->status != NC_STATUS_RUNNING) || (session->side != NC_CLIENT)) { + NC_CHECK_ARG_RET(session, session, notif_clb, -1); + + if ((session->status != NC_STATUS_RUNNING) || (session->side != NC_CLIENT)) { ERR(session, "Invalid session to receive Notifications."); return -1; } @@ -2599,16 +2561,9 @@ nc_send_rpc(struct nc_session *session, struct nc_rpc *rpc, int timeout, uint64_ char str[11]; uint64_t cur_msgid; - if (!session) { - ERRARG("session"); - return NC_MSG_ERROR; - } else if (!rpc) { - ERRARG("rpc"); - return NC_MSG_ERROR; - } else if (!msgid) { - ERRARG("msgid"); - return NC_MSG_ERROR; - } else if ((session->status != NC_STATUS_RUNNING) || (session->side != NC_CLIENT)) { + NC_CHECK_ARG_RET(session, session, rpc, msgid, NC_MSG_ERROR); + + if ((session->status != NC_STATUS_RUNNING) || (session->side != NC_CLIENT)) { ERR(session, "Invalid session to send RPCs."); return NC_MSG_ERROR; } @@ -3191,7 +3146,7 @@ API void nc_client_session_set_not_strict(struct nc_session *session) { if (session->side != NC_CLIENT) { - ERRARG("session"); + ERRARG(NULL, "session"); return; } diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c index 3bb5faf4..c3c8d1f9 100644 --- a/src/session_client_ssh.c +++ b/src/session_client_ssh.c @@ -920,13 +920,7 @@ _nc_client_ssh_add_keypair(const char *pub_key, const char *priv_key, struct nc_ FILE *key; char line[128]; - if (!pub_key) { - ERRARG("pub_key"); - return -1; - } else if (!priv_key) { - ERRARG("priv_key"); - return -1; - } + NC_CHECK_ARG_RET(NULL, pub_key, priv_key, -1); for (i = 0; i < opts->key_count; ++i) { if (!strcmp(opts->keys[i].pubkey_path, pub_key) || !strcmp(opts->keys[i].privkey_path, priv_key)) { @@ -1000,7 +994,7 @@ static int _nc_client_ssh_del_keypair(int idx, struct nc_client_ssh_opts *opts) { if (idx >= opts->key_count) { - ERRARG("idx"); + ERRARG(NULL, "idx"); return -1; } @@ -1059,10 +1053,10 @@ static int _nc_client_ssh_get_keypair(int idx, const char **pub_key, const char **priv_key, struct nc_client_ssh_opts *opts) { if (idx >= opts->key_count) { - ERRARG("idx"); + ERRARG(NULL, "idx"); return -1; } else if (!pub_key && !priv_key) { - ERRARG("pub_key and priv_key"); + ERRARG(NULL, "pub_key and priv_key"); return -1; } @@ -1566,10 +1560,7 @@ _nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx, struct nc_keepal char *buf = NULL; size_t buf_len = 0; - if (!ssh_session) { - ERRARG("ssh_session"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, ssh_session, NULL); /* prepare session structure */ session = nc_new_session(NC_CLIENT, 0); @@ -1823,10 +1814,7 @@ nc_connect_ssh_channel(struct nc_session *session, struct ly_ctx *ctx) { struct nc_session *new_session, *ptr; - if (!session) { - ERRARG("session"); - return NULL; - } + NC_CHECK_ARG_RET(session, session, NULL); /* prepare session structure */ new_session = nc_new_session(NC_CLIENT, 1); diff --git a/src/session_client_tls.c b/src/session_client_tls.c index f95fd460..94b21b42 100644 --- a/src/session_client_tls.c +++ b/src/session_client_tls.c @@ -262,10 +262,7 @@ nc_client_tls_destroy_opts(void) static int _nc_client_tls_set_cert_key_paths(const char *client_cert, const char *client_key, struct nc_client_tls_opts *opts) { - if (!client_cert) { - ERRARG("client_cert"); - return -1; - } + NC_CHECK_ARG_RET(NULL, client_cert, -1); free(opts->cert_path); free(opts->key_path); @@ -307,7 +304,7 @@ static void _nc_client_tls_get_cert_key_paths(const char **client_cert, const char **client_key, struct nc_client_tls_opts *opts) { if (!client_cert && !client_key) { - ERRARG("client_cert and client_key"); + ERRARG(NULL, "client_cert and client_key"); return; } @@ -335,7 +332,7 @@ static int _nc_client_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir, struct nc_client_tls_opts *opts) { if (!ca_file && !ca_dir) { - ERRARG("ca_file and ca_dir"); + ERRARG(NULL, "ca_file and ca_dir"); return -1; } @@ -383,7 +380,7 @@ static void _nc_client_tls_get_trusted_ca_paths(const char **ca_file, const char **ca_dir, struct nc_client_tls_opts *opts) { if (!ca_file && !ca_dir) { - ERRARG("ca_file and ca_dir"); + ERRARG(NULL, "ca_file and ca_dir"); return; } @@ -411,7 +408,7 @@ static int _nc_client_tls_set_crl_paths(const char *crl_file, const char *crl_dir, struct nc_client_tls_opts *opts) { if (!crl_file && !crl_dir) { - ERRARG("crl_file and crl_dir"); + ERRARG(NULL, "crl_file and crl_dir"); return -1; } @@ -459,7 +456,7 @@ static void _nc_client_tls_get_crl_paths(const char **crl_file, const char **crl_dir, struct nc_client_tls_opts *opts) { if (!crl_file && !crl_dir) { - ERRARG("crl_file and crl_dir"); + ERRARG(NULL, "crl_file and crl_dir"); return; } @@ -757,10 +754,9 @@ nc_connect_libssl(SSL *tls, struct ly_ctx *ctx) { struct nc_session *session; - if (!tls) { - ERRARG("tls"); - return NULL; - } else if (!SSL_is_init_finished(tls)) { + NC_CHECK_ARG_RET(NULL, tls, NULL); + + if (!SSL_is_init_finished(tls)) { ERR(NULL, "Supplied TLS session is not fully connected!"); return NULL; } diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index 34db6585..0b7aad85 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -551,10 +551,7 @@ nc_server_ssh_ch_client_endpt_get_auth_methods(const char *client_name, const ch static int nc_server_ssh_set_auth_attempts(uint16_t auth_attempts, struct nc_server_ssh_opts *opts) { - if (!auth_attempts) { - ERRARG("auth_attempts"); - return -1; - } + NC_CHECK_ARG_RET(NULL, auth_attempts, -1); opts->auth_attempts = auth_attempts; return 0; @@ -604,10 +601,7 @@ nc_server_ssh_ch_client_endpt_set_auth_attempts(const char *client_name, const c static int nc_server_ssh_set_auth_timeout(uint16_t auth_timeout, struct nc_server_ssh_opts *opts) { - if (!auth_timeout) { - ERRARG("auth_timeout"); - return -1; - } + NC_CHECK_ARG_RET(NULL, auth_timeout, -1); opts->auth_timeout = auth_timeout; return 0; @@ -1953,13 +1947,7 @@ nc_session_accept_ssh_channel(struct nc_session *orig_session, struct nc_session struct nc_session *new_session = NULL; struct timespec ts_cur; - if (!orig_session) { - ERRARG("orig_session"); - return NC_MSG_ERROR; - } else if (!session) { - ERRARG("session"); - return NC_MSG_ERROR; - } + NC_CHECK_ARG_RET(orig_session, orig_session, session, NC_MSG_ERROR); if ((orig_session->status == NC_STATUS_RUNNING) && (orig_session->ti_type == NC_TI_LIBSSH) && orig_session->ti.libssh.next) { @@ -2010,13 +1998,7 @@ nc_ps_accept_ssh_channel(struct nc_pollsession *ps, struct nc_session **session) struct timespec ts_cur; uint16_t i; - if (!ps) { - ERRARG("ps"); - return NC_MSG_ERROR; - } else if (!session) { - ERRARG("session"); - return NC_MSG_ERROR; - } + NC_CHECK_ARG_RET(NULL, ps, session, NC_MSG_ERROR); /* LOCK */ if (nc_ps_lock(ps, &q_id, __func__)) { diff --git a/src/session_server_tls.c b/src/session_server_tls.c index 76b3c8ce..0c227ce7 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -920,10 +920,7 @@ nc_server_tls_endpt_set_server_cert(const char *endpt_name, const char *name) int ret; struct nc_endpt *endpt; - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, endpt_name, -1); /* LOCK */ endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); @@ -964,7 +961,7 @@ nc_server_tls_set_server_cert_clb(int (*cert_clb)(const char *name, void *user_d void (*free_user_data)(void *user_data)) { if (!cert_clb) { - ERRARG("cert_clb"); + ERRARG(NULL, "cert_clb"); return; } @@ -978,7 +975,7 @@ nc_server_tls_set_server_cert_chain_clb(int (*cert_chain_clb)(const char *name, int *cert_path_count, char ***cert_data, int *cert_data_count), void *user_data, void (*free_user_data)(void *user_data)) { if (!cert_chain_clb) { - ERRARG("cert_chain_clb"); + ERRARG(NULL, "cert_chain_clb"); return; } @@ -990,10 +987,7 @@ nc_server_tls_set_server_cert_chain_clb(int (*cert_chain_clb)(const char *name, static int nc_server_tls_add_trusted_cert_list(const char *name, struct nc_server_tls_opts *opts) { - if (!name) { - ERRARG("name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, name, -1); ++opts->trusted_cert_list_count; opts->trusted_cert_lists = nc_realloc(opts->trusted_cert_lists, @@ -1013,10 +1007,7 @@ nc_server_tls_endpt_add_trusted_cert_list(const char *endpt_name, const char *na int ret; struct nc_endpt *endpt; - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, endpt_name, -1); /* LOCK */ endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); @@ -1057,7 +1048,7 @@ nc_server_tls_set_trusted_cert_list_clb(int (*cert_list_clb)(const char *name, v void *user_data, void (*free_user_data)(void *user_data)) { if (!cert_list_clb) { - ERRARG("cert_list_clb"); + ERRARG(NULL, "cert_list_clb"); return; } @@ -1104,10 +1095,7 @@ nc_server_tls_endpt_del_trusted_cert_list(const char *endpt_name, const char *na int ret; struct nc_endpt *endpt; - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, endpt_name, -1); /* LOCK */ endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); @@ -1146,7 +1134,7 @@ static int nc_server_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir, struct nc_server_tls_opts *opts) { if (!ca_file && !ca_dir) { - ERRARG("ca_file and ca_dir"); + ERRARG(NULL, "ca_file and ca_dir"); return -1; } @@ -1169,10 +1157,7 @@ nc_server_tls_endpt_set_trusted_ca_paths(const char *endpt_name, const char *ca_ int ret; struct nc_endpt *endpt; - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, endpt_name, -1); /* LOCK */ endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); @@ -1214,7 +1199,7 @@ nc_server_tls_set_crl_paths(const char *crl_file, const char *crl_dir, struct nc X509_LOOKUP *lookup; if (!crl_file && !crl_dir) { - ERRARG("crl_file and crl_dir"); + ERRARG(NULL, "crl_file and crl_dir"); return -1; } @@ -1260,10 +1245,7 @@ nc_server_tls_endpt_set_crl_paths(const char *endpt_name, const char *crl_file, int ret; struct nc_endpt *endpt; - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, endpt_name, -1); /* LOCK */ endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); @@ -1316,7 +1298,7 @@ nc_server_tls_endpt_clear_crls(const char *endpt_name) struct nc_endpt *endpt; if (!endpt_name) { - ERRARG("endpt_name"); + ERRARG(NULL, "endpt_name"); return; } @@ -1410,10 +1392,7 @@ nc_server_tls_endpt_add_ctn(const char *endpt_name, uint32_t id, const char *fin int ret; struct nc_endpt *endpt; - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, endpt_name, -1); /* LOCK */ endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); @@ -1508,10 +1487,7 @@ nc_server_tls_endpt_del_ctn(const char *endpt_name, int64_t id, const char *fing int ret; struct nc_endpt *endpt; - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, endpt_name, -1); /* LOCK */ endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); @@ -1596,10 +1572,7 @@ nc_server_tls_endpt_get_ctn(const char *endpt_name, uint32_t *id, char **fingerp int ret; struct nc_endpt *endpt; - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } + NC_CHECK_ARG_RET(NULL, endpt_name, -1); /* LOCK */ endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); @@ -1639,7 +1612,7 @@ API const X509 * nc_session_get_client_cert(const struct nc_session *session) { if (!session || (session->side != NC_SERVER)) { - ERRARG("session"); + ERRARG(session, "session"); return NULL; } From 4d3420ff20594e950b980403b8489079022020bb Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 5 May 2023 16:14:37 +0200 Subject: [PATCH 023/134] ssh UPDATE add new private key identities Added support for new privkey identities - PKCS8 and OpenSSH, which are missing in the ietf-netconf-server model. Renamed config_new to config_new_ssh. --- CMakeLists.txt | 2 +- examples/server.c | 6 +- modules/libnetconf2-netconf-server.yang | 66 +++ src/config_new.h | 56 -- src/{config_new.c => config_new_ssh.c} | 737 ++++++++++++++---------- src/config_new_ssh.h | 89 +++ src/server_config.c | 20 +- src/server_config.h | 20 +- src/session_p.h | 12 +- src/session_server.c | 2 +- tests/test_config_new.c | 8 +- tests/test_ec.c | 10 +- tests/test_ed25519.c | 6 +- 13 files changed, 630 insertions(+), 404 deletions(-) delete mode 100644 src/config_new.h rename src/{config_new.c => config_new_ssh.c} (65%) create mode 100644 src/config_new_ssh.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e20d2907..e2efc0e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,7 @@ set(libsrc src/session_client.c src/session_server.c src/server_config.c - src/config_new.c) + src/config_new_ssh.c) if(ENABLE_SSH) list(APPEND libsrc diff --git a/examples/server.c b/examples/server.c index 6c94b8ec..c28db625 100644 --- a/examples/server.c +++ b/examples/server.c @@ -238,19 +238,19 @@ init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_T /* this is where the YANG configuration data gets generated, * start by creating hostkey configuration data */ - rc = nc_server_config_ssh_new_hostkey(hostkey_path, NULL, *context, "endpt", "hostkey", &config); + rc = nc_server_config_new_ssh_hostkey(hostkey_path, NULL, *context, "endpt", "hostkey", &config); if (rc) { ERR_MSG_CLEANUP("Error creating new hostkey configuration data.\n"); } /* create address and port configuration data */ - rc = nc_server_config_ssh_new_address_port(SSH_ADDRESS, SSH_PORT, *context, "endpt", &config); + rc = nc_server_config_new_ssh_address_port(SSH_ADDRESS, SSH_PORT, *context, "endpt", &config); if (rc) { ERR_MSG_CLEANUP("Error creating new address and port configuration data.\n"); } /* create client authentication configuration data */ - rc = nc_server_config_ssh_new_client_auth_password(SSH_PASSWORD, *context, "endpt", SSH_USERNAME, &config); + rc = nc_server_config_new_ssh_client_auth_password(SSH_PASSWORD, *context, "endpt", SSH_USERNAME, &config); if (rc) { ERR_MSG_CLEANUP("Error creating client authentication configuration data.\n"); } diff --git a/modules/libnetconf2-netconf-server.yang b/modules/libnetconf2-netconf-server.yang index e38232d1..c9994bec 100644 --- a/modules/libnetconf2-netconf-server.yang +++ b/modules/libnetconf2-netconf-server.yang @@ -57,7 +57,73 @@ module libnetconf2-netconf-server { } } +/* identity ed25519-private-key-format { base ct:private-key-format; + description + "This identity would indicate that the + private key is encoded in a ED25519PrivateKey + format. However no such format is currently + standardized or even exists. + + If you wish to use a private key that uses + an ED25519 algorithm, you need to pick either + the private-key-info-format or + openssh-private-key-format identity."; + } +*/ + + identity private-key-info-format { + base ct:private-key-format; + description + "Indicates that the private key is encoded + as a PrivateKeyInfo structure (from RFC 5208). + + The expected header of the private key: + -----BEGIN PRIVATE KEY----- + The expected footer of the private key: + -----END PRIVATE KEY----- + + Supported private key algorithms to use with + this format are: RSA, EC and ED25519. + + Commonly used public key format for this + type of private key is represented by the + SubjectPublicKeyInfo identity."; + + reference + "RFC 5208: PKCS #8: Private-Key Information + Syntax Specification Version 1.2"; + } + + identity openssh-private-key-format { + base ct:private-key-format; + description + "Indicates that the private key is encoded + in the OpenSSH format. + + The expected header of the private key: + -----BEGIN OPENSSH PRIVATE KEY----- + The expected footer of the private key: + -----END OPENSSH PRIVATE KEY----- + + Supported private key algorithms to use with + this format are: RSA, EC and ED25519. + + Commonly used public key format for this + type of private key is either the + SSH2 public key format (from RFC 4716) + or the Public key format defined in RFC 4253, + Section 6.6."; + + reference + "The OpenSSH Private Key Format: + https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key + + RFC 4716: + The Secure Shell (SSH) Public Key File Format + + RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; } } diff --git a/src/config_new.h b/src/config_new.h deleted file mode 100644 index 457be852..00000000 --- a/src/config_new.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file config_new.h - * @author Roman Janota - * @brief libnetconf2 server new configuration creation - * - * @copyright - * Copyright (c) 2015 - 2021 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_NEW_H_ -#define NC_CONFIG_NEW_H_ - -#include - -#include "session_p.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - NC_ALG_HOSTKEY, - NC_ALG_KEY_EXCHANGE, - NC_ALG_ENCRYPTION, - NC_ALG_MAC -} NC_ALG_TYPE; - -/** - * @brief Configures the listen subtree in the ietf-netconf-server module. - * - * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. - * @return 0 on success, 1 on error. - */ -int nc_server_config_listen(NC_OPERATION op); - -/** - * @brief Deletes everything stored in the keystore. - */ -void nc_server_config_del_keystore(void); - -/** - * @brief Deletes everything stored in the truststore. - */ -void nc_server_config_del_trustore(void); - -#ifdef __cplusplus -} -#endif - -#endif /* NC_CONFIG_NEW_H_ */ diff --git a/src/config_new.c b/src/config_new_ssh.c similarity index 65% rename from src/config_new.c rename to src/config_new_ssh.c index 4c30382b..dd18b96f 100644 --- a/src/config_new.c +++ b/src/config_new_ssh.c @@ -1,10 +1,10 @@ /** - * @file config_new.c + * @file config_new_ssh.c * @author Roman Janota * @brief libnetconf2 server new configuration creation functions * * @copyright - * Copyright (c) 2015 - 2021 CESNET, z.s.p.o. + * Copyright (c) 2023 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. @@ -30,7 +30,7 @@ #include #include "compat.h" -#include "config_new.h" +#include "config_new_ssh.h" #include "libnetconf.h" #include "server_config.h" #include "session_server.h" @@ -40,57 +40,238 @@ extern pthread_mutex_t crypt_lock; #endif static int -nc_server_config_ssh_new_get_keys(const char *privkey_path, const char *pubkey_path, - char **privkey, char **pubkey, EVP_PKEY **priv_pkey_p) +nc_server_config_new_ssh_read_ssh2_pubkey(FILE *f, char **pubkey) { + char *buffer = NULL; + size_t size = 0, pubkey_len = 0; + void *tmp; + ssize_t read; int ret = 0; - EVP_PKEY *priv_pkey = NULL, *pub_pkey = NULL; - FILE *f_privkey = NULL, *f_pubkey = NULL; - BIO *bio_pub = NULL, *bio_priv = NULL; - int pub_len, priv_len; - - assert(privkey_path); - assert(privkey); - assert(pubkey); - assert(priv_pkey_p); - *privkey = NULL; + + while ((read = getline(&buffer, &size, f)) > 0) { + if (!strncmp(buffer, "----", 4)) { + continue; + } + + if (!strncmp(buffer, "Comment:", 8)) { + continue; + } + + if (buffer[read - 1] == '\n') { + read--; + } + + tmp = realloc(*pubkey, pubkey_len + read + 1); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + + *pubkey = tmp; + memcpy(*pubkey + pubkey_len, buffer, read); + pubkey_len += read; + } + + if (!pubkey_len) { + ERR(NULL, "Unexpected public key format."); + ret = 1; + goto cleanup; + } + + (*pubkey)[pubkey_len] = '\0'; + +cleanup: + free(buffer); + return ret; +} + +static int +nc_server_config_new_ssh_read_pubkey_openssl(FILE *f, char **pubkey) +{ + int ret = 0; + EVP_PKEY *pkey; + BIO *bio; + char *key = NULL; + int pub_len; + + /* read the pubkey from file */ + pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL); + if (!pkey) { + ret = -1; + goto cleanup; + } + + bio = BIO_new(BIO_s_mem()); + if (!bio) { + ret = -1; + goto cleanup; + } + + /* write the pubkey into bio */ + ret = PEM_write_bio_PUBKEY(bio, pkey); + if (!ret) { + ret = -1; + goto cleanup; + } + + pub_len = BIO_pending(bio); + if (pub_len <= 0) { + ret = -1; + goto cleanup; + } + + /* get pubkey's length */ + key = malloc(pub_len + 1); + if (!key) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* read the public key from bio */ + ret = BIO_read(bio, key, pub_len); + if (ret <= 0) { + ret = -1; + goto cleanup; + } + key[pub_len] = '\0'; + + /* strip the pubkey of the header and footer */ + *pubkey = strdup(key + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER)); + if (!*pubkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + + (*pubkey)[strlen(*pubkey) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER)] = '\0'; + + ret = 0; +cleanup: + if (ret == -1) { + ERR(NULL, "Error getting public key from file (OpenSSL Error): \"%s\".", ERR_reason_error_string(ERR_get_error())); + ret = 1; + } + + BIO_free(bio); + EVP_PKEY_free(pkey); + free(key); + + return ret; +} + +static int +nc_server_config_new_ssh_read_pubkey_libssh(const char *pubkey_path, char **pubkey) +{ + int ret = 0; + ssh_key pub_sshkey = NULL; + + ret = ssh_pki_import_pubkey_file(pubkey_path, &pub_sshkey); + if (ret) { + ERR(NULL, "Importing public key from file \"%s\" failed.", pubkey_path); + return ret; + } + + ret = ssh_pki_export_pubkey_base64(pub_sshkey, pubkey); + if (ret) { + ERR(NULL, "Exporting public key to base64 failed."); + } + + ssh_key_free(pub_sshkey); + return ret; +} + +static int +nc_server_config_new_ssh_get_pubkey(const char *pubkey_path, char **pubkey, NC_SSH_PUBKEY_TYPE *pubkey_type) +{ + int ret = 0; + FILE *f = NULL; + char *header = NULL; + size_t len = 0; + + NC_CHECK_ARG_RET(NULL, pubkey, pubkey_type, 1); + *pubkey = NULL; - *priv_pkey_p = NULL; - /* get private key first */ - f_privkey = fopen(privkey_path, "r"); - if (!f_privkey) { - ERR(NULL, "Unable to open file \"%s\".", privkey_path); + f = fopen(pubkey_path, "r"); + if (!f) { + ERR(NULL, "Unable to open file \"%s\".", pubkey_path); ret = 1; goto cleanup; } - priv_pkey = PEM_read_PrivateKey(f_privkey, NULL, NULL, NULL); - if (!priv_pkey) { + if (getline(&header, &len, f) < 0) { + ERR(NULL, "Error reading header from file \"%s\".", pubkey_path); + ret = 1; + goto cleanup; + } + rewind(f); + + if (!strncmp(header, NC_SUBJECT_PUBKEY_INFO_HEADER, strlen(NC_SUBJECT_PUBKEY_INFO_HEADER))) { + /* it's subject public key info public key */ + ret = nc_server_config_new_ssh_read_pubkey_openssl(f, pubkey); + *pubkey_type = NC_SSH_PUBKEY_X509; + } else if (!strncmp(header, NC_SSH2_PUBKEY_HEADER, strlen(NC_SSH2_PUBKEY_HEADER))) { + /* it's ssh2 public key */ + ret = nc_server_config_new_ssh_read_ssh2_pubkey(f, pubkey); + *pubkey_type = NC_SSH_PUBKEY_SSH2; + } else { + /* it's probably OpenSSH public key */ + ret = nc_server_config_new_ssh_read_pubkey_libssh(pubkey_path, pubkey); + *pubkey_type = NC_SSH_PUBKEY_SSH2; + } + + if (ret) { + ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path); + goto cleanup; + } + +cleanup: + if (f) { + fclose(f); + } + + free(header); + + return ret; +} + +static int +nc_server_config_new_ssh_get_privkey_openssl(FILE *f, char **privkey, EVP_PKEY **priv_pkey) +{ + int ret = 0, priv_len; + BIO *bio = NULL; + + NC_CHECK_ARG_RET(NULL, privkey, priv_pkey, 1); + + /* read private key from file */ + *priv_pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL); + if (!*priv_pkey) { ret = -1; goto cleanup; } - /* set out param */ - *priv_pkey_p = priv_pkey; - bio_priv = BIO_new(BIO_s_mem()); - if (!bio_priv) { + bio = BIO_new(BIO_s_mem()); + if (!bio) { ret = -1; goto cleanup; } - ret = PEM_write_bio_PrivateKey(bio_priv, priv_pkey, NULL, NULL, 0, NULL, NULL); + /* write the private key in to bio */ + ret = PEM_write_bio_PrivateKey(bio, *priv_pkey, NULL, NULL, 0, NULL, NULL); if (!ret) { ret = -1; goto cleanup; } - priv_len = BIO_pending(bio_priv); + priv_len = BIO_pending(bio); if (priv_len <= 0) { ret = -1; goto cleanup; } + /* get private key's length */ *privkey = malloc(priv_len + 1); if (!*privkey) { ERRMEM; @@ -98,46 +279,44 @@ nc_server_config_ssh_new_get_keys(const char *privkey_path, const char *pubkey_p goto cleanup; } - ret = BIO_read(bio_priv, *privkey, priv_len); + /* read the private key from bio */ + ret = BIO_read(bio, *privkey, priv_len); if (ret <= 0) { ret = -1; goto cleanup; } (*privkey)[priv_len] = '\0'; - /* if public key is supplied, then read it */ - if (pubkey_path) { - f_pubkey = fopen(pubkey_path, "r"); - if (!f_pubkey) { - ERR(NULL, "Unable to open file \"%s\"", pubkey_path); - ret = 1; - goto cleanup; - } - pub_pkey = PEM_read_PUBKEY(f_pubkey, NULL, NULL, NULL); - if (!pub_pkey) { - ret = -1; - goto cleanup; - } + ret = 0; +cleanup: + if (ret < 0) { + ERR(NULL, "Getting private key from file failed (%s).", ERR_reason_error_string(ERR_get_error())); } + BIO_free(bio); + return ret; +} + +static int +nc_server_config_new_ssh_privkey_to_pubkey_openssl(EVP_PKEY *priv_pkey, char **pubkey) +{ + int ret = 0, pub_len; + BIO *bio = NULL; - bio_pub = BIO_new(BIO_s_mem()); - if (!bio_pub) { + bio = BIO_new(BIO_s_mem()); + if (!bio) { ret = -1; goto cleanup; } - /* get public key either from the private key or from the given file */ - if (pubkey_path) { - ret = PEM_write_bio_PUBKEY(bio_pub, pub_pkey); - } else { - ret = PEM_write_bio_PUBKEY(bio_pub, priv_pkey); - } + /* write the pubkey into bio */ + ret = PEM_write_bio_PUBKEY(bio, priv_pkey); if (!ret) { ret = -1; goto cleanup; } - pub_len = BIO_pending(bio_pub); + /* get the length of the pubkey */ + pub_len = BIO_pending(bio); if (pub_len <= 0) { ret = -1; goto cleanup; @@ -150,7 +329,8 @@ nc_server_config_ssh_new_get_keys(const char *privkey_path, const char *pubkey_p goto cleanup; } - ret = BIO_read(bio_pub, *pubkey, pub_len); + /* read the pubkey from the bio */ + ret = BIO_read(bio, *pubkey, pub_len); if (ret <= 0) { ret = -1; goto cleanup; @@ -158,37 +338,170 @@ nc_server_config_ssh_new_get_keys(const char *privkey_path, const char *pubkey_p (*pubkey)[pub_len] = '\0'; ret = 0; + cleanup: if (ret < 0) { - ERR(NULL, "Error getting keys from file: \"%s\".", ERR_reason_error_string(ERR_get_error())); + ERR(NULL, "Converting private to public key failed (%s).", ERR_reason_error_string(ERR_get_error())); + } + BIO_free(bio); + return ret; +} + +static int +nc_server_config_new_ssh_privkey_to_pubkey_libssh(const ssh_key priv_sshkey, char **pubkey) +{ + int ret; + ssh_key pub_sshkey = NULL; + + ret = ssh_pki_export_privkey_to_pubkey(priv_sshkey, &pub_sshkey); + if (ret) { + ERR(NULL, "Exporting privkey to pubkey failed."); + return ret; + } + + ret = ssh_pki_export_pubkey_base64(pub_sshkey, pubkey); + if (ret) { + ERR(NULL, "Exporting pubkey to base64 failed."); + } + + ssh_key_free(pub_sshkey); + return ret; +} + +static int +nc_server_config_new_ssh_privkey_to_pubkey(EVP_PKEY *priv_pkey, const ssh_key priv_sshkey, NC_PRIVKEY_FORMAT privkey_type, char **pubkey, NC_SSH_PUBKEY_TYPE *pubkey_type) +{ + switch (privkey_type) { + case NC_PRIVKEY_FORMAT_RSA: + case NC_PRIVKEY_FORMAT_EC: + case NC_PRIVKEY_FORMAT_OPENSSH: + *pubkey_type = NC_SSH_PUBKEY_SSH2; + return nc_server_config_new_ssh_privkey_to_pubkey_libssh(priv_sshkey, pubkey); + case NC_PRIVKEY_FORMAT_PKCS8: + *pubkey_type = NC_SSH_PUBKEY_X509; + return nc_server_config_new_ssh_privkey_to_pubkey_openssl(priv_pkey, pubkey); + } + + return 1; +} + +static int +nc_server_config_new_ssh_get_privkey_libssh(const char *privkey_path, char **privkey, ssh_key *priv_sshkey) +{ + int ret; + + *priv_sshkey = NULL; + + ret = ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, priv_sshkey); + if (ret) { + ERR(NULL, "Importing privkey from file \"%s\" failed.", privkey_path); + return ret; + } + + ret = ssh_pki_export_privkey_base64(*priv_sshkey, NULL, NULL, NULL, privkey); + if (ret) { + ERR(NULL, "Exporting privkey from file \"%s\" to base64 failed.", privkey_path); + } + + return ret; +} + +static int +nc_server_config_new_ssh_get_keys(const char *privkey_path, const char *pubkey_path, + char **privkey, char **pubkey, NC_PRIVKEY_FORMAT *privkey_type, NC_SSH_PUBKEY_TYPE *pubkey_type) +{ + int ret = 0; + EVP_PKEY *priv_pkey = NULL; + ssh_key priv_sshkey = NULL; + FILE *f_privkey = NULL; + char *header = NULL; + size_t len = 0; + + NC_CHECK_ARG_RET(NULL, privkey_path, privkey, pubkey, privkey_type, 1); + + *privkey = NULL; + *pubkey = NULL; + + /* get private key first */ + f_privkey = fopen(privkey_path, "r"); + if (!f_privkey) { + ERR(NULL, "Unable to open file \"%s\".", privkey_path); ret = 1; + goto cleanup; } - EVP_PKEY_free(pub_pkey); + + if (getline(&header, &len, f_privkey) < 0) { + ERR(NULL, "Error reading header from file \"%s\".", privkey_path); + ret = 1; + goto cleanup; + } + rewind(f_privkey); + + if (!strncmp(header, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) { + /* it's PKCS8 (X.509) private key */ + *privkey_type = NC_PRIVKEY_FORMAT_PKCS8; + ret = nc_server_config_new_ssh_get_privkey_openssl(f_privkey, privkey, &priv_pkey); + } else if (!strncmp(header, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) { + /* it's OpenSSH private key */ + *privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; + ret = nc_server_config_new_ssh_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); + } else if (!strncmp(header, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) { + /* it's RSA privkey in PKCS1 format */ + *privkey_type = NC_PRIVKEY_FORMAT_RSA; + ret = nc_server_config_new_ssh_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); + } else if (!strncmp(header, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) { + /* it's EC privkey in SEC1 format */ + *privkey_type = NC_PRIVKEY_FORMAT_EC; + ret = nc_server_config_new_ssh_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); + } else { + ERR(NULL, "Private key format not supported."); + ret = 1; + goto cleanup; + } + + if (ret) { + goto cleanup; + } + + if (pubkey_path) { + ret = nc_server_config_new_ssh_get_pubkey(pubkey_path, pubkey, pubkey_type); + } else { + ret = nc_server_config_new_ssh_privkey_to_pubkey(priv_pkey, priv_sshkey, *privkey_type, pubkey, pubkey_type); + } + + if (ret) { + ERR(NULL, "Getting public key failed."); + goto cleanup; + } + +cleanup: if (f_privkey) { fclose(f_privkey); } - if (f_pubkey) { - fclose(f_pubkey); - } - BIO_free(bio_priv); - BIO_free(bio_pub); + + free(header); + + ssh_key_free(priv_sshkey); + EVP_PKEY_free(priv_pkey); + return ret; } API int -nc_server_config_ssh_new_hostkey(const char *privkey_path, const char *pubkey_path, const struct ly_ctx *ctx, +nc_server_config_new_ssh_hostkey(const char *privkey_path, const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, struct lyd_node **config) { int ret = 0; - char *pub_key = NULL, *priv_key = NULL, *pub_key_stripped, *priv_key_stripped; + char *pubkey = NULL, *privkey = NULL, *pubkey_stripped, *privkey_stripped; struct lyd_node *new_tree; char *tree_path = NULL; - EVP_PKEY *priv_pkey = NULL; + NC_PRIVKEY_FORMAT privkey_type; + NC_SSH_PUBKEY_TYPE pubkey_type; NC_CHECK_ARG_RET(NULL, privkey_path, config, ctx, endpt_name, hostkey_name, 1); /* get the keys as a string from the given files */ - ret = nc_server_config_ssh_new_get_keys(privkey_path, pubkey_path, &priv_key, &pub_key, &priv_pkey); + ret = nc_server_config_new_ssh_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); if (ret) { ERR(NULL, "Getting keys from file(s) failed."); goto cleanup; @@ -225,7 +538,7 @@ nc_server_config_ssh_new_hostkey(const char *privkey_path, const char *pubkey_pa } /* insert pubkey format */ - if (!strstr(pub_key, "---- BEGIN SSH2 PUBLIC KEY ----")) { + if (pubkey_type == NC_SSH_PUBKEY_SSH2) { ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:ssh-public-key-format", 0, NULL); } else { ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:subject-public-key-info-format", 0, NULL); @@ -234,35 +547,51 @@ nc_server_config_ssh_new_hostkey(const char *privkey_path, const char *pubkey_pa goto cleanup; } - /* strip pubkey's header and footer */ - pub_key_stripped = pub_key + strlen("-----BEGIN PUBLIC KEY-----") + 1; - pub_key_stripped[strlen(pub_key_stripped) - strlen("-----END PUBLIC KEY-----") - 2] = '\0'; + /* strip pubkey's header and footer only if it's generated from pkcs8 key (using OpenSSL), + * otherwise it's already stripped + */ + if (!pubkey_path && (privkey_type == NC_PRIVKEY_FORMAT_PKCS8)) { + pubkey_stripped = pubkey + strlen("-----BEGIN PUBLIC KEY-----") + 1; + pubkey_stripped[strlen(pubkey_stripped) - strlen("-----END PUBLIC KEY-----") - 2] = '\0'; + } else { + pubkey_stripped = pubkey; + } /* insert pubkey b64 */ - ret = lyd_new_term(new_tree, NULL, "public-key", pub_key_stripped, 0, NULL); + ret = lyd_new_term(new_tree, NULL, "public-key", pubkey_stripped, 0, NULL); if (ret) { goto cleanup; } - /* do the same for private key */ - if (EVP_PKEY_is_a(priv_pkey, "RSA")) { + /* insert private key format */ + if (privkey_type == NC_PRIVKEY_FORMAT_RSA) { ret = lyd_new_term(new_tree, NULL, "private-key-format", "ietf-crypto-types:rsa-private-key-format", 0, NULL); - } else if (EVP_PKEY_is_a(priv_pkey, "EC")) { + } else if (privkey_type == NC_PRIVKEY_FORMAT_EC) { ret = lyd_new_term(new_tree, NULL, "private-key-format", "ietf-crypto-types:ec-private-key-format", 0, NULL); - } else if (EVP_PKEY_is_a(priv_pkey, "ED25519")) { - ret = lyd_new_term(new_tree, NULL, "private-key-format", "libnetconf2-netconf-server:ed25519-private-key-format", 0, NULL); + } else if (privkey_type == NC_PRIVKEY_FORMAT_PKCS8) { + ret = lyd_new_term(new_tree, NULL, "private-key-format", "libnetconf2-netconf-server:subject-private-key-info-format", 0, NULL); + } else if (privkey_type == NC_PRIVKEY_FORMAT_OPENSSH) { + ret = lyd_new_term(new_tree, NULL, "private-key-format", "libnetconf2-netconf-server:openssh-private-key-format", 0, NULL); } else { ERR(NULL, "Private key type not supported."); ret = 1; } + if (ret) { goto cleanup; } - priv_key_stripped = priv_key + strlen("-----BEGIN PRIVATE KEY-----") + 1; - priv_key_stripped[strlen(priv_key_stripped) - strlen("-----END PRIVATE KEY-----") - 2] = '\0'; + if (privkey_type == NC_PRIVKEY_FORMAT_OPENSSH) { + /* only OpenSSH private keys have different header and footer after processing */ + privkey_stripped = privkey + strlen(NC_OPENSSH_PRIVKEY_HEADER); + privkey_stripped[strlen(privkey_stripped) - strlen(NC_OPENSSH_PRIVKEY_FOOTER)] = '\0'; + } else { + /* the rest share the same header and footer */ + privkey_stripped = privkey + strlen(NC_PKCS8_PRIVKEY_HEADER); + privkey_stripped[strlen(privkey_stripped) - strlen(NC_PKCS8_PRIVKEY_FOOTER)] = '\0'; + } - ret = lyd_new_term(new_tree, NULL, "cleartext-private-key", priv_key_stripped, 0, NULL); + ret = lyd_new_term(new_tree, NULL, "cleartext-private-key", privkey_stripped, 0, NULL); if (ret) { goto cleanup; } @@ -274,15 +603,14 @@ nc_server_config_ssh_new_hostkey(const char *privkey_path, const char *pubkey_pa } cleanup: - EVP_PKEY_free(priv_pkey); - free(priv_key); - free(pub_key); + free(privkey); + free(pubkey); free(tree_path); return ret; } API int -nc_server_config_ssh_new_address_port(const char *address, const char *port, const struct ly_ctx *ctx, +nc_server_config_new_ssh_address_port(const char *address, const char *port, const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config) { int ret = 0; @@ -348,7 +676,7 @@ nc_server_config_ssh_new_address_port(const char *address, const char *port, con } static int -nc_server_config_ssh_new_transport_params_prep(const struct ly_ctx *ctx, const char *endpt_name, +nc_server_config_new_ssh_transport_params_prep(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node *config, struct lyd_node **new_tree, struct lyd_node **alg_tree) { int ret = 0; @@ -384,7 +712,7 @@ nc_server_config_ssh_new_transport_params_prep(const struct ly_ctx *ctx, const c } static int -nc_server_config_ssh_new_transport_params(const struct ly_ctx *ctx, NC_ALG_TYPE alg_type, int alg_count, va_list ap, +nc_server_config_new_ssh_transport_params(const struct ly_ctx *ctx, NC_ALG_TYPE alg_type, int alg_count, va_list ap, struct lyd_node *tree) { int i, ret = 0; @@ -452,14 +780,14 @@ nc_server_config_ssh_new_transport_params(const struct ly_ctx *ctx, NC_ALG_TYPE } API int -nc_server_config_ssh_new_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, +nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...) { int ret = 0; struct lyd_node *new_tree, *alg_tree; va_list ap; - ret = nc_server_config_ssh_new_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + ret = nc_server_config_new_ssh_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); if (ret) { goto cleanup; } @@ -470,7 +798,7 @@ nc_server_config_ssh_new_host_key_algs(const struct ly_ctx *ctx, const char *end va_start(ap, alg_count); - ret = nc_server_config_ssh_new_transport_params(ctx, NC_ALG_HOSTKEY, alg_count, ap, alg_tree); + ret = nc_server_config_new_ssh_transport_params(ctx, NC_ALG_HOSTKEY, alg_count, ap, alg_tree); if (ret) { goto cleanup; } @@ -492,7 +820,7 @@ nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char struct lyd_node *new_tree, *alg_tree; va_list ap; - ret = nc_server_config_ssh_new_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + ret = nc_server_config_new_ssh_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); if (ret) { goto cleanup; } @@ -503,7 +831,7 @@ nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char va_start(ap, alg_count); - ret = nc_server_config_ssh_new_transport_params(ctx, NC_ALG_KEY_EXCHANGE, alg_count, ap, alg_tree); + ret = nc_server_config_new_ssh_transport_params(ctx, NC_ALG_KEY_EXCHANGE, alg_count, ap, alg_tree); if (ret) { goto cleanup; } @@ -518,14 +846,14 @@ nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char } API int -nc_server_config_ssh_new_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, +nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...) { int ret = 0; struct lyd_node *new_tree, *alg_tree; va_list ap; - ret = nc_server_config_ssh_new_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + ret = nc_server_config_new_ssh_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); if (ret) { goto cleanup; } @@ -536,7 +864,7 @@ nc_server_config_ssh_new_encryption_algs(const struct ly_ctx *ctx, const char *e va_start(ap, alg_count); - ret = nc_server_config_ssh_new_transport_params(ctx, NC_ALG_ENCRYPTION, alg_count, ap, alg_tree); + ret = nc_server_config_new_ssh_transport_params(ctx, NC_ALG_ENCRYPTION, alg_count, ap, alg_tree); if (ret) { goto cleanup; } @@ -558,7 +886,7 @@ nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_na struct lyd_node *new_tree, *alg_tree; va_list ap; - ret = nc_server_config_ssh_new_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + ret = nc_server_config_new_ssh_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); if (ret) { goto cleanup; } @@ -569,7 +897,7 @@ nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_na va_start(ap, alg_count); - ret = nc_server_config_ssh_new_transport_params(ctx, NC_ALG_MAC, alg_count, ap, alg_tree); + ret = nc_server_config_new_ssh_transport_params(ctx, NC_ALG_MAC, alg_count, ap, alg_tree); if (ret) { goto cleanup; } @@ -583,223 +911,8 @@ nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_na return ret; } -static int -nc_server_config_ssh_read_openssh_pubkey(FILE *f, char **pubkey) -{ - int ret = 0; - char *buffer = NULL; - size_t len = 0; - char *start, *end; - - if (getline(&buffer, &len, f) < 0) { - ERR(NULL, "Reading line from file failed."); - return 1; - } - - if (len < 8) { - ERR(NULL, "Unexpected public key format."); - ret = 1; - goto cleanup; - } - - start = buffer; - if (!strncmp(buffer, "ssh-dss ", 8)) { - ERR(NULL, "DSA public keys not supported."); - ret = 1; - goto cleanup; - } else if (!strncmp(buffer, "ssh-rsa ", 8)) { - start += strlen("ssh-rsa "); - } else if (!strncmp(buffer, "ecdsa-sha2-nistp256 ", 20)) { - start += strlen("ecdsa-sha2-nistp256 "); - } else if (!strncmp(buffer, "ecdsa-sha2-nistp384 ", 20)) { - start += strlen("ecdsa-sha2-nistp384 "); - } else if (!strncmp(buffer, "ecdsa-sha2-nistp521 ", 20)) { - start += strlen("ecdsa-sha2-nistp521 "); - } else if (!strncmp(buffer, "ssh-ed25519 ", 12)) { - start += strlen("ssh-ed25519 "); - } else { - ERR(NULL, "Unknown public key type."); - ret = 1; - goto cleanup; - } - - end = strchr(start, ' '); - if (!end) { - ERR(NULL, "Unexpected public key format."); - ret = 1; - goto cleanup; - } - - *pubkey = strdup(start); - if (!*pubkey) { - ERRMEM; - ret = 1; - goto cleanup; - } - - (*pubkey)[strlen(*pubkey) - strlen(end)] = '\0'; - -cleanup: - free(buffer); - return ret; -} - -static int -nc_server_config_ssh_read_ssh2_pubkey(FILE *f, char **pubkey) -{ - char *buffer = NULL; - size_t len = 0; - size_t pubkey_len = 0; - void *tmp; - - while (getline(&buffer, &len, f) > 0) { - if (!strncmp(buffer, "----", 4)) { - free(buffer); - buffer = NULL; - continue; - } - - if (!strncmp(buffer, "Comment:", 8)) { - free(buffer); - buffer = NULL; - continue; - } - - len = strlen(buffer); - - tmp = realloc(*pubkey, pubkey_len + len + 1); - if (!tmp) { - ERRMEM; - free(buffer); - buffer = NULL; - return 1; - } - - *pubkey = tmp; - memcpy(*pubkey + pubkey_len, buffer, len); - pubkey_len += len; - free(buffer); - buffer = NULL; - } - - if (!pubkey_len) { - ERR(NULL, "Unexpected public key format."); - return 1; - } - - (*pubkey)[pubkey_len - 1] = '\0'; - free(buffer); - return 0; -} - -static int -nc_server_config_ssh_read_subject_pubkey(FILE *f, char **pubkey) -{ - int ret = 0; - EVP_PKEY *pkey; - BIO *bio; - BUF_MEM *mem; - char *tmp; - - pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL); - if (!pkey) { - ret = -1; - goto cleanup; - } - - bio = BIO_new(BIO_s_mem()); - if (!bio) { - ret = -1; - goto cleanup; - } - - ret = PEM_write_bio_PUBKEY(bio, pkey); - if (!ret) { - ret = -1; - goto cleanup; - } - ret = 0; - - BIO_get_mem_ptr(bio, &mem); - tmp = malloc(mem->length + 1); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - - memcpy(tmp, mem->data, mem->length); - tmp[mem->length] = '\0'; - - *pubkey = strdup(tmp + strlen("-----BEGIN PUBLIC KEY-----\n")); - (*pubkey)[strlen(*pubkey) - strlen("\n-----END PUBLIC KEY-----\n")] = '\0'; - -cleanup: - if (ret == -1) { - ERR(NULL, "Error getting public key from file (OpenSSL Error): \"%s\".", ERR_reason_error_string(ERR_get_error())); - ret = 1; - } - - BIO_free(bio); - EVP_PKEY_free(pkey); - free(tmp); - - return ret; -} - -static int -nc_server_config_ssh_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_SSH_PUBKEY_TYPE *pubkey_type) -{ - int ret = 0; - FILE *f = NULL; - char *buffer = NULL; - size_t len = 0; - - *pubkey = NULL; - - f = fopen(pubkey_path, "r"); - if (!f) { - ERR(NULL, "Unable to open file \"%s\".", pubkey_path); - ret = 1; - goto cleanup; - } - - if (getline(&buffer, &len, f) < 0) { - ERR(NULL, "Error reading header from file \"%s\".", pubkey_path); - ret = 1; - goto cleanup; - } - - rewind(f); - - if (!strncmp(buffer, "-----BEGIN PUBLIC KEY-----\n", strlen("-----BEGIN PUBLIC KEY-----\n"))) { - ret = nc_server_config_ssh_read_subject_pubkey(f, pubkey); - *pubkey_type = NC_SSH_PUBKEY_X509; - } else if (!strncmp(buffer, "---- BEGIN SSH2 PUBLIC KEY ----\n", strlen("---- BEGIN SSH2 PUBLIC KEY ----\n"))) { - ret = nc_server_config_ssh_read_ssh2_pubkey(f, pubkey); - *pubkey_type = NC_SSH_PUBKEY_SSH2; - } else { - ret = nc_server_config_ssh_read_openssh_pubkey(f, pubkey); - *pubkey_type = NC_SSH_PUBKEY_SSH2; - } - - if (ret) { - ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path); - goto cleanup; - } - -cleanup: - if (f) { - fclose(f); - } - - free(buffer); - - return ret; -} - API int -nc_server_config_ssh_new_client_auth_pubkey(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, +nc_server_config_new_ssh_client_auth_pubkey(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *pubkey_name, struct lyd_node **config) { int ret = 0; @@ -807,7 +920,7 @@ nc_server_config_ssh_new_client_auth_pubkey(const char *pubkey_path, const struc struct lyd_node *new_tree; NC_SSH_PUBKEY_TYPE pubkey_type; - ret = nc_server_config_ssh_new_get_pubkey(pubkey_path, &pubkey, &pubkey_type); + ret = nc_server_config_new_ssh_get_pubkey(pubkey_path, &pubkey, &pubkey_type); if (ret) { goto cleanup; } @@ -865,7 +978,7 @@ nc_server_config_ssh_new_client_auth_pubkey(const char *pubkey_path, const struc } API int -nc_server_config_ssh_new_client_auth_password(const char *password, const struct ly_ctx *ctx, const char *endpt_name, +nc_server_config_new_ssh_client_auth_password(const char *password, const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, struct lyd_node **config) { int ret = 0; @@ -934,7 +1047,7 @@ nc_server_config_ssh_new_client_auth_password(const char *password, const struct } API int -nc_server_config_ssh_new_client_auth_none(const struct ly_ctx *ctx, const char *endpt_name, +nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, struct lyd_node **config) { int ret = 0; @@ -983,7 +1096,7 @@ nc_server_config_ssh_new_client_auth_none(const struct ly_ctx *ctx, const char * } API int -nc_server_config_ssh_new_client_auth_interactive(const char *pam_config_name, const char *pam_config_dir, +nc_server_config_new_ssh_client_auth_interactive(const char *pam_config_name, const char *pam_config_dir, const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, struct lyd_node **config) { diff --git a/src/config_new_ssh.h b/src/config_new_ssh.h new file mode 100644 index 00000000..780a9c75 --- /dev/null +++ b/src/config_new_ssh.h @@ -0,0 +1,89 @@ +/** + * @file config_new_ssh.h + * @author Roman Janota + * @brief libnetconf2 server new configuration creation + * + * @copyright + * Copyright (c) 2023 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_NEW_SSH_H_ +#define NC_CONFIG_NEW_SSH_H_ + +#include + +#include "session_p.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* private key's pkcs8 header */ +#define NC_PKCS8_PRIVKEY_HEADER "-----BEGIN PRIVATE KEY-----\n" + +/* private key's pkcs8 footer */ +#define NC_PKCS8_PRIVKEY_FOOTER "\n-----END PRIVATE KEY-----\n" + +/* private key's openssh header */ +#define NC_OPENSSH_PRIVKEY_HEADER "-----BEGIN OPENSSH PRIVATE KEY-----\n" + +/* private key's openssh footer */ +#define NC_OPENSSH_PRIVKEY_FOOTER "\n-----END OPENSSH PRIVATE KEY-----\n" + +/* private key's pkcs1 rsa header */ +#define NC_PKCS1_RSA_PRIVKEY_HEADER "-----BEGIN RSA PRIVATE KEY-----\n" + +/* private key's sec1 ec header */ +#define NC_SEC1_EC_PRIVKEY_HEADER "-----BEGIN EC PRIVATE KEY-----\n" + +/* private key's header when getting an EC/RSA privkey from file using libssh */ +#define NC_LIBSSH_PRIVKEY_HEADER "-----BEGIN PRIVATE KEY-----\n" + +/* private key's footer when getting an EC/RSA privkey from file using libssh */ +#define NC_LIBSSH_PRIVKEY_FOOTER "\n-----END PRIVATE KEY-----\n" + +/* public key's ssh2 header */ +#define NC_SSH2_PUBKEY_HEADER "---- BEGIN SSH2 PUBLIC KEY ----\n" + +/* public key's SubjectPublicKeyInfo format header */ +#define NC_SUBJECT_PUBKEY_INFO_HEADER "-----BEGIN PUBLIC KEY-----\n" + +/* public key's SubjectPublicKeyInfo format footer */ +#define NC_SUBJECT_PUBKEY_INFO_FOOTER "\n-----END PUBLIC KEY-----\n" + +typedef enum { + NC_ALG_HOSTKEY, + NC_ALG_KEY_EXCHANGE, + NC_ALG_ENCRYPTION, + NC_ALG_MAC +} NC_ALG_TYPE; + +/** + * @brief Configures the listen subtree in the ietf-netconf-server module. + * + * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. + * @return 0 on success, 1 on error. + */ +int nc_server_config_listen(NC_OPERATION op); + +/** + * @brief Deletes everything stored in the keystore. + */ +void nc_server_config_del_keystore(void); + +/** + * @brief Deletes everything stored in the truststore. + */ +void nc_server_config_del_trustore(void); + +#ifdef __cplusplus +} +#endif + +#endif /* NC_CONFIG_NEW_SSH_H_ */ diff --git a/src/server_config.c b/src/server_config.c index b3ffefe8..91193ef9 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -1175,11 +1175,13 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op format = ((struct lyd_node_term *)node)->value.ident->name; if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { if (!strcmp(format, "rsa-private-key-format")) { - hostkey->key.privkey_type = NC_SSH_KEY_RSA; + hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_RSA; } else if (!strcmp(format, "ec-private-key-format")) { - hostkey->key.privkey_type = NC_SSH_KEY_ECDSA; - } else if (!strcmp(format, "ed25519-private-key-format")) { - hostkey->key.privkey_type = NC_SSH_KEY_ED25519; + hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_EC; + } else if (!strcmp(format, "subject-private-key-info-format")) { + hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_PKCS8; + } else if (!strcmp(format, "openssh-private-key-format")) { + hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; } else { ERR(NULL, "Private key format (%s) not supported.", format); } @@ -2379,13 +2381,15 @@ nc_server_config_asymmetric_key(const struct lyd_node *tree) if (!ret) { format = ((struct lyd_node_term *)node)->value.ident->name; if (!strcmp(format, "rsa-private-key-format")) { - key->privkey_type = NC_SSH_KEY_RSA; + key->privkey_type = NC_PRIVKEY_FORMAT_RSA; } else if (!strcmp(format, "ec-private-key-format")) { - key->privkey_type = NC_SSH_KEY_ECDSA; + key->privkey_type = NC_PRIVKEY_FORMAT_EC; + } else if (!strcmp(format, "subject-private-key-info-format")) { + key->privkey_type = NC_PRIVKEY_FORMAT_PKCS8; + } else if (!strcmp(format, "openssh-private-key-format")) { + key->privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; } else { ERR(NULL, "Private key format (%s) not supported.", format); - ret = 1; - goto cleanup; } } diff --git a/src/server_config.h b/src/server_config.h index 3af4772c..199e4947 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -84,7 +84,7 @@ int nc_server_config_load_modules(struct ly_ctx **ctx); * 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_ssh_new_hostkey(const char *privkey_path, const char *pubkey_path, const struct ly_ctx *ctx, +int nc_server_config_new_ssh_hostkey(const char *privkey_path, const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, struct lyd_node **config); /** @@ -99,7 +99,7 @@ int nc_server_config_ssh_new_hostkey(const char *privkey_path, const char *pubke * 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_ssh_new_address_port(const char *address, const char *port, const struct ly_ctx *ctx, +int nc_server_config_new_ssh_address_port(const char *address, const char *port, const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config); /** @@ -117,7 +117,7 @@ int nc_server_config_ssh_new_address_port(const char *address, const char *port, * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_ssh_new_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, +int nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...); /** @@ -136,7 +136,7 @@ int nc_server_config_ssh_new_host_key_algs(const struct ly_ctx *ctx, const char * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, +int nc_server_config_new_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...); /** @@ -154,7 +154,7 @@ int nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const c * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_ssh_new_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, +int nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...); /** @@ -171,7 +171,7 @@ int nc_server_config_ssh_new_encryption_algs(const struct ly_ctx *ctx, const cha * @param[in] ... String literals of mac algorithms in a decreasing order of preference. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, +int nc_server_config_new_ssh_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...); /** @@ -189,7 +189,7 @@ int nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endp * 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_ssh_new_client_auth_pubkey(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, +int nc_server_config_new_ssh_client_auth_pubkey(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *pubkey_name, struct lyd_node **config); /** @@ -207,7 +207,7 @@ int nc_server_config_ssh_new_client_auth_pubkey(const char *pubkey_path, const s * 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_ssh_new_client_auth_password(const char *password, const struct ly_ctx *ctx, const char *endpt_name, +int nc_server_config_new_ssh_client_auth_password(const char *password, const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, struct lyd_node **config); /** @@ -222,7 +222,7 @@ int nc_server_config_ssh_new_client_auth_password(const char *password, const st * 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_ssh_new_client_auth_none(const struct ly_ctx *ctx, const char *endpt_name, +int nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, struct lyd_node **config); /** @@ -241,7 +241,7 @@ int nc_server_config_ssh_new_client_auth_none(const struct ly_ctx *ctx, const ch * 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_ssh_new_client_auth_interactive(const char *pam_config_name, const char *pam_config_dir, +int nc_server_config_new_ssh_client_auth_interactive(const char *pam_config_name, const char *pam_config_dir, const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, struct lyd_node **config); diff --git a/src/session_p.h b/src/session_p.h index 5ef0e29e..588419b2 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -61,6 +61,16 @@ typedef enum { NC_SSH_PUBKEY_X509 /**< begins with BEGIN PUBLICKEY, see RFC 5280 sec. 4.1.2.7 */ } NC_SSH_PUBKEY_TYPE; +/** + * Enumeration of private key file formats. + */ +typedef enum { + NC_PRIVKEY_FORMAT_RSA, /**< PKCS1 RSA format */ + NC_PRIVKEY_FORMAT_EC, /**< SEC1 EC format */ + NC_PRIVKEY_FORMAT_PKCS8, /**< PKCS8 format */ + NC_PRIVKEY_FORMAT_OPENSSH /**< OpenSSH format */ +} NC_PRIVKEY_FORMAT; + /** * @brief A basic certificate. */ @@ -83,7 +93,7 @@ struct nc_asymmetric_key { NC_SSH_PUBKEY_TYPE pubkey_type; /**< Type of the public key. */ char *pub_base64; /**< Base-64 encoded public key. */ - NC_SSH_KEY_TYPE privkey_type; /**< Type of the private key. */ + NC_PRIVKEY_FORMAT privkey_type; /**< Type of the private key. */ char *priv_base64; /**< Base-64 encoded private key. */ struct nc_certificate *certs; /**< The certificates associated with this key. */ diff --git a/src/session_server.c b/src/session_server.c index 5928b0ba..03938ee7 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -35,7 +35,7 @@ #include #include "compat.h" -#include "config_new.h" +#include "config_new_ssh.h" #include "libnetconf.h" #include "session_server.h" #include "session_server_ch.h" diff --git a/tests/test_config_new.c b/tests/test_config_new.c index cb4948b5..f7b77050 100644 --- a/tests/test_config_new.c +++ b/tests/test_config_new.c @@ -152,19 +152,19 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new hostkey data */ - ret = nc_server_config_ssh_new_hostkey(TESTS_DIR "/data/server.key", NULL, ctx, "endpt", "hostkey", &tree); + ret = nc_server_config_new_ssh_hostkey(TESTS_DIR "/data/server.key", NULL, ctx, "endpt", "hostkey", &tree); assert_int_equal(ret, 0); /* create new address and port data */ - ret = nc_server_config_ssh_new_address_port("127.0.0.1", "10005", ctx, "endpt", &tree); + ret = nc_server_config_new_ssh_address_port("127.0.0.1", "10005", ctx, "endpt", &tree); assert_int_equal(ret, 0); /* create the host-key algorithms data */ - ret = nc_server_config_ssh_new_host_key_algs(ctx, "endpt", &tree, 1, "rsa-sha2-512"); + ret = nc_server_config_new_ssh_host_key_algs(ctx, "endpt", &tree, 1, "rsa-sha2-512"); assert_int_equal(ret, 0); /* create the client authentication data, password only */ - ret = nc_server_config_ssh_new_client_auth_password("testpassword123", ctx, "endpt", "client", &tree); + ret = nc_server_config_new_ssh_client_auth_password("testpassword123", ctx, "endpt", "client", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_ec.c b/tests/test_ec.c index c8d00058..f3f846c8 100644 --- a/tests/test_ec.c +++ b/tests/test_ec.c @@ -215,19 +215,19 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_ssh_new_hostkey(TESTS_DIR "/data/key_ecdsa", NULL, ctx, "endpt", "hostkey", &tree); + ret = nc_server_config_new_ssh_hostkey(TESTS_DIR "/data/key_ecdsa", NULL, ctx, "endpt", "hostkey", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_ssh_new_address_port("127.0.0.1", "10009", ctx, "endpt", &tree); + ret = nc_server_config_new_ssh_address_port("127.0.0.1", "10009", ctx, "endpt", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_ssh_new_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa256.pub", ctx, "endpt", "test_ec256", "pubkey", &tree); + ret = nc_server_config_new_ssh_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa256.pub", ctx, "endpt", "test_ec256", "pubkey", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_ssh_new_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa384.pub", ctx, "endpt", "test_ec384", "pubkey", &tree); + ret = nc_server_config_new_ssh_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa384.pub", ctx, "endpt", "test_ec384", "pubkey", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_ssh_new_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa521.pub", ctx, "endpt", "test_ec521", "pubkey", &tree); + ret = nc_server_config_new_ssh_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa521.pub", ctx, "endpt", "test_ec521", "pubkey", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_ed25519.c b/tests/test_ed25519.c index 08c73256..110833aa 100644 --- a/tests/test_ed25519.c +++ b/tests/test_ed25519.c @@ -152,13 +152,13 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_ssh_new_hostkey(TESTS_DIR "/data/server.key", NULL, ctx, "endpt", "hostkey", &tree); + ret = nc_server_config_new_ssh_hostkey(TESTS_DIR "/data/server.key", NULL, ctx, "endpt", "hostkey", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_ssh_new_address_port("127.0.0.1", "10009", ctx, "endpt", &tree); + ret = nc_server_config_new_ssh_address_port("127.0.0.1", "10009", ctx, "endpt", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_ssh_new_client_auth_pubkey(TESTS_DIR "/data/id_ed25519.pub", ctx, "endpt", "test_ed25519", "pubkey", &tree); + ret = nc_server_config_new_ssh_client_auth_pubkey(TESTS_DIR "/data/id_ed25519.pub", ctx, "endpt", "test_ed25519", "pubkey", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ From 64410bc8ec1cafa14496e6c0accf8ca67a4a0dfd Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 22 May 2023 14:04:29 +0200 Subject: [PATCH 024/134] configuration UPDATE new YANG data config API Added the option to either use diff YANG data or ordinary ietf-netconf-server YANG data without any operation for configuring the server. --- src/server_config.c | 134 ++++++++++++++++++++++++++++++++------------ src/session_p.h | 1 + 2 files changed, 98 insertions(+), 37 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 91193ef9..570de835 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -2225,28 +2225,30 @@ nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op { struct lyd_node *child; struct lyd_meta *m; - NC_OPERATION current_op; + NC_OPERATION current_op = NC_OP_UNKNOWN; assert(node); - /* get current op */ - LY_LIST_FOR(node->meta, m) { - if (!strcmp(m->name, "operation")) { - if (!strcmp(lyd_get_meta_value(m), "create")) { - current_op = NC_OP_CREATE; - } else if (!strcmp(lyd_get_meta_value(m), "delete")) { - current_op = NC_OP_DELETE; - } else if (!strcmp(lyd_get_meta_value(m), "replace")) { - current_op = NC_OP_REPLACE; - } else if (!strcmp(lyd_get_meta_value(m), "none")) { - current_op = NC_OP_NONE; - } - break; + /* get current op if there is any */ + if ((m = lyd_find_meta(node->meta, NULL, "yang:operation"))) { + if (!strcmp(lyd_get_meta_value(m), "create")) { + current_op = NC_OP_CREATE; + } else if (!strcmp(lyd_get_meta_value(m), "delete")) { + current_op = NC_OP_DELETE; + } else if (!strcmp(lyd_get_meta_value(m), "replace")) { + current_op = NC_OP_REPLACE; + } else if (!strcmp(lyd_get_meta_value(m), "none")) { + current_op = NC_OP_NONE; } } /* node has no op, inherit from the parent */ - if (!m) { + if (!current_op) { + if (!parent_op) { + ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node)); + return 1; + } + current_op = parent_op; } @@ -2485,7 +2487,7 @@ nc_server_config_symmetric_key(const struct lyd_node *tree) } static int -nc_fill_keystore(const struct lyd_node *data) +nc_server_config_fill_keystore(const struct lyd_node *data) { int ret = 0; uint32_t prev_lo; @@ -2743,7 +2745,7 @@ nc_server_config_public_key_bag(const struct lyd_node *tree) } static int -nc_fill_truststore(const struct lyd_node *data) +nc_server_config_fill_truststore(const struct lyd_node *data) { int ret = 0; struct lyd_node *tree, *cert_bags, *pub_bags, *iter; @@ -2905,55 +2907,113 @@ nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path) return ret; } +static int +nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op) +{ + int ret = 0; + struct lyd_node *tree; + + ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree); + if (ret) { + ERR(NULL, "Unable to find the netconf-server container in the YANG data."); + goto cleanup; + } + + if (nc_session_server_parse_tree(tree, op)) { + ret = 1; + goto cleanup; + } + +cleanup: + return ret; +} + API int nc_server_config_setup(const struct lyd_node *data) { int ret = 0; - struct lyd_node *tree; - struct lyd_meta *m; - NC_OPERATION op = NC_OP_NONE; /* LOCK */ pthread_rwlock_wrlock(&server_opts.config_lock); - ret = nc_fill_keystore(data); + /* configure keystore */ + ret = nc_server_config_fill_keystore(data); if (ret) { ERR(NULL, "Filling keystore failed."); goto cleanup; } - ret = nc_fill_truststore(data); + /* configure truststore */ + ret = nc_server_config_fill_truststore(data); if (ret) { ERR(NULL, "Filling truststore failed."); goto cleanup; } - ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree); + /* configure netconf-server */ + ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN); + if (ret) { + ERR(NULL, "Filling netconf-server failed."); + goto cleanup; + } + +cleanup: + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); + return ret; +} + +API int +nc_server_config_setup2(const struct lyd_node *data) +{ + int ret = 0; + struct lyd_node *tree, *iter, *root; + + /* LOCK */ + pthread_rwlock_wrlock(&server_opts.config_lock); + + /* find the netconf-server node */ + ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &root); if (ret) { ERR(NULL, "Unable to find the netconf-server container in the YANG data."); goto cleanup; } - LY_LIST_FOR(tree->meta, m) { - if (!strcmp(m->name, "operation")) { - if (!strcmp(lyd_get_meta_value(m), "create")) { - op = NC_OP_CREATE; - } else if (!strcmp(lyd_get_meta_value(m), "delete")) { - op = NC_OP_DELETE; - } else if (!strcmp(lyd_get_meta_value(m), "replace")) { - op = NC_OP_REPLACE; - } else if (!strcmp(lyd_get_meta_value(m), "none")) { - op = NC_OP_NONE; - } else { - ERR(NULL, "Unexpected operation (%s).", lyd_get_meta_value(m)); + /* iterate through all the nodes and make sure there is no operation attribute */ + LY_LIST_FOR(root, tree) { + LYD_TREE_DFS_BEGIN(tree, iter) { + if (lyd_find_meta(iter->meta, NULL, "yang:operation")) { + ERR(NULL, "Unexpected operation attribute in the YANG data."); ret = 1; goto cleanup; } + LYD_TREE_DFS_END(tree, iter); } } - if (nc_session_server_parse_tree(tree, op)) { - ret = 1; + /* delete the current configuration */ + nc_server_config_listen(NC_OP_DELETE); + nc_server_config_del_keystore(); + nc_server_config_del_trustore(); + + /* configure keystore */ + ret = nc_server_config_fill_keystore(data); + if (ret) { + ERR(NULL, "Filling keystore failed."); + goto cleanup; + } + + /* configure truststore */ + ret = nc_server_config_fill_truststore(data); + if (ret) { + ERR(NULL, "Filling truststore failed."); + goto cleanup; + } + + /* configure netconf-server */ + ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE); + if (ret) { + ERR(NULL, "Filling netconf-server failed."); goto cleanup; } diff --git a/src/session_p.h b/src/session_p.h index 588419b2..87dc3d65 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -36,6 +36,7 @@ * Enumeration of diff operation types. */ typedef enum { + NC_OP_UNKNOWN = 0, NC_OP_NONE, NC_OP_CREATE, NC_OP_DELETE, From c2f4c009b86e917dc709ce0efd5259e4e2000434 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 25 May 2023 09:44:11 +0200 Subject: [PATCH 025/134] config UPDATE diff trustore and keystore Trustore and keystore modules now support diff YANG data. Symmetric-keys keystore feature disabled. New private header for server configuration. --- CMakeLists.txt | 2 + src/config_new_ssh.h | 18 - src/server_config.c | 977 ++++++---------------------------------- src/server_config.h | 16 +- src/server_config_ks.c | 490 ++++++++++++++++++++ src/server_config_p.h | 182 ++++++++ src/server_config_ts.c | 630 ++++++++++++++++++++++++++ tests/test_keystore.c | 2 +- tests/test_truststore.c | 2 +- 9 files changed, 1465 insertions(+), 854 deletions(-) create mode 100644 src/server_config_ks.c create mode 100644 src/server_config_p.h create mode 100644 src/server_config_ts.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e2efc0e2..e21faa5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,6 +113,8 @@ set(libsrc src/session_client.c src/session_server.c src/server_config.c + src/server_config_ks.c + src/server_config_ts.c src/config_new_ssh.c) if(ENABLE_SSH) diff --git a/src/config_new_ssh.h b/src/config_new_ssh.h index 780a9c75..0f03da66 100644 --- a/src/config_new_ssh.h +++ b/src/config_new_ssh.h @@ -64,24 +64,6 @@ typedef enum { NC_ALG_MAC } NC_ALG_TYPE; -/** - * @brief Configures the listen subtree in the ietf-netconf-server module. - * - * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. - * @return 0 on success, 1 on error. - */ -int nc_server_config_listen(NC_OPERATION op); - -/** - * @brief Deletes everything stored in the keystore. - */ -void nc_server_config_del_keystore(void); - -/** - * @brief Deletes everything stored in the truststore. - */ -void nc_server_config_del_trustore(void); - #ifdef __cplusplus } #endif diff --git a/src/server_config.c b/src/server_config.c index 570de835..c341ab0f 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -4,7 +4,7 @@ * @brief libnetconf2 server configuration functions * * @copyright - * Copyright (c) 2015 - 2021 CESNET, z.s.p.o. + * Copyright (c) 2022-2023 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,6 +22,7 @@ #include "compat.h" #include "libnetconf.h" #include "server_config.h" +#include "server_config_p.h" #include "session_server.h" #include "session_server_ch.h" @@ -55,16 +56,8 @@ static const char *supported_mac_algs[] = { extern struct nc_server_opts server_opts; -/** - * @brief Get the pointer to an endpoint structure based on node's location in the YANG data. - * - * @param[in] node Node from which the endpoint containing this node is derived. - * @param[out] endpt Endpoint containing the node. - * @param[out] bind Bind corresponding to the endpoint. Optional. - * @return 0 on success, 1 on error. - */ -static int -nc_server_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind) +int +nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind) { uint16_t i; const char *endpt_name; @@ -101,16 +94,8 @@ nc_server_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct return 1; } -/** - * @brief Get the pointer to a hostkey structure based on node's location in the YANG data. - * - * @param[in] node Node from which the hotkey containing this node is derived. - * @param[in] opts Server SSH opts storing the array of the hostkey structures. - * @param[out] hostkey Hostkey containing the node. - * @return 0 on success, 1 on error. - */ -static int -nc_server_get_hostkey(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_hostkey **hostkey) +int +nc_server_config_get_hostkey(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_hostkey **hostkey) { uint16_t i; const char *hostkey_name; @@ -144,16 +129,8 @@ nc_server_get_hostkey(const struct lyd_node *node, const struct nc_server_ssh_op return 1; } -/** - * @brief Get the pointer to a client authentication structure based on node's location in the YANG data. - * - * @param[in] node Node from which the client-authentication structure containing this node is derived. - * @param[in] opts Server SSH opts storing the array of the client authentication structures. - * @param[out] auth_client Client authentication structure containing the node. - * @return 0 on success, 1 on error. - */ -static int -nc_server_get_auth_client(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_client_auth **auth_client) +int +nc_server_config_get_auth_client(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_client_auth **auth_client) { uint16_t i; const char *authkey_name; @@ -187,16 +164,8 @@ nc_server_get_auth_client(const struct lyd_node *node, const struct nc_server_ss return 1; } -/** - * @brief Get the pointer to a client authentication public key structure based on node's location in the YANG data. - * - * @param[in] node Node from which the ca-public key structure containing this node is derived. - * @param[in] auth_client Client authentication structure storing the array of the public key structures. - * @param[out] pubkey Public key structure containing the node. - * @return 0 on success, 1 on error. - */ -static int -nc_server_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_public_key **pubkey) +int +nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_public_key **pubkey) { uint16_t i; const char *pubkey_name; @@ -231,15 +200,7 @@ nc_server_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *a return 1; } -/** - * @brief Compares the nth-parent name. - * - * @param[in] node Node of which nth-parent to compare. - * @param[in] parent_count Count of parents. - * @param[in] parent_name Expected name of the parent. - * @return 1 if the name matches, 0 otherwise. - */ -static int +int equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name) { uint16_t i; @@ -258,6 +219,40 @@ equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char return 0; } +int +nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count) +{ + int ret = 0; + void *tmp; + char **name; + + tmp = realloc(*ptr, (*count + 1) * size); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + *ptr = tmp; + + /* set the newly allocated memory to 0 */ + memset((char *)(*ptr) + (*count * size), 0, size); + (*count)++; + + /* access the first member of the supposed structure */ + name = (char **)((*ptr) + ((*count - 1) * size)); + + /* and set it's value */ + *name = strdup(key_value); + if (!*name) { + ERRMEM; + ret = 1; + goto cleanup; + } + +cleanup: + return ret; +} + static void nc_server_del_auth_client_pam_name(struct nc_client_auth *auth_client) { @@ -492,86 +487,14 @@ nc_server_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind) } } -void -nc_server_config_del_keystore(void) -{ - int i, j; - struct nc_keystore *ks = &server_opts.keystore; - - /* delete all asymmetric keys */ - for (i = 0; i < ks->asym_key_count; i++) { - free(ks->asym_keys[i].name); - free(ks->asym_keys[i].pub_base64); - free(ks->asym_keys[i].priv_base64); - - for (j = 0; j < ks->asym_keys[i].cert_count; j++) { - /* free associated certificates */ - free(ks->asym_keys[i].certs[j].name); - free(ks->asym_keys[i].certs[j].cert_base64); - } - free(ks->asym_keys[i].certs); - ks->asym_keys[i].certs = NULL; - ks->asym_keys[i].cert_count = 0; - } - free(ks->asym_keys); - ks->asym_keys = NULL; - ks->asym_key_count = 0; - - /* delete all symmetric keys */ - for (i = 0; i < ks->sym_key_count; i++) { - free(ks->sym_keys[i].name); - free(ks->sym_keys[i].base64); - } - free(ks->sym_keys); - ks->sym_keys = NULL; - ks->sym_key_count = 0; -} - -void -nc_server_config_del_trustore(void) -{ - int i, j; - struct nc_truststore *ts = &server_opts.truststore; - - /* delete all cert bags */ - for (i = 0; i < ts->cert_bag_count; i++) { - free(ts->cert_bags[i].name); - for (j = 0; j < ts->cert_bags[i].cert_count; j++) { - /* free associated certificates */ - free(ts->cert_bags[i].certs[j].name); - free(ts->cert_bags[i].certs[j].cert_base64); - } - free(ts->cert_bags[i].certs); - ts->cert_bags[i].certs = NULL; - ts->cert_bags[i].cert_count = 0; - } - free(ts->cert_bags); - ts->cert_bags = NULL; - ts->cert_bag_count = 0; - - /* delete all pubkey bags */ - for (i = 0; i < ts->pub_bag_count; i++) { - free(ts->pub_bags[i].name); - for (j = 0; j < ts->pub_bags[i].pubkey_count; j++) { - /* free associated pubkeys */ - free(ts->pub_bags[i].pubkeys[j].name); - free(ts->pub_bags[i].pubkeys[j].pub_base64); - } - free(ts->pub_bags[i].pubkeys); - ts->pub_bags[i].pubkeys = NULL; - ts->pub_bags[i].pubkey_count = 0; - } - free(ts->pub_bags); - ts->pub_bags = NULL; - ts->pub_bag_count = 0; -} - /* presence container */ int -nc_server_config_listen(NC_OPERATION op) +nc_server_config_listen(struct lyd_node *node, NC_OPERATION op) { uint16_t i; + (void) node; + assert(op == NC_OP_CREATE || op == NC_OP_DELETE); if (op == NC_OP_DELETE) { @@ -643,37 +566,14 @@ nc_server_create_bind(void) static int nc_server_create_endpoint(const struct lyd_node *node) { - int ret = 0; - void *tmp; - - tmp = realloc(server_opts.endpts, (server_opts.endpt_count + 1) * sizeof *server_opts.endpts); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; + if (nc_server_create_bind()) { + return 1; } - server_opts.endpts = tmp; - memset(&server_opts.endpts[server_opts.endpt_count], 0, sizeof *server_opts.endpts); node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); - server_opts.endpts[server_opts.endpt_count].name = strdup(lyd_get_value(node)); - if (!server_opts.endpts[server_opts.endpt_count].name) { - ERRMEM; - ret = 1; - goto cleanup; - } - - if (nc_server_create_bind()) { - ret = 1; - goto cleanup; - } - - server_opts.endpt_count++; - -cleanup: - return ret; + return nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.endpts, sizeof *server_opts.endpts, &server_opts.endpt_count); } /* list */ @@ -693,7 +593,7 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) } } else if (op == NC_OP_DELETE) { /* free all children */ - if (nc_server_get_endpt(node, &endpt, &bind)) { + if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; } @@ -727,7 +627,7 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "ssh")); - if (nc_server_get_endpt(node, &endpt, &bind)) { + if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; } @@ -823,7 +723,7 @@ nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "local-address")); if (equal_parent_name(node, 4, "listen")) { - if (nc_server_get_endpt(node, &endpt, &bind)) { + if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; } @@ -857,7 +757,7 @@ nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "local-port")); if (equal_parent_name(node, 4, "listen")) { - if (nc_server_get_endpt(node, &endpt, &bind)) { + if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; } @@ -890,7 +790,7 @@ nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "keepalives")); if (equal_parent_name(node, 4, "listen")) { - if (nc_server_get_endpt(node, &endpt, &bind)) { + if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; } @@ -921,7 +821,7 @@ nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "idle-time")); if (equal_parent_name(node, 4, "listen")) { - if (nc_server_get_endpt(node, &endpt, &bind)) { + if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; } @@ -952,7 +852,7 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "max-probes")); if (equal_parent_name(node, 4, "listen")) { - if (nc_server_get_endpt(node, &endpt, &bind)) { + if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; } @@ -983,7 +883,7 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "probe-interval")); if (equal_parent_name(node, 4, "listen")) { - if (nc_server_get_endpt(node, &endpt, &bind)) { + if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; } @@ -1006,41 +906,10 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) static int nc_server_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts) { - int ret = 0; - void *tmp; - - tmp = realloc(opts->hostkeys, - (opts->hostkey_count + 1) * sizeof *opts->hostkeys); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - opts->hostkeys = tmp; - - memset(&opts->hostkeys[opts->hostkey_count], 0, sizeof *opts->hostkeys); - - opts->hostkeys[opts->hostkey_count].name = strdup(lyd_get_value(lyd_child(node))); - if (!opts->hostkeys[opts->hostkey_count].name) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* set union selector */ - lyd_find_path(node, "public-key", 0, (struct lyd_node **)&node); - assert(node); - - if (!lyd_find_path(node, "local-definition", 0, NULL)) { - opts->hostkeys[opts->hostkey_count].ks_type = NC_STORE_LOCAL; - } else { - opts->hostkeys[opts->hostkey_count].ks_type = NC_STORE_KEYSTORE; - } - - opts->hostkey_count++; + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); -cleanup: - return ret; + return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count); } /* list */ @@ -1054,7 +923,7 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "host-key")); if ((equal_parent_name(node, 1, "server-identity")) && (equal_parent_name(node, 5, "listen"))) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } @@ -1065,7 +934,7 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; } @@ -1101,37 +970,37 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) format = ((struct lyd_node_term *)node)->value.ident->name; if ((equal_parent_name(node, 6, "client-authentication")) && (equal_parent_name(node, 10, "listen"))) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; } - if (nc_server_get_pubkey(node, auth_client, &pubkey)) { + if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { if (!strcmp(format, "ssh-public-key-format")) { - pubkey->pubkey_type = NC_SSH_PUBKEY_X509; - } else if (!strcmp(format, "subject-public-key-info-format")) { pubkey->pubkey_type = NC_SSH_PUBKEY_SSH2; + } else if (!strcmp(format, "subject-public-key-info-format")) { + pubkey->pubkey_type = NC_SSH_PUBKEY_X509; } else { ERR(NULL, "Public key format (%s) not supported.", format); } } } else if ((equal_parent_name(node, 5, "server-identity")) && (equal_parent_name(node, 11, "listen"))) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; } @@ -1162,12 +1031,12 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op assert(!strcmp(LYD_NAME(node), "private-key-format")); - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; } @@ -1214,11 +1083,11 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION assert(!strcmp(LYD_NAME(node), "cleartext-private-key")); if ((equal_parent_name(node, 6, "ssh")) && (equal_parent_name(node, 8, "listen"))) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; } @@ -1271,16 +1140,19 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op assert(!strcmp(LYD_NAME(node), "keystore-reference")); if ((equal_parent_name(node, 3, "server-identity")) && (equal_parent_name(node, 7, "listen"))) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* set to keystore */ + hostkey->ks_type = NC_STORE_KEYSTORE; + ret = nc_server_create_keystore_reference(node, hostkey); if (ret) { goto cleanup; @@ -1297,35 +1169,12 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op static int nc_server_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_client_auth *auth_client) { - int ret = 0; - void *tmp; - assert(!strcmp(LYD_NAME(node), "public-key")); - tmp = realloc(auth_client->pubkeys, (auth_client->pubkey_count + 1) * sizeof *auth_client->pubkeys); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - auth_client->pubkeys = tmp; - - memset(&auth_client->pubkeys[auth_client->pubkey_count], 0, sizeof *auth_client->pubkeys); - node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); - auth_client->pubkeys[auth_client->pubkey_count].name = strdup(lyd_get_value(node)); - if (!auth_client->pubkeys[auth_client->pubkey_count].name) { - ERRMEM; - ret = 1; - goto cleanup; - } - - ++auth_client->pubkey_count; - -cleanup: - return ret; + return nc_server_config_realloc(lyd_get_value(node), (void **)&auth_client->pubkeys, sizeof *auth_client->pubkeys, &auth_client->pubkey_count); } static int @@ -1369,17 +1218,20 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) if ((equal_parent_name(node, 3, "host-key")) && (equal_parent_name(node, 8, "listen"))) { /* server's public-key, mandatory leaf */ - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* set to local */ + hostkey->ks_type = NC_STORE_LOCAL; + ret = nc_server_replace_host_key_public_key(node, hostkey); if (ret) { goto cleanup; @@ -1387,23 +1239,26 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } } else if ((equal_parent_name(node, 5, "client-authentication")) && (equal_parent_name(node, 9, "listen"))) { /* client auth pubkeys, list */ - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; } if (op == NC_OP_CREATE) { + /* set to local */ + auth_client->ks_type = NC_STORE_LOCAL; + ret = nc_server_create_auth_key_public_key_list(node, auth_client); if (ret) { goto cleanup; } } else if (op == NC_OP_DELETE) { - if (nc_server_get_pubkey(node, auth_client, &pubkey)) { + if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { ret = 1; goto cleanup; } @@ -1412,17 +1267,17 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } } else if ((equal_parent_name(node, 6, "client-authentication")) && (equal_parent_name(node, 10, "listen"))) { /* client auth pubkey, leaf */ - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; } - if (nc_server_get_pubkey(node, auth_client, &pubkey)) { + if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { ret = 1; goto cleanup; } @@ -1444,41 +1299,10 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) static int nc_server_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts) { - int ret = 0; - void *tmp; - - tmp = realloc(opts->auth_clients, (opts->client_count + 1) * sizeof *opts->auth_clients); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - opts->auth_clients = tmp; - - memset(&opts->auth_clients[opts->client_count], 0, sizeof *opts->auth_clients); - - opts->auth_clients[opts->client_count].username = strdup(lyd_get_value(lyd_child(node))); - if (!opts->auth_clients[opts->client_count].username) { - ERRMEM; - ret = 1; - goto cleanup; - } - - lyd_find_path(node, "public-keys", 0, (struct lyd_node **)&node); - - if (node) { - /* set union selector */ - if (!lyd_find_path(node, "local-definition", 0, NULL)) { - opts->auth_clients[opts->client_count].ks_type = NC_STORE_LOCAL; - } else { - opts->auth_clients[opts->client_count].ks_type = NC_STORE_TRUSTSTORE; - } - } - - ++opts->client_count; + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); -cleanup: - return ret; + return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->auth_clients, sizeof *opts->auth_clients, &opts->client_count); } /* list */ @@ -1492,7 +1316,7 @@ nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "user")); if (equal_parent_name(node, 6, "listen")) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } @@ -1503,7 +1327,7 @@ nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; } @@ -1525,7 +1349,7 @@ nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "auth-attempts")); if (equal_parent_name(node, 5, "listen")) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } @@ -1548,7 +1372,7 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "auth-timeout")); if (equal_parent_name(node, 5, "listen")) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } @@ -1596,17 +1420,20 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION assert(!strcmp(LYD_NAME(node), "truststore-reference")); if ((equal_parent_name(node, 1, "public-keys")) && (equal_parent_name(node, 8, "listen"))) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* set to truststore */ + auth_client->ks_type = NC_STORE_TRUSTSTORE; + ret = nc_server_replace_truststore_reference(node, auth_client); if (ret) { goto cleanup; @@ -1645,12 +1472,12 @@ nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "password")); if (equal_parent_name(node, 7, "listen")) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; } @@ -1679,12 +1506,12 @@ nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "pam-config-file-name")); if (equal_parent_name(node, 8, "listen")) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; } @@ -1715,12 +1542,12 @@ nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "pam-config-file-dir")); if (equal_parent_name(node, 8, "listen")) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; } @@ -1751,12 +1578,12 @@ nc_server_config_none(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "none")); if (equal_parent_name(node, 7, "listen")) { - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - if (nc_server_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; } @@ -1841,7 +1668,7 @@ nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op) if (equal_parent_name(node, 6, "listen")) { listen = 1; - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } @@ -1884,7 +1711,7 @@ nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op) if (equal_parent_name(node, 6, "listen")) { listen = 1; - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } @@ -1927,7 +1754,7 @@ nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op) if (equal_parent_name(node, 6, "listen")) { listen = 1; - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } @@ -1970,7 +1797,7 @@ nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op) if (equal_parent_name(node, 6, "listen")) { listen = 1; - if (nc_server_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } @@ -2029,7 +1856,7 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "unix-socket")); - if (nc_server_get_endpt(node, &endpt, &bind)) { + if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; } @@ -2086,12 +1913,12 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_configure(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op) { const char *name = LYD_NAME(node); if (!strcmp(name, "listen")) { - if (nc_server_config_listen(op)) { + if (nc_server_config_listen(NULL, op)) { goto error; } } else if (!strcmp(name, "idle-timeout")) { @@ -2221,11 +2048,12 @@ nc_server_configure(const struct lyd_node *node, NC_OPERATION op) } int -nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op) +nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module) { struct lyd_node *child; struct lyd_meta *m; NC_OPERATION current_op = NC_OP_UNKNOWN; + int ret; assert(node); @@ -2258,8 +2086,15 @@ nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op case NC_OP_CREATE: case NC_OP_DELETE: case NC_OP_REPLACE: - if (nc_server_configure(node, current_op)) { - return 1; + if (module == NC_MODULE_NETCONF_SERVER) { + ret = nc_server_config_parse_netconf_server(node, current_op); + } else if (module == NC_MODULE_KEYSTORE) { + ret = nc_server_config_parse_keystore(node, current_op); + } else { + ret = nc_server_config_parse_truststore(node, current_op); + } + if (ret) { + return ret; } break; default: @@ -2268,7 +2103,7 @@ nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op if (current_op != NC_OP_DELETE) { LY_LIST_FOR(lyd_child(node), child) { - if (nc_session_server_parse_tree(child, current_op)) { + if (nc_session_server_parse_tree(child, current_op, module)) { return 1; } } @@ -2276,530 +2111,6 @@ nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op return 0; } -static int -nc_server_config_asymmetric_key_certificate(const struct lyd_node *tree, struct nc_asymmetric_key *key) -{ - int ret = 0; - struct lyd_node *node; - void *tmp; - - /* create new certificate */ - tmp = realloc(key->certs, (key->cert_count + 1) * sizeof *key->certs); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - key->certs = tmp; - key->cert_count++; - - /* set name */ - lyd_find_path(tree, "name", 0, &node); - assert(node); - - key->certs[key->cert_count - 1].name = strdup(lyd_get_value(node)); - if (!key->certs[key->cert_count - 1].name) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* set certificate data */ - lyd_find_path(tree, "cert-data", 0, &node); - assert(node); - - key->certs[key->cert_count - 1].cert_base64 = strdup(lyd_get_value(node)); - if (!key->certs[key->cert_count - 1].cert_base64) { - ERRMEM; - ret = 1; - goto cleanup; - } - -cleanup: - return ret; -} - -static int -nc_server_config_asymmetric_key(const struct lyd_node *tree) -{ - int ret = 0; - struct lyd_node *node = NULL, *iter; - void *tmp; - struct nc_keystore *ks = &server_opts.keystore; - struct nc_asymmetric_key *key; - const char *format; - - /* create new asymmetric key */ - tmp = realloc(ks->asym_keys, (ks->asym_key_count + 1) * sizeof *ks->asym_keys); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - ks->asym_keys = tmp; - memset(&ks->asym_keys[ks->asym_key_count], 0, sizeof *ks->asym_keys); - key = &ks->asym_keys[ks->asym_key_count]; - ks->asym_key_count++; - - /* set name */ - lyd_find_path(tree, "name", 0, &node); - assert(node); - - key->name = strdup(lyd_get_value(node)); - if (!key->name) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* set public-key-format, mandatory */ - lyd_find_path(tree, "public-key-format", 0, &node); - assert(node); - - format = ((struct lyd_node_term *)node)->value.ident->name; - if (!strcmp(format, "ssh-public-key-format")) { - key->pubkey_type = NC_SSH_PUBKEY_SSH2; - } else if (!strcmp(format, "subject-public-key-info-format")) { - key->pubkey_type = NC_SSH_PUBKEY_X509; - } else { - ERR(NULL, "Public key format \"%s\" not supported.", format); - ret = 1; - goto cleanup; - } - - /* set public-key, mandatory */ - lyd_find_path(tree, "public-key", 0, &node); - assert(node); - - key->pub_base64 = strdup(lyd_get_value(node)); - if (!key->pub_base64) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* set private-key-format */ - ret = lyd_find_path(tree, "private-key-format", 0, &node); - if (!ret) { - format = ((struct lyd_node_term *)node)->value.ident->name; - if (!strcmp(format, "rsa-private-key-format")) { - key->privkey_type = NC_PRIVKEY_FORMAT_RSA; - } else if (!strcmp(format, "ec-private-key-format")) { - key->privkey_type = NC_PRIVKEY_FORMAT_EC; - } else if (!strcmp(format, "subject-private-key-info-format")) { - key->privkey_type = NC_PRIVKEY_FORMAT_PKCS8; - } else if (!strcmp(format, "openssh-private-key-format")) { - key->privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; - } else { - ERR(NULL, "Private key format (%s) not supported.", format); - } - } - - /* set private key, mandatory */ - lyd_find_path(tree, "cleartext-private-key", 0, &node); - assert(node); - - key->priv_base64 = strdup(lyd_get_value(node)); - if (!key->priv_base64) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* set certificates associated with the key pair */ - ret = lyd_find_path(tree, "certificates", 0, &node); - if (!ret) { - node = lyd_child(node); - if (node) { - /* certificate list instance */ - LY_LIST_FOR(node, iter) { - if (nc_server_config_asymmetric_key_certificate(iter, key)) { - ret = 1; - goto cleanup; - } - } - } - } else if (ret == LY_ENOTFOUND) { - /* certificates container not present, but it's ok */ - ret = 0; - } - -cleanup: - return ret; -} - -static int -nc_server_config_symmetric_key(const struct lyd_node *tree) -{ - int ret = 0; - const char *format; - struct lyd_node *node; - struct nc_keystore *ks = &server_opts.keystore; - struct nc_symmetric_key *key; - void *tmp; - - /* create new symmetric key */ - tmp = realloc(ks->sym_keys, (ks->sym_key_count + 1) * sizeof *ks->sym_keys); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - memset(&ks->sym_keys[ks->sym_key_count], 0, sizeof *ks->sym_keys); - ks->sym_keys = tmp; - key = &ks->sym_keys[ks->sym_key_count]; - ks->sym_key_count++; - - /* set name */ - lyd_find_path(tree, "name", 0, &node); - assert(node); - - key->name = strdup(lyd_get_value(node)); - if (!key->name) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* check if the identity matches with the supported one */ - lyd_find_path(tree, "key-format", 0, &node); - assert(node); - - format = ((struct lyd_node_term *)node)->value.ident->name; - if (strcmp(format, "symmetric-key-format")) { - ret = 1; - goto cleanup; - } - - /* set key data */ - lyd_find_path(tree, "cleartext-key", 0, &node); - assert(node); - - key->base64 = strdup(lyd_get_value(node)); - if (!key->base64) { - ERRMEM; - ret = 1; - goto cleanup; - } - -cleanup: - return ret; -} - -static int -nc_server_config_fill_keystore(const struct lyd_node *data) -{ - int ret = 0; - uint32_t prev_lo; - struct lyd_node *tree, *as_keys, *s_keys, *iter; - - /* silently search for nodes, some of them may not be present */ - prev_lo = ly_log_options(0); - - ret = lyd_find_path(data, "/ietf-keystore:keystore", 0, &tree); - if (ret) { - VRB(NULL, "Keystore container not found in the YANG data."); - ret = 0; - goto cleanup; - } - - ret = lyd_find_path(tree, "asymmetric-keys", 0, &as_keys); - if (!ret) { - /* asymmetric keys container is present */ - as_keys = lyd_child(as_keys); - if (as_keys && !strcmp(LYD_NAME(as_keys), "asymmetric-key")) { - /* asymmetric key list */ - LY_LIST_FOR(as_keys, iter) { - if (nc_server_config_asymmetric_key(iter)) { - ret = 1; - goto cleanup; - } - } - } - } - - ret = lyd_find_path(tree, "symmetric-keys", 0, &s_keys); - if (!ret) { - /* symmetric keys container is present */ - s_keys = lyd_child(s_keys); - if (s_keys && !strcmp(LYD_NAME(s_keys), "symmetric-key")) { - /* symmetric key list */ - LY_LIST_FOR(s_keys, iter) { - if (nc_server_config_symmetric_key(iter)) { - ret = 1; - goto cleanup; - } - } - } - } - -cleanup: - /* reset the logging options back to what they were */ - ly_log_options(prev_lo); - return ret; -} - -static int -nc_server_config_create_truststore_certificate(const struct lyd_node *tree, struct nc_certificate_bag *bag) -{ - int ret = 0; - struct lyd_node *node; - void *tmp; - struct nc_certificate *cert; - - /* create new certificate */ - tmp = realloc(bag->certs, (bag->cert_count + 1) * sizeof *bag->certs); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - memset(&bag->certs[bag->cert_count], 0, sizeof *bag->certs); - bag->certs = tmp; - cert = &bag->certs[bag->cert_count]; - bag->cert_count++; - - /* set name */ - lyd_find_path(tree, "name", 0, &node); - assert(node); - - cert->name = strdup(lyd_get_value(node)); - if (!cert->name) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* set cert data */ - lyd_find_path(tree, "cert-data", 0, &node); - assert(node); - - cert->cert_base64 = strdup(lyd_get_value(node)); - if (!cert->cert_base64) { - ERRMEM; - ret = 1; - goto cleanup; - } - -cleanup: - return ret; -} - -static int -nc_server_config_certificate_bag(const struct lyd_node *tree) -{ - int ret = 0; - struct lyd_node *node = NULL, *iter; - void *tmp; - struct nc_truststore *ts = &server_opts.truststore; - struct nc_certificate_bag *bag; - - /* create new certificate bag */ - tmp = realloc(ts->cert_bags, (ts->cert_bag_count + 1) * sizeof *ts->cert_bags); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - ts->cert_bags = tmp; - memset(&ts->cert_bags[ts->cert_bag_count], 0, sizeof *ts->cert_bags); - bag = &ts->cert_bags[ts->cert_bag_count]; - ts->cert_bag_count++; - - /* set name */ - lyd_find_path(tree, "name", 0, &node); - assert(node); - - bag->name = strdup(lyd_get_value(node)); - if (!bag->name) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* set certificates associated with this bag */ - ret = lyd_find_path(tree, "certificate", 0, &node); - if (!ret) { - LY_LIST_FOR(node, iter) { - if (nc_server_config_create_truststore_certificate(iter, bag)) { - ret = 1; - goto cleanup; - } - } - } else if (ret == LY_ENOTFOUND) { - /* certificate list not present, but it's ok */ - ret = 0; - } - -cleanup: - return ret; -} - -static int -nc_server_config_create_truststore_public_key(const struct lyd_node *tree, struct nc_public_key_bag *bag) -{ - int ret = 0; - struct lyd_node *node; - void *tmp; - struct nc_public_key *key; - const char *format; - - /* create new public key */ - tmp = realloc(bag->pubkeys, (bag->pubkey_count + 1) * sizeof *bag->pubkeys); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - bag->pubkeys = tmp; - memset(&bag->pubkeys[bag->pubkey_count], 0, sizeof *bag->pubkeys); - key = &bag->pubkeys[bag->pubkey_count]; - bag->pubkey_count++; - - /* set name */ - lyd_find_path(tree, "name", 0, &node); - assert(node); - - key->name = strdup(lyd_get_value(node)); - if (!key->name) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* set public-key-format, mandatory */ - lyd_find_path(tree, "public-key-format", 0, &node); - assert(node); - - format = ((struct lyd_node_term *)node)->value.ident->name; - if (!strcmp(format, "ssh-public-key-format")) { - key->pubkey_type = NC_SSH_PUBKEY_SSH2; - } else if (!strcmp(format, "subject-public-key-info-format")) { - key->pubkey_type = NC_SSH_PUBKEY_X509; - } else { - ERR(NULL, "Public key format \"%s\" not supported.", format); - ret = 1; - goto cleanup; - } - - /* set public key data */ - lyd_find_path(tree, "public-key", 0, &node); - assert(node); - - key->pub_base64 = strdup(lyd_get_value(node)); - if (!key->pub_base64) { - ERRMEM; - ret = 1; - goto cleanup; - } - -cleanup: - return ret; -} - -static int -nc_server_config_public_key_bag(const struct lyd_node *tree) -{ - int ret = 0; - struct lyd_node *node = NULL, *iter; - void *tmp; - struct nc_truststore *ts = &server_opts.truststore; - struct nc_public_key_bag *bag; - const struct lysc_node *schema; - - /* create new public key bag */ - tmp = realloc(ts->pub_bags, (ts->pub_bag_count + 1) * sizeof *ts->pub_bags); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - ts->pub_bags = tmp; - memset(&ts->pub_bags[ts->pub_bag_count], 0, sizeof *ts->pub_bags); - bag = &ts->pub_bags[ts->pub_bag_count]; - ts->pub_bag_count++; - - /* set name */ - lyd_find_path(tree, "name", 0, &node); - assert(node); - - bag->name = strdup(lyd_get_value(node)); - if (!bag->name) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* get the schema node of public key so we can iterate over it's list */ - schema = lys_find_path(NULL, tree->schema, "public-key", 0); - LYD_LIST_FOR_INST(node, schema, iter) { - /* set public keys associated with this bag */ - if (nc_server_config_create_truststore_public_key(iter, bag)) { - ret = 1; - goto cleanup; - } - } - -cleanup: - return ret; -} - -static int -nc_server_config_fill_truststore(const struct lyd_node *data) -{ - int ret = 0; - struct lyd_node *tree, *cert_bags, *pub_bags, *iter; - uint32_t prev_lo; - - /* silently search for nodes, some of them may not be present */ - prev_lo = ly_log_options(0); - - ret = lyd_find_path(data, "/ietf-truststore:truststore", 0, &tree); - if (ret) { - VRB(NULL, "Truststore container not found in the YANG data."); - ret = 0; - goto cleanup; - } - - ret = lyd_find_path(tree, "certificate-bags", 0, &cert_bags); - if (!ret) { - /* certificate bags container is present */ - cert_bags = lyd_child(cert_bags); - if (cert_bags && !strcmp(LYD_NAME(cert_bags), "certificate-bag")) { - /* certificate bag list */ - LY_LIST_FOR(cert_bags, iter) { - if (nc_server_config_certificate_bag(iter)) { - ret = 1; - goto cleanup; - } - } - } - } - - ret = lyd_find_path(tree, "public-key-bags", 0, &pub_bags); - if (!ret) { - /* public key bags container is present */ - pub_bags = lyd_child(pub_bags); - if (pub_bags && !strcmp(LYD_NAME(pub_bags), "public-key-bag")) { - /* public key bag list */ - LY_LIST_FOR(pub_bags, iter) { - if (nc_server_config_public_key_bag(iter)) { - ret = 1; - goto cleanup; - } - } - } - } else if (ret == LY_ENOTFOUND) { - /* it's not mandatory so it's ok */ - ret = 0; - } - -cleanup: - /* reset the logging options back to what they were */ - ly_log_options(prev_lo); - return ret; -} - API int nc_server_config_load_modules(struct ly_ctx **ctx) { @@ -2836,8 +2147,8 @@ nc_server_config_load_modules(struct ly_ctx **ctx) const char *iana_ssh_mac_algs[] = {NULL}; /* all features */ const char *iana_ssh_public_key_algs[] = {NULL}; - /* all features */ - const char *ietf_keystore[] = {"central-keystore-supported", "local-definitions-supported", "asymmetric-keys", "symmetric-keys", NULL}; + /* no symmetric-keys */ + const char *ietf_keystore[] = {"central-keystore-supported", "local-definitions-supported", "asymmetric-keys", NULL}; /* no ssh-server-keepalives and local-user-auth-hostbased */ const char *ietf_ssh_server[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL}; /* all features */ @@ -2919,7 +2230,7 @@ nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION o goto cleanup; } - if (nc_session_server_parse_tree(tree, op)) { + if (nc_session_server_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) { ret = 1; goto cleanup; } @@ -2937,14 +2248,14 @@ nc_server_config_setup(const struct lyd_node *data) pthread_rwlock_wrlock(&server_opts.config_lock); /* configure keystore */ - ret = nc_server_config_fill_keystore(data); + ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN); if (ret) { ERR(NULL, "Filling keystore failed."); goto cleanup; } /* configure truststore */ - ret = nc_server_config_fill_truststore(data); + ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN); if (ret) { ERR(NULL, "Filling truststore failed."); goto cleanup; @@ -2992,19 +2303,19 @@ nc_server_config_setup2(const struct lyd_node *data) } /* delete the current configuration */ - nc_server_config_listen(NC_OP_DELETE); - nc_server_config_del_keystore(); - nc_server_config_del_trustore(); + nc_server_config_listen(NULL, NC_OP_DELETE); + nc_server_config_ks_keystore(NULL, NC_OP_DELETE); + nc_server_config_ts_truststore(NULL, NC_OP_DELETE); /* configure keystore */ - ret = nc_server_config_fill_keystore(data); + ret = nc_server_config_fill_keystore(data, NC_OP_CREATE); if (ret) { ERR(NULL, "Filling keystore failed."); goto cleanup; } /* configure truststore */ - ret = nc_server_config_fill_truststore(data); + ret = nc_server_config_fill_truststore(data, NC_OP_CREATE); if (ret) { ERR(NULL, "Filling truststore failed."); goto cleanup; diff --git a/src/server_config.h b/src/server_config.h index 199e4947..9d3e161d 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -28,7 +28,7 @@ extern "C" { #include "session_p.h" /** - * @brief Configure server based on the given data. + * @brief Configure server based on the given diff data. * * Expected data is a validated instance of a ietf-netconf-server YANG data. * The data must be in the diff format and supported operations are: create, replace, @@ -40,6 +40,20 @@ extern "C" { */ int nc_server_config_setup(const struct lyd_node *data); +/** + * @brief Configure server based on the given data. + * + * Expected data is a validated instance of a ietf-netconf-server YANG data. + * Behaves as if all the nodes in data had the replace operation. That means that the current configuration will be deleted + * and just the given data will all be applied. + * The data must not contain any operation attribute, see ::nc_config_setup() which works with diff. + * Context must already have implemented the required modules, see * ::nc_config_load_modules(). + * + * @param[in] data ietf-netconf-server YANG data. + * @return 0 on success, 1 on error. + */ +int nc_server_config_setup2(const struct lyd_node *data); + /** * @brief Configure server based on the given ietf-netconf-server YANG data. * Wrapper around ::nc_config_setup_server() hiding work with parsing the data. diff --git a/src/server_config_ks.c b/src/server_config_ks.c new file mode 100644 index 00000000..da00811b --- /dev/null +++ b/src/server_config_ks.c @@ -0,0 +1,490 @@ +/** + * @file server_config_ks.c + * @author Roman Janota + * @brief libnetconf2 keystore configuration functions + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include + +#include "compat.h" +#include "libnetconf.h" +#include "server_config_p.h" + +extern struct nc_server_opts server_opts; + +/** + * @brief Get the pointer to an asymmetric key structure based on node's location in the YANG data. + * + * @param[in] node Node from which the asymmetric key containing this node is derived. + * @param[out] askey Asymmetric key containing the node. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_get_asymmetric_key(const struct lyd_node *node, struct nc_asymmetric_key **askey) +{ + uint16_t i; + const char *askey_name; + struct nc_keystore *ks; + + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "asymmetric-key")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in an asymmetric-key subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + askey_name = lyd_get_value(node); + + ks = &server_opts.keystore; + for (i = 0; i < ks->asym_key_count; i++) { + if (!strcmp(ks->asym_keys[i].name, askey_name)) { + *askey = &ks->asym_keys[i]; + return 0; + } + } + + ERR(NULL, "Asymmetric key \"%s\" was not found.", askey_name); + return 1; +} + +/** + * @brief Get the pointer to a certificate structure based on node's location in the YANG data. + * + * @param[in] node Node from which the certificate containing this node is derived. + * @param[out] cert Certificate containing the node. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_get_certificate(const struct lyd_node *node, const struct nc_asymmetric_key *askey, struct nc_certificate **cert) +{ + uint16_t i; + const char *cert_name; + + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "certificate")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + cert_name = lyd_get_value(node); + + for (i = 0; i < askey->cert_count; i++) { + if (!strcmp(askey->certs[i].name, cert_name)) { + *cert = &askey->certs[i]; + return 0; + } + } + + ERR(NULL, "Certificate \"%s\" was not found.", cert_name); + return 1; +} + +static void +nc_server_config_ks_del_asymmetric_key_cert(struct nc_asymmetric_key *key, struct nc_certificate *cert) +{ + free(cert->name); + cert->name = NULL; + + free(cert->cert_base64); + cert->cert_base64 = NULL; + + key->cert_count--; + if (key->cert_count == 0) { + free(key->certs); + key->certs = NULL; + } +} + +static void +nc_server_config_ks_del_public_key(struct nc_asymmetric_key *key) +{ + free(key->pub_base64); + key->pub_base64 = NULL; +} + +static void +nc_server_config_ks_del_private_key(struct nc_asymmetric_key *key) +{ + free(key->priv_base64); + key->priv_base64 = NULL; +} + +static void +nc_server_config_ks_del_cert_data(struct nc_certificate *cert) +{ + free(cert->cert_base64); + cert->cert_base64 = NULL; +} + +static void +nc_server_config_ks_del_asymmetric_key(struct nc_asymmetric_key *key) +{ + uint16_t i, cert_count; + struct nc_keystore *ks = &server_opts.keystore; + + free(key->name); + key->name = NULL; + + nc_server_config_ks_del_public_key(key); + nc_server_config_ks_del_private_key(key); + + cert_count = key->cert_count; + for (i = 0; i < cert_count; i++) { + nc_server_config_ks_del_asymmetric_key_cert(key, &key->certs[i]); + } + + ks->asym_key_count--; + if (!ks->asym_key_count) { + free(ks->asym_keys); + ks->asym_keys = NULL; + } +} + +static int +nc_server_config_ks_asymmetric_keys(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_keystore *ks = &server_opts.keystore; + uint16_t i, asym_key_count; + + (void) node; + + if (op == NC_OP_DELETE) { + asym_key_count = ks->asym_key_count; + for (i = 0; i < asym_key_count; i++) { + nc_server_config_ks_del_asymmetric_key(&ks->asym_keys[i]); + } + } + + return 0; +} + +int +nc_server_config_ks_keystore(const struct lyd_node *node, NC_OPERATION op) +{ + (void) node; + + if (op == NC_OP_DELETE) { + nc_server_config_ks_asymmetric_keys(NULL, NC_OP_DELETE); + } + + return 0; +} + +static int +nc_server_config_ks_create_asymmetric_key(const struct lyd_node *node) +{ + struct nc_keystore *ks = &server_opts.keystore; + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + return nc_server_config_realloc(lyd_get_value(node), (void **)&ks->asym_keys, sizeof *ks->asym_keys, &ks->asym_key_count); +} + +static int +nc_server_config_ks_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_asymmetric_key *key; + + assert(!strcmp(LYD_NAME(node), "asymmetric-key")); + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_ks_create_asymmetric_key(node); + } else { + if (nc_server_config_get_asymmetric_key(node, &key)) { + ret = 1; + goto cleanup; + } + + nc_server_config_ks_del_asymmetric_key(key); + } + +cleanup: + return ret; +} + +static int +nc_server_config_ks_public_key_format(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_asymmetric_key *key; + const char *format; + + (void) op; + + assert(!strcmp(LYD_NAME(node), "public-key-format")); + + if (nc_server_config_get_asymmetric_key(node, &key)) { + return 1; + } + + format = ((struct lyd_node_term *)node)->value.ident->name; + if (!strcmp(format, "ssh-public-key-format")) { + key->pubkey_type = NC_SSH_PUBKEY_SSH2; + } else if (!strcmp(format, "subject-public-key-info-format")) { + key->pubkey_type = NC_SSH_PUBKEY_X509; + } else { + ERR(NULL, "Public key format (%s) not supported.", format); + } + + return 0; +} + +static int +nc_server_config_ks_public_key(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_asymmetric_key *key; + + (void) op; + + assert(!strcmp(LYD_NAME(node), "public-key")); + + if (nc_server_config_get_asymmetric_key(node, &key)) { + return 1; + } + + /* replace the pubkey */ + nc_server_config_ks_del_public_key(key); + key->pub_base64 = strdup(lyd_get_value(node)); + if (!key->pub_base64) { + ERRMEM; + return 1; + } + + return 0; +} + +static int +nc_server_config_ks_private_key_format(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_asymmetric_key *key; + const char *format; + + assert(!strcmp(LYD_NAME(node), "private-key-format")); + + if (nc_server_config_get_asymmetric_key(node, &key)) { + return 1; + } + + format = ((struct lyd_node_term *)node)->value.ident->name; + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + if (!strcmp(format, "rsa-private-key-format")) { + key->privkey_type = NC_PRIVKEY_FORMAT_RSA; + } else if (!strcmp(format, "ec-private-key-format")) { + key->privkey_type = NC_PRIVKEY_FORMAT_EC; + } else if (!strcmp(format, "subject-private-key-info-format")) { + key->privkey_type = NC_PRIVKEY_FORMAT_PKCS8; + } else if (!strcmp(format, "openssh-private-key-format")) { + key->privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; + } else { + ERR(NULL, "Private key format (%s) not supported.", format); + } + } + + return 0; +} + +static int +nc_server_config_ks_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_asymmetric_key *key; + + assert(!strcmp(LYD_NAME(node), "cleartext-private-key")); + + if (nc_server_config_get_asymmetric_key(node, &key)) { + return 1; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* replace the privkey */ + nc_server_config_ks_del_private_key(key); + key->priv_base64 = strdup(lyd_get_value(node)); + if (!key->priv_base64) { + ERRMEM; + return 1; + } + } else if (op == NC_OP_DELETE) { + nc_server_config_ks_del_private_key(key); + } + + return 0; +} + +static int +nc_server_config_ks_create_certificate(const struct lyd_node *node, struct nc_asymmetric_key *key) +{ + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + return nc_server_config_realloc(lyd_get_value(node), (void **)&key->certs, sizeof *key->certs, &key->cert_count); +} + +static int +nc_server_config_ks_certificate(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_asymmetric_key *key; + struct nc_certificate *cert; + + assert(!strcmp(LYD_NAME(node), "certificate")); + + if (nc_server_config_get_asymmetric_key(node, &key)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_ks_create_certificate(node, key); + } else { + if (nc_server_config_get_certificate(node, key, &cert)) { + ret = 1; + goto cleanup; + } + + nc_server_config_ks_del_asymmetric_key_cert(key, cert); + } + +cleanup: + return ret; +} + +static int +nc_server_config_ks_cert_data(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_asymmetric_key *key; + struct nc_certificate *cert; + + (void) op; + + assert(!strcmp(LYD_NAME(node), "cert-data")); + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + if (nc_server_config_get_asymmetric_key(node, &key)) { + return 1; + } + + if (nc_server_config_get_certificate(node, key, &cert)) { + return 1; + } + + /* replace the cert data */ + nc_server_config_ks_del_cert_data(cert); + cert->cert_base64 = strdup(lyd_get_value(node)); + if (!cert->cert_base64) { + ERRMEM; + return 1; + } + } + + return 0; +} + +int +nc_server_config_parse_keystore(const struct lyd_node *node, NC_OPERATION op) +{ + const char *name = LYD_NAME(node); + + if (!strcmp(name, "keystore")) { + if (nc_server_config_ks_keystore(node, op)) { + goto error; + } + } else if (!strcmp(name, "asymmetric-keys")) { + if (nc_server_config_ks_asymmetric_keys(node, op)) { + goto error; + } + } else if (!strcmp(name, "asymmetric-key")) { + if (nc_server_config_ks_asymmetric_key(node, op)) { + goto error; + } + } else if (!strcmp(name, "public-key-format")) { + if (nc_server_config_ks_public_key_format(node, op)) { + goto error; + } + } else if (!strcmp(name, "public-key")) { + if (nc_server_config_ks_public_key(node, op)) { + goto error; + } + } else if (!strcmp(name, "private-key-format")) { + if (nc_server_config_ks_private_key_format(node, op)) { + goto error; + } + } else if (!strcmp(name, "cleartext-private-key")) { + if (nc_server_config_ks_cleartext_private_key(node, op)) { + goto error; + } + } else if (!strcmp(name, "certificate")) { + if (nc_server_config_ks_certificate(node, op)) { + goto error; + } + } else if (!strcmp(name, "cert-data")) { + if (nc_server_config_ks_cert_data(node, op)) { + goto error; + } + } + + return 0; + +error: + ERR(NULL, "Configuring (%s) failed.", name); + return 1; +} + +int +nc_server_config_fill_keystore(const struct lyd_node *data, NC_OPERATION op) +{ + int ret = 0; + uint32_t prev_lo; + struct lyd_node *tree; + + /* silently search for nodes, some of them may not be present */ + prev_lo = ly_log_options(0); + + ret = lyd_find_path(data, "/ietf-keystore:keystore", 0, &tree); + if (ret || (tree->flags & LYD_DEFAULT)) { + VRB(NULL, "Keystore container not found in the YANG data."); + ret = 0; + goto cleanup; + } + + if (nc_session_server_parse_tree(tree, op, NC_MODULE_KEYSTORE)) { + ret = 1; + goto cleanup; + } + +cleanup: + /* reset the logging options back to what they were */ + ly_log_options(prev_lo); + return ret; +} diff --git a/src/server_config_p.h b/src/server_config_p.h new file mode 100644 index 00000000..deaec676 --- /dev/null +++ b/src/server_config_p.h @@ -0,0 +1,182 @@ +/** + * @file server_config_p.h + * @author Roman Janota + * @brief libnetconf2 server configuration + * + * @copyright + * Copyright (c) 2023 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_P_H_ +#define NC_CONFIG_SERVER_P_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "compat.h" +#include "libnetconf.h" +#include "netconf.h" +#include "session_p.h" + +/** + * Enumeration of ietf-netconf-server's modules/trees (top-level containers) + */ +typedef enum { + NC_MODULE_NETCONF_SERVER, + NC_MODULE_KEYSTORE, + NC_MODULE_TRUSTSTORE +} NC_MODULE; + +/** + * @brief Get the pointer to an endpoint structure based on node's location in the YANG data. + * + * @param[in] node Node from which the endpoint containing this node is derived. + * @param[out] endpt Endpoint containing the node. + * @param[out] bind Bind corresponding to the endpoint. Optional. + * @return 0 on success, 1 on error. + */ +int nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind); + +/** + * @brief Get the pointer to a hostkey structure based on node's location in the YANG data. + * + * @param[in] node Node from which the hotkey containing this node is derived. + * @param[in] opts Server SSH opts storing the array of the hostkey structures. + * @param[out] hostkey Hostkey containing the node. + * @return 0 on success, 1 on error. + */ +int nc_server_config_get_hostkey(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_hostkey **hostkey); + +/** + * @brief Get the pointer to a client authentication structure based on node's location in the YANG data. + * + * @param[in] node Node from which the client-authentication structure containing this node is derived. + * @param[in] opts Server SSH opts storing the array of the client authentication structures. + * @param[out] auth_client Client authentication structure containing the node. + * @return 0 on success, 1 on error. + */ +int nc_server_config_get_auth_client(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_client_auth **auth_client); + +/** + * @brief Get the pointer to a client authentication public key structure based on node's location in the YANG data. + * + * @param[in] node Node from which the ca-public key structure containing this node is derived. + * @param[in] auth_client Client authentication structure storing the array of the public key structures. + * @param[out] pubkey Public key structure containing the node. + * @return 0 on success, 1 on error. + */ +int nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_public_key **pubkey); + +/** + * @brief Compares the nth-parent name. + * + * @param[in] node Node of which nth-parent to compare. + * @param[in] parent_count Count of parents. + * @param[in] parent_name Expected name of the parent. + * @return 1 if the name matches, 0 otherwise. + */ +int equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name); + +/** + * @brief Generic realloc function for arrays of structures representing YANG lists whose first member is the key (char *) + * + * @param[in] key_value Value of the key, which will be assigned to the first member of the given struct. + * @param[in] size Size of a member of the array. + * @param[in,out] ptr Pointer to the beginning of the given array, which will be reallocated. + * @param[in,out] count Count of members in the array, incremented at the end. + * @return 0 on success, 1 on error. + */ +int nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count); + +/** + * @brief Recursively parse the given tree and apply it's data to the server's configuration. + * + * @param[in] node YANG data tree. + * @param[in] parent_op Operation of the parent. + * @param[in] module Module for which to parse the data - either ietf-netconf-server, ietf-keystore or ietf-truststore + * @return 0 on success, 1 on error. + */ +int nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module); + +/** + * @brief Configures the listen subtree in the ietf-netconf-server module. + * + * @param[in] node Listen YANG data node. + * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. + * @return 0 on success, 1 on error. + */ +int nc_server_config_listen(struct lyd_node *node, NC_OPERATION op); + +/** KEYSTORE **/ + +/** + * @brief Checks if keystore tree is present in the data and if yes, tries to apply it's data. + * + * @param[in] data YANG data tree. + * @param[in] op Operation saying what to do with the top-level node. + * @return 0 either if keystore is not present or if it is and application was successful, 1 on error. + */ +int nc_server_config_fill_keystore(const struct lyd_node *data, NC_OPERATION op); + +/** + * @brief Parse the given node, which belongs to the ietf-keystore subtree, and apply it's data to the server's configuration. + * + * @param[in] node YANG data node. + * @param[in] op Operation saying what to do with the node. + * @return 0 on success, 1 on error. + */ +int nc_server_config_parse_keystore(const struct lyd_node *node, NC_OPERATION op); + +/** + * @brief Configures the keystore subtree in the ietf-keystore module. + * + * @param[in] node Keystore YANG data node. + * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. + * @return 0. + */ +int nc_server_config_ks_keystore(const struct lyd_node *node, NC_OPERATION op); + +/** TRUSTSTORE **/ + +/** + * @brief Checks if truststore tree is present in the data and if yes, tries to apply it's data. + * + * @param[in] data YANG data tree. + * @param[in] op Operation saying what to do with the top-level node. + * @return 0 either if truststore is not present or if it is and application was successful, 1 on error. + */ +int nc_server_config_fill_truststore(const struct lyd_node *data, NC_OPERATION op); + +/** + * @brief Parse the given node, which belongs to the ietf-truststore subtree, and apply it's data to the server's configuration. + * + * @param[in] node YANG data node. + * @param[in] op Operation saying what to do with the node. + * @return 0 on success, 1 on error. + */ +int nc_server_config_parse_truststore(const struct lyd_node *node, NC_OPERATION op); + +/** + * @brief Configures the truststore subtree in the ietf-truststore module. + * + * @param[in] node Truststore YANG data node. + * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. + * @return 0. + */ +int nc_server_config_ts_truststore(const struct lyd_node *node, NC_OPERATION op); + +#ifdef __cplusplus +} +#endif + +#endif /* NC_CONFIG_SERVER_P_H_ */ diff --git a/src/server_config_ts.c b/src/server_config_ts.c new file mode 100644 index 00000000..12c4cdd1 --- /dev/null +++ b/src/server_config_ts.c @@ -0,0 +1,630 @@ +/** + * @file server_config_ts.c + * @author Roman Janota + * @brief libnetconf2 truststore configuration functions + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include + +#include "compat.h" +#include "libnetconf.h" +#include "server_config_p.h" + +extern struct nc_server_opts server_opts; + +/** + * @brief Get the pointer to a certificate bag structure based on node's location in the YANG data. + * + * @param[in] node Node from which the certificate bag containing this node is derived. + * @param[out] cbag Certificate bag containing the node. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_get_certificate_bag(const struct lyd_node *node, struct nc_certificate_bag **cbag) +{ + uint16_t i; + const char *cbag_name; + struct nc_truststore *ts; + + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "certificate-bag")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a certificate-bag subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + cbag_name = lyd_get_value(node); + + ts = &server_opts.truststore; + for (i = 0; i < ts->cert_bag_count; i++) { + if (!strcmp(ts->cert_bags[i].name, cbag_name)) { + *cbag = &ts->cert_bags[i]; + return 0; + } + } + + ERR(NULL, "Certificate bag \"%s\" was not found.", cbag_name); + return 1; +} + +/** + * @brief Get the pointer to a certificate structure based on node's location in the YANG data. + * + * @param[in] node Node from which the certificate containing this node is derived. + * @param[in] cbag Certificate bag containing the certificate. + * @param[out] cert Certificate containing the node. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_get_certificate(const struct lyd_node *node, const struct nc_certificate_bag *cbag, struct nc_certificate **cert) +{ + uint16_t i; + const char *cert_name; + + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "certificate")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + cert_name = lyd_get_value(node); + + for (i = 0; i < cbag->cert_count; i++) { + if (!strcmp(cbag->certs[i].name, cert_name)) { + *cert = &cbag->certs[i]; + return 0; + } + } + + ERR(NULL, "Certificate \"%s\" was not found.", cert_name); + return 1; +} + +/** + * @brief Get the pointer to a public key bag structure based on node's location in the YANG data. + * + * @param[in] node Node from which the public key bag containing this node is derived. + * @param[out] pbag Public key bag containing the node. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_get_public_key_bag(const struct lyd_node *node, struct nc_public_key_bag **pbag) +{ + uint16_t i; + const char *pbag_name; + struct nc_truststore *ts; + + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "public-key-bag")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a public-key-bag subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + pbag_name = lyd_get_value(node); + + ts = &server_opts.truststore; + for (i = 0; i < ts->pub_bag_count; i++) { + if (!strcmp(ts->pub_bags[i].name, pbag_name)) { + *pbag = &ts->pub_bags[i]; + return 0; + } + } + + ERR(NULL, "Public key bag \"%s\" was not found.", pbag_name); + return 1; +} + +/** + * @brief Get the pointer to a public key structure based on node's location in the YANG data. + * + * @param[in] node Node from which the public key containing this node is derived. + * @param[in] pbag Public key bag containing the public key. + * @param[out] pkey Public key containing the node. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_get_public_key(const struct lyd_node *node, const struct nc_public_key_bag *pbag, struct nc_public_key **pkey) +{ + uint16_t i; + const char *pkey_name; + + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "public-key")) { + if (lyd_child(node)) { + /* check if it's not the leaf public-key, only case about the list */ + break; + } + } + + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + pkey_name = lyd_get_value(node); + + for (i = 0; i < pbag->pubkey_count; i++) { + if (!strcmp(pbag->pubkeys[i].name, pkey_name)) { + *pkey = &pbag->pubkeys[i]; + return 0; + } + } + + ERR(NULL, "Public key \"%s\" was not found.", pkey_name); + return 1; +} + +static void +nc_server_config_ts_del_cert_data(struct nc_certificate *cert) +{ + free(cert->cert_base64); + cert->cert_base64 = NULL; +} + +static void +nc_server_config_ts_del_public_key_base64(struct nc_public_key *pkey) +{ + free(pkey->pub_base64); + pkey->pub_base64 = NULL; +} + +static void +nc_server_config_ts_del_certificate(struct nc_certificate_bag *cbag, struct nc_certificate *cert) +{ + free(cert->name); + cert->name = NULL; + + nc_server_config_ts_del_cert_data(cert); + + cbag->cert_count--; + if (cbag->cert_count == 0) { + free(cbag->certs); + cbag->certs = NULL; + } +} + +static void +nc_server_config_ts_del_public_key(struct nc_public_key_bag *pbag, struct nc_public_key *pkey) +{ + free(pkey->name); + pkey->name = NULL; + + nc_server_config_ts_del_public_key_base64(pkey); + + pbag->pubkey_count--; + if (pbag->pubkey_count == 0) { + free(pbag->pubkeys); + pbag->pubkeys = NULL; + } +} + +static void +nc_server_config_ts_del_certificate_bag(struct nc_certificate_bag *cbag) +{ + uint16_t i, cert_count; + struct nc_truststore *ts = &server_opts.truststore; + + free(cbag->name); + cbag->name = NULL; + + cert_count = cbag->cert_count; + for (i = 0; i < cert_count; i++) { + nc_server_config_ts_del_certificate(cbag, &cbag->certs[i]); + } + + ts->cert_bag_count--; + if (ts->cert_bag_count == 0) { + free(ts->cert_bags); + ts->cert_bags = NULL; + } +} + +static void +nc_server_config_ts_del_public_key_bag(struct nc_public_key_bag *pbag) +{ + uint16_t i, pubkey_count; + struct nc_truststore *ts = &server_opts.truststore; + + free(pbag->name); + pbag->name = NULL; + + pubkey_count = pbag->pubkey_count; + for (i = 0; i < pubkey_count; i++) { + nc_server_config_ts_del_public_key(pbag, &pbag->pubkeys[i]); + } + + ts->pub_bag_count--; + if (ts->pub_bag_count == 0) { + free(ts->pub_bags); + ts->pub_bags = NULL; + } +} + +static int +nc_server_config_ts_certificate_bags(const struct lyd_node *node, NC_OPERATION op) +{ + uint16_t i, cert_bag_count; + struct nc_truststore *ts = &server_opts.truststore; + + (void) node; + + if (op == NC_OP_DELETE) { + cert_bag_count = ts->cert_bag_count; + for (i = 0; i < cert_bag_count; i++) { + nc_server_config_ts_del_certificate_bag(&ts->cert_bags[i]); + } + } + + return 0; +} + +static int +nc_server_config_ts_public_key_bags(const struct lyd_node *node, NC_OPERATION op) +{ + uint16_t i, pub_bag_count; + struct nc_truststore *ts = &server_opts.truststore; + + (void) node; + + if (op == NC_OP_DELETE) { + pub_bag_count = ts->pub_bag_count; + for (i = 0; i < pub_bag_count; i++) { + nc_server_config_ts_del_public_key_bag(&ts->pub_bags[i]); + } + } + + return 0; +} + +int +nc_server_config_ts_truststore(const struct lyd_node *node, NC_OPERATION op) +{ + (void) node; + + if (op == NC_OP_DELETE) { + nc_server_config_ts_certificate_bags(NULL, NC_OP_DELETE); + nc_server_config_ts_public_key_bags(NULL, NC_OP_DELETE); + } + + return 0; +} + +static int +nc_server_config_ts_create_certificate_bag(const struct lyd_node *node) +{ + struct nc_truststore *ts = &server_opts.truststore; + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + return nc_server_config_realloc(lyd_get_value(node), (void **)&ts->cert_bags, sizeof *ts->cert_bags, &ts->cert_bag_count); +} + +static int +nc_server_config_ts_certificate_bag(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_certificate_bag *bag; + + assert(!strcmp(LYD_NAME(node), "certificate-bag")); + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + if (nc_server_config_ts_create_certificate_bag(node)) { + return 1; + } + } else { + if (nc_server_config_get_certificate_bag(node, &bag)) { + return 1; + } + + nc_server_config_ts_del_certificate_bag(bag); + } + + return 0; +} + +static int +nc_server_config_ts_create_certificate(const struct lyd_node *node, struct nc_certificate_bag *bag) +{ + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + return nc_server_config_realloc(lyd_get_value(node), (void **)&bag->certs, sizeof *bag->certs, &bag->cert_count); +} + +static int +nc_server_config_ts_certificate(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_certificate_bag *bag; + struct nc_certificate *cert; + + assert(!strcmp(LYD_NAME(node), "certificate")); + + if (nc_server_config_get_certificate_bag(node, &bag)) { + return 1; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + if (nc_server_config_ts_create_certificate(node, bag)) { + return 1; + } + } else { + if (nc_server_config_get_certificate(node, bag, &cert)) { + return 1; + } + + nc_server_config_ts_del_certificate(bag, cert); + } + + return 0; +} + +static int +nc_server_config_ts_cert_data(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_certificate_bag *bag; + struct nc_certificate *cert; + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + if (nc_server_config_get_certificate_bag(node, &bag)) { + return 1; + } + if (nc_server_config_get_certificate(node, bag, &cert)) { + return 1; + } + + nc_server_config_ts_del_cert_data(cert); + cert->cert_base64 = strdup(lyd_get_value(node)); + if (!cert->cert_base64) { + ERRMEM; + return 1; + } + } + + return 0; +} + +static int +nc_server_config_ts_create_public_key_bag(const struct lyd_node *node) +{ + struct nc_truststore *ts = &server_opts.truststore; + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + return nc_server_config_realloc(lyd_get_value(node), (void **)&ts->pub_bags, sizeof *ts->pub_bags, &ts->pub_bag_count); +} + +static int +nc_server_config_ts_public_key_bag(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_public_key_bag *pbag; + + assert(!strcmp(LYD_NAME(node), "public-key-bag")); + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + if (nc_server_config_ts_create_public_key_bag(node)) { + return 1; + } + } else { + if (nc_server_config_get_public_key_bag(node, &pbag)) { + return 1; + } + + nc_server_config_ts_del_public_key_bag(pbag); + } + + return 0; +} + +static int +nc_server_config_ts_create_public_key(const struct lyd_node *node, struct nc_public_key_bag *bag) +{ + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + return nc_server_config_realloc(lyd_get_value(node), (void **)&bag->pubkeys, sizeof *bag->pubkeys, &bag->pubkey_count); +} + +static int +nc_server_config_ts_public_key(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_public_key_bag *bag; + struct nc_public_key *pkey; + + if (nc_server_config_get_public_key_bag(node, &bag)) { + ret = 1; + goto cleanup; + } + + if (equal_parent_name(node, 1, "public-key-bag")) { + /* public-key list */ + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_ts_create_public_key(node, bag); + if (ret) { + goto cleanup; + } + } else { + if (nc_server_config_get_public_key(node, bag, &pkey)) { + ret = 1; + goto cleanup; + } + + nc_server_config_ts_del_public_key(bag, pkey); + } + } else { + /* public-key leaf */ + if (nc_server_config_get_public_key(node, bag, &pkey)) { + ret = 1; + goto cleanup; + } + + /* replace the public key */ + nc_server_config_ts_del_public_key_base64(pkey); + pkey->pub_base64 = strdup(lyd_get_value(node)); + if (!pkey->pub_base64) { + ERRMEM; + ret = 1; + goto cleanup; + } + } + +cleanup: + return ret; +} + +static int +nc_server_config_ts_public_key_format(const struct lyd_node *node, NC_OPERATION op) +{ + const char *format; + struct nc_public_key_bag *bag; + struct nc_public_key *pkey; + + (void) op; + + if (nc_server_config_get_public_key_bag(node, &bag)) { + return 1; + } + + if (nc_server_config_get_public_key(node, bag, &pkey)) { + return 1; + } + + format = ((struct lyd_node_term *)node)->value.ident->name; + if (!strcmp(format, "ssh-public-key-format")) { + pkey->pubkey_type = NC_SSH_PUBKEY_SSH2; + } else if (!strcmp(format, "subject-public-key-info-format")) { + pkey->pubkey_type = NC_SSH_PUBKEY_X509; + } else { + ERR(NULL, "Public key format (%s) not supported.", format); + } + + return 0; +} + +int +nc_server_config_parse_truststore(const struct lyd_node *node, NC_OPERATION op) +{ + const char *name = LYD_NAME(node); + + if (!strcmp(name, "truststore")) { + if (nc_server_config_ts_truststore(node, op)) { + goto error; + } + } else if (!strcmp(name, "certificate-bags")) { + if (nc_server_config_ts_certificate_bags(node, op)) { + goto error; + } + } else if (!strcmp(name, "certificate-bag")) { + if (nc_server_config_ts_certificate_bag(node, op)) { + goto error; + } + } else if (!strcmp(name, "certificate")) { + if (nc_server_config_ts_certificate(node, op)) { + goto error; + } + } else if (!strcmp(name, "cert-data")) { + if (nc_server_config_ts_cert_data(node, op)) { + goto error; + } + } else if (!strcmp(name, "public-key-bags")) { + if (nc_server_config_ts_public_key_bags(node, op)) { + goto error; + } + } else if (!strcmp(name, "public-key-bag")) { + if (nc_server_config_ts_public_key_bag(node, op)) { + goto error; + } + } else if (!strcmp(name, "public-key")) { + if (nc_server_config_ts_public_key(node, op)) { + goto error; + } + } else if (!strcmp(name, "public-key-format")) { + if (nc_server_config_ts_public_key_format(node, op)) { + goto error; + } + } + + return 0; + +error: + ERR(NULL, "Configuring (%s) failed.", name); + return 1; +} + +int +nc_server_config_fill_truststore(const struct lyd_node *data, NC_OPERATION op) +{ + int ret = 0; + uint32_t prev_lo; + struct lyd_node *tree; + + /* silently search for nodes, some of them may not be present */ + prev_lo = ly_log_options(0); + + ret = lyd_find_path(data, "/ietf-truststore:truststore", 0, &tree); + if (ret || (tree->flags & LYD_DEFAULT)) { + VRB(NULL, "Truststore container not found in the YANG data."); + ret = 0; + goto cleanup; + } + + if (nc_session_server_parse_tree(tree, op, NC_MODULE_TRUSTSTORE)) { + ret = 1; + goto cleanup; + } + +cleanup: + /* reset the logging options back to what they were */ + ly_log_options(prev_lo); + return ret; +} diff --git a/tests/test_keystore.c b/tests/test_keystore.c index f9821d81..f443b210 100644 --- a/tests/test_keystore.c +++ b/tests/test_keystore.c @@ -92,7 +92,7 @@ const char *data = " \n" "\n" "\n" - "\n" + "\n" " \n" " \n" " test_keystore\n" diff --git a/tests/test_truststore.c b/tests/test_truststore.c index 90bc882a..aa5af9f0 100644 --- a/tests/test_truststore.c +++ b/tests/test_truststore.c @@ -91,7 +91,7 @@ const char *data = " \n" "\n" "\n" - "\n" + "\n" " \n" " \n" " test_truststore\n" From 40df9f4e6a356b15f4d9b744f3517361609a941b Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 25 May 2023 10:20:01 +0200 Subject: [PATCH 026/134] config REFACTOR unify func names to server_config Also renamed store type from ks_type to store. --- src/server_config.c | 188 ++++++++++++++++++++++---------------------- src/session_p.h | 4 +- 2 files changed, 96 insertions(+), 96 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index c341ab0f..41c5a2f4 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -254,121 +254,121 @@ nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_ } static void -nc_server_del_auth_client_pam_name(struct nc_client_auth *auth_client) +nc_server_config_del_auth_client_pam_name(struct nc_client_auth *auth_client) { free(auth_client->pam_config_name); auth_client->pam_config_name = NULL; } static void -nc_server_del_auth_client_pam_dir(struct nc_client_auth *auth_client) +nc_server_config_del_auth_client_pam_dir(struct nc_client_auth *auth_client) { free(auth_client->pam_config_dir); auth_client->pam_config_dir = NULL; } static void -nc_server_del_endpt_name(struct nc_endpt *endpt) +nc_server_config_del_endpt_name(struct nc_endpt *endpt) { free(endpt->name); endpt->name = NULL; } static void -nc_server_del_local_address(struct nc_bind *bind) +nc_server_config_del_local_address(struct nc_bind *bind) { free(bind->address); bind->address = NULL; } static void -nc_server_del_hostkey_name(struct nc_hostkey *hostkey) +nc_server_config_del_hostkey_name(struct nc_hostkey *hostkey) { free(hostkey->name); hostkey->name = NULL; } static void -nc_server_del_public_key(struct nc_hostkey *hostkey) +nc_server_config_del_public_key(struct nc_hostkey *hostkey) { free(hostkey->key.pub_base64); hostkey->key.pub_base64 = NULL; } static void -nc_server_del_private_key(struct nc_hostkey *hostkey) +nc_server_config_del_private_key(struct nc_hostkey *hostkey) { free(hostkey->key.priv_base64); hostkey->key.priv_base64 = NULL; } static void -nc_server_del_auth_client_username(struct nc_client_auth *auth_client) +nc_server_config_del_auth_client_username(struct nc_client_auth *auth_client) { free(auth_client->username); auth_client->username = NULL; } static void -nc_server_del_auth_client_pubkey_name(struct nc_public_key *pubkey) +nc_server_config_del_auth_client_pubkey_name(struct nc_public_key *pubkey) { free(pubkey->name); pubkey->name = NULL; } static void -nc_server_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey) +nc_server_config_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey) { free(pubkey->pub_base64); pubkey->pub_base64 = NULL; } static void -nc_server_del_auth_client_password(struct nc_client_auth *auth_client) +nc_server_config_del_auth_client_password(struct nc_client_auth *auth_client) { free(auth_client->password); auth_client->password = NULL; } static void -nc_server_del_hostkey_algs(struct nc_server_ssh_opts *opts) +nc_server_config_del_hostkey_algs(struct nc_server_ssh_opts *opts) { free(opts->hostkey_algs); opts->hostkey_algs = NULL; } static void -nc_server_del_kex_algs(struct nc_server_ssh_opts *opts) +nc_server_config_del_kex_algs(struct nc_server_ssh_opts *opts) { free(opts->kex_algs); opts->kex_algs = NULL; } static void -nc_server_del_encryption_algs(struct nc_server_ssh_opts *opts) +nc_server_config_del_encryption_algs(struct nc_server_ssh_opts *opts) { free(opts->encryption_algs); opts->encryption_algs = NULL; } static void -nc_server_del_mac_algs(struct nc_server_ssh_opts *opts) +nc_server_config_del_mac_algs(struct nc_server_ssh_opts *opts) { free(opts->mac_algs); opts->mac_algs = NULL; } static void -nc_server_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey) +nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey) { - assert(hostkey->ks_type == NC_STORE_LOCAL || hostkey->ks_type == NC_STORE_KEYSTORE); + assert(hostkey->store == NC_STORE_LOCAL || hostkey->store == NC_STORE_KEYSTORE); - if (hostkey->ks_type == NC_STORE_LOCAL) { - nc_server_del_public_key(hostkey); - nc_server_del_private_key(hostkey); + if (hostkey->store == NC_STORE_LOCAL) { + nc_server_config_del_public_key(hostkey); + nc_server_config_del_private_key(hostkey); } - nc_server_del_hostkey_name(hostkey); + nc_server_config_del_hostkey_name(hostkey); opts->hostkey_count--; if (!opts->hostkey_count) { free(opts->hostkeys); @@ -377,10 +377,10 @@ nc_server_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostke } static void -nc_server_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_public_key *pubkey) +nc_server_config_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_public_key *pubkey) { - nc_server_del_auth_client_pubkey_name(pubkey); - nc_server_del_auth_client_pubkey_pub_base64(pubkey); + nc_server_config_del_auth_client_pubkey_name(pubkey); + nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); auth_client->pubkey_count--; if (!auth_client->pubkey_count) { @@ -390,21 +390,21 @@ nc_server_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_p } static void -nc_server_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth *auth_client) +nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth *auth_client) { uint16_t i, pubkey_count; - if (auth_client->ks_type == NC_STORE_LOCAL) { + if (auth_client->store == NC_STORE_LOCAL) { pubkey_count = auth_client->pubkey_count; for (i = 0; i < pubkey_count; i++) { - nc_server_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]); + nc_server_config_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]); } } - nc_server_del_auth_client_password(auth_client); - nc_server_del_auth_client_pam_name(auth_client); - nc_server_del_auth_client_pam_dir(auth_client); - nc_server_del_auth_client_username(auth_client); + nc_server_config_del_auth_client_password(auth_client); + nc_server_config_del_auth_client_pam_name(auth_client); + nc_server_config_del_auth_client_pam_dir(auth_client); + nc_server_config_del_auth_client_username(auth_client); opts->client_count--; if (!opts->client_count) { @@ -414,11 +414,11 @@ nc_server_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth } static void -nc_server_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts) +nc_server_config_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts) { uint16_t i, hostkey_count, client_count; - nc_server_del_local_address(bind); + nc_server_config_del_local_address(bind); if (bind->sock > -1) { close(bind->sock); } @@ -426,28 +426,28 @@ nc_server_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts) /* store in variable because it gets decremented in the function call */ hostkey_count = opts->hostkey_count; for (i = 0; i < hostkey_count; i++) { - nc_server_del_hostkey(opts, &opts->hostkeys[i]); + nc_server_config_del_hostkey(opts, &opts->hostkeys[i]); } client_count = opts->client_count; for (i = 0; i < client_count; i++) { - nc_server_del_auth_client(opts, &opts->auth_clients[i]); + nc_server_config_del_auth_client(opts, &opts->auth_clients[i]); } - nc_server_del_hostkey_algs(opts); - nc_server_del_kex_algs(opts); - nc_server_del_encryption_algs(opts); - nc_server_del_mac_algs(opts); + nc_server_config_del_hostkey_algs(opts); + nc_server_config_del_kex_algs(opts); + nc_server_config_del_encryption_algs(opts); + nc_server_config_del_mac_algs(opts); free(opts); opts = NULL; } void -nc_server_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) +nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) { - nc_server_del_endpt_name(endpt); - nc_server_del_ssh(bind, endpt->opts.ssh); + nc_server_config_del_endpt_name(endpt); + nc_server_config_del_ssh(bind, endpt->opts.ssh); server_opts.endpt_count--; if (!server_opts.endpt_count) { @@ -459,7 +459,7 @@ nc_server_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) } void -nc_server_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts) +nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts) { if (bind->sock > -1) { close(bind->sock); @@ -473,10 +473,10 @@ nc_server_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts } void -nc_server_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind) +nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind) { - nc_server_del_endpt_name(endpt); - nc_server_del_unix_socket(bind, endpt->opts.unixsock); + nc_server_config_del_endpt_name(endpt); + nc_server_config_del_unix_socket(bind, endpt->opts.unixsock); server_opts.endpt_count--; if (!server_opts.endpt_count) { @@ -502,7 +502,7 @@ nc_server_config_listen(struct lyd_node *node, NC_OPERATION op) switch (server_opts.endpts[i].ti) { #ifdef NC_ENABLED_SSH case NC_TI_LIBSSH: - nc_server_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]); + nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]); break; #endif #ifdef NC_ENABLED_TLS @@ -511,7 +511,7 @@ nc_server_config_listen(struct lyd_node *node, NC_OPERATION op) break; #endif case NC_TI_UNIX: - nc_server_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]); + nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]); break; case NC_TI_NONE: case NC_TI_FD: @@ -543,7 +543,7 @@ nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_create_bind(void) +nc_server_config_create_bind(void) { int ret = 0; void *tmp; @@ -564,9 +564,9 @@ nc_server_create_bind(void) } static int -nc_server_create_endpoint(const struct lyd_node *node) +nc_server_config_create_endpoint(const struct lyd_node *node) { - if (nc_server_create_bind()) { + if (nc_server_config_create_bind()) { return 1; } @@ -587,7 +587,7 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "endpoint")); if (op == NC_OP_CREATE) { - ret = nc_server_create_endpoint(node); + ret = nc_server_config_create_endpoint(node); if (ret) { goto cleanup; } @@ -597,7 +597,7 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) ret = 1; goto cleanup; } - nc_server_del_endpt_ssh(endpt, bind); + nc_server_config_del_endpt_ssh(endpt, bind); } cleanup: @@ -605,7 +605,7 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_create_ssh(struct nc_endpt *endpt) +nc_server_config_create_ssh(struct nc_endpt *endpt) { endpt->ti = NC_TI_LIBSSH; endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts)); @@ -633,12 +633,12 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) } if (op == NC_OP_CREATE) { - ret = nc_server_create_ssh(endpt); + ret = nc_server_config_create_ssh(endpt); if (ret) { goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_del_ssh(bind, endpt->opts.ssh); + nc_server_config_del_ssh(bind, endpt->opts.ssh); } cleanup: @@ -728,7 +728,7 @@ nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } - nc_server_del_local_address(bind); + nc_server_config_del_local_address(bind); bind->address = strdup(lyd_get_value(node)); if (!bind->address) { ERRMEM; @@ -904,7 +904,7 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts) +nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts) { node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); @@ -929,7 +929,7 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) } if (op == NC_OP_CREATE) { - ret = nc_server_create_host_key(node, endpt->opts.ssh); + ret = nc_server_config_create_host_key(node, endpt->opts.ssh); if (ret) { goto cleanup; } @@ -939,7 +939,7 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } - nc_server_del_hostkey(endpt->opts.ssh, hostkey); + nc_server_config_del_hostkey(endpt->opts.ssh, hostkey); } } else if (equal_parent_name(node, 1, "transport-params")) { /* just a container with the name host-key, nothing to be done */ @@ -1061,9 +1061,9 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op } static int -nc_server_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey) +nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey) { - nc_server_del_private_key(hostkey); + nc_server_config_del_private_key(hostkey); hostkey->key.priv_base64 = strdup(lyd_get_value(node)); if (!hostkey->key.priv_base64) { ERRMEM; @@ -1093,12 +1093,12 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_replace_cleartext_private_key(node, hostkey); + ret = nc_server_config_replace_cleartext_private_key(node, hostkey); if (ret) { goto cleanup; } } else { - nc_server_del_private_key(hostkey); + nc_server_config_del_private_key(hostkey); } } @@ -1107,7 +1107,7 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION } static int -nc_server_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey) +nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey) { uint16_t i; struct nc_keystore *ks = &server_opts.keystore; @@ -1151,9 +1151,9 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to keystore */ - hostkey->ks_type = NC_STORE_KEYSTORE; + hostkey->store = NC_STORE_KEYSTORE; - ret = nc_server_create_keystore_reference(node, hostkey); + ret = nc_server_config_create_keystore_reference(node, hostkey); if (ret) { goto cleanup; } @@ -1167,7 +1167,7 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op } static int -nc_server_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_client_auth *auth_client) +nc_server_config_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_client_auth *auth_client) { assert(!strcmp(LYD_NAME(node), "public-key")); @@ -1178,9 +1178,9 @@ nc_server_create_auth_key_public_key_list(const struct lyd_node *node, struct nc } static int -nc_server_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey) +nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey) { - nc_server_del_auth_client_pubkey_pub_base64(pubkey); + nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); pubkey->pub_base64 = strdup(lyd_get_value(node)); if (!pubkey->pub_base64) { @@ -1192,9 +1192,9 @@ nc_server_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct n } static int -nc_server_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey) +nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey) { - nc_server_del_public_key(hostkey); + nc_server_config_del_public_key(hostkey); hostkey->key.pub_base64 = strdup(lyd_get_value(node)); if (!hostkey->key.pub_base64) { @@ -1230,9 +1230,9 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to local */ - hostkey->ks_type = NC_STORE_LOCAL; + hostkey->store = NC_STORE_LOCAL; - ret = nc_server_replace_host_key_public_key(node, hostkey); + ret = nc_server_config_replace_host_key_public_key(node, hostkey); if (ret) { goto cleanup; } @@ -1251,9 +1251,9 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) if (op == NC_OP_CREATE) { /* set to local */ - auth_client->ks_type = NC_STORE_LOCAL; + auth_client->store = NC_STORE_LOCAL; - ret = nc_server_create_auth_key_public_key_list(node, auth_client); + ret = nc_server_config_create_auth_key_public_key_list(node, auth_client); if (ret) { goto cleanup; } @@ -1263,7 +1263,7 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } - nc_server_del_auth_client_pubkey(auth_client, pubkey); + nc_server_config_del_auth_client_pubkey(auth_client, pubkey); } } else if ((equal_parent_name(node, 6, "client-authentication")) && (equal_parent_name(node, 10, "listen"))) { /* client auth pubkey, leaf */ @@ -1283,12 +1283,12 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_replace_auth_key_public_key_leaf(node, pubkey); + ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey); if (ret) { goto cleanup; } } else { - nc_server_del_auth_client_pubkey_pub_base64(pubkey); + nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); } } @@ -1297,7 +1297,7 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts) +nc_server_config_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts) { node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); @@ -1322,7 +1322,7 @@ nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) } if (op == NC_OP_CREATE) { - ret = nc_server_create_user(node, endpt->opts.ssh); + ret = nc_server_config_create_user(node, endpt->opts.ssh); if (ret) { goto cleanup; } @@ -1332,7 +1332,7 @@ nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } - nc_server_del_auth_client(endpt->opts.ssh, auth_client); + nc_server_config_del_auth_client(endpt->opts.ssh, auth_client); } } @@ -1387,7 +1387,7 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth) +nc_server_config_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth) { uint16_t i; struct nc_truststore *ts = &server_opts.truststore; @@ -1432,9 +1432,9 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to truststore */ - auth_client->ks_type = NC_STORE_TRUSTSTORE; + auth_client->store = NC_STORE_TRUSTSTORE; - ret = nc_server_replace_truststore_reference(node, auth_client); + ret = nc_server_config_replace_truststore_reference(node, auth_client); if (ret) { goto cleanup; } @@ -1448,9 +1448,9 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION } static int -nc_server_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client) +nc_server_config_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client) { - nc_server_del_auth_client_password(auth_client); + nc_server_config_del_auth_client_password(auth_client); auth_client->password = strdup(lyd_get_value(node)); if (!auth_client->password) { @@ -1483,12 +1483,12 @@ nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_replace_password(node, auth_client); + ret = nc_server_config_replace_password(node, auth_client); if (ret) { goto cleanup; } } else { - nc_server_del_auth_client_password(auth_client); + nc_server_config_del_auth_client_password(auth_client); } } @@ -1517,7 +1517,7 @@ nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_del_auth_client_pam_name(auth_client); + nc_server_config_del_auth_client_pam_name(auth_client); auth_client->pam_config_name = strdup(lyd_get_value(node)); if (!auth_client->pam_config_name) { @@ -1553,7 +1553,7 @@ nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_del_auth_client_pam_dir(auth_client); + nc_server_config_del_auth_client_pam_dir(auth_client); auth_client->pam_config_dir = strdup(lyd_get_value(node)); if (!auth_client->pam_config_dir) { ERRMEM; @@ -1827,7 +1827,7 @@ nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_create_unix_socket(struct nc_endpt *endpt) +nc_server_config_create_unix_socket(struct nc_endpt *endpt) { endpt->ti = NC_TI_UNIX; endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock); @@ -1862,7 +1862,7 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) } if (op == NC_OP_CREATE) { - if (nc_server_create_unix_socket(endpt)) { + if (nc_server_config_create_unix_socket(endpt)) { ret = 1; goto cleanup; } @@ -1905,7 +1905,7 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_del_unix_socket(bind, endpt->opts.unixsock); + nc_server_config_del_unix_socket(bind, endpt->opts.unixsock); } cleanup: diff --git a/src/session_p.h b/src/session_p.h index 87dc3d65..f6d07faf 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -170,7 +170,7 @@ struct nc_auth_state { struct nc_client_auth { char *username; /**< Arbitrary username. */ - NC_STORE_TYPE ks_type; /**< Specifies how/where the client's public key is stored. */ + NC_STORE_TYPE store; /**< Specifies how/where the client's public key is stored. */ union { struct { struct nc_public_key *pubkeys; /**< The client's public keys. */ @@ -191,7 +191,7 @@ struct nc_client_auth { struct nc_hostkey { char *name; /**< Arbitrary name of the host key. */ - NC_STORE_TYPE ks_type; /**< Specifies how/where the key is stored. */ + NC_STORE_TYPE store; /**< Specifies how/where the key is stored. */ union { struct nc_asymmetric_key key; /**< The server's hostkey. */ struct nc_asymmetric_key *ks_ref; /**< Reference to a key-store. */ From f45462fba231080fc48a902a9270561d7e0f98f9 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 25 May 2023 14:27:51 +0200 Subject: [PATCH 027/134] config UPDATE add config replace test Added test for replacing configuration data. Renamed configuration setup API calls. Added loading JSON from files. --- examples/server.c | 2 +- src/server_config.c | 8 +- src/server_config.h | 12 +- tests/CMakeLists.txt | 2 +- tests/test_auth.c | 2 +- tests/test_config_new.c | 2 +- tests/test_ec.c | 2 +- tests/test_ed25519.c | 2 +- tests/test_keystore.c | 2 +- tests/test_replace.c | 298 ++++++++++++++++++++++++++++++++++++++ tests/test_truststore.c | 2 +- tests/test_two_channels.c | 2 +- tests/test_unix_socket.c | 2 +- 13 files changed, 318 insertions(+), 20 deletions(-) create mode 100644 tests/test_replace.c diff --git a/examples/server.c b/examples/server.c index c28db625..2ca22155 100644 --- a/examples/server.c +++ b/examples/server.c @@ -256,7 +256,7 @@ init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_T } /* apply the created configuration data */ - rc = nc_server_config_setup(config); + rc = nc_server_config_setup_diff(config); if (rc) { ERR_MSG_CLEANUP("Application of configuration data failed.\n"); } diff --git a/src/server_config.c b/src/server_config.c index 41c5a2f4..4221741d 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -2203,12 +2203,12 @@ nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path) NC_CHECK_ARG_RET(NULL, path, 1); - ret = lyd_parse_data_path(ctx, path, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); if (ret) { goto cleanup; } - ret = nc_server_config_setup(tree); + ret = nc_server_config_setup_data(tree); if (ret) { goto cleanup; } @@ -2240,7 +2240,7 @@ nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION o } API int -nc_server_config_setup(const struct lyd_node *data) +nc_server_config_setup_diff(const struct lyd_node *data) { int ret = 0; @@ -2275,7 +2275,7 @@ nc_server_config_setup(const struct lyd_node *data) } API int -nc_server_config_setup2(const struct lyd_node *data) +nc_server_config_setup_data(const struct lyd_node *data) { int ret = 0; struct lyd_node *tree, *iter, *root; diff --git a/src/server_config.h b/src/server_config.h index 9d3e161d..019db841 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -30,15 +30,15 @@ extern "C" { /** * @brief Configure server based on the given diff data. * - * Expected data is a validated instance of a ietf-netconf-server YANG data. + * Expected data are a validated instance of a ietf-netconf-server YANG data. * The data must be in the diff format and supported operations are: create, replace, * delete and none. Context must already have implemented the required modules, see * ::nc_config_load_modules(). * - * @param[in] data ietf-netconf-server YANG data. + * @param[in] diff ietf-netconf-server YANG diff data. * @return 0 on success, 1 on error. */ -int nc_server_config_setup(const struct lyd_node *data); +int nc_server_config_setup_diff(const struct lyd_node *diff); /** * @brief Configure server based on the given data. @@ -46,17 +46,17 @@ int nc_server_config_setup(const struct lyd_node *data); * Expected data is a validated instance of a ietf-netconf-server YANG data. * Behaves as if all the nodes in data had the replace operation. That means that the current configuration will be deleted * and just the given data will all be applied. - * The data must not contain any operation attribute, see ::nc_config_setup() which works with diff. + * The data must not contain any operation attribute, see ::nc_config_setup_diff() which works with diff. * Context must already have implemented the required modules, see * ::nc_config_load_modules(). * * @param[in] data ietf-netconf-server YANG data. * @return 0 on success, 1 on error. */ -int nc_server_config_setup2(const struct lyd_node *data); +int nc_server_config_setup_data(const struct lyd_node *data); /** * @brief Configure server based on the given ietf-netconf-server YANG data. - * Wrapper around ::nc_config_setup_server() hiding work with parsing the data. + * Wrapper around ::nc_config_setup_server_data() hiding work with parsing the data. * * @param[in] ctx libyang context. * @param[in] path Path to the file with YANG data in XML format. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2fee7768..65ee29ef 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,7 @@ endif() # list of all the tests in each directory #set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages) -set(tests test_two_channels test_keystore test_unix_socket test_config_new test_truststore test_ec test_ed25519) +set(tests test_two_channels test_keystore test_unix_socket test_config_new test_truststore test_ec test_ed25519 test_replace) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) diff --git a/tests/test_auth.c b/tests/test_auth.c index cdd14db9..a5a53d56 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -401,7 +401,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup(tree); + ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); /* initialize client */ diff --git a/tests/test_config_new.c b/tests/test_config_new.c index f7b77050..b82c6f20 100644 --- a/tests/test_config_new.c +++ b/tests/test_config_new.c @@ -168,7 +168,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup(tree); + ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); /* initialize client */ diff --git a/tests/test_ec.c b/tests/test_ec.c index f3f846c8..ad95a4e8 100644 --- a/tests/test_ec.c +++ b/tests/test_ec.c @@ -231,7 +231,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup(tree); + ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); /* initialize client */ diff --git a/tests/test_ed25519.c b/tests/test_ed25519.c index 110833aa..3a84f22b 100644 --- a/tests/test_ed25519.c +++ b/tests/test_ed25519.c @@ -162,7 +162,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup(tree); + ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); /* initialize client */ diff --git a/tests/test_keystore.c b/tests/test_keystore.c index f443b210..93129682 100644 --- a/tests/test_keystore.c +++ b/tests/test_keystore.c @@ -218,7 +218,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup(tree); + ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); /* initialize client */ diff --git a/tests/test_replace.c b/tests/test_replace.c new file mode 100644 index 00000000..28fd032d --- /dev/null +++ b/tests/test_replace.c @@ -0,0 +1,298 @@ +/** + * @file test_replace.c + * @author Roman Janota + * @brief libnetconf2 Non-diff YANG data configuration test + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 + +struct ly_ctx *ctx; + +struct test_state { + pthread_barrier_t barrier; +}; + +const char *old_data = + "\n" + " \n" + " 10\n" + " \n" + " old-ssh\n" + " \n" + " \n" + " 127.0.0.1\n" + " 10005\n" + " \n" + " \n" + " \n" + " \n" + " old_key\n" + " \n" + " \n" + " ct:ssh-public-key-format\n" + " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" + " ct:rsa-private-key-format\n" + " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " old_user\n" + " $6$xyz$lomVe5tZ2Gz9uSKKywzXuPcHhqjIByhBbqdUTx/jAwUnw7JRp7QHd4ORiEVqxeZg1NEJkHux.mETo9BFPSh1x.\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +const char *new_data = + "\n" + " \n" + " 10\n" + " \n" + " new-ssh\n" + " \n" + " \n" + " 127.0.0.1\n" + " 10005\n" + " \n" + " \n" + " \n" + " \n" + " new_key\n" + " \n" + " \n" + " ct:ssh-public-key-format\n" + " AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDRIB2eNSRWU+HNWRUGKr76ghCLg8RaMlUCps9lBjnc6ggaJl2Q+TOLn8se2wAdK3lYBMz3dcqR+SlU7eB8wJAc=\n" + " ct:ec-private-key-format\n" + " MHcCAQEEICQ2fr9Jt2xluom0YQQ7HseE8YTo5reZRVcQENKUWOrooAoGCCqGSM49AwEHoUQDQgAENEgHZ41JFZT4c1ZFQYqvvqCEIuDxFoyVQKmz2UGOdzqCBomXZD5M4ufyx7bAB0reVgEzPd1ypH5KVTt4HzAkBw==\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " new_user\n" + " \n" + " \n" + " \n" + " test\n" + " ct:ssh-public-key-format\n" + " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_thread_destroy(); + return NULL; +} + +static void * +client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + + /* set directory where to search for modules */ + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set ssh username */ + ret = nc_client_ssh_set_username("new_user"); + assert_int_equal(ret, 0); + + /* add client's key pair */ + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + assert_int_equal(ret, 0); + + /* wait for the server to reach polling */ + pthread_barrier_wait(&state->barrier); + + /* connect */ + session = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +nc_test_replace(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *old_tree = NULL, *new_tree = NULL; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + /* create new context */ + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* load default modules into context */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf-netconf-server module and it's imports into context */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* parse yang data */ + ret = lyd_parse_data_mem(ctx, old_data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &old_tree); + assert_int_equal(ret, 0); + + /* configure the server based on the yang data, treat them as if every node had replace operation */ + ret = nc_server_config_setup_data(old_tree); + assert_int_equal(ret, 0); + + /* parse the new yang data */ + ret = lyd_parse_data_mem(ctx, new_data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &new_tree); + assert_int_equal(ret, 0); + + /* configure the server based on the yang data, meaning + * everything configured will be deleted and only the new data applied + */ + ret = nc_server_config_setup_data(new_tree); + assert_int_equal(ret, 0); + + /* initialize the client */ + nc_client_init(); + + /* initialize the server */ + ret = nc_server_init(); + assert_int_equal(ret, 0); + + lyd_free_all(old_tree); + lyd_free_all(new_tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(nc_test_replace, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/test_truststore.c b/tests/test_truststore.c index aa5af9f0..5b386588 100644 --- a/tests/test_truststore.c +++ b/tests/test_truststore.c @@ -222,7 +222,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup(tree); + ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); /* initialize client */ diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c index 85ee4385..d56beccc 100644 --- a/tests/test_two_channels.c +++ b/tests/test_two_channels.c @@ -234,7 +234,7 @@ setup_f(void **state) ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_setup(tree); + ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); ret = nc_server_init(); diff --git a/tests/test_unix_socket.c b/tests/test_unix_socket.c index e1069821..deed6f96 100644 --- a/tests/test_unix_socket.c +++ b/tests/test_unix_socket.c @@ -147,7 +147,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup(tree); + ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); /* initialize client */ From 6db6b2fc45bafae74ea5d07115ee2369ffc8ae0d Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 26 May 2023 09:59:09 +0200 Subject: [PATCH 028/134] config UPDATE share clients between endpoints --- modules/libnetconf2-netconf-server.yang | 126 +++++++---- src/server_config.c | 151 ++++++++++++- src/server_config_ks.c | 2 +- src/server_config_p.h | 2 +- src/server_config_ts.c | 2 +- src/session_p.h | 4 +- tests/CMakeLists.txt | 2 +- tests/test_endpt_share_clients.c | 289 ++++++++++++++++++++++++ 8 files changed, 521 insertions(+), 57 deletions(-) create mode 100644 tests/test_endpt_share_clients.c diff --git a/modules/libnetconf2-netconf-server.yang b/modules/libnetconf2-netconf-server.yang index c9994bec..86ca47ae 100644 --- a/modules/libnetconf2-netconf-server.yang +++ b/modules/libnetconf2-netconf-server.yang @@ -11,53 +11,7 @@ module libnetconf2-netconf-server { prefix ct; } - augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { - leaf auth-attempts { - type uint16; - default 3; - } - - leaf auth-timeout { - type uint16; - default 10; - units "seconds"; - } - } - - augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" { - container keyboard-interactive { - presence ""; - leaf pam-config-file-name { - type string; - mandatory true; - } - leaf pam-config-file-dir { - type string; - } - } - } - - augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport" { - case unix-socket { - container unix-socket { - leaf path { - type string; - mandatory true; - } - leaf mode { - type uint16; - } - leaf uid { - type uint16; - } - leaf gid { - type uint16; - } - } - } - } - -/* + /* identity ed25519-private-key-format { base ct:private-key-format; description @@ -126,4 +80,82 @@ module libnetconf2-netconf-server { RFC 4253: The Secure Shell (SSH) Transport Layer Protocol"; } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { + leaf auth-attempts { + type uint16; + default 3; + } + + leaf auth-timeout { + type uint16; + default 10; + units "seconds"; + } + } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" { + container keyboard-interactive { + presence ""; + leaf pam-config-file-name { + type string; + mandatory true; + } + leaf pam-config-file-dir { + type string; + } + } + } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport" { + case unix-socket { + container unix-socket { + leaf path { + type string; + mandatory true; + } + leaf mode { + type uint16; + } + leaf uid { + type uint16; + } + leaf gid { + type uint16; + } + } + } + } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { + description + "Reference to another SSH endpoint's client-authentication container. + All the users set in the referencing endpoint will be tried first and if and only if + there is no match, the referenced endpoint's users will be tried. The references can be + multiple, however there must not be a cycle."; + + leaf endpoint-client-auth { + type leafref { + path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name"; + } + + must "deref(.)/../*[local-name() = 'ssh']"; + } + } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { + description + "Reference to another TLS endpoint's client-authentication container. + All the users set in the referencing endpoint will be tried first and if and only if + there is no match, the referenced endpoint's users will be tried. The references can be + multiple, however there must not be a cycle."; + + leaf endpoint-client-auth { + type leafref { + path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name"; + } + + must "deref(.)/../*[local-name() = 'tls']"; + } + } } diff --git a/src/server_config.c b/src/server_config.c index 4221741d..4d4191ca 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -274,6 +274,13 @@ nc_server_config_del_endpt_name(struct nc_endpt *endpt) endpt->name = NULL; } +static void +nc_server_config_del_endpt_reference(struct nc_endpt *endpt) +{ + free(endpt->referenced_endpt_name); + endpt->referenced_endpt_name = NULL; +} + static void nc_server_config_del_local_address(struct nc_bind *bind) { @@ -447,6 +454,7 @@ void nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) { nc_server_config_del_endpt_name(endpt); + nc_server_config_del_endpt_reference(endpt); nc_server_config_del_ssh(bind, endpt->opts.ssh); server_opts.endpt_count--; @@ -491,14 +499,15 @@ nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *b int nc_server_config_listen(struct lyd_node *node, NC_OPERATION op) { - uint16_t i; + uint16_t i, endpt_count; (void) node; assert(op == NC_OP_CREATE || op == NC_OP_DELETE); if (op == NC_OP_DELETE) { - for (i = 0; i < server_opts.endpt_count; i++) { + endpt_count = server_opts.endpt_count; + for (i = 0; i < endpt_count; i++) { switch (server_opts.endpts[i].ti) { #ifdef NC_ENABLED_SSH case NC_TI_LIBSSH: @@ -1912,6 +1921,129 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) return ret; } +/** + * @brief Set all endpoint client auth references, which couldn't be set beforehand. + * + * The references that could not be set are those, which reference endpoints, which + * lie below the given endpoint in the YANG data (because of DFS tree parsing). + * + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_fill_endpt_client_auth(void) +{ + uint16_t i, j; + + for (i = 0; i < server_opts.endpt_count; i++) { + /* go through all the endpoint */ + if (server_opts.endpts[i].referenced_endpt_name) { + /* endpt has a reference, that hasn't been set yet */ + for (j = i + 1; j < server_opts.endpt_count; j++) { + /* go through all the remaining endpts */ + if (!strcmp(server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[j].name)) { + /* found the endpoint we were looking for */ + if (server_opts.endpts[i].ti == NC_TI_LIBSSH) { + server_opts.endpts[i].opts.ssh->endpt_client_ref = &server_opts.endpts[j]; + break; + } else { + ERRINT; + return 1; + } + } + } + + /* didn't find the endpoint */ + if (j == server_opts.endpt_count) { + ERR(NULL, "Endpoint \"%s\" referenced by \"%s\" not found.", + server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name); + return 1; + } + } + } + + return 0; +} + +static int +nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next, NC_TRANSPORT_IMPL transport) +{ + if (transport == NC_TI_LIBSSH) { + if (next->opts.ssh->endpt_client_ref) { + if (next->opts.ssh->endpt_client_ref == original) { + return 1; + } else { + return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref, NC_TI_LIBSSH); + } + } else { + return 0; + } + } else { + ERRINT; + return 1; + } +} + +static int +nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + uint16_t i; + const char *endpt_name; + struct nc_endpt *endpt; + + assert(!strcmp(LYD_NAME(node), "endpoint-client-auth")); + + /* get current endpoint */ + ret = nc_server_config_get_endpt(node, &endpt, NULL); + if (ret) { + goto cleanup; + } + + if (op == NC_OP_DELETE) { + endpt->opts.ssh->endpt_client_ref = NULL; + goto cleanup; + } + + /* find the endpoint leafref is referring to */ + endpt_name = lyd_get_value(node); + for (i = 0; i < server_opts.endpt_count; i++) { + if (!strcmp(endpt_name, server_opts.endpts[i].name)) { + break; + } + } + + if (i == server_opts.endpt_count) { + /* endpt not found, save the name and try to look it up later */ + endpt->referenced_endpt_name = strdup(endpt_name); + if (!endpt->referenced_endpt_name) { + ERRMEM; + ret = 1; + goto cleanup; + } + goto cleanup; + } + + /* check for self reference */ + if (endpt == &server_opts.endpts[i]) { + ERR(NULL, "Self client authentication reference detected."); + ret = 1; + goto cleanup; + } + + /* check for cyclic references */ + ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i], endpt->ti); + if (ret) { + ERR(NULL, "Cyclic client authentication reference detected."); + goto cleanup; + } + + /* assign the current endpt the referrenced endpt */ + endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i]; + +cleanup: + return ret; +} + static int nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op) { @@ -2033,6 +2165,10 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_unix_socket(node, op)) { goto error; } + } else if (!strcmp(name, "endpoint-client-auth")) { + if (nc_server_config_endpoint_client_auth(node, op)) { + goto error; + } } else if (!strcmp(name, "cert-data")) {} else if (!strcmp(name, "expiration-date")) {} else if (!strcmp(name, "asymmetric-key")) {} else if (!strcmp(name, "certificate")) {} else if (!strcmp(name, "key-format")) {} else if (!strcmp(name, "cleartext-key")) {} else if (!strcmp(name, "hidden-key")) {} else if (!strcmp(name, "id_hint")) {} else if (!strcmp(name, "external-identity")) {} else if (!strcmp(name, "hash")) {} else if (!strcmp(name, "context")) {} else if (!strcmp(name, "target-protocol")) {} else if (!strcmp(name, "target-kdf")) {} else if (!strcmp(name, "client-authentication")) {} else if (!strcmp(name, "ca-certs")) {} else if (!strcmp(name, "ee-certs")) {} else if (!strcmp(name, @@ -2048,7 +2184,7 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION } int -nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module) +nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module) { struct lyd_node *child; struct lyd_meta *m; @@ -2103,7 +2239,7 @@ nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op if (current_op != NC_OP_DELETE) { LY_LIST_FOR(lyd_child(node), child) { - if (nc_session_server_parse_tree(child, current_op, module)) { + if (nc_server_config_parse_tree(child, current_op, module)) { return 1; } } @@ -2230,7 +2366,12 @@ nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION o goto cleanup; } - if (nc_session_server_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) { + if (nc_server_config_parse_tree(tree, op, NC_MODULE_NETCONF_SERVER)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_fill_endpt_client_auth()) { ret = 1; goto cleanup; } diff --git a/src/server_config_ks.c b/src/server_config_ks.c index da00811b..dfcb3857 100644 --- a/src/server_config_ks.c +++ b/src/server_config_ks.c @@ -478,7 +478,7 @@ nc_server_config_fill_keystore(const struct lyd_node *data, NC_OPERATION op) goto cleanup; } - if (nc_session_server_parse_tree(tree, op, NC_MODULE_KEYSTORE)) { + if (nc_server_config_parse_tree(tree, op, NC_MODULE_KEYSTORE)) { ret = 1; goto cleanup; } diff --git a/src/server_config_p.h b/src/server_config_p.h index deaec676..7d5469df 100644 --- a/src/server_config_p.h +++ b/src/server_config_p.h @@ -106,7 +106,7 @@ int nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uin * @param[in] module Module for which to parse the data - either ietf-netconf-server, ietf-keystore or ietf-truststore * @return 0 on success, 1 on error. */ -int nc_session_server_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module); +int nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, NC_MODULE module); /** * @brief Configures the listen subtree in the ietf-netconf-server module. diff --git a/src/server_config_ts.c b/src/server_config_ts.c index 12c4cdd1..9b06ada9 100644 --- a/src/server_config_ts.c +++ b/src/server_config_ts.c @@ -618,7 +618,7 @@ nc_server_config_fill_truststore(const struct lyd_node *data, NC_OPERATION op) goto cleanup; } - if (nc_session_server_parse_tree(tree, op, NC_MODULE_TRUSTSTORE)) { + if (nc_server_config_parse_tree(tree, op, NC_MODULE_TRUSTSTORE)) { ret = 1; goto cleanup; } diff --git a/src/session_p.h b/src/session_p.h index f6d07faf..6628a3de 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -208,6 +208,8 @@ struct nc_server_ssh_opts { struct nc_client_auth *auth_clients; /**< Server's authorized clients. */ uint16_t client_count; /**< Number of server's authorized clients. */ + struct nc_endpt *endpt_client_ref; /**< Reference to another endpoint (used for client authentication). */ + char *hostkey_algs; /**< Hostkey algorithms supported by the server. */ char *encryption_algs; /**< Encryption algorithms supported by the server. */ char *kex_algs; /**< Key exchange algorithms supported by the server. */ @@ -419,7 +421,7 @@ struct nc_server_opts { struct nc_bind *binds; struct nc_endpt { char *name; - int changed; + char *referenced_endpt_name; NC_TRANSPORT_IMPL ti; struct nc_keepalives ka; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 65ee29ef..68aee07b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,7 @@ endif() # list of all the tests in each directory #set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages) -set(tests test_two_channels test_keystore test_unix_socket test_config_new test_truststore test_ec test_ed25519 test_replace) +set(tests test_two_channels test_keystore test_unix_socket test_config_new test_truststore test_ec test_ed25519 test_replace test_endpt_share_clients) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c new file mode 100644 index 00000000..21cc2f69 --- /dev/null +++ b/tests/test_endpt_share_clients.c @@ -0,0 +1,289 @@ +/** + * @file test_endpt_share_clients.c + * @author Roman Janota + * @brief libnetconf2 Sharing clients between endpoints test + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 + +struct ly_ctx *ctx; + +struct test_state { + pthread_barrier_t barrier; +}; + +const char *data = + "\n" + " \n" + " 10\n" + " \n" + " endpoint_1\n" + " \n" + " \n" + " 127.0.0.1\n" + " 10005\n" + " \n" + " \n" + " \n" + " \n" + " hostkey\n" + " \n" + " \n" + " ct:ssh-public-key-format\n" + " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" + " ct:rsa-private-key-format\n" + " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client\n" + " \n" + " \n" + " \n" + " test\n" + " ct:ssh-public-key-format\n" + " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " endpoint_2\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " endpoint_2\n" + " \n" + " \n" + " 127.0.0.1\n" + " 10006\n" + " \n" + " \n" + " \n" + " \n" + " hostkey\n" + " \n" + " \n" + " ct:ssh-public-key-format\n" + " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" + " ct:rsa-private-key-format\n" + " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client2\n" + " \n" + " \n" + " \n" + " test\n" + " ct:ssh-public-key-format\n" + " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_thread_destroy(); + return NULL; +} + +static void * +client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + + /* set directory where to search for modules */ + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set ssh username */ + ret = nc_client_ssh_set_username("client"); + assert_int_equal(ret, 0); + + /* add client's key pair */ + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + assert_int_equal(ret, 0); + + /* wait for the server to reach polling */ + pthread_barrier_wait(&state->barrier); + + /* connect */ + session = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +nc_test_endpt_share_clients(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + /* create new context */ + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* load default modules into context */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf-netconf-server module and it's imports into context */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* parse yang data */ + ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the yang data */ + ret = nc_server_config_setup_data(tree); + assert_int_equal(ret, 0); + + /* initialize the client */ + nc_client_init(); + + /* initialize the server */ + ret = nc_server_init(); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(nc_test_endpt_share_clients, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} From b16b2e78ef65712fc553dc268dff6c5e0d72f314 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 26 May 2023 13:26:02 +0200 Subject: [PATCH 029/134] config UPDATE add support for libssh params Added identities for libssh's host-key, key exchange, encryption and mac algs. --- modules/libnetconf2-netconf-server.yang | 151 ++++++++++++++++++++++++ src/server_config.c | 48 ++++++-- 2 files changed, 189 insertions(+), 10 deletions(-) diff --git a/modules/libnetconf2-netconf-server.yang b/modules/libnetconf2-netconf-server.yang index 86ca47ae..185dafc1 100644 --- a/modules/libnetconf2-netconf-server.yang +++ b/modules/libnetconf2-netconf-server.yang @@ -11,6 +11,22 @@ module libnetconf2-netconf-server { prefix ct; } + import iana-ssh-public-key-algs { + prefix sshpka; + } + + import iana-ssh-key-exchange-algs { + prefix sshkea; + } + + import iana-ssh-encryption-algs { + prefix sshea; + } + + import iana-ssh-mac-algs { + prefix sshma; + } + /* identity ed25519-private-key-format { base ct:private-key-format; @@ -81,6 +97,141 @@ module libnetconf2-netconf-server { The Secure Shell (SSH) Transport Layer Protocol"; } + identity openssh-ssh-ed25519-cert-v01 { + base sshpka:public-key-alg-base; + description + "SSH-ED25519-CERT-V01@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL.certkeys: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD"; + } + + identity openssh-ecdsa-sha2-nistp521-cert-v01 { + base sshpka:public-key-alg-base; + description + "ECDSA-SHA2-NISTP521-CERT-V01@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL.certkeys: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD"; + } + + identity openssh-ecdsa-sha2-nistp384-cert-v01 { + base sshpka:public-key-alg-base; + description + "ECDSA-SHA2-NISTP384-CERT-V01@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL.certkeys: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD"; + } + + identity openssh-ecdsa-sha2-nistp256-cert-v01 { + base sshpka:public-key-alg-base; + description + "ECDSA-SHA2-NISTP256-CERT-V01@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL.certkeys: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD"; + } + + identity openssh-rsa-sha2-512-cert-v01 { + base sshpka:public-key-alg-base; + description + "RSA-SHA2-512-CERT-V01@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL.certkeys: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD"; + } + + identity openssh-rsa-sha2-256-cert-v01 { + base sshpka:public-key-alg-base; + description + "RSA-SHA2-256-CERT-V01@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL.certkeys: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD"; + } + + identity openssh-ssh-rsa-cert-v01 { + base sshpka:public-key-alg-base; + description + "SSH-RSA-CERT-V01@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL.certkeys: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD"; + } + + identity openssh-ssh-dss-cert-v01 { + base sshpka:public-key-alg-base; + description + "SSH-DSS-CERT-V01@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL.certkeys: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD"; + } + + identity libssh-curve25519-sha256 { + base sshkea:key-exchange-alg-base; + description + "CURVE25519-SHA256@LIBSSH.ORG"; + reference + "curve25519-sha256@libssh.org specification: + https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt"; + } + + identity openssh-chacha20-poly1305 { + base sshea:encryption-alg-base; + description + "CHACHA20-POLY1305@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL.chacha20poly1305: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.chacha20poly1305?annotate=HEAD"; + } + + identity openssh-aes256-gcm { + base sshea:encryption-alg-base; + description + "AES256-GCM@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL, Section 1.6: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD"; + } + + identity openssh-aes128-gcm { + base sshea:encryption-alg-base; + description + "AES128-GCM@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL, Section 1.6: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD"; + } + + identity openssh-hmac-sha2-256-etm { + base sshma:mac-alg-base; + description + "HMAC-SHA2-256-ETM@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD"; + } + + identity openssh-hmac-sha2-512-etm { + base sshma:mac-alg-base; + description + "HMAC-SHA2-512-ETM@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD"; + } + + identity openssh-hmac-sha1-etm { + base sshma:mac-alg-base; + description + "HMAC-SHA1-ETM@OPENSSH.COM"; + reference + "OpenSSH PROTOCOL: + https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD"; + } + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { leaf auth-attempts { type uint16; diff --git a/src/server_config.c b/src/server_config.c index 4d4191ca..9ec3e433 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -29,28 +29,28 @@ /* All libssh supported host-key, key-exchange, encryption and mac algorithms as of version 0.10.90 */ static const char *supported_hostkey_algs[] = { - "ssh-ed25519-cert-v01@openssh.com", "ecdsa-sha2-nistp521-cert-v01@openssh.com", - "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ecdsa-sha2-nistp256-cert-v01@openssh.com", - "rsa-sha2-512-cert-v01@openssh.com", "rsa-sha2-256-cert-v01@openssh.com", - "ssh-rsa-cert-v01@openssh.com", "ssh-dss-cert-v01@openssh.com", + "openssh-ssh-ed25519-cert-v01", "openssh-ecdsa-sha2-nistp521-cert-v01", + "openssh-ecdsa-sha2-nistp384-cert-v01", "openssh-ecdsa-sha2-nistp256-cert-v01", + "openssh-rsa-sha2-512-cert-v01", "openssh-rsa-sha2-256-cert-v01", + "openssh-ssh-rsa-cert-v01", "openssh-ssh-dss-cert-v01", "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256", "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL }; static const char *supported_kex_algs[] = { - "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "curve25519-sha256@libssh.org", + "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "libssh-curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group18-sha512", "diffie-hellman-group16-sha512", "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", NULL }; static const char *supported_encryption_algs[] = { - "chacha20-poly1305@openssh.com", "aes256-gcm@openssh.com", "aes128-gcm@openssh.com", + "openssh-chacha20-poly1305", "openssh-aes256-gcm", "openssh-aes128-gcm", "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc", "blowfish-cbc", "triple-des-cbc", "none", NULL }; static const char *supported_mac_algs[] = { - "hmac-sha2-256-etm@openssh.com", "hmac-sha2-512-etm@openssh.com", "hmac-sha1-etm@openssh.com", + "openssh-hmac-sha2-256-etm", "openssh-hmac-sha2-512-etm", "openssh-hmac-sha1-etm", "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL }; @@ -1609,11 +1609,38 @@ nc_server_config_none(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_config_transport_params(const char *alg, char **alg_store, NC_OPERATION op) +nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op) { int ret = 0, alg_found = 0; - char *substr, *haystack; - size_t alg_len = strlen(alg); + char *substr, *haystack, *alg = NULL; + size_t alg_len; + + if (!strncmp(algorithm, "openssh-", 8)) { + /* if the name starts with openssh, convert it to it's original libssh accepted form */ + asprintf(&alg, "%s@openssh.com", algorithm + 8); + if (!alg) { + ERRMEM; + ret = 1; + goto cleanup; + } + } else if (!strncmp(algorithm, "libssh-", 7)) { + /* if the name starts with libssh, convert it to it's original libssh accepted form */ + asprintf(&alg, "%s@libssh.org", algorithm + 7); + if (!alg) { + ERRMEM; + ret = 1; + goto cleanup; + } + } else { + alg = strdup(algorithm); + if (!alg) { + ERRMEM; + ret = 1; + goto cleanup; + } + } + + alg_len = strlen(alg); if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { if (!*alg_store) { @@ -1660,6 +1687,7 @@ nc_server_config_transport_params(const char *alg, char **alg_store, NC_OPERATIO } cleanup: + free(alg); return ret; } From 9290a6f99da8614995541341cdcb7589997c18bb Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 5 Jun 2023 14:26:58 +0200 Subject: [PATCH 030/134] config UPDATE add support for TLS New API for configuring TLS added. For the server, only it's certificate is currently supported. For the client, only it's end-entity and certificate-authority certificates are supported (as compared to ietf-netconf-server module). Each source and header files' includes were refactored (added missing/deleted redundant). New file to generate documentation from added to replace the old one. New API parameters position changed. Split the API to SSH/TLS/common files and added new common header for these. Made changes to some internal structures and renamed some members. --- CMakeLists.txt | 21 +- Doxyfile.in | 2 +- src/libnetconf.h => doc/libnetconf.doc | 31 - examples/server.c | 6 +- src/config_new.c | 693 +++++++++ src/{config_new_ssh.h => config_new.h} | 27 +- src/config_new_ssh.c | 642 ++------- src/config_new_tls.c | 406 ++++++ src/io.c | 9 +- src/log.c | 4 +- src/log_p.h | 3 +- src/messages_client.c | 8 +- src/messages_p.h | 3 + src/messages_server.c | 7 +- src/messages_server.h | 4 +- src/netconf.h | 2 - src/server_config.c | 1385 +++++++++++++++--- src/server_config.h | 134 +- src/server_config_ks.c | 61 +- src/server_config_p.h | 15 +- src/server_config_ts.c | 26 +- src/session.c | 41 +- src/session.h | 14 - src/session_client.c | 7 +- src/session_client_ssh.c | 6 +- src/session_client_tls.c | 6 +- src/session_p.h | 131 +- src/session_server_ch.h | 1 + src/session_server_tls.c | 1811 +++++++++--------------- tests/CMakeLists.txt | 17 +- tests/test_config_new.c | 6 +- tests/test_ec.c | 10 +- tests/test_ed25519.c | 6 +- tests/test_tls.c | 207 +++ tests/test_unix_socket.c | 4 + 35 files changed, 3651 insertions(+), 2105 deletions(-) rename src/libnetconf.h => doc/libnetconf.doc (96%) create mode 100644 src/config_new.c rename src/{config_new_ssh.h => config_new.h} (66%) create mode 100644 src/config_new_tls.c create mode 100644 tests/test_tls.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e21faa5e..6c08b017 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,7 @@ option(ENABLE_EXAMPLES "Build examples" ON) option(ENABLE_COVERAGE "Build code coverage report from tests" OFF) option(ENABLE_SSH "Enable NETCONF over SSH support (via libssh)" ON) option(ENABLE_TLS "Enable NETCONF over TLS support (via OpenSSL)" ON) +# 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) set(READ_INACTIVE_TIMEOUT 20 CACHE STRING "Maximum number of seconds waiting for new data once some data have arrived") set(READ_ACTIVE_TIMEOUT 300 CACHE STRING "Maximum number of seconds for receiving a full message") @@ -115,19 +116,21 @@ set(libsrc src/server_config.c src/server_config_ks.c src/server_config_ts.c - src/config_new_ssh.c) + src/config_new.c) if(ENABLE_SSH) list(APPEND libsrc src/session_client_ssh.c - src/session_server_ssh.c) + src/session_server_ssh.c + src/config_new_ssh.c) set(SSH_MACRO "#ifndef NC_ENABLED_SSH\n#define NC_ENABLED_SSH\n#endif") endif() if(ENABLE_TLS) list(APPEND libsrc src/session_client_tls.c - src/session_server_tls.c) + src/session_server_tls.c + src/config_new_tls.c) set(TLS_MACRO "#ifndef NC_ENABLED_TLS\n#define NC_ENABLED_TLS\n#endif") endif() @@ -145,7 +148,7 @@ set(headers # files to generate doxygen from set(doxy_files - src/libnetconf.h + doc/libnetconf.doc src/log.h src/netconf.h src/session.h @@ -233,14 +236,11 @@ check_function_exists(pthread_rwlockattr_setkind_np HAVE_PTHREAD_RWLOCKATTR_SETK # dependencies - openssl if(ENABLE_TLS OR ENABLE_DNSSEC OR ENABLE_SSH) - find_package(OpenSSL REQUIRED) + find_package(OpenSSL 3.0.0 REQUIRED) if(ENABLE_TLS) message(STATUS "OpenSSL found, required for TLS") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_ENABLED_TLS") endif() - if(OPENSSL_VERSION VERSION_LESS 1.1.1) - message(WARNING "OpenSSL version ${OPENSSL_VERSION} is no longer maintained, consider an update.") - endif() target_link_libraries(netconf2 ${OPENSSL_LIBRARIES}) include_directories(${OPENSSL_INCLUDE_DIR}) @@ -248,10 +248,7 @@ endif() # dependencies - libssh if(ENABLE_SSH) - find_package(LibSSH 0.7.1 REQUIRED) - if(LIBSSH_VERSION VERSION_EQUAL 0.9.3 OR LIBSSH_VERSION VERSION_EQUAL 0.9.4) - message(FATAL_ERROR "LibSSH ${LIBSSH_VERSION} includes regression bugs and libnetconf2 will NOT work properly, try to use another version") - endif() + find_package(LibSSH 0.9.5 REQUIRED) target_link_libraries(netconf2 ${LIBSSH_LIBRARIES}) list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBSSH_LIBRARIES}) diff --git a/Doxyfile.in b/Doxyfile.in index 324e670f..445709fc 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -2184,7 +2184,7 @@ HIDE_UNDOC_RELATIONS = YES # set to NO # The default value is: NO. -HAVE_DOT = @HAVE_DOT@ +HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of diff --git a/src/libnetconf.h b/doc/libnetconf.doc similarity index 96% rename from src/libnetconf.h rename to doc/libnetconf.doc index a09c1983..83d0d450 100644 --- a/src/libnetconf.h +++ b/doc/libnetconf.doc @@ -1,32 +1,3 @@ -/** - * @file libnetconf.h - * @author Radek Krejci - * @author Michal Vasko - * @brief libnetconf2 main internal header. - * - * @copyright - * Copyright (c) 2015 - 2021 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_LIBNETCONF_H_ -#define NC_LIBNETCONF_H_ - -#include "config.h" -#include "log_p.h" -#include "messages_p.h" -#include "netconf.h" -#include "session_p.h" - -/* Tests whether string is empty or non-empty. */ -#define strisempty(str) ((str)[0] == '\0') -#define strnonempty(str) ((str)[0] != '\0') - /** * @mainpage About * @@ -664,5 +635,3 @@ * @defgroup server Server * @brief NETCONF server functionality. */ - -#endif /* NC_LIBNETCONF_H_ */ diff --git a/examples/server.c b/examples/server.c index 2ca22155..bfa6ece8 100644 --- a/examples/server.c +++ b/examples/server.c @@ -238,19 +238,19 @@ init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_T /* this is where the YANG configuration data gets generated, * start by creating hostkey configuration data */ - rc = nc_server_config_new_ssh_hostkey(hostkey_path, NULL, *context, "endpt", "hostkey", &config); + rc = nc_server_config_new_ssh_hostkey(*context, "endpt", "hostkey", hostkey_path, NULL, &config); if (rc) { ERR_MSG_CLEANUP("Error creating new hostkey configuration data.\n"); } /* create address and port configuration data */ - rc = nc_server_config_new_ssh_address_port(SSH_ADDRESS, SSH_PORT, *context, "endpt", &config); + rc = nc_server_config_new_address_port(*context, "endpt", NC_TI_LIBSSH, SSH_ADDRESS, SSH_PORT, &config); if (rc) { ERR_MSG_CLEANUP("Error creating new address and port configuration data.\n"); } /* create client authentication configuration data */ - rc = nc_server_config_new_ssh_client_auth_password(SSH_PASSWORD, *context, "endpt", SSH_USERNAME, &config); + rc = nc_server_config_new_ssh_client_auth_password(*context, "endpt", SSH_USERNAME, SSH_PASSWORD, &config); if (rc) { ERR_MSG_CLEANUP("Error creating client authentication configuration data.\n"); } diff --git a/src/config_new.c b/src/config_new.c new file mode 100644 index 00000000..4a20fe59 --- /dev/null +++ b/src/config_new.c @@ -0,0 +1,693 @@ +/** + * @file config_new.c + * @author Roman Janota + * @brief libnetconf2 server new configuration creation functions + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "compat.h" +#include "config_new.h" +#include "log_p.h" +#include "session.h" +#include "session_p.h" + +int +nc_config_new_check_add_operation(const struct ly_ctx *ctx, struct lyd_node *top) +{ + if (lyd_find_meta(top->meta, NULL, "yang:operation")) { + /* it already has operation attribute */ + return 0; + } + + /* give the top level container create operation */ + if (lyd_new_meta(ctx, top, NULL, "yang:operation", "create", 0, NULL)) { + return 1; + } + + return 0; +} + +const char * +nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT format) +{ + switch (format) { + case NC_PRIVKEY_FORMAT_RSA: + return "ietf-crypto-types:rsa-private-key-format"; + case NC_PRIVKEY_FORMAT_EC: + return "ietf-crypto-types:ec-private-key-format"; + case NC_PRIVKEY_FORMAT_X509: + return "libnetconf2-netconf-server:subject-private-key-info-format"; + case NC_PRIVKEY_FORMAT_OPENSSH: + return "libnetconf2-netconf-server:openssh-private-key-format"; + default: + ERR(NULL, "Private key type not supported."); + return NULL; + } +} + +int +nc_server_config_new_read_certificate(const char *cert_path, char **cert) +{ + int ret = 0, cert_len; + X509 *x509 = NULL; + FILE *f = NULL; + BIO *bio = NULL; + char *c = NULL; + + *cert = NULL; + + f = fopen(cert_path, "r"); + if (!f) { + ERR(NULL, "Unable to open certificate file \"%s\".", cert_path); + ret = 1; + goto cleanup; + } + + /* load the cert into memory */ + x509 = PEM_read_X509(f, NULL, NULL, NULL); + if (!x509) { + ret = -1; + goto cleanup; + } + + bio = BIO_new(BIO_s_mem()); + if (!bio) { + ret = -1; + goto cleanup; + } + + ret = PEM_write_bio_X509(bio, x509); + if (!ret) { + ret = -1; + goto cleanup; + } + + cert_len = BIO_pending(bio); + if (cert_len <= 0) { + ret = -1; + goto cleanup; + } + + c = malloc(cert_len + 1); + if (!c) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* read the cert from bio */ + ret = BIO_read(bio, c, cert_len); + if (ret <= 0) { + ret = -1; + goto cleanup; + } + c[cert_len] = '\0'; + + /* strip the cert of the header and footer */ + *cert = strdup(c + strlen(NC_PEM_CERTIFICATE_HEADER)); + if (!*cert) { + ERRMEM; + ret = 1; + goto cleanup; + } + + (*cert)[strlen(*cert) - strlen(NC_PEM_CERTIFICATE_FOOTER)] = '\0'; + + ret = 0; + +cleanup: + if (ret == -1) { + ERR(NULL, "Error getting certificate from file \"%s\" (OpenSSL Error): \"%s\".", cert_path, ERR_reason_error_string(ERR_get_error())); + ret = 1; + } + if (f) { + fclose(f); + } + + BIO_free(bio); + X509_free(x509); + free(c); + return ret; +} + +static int +nc_server_config_new_read_ssh2_pubkey(FILE *f, char **pubkey) +{ + char *buffer = NULL; + size_t size = 0, pubkey_len = 0; + void *tmp; + ssize_t read; + int ret = 0; + + while ((read = getline(&buffer, &size, f)) > 0) { + if (!strncmp(buffer, "----", 4)) { + continue; + } + + if (!strncmp(buffer, "Comment:", 8)) { + continue; + } + + if (buffer[read - 1] == '\n') { + read--; + } + + tmp = realloc(*pubkey, pubkey_len + read + 1); + if (!tmp) { + ERRMEM; + ret = 1; + goto cleanup; + } + + *pubkey = tmp; + memcpy(*pubkey + pubkey_len, buffer, read); + pubkey_len += read; + } + + if (!pubkey_len) { + ERR(NULL, "Unexpected public key format."); + ret = 1; + goto cleanup; + } + + (*pubkey)[pubkey_len] = '\0'; + +cleanup: + free(buffer); + return ret; +} + +static int +nc_server_config_new_read_pubkey_openssl(FILE *f, char **pubkey) +{ + int ret = 0; + EVP_PKEY *pkey = NULL; + BIO *bio = NULL; + char *key = NULL; + int pub_len; + + /* read the pubkey from file */ + pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL); + if (!pkey) { + ret = -1; + goto cleanup; + } + + bio = BIO_new(BIO_s_mem()); + if (!bio) { + ret = -1; + goto cleanup; + } + + /* write the pubkey into bio */ + ret = PEM_write_bio_PUBKEY(bio, pkey); + if (!ret) { + ret = -1; + goto cleanup; + } + + pub_len = BIO_pending(bio); + if (pub_len <= 0) { + ret = -1; + goto cleanup; + } + + /* get pubkey's length */ + key = malloc(pub_len + 1); + if (!key) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* read the public key from bio */ + ret = BIO_read(bio, key, pub_len); + if (ret <= 0) { + ret = -1; + goto cleanup; + } + key[pub_len] = '\0'; + + /* strip the pubkey of the header and footer */ + *pubkey = strdup(key + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER)); + if (!*pubkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + + (*pubkey)[strlen(*pubkey) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER)] = '\0'; + + ret = 0; +cleanup: + if (ret == -1) { + ERR(NULL, "Error getting public key from file (OpenSSL Error): \"%s\".", ERR_reason_error_string(ERR_get_error())); + ret = 1; + } + + BIO_free(bio); + EVP_PKEY_free(pkey); + free(key); + + return ret; +} + +#ifdef NC_ENABLED_SSH + +static int +nc_server_config_new_read_pubkey_libssh(const char *pubkey_path, char **pubkey) +{ + int ret = 0; + ssh_key pub_sshkey = NULL; + + ret = ssh_pki_import_pubkey_file(pubkey_path, &pub_sshkey); + if (ret) { + ERR(NULL, "Importing public key from file \"%s\" failed.", pubkey_path); + return ret; + } + + ret = ssh_pki_export_pubkey_base64(pub_sshkey, pubkey); + if (ret) { + ERR(NULL, "Exporting public key to base64 failed."); + } + + ssh_key_free(pub_sshkey); + return ret; +} + +#endif /* NC_ENABLED_SSH */ + +int +nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_PUBKEY_FORMAT *pubkey_type) +{ + int ret = 0; + FILE *f = NULL; + char *header = NULL; + size_t len = 0; + + NC_CHECK_ARG_RET(NULL, pubkey, pubkey_type, 1); + + *pubkey = NULL; + + f = fopen(pubkey_path, "r"); + if (!f) { + ERR(NULL, "Unable to open file \"%s\".", pubkey_path); + ret = 1; + goto cleanup; + } + + if (getline(&header, &len, f) < 0) { + ERR(NULL, "Error reading header from file \"%s\".", pubkey_path); + ret = 1; + goto cleanup; + } + rewind(f); + + if (!strncmp(header, NC_SUBJECT_PUBKEY_INFO_HEADER, strlen(NC_SUBJECT_PUBKEY_INFO_HEADER))) { + /* it's subject public key info public key */ + ret = nc_server_config_new_read_pubkey_openssl(f, pubkey); + *pubkey_type = NC_PUBKEY_FORMAT_X509; + } else if (!strncmp(header, NC_SSH2_PUBKEY_HEADER, strlen(NC_SSH2_PUBKEY_HEADER))) { + /* it's ssh2 public key */ + ret = nc_server_config_new_read_ssh2_pubkey(f, pubkey); + *pubkey_type = NC_PUBKEY_FORMAT_SSH2; + } +#ifdef NC_ENABLED_SSH + else { + /* it's probably OpenSSH public key */ + ret = nc_server_config_new_read_pubkey_libssh(pubkey_path, pubkey); + *pubkey_type = NC_PUBKEY_FORMAT_SSH2; + } +#endif /* NC_ENABLED_SSH */ + + if (ret) { + ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path); + goto cleanup; + } + +cleanup: + if (f) { + fclose(f); + } + + free(header); + + return ret; +} + +static int +nc_server_config_new_get_privkey_openssl(FILE *f, char **privkey, EVP_PKEY **priv_pkey) +{ + int ret = 0, priv_len; + BIO *bio = NULL; + + NC_CHECK_ARG_RET(NULL, privkey, priv_pkey, 1); + + /* read private key from file */ + *priv_pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL); + if (!*priv_pkey) { + ret = -1; + goto cleanup; + } + + bio = BIO_new(BIO_s_mem()); + if (!bio) { + ret = -1; + goto cleanup; + } + + /* write the private key in to bio */ + ret = PEM_write_bio_PrivateKey(bio, *priv_pkey, NULL, NULL, 0, NULL, NULL); + if (!ret) { + ret = -1; + goto cleanup; + } + + priv_len = BIO_pending(bio); + if (priv_len <= 0) { + ret = -1; + goto cleanup; + } + + /* get private key's length */ + *privkey = malloc(priv_len + 1); + if (!*privkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* read the private key from bio */ + ret = BIO_read(bio, *privkey, priv_len); + if (ret <= 0) { + ret = -1; + goto cleanup; + } + (*privkey)[priv_len] = '\0'; + + ret = 0; +cleanup: + if (ret < 0) { + ERR(NULL, "Getting private key from file failed (%s).", ERR_reason_error_string(ERR_get_error())); + } + BIO_free(bio); + return ret; +} + +static int +nc_server_config_new_privkey_to_pubkey_openssl(EVP_PKEY *priv_pkey, char **pubkey) +{ + int ret = 0, pub_len; + BIO *bio = NULL; + + bio = BIO_new(BIO_s_mem()); + if (!bio) { + ret = -1; + goto cleanup; + } + + /* write the pubkey into bio */ + ret = PEM_write_bio_PUBKEY(bio, priv_pkey); + if (!ret) { + ret = -1; + goto cleanup; + } + + /* get the length of the pubkey */ + pub_len = BIO_pending(bio); + if (pub_len <= 0) { + ret = -1; + goto cleanup; + } + + *pubkey = malloc(pub_len + 1); + if (!*pubkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* read the pubkey from the bio */ + ret = BIO_read(bio, *pubkey, pub_len); + if (ret <= 0) { + ret = -1; + goto cleanup; + } + (*pubkey)[pub_len] = '\0'; + + ret = 0; + +cleanup: + if (ret < 0) { + ERR(NULL, "Converting private to public key failed (%s).", ERR_reason_error_string(ERR_get_error())); + } + BIO_free(bio); + return ret; +} + +static int +nc_server_config_new_privkey_to_pubkey_libssh(const ssh_key priv_sshkey, char **pubkey) +{ + int ret; + ssh_key pub_sshkey = NULL; + + ret = ssh_pki_export_privkey_to_pubkey(priv_sshkey, &pub_sshkey); + if (ret) { + ERR(NULL, "Exporting privkey to pubkey failed."); + return ret; + } + + ret = ssh_pki_export_pubkey_base64(pub_sshkey, pubkey); + if (ret) { + ERR(NULL, "Exporting pubkey to base64 failed."); + } + + ssh_key_free(pub_sshkey); + return ret; +} + +static int +nc_server_config_new_privkey_to_pubkey(EVP_PKEY *priv_pkey, const ssh_key priv_sshkey, NC_PRIVKEY_FORMAT privkey_type, char **pubkey, NC_PUBKEY_FORMAT *pubkey_type) +{ + switch (privkey_type) { +#ifdef NC_ENABLED_SSH + case NC_PRIVKEY_FORMAT_RSA: + case NC_PRIVKEY_FORMAT_EC: + case NC_PRIVKEY_FORMAT_OPENSSH: + *pubkey_type = NC_PUBKEY_FORMAT_SSH2; + return nc_server_config_new_privkey_to_pubkey_libssh(priv_sshkey, pubkey); +#endif /* NC_ENABLED_SSH */ + case NC_PRIVKEY_FORMAT_X509: + *pubkey_type = NC_PUBKEY_FORMAT_X509; + return nc_server_config_new_privkey_to_pubkey_openssl(priv_pkey, pubkey); + default: + break; + } + + return 1; +} + +#ifdef NC_ENABLED_SSH + +static int +nc_server_config_new_get_privkey_libssh(const char *privkey_path, char **privkey, ssh_key *priv_sshkey) +{ + int ret; + + *priv_sshkey = NULL; + + ret = ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, priv_sshkey); + if (ret) { + ERR(NULL, "Importing privkey from file \"%s\" failed.", privkey_path); + return ret; + } + + ret = ssh_pki_export_privkey_base64(*priv_sshkey, NULL, NULL, NULL, privkey); + if (ret) { + ERR(NULL, "Exporting privkey from file \"%s\" to base64 failed.", privkey_path); + } + + return ret; +} + +#endif /* NC_ENABLED_SSH */ + +int +nc_server_config_new_get_keys(const char *privkey_path, const char *pubkey_path, + char **privkey, char **pubkey, NC_PRIVKEY_FORMAT *privkey_type, NC_PUBKEY_FORMAT *pubkey_type) +{ + int ret = 0; + EVP_PKEY *priv_pkey = NULL; + ssh_key priv_sshkey = NULL; + FILE *f_privkey = NULL; + char *header = NULL; + size_t len = 0; + + NC_CHECK_ARG_RET(NULL, privkey_path, privkey, pubkey, privkey_type, 1); + + *privkey = NULL; + *pubkey = NULL; + + /* get private key first */ + f_privkey = fopen(privkey_path, "r"); + if (!f_privkey) { + ERR(NULL, "Unable to open file \"%s\".", privkey_path); + ret = 1; + goto cleanup; + } + + if (getline(&header, &len, f_privkey) < 0) { + ERR(NULL, "Error reading header from file \"%s\".", privkey_path); + ret = 1; + goto cleanup; + } + rewind(f_privkey); + + if (!strncmp(header, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) { + /* it's PKCS8 (X.509) private key */ + *privkey_type = NC_PRIVKEY_FORMAT_X509; + ret = nc_server_config_new_get_privkey_openssl(f_privkey, privkey, &priv_pkey); + } +#ifdef NC_ENABLED_SSH + else if (!strncmp(header, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) { + /* it's OpenSSH private key */ + *privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; + ret = nc_server_config_new_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); + } else if (!strncmp(header, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) { + /* it's RSA privkey in PKCS1 format */ + *privkey_type = NC_PRIVKEY_FORMAT_RSA; + ret = nc_server_config_new_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); + } else if (!strncmp(header, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) { + /* it's EC privkey in SEC1 format */ + *privkey_type = NC_PRIVKEY_FORMAT_EC; + ret = nc_server_config_new_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); + } +#endif /* NC_ENABLED_SSH */ + else { + ERR(NULL, "Private key format not supported."); + ret = 1; + goto cleanup; + } + + if (ret) { + goto cleanup; + } + + if (pubkey_path) { + ret = nc_server_config_new_get_pubkey(pubkey_path, pubkey, pubkey_type); + } else { + ret = nc_server_config_new_privkey_to_pubkey(priv_pkey, priv_sshkey, *privkey_type, pubkey, pubkey_type); + } + + if (ret) { + ERR(NULL, "Getting public key failed."); + goto cleanup; + } + +cleanup: + if (f_privkey) { + fclose(f_privkey); + } + + free(header); + + ssh_key_free(priv_sshkey); + EVP_PKEY_free(priv_pkey); + + return ret; +} + +API int +nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_name, NC_TRANSPORT_IMPL transport, + const char *address, const char *port, struct lyd_node **config) +{ + int ret = 0; + char *tree_path = NULL; + struct lyd_node *new_tree, *port_node; + + NC_CHECK_ARG_RET(NULL, address, port, ctx, endpt_name, config, 1); + + /* prepare path for instertion of leaves later */ +#ifdef NC_ENABLED_SSH + if (transport == NC_TI_LIBSSH) { + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/tcp-server-parameters", endpt_name); + } +#endif +#ifdef NC_ENABLED_TLS + if (transport == NC_TI_OPENSSL) { + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tcp-server-parameters", endpt_name); + } +#endif + if (!tree_path) { + ERR(NULL, "Transport not supported or memory allocation error."); + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } + if (ret) { + ERR(NULL, "Unable to find tcp-server-parameters container."); + goto cleanup; + } + + ret = lyd_new_term(new_tree, NULL, "local-address", address, 0, NULL); + if (ret) { + goto cleanup; + } + + ret = lyd_find_path(new_tree, "local-port", 0, &port_node); + if (!ret) { + ret = lyd_change_term(port_node, port); + } else if (ret == LY_ENOTFOUND) { + ret = lyd_new_term(new_tree, NULL, "local-port", port, 0, NULL); + } + + if (ret && (ret != LY_EEXIST) && (ret != LY_ENOT)) { + /* only fail if there was actually an error */ + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } +cleanup: + free(tree_path); + return ret; +} diff --git a/src/config_new_ssh.h b/src/config_new.h similarity index 66% rename from src/config_new_ssh.h rename to src/config_new.h index 0f03da66..747b648a 100644 --- a/src/config_new_ssh.h +++ b/src/config_new.h @@ -1,7 +1,7 @@ /** - * @file config_new_ssh.h + * @file config_new.h * @author Roman Janota - * @brief libnetconf2 server new configuration creation + * @brief libnetconf2 server new configuration creation header * * @copyright * Copyright (c) 2023 CESNET, z.s.p.o. @@ -13,8 +13,8 @@ * https://opensource.org/licenses/BSD-3-Clause */ -#ifndef NC_CONFIG_NEW_SSH_H_ -#define NC_CONFIG_NEW_SSH_H_ +#ifndef NC_CONFIG_NEW_H_ +#define NC_CONFIG_NEW_H_ #include @@ -57,6 +57,12 @@ extern "C" { /* public key's SubjectPublicKeyInfo format footer */ #define NC_SUBJECT_PUBKEY_INFO_FOOTER "\n-----END PUBLIC KEY-----\n" +/* certificate's PEM format header */ +#define NC_PEM_CERTIFICATE_HEADER "-----BEGIN CERTIFICATE-----\n" + +/* certificate's PEM format footer */ +#define NC_PEM_CERTIFICATE_FOOTER "\n-----END CERTIFICATE-----\n" + typedef enum { NC_ALG_HOSTKEY, NC_ALG_KEY_EXCHANGE, @@ -64,8 +70,19 @@ typedef enum { NC_ALG_MAC } NC_ALG_TYPE; +int nc_server_config_new_get_keys(const char *privkey_path, const char *pubkey_path, + char **privkey, char **pubkey, NC_PRIVKEY_FORMAT *privkey_type, NC_PUBKEY_FORMAT *pubkey_type); + +int nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_PUBKEY_FORMAT *pubkey_type); + +int nc_server_config_new_read_certificate(const char *cert_path, char **cert); + +int nc_config_new_check_add_operation(const struct ly_ctx *ctx, struct lyd_node *top); + +const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT format); + #ifdef __cplusplus } #endif -#endif /* NC_CONFIG_NEW_SSH_H_ */ +#endif /* NC_CONFIG_NEW_H_ */ diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index dd18b96f..a64a8a14 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -1,7 +1,7 @@ /** * @file config_new_ssh.c * @author Roman Janota - * @brief libnetconf2 server new configuration creation functions + * @brief libnetconf2 server new SSH configuration creation functions * * @copyright * Copyright (c) 2023 CESNET, z.s.p.o. @@ -15,493 +15,41 @@ #define _GNU_SOURCE -#include #include -#include #include #include #include #include -#include -#include -#include -#include -#include +#include #include "compat.h" -#include "config_new_ssh.h" -#include "libnetconf.h" +#include "config.h" +#include "config_new.h" +#include "log_p.h" #include "server_config.h" -#include "session_server.h" +#include "session_p.h" #if !defined (HAVE_CRYPT_R) extern pthread_mutex_t crypt_lock; #endif -static int -nc_server_config_new_ssh_read_ssh2_pubkey(FILE *f, char **pubkey) -{ - char *buffer = NULL; - size_t size = 0, pubkey_len = 0; - void *tmp; - ssize_t read; - int ret = 0; - - while ((read = getline(&buffer, &size, f)) > 0) { - if (!strncmp(buffer, "----", 4)) { - continue; - } - - if (!strncmp(buffer, "Comment:", 8)) { - continue; - } - - if (buffer[read - 1] == '\n') { - read--; - } - - tmp = realloc(*pubkey, pubkey_len + read + 1); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } - - *pubkey = tmp; - memcpy(*pubkey + pubkey_len, buffer, read); - pubkey_len += read; - } - - if (!pubkey_len) { - ERR(NULL, "Unexpected public key format."); - ret = 1; - goto cleanup; - } - - (*pubkey)[pubkey_len] = '\0'; - -cleanup: - free(buffer); - return ret; -} - -static int -nc_server_config_new_ssh_read_pubkey_openssl(FILE *f, char **pubkey) -{ - int ret = 0; - EVP_PKEY *pkey; - BIO *bio; - char *key = NULL; - int pub_len; - - /* read the pubkey from file */ - pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL); - if (!pkey) { - ret = -1; - goto cleanup; - } - - bio = BIO_new(BIO_s_mem()); - if (!bio) { - ret = -1; - goto cleanup; - } - - /* write the pubkey into bio */ - ret = PEM_write_bio_PUBKEY(bio, pkey); - if (!ret) { - ret = -1; - goto cleanup; - } - - pub_len = BIO_pending(bio); - if (pub_len <= 0) { - ret = -1; - goto cleanup; - } - - /* get pubkey's length */ - key = malloc(pub_len + 1); - if (!key) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* read the public key from bio */ - ret = BIO_read(bio, key, pub_len); - if (ret <= 0) { - ret = -1; - goto cleanup; - } - key[pub_len] = '\0'; - - /* strip the pubkey of the header and footer */ - *pubkey = strdup(key + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER)); - if (!*pubkey) { - ERRMEM; - ret = 1; - goto cleanup; - } - - (*pubkey)[strlen(*pubkey) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER)] = '\0'; - - ret = 0; -cleanup: - if (ret == -1) { - ERR(NULL, "Error getting public key from file (OpenSSL Error): \"%s\".", ERR_reason_error_string(ERR_get_error())); - ret = 1; - } - - BIO_free(bio); - EVP_PKEY_free(pkey); - free(key); - - return ret; -} - -static int -nc_server_config_new_ssh_read_pubkey_libssh(const char *pubkey_path, char **pubkey) -{ - int ret = 0; - ssh_key pub_sshkey = NULL; - - ret = ssh_pki_import_pubkey_file(pubkey_path, &pub_sshkey); - if (ret) { - ERR(NULL, "Importing public key from file \"%s\" failed.", pubkey_path); - return ret; - } - - ret = ssh_pki_export_pubkey_base64(pub_sshkey, pubkey); - if (ret) { - ERR(NULL, "Exporting public key to base64 failed."); - } - - ssh_key_free(pub_sshkey); - return ret; -} - -static int -nc_server_config_new_ssh_get_pubkey(const char *pubkey_path, char **pubkey, NC_SSH_PUBKEY_TYPE *pubkey_type) -{ - int ret = 0; - FILE *f = NULL; - char *header = NULL; - size_t len = 0; - - NC_CHECK_ARG_RET(NULL, pubkey, pubkey_type, 1); - - *pubkey = NULL; - - f = fopen(pubkey_path, "r"); - if (!f) { - ERR(NULL, "Unable to open file \"%s\".", pubkey_path); - ret = 1; - goto cleanup; - } - - if (getline(&header, &len, f) < 0) { - ERR(NULL, "Error reading header from file \"%s\".", pubkey_path); - ret = 1; - goto cleanup; - } - rewind(f); - - if (!strncmp(header, NC_SUBJECT_PUBKEY_INFO_HEADER, strlen(NC_SUBJECT_PUBKEY_INFO_HEADER))) { - /* it's subject public key info public key */ - ret = nc_server_config_new_ssh_read_pubkey_openssl(f, pubkey); - *pubkey_type = NC_SSH_PUBKEY_X509; - } else if (!strncmp(header, NC_SSH2_PUBKEY_HEADER, strlen(NC_SSH2_PUBKEY_HEADER))) { - /* it's ssh2 public key */ - ret = nc_server_config_new_ssh_read_ssh2_pubkey(f, pubkey); - *pubkey_type = NC_SSH_PUBKEY_SSH2; - } else { - /* it's probably OpenSSH public key */ - ret = nc_server_config_new_ssh_read_pubkey_libssh(pubkey_path, pubkey); - *pubkey_type = NC_SSH_PUBKEY_SSH2; - } - - if (ret) { - ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path); - goto cleanup; - } - -cleanup: - if (f) { - fclose(f); - } - - free(header); - - return ret; -} - -static int -nc_server_config_new_ssh_get_privkey_openssl(FILE *f, char **privkey, EVP_PKEY **priv_pkey) -{ - int ret = 0, priv_len; - BIO *bio = NULL; - - NC_CHECK_ARG_RET(NULL, privkey, priv_pkey, 1); - - /* read private key from file */ - *priv_pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL); - if (!*priv_pkey) { - ret = -1; - goto cleanup; - } - - bio = BIO_new(BIO_s_mem()); - if (!bio) { - ret = -1; - goto cleanup; - } - - /* write the private key in to bio */ - ret = PEM_write_bio_PrivateKey(bio, *priv_pkey, NULL, NULL, 0, NULL, NULL); - if (!ret) { - ret = -1; - goto cleanup; - } - - priv_len = BIO_pending(bio); - if (priv_len <= 0) { - ret = -1; - goto cleanup; - } - - /* get private key's length */ - *privkey = malloc(priv_len + 1); - if (!*privkey) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* read the private key from bio */ - ret = BIO_read(bio, *privkey, priv_len); - if (ret <= 0) { - ret = -1; - goto cleanup; - } - (*privkey)[priv_len] = '\0'; - - ret = 0; -cleanup: - if (ret < 0) { - ERR(NULL, "Getting private key from file failed (%s).", ERR_reason_error_string(ERR_get_error())); - } - BIO_free(bio); - return ret; -} - -static int -nc_server_config_new_ssh_privkey_to_pubkey_openssl(EVP_PKEY *priv_pkey, char **pubkey) -{ - int ret = 0, pub_len; - BIO *bio = NULL; - - bio = BIO_new(BIO_s_mem()); - if (!bio) { - ret = -1; - goto cleanup; - } - - /* write the pubkey into bio */ - ret = PEM_write_bio_PUBKEY(bio, priv_pkey); - if (!ret) { - ret = -1; - goto cleanup; - } - - /* get the length of the pubkey */ - pub_len = BIO_pending(bio); - if (pub_len <= 0) { - ret = -1; - goto cleanup; - } - - *pubkey = malloc(pub_len + 1); - if (!*pubkey) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* read the pubkey from the bio */ - ret = BIO_read(bio, *pubkey, pub_len); - if (ret <= 0) { - ret = -1; - goto cleanup; - } - (*pubkey)[pub_len] = '\0'; - - ret = 0; - -cleanup: - if (ret < 0) { - ERR(NULL, "Converting private to public key failed (%s).", ERR_reason_error_string(ERR_get_error())); - } - BIO_free(bio); - return ret; -} - -static int -nc_server_config_new_ssh_privkey_to_pubkey_libssh(const ssh_key priv_sshkey, char **pubkey) -{ - int ret; - ssh_key pub_sshkey = NULL; - - ret = ssh_pki_export_privkey_to_pubkey(priv_sshkey, &pub_sshkey); - if (ret) { - ERR(NULL, "Exporting privkey to pubkey failed."); - return ret; - } - - ret = ssh_pki_export_pubkey_base64(pub_sshkey, pubkey); - if (ret) { - ERR(NULL, "Exporting pubkey to base64 failed."); - } - - ssh_key_free(pub_sshkey); - return ret; -} - -static int -nc_server_config_new_ssh_privkey_to_pubkey(EVP_PKEY *priv_pkey, const ssh_key priv_sshkey, NC_PRIVKEY_FORMAT privkey_type, char **pubkey, NC_SSH_PUBKEY_TYPE *pubkey_type) -{ - switch (privkey_type) { - case NC_PRIVKEY_FORMAT_RSA: - case NC_PRIVKEY_FORMAT_EC: - case NC_PRIVKEY_FORMAT_OPENSSH: - *pubkey_type = NC_SSH_PUBKEY_SSH2; - return nc_server_config_new_ssh_privkey_to_pubkey_libssh(priv_sshkey, pubkey); - case NC_PRIVKEY_FORMAT_PKCS8: - *pubkey_type = NC_SSH_PUBKEY_X509; - return nc_server_config_new_ssh_privkey_to_pubkey_openssl(priv_pkey, pubkey); - } - - return 1; -} - -static int -nc_server_config_new_ssh_get_privkey_libssh(const char *privkey_path, char **privkey, ssh_key *priv_sshkey) -{ - int ret; - - *priv_sshkey = NULL; - - ret = ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, priv_sshkey); - if (ret) { - ERR(NULL, "Importing privkey from file \"%s\" failed.", privkey_path); - return ret; - } - - ret = ssh_pki_export_privkey_base64(*priv_sshkey, NULL, NULL, NULL, privkey); - if (ret) { - ERR(NULL, "Exporting privkey from file \"%s\" to base64 failed.", privkey_path); - } - - return ret; -} - -static int -nc_server_config_new_ssh_get_keys(const char *privkey_path, const char *pubkey_path, - char **privkey, char **pubkey, NC_PRIVKEY_FORMAT *privkey_type, NC_SSH_PUBKEY_TYPE *pubkey_type) -{ - int ret = 0; - EVP_PKEY *priv_pkey = NULL; - ssh_key priv_sshkey = NULL; - FILE *f_privkey = NULL; - char *header = NULL; - size_t len = 0; - - NC_CHECK_ARG_RET(NULL, privkey_path, privkey, pubkey, privkey_type, 1); - - *privkey = NULL; - *pubkey = NULL; - - /* get private key first */ - f_privkey = fopen(privkey_path, "r"); - if (!f_privkey) { - ERR(NULL, "Unable to open file \"%s\".", privkey_path); - ret = 1; - goto cleanup; - } - - if (getline(&header, &len, f_privkey) < 0) { - ERR(NULL, "Error reading header from file \"%s\".", privkey_path); - ret = 1; - goto cleanup; - } - rewind(f_privkey); - - if (!strncmp(header, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) { - /* it's PKCS8 (X.509) private key */ - *privkey_type = NC_PRIVKEY_FORMAT_PKCS8; - ret = nc_server_config_new_ssh_get_privkey_openssl(f_privkey, privkey, &priv_pkey); - } else if (!strncmp(header, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) { - /* it's OpenSSH private key */ - *privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; - ret = nc_server_config_new_ssh_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); - } else if (!strncmp(header, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) { - /* it's RSA privkey in PKCS1 format */ - *privkey_type = NC_PRIVKEY_FORMAT_RSA; - ret = nc_server_config_new_ssh_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); - } else if (!strncmp(header, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) { - /* it's EC privkey in SEC1 format */ - *privkey_type = NC_PRIVKEY_FORMAT_EC; - ret = nc_server_config_new_ssh_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); - } else { - ERR(NULL, "Private key format not supported."); - ret = 1; - goto cleanup; - } - - if (ret) { - goto cleanup; - } - - if (pubkey_path) { - ret = nc_server_config_new_ssh_get_pubkey(pubkey_path, pubkey, pubkey_type); - } else { - ret = nc_server_config_new_ssh_privkey_to_pubkey(priv_pkey, priv_sshkey, *privkey_type, pubkey, pubkey_type); - } - - if (ret) { - ERR(NULL, "Getting public key failed."); - goto cleanup; - } - -cleanup: - if (f_privkey) { - fclose(f_privkey); - } - - free(header); - - ssh_key_free(priv_sshkey); - EVP_PKEY_free(priv_pkey); - - return ret; -} - API int -nc_server_config_new_ssh_hostkey(const char *privkey_path, const char *pubkey_path, const struct ly_ctx *ctx, - const char *endpt_name, const char *hostkey_name, struct lyd_node **config) +nc_server_config_new_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 ret = 0; char *pubkey = NULL, *privkey = NULL, *pubkey_stripped, *privkey_stripped; struct lyd_node *new_tree; char *tree_path = NULL; NC_PRIVKEY_FORMAT privkey_type; - NC_SSH_PUBKEY_TYPE pubkey_type; + NC_PUBKEY_FORMAT pubkey_type; + const char *privkey_identity; NC_CHECK_ARG_RET(NULL, privkey_path, config, ctx, endpt_name, hostkey_name, 1); /* get the keys as a string from the given files */ - ret = nc_server_config_new_ssh_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); + ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); if (ret) { ERR(NULL, "Getting keys from file(s) failed."); goto cleanup; @@ -525,12 +73,6 @@ nc_server_config_new_ssh_hostkey(const char *privkey_path, const char *pubkey_pa *config = new_tree; } - /* give the top level container create operation */ - ret = lyd_new_meta(ctx, *config, NULL, "yang:operation", "create", 0, NULL); - if (ret) { - goto cleanup; - } - /* find the node where leaves will get inserted */ ret = lyd_find_path(*config, tree_path, 0, &new_tree); if (ret) { @@ -538,7 +80,7 @@ nc_server_config_new_ssh_hostkey(const char *privkey_path, const char *pubkey_pa } /* insert pubkey format */ - if (pubkey_type == NC_SSH_PUBKEY_SSH2) { + if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:ssh-public-key-format", 0, NULL); } else { ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:subject-public-key-info-format", 0, NULL); @@ -550,9 +92,9 @@ nc_server_config_new_ssh_hostkey(const char *privkey_path, const char *pubkey_pa /* strip pubkey's header and footer only if it's generated from pkcs8 key (using OpenSSL), * otherwise it's already stripped */ - if (!pubkey_path && (privkey_type == NC_PRIVKEY_FORMAT_PKCS8)) { - pubkey_stripped = pubkey + strlen("-----BEGIN PUBLIC KEY-----") + 1; - pubkey_stripped[strlen(pubkey_stripped) - strlen("-----END PUBLIC KEY-----") - 2] = '\0'; + if (!pubkey_path && (privkey_type == NC_PRIVKEY_FORMAT_X509)) { + pubkey_stripped = pubkey + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER); + pubkey_stripped[strlen(pubkey_stripped) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER)] = '\0'; } else { pubkey_stripped = pubkey; } @@ -563,20 +105,15 @@ nc_server_config_new_ssh_hostkey(const char *privkey_path, const char *pubkey_pa goto cleanup; } - /* insert private key format */ - if (privkey_type == NC_PRIVKEY_FORMAT_RSA) { - ret = lyd_new_term(new_tree, NULL, "private-key-format", "ietf-crypto-types:rsa-private-key-format", 0, NULL); - } else if (privkey_type == NC_PRIVKEY_FORMAT_EC) { - ret = lyd_new_term(new_tree, NULL, "private-key-format", "ietf-crypto-types:ec-private-key-format", 0, NULL); - } else if (privkey_type == NC_PRIVKEY_FORMAT_PKCS8) { - ret = lyd_new_term(new_tree, NULL, "private-key-format", "libnetconf2-netconf-server:subject-private-key-info-format", 0, NULL); - } else if (privkey_type == NC_PRIVKEY_FORMAT_OPENSSH) { - ret = lyd_new_term(new_tree, NULL, "private-key-format", "libnetconf2-netconf-server:openssh-private-key-format", 0, NULL); - } else { - ERR(NULL, "Private key type not supported."); + /* get privkey identityref value */ + privkey_identity = nc_config_new_privkey_format_to_identityref(privkey_type); + if (!privkey_identity) { ret = 1; + goto cleanup; } + /* insert private key format */ + ret = lyd_new_term(new_tree, NULL, "private-key-format", privkey_identity, 0, NULL); if (ret) { goto cleanup; } @@ -596,81 +133,21 @@ nc_server_config_new_ssh_hostkey(const char *privkey_path, const char *pubkey_pa goto cleanup; } - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); if (ret) { goto cleanup; } -cleanup: - free(privkey); - free(pubkey); - free(tree_path); - return ret; -} - -API int -nc_server_config_new_ssh_address_port(const char *address, const char *port, const struct ly_ctx *ctx, - const char *endpt_name, struct lyd_node **config) -{ - int ret = 0; - char *tree_path = NULL; - struct lyd_node *new_tree, *port_node; - - NC_CHECK_ARG_RET(NULL, address, port, ctx, endpt_name, config, 1); - - /* prepare path for instertion of leaves later */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/tcp-server-parameters", endpt_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } - if (ret) { - ERR(NULL, "Unable to find tcp-server-parameters container."); - goto cleanup; - } - - ret = lyd_new_term(new_tree, NULL, "local-address", address, 0, NULL); - if (ret) { - goto cleanup; - } - - ret = lyd_find_path(new_tree, "local-port", 0, &port_node); - if (!ret) { - ret = lyd_change_term(port_node, port); - } else if (ret == LY_ENOTFOUND) { - ret = lyd_new_term(new_tree, NULL, "local-port", port, 0, NULL); - } - - if (ret && (ret != LY_EEXIST) && (ret != LY_ENOT)) { - /* only fail if there was actually an error */ - goto cleanup; - } - /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { goto cleanup; } + cleanup: + free(privkey); + free(pubkey); free(tree_path); return ret; } @@ -803,6 +280,12 @@ nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *end goto cleanup; } + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -836,6 +319,12 @@ nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char goto cleanup; } + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -869,6 +358,12 @@ nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *e goto cleanup; } + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -902,6 +397,12 @@ nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_na goto cleanup; } + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -912,15 +413,15 @@ nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_na } API int -nc_server_config_new_ssh_client_auth_pubkey(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, const char *pubkey_name, struct lyd_node **config) +nc_server_config_new_ssh_client_auth_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) { int ret = 0; char *pubkey = NULL, *tree_path = NULL; struct lyd_node *new_tree; - NC_SSH_PUBKEY_TYPE pubkey_type; + NC_PUBKEY_FORMAT pubkey_type; - ret = nc_server_config_new_ssh_get_pubkey(pubkey_path, &pubkey, &pubkey_type); + ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_type); if (ret) { goto cleanup; } @@ -950,7 +451,7 @@ nc_server_config_new_ssh_client_auth_pubkey(const char *pubkey_path, const struc } /* insert pubkey format */ - if (pubkey_type == NC_SSH_PUBKEY_SSH2) { + if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:ssh-public-key-format", 0, NULL); } else { ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:subject-public-key-info-format", 0, NULL); @@ -965,6 +466,12 @@ nc_server_config_new_ssh_client_auth_pubkey(const char *pubkey_path, const struc goto cleanup; } + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -978,8 +485,8 @@ nc_server_config_new_ssh_client_auth_pubkey(const char *pubkey_path, const struc } API int -nc_server_config_new_ssh_client_auth_password(const char *password, const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config) +nc_server_config_new_ssh_client_auth_password(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *password, struct lyd_node **config) { int ret = 0; char *tree_path = NULL, *hashed_pw = NULL; @@ -1035,6 +542,12 @@ nc_server_config_new_ssh_client_auth_password(const char *password, const struct goto cleanup; } + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -1084,6 +597,12 @@ nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const char * goto cleanup; } + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -1096,9 +615,8 @@ nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const char * } API int -nc_server_config_new_ssh_client_auth_interactive(const char *pam_config_name, const char *pam_config_dir, - const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config) +nc_server_config_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) { int ret = 0; char *tree_path = NULL; @@ -1142,6 +660,12 @@ nc_server_config_new_ssh_client_auth_interactive(const char *pam_config_name, co } } + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { diff --git a/src/config_new_tls.c b/src/config_new_tls.c new file mode 100644 index 00000000..078b73c7 --- /dev/null +++ b/src/config_new_tls.c @@ -0,0 +1,406 @@ +/** + * @file config_new_tls.c + * @author Roman Janota + * @brief libnetconf2 TLS server new configuration creation functions + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include + +#include "compat.h" +#include "config.h" +#include "config_new.h" +#include "log_p.h" +#include "server_config.h" +#include "session.h" +#include "session_p.h" + +API int +nc_server_config_new_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) +{ + int ret = 0; + char *tree_path = NULL; + struct lyd_node *new_tree; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, map_type, name, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + /* prepare path for instertion of leaves later */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']", endpt_name, id); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } + if (ret) { + ERR(NULL, "Unable to find netconf-server-parameters container."); + goto cleanup; + } + + /* not mandatory */ + if (fingerprint) { + ret = lyd_new_term(new_tree, NULL, "fingerprint", fingerprint, 0, NULL); + if (ret) { + goto cleanup; + } + } + + /* insert map-type */ + switch (map_type) { + case NC_TLS_CTN_SPECIFIED: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:specified", 0, NULL); + break; + case NC_TLS_CTN_SAN_RFC822_NAME: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-rfc822-name", 0, NULL); + break; + case NC_TLS_CTN_SAN_DNS_NAME: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-dns-name", 0, NULL); + break; + case NC_TLS_CTN_SAN_IP_ADDRESS: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-ip-address", 0, NULL); + break; + case NC_TLS_CTN_SAN_ANY: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-any", 0, NULL); + break; + case NC_TLS_CTN_COMMON_NAME: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:common-name", 0, NULL); + break; + case NC_TLS_CTN_UNKNOWN: + default: + ERR(NULL, "Unknown map_type."); + ret = 1; + break; + } + if (ret) { + goto cleanup; + } + + /* insert name */ + ret = lyd_new_term(new_tree, NULL, "name", name, 0, NULL); + if (ret) { + goto cleanup; + } + + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(tree_path); + return ret; +} + +API int +nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *pubkey_path, + const char *privkey_path, const char *certificate_path, struct lyd_node **config) +{ + int ret = 0; + char *tree_path = NULL, *privkey = NULL, *pubkey = NULL, *pubkey_stripped = NULL, *privkey_stripped, *cert = NULL; + struct lyd_node *new_tree; + NC_PRIVKEY_FORMAT privkey_type; + NC_PUBKEY_FORMAT pubkey_type; + const char *privkey_identity; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, certificate_path, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + /* get the keys as a string from the given files */ + ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); + if (ret) { + ERR(NULL, "Getting keys from file(s) failed."); + goto cleanup; + } + + ret = nc_server_config_new_read_certificate(certificate_path, &cert); + if (ret) { + ERR(NULL, "Getting certificate from file \"%s\" failed.", certificate_path); + goto cleanup; + } + + /* prepare path for instertion of leaves later */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate/local-definition", endpt_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } + if (ret) { + ERR(NULL, "Unable to find local-definition container."); + goto cleanup; + } + + /* insert pubkey format */ + if (pubkey_type == NC_PUBKEY_FORMAT_X509) { + ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:public-key-info-format", 0, NULL); + } else { + ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:ssh-public-key-format", 0, NULL); + } + if (ret) { + goto cleanup; + } + + /* strip pubkey's header and footer only if it's generated from pkcs8 key (using OpenSSL), + * otherwise it's already stripped + */ + if (!pubkey_path && (privkey_type == NC_PRIVKEY_FORMAT_X509)) { + pubkey_stripped = pubkey + strlen("-----BEGIN PUBLIC KEY-----") + 1; + pubkey_stripped[strlen(pubkey_stripped) - strlen("-----END PUBLIC KEY-----") - 2] = '\0'; + } else { + pubkey_stripped = pubkey; + } + + /* insert pubkey b64 */ + ret = lyd_new_term(new_tree, NULL, "public-key", pubkey_stripped, 0, NULL); + if (ret) { + goto cleanup; + } + + /* get privkey identityref value */ + privkey_identity = nc_config_new_privkey_format_to_identityref(privkey_type); + if (!privkey_identity) { + ret = 1; + goto cleanup; + } + + /* insert private key format */ + ret = lyd_new_term(new_tree, NULL, "private-key-format", privkey_identity, 0, NULL); + if (ret) { + goto cleanup; + } + + if (privkey_type == NC_PRIVKEY_FORMAT_OPENSSH) { + /* only OpenSSH private keys have different header and footer after processing */ + privkey_stripped = privkey + strlen(NC_OPENSSH_PRIVKEY_HEADER); + privkey_stripped[strlen(privkey_stripped) - strlen(NC_OPENSSH_PRIVKEY_FOOTER)] = '\0'; + } else { + /* the rest share the same header and footer */ + privkey_stripped = privkey + strlen(NC_PKCS8_PRIVKEY_HEADER); + privkey_stripped[strlen(privkey_stripped) - strlen(NC_PKCS8_PRIVKEY_FOOTER)] = '\0'; + } + + ret = lyd_new_term(new_tree, NULL, "cleartext-private-key", privkey_stripped, 0, NULL); + if (ret) { + goto cleanup; + } + + ret = lyd_new_term(new_tree, NULL, "cert-data", cert, 0, NULL); + if (ret) { + goto cleanup; + } + + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(privkey); + free(pubkey); + free(cert); + free(tree_path); + return ret; +} + +API int +nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, + const char *cert_path, struct lyd_node **config) +{ + int ret = 0; + struct lyd_node *new_tree; + char *tree_path = NULL, *cert = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); + + ret = nc_server_config_new_read_certificate(cert_path, &cert); + if (ret) { + ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path); + goto cleanup; + } + + /* prepare path for instertion of leaves later */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/local-definition/certificate[name='%s']", endpt_name, cert_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } + if (ret) { + goto cleanup; + } + + /* insert cert-data */ + ret = lyd_new_term(new_tree, NULL, "cert-data", cert, 0, NULL); + if (ret) { + goto cleanup; + } + + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(cert); + free(tree_path); + return ret; +} + +API int +nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, + const char *cert_path, struct lyd_node **config) +{ + int ret = 0; + struct lyd_node *new_tree; + char *tree_path = NULL, *cert = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); + + ret = nc_server_config_new_read_certificate(cert_path, &cert); + if (ret) { + ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path); + goto cleanup; + } + + /* prepare path for instertion of leaves later */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/local-definition/certificate[name='%s']", endpt_name, cert_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } + if (ret) { + goto cleanup; + } + + /* insert cert-data */ + ret = lyd_new_term(new_tree, NULL, "cert-data", cert, 0, NULL); + if (ret) { + goto cleanup; + } + + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(cert); + free(tree_path); + return ret; +} diff --git a/src/io.c b/src/io.c index d9b5c54a..eb9360ae 100644 --- a/src/io.c +++ b/src/io.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -30,12 +31,18 @@ #ifdef NC_ENABLED_TLS # include +# include #endif #include #include "compat.h" -#include "libnetconf.h" +#include "config.h" +#include "log_p.h" +#include "messages_p.h" +#include "netconf.h" +#include "session.h" +#include "session_p.h" const char *nc_msgtype2str[] = { "error", diff --git a/src/log.c b/src/log.c index c87b4fb4..f5d2feec 100644 --- a/src/log.c +++ b/src/log.c @@ -17,6 +17,7 @@ #include #include +#include #include @@ -25,8 +26,9 @@ #endif #include "compat.h" -#include "libnetconf.h" +#include "config.h" #include "log.h" +#include "session_p.h" /** * @brief libnetconf verbose level variable diff --git a/src/log_p.h b/src/log_p.h index 8bd57c0b..dbde9963 100644 --- a/src/log_p.h +++ b/src/log_p.h @@ -16,7 +16,7 @@ #ifndef NC_LOG_PRIVATE_H_ #define NC_LOG_PRIVATE_H_ -#include +#include #include "compat.h" #include "log.h" @@ -51,7 +51,6 @@ extern ATOMIC_T verbose_level; #define ERRMEM ERR(NULL, "%s: memory reallocation failed (%s:%d).", __func__, __FILE__, __LINE__) #define ERRINIT ERR(NULL, "%s: libnetconf2 not initialized.", __func__) #define ERRINT ERR(NULL, "%s: internal error (%s:%d).", __func__, __FILE__, __LINE__) -#define ERRNODE(name) ERR(NULL, "%s: missing node (%s) in the YANG data.", __func__, name) #define ERRARG(session, ARG) ERR(session, "Invalid argument %s (%s()).", #ARG, __func__) #define GETMACRO1(_1, NAME, ...) NAME diff --git a/src/messages_client.c b/src/messages_client.c index e222dbef..5cd1165c 100644 --- a/src/messages_client.c +++ b/src/messages_client.c @@ -17,13 +17,17 @@ #include #include -#include #include #include #include -#include "libnetconf.h" +#include "compat.h" +#include "config.h" +#include "log_p.h" +#include "messages_client.h" +#include "messages_p.h" +#include "netconf.h" const char *rpcedit_dfltop2str[] = {NULL, "merge", "replace", "none"}; const char *rpcedit_testopt2str[] = {NULL, "test-then-set", "set", "test-only"}; diff --git a/src/messages_p.h b/src/messages_p.h index 0ea41885..5bf3d3aa 100644 --- a/src/messages_p.h +++ b/src/messages_p.h @@ -16,10 +16,13 @@ #ifndef NC_MESSAGES_P_H_ #define NC_MESSAGES_P_H_ +#include + #include #include "messages_client.h" #include "messages_server.h" +#include "netconf.h" extern const char *rpcedit_dfltop2str[]; extern const char *rpcedit_testopt2str[]; diff --git a/src/messages_server.c b/src/messages_server.c index 7864ebfc..2cc193ab 100644 --- a/src/messages_server.c +++ b/src/messages_server.c @@ -24,8 +24,11 @@ #include #include "compat.h" -#include "libnetconf.h" -#include "session_server.h" +#include "config.h" +#include "log_p.h" +#include "messages_p.h" +#include "messages_server.h" +#include "netconf.h" extern struct nc_server_opts server_opts; diff --git a/src/messages_server.h b/src/messages_server.h index a9bbbae0..a3deacbc 100644 --- a/src/messages_server.h +++ b/src/messages_server.h @@ -20,9 +20,11 @@ extern "C" { #endif -#include +#include #include +#include + #include "netconf.h" #include "session.h" diff --git a/src/netconf.h b/src/netconf.h index 48058cb2..1e25cce7 100644 --- a/src/netconf.h +++ b/src/netconf.h @@ -20,8 +20,6 @@ extern "C" { #endif -#include - /** * @addtogroup misc * @{ diff --git a/src/server_config.c b/src/server_config.c index 9ec3e433..9dc94366 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -16,15 +16,21 @@ #define _GNU_SOURCE #include +#include +#include #include #include +#include + #include "compat.h" -#include "libnetconf.h" +#include "config.h" +#include "log_p.h" #include "server_config.h" #include "server_config_p.h" -#include "session_server.h" -#include "session_server_ch.h" +#include "session_p.h" + +#ifdef NC_ENABLED_SSH /* All libssh supported host-key, key-exchange, encryption and mac algorithms as of version 0.10.90 */ @@ -54,6 +60,8 @@ static const char *supported_mac_algs[] = { "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL }; +#endif /* NC_ENABLED_SSH */ + extern struct nc_server_opts server_opts; int @@ -94,6 +102,8 @@ nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, return 1; } +#ifdef NC_ENABLED_SSH + int nc_server_config_get_hostkey(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_hostkey **hostkey) { @@ -200,6 +210,86 @@ nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_client_ return 1; } +#endif /* NC_ENABLED_SSH */ + +#ifdef NC_ENABLED_TLS + +int +nc_server_config_get_cert(const struct lyd_node *node, struct nc_cert_grouping *auth_client, struct nc_certificate **cert) +{ + uint16_t i; + const char *cert_name; + + assert(node && auth_client); + + while (node) { + if (!strcmp(LYD_NAME(node), "certificate")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + cert_name = lyd_get_value(node); + + for (i = 0; i < auth_client->cert_count; i++) { + if (!strcmp(auth_client->certs[i].name, cert_name)) { + *cert = &auth_client->certs[i]; + return 0; + } + } + + ERR(NULL, "Certificate \"%s\" was not found.", cert_name); + return 1; +} + +static int +nc_server_config_get_ctn(const struct lyd_node *node, struct nc_endpt *endpt, struct nc_ctn **ctn) +{ + uint32_t id; + struct nc_ctn *iter; + + assert(node && endpt); + + node = lyd_parent(node); + while (node) { + if (!strcmp(LYD_NAME(node), "cert-to-name")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a cert-to-name subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "id")); + id = strtoul(lyd_get_value(node), NULL, 10); + + iter = endpt->opts.tls->ctn; + while (iter) { + if (iter->id == id) { + *ctn = iter; + return 0; + } + + iter = iter->next; + } + + ERR(NULL, "Cert-to-name entry with id \"%d\" was not found.", id); + return 1; +} + +#endif /* NC_ENABLED_TLS */ + int equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name) { @@ -219,6 +309,23 @@ equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char return 0; } +NC_PRIVKEY_FORMAT +nc_server_config_get_private_key_type(const char *format) +{ + if (!strcmp(format, "rsa-private-key-format")) { + return NC_PRIVKEY_FORMAT_RSA; + } else if (!strcmp(format, "ec-private-key-format")) { + return NC_PRIVKEY_FORMAT_EC; + } else if (!strcmp(format, "subject-private-key-info-format")) { + return NC_PRIVKEY_FORMAT_X509; + } else if (!strcmp(format, "openssh-private-key-format")) { + return NC_PRIVKEY_FORMAT_OPENSSH; + } else { + ERR(NULL, "Private key format (%s) not supported.", format); + return NC_PRIVKEY_FORMAT_UNKNOWN; + } +} + int nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count) { @@ -253,20 +360,73 @@ nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_ return ret; } -static void -nc_server_config_del_auth_client_pam_name(struct nc_client_auth *auth_client) +static int +is_listen(const struct lyd_node *node) { - free(auth_client->pam_config_name); - auth_client->pam_config_name = NULL; + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "listen")) { + break; + } + node = lyd_parent(node); + } + + return node != NULL; } -static void -nc_server_config_del_auth_client_pam_dir(struct nc_client_auth *auth_client) +// static int +// is_ch(const struct lyd_node *node) +// { +// assert(node); + +// while (node) { +// if (!strcmp(LYD_NAME(node), "call-home")) { +// break; +// } +// node = lyd_parent(node); +// } + +// return node != NULL; +// } + +#ifdef NC_ENABLED_SSH + +static int +is_ssh(const struct lyd_node *node) { - free(auth_client->pam_config_dir); - auth_client->pam_config_dir = NULL; + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "ssh")) { + break; + } + node = lyd_parent(node); + } + + return node != NULL; +} + +#endif /* NC_ENABLED_SSH */ + +#ifdef NC_ENABLED_TLS +static int +is_tls(const struct lyd_node *node) +{ + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "tls")) { + break; + } + node = lyd_parent(node); + } + + return node != NULL; } +#endif /* NC_ENABLED_TLS */ + static void nc_server_config_del_endpt_name(struct nc_endpt *endpt) { @@ -275,17 +435,33 @@ nc_server_config_del_endpt_name(struct nc_endpt *endpt) } static void -nc_server_config_del_endpt_reference(struct nc_endpt *endpt) +nc_server_config_del_local_address(struct nc_bind *bind) { - free(endpt->referenced_endpt_name); - endpt->referenced_endpt_name = NULL; + free(bind->address); + bind->address = NULL; } +#ifdef NC_ENABLED_SSH + static void -nc_server_config_del_local_address(struct nc_bind *bind) +nc_server_config_del_auth_client_pam_name(struct nc_client_auth *auth_client) { - free(bind->address); - bind->address = NULL; + free(auth_client->pam_config_name); + auth_client->pam_config_name = NULL; +} + +static void +nc_server_config_del_auth_client_pam_dir(struct nc_client_auth *auth_client) +{ + free(auth_client->pam_config_dir); + auth_client->pam_config_dir = NULL; +} + +static void +nc_server_config_del_endpt_reference(struct nc_endpt *endpt) +{ + free(endpt->referenced_endpt_name); + endpt->referenced_endpt_name = NULL; } static void @@ -298,15 +474,15 @@ nc_server_config_del_hostkey_name(struct nc_hostkey *hostkey) static void nc_server_config_del_public_key(struct nc_hostkey *hostkey) { - free(hostkey->key.pub_base64); - hostkey->key.pub_base64 = NULL; + free(hostkey->key.pubkey_data); + hostkey->key.pubkey_data = NULL; } static void nc_server_config_del_private_key(struct nc_hostkey *hostkey) { - free(hostkey->key.priv_base64); - hostkey->key.priv_base64 = NULL; + free(hostkey->key.privkey_data); + hostkey->key.privkey_data = NULL; } static void @@ -326,8 +502,8 @@ nc_server_config_del_auth_client_pubkey_name(struct nc_public_key *pubkey) static void nc_server_config_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey) { - free(pubkey->pub_base64); - pubkey->pub_base64 = NULL; + free(pubkey->data); + pubkey->data = NULL; } static void @@ -466,6 +642,8 @@ nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) } } +#endif /* NC_ENABLED_SSH */ + void nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts) { @@ -495,6 +673,158 @@ nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *b } } +#ifdef NC_ENABLED_TLS + +static void +nc_server_config_tls_del_public_key(struct nc_server_tls_opts *opts) +{ + free(opts->pubkey_data); + opts->pubkey_data = NULL; +} + +static void +nc_server_config_tls_del_cleartext_private_key(struct nc_server_tls_opts *opts) +{ + free(opts->privkey_data); + opts->privkey_data = NULL; +} + +static void +nc_server_config_tls_del_cert_data(struct nc_server_tls_opts *opts) +{ + free(opts->cert_data); + opts->cert_data = NULL; +} + +static void +nc_server_config_tls_del_cert_data_certificate(struct nc_certificate *cert) +{ + free(cert->data); + cert->data = NULL; +} + +static void +nc_server_config_del_fingerprint(struct nc_ctn *ctn) +{ + free(ctn->fingerprint); + ctn->fingerprint = NULL; +} + +static void +nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert) +{ + free(cert->name); + cert->name = NULL; + + free(cert->data); + cert->data = NULL; + + certs->cert_count--; + if (!certs->cert_count) { + free(certs->certs); + certs->certs = NULL; + } +} + +static void +nc_server_config_tls_del_certs(struct nc_cert_grouping *ca) +{ + uint16_t i, cert_count; + + if (ca->store == NC_STORE_LOCAL) { + cert_count = ca->cert_count; + for (i = 0; i < cert_count; i++) { + nc_server_config_del_cert(ca, &ca->certs[i]); + } + } +} + +static void +nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn) +{ + struct nc_ctn *iter; + + free(ctn->fingerprint); + ctn->fingerprint = NULL; + + free(ctn->name); + ctn->name = NULL; + + if (opts->ctn == ctn) { + /* it's the first in the list */ + opts->ctn = ctn->next; + free(ctn); + return; + } + + iter = opts->ctn; + while (iter) { + if (iter->next == ctn) { + /* found the ctn */ + break; + } + iter = iter->next; + } + + iter->next = ctn->next; + free(ctn); +} + +static void +nc_server_config_del_ctns(struct nc_server_tls_opts *opts) +{ + struct nc_ctn *cur, *next; + + cur = opts->ctn; + while (cur) { + next = cur->next; + free(cur->fingerprint); + free(cur->name); + free(cur); + cur = next; + } + opts->ctn = NULL; +} + +static void +nc_server_config_del_tls(struct nc_bind *bind, struct nc_server_tls_opts *opts) +{ + nc_server_config_del_local_address(bind); + if (bind->sock > -1) { + close(bind->sock); + } + + if (opts->store == NC_STORE_LOCAL) { + nc_server_config_tls_del_public_key(opts); + nc_server_config_tls_del_cleartext_private_key(opts); + nc_server_config_tls_del_cert_data(opts); + } + + nc_server_config_tls_del_certs(&opts->ca_certs); + nc_server_config_tls_del_certs(&opts->ee_certs); + + nc_server_config_del_ctns(opts); + + free(opts); +} + +static void +nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind) +{ + nc_server_config_del_endpt_name(endpt); + nc_server_config_del_tls(bind, endpt->opts.tls); + + server_opts.endpt_count--; + if (!server_opts.endpt_count) { + free(server_opts.endpts); + free(server_opts.binds); + server_opts.endpts = NULL; + server_opts.binds = NULL; + } +} + +#endif /* NC_ENABLED_TLS */ + /* presence container */ int nc_server_config_listen(struct lyd_node *node, NC_OPERATION op) @@ -513,12 +843,12 @@ nc_server_config_listen(struct lyd_node *node, NC_OPERATION op) case NC_TI_LIBSSH: nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]); break; -#endif +#endif /* NC_ENABLED_SSH */ #ifdef NC_ENABLED_TLS case NC_TI_OPENSSL: - /* todo */ + nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]); break; -#endif +#endif /* NC_ENABLED_TLS */ case NC_TI_UNIX: nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]); break; @@ -606,13 +936,35 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) ret = 1; goto cleanup; } - nc_server_config_del_endpt_ssh(endpt, bind); + + switch (endpt->ti) { +#ifdef NC_ENABLED_SSH + case NC_TI_LIBSSH: + nc_server_config_del_endpt_ssh(endpt, bind); + break; +#endif /* NC_ENABLED_SSH */ +#ifdef NC_ENABLED_TLS + case NC_TI_OPENSSL: + nc_server_config_del_endpt_tls(endpt, bind); + break; +#endif /* NC_ENABLED_TLS */ + case NC_TI_UNIX: + nc_server_config_del_endpt_unix_socket(endpt, bind); + break; + case NC_TI_NONE: + case NC_TI_FD: + ERRINT; + ret = 1; + goto cleanup; + } } cleanup: return ret; } +#ifdef NC_ENABLED_SSH + static int nc_server_config_create_ssh(struct nc_endpt *endpt) { @@ -654,17 +1006,63 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) return ret; } -static int -nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port) -{ - int sock = -1, set_addr, ret = 0; +#endif /* NC_ENABLED_SSH */ - assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX)); +#ifdef NC_ENABLED_TLS - if (address) { - set_addr = 1; - } else { - set_addr = 0; +static int +nc_server_config_create_tls(struct nc_endpt *endpt) +{ + endpt->ti = NC_TI_OPENSSL; + endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls); + if (!endpt->opts.tls) { + ERRMEM; + return 1; + } + + return 0; +} + +static int +nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op) +{ + struct nc_endpt *endpt; + struct nc_bind *bind; + int ret = 0; + + assert(!strcmp(LYD_NAME(node), "tls")); + + if (nc_server_config_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + ret = nc_server_config_create_tls(endpt); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + nc_server_config_del_tls(bind, endpt->opts.tls); + } + +cleanup: + return ret; +} + +#endif /* NC_ENABLED_TLS */ + +static int +nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port) +{ + int sock = -1, set_addr, ret = 0; + + assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX)); + + if (address) { + set_addr = 1; + } else { + set_addr = 0; } if (set_addr) { @@ -798,7 +1196,7 @@ nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "keepalives")); - if (equal_parent_name(node, 4, "listen")) { + if (equal_parent_name(node, 1, "tcp-server-parameters")) { if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; @@ -912,6 +1310,8 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) return ret; } +#ifdef NC_ENABLED_SSH + static int nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts) { @@ -963,22 +1363,38 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) return ret; } +#endif /* NC_ENABLED_SSH */ + /* mandatory leaf */ static int nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) { const char *format; + int ret = 0; + NC_PUBKEY_FORMAT pubkey_type; struct nc_endpt *endpt; + +#ifdef NC_ENABLED_SSH struct nc_client_auth *auth_client; struct nc_public_key *pubkey; struct nc_hostkey *hostkey; - int ret = 0; +#endif /* NC_ENABLED_SSH */ assert(!strcmp(LYD_NAME(node), "public-key-format")); format = ((struct lyd_node_term *)node)->value.ident->name; + if (!strcmp(format, "ssh-public-key-format")) { + pubkey_type = NC_PUBKEY_FORMAT_SSH2; + } else if (!strcmp(format, "subject-public-key-info-format")) { + pubkey_type = NC_PUBKEY_FORMAT_X509; + } else { + ERR(NULL, "Public key format (%s) not supported.", format); + ret = 1; + goto cleanup; + } - if ((equal_parent_name(node, 6, "client-authentication")) && (equal_parent_name(node, 10, "listen"))) { +#ifdef NC_ENABLED_SSH + if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -995,15 +1411,9 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - if (!strcmp(format, "ssh-public-key-format")) { - pubkey->pubkey_type = NC_SSH_PUBKEY_SSH2; - } else if (!strcmp(format, "subject-public-key-info-format")) { - pubkey->pubkey_type = NC_SSH_PUBKEY_X509; - } else { - ERR(NULL, "Public key format (%s) not supported.", format); - } + pubkey->type = pubkey_type; } - } else if ((equal_parent_name(node, 5, "server-identity")) && (equal_parent_name(node, 11, "listen"))) { + } else if (equal_parent_name(node, 5, "server-identity") && is_ssh(node) && is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -1015,15 +1425,23 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - if (!strcmp(format, "ssh-public-key-format")) { - hostkey->key.pubkey_type = NC_SSH_PUBKEY_SSH2; - } else if (!strcmp(format, "subject-public-key-info-format")) { - hostkey->key.pubkey_type = NC_SSH_PUBKEY_X509; - } else { - ERR(NULL, "Public key format (%s) not supported.", format); - } + hostkey->key.pubkey_type = pubkey_type; + } + } +#endif /* NC_ENABLED_SSH */ +#ifdef NC_ENABLED_TLS + if (equal_parent_name(node, 3, "server-identity") && is_tls(node) && is_listen(node)) { + /* TLS listen server-identity */ + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + endpt->opts.tls->pubkey_type = pubkey_type; } } +#endif /* NC_ENABLED_TLS */ cleanup: return ret; @@ -1033,10 +1451,16 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; const char *format; struct nc_endpt *endpt; + NC_PRIVKEY_FORMAT privkey_type; + +#ifdef NC_ENABLED_SSH struct nc_hostkey *hostkey; - int ret = 0; +#endif /* NC_ENABLED_SSH */ + + (void) op; assert(!strcmp(LYD_NAME(node), "private-key-format")); @@ -1045,36 +1469,65 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op goto cleanup; } - if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + format = ((struct lyd_node_term *)node)->value.ident->name; + if (!format) { ret = 1; goto cleanup; } - format = ((struct lyd_node_term *)node)->value.ident->name; - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - if (!strcmp(format, "rsa-private-key-format")) { - hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_RSA; - } else if (!strcmp(format, "ec-private-key-format")) { - hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_EC; - } else if (!strcmp(format, "subject-private-key-info-format")) { - hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_PKCS8; - } else if (!strcmp(format, "openssh-private-key-format")) { - hostkey->key.privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; - } else { - ERR(NULL, "Private key format (%s) not supported.", format); + privkey_type = nc_server_config_get_private_key_type(format); + if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) { + ret = 1; + goto cleanup; + } + +#ifdef NC_ENABLED_SSH + if ((is_ssh(node)) && (is_listen(node))) { + /* listen ssh */ + if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; } + + hostkey->key.privkey_type = privkey_type; + } +#endif /* NC_ENABLED_SSH */ +#ifdef NC_ENABLED_TLS + if ((is_tls(node)) && (is_listen(node))) { + /* listen tls */ + + endpt->opts.tls->privkey_type = privkey_type; } +#endif /* NC_ENABLED_TLS */ cleanup: return ret; } +#ifdef NC_ENABLED_SSH + static int nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey) { nc_server_config_del_private_key(hostkey); - hostkey->key.priv_base64 = strdup(lyd_get_value(node)); - if (!hostkey->key.priv_base64) { + hostkey->key.privkey_data = strdup(lyd_get_value(node)); + if (!hostkey->key.privkey_data) { + ERRMEM; + return 1; + } + + return 0; +} + +#endif /* NC_ENABLED_SSH */ + +#ifdef NC_ENABLED_TLS +static int +nc_server_config_tls_replace_cleartext_private_key(const struct lyd_node *node, struct nc_server_tls_opts *opts) +{ + nc_server_config_tls_del_cleartext_private_key(opts); + opts->privkey_data = strdup(lyd_get_value(node)); + if (!opts->privkey_data) { ERRMEM; return 1; } @@ -1082,20 +1535,27 @@ nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, stru return 0; } +#endif /* NC_ENABLED_TLS */ + static int nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; + +#ifdef NC_ENABLED_SSH struct nc_hostkey *hostkey; - int ret = 0; +#endif /* NC_ENABLED_SSH */ assert(!strcmp(LYD_NAME(node), "cleartext-private-key")); - if ((equal_parent_name(node, 6, "ssh")) && (equal_parent_name(node, 8, "listen"))) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + +#ifdef NC_ENABLED_SSH + if ((is_ssh(node)) && (is_listen(node))) { if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; @@ -1110,11 +1570,28 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION nc_server_config_del_private_key(hostkey); } } +#endif /* NC_ENABLED_SSH */ +#ifdef NC_ENABLED_TLS + if ((is_tls(node)) && (is_listen(node))) { + /* listen tls */ + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_tls_replace_cleartext_private_key(node, endpt->opts.tls); + if (ret) { + goto cleanup; + } + } else { + nc_server_config_tls_del_cleartext_private_key(endpt->opts.tls); + } + } +#endif /* NC_ENABLED_TLS */ cleanup: return ret; } +#ifdef NC_ENABLED_SSH + static int nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey) { @@ -1148,7 +1625,7 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op assert(!strcmp(LYD_NAME(node), "keystore-reference")); - if ((equal_parent_name(node, 3, "server-identity")) && (equal_parent_name(node, 7, "listen"))) { + if ((equal_parent_name(node, 3, "server-identity")) && (is_ssh(node)) && (is_listen(node))) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -1191,8 +1668,8 @@ nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, s { nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); - pubkey->pub_base64 = strdup(lyd_get_value(node)); - if (!pubkey->pub_base64) { + pubkey->data = strdup(lyd_get_value(node)); + if (!pubkey->data) { ERRMEM; return 1; } @@ -1205,8 +1682,25 @@ nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct { nc_server_config_del_public_key(hostkey); - hostkey->key.pub_base64 = strdup(lyd_get_value(node)); - if (!hostkey->key.pub_base64) { + hostkey->key.pubkey_data = strdup(lyd_get_value(node)); + if (!hostkey->key.pubkey_data) { + ERRMEM; + return 1; + } + + return 0; +} + +#endif /* NC_ENABLED_SSH */ + +#ifdef NC_ENABLED_TLS +static int +nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts) +{ + nc_server_config_tls_del_public_key(opts); + + opts->pubkey_data = strdup(lyd_get_value(node)); + if (!opts->pubkey_data) { ERRMEM; return 1; } @@ -1214,24 +1708,30 @@ nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct return 0; } +#endif /* NC_ENABLED_TLS */ + static int nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; + +#ifdef NC_ENABLED_SSH struct nc_hostkey *hostkey; struct nc_client_auth *auth_client; struct nc_public_key *pubkey; - int ret = 0; +#endif /* NC_ENABLED_SSH */ assert(!strcmp(LYD_NAME(node), "public-key")); - if ((equal_parent_name(node, 3, "host-key")) && (equal_parent_name(node, 8, "listen"))) { - /* server's public-key, mandatory leaf */ - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } +#ifdef NC_ENABLED_SSH + if ((equal_parent_name(node, 3, "host-key")) && (is_ssh(node)) && (is_listen(node))) { + /* server's public-key, mandatory leaf */ if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; @@ -1246,13 +1746,8 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } - } else if ((equal_parent_name(node, 5, "client-authentication")) && (equal_parent_name(node, 9, "listen"))) { + } else if ((equal_parent_name(node, 5, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) { /* client auth pubkeys, list */ - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; @@ -1274,13 +1769,8 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) nc_server_config_del_auth_client_pubkey(auth_client, pubkey); } - } else if ((equal_parent_name(node, 6, "client-authentication")) && (equal_parent_name(node, 10, "listen"))) { + } else if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) { /* client auth pubkey, leaf */ - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; @@ -1300,11 +1790,29 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); } } +#endif /* NC_ENABLED_SSH */ +#ifdef NC_ENABLED_TLS + if ((equal_parent_name(node, 3, "server-identity")) && (is_tls(node)) && (is_listen(node))) { + /* tls listen server-identity */ + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* set to local */ + endpt->opts.tls->store = NC_STORE_LOCAL; + + ret = nc_server_config_tls_replace_server_public_key(node, endpt->opts.tls); + if (ret) { + goto cleanup; + } + } + } +#endif /* NC_ENABLED_TLS */ cleanup: return ret; } +#ifdef NC_ENABLED_SSH + static int nc_server_config_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts) { @@ -1409,7 +1917,7 @@ nc_server_config_replace_truststore_reference(const struct lyd_node *node, struc } if (i == ts->pub_bag_count) { - ERR(NULL, "Truststore \"%s\" not found.", lyd_get_value(node)); + ERR(NULL, "Public-key bag \"%s\" not found in truststore.", lyd_get_value(node)); return 1; } @@ -1418,22 +1926,54 @@ nc_server_config_replace_truststore_reference(const struct lyd_node *node, struc return 0; } +#endif /* NC_ENABLED_SSH */ + +#ifdef NC_ENABLED_TLS +static int +nc_server_config_tls_replace_truststore_reference(const struct lyd_node *node, struct nc_cert_grouping *auth_client) +{ + uint16_t i; + struct nc_truststore *ts = &server_opts.truststore; + + /* lookup name */ + for (i = 0; i < ts->cert_bag_count; i++) { + if (!strcmp(lyd_get_value(node), ts->cert_bags[i].name)) { + break; + } + } + + if (i == ts->cert_bag_count) { + ERR(NULL, "Certificate bag \"%s\" not found in truststore.", lyd_get_value(node)); + return 1; + } + + auth_client->ts_ref = &ts->cert_bags[i]; + + return 0; +} + +#endif /* NC_ENABLED_TLS */ + /* leaf */ static int nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; + +#ifdef NC_ENABLED_SSH struct nc_client_auth *auth_client; - int ret = 0; +#endif /* NC_ENABLED_SSH */ assert(!strcmp(LYD_NAME(node), "truststore-reference")); - if ((equal_parent_name(node, 1, "public-keys")) && (equal_parent_name(node, 8, "listen"))) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } +#ifdef NC_ENABLED_SSH + if ((equal_parent_name(node, 1, "public-keys")) && (is_ssh(node)) && (is_listen(node))) { if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; @@ -1451,11 +1991,41 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION auth_client->ts_ref = NULL; } } +#endif /* NC_ENABLED_SSH */ +#ifdef NC_ENABLED_TLS + if ((equal_parent_name(node, 1, "ca-certs")) && (is_listen(node))) { + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* set to truststore */ + endpt->opts.tls->ca_certs.store = NC_STORE_TRUSTSTORE; + + ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ca_certs); + if (ret) { + goto cleanup; + } + } else { + endpt->opts.tls->ca_certs.ts_ref = NULL; + } + } else if ((equal_parent_name(node, 1, "ee-certs")) && (is_listen(node))) { + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* set to truststore */ + endpt->opts.tls->ee_certs.store = NC_STORE_TRUSTSTORE; + + ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ee_certs); + if (ret) { + goto cleanup; + } + } else { + endpt->opts.tls->ee_certs.ts_ref = NULL; + } + } +#endif /* NC_ENABLED_TLS */ cleanup: return ret; } +#ifdef NC_ENABLED_SSH + static int nc_server_config_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client) { @@ -1863,6 +2433,8 @@ nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op) return ret; } +#endif /* NC_ENABLED_SSH */ + static int nc_server_config_create_unix_socket(struct nc_endpt *endpt) { @@ -1949,6 +2521,8 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) return ret; } +#ifdef NC_ENABLED_SSH + /** * @brief Set all endpoint client auth references, which couldn't be set beforehand. * @@ -2072,28 +2646,476 @@ nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION return ret; } +#endif /* NC_ENABLED_SSH */ + +#ifdef NC_ENABLED_TLS + static int -nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_tls_replace_cert_data(const struct lyd_node *node, struct nc_server_tls_opts *opts) { - const char *name = LYD_NAME(node); + nc_server_config_tls_del_cert_data(opts); + opts->cert_data = strdup(lyd_get_value(node)); + if (!opts->cert_data) { + ERRMEM; + return 1; + } - if (!strcmp(name, "listen")) { - if (nc_server_config_listen(NULL, op)) { - goto error; - } - } else if (!strcmp(name, "idle-timeout")) { - if (nc_server_config_idle_timeout(node, op)) { - goto error; - } - } else if (!strcmp(name, "endpoint")) { - if (nc_server_config_endpoint(node, op)) { - goto error; - } - } else if (!strcmp(name, "ssh")) { - if (nc_server_config_ssh(node, op)) { - goto error; - } - } else if (!strcmp(name, "local-address")) { + return 0; +} + +static int +nc_server_config_tls_replace_cert_data_client_auth(const struct lyd_node *node, struct nc_certificate *cert) +{ + nc_server_config_tls_del_cert_data_certificate(cert); + cert->data = strdup(lyd_get_value(node)); + if (!cert->data) { + ERRMEM; + return 1; + } + + return 0; +} + +static int +nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + struct nc_certificate *cert; + + assert(!strcmp(LYD_NAME(node), "cert-data")); + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if ((equal_parent_name(node, 3, "server-identity")) && (is_listen(node))) { + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_tls_replace_cert_data(node, endpt->opts.tls); + if (ret) { + goto cleanup; + } + } + } else if ((equal_parent_name(node, 3, "ca-certs")) && (is_listen(node))) { + if (nc_server_config_get_cert(node, &endpt->opts.tls->ca_certs, &cert)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert); + if (ret) { + goto cleanup; + } + } else { + nc_server_config_tls_del_cert_data_certificate(cert); + } + } else if ((equal_parent_name(node, 3, "ee-certs")) && (is_listen(node))) { + if (nc_server_config_get_cert(node, &endpt->opts.tls->ee_certs, &cert)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert); + if (ret) { + goto cleanup; + } + } else { + nc_server_config_tls_del_cert_data_certificate(cert); + } + } + +cleanup: + return ret; +} + +static int +nc_server_config_tls_create_asymmetric_key_ref(const struct lyd_node *node, struct nc_endpt *endpt) +{ + uint16_t i; + struct nc_keystore *ks = &server_opts.keystore; + + /* lookup name */ + for (i = 0; i < ks->asym_key_count; i++) { + if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) { + break; + } + } + + if (i == ks->asym_key_count) { + ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node)); + return 1; + } + + endpt->opts.tls->key_ref = &ks->asym_keys[i]; + + return 0; +} + +static int +nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + + assert(!strcmp(LYD_NAME(node), "asymmetric-key")); + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* set to keystore */ + endpt->opts.tls->store = NC_STORE_KEYSTORE; + + ret = nc_server_config_tls_create_asymmetric_key_ref(node, endpt); + if (ret) { + goto cleanup; + } + } else { + endpt->opts.tls->key_ref = NULL; + } + +cleanup: + return ret; +} + +static int +nc_server_config_tls_create_certificate_ref(const struct lyd_node *node, struct nc_endpt *endpt, struct nc_asymmetric_key *key) +{ + uint16_t i; + + /* lookup name */ + for (i = 0; i < key->cert_count; i++) { + if (!strcmp(lyd_get_value(node), key->certs[i].name)) { + break; + } + } + + if (i == key->cert_count) { + ERR(NULL, "Certificate \"%s\" not found in the asymmetric key \"%s\".", lyd_get_value(node), key->name); + return 1; + } + + endpt->opts.tls->cert_ref = &key->certs[i]; + + return 0; +} + +static struct nc_asymmetric_key * +cert_get_asymmetric_key(const struct lyd_node *node) +{ + uint16_t i; + struct nc_keystore *ks = &server_opts.keystore; + + /* starting with certificate node */ + assert(!strcmp(LYD_NAME(node), "certificate")); + + /* switch to it's only sibling, must be asymmetric-key */ + node = node->prev; + assert(!strcmp(LYD_NAME(node), "asymmetric-key")); + + /* find the given asymmetric key */ + for (i = 0; i < ks->asym_key_count; i++) { + if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) { + return &ks->asym_keys[i]; + } + } + + /* didn't find it */ + ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node)); + return NULL; +} + +static int +nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts) +{ + assert(!strcmp(LYD_NAME(node), "certificate")); + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs, &opts->ca_certs.cert_count); +} + +static int +nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts) +{ + assert(!strcmp(LYD_NAME(node), "certificate")); + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs, &opts->ee_certs.cert_count); +} + +static int +nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + struct nc_asymmetric_key *key; + + assert(!strcmp(LYD_NAME(node), "certificate")); + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if ((equal_parent_name(node, 1, "keystore-reference")) && (is_listen(node))) { + /* server-identity TLS listen */ + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* set to keystore */ + endpt->opts.tls->store = NC_STORE_KEYSTORE; + + if (!endpt->opts.tls->key_ref) { + /* we don't have a key from which we need the cert yet */ + key = cert_get_asymmetric_key(node); + if (!key) { + ret = 1; + goto cleanup; + } + } else { + /* we have the key */ + key = endpt->opts.tls->key_ref; + } + + /* find the given cert in the key and set it */ + ret = nc_server_config_tls_create_certificate_ref(node, endpt, key); + if (ret) { + goto cleanup; + } + } else { + endpt->opts.tls->cert_ref = NULL; + } + } else if ((equal_parent_name(node, 2, "ca-certs")) && (is_listen(node))) { + /* client auth TLS listen */ + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_create_ca_certs_certificate(node, endpt->opts.tls); + if (ret) { + goto cleanup; + } + } else { + nc_server_config_tls_del_certs(&endpt->opts.tls->ca_certs); + } + } else if ((equal_parent_name(node, 2, "ee-certs")) && (is_listen(node))) { + /* client auth TLS listen */ + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_create_ee_certs_certificate(node, endpt->opts.tls); + if (ret) { + goto cleanup; + } + } else { + nc_server_config_tls_del_certs(&endpt->opts.tls->ee_certs); + } + } + +cleanup: + return ret; +} + +static int +nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts) +{ + int ret = 0; + struct lyd_node *n; + struct nc_ctn *new, *iter; + const char *map_type, *name; + uint32_t id; + NC_TLS_CTN_MAPTYPE m_type; + + assert(!strcmp(LYD_NAME(node), "cert-to-name")); + + /* create new ctn */ + new = calloc(1, sizeof *new); + if (!new) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* get all the data */ + /* find the list's key */ + lyd_find_path(node, "id", 0, &n); + assert(n); + id = strtoul(lyd_get_value(n), NULL, 10); + + /* find the ctn's name */ + lyd_find_path(node, "name", 0, &n); + assert(n); + name = lyd_get_value(n); + + /* find the ctn's map-type */ + lyd_find_path(node, "map-type", 0, &n); + assert(n); + map_type = ((struct lyd_node_term *)n)->value.ident->name; + if (!strcmp(map_type, "specified")) { + m_type = NC_TLS_CTN_SPECIFIED; + } else if (!strcmp(map_type, "san-rfc822-name")) { + m_type = NC_TLS_CTN_SAN_RFC822_NAME; + } else if (!strcmp(map_type, "san-dns-name")) { + m_type = NC_TLS_CTN_SAN_DNS_NAME; + } else if (!strcmp(map_type, "san-ip-address")) { + m_type = NC_TLS_CTN_SAN_IP_ADDRESS; + } else if (!strcmp(map_type, "san-any")) { + m_type = NC_TLS_CTN_SAN_ANY; + } else if (!strcmp(map_type, "common-name")) { + m_type = NC_TLS_CTN_COMMON_NAME; + } else { + ERR(NULL, "Map-type identity \"%s\" not supported.", map_type); + ret = 1; + goto cleanup; + } + + /* find the right place for insertion */ + if (!opts->ctn) { + /* inserting the first one */ + opts->ctn = new; + } else if (opts->ctn->id > new->id) { + /* insert at the beginning */ + new->next = opts->ctn; + opts->ctn = new; + } else { + /* have to find the right place */ + for (iter = opts->ctn; iter->next && iter->next->id <= new->id; iter = iter->next) {} + if (iter->id == new->id) { + /* collision */ + new = iter; + } else { + new->next = iter->next; + iter->next = new; + } + } + + /* insert the right data */ + new->id = id; + if (new->name) { + free(new->name); + } + new->name = strdup(name); + if (!new->name) { + ERRMEM; + ret = 1; + goto cleanup; + } + new->map_type = m_type; + +cleanup: + return ret; +} + +static int +nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + struct lyd_node *key; + struct nc_ctn *ctn; + + assert(!strcmp(LYD_NAME(node), "cert-to-name")); + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_create_cert_to_name(node, endpt->opts.tls); + if (ret) { + goto cleanup; + } + } else { + /* find the given ctn entry */ + lyd_find_path(node, "id", 0, &key); + assert(key); + if (nc_server_config_get_ctn(node, endpt, &ctn)) { + ret = 1; + goto cleanup; + } + nc_server_config_del_ctn(endpt->opts.tls, ctn); + } + +cleanup: + return ret; +} + +static int +nc_server_config_replace_fingerprint(const struct lyd_node *node, struct nc_ctn *ctn) +{ + nc_server_config_del_fingerprint(ctn); + + ctn->fingerprint = strdup(lyd_get_value(node)); + if (!ctn->fingerprint) { + ERRMEM; + return 1; + } + + return 0; +} + +static int +nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + struct nc_ctn *ctn; + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ctn(node, endpt, &ctn)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_replace_fingerprint(node, ctn); + if (ret) { + goto cleanup; + } + } else { + nc_server_config_del_fingerprint(ctn); + } + +cleanup: + return ret; +} + +#endif /* NC_ENABLED_TLS */ + +static int +nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op) +{ + const char *name = LYD_NAME(node); + + if (!strcmp(name, "listen")) { + if (nc_server_config_listen(NULL, op)) { + goto error; + } + } else if (!strcmp(name, "idle-timeout")) { + if (nc_server_config_idle_timeout(node, op)) { + goto error; + } + } else if (!strcmp(name, "endpoint")) { + if (nc_server_config_endpoint(node, op)) { + goto error; + } + } +#ifdef NC_ENABLED_SSH + else if (!strcmp(name, "ssh")) { + if (nc_server_config_ssh(node, op)) { + goto error; + } + } +#endif /* NC_ENABLED_SSH */ + else if (!strcmp(name, "local-address")) { if (nc_server_config_local_address(node, op)) { goto error; } @@ -2117,11 +3139,15 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_probe_interval(node, op)) { goto error; } - } else if (!strcmp(name, "host-key")) { + } +#ifdef NC_ENABLED_SSH + else if (!strcmp(name, "host-key")) { if (nc_server_config_host_key(node, op)) { goto error; } - } else if (!strcmp(name, "public-key-format")) { + } +#endif /* NC_ENABLED_SSH */ + else if (!strcmp(name, "public-key-format")) { if (nc_server_config_public_key_format(node, op)) { goto error; } @@ -2137,7 +3163,9 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_cleartext_private_key(node, op)) { goto error; } - } else if (!strcmp(name, "keystore-reference")) { + } +#ifdef NC_ENABLED_SSH + else if (!strcmp(name, "keystore-reference")) { if (nc_server_config_keystore_reference(node, op)) { goto error; } @@ -2153,11 +3181,15 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_auth_timeout(node, op)) { goto error; } - } else if (!strcmp(name, "truststore-reference")) { + } +#endif /* NC_ENABLED_SSH */ + else if (!strcmp(name, "truststore-reference")) { if (nc_server_config_truststore_reference(node, op)) { goto error; } - } else if (!strcmp(name, "password")) { + } +#ifdef NC_ENABLED_SSH + else if (!strcmp(name, "password")) { if (nc_server_config_password(node, op)) { goto error; } @@ -2189,20 +3221,47 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_mac_alg(node, op)) { goto error; } - } else if (!strcmp(name, "unix-socket")) { + } +#endif /* NC_ENABLED_SSH */ + else if (!strcmp(name, "unix-socket")) { if (nc_server_config_unix_socket(node, op)) { goto error; } - } else if (!strcmp(name, "endpoint-client-auth")) { + } +#ifdef NC_ENABLED_SSH + else if (!strcmp(name, "endpoint-client-auth")) { if (nc_server_config_endpoint_client_auth(node, op)) { goto error; } - } else if (!strcmp(name, "cert-data")) {} else if (!strcmp(name, "expiration-date")) {} else if (!strcmp(name, "asymmetric-key")) {} else if (!strcmp(name, "certificate")) {} else if (!strcmp(name, "key-format")) {} else if (!strcmp(name, - "cleartext-key")) {} else if (!strcmp(name, "hidden-key")) {} else if (!strcmp(name, "id_hint")) {} else if (!strcmp(name, "external-identity")) {} else if (!strcmp(name, "hash")) {} else if (!strcmp(name, "context")) {} else if (!strcmp(name, - "target-protocol")) {} else if (!strcmp(name, "target-kdf")) {} else if (!strcmp(name, "client-authentication")) {} else if (!strcmp(name, "ca-certs")) {} else if (!strcmp(name, "ee-certs")) {} else if (!strcmp(name, - "raw-public-keys")) {} else if (!strcmp(name, "tls12-psks")) {} else if (!strcmp(name, "tls13-epsks")) {} else if (!strcmp(name, "tls-version")) {} else if (!strcmp(name, "cipher-suite")) {} else if (!strcmp(name, - "peer-allowed-to-send")) {} else if (!strcmp(name, "test-peer-aliveness")) {} else if (!strcmp(name, "max-wait")) {} else if (!strcmp(name, "max-attempts")) {} else if (!strcmp(name, "cert-to-name")) {} else if (!strcmp(name, - "id")) {} else if (!strcmp(name, "fingerprint")) {} else if (!strcmp(name, "map-type")) {} + } +#endif /* NC_ENABLED_SSH */ +#ifdef NC_ENABLED_TLS + else if (!strcmp(name, "tls")) { + if (nc_server_config_tls(node, op)) { + goto error; + } + } else if (!strcmp(name, "cert-data")) { + if (nc_server_config_cert_data(node, op)) { + goto error; + } + } else if (!strcmp(name, "asymmetric-key")) { + if (nc_server_config_asymmetric_key(node, op)) { + goto error; + } + } else if (!strcmp(name, "certificate")) { + if (nc_server_config_certificate(node, op)) { + goto error; + } + } else if (!strcmp(name, "cert-to-name")) { + if (nc_server_config_cert_to_name(node, op)) { + goto error; + } + } else if (!strcmp(name, "fingerprint")) { + if (nc_server_config_fingerprint(node, op)) { + goto error; + } + } +#endif /* NC_ENABLED_TLS */ return 0; @@ -2359,29 +3418,6 @@ nc_server_config_load_modules(struct ly_ctx **ctx) return 1; } -API int -nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path) -{ - struct lyd_node *tree = NULL; - int ret = 0; - - NC_CHECK_ARG_RET(NULL, path, 1); - - ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); - if (ret) { - goto cleanup; - } - - ret = nc_server_config_setup_data(tree); - if (ret) { - goto cleanup; - } - -cleanup: - lyd_free_all(tree); - return ret; -} - static int nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op) { @@ -2399,10 +3435,12 @@ nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION o goto cleanup; } +#ifdef NC_ENABLED_SSH if (nc_server_config_fill_endpt_client_auth()) { ret = 1; goto cleanup; } +#endif /* NC_ENABLED_SSH */ cleanup: return ret; @@ -2502,3 +3540,26 @@ nc_server_config_setup_data(const struct lyd_node *data) pthread_rwlock_unlock(&server_opts.config_lock); return ret; } + +API int +nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path) +{ + struct lyd_node *tree = NULL; + int ret = 0; + + NC_CHECK_ARG_RET(NULL, path, 1); + + ret = lyd_parse_data_path(ctx, path, LYD_UNKNOWN, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_setup_data(tree); + if (ret) { + goto cleanup; + } + +cleanup: + lyd_free_all(tree); + return ret; +} diff --git a/src/server_config.h b/src/server_config.h index 019db841..63b30eeb 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -4,7 +4,7 @@ * @brief libnetconf2 server configuration * * @copyright - * Copyright (c) 2015 - 2021 CESNET, z.s.p.o. + * Copyright (c) 2023 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,12 +20,12 @@ extern "C" { #endif -#include +#include #include -#include "netconf.h" +#include + #include "session.h" -#include "session_p.h" /** * @brief Configure server based on the given diff data. @@ -83,38 +83,39 @@ int nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path); int nc_server_config_load_modules(struct ly_ctx **ctx); /** - * @brief Creates new YANG configuration data nodes for a hostkey. + * @brief Creates new YANG configuration data nodes for a local-address and local-port. * - * @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] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's hostkey might be changed. - * @param[in] hostkey_name Arbitrary identifier of the hostkey. - * If a hostkey with this identifier already exists, it's contents will be changed. + * @param[in] transport Either SSH or TLS transport for the given endpoint. + * @param[in] address New listening address. + * @param[in] port New listening port. + * If an endpoint with this identifier already exists, it's address and port will be overriden. * @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_new_ssh_hostkey(const char *privkey_path, const char *pubkey_path, const struct ly_ctx *ctx, - const char *endpt_name, const char *hostkey_name, struct lyd_node **config); +int nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_name, NC_TRANSPORT_IMPL transport, + const char *address, const char *port, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a local-address and local-port. + * @brief Creates new YANG configuration data nodes for a hostkey. * - * @param[in] address New listening address. - * @param[in] port New listening port. * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's address and port will be overriden. + * If an endpoint with this identifier already exists, it's hostkey might be changed. + * @param[in] hostkey_name Arbitrary identifier of the hostkey. + * If a hostkey with this identifier already exists, it's 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_new_ssh_address_port(const char *address, const char *port, const struct ly_ctx *ctx, - const char *endpt_name, struct lyd_node **config); +int nc_server_config_new_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 Creates new YANG configuration data nodes for host-key algorithms replacing any previous ones. @@ -191,7 +192,6 @@ int nc_server_config_new_ssh_mac_algs(const struct ly_ctx *ctx, const char *endp /** * @brief Creates new YANG configuration data nodes for a client, which supports the public key authentication method. * - * @param[in] pubkey_path Path to a file containing the user's public key. * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. * If an endpoint with this identifier already exists, it's user might be changed. @@ -199,30 +199,31 @@ int nc_server_config_new_ssh_mac_algs(const struct ly_ctx *ctx, const char *endp * If an user with this identifier already exists, it's 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, it's 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_new_ssh_client_auth_pubkey(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, const char *pubkey_name, struct lyd_node **config); +int nc_server_config_new_ssh_client_auth_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 Creates new YANG configuration data nodes for a client, which supports the password authentication method. * * This function sets the password for the given user. * - * @param[in] password Cleartext user's password. * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. * If an endpoint with this identifier already exists, it's user might be changed. * @param[in] user_name Arbitrary identifier of the user. * If an user with this identifier already exists, it's contents will be changed. + * @param[in] password Cleartext user's password. * @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_new_ssh_client_auth_password(const char *password, const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config); +int nc_server_config_new_ssh_client_auth_password(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *password, struct lyd_node **config); /** * @brief Creates new YANG configuration data nodes for a client, which supports the none authentication method. @@ -242,22 +243,91 @@ int nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const ch /** * @brief Creates new YANG configuration data nodes for a client, which supports the interactive authentication method. * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's user might be changed. + * @param[in] user_name Arbitrary identifier of the user. + * If an user with this identifier already exists, it's contents will be changed. * @param[in] pam_config_name Name of the PAM configuration file. * @param[in] pam_config_name Optional. The absolute path to the directory in which the configuration file * with the name conf_name is located. A newer version (>= 1.4) of PAM library is required to be able to specify * the path. If NULL is passed, then the PAM's system directories will be searched (usually /etc/pam.d/). + * @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_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config); + +#ifdef NC_ENABLED_TLS +/** + * @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, it's user might be changed. - * @param[in] user_name Arbitrary identifier of the user. - * If an user with this identifier already exists, it's contents will be changed. + * If an endpoint with this identifier already exists, it's server certificate will be changed. + * @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] privkey_path Path to the server's private key file. + * @param[in] certificate_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_new_ssh_client_auth_interactive(const char *pam_config_name, const char *pam_config_dir, - const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config); +int nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *pubkey_path, + const char *privkey_path, const char *certificate_path, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a client's (end-entity) certificate. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's contents will be changed. + * @param[in] cert_name Arbitrary identifier of the client's certificate. + * If a client certificate with this indetifier 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_new_tls_client_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, + const char *cert_path, 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] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's contents will be changed. + * @param[in] cert_name Arbitrary identifier of the certificate authority certificate. + * If a CA with this indetifier 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_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, + const char *cert_path, 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, it's 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. + * @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_new_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); + +#endif /* NC_ENABLED_TLS */ #ifdef __cplusplus } diff --git a/src/server_config_ks.c b/src/server_config_ks.c index dfcb3857..25b67748 100644 --- a/src/server_config_ks.c +++ b/src/server_config_ks.c @@ -16,12 +16,16 @@ #define _GNU_SOURCE #include +#include #include #include +#include + #include "compat.h" -#include "libnetconf.h" +#include "log_p.h" #include "server_config_p.h" +#include "session_p.h" extern struct nc_server_opts server_opts; @@ -117,8 +121,8 @@ nc_server_config_ks_del_asymmetric_key_cert(struct nc_asymmetric_key *key, struc free(cert->name); cert->name = NULL; - free(cert->cert_base64); - cert->cert_base64 = NULL; + free(cert->data); + cert->data = NULL; key->cert_count--; if (key->cert_count == 0) { @@ -130,22 +134,22 @@ nc_server_config_ks_del_asymmetric_key_cert(struct nc_asymmetric_key *key, struc static void nc_server_config_ks_del_public_key(struct nc_asymmetric_key *key) { - free(key->pub_base64); - key->pub_base64 = NULL; + free(key->pubkey_data); + key->pubkey_data = NULL; } static void nc_server_config_ks_del_private_key(struct nc_asymmetric_key *key) { - free(key->priv_base64); - key->priv_base64 = NULL; + free(key->privkey_data); + key->privkey_data = NULL; } static void nc_server_config_ks_del_cert_data(struct nc_certificate *cert) { - free(cert->cert_base64); - cert->cert_base64 = NULL; + free(cert->data); + cert->data = NULL; } static void @@ -252,9 +256,9 @@ nc_server_config_ks_public_key_format(const struct lyd_node *node, NC_OPERATION format = ((struct lyd_node_term *)node)->value.ident->name; if (!strcmp(format, "ssh-public-key-format")) { - key->pubkey_type = NC_SSH_PUBKEY_SSH2; + key->pubkey_type = NC_PUBKEY_FORMAT_SSH2; } else if (!strcmp(format, "subject-public-key-info-format")) { - key->pubkey_type = NC_SSH_PUBKEY_X509; + key->pubkey_type = NC_PUBKEY_FORMAT_X509; } else { ERR(NULL, "Public key format (%s) not supported.", format); } @@ -277,8 +281,8 @@ nc_server_config_ks_public_key(const struct lyd_node *node, NC_OPERATION op) /* replace the pubkey */ nc_server_config_ks_del_public_key(key); - key->pub_base64 = strdup(lyd_get_value(node)); - if (!key->pub_base64) { + key->pubkey_data = strdup(lyd_get_value(node)); + if (!key->pubkey_data) { ERRMEM; return 1; } @@ -291,6 +295,9 @@ nc_server_config_ks_private_key_format(const struct lyd_node *node, NC_OPERATION { struct nc_asymmetric_key *key; const char *format; + NC_PRIVKEY_FORMAT privkey_type; + + (void) op; assert(!strcmp(LYD_NAME(node), "private-key-format")); @@ -299,19 +306,15 @@ nc_server_config_ks_private_key_format(const struct lyd_node *node, NC_OPERATION } format = ((struct lyd_node_term *)node)->value.ident->name; - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - if (!strcmp(format, "rsa-private-key-format")) { - key->privkey_type = NC_PRIVKEY_FORMAT_RSA; - } else if (!strcmp(format, "ec-private-key-format")) { - key->privkey_type = NC_PRIVKEY_FORMAT_EC; - } else if (!strcmp(format, "subject-private-key-info-format")) { - key->privkey_type = NC_PRIVKEY_FORMAT_PKCS8; - } else if (!strcmp(format, "openssh-private-key-format")) { - key->privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; - } else { - ERR(NULL, "Private key format (%s) not supported.", format); - } + if (!format) { + return 1; + } + + privkey_type = nc_server_config_get_private_key_type(format); + if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) { + return 1; } + key->privkey_type = privkey_type; return 0; } @@ -330,8 +333,8 @@ nc_server_config_ks_cleartext_private_key(const struct lyd_node *node, NC_OPERAT if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* replace the privkey */ nc_server_config_ks_del_private_key(key); - key->priv_base64 = strdup(lyd_get_value(node)); - if (!key->priv_base64) { + key->privkey_data = strdup(lyd_get_value(node)); + if (!key->privkey_data) { ERRMEM; return 1; } @@ -401,8 +404,8 @@ nc_server_config_ks_cert_data(const struct lyd_node *node, NC_OPERATION op) /* replace the cert data */ nc_server_config_ks_del_cert_data(cert); - cert->cert_base64 = strdup(lyd_get_value(node)); - if (!cert->cert_base64) { + cert->data = strdup(lyd_get_value(node)); + if (!cert->data) { ERRMEM; return 1; } diff --git a/src/server_config_p.h b/src/server_config_p.h index 7d5469df..7866bf99 100644 --- a/src/server_config_p.h +++ b/src/server_config_p.h @@ -22,10 +22,8 @@ extern "C" { #include #include +#include -#include "compat.h" -#include "libnetconf.h" -#include "netconf.h" #include "session_p.h" /** @@ -47,6 +45,7 @@ typedef enum { */ int nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind); +#ifdef NC_ENABLED_SSH /** * @brief Get the pointer to a hostkey structure based on node's location in the YANG data. * @@ -77,6 +76,8 @@ int nc_server_config_get_auth_client(const struct lyd_node *node, const struct n */ int nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_public_key **pubkey); +#endif /* NC_ENABLED_SSH */ + /** * @brief Compares the nth-parent name. * @@ -87,6 +88,14 @@ int nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_cli */ int equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name); +/** + * @brief Get private key type from YANG identity stored in a string. + * + * @param[in] format Value of the YANG identityref. + * @return Private key format on success, NC_PRIVKEY_FORMAT_UNKNOWN otherwise. + */ +NC_PRIVKEY_FORMAT nc_server_config_get_private_key_type(const char *format); + /** * @brief Generic realloc function for arrays of structures representing YANG lists whose first member is the key (char *) * diff --git a/src/server_config_ts.c b/src/server_config_ts.c index 9b06ada9..b0d318b8 100644 --- a/src/server_config_ts.c +++ b/src/server_config_ts.c @@ -16,12 +16,16 @@ #define _GNU_SOURCE #include +#include #include #include +#include + #include "compat.h" -#include "libnetconf.h" +#include "log_p.h" #include "server_config_p.h" +#include "session_p.h" extern struct nc_server_opts server_opts; @@ -206,15 +210,15 @@ nc_server_config_get_public_key(const struct lyd_node *node, const struct nc_pub static void nc_server_config_ts_del_cert_data(struct nc_certificate *cert) { - free(cert->cert_base64); - cert->cert_base64 = NULL; + free(cert->data); + cert->data = NULL; } static void nc_server_config_ts_del_public_key_base64(struct nc_public_key *pkey) { - free(pkey->pub_base64); - pkey->pub_base64 = NULL; + free(pkey->data); + pkey->data = NULL; } static void @@ -422,8 +426,8 @@ nc_server_config_ts_cert_data(const struct lyd_node *node, NC_OPERATION op) } nc_server_config_ts_del_cert_data(cert); - cert->cert_base64 = strdup(lyd_get_value(node)); - if (!cert->cert_base64) { + cert->data = strdup(lyd_get_value(node)); + if (!cert->data) { ERRMEM; return 1; } @@ -510,8 +514,8 @@ nc_server_config_ts_public_key(const struct lyd_node *node, NC_OPERATION op) /* replace the public key */ nc_server_config_ts_del_public_key_base64(pkey); - pkey->pub_base64 = strdup(lyd_get_value(node)); - if (!pkey->pub_base64) { + pkey->data = strdup(lyd_get_value(node)); + if (!pkey->data) { ERRMEM; ret = 1; goto cleanup; @@ -541,9 +545,9 @@ nc_server_config_ts_public_key_format(const struct lyd_node *node, NC_OPERATION format = ((struct lyd_node_term *)node)->value.ident->name; if (!strcmp(format, "ssh-public-key-format")) { - pkey->pubkey_type = NC_SSH_PUBKEY_SSH2; + pkey->type = NC_PUBKEY_FORMAT_SSH2; } else if (!strcmp(format, "subject-public-key-info-format")) { - pkey->pubkey_type = NC_SSH_PUBKEY_X509; + pkey->type = NC_PUBKEY_FORMAT_X509; } else { ERR(NULL, "Public key format (%s) not supported.", format); } diff --git a/src/session.c b/src/session.c index 17c6bea3..a3c7fb02 100644 --- a/src/session.c +++ b/src/session.c @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include #include #include @@ -30,9 +28,10 @@ #include #include "compat.h" -#include "libnetconf.h" -#include "session.h" -#include "session_server.h" +#include "config.h" +#include "log_p.h" +#include "netconf.h" +#include "session_p.h" #ifdef NC_ENABLED_SSH @@ -107,37 +106,21 @@ nc_realtime_get(struct timespec *ts) } } -/** - * @brief Convert key type to string. - * - * @param[in] type Type of the key. - * @return String literal representing the key type or NULL. - */ const char * -nc_keytype2str(NC_SSH_KEY_TYPE type) +nc_privkey_format_to_str(NC_PRIVKEY_FORMAT format) { - switch (type) { - case NC_SSH_KEY_UNKNOWN: - return "unknown"; - case NC_SSH_KEY_DSA: - return "DSA"; - case NC_SSH_KEY_RSA: + switch (format) { + case NC_PRIVKEY_FORMAT_RSA: return "RSA"; - case NC_SSH_KEY_ECDSA: + case NC_PRIVKEY_FORMAT_EC: return "EC"; - case NC_SSH_KEY_ECDSA_P256: - return "ECDSA_P256"; - case NC_SSH_KEY_ECDSA_P384: - return "ECDSA_P384"; - case NC_SSH_KEY_ECDSA_P521: - return "ECDSA_P521"; - case NC_SSH_KEY_ED25519: + case NC_PRIVKEY_FORMAT_X509: return NULL; + case NC_PRIVKEY_FORMAT_OPENSSH: + return "OPENSSH"; default: - break; + return NULL; } - - return NULL; } int diff --git a/src/session.h b/src/session.h index aab4cac6..eb3b36fa 100644 --- a/src/session.h +++ b/src/session.h @@ -109,20 +109,6 @@ typedef enum { NC_CH_RANDOM } NC_CH_START_WITH; -/** - * @brief Enumeration of SSH key types. - */ -typedef enum { - NC_SSH_KEY_UNKNOWN = 0, - NC_SSH_KEY_DSA, - NC_SSH_KEY_RSA, - NC_SSH_KEY_ECDSA, /**< only for private key */ - NC_SSH_KEY_ECDSA_P256, - NC_SSH_KEY_ECDSA_P384, - NC_SSH_KEY_ECDSA_P521, - NC_SSH_KEY_ED25519 -} NC_SSH_KEY_TYPE; - /** * @brief NETCONF session object */ diff --git a/src/session_client.c b/src/session_client.c index c7ff7ccd..69d0bf91 100644 --- a/src/session_client.c +++ b/src/session_client.c @@ -42,9 +42,12 @@ #include #include "compat.h" -#include "libnetconf.h" -#include "messages_client.h" +#include "config.h" +#include "log_p.h" +#include "messages_p.h" #include "session_client.h" +#include "session_client_ch.h" +#include "session_p.h" #include "../modules/ietf_netconf@2013-09-29_yang.h" #include "../modules/ietf_netconf_monitoring@2010-10-04_yang.h" diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c index c3c8d1f9..500fdbe4 100644 --- a/src/session_client_ssh.c +++ b/src/session_client_ssh.c @@ -45,9 +45,11 @@ #include #include "compat.h" -#include "libnetconf.h" +#include "config.h" +#include "log_p.h" #include "session_client.h" #include "session_client_ch.h" +#include "session_p.h" struct nc_client_context *nc_client_context_location(void); @@ -1690,7 +1692,7 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx) char *known_hosts_path = NULL; /* process parameters */ - if (!host || strisempty(host)) { + if (!host || (host[0] == '\0')) { host = "localhost"; } diff --git a/src/session_client_tls.c b/src/session_client_tls.c index 94b21b42..26b22e42 100644 --- a/src/session_client_tls.c +++ b/src/session_client_tls.c @@ -28,9 +28,11 @@ #include #include -#include "libnetconf.h" +#include "config.h" +#include "log_p.h" #include "session_client.h" #include "session_client_ch.h" +#include "session_p.h" #if OPENSSL_VERSION_NUMBER < 0x10100000L #define X509_STORE_CTX_get_by_subject X509_STORE_get_by_subject @@ -666,7 +668,7 @@ nc_connect_tls(const char *host, unsigned short port, struct ly_ctx *ctx) } /* process parameters */ - if (!host || strisempty(host)) { + if (!host || (host[0] == '\0')) { host = "localhost"; } diff --git a/src/session_p.h b/src/session_p.h index 6628a3de..6af60a0a 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -21,15 +21,12 @@ #include #include -#include #include +#include #include "compat.h" -#include "libnetconf.h" -#include "messages_client.h" -#include "netconf.h" -#include "session.h" +#include "config.h" #include "session_client.h" /** @@ -55,12 +52,12 @@ typedef enum { } NC_STORE_TYPE; /** - * Enumeration of SSH public key representation types. + * Enumeration of SSH public key formats. */ typedef enum { - NC_SSH_PUBKEY_SSH2, /**< begins with BEGIN SSH2 PUBLICKEY, see RFC 4716 */ - NC_SSH_PUBKEY_X509 /**< begins with BEGIN PUBLICKEY, see RFC 5280 sec. 4.1.2.7 */ -} NC_SSH_PUBKEY_TYPE; + NC_PUBKEY_FORMAT_SSH2, /**< begins with BEGIN SSH2 PUBLICKEY, see RFC 4716 */ + NC_PUBKEY_FORMAT_X509 /**< begins with BEGIN PUBLICKEY, see RFC 5280 sec. 4.1.2.7 */ +} NC_PUBKEY_FORMAT; /** * Enumeration of private key file formats. @@ -68,16 +65,17 @@ typedef enum { typedef enum { NC_PRIVKEY_FORMAT_RSA, /**< PKCS1 RSA format */ NC_PRIVKEY_FORMAT_EC, /**< SEC1 EC format */ - NC_PRIVKEY_FORMAT_PKCS8, /**< PKCS8 format */ - NC_PRIVKEY_FORMAT_OPENSSH /**< OpenSSH format */ + NC_PRIVKEY_FORMAT_X509, /**< X509 (PKCS8) format */ + NC_PRIVKEY_FORMAT_OPENSSH, /**< OpenSSH format */ + NC_PRIVKEY_FORMAT_UNKNOWN /**< Unknown format */ } NC_PRIVKEY_FORMAT; /** * @brief A basic certificate. */ struct nc_certificate { - char *name; /**< Arbitrary name of the certificate. */ - char *cert_base64; /**< Base-64 encoded certificate. */ + char *name; /**< Arbitrary name of the certificate. */ + char *data; /**< Base-64 encoded certificate. */ }; struct nc_certificate_bag { @@ -92,10 +90,10 @@ struct nc_certificate_bag { struct nc_asymmetric_key { char *name; /**< Arbitrary name of the key. */ - NC_SSH_PUBKEY_TYPE pubkey_type; /**< Type of the public key. */ - char *pub_base64; /**< Base-64 encoded public key. */ - NC_PRIVKEY_FORMAT privkey_type; /**< Type of the private key. */ - char *priv_base64; /**< Base-64 encoded private key. */ + NC_PUBKEY_FORMAT pubkey_type; /**< Type of the public key. */ + char *pubkey_data; /**< Base-64 encoded public key. */ + NC_PRIVKEY_FORMAT privkey_type; /**< Type of the private key. */ + char *privkey_data; /**< Base-64 encoded private key. */ struct nc_certificate *certs; /**< The certificates associated with this key. */ uint16_t cert_count; /**< Number of certificates associated with this key. */ @@ -105,17 +103,17 @@ struct nc_asymmetric_key { * @brief A symmetric key. */ struct nc_symmetric_key { - char *name; /**< Arbitrary name of the key. */ - char *base64; /**< Base-64 encoded key. */ + char *name; /**< Arbitrary name of the key. */ + char *data; /**< Base-64 encoded key. */ }; /** * @brief A public key. */ struct nc_public_key { - char *name; /**< Arbitrary name of the public key. */ - NC_SSH_PUBKEY_TYPE pubkey_type; /**< Type of the public key. */ - char *pub_base64; /**< Base-64 encoded public key. */ + char *name; /**< Arbitrary name of the public key. */ + NC_PUBKEY_FORMAT type; /**< Type of the public key. */ + char *data; /**< Base-64 encoded public key. */ }; struct nc_public_key_bag { @@ -147,10 +145,6 @@ struct nc_keystore { #ifdef NC_ENABLED_SSH -# include -# include -# include - /* seconds */ # define NC_SSH_TIMEOUT 10 /* number of all supported authentication methods */ @@ -223,9 +217,6 @@ struct nc_server_ssh_opts { #ifdef NC_ENABLED_TLS -# include -# include - /* ACCESS unlocked */ struct nc_client_tls_opts { char *cert_path; @@ -241,22 +232,57 @@ struct nc_client_tls_opts { X509_STORE *crl_store; }; -/* ACCESS locked, separate locks */ +/** + * @brief Certificate grouping (either local-definition or truststore reference). + */ +struct nc_cert_grouping { + NC_STORE_TYPE store; /**< Specifies how/where the certificates are stored. */ + union { + struct { + struct nc_certificate *certs; /**< Local-defined certificates */ + uint16_t cert_count; /**< Certificate count */ + }; + struct nc_certificate_bag *ts_ref; /**< Referenced trustore certificate bag */ + }; +}; + +/** + * @brief Cert-to-name entries. + */ +struct nc_ctn { + uint32_t id; /**< ID of the entry, the lower the higher priority */ + char *fingerprint; /**< Fingerprint of the entry */ + NC_TLS_CTN_MAPTYPE map_type; /**< Specifies how to get the username from the certificate */ + char *name; /**< Username for this entry */ + struct nc_ctn *next; /**< Linked-list reference to the next entry */ +}; + +/** + * @brief Server options for configuring the TLS transport protocol. + */ struct nc_server_tls_opts { - char *server_cert; - char **trusted_cert_lists; - uint16_t trusted_cert_list_count; - char *trusted_ca_file; - char *trusted_ca_dir; - X509_STORE *crl_store; + NC_STORE_TYPE store; /**< Specifies how/where the server identity is stored. */ + union { + struct { + NC_PUBKEY_FORMAT pubkey_type; /**< Server public key type */ + char *pubkey_data; /**< Server's public key */ - struct nc_ctn { - uint32_t id; - char *fingerprint; - NC_TLS_CTN_MAPTYPE map_type; - char *name; - struct nc_ctn *next; - } *ctn; + NC_PRIVKEY_FORMAT privkey_type; /**< Server private key type */ + char *privkey_data; /**< Server's private key */ + + char *cert_data; /**< Server's certificate */ + }; + + struct { + struct nc_asymmetric_key *key_ref; /**< Reference to the server's key */ + struct nc_certificate *cert_ref; /**< Reference to the concrete server's certificate */ + }; + }; + + struct nc_cert_grouping ca_certs; /**< Client certificate authorities */ + struct nc_cert_grouping ee_certs; /**< Client end-entity certificates */ + + struct nc_ctn *ctn; /**< Cert-to-name entries */ }; #endif /* NC_ENABLED_TLS */ @@ -394,21 +420,6 @@ struct nc_server_opts { #endif #ifdef NC_ENABLED_TLS int (*user_verify_clb)(const struct nc_session *session); - - int (*server_cert_clb)(const char *name, void *user_data, char **cert_path, char **cert_data, char **privkey_path, - char **privkey_data, NC_SSH_KEY_TYPE *privkey_type); - void *server_cert_data; - void (*server_cert_data_free)(void *data); - - int (*server_cert_chain_clb)(const char *name, void *user_data, char ***cert_paths, int *cert_path_count, - char ***cert_data, int *cert_data_count); - void *server_cert_chain_data; - void (*server_cert_chain_data_free)(void *data); - - int (*trusted_cert_list_clb)(const char *name, void *user_data, char ***cert_paths, int *cert_path_count, - char ***cert_data, int *cert_data_count); - void *trusted_cert_list_data; - void (*trusted_cert_list_data_free)(void *data); #endif pthread_rwlock_t config_lock; @@ -723,7 +734,7 @@ int32_t nc_timeouttime_cur_diff(const struct timespec *ts); */ void nc_realtime_get(struct timespec *ts); -const char *nc_keytype2str(NC_SSH_KEY_TYPE type); +const char *nc_privkey_format_to_str(NC_PRIVKEY_FORMAT format); int nc_sock_configure_keepalive(int sock, struct nc_keepalives *ka); @@ -980,7 +991,7 @@ struct nc_session *nc_accept_callhome_tls_sock(int sock, const char *host, uint1 * @param[in] timeout Transport operations timeout in msec. * @return 1 on success, 0 on timeout, -1 on error. */ -int nc_accept_tls_session(struct nc_session *session, int sock, int timeout); +int nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opts, int sock, int timeout); void nc_server_tls_clear_opts(struct nc_server_tls_opts *opts); diff --git a/src/session_server_ch.h b/src/session_server_ch.h index e8c508ba..bf59ce4a 100644 --- a/src/session_server_ch.h +++ b/src/session_server_ch.h @@ -22,6 +22,7 @@ extern "C" { #include #include +#include #include "netconf.h" #include "session.h" diff --git a/src/session_server_tls.c b/src/session_server_tls.c index 0c227ce7..5f5c6ea5 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -1,10 +1,11 @@ /** * @file session_server_tls.c * @author Michal Vasko + * @author Roman Janota * @brief libnetconf2 TLS server session manipulation functions * * @copyright - * Copyright (c) 2015 - 2021 CESNET, z.s.p.o. + * Copyright (c) 2015 - 2023 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. @@ -16,9 +17,14 @@ #define _GNU_SOURCE #include +#include +#include +#include #include #include +#include +#include #include #include #include @@ -26,13 +32,10 @@ #include #include "compat.h" -#include "libnetconf.h" -#include "session_server.h" -#include "session_server_ch.h" - -#if OPENSSL_VERSION_NUMBER < 0x10100000L -#define X509_STORE_CTX_get_by_subject X509_STORE_get_by_subject -#endif +#include "config.h" +#include "log_p.h" +#include "session.h" +#include "session_p.h" struct nc_server_tls_opts tls_ch_opts; pthread_mutex_t tls_ch_opts_lock = PTHREAD_MUTEX_INITIALIZER; @@ -51,10 +54,12 @@ asn1time_to_str(const ASN1_TIME *t) if (!t) { return NULL; } + bio = BIO_new(BIO_s_mem()); if (!bio) { return NULL; } + ASN1_TIME_print(bio, t); n = BIO_pending(bio); cp = malloc(n + 1); @@ -63,12 +68,14 @@ asn1time_to_str(const ASN1_TIME *t) BIO_free(bio); return NULL; } + n = BIO_read(bio, cp, n); if (n < 0) { BIO_free(bio); free(cp); return NULL; } + cp[n] = '\0'; BIO_free(bio); return cp; @@ -123,23 +130,6 @@ base64der_to_cert(const char *in) return out; } -/* return NULL - either errno or SSL error */ -static X509 * -pem_to_cert(const char *path) -{ - FILE *fp; - X509 *out; - - fp = fopen(path, "r"); - if (!fp) { - return NULL; - } - - out = PEM_read_X509(fp, NULL, NULL, NULL); - fclose(fp); - return out; -} - static EVP_PKEY * base64der_to_privatekey(const char *in, const char *key_str) { @@ -215,7 +205,7 @@ nc_tls_ctn_get_username_from_cert(X509 *client_cert, NC_TLS_CTN_MAPTYPE map_type *username = strdup(common_name); if (!*username) { ERRMEM; - return -1; + return 1; } free(subject); } else { @@ -233,14 +223,10 @@ nc_tls_ctn_get_username_from_cert(X509 *client_cert, NC_TLS_CTN_MAPTYPE map_type /* rfc822Name (email) */ if (((map_type == NC_TLS_CTN_SAN_ANY) || (map_type == NC_TLS_CTN_SAN_RFC822_NAME)) && (san_name->type == GEN_EMAIL)) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - *username = strdup((char *)ASN1_STRING_data(san_name->d.rfc822Name)); -#else *username = strdup((char *)ASN1_STRING_get0_data(san_name->d.rfc822Name)); -#endif if (!*username) { ERRMEM; - return -1; + return 1; } break; } @@ -248,14 +234,10 @@ nc_tls_ctn_get_username_from_cert(X509 *client_cert, NC_TLS_CTN_MAPTYPE map_type /* dNSName */ if (((map_type == NC_TLS_CTN_SAN_ANY) || (map_type == NC_TLS_CTN_SAN_DNS_NAME)) && (san_name->type == GEN_DNS)) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - *username = strdup((char *)ASN1_STRING_data(san_name->d.dNSName)); -#else *username = strdup((char *)ASN1_STRING_get0_data(san_name->d.dNSName)); -#endif if (!*username) { ERRMEM; - return -1; + return 1; } break; } @@ -340,13 +322,17 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * map_type = NC_TLS_CTN_UNKNOWN; /* first make sure the entry is valid */ - if (!ctn->fingerprint || !ctn->map_type || ((ctn->map_type == NC_TLS_CTN_SPECIFIED) && !ctn->name)) { + if (!ctn->map_type || ((ctn->map_type == NC_TLS_CTN_SPECIFIED) && !ctn->name)) { VRB(NULL, "Cert verify CTN: entry with id %u not valid, skipping.", ctn->id); continue; } - /* MD5 */ - if (!strncmp(ctn->fingerprint, "01", 2)) { + /* if ctn has no fingerprint, it will match any certificate */ + if (!ctn->fingerprint) { + map_type = ctn->map_type; + + /* MD5 */ + } else if (!strncmp(ctn->fingerprint, "01", 2)) { if (!digest_md5) { if (X509_digest(cert, EVP_md5(), buf, &buf_len) != 1) { ERR(NULL, "Calculating MD5 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); @@ -361,6 +347,8 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } + free(digest_md5); + digest_md5 = NULL; /* SHA-1 */ } else if (!strncmp(ctn->fingerprint, "02", 2)) { @@ -378,6 +366,8 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } + free(digest_sha1); + digest_sha1 = NULL; /* SHA-224 */ } else if (!strncmp(ctn->fingerprint, "03", 2)) { @@ -395,6 +385,8 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } + free(digest_sha224); + digest_sha224 = NULL; /* SHA-256 */ } else if (!strncmp(ctn->fingerprint, "04", 2)) { @@ -412,6 +404,8 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } + free(digest_sha256); + digest_sha256 = NULL; /* SHA-384 */ } else if (!strncmp(ctn->fingerprint, "05", 2)) { @@ -429,6 +423,8 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } + free(digest_sha384); + digest_sha384 = NULL; /* SHA-512 */ } else if (!strncmp(ctn->fingerprint, "06", 2)) { @@ -446,6 +442,8 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } + free(digest_sha512); + digest_sha512 = NULL; /* unknown */ } else { @@ -499,224 +497,201 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * return ret; } -#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0 - static int -nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) +nc_server_tls_check_crl(X509_STORE *crl_store, X509_STORE_CTX *x509_ctx, X509 *cert, + const X509_NAME *subject, const X509_NAME *issuer) { - X509_STORE_CTX *store_ctx; - X509_OBJECT *obj; - X509_NAME *subject; - X509_NAME *issuer; - X509 *cert; + int n, i, ret = 0; + X509_STORE_CTX *store_ctx = NULL; + X509_OBJECT *obj = NULL; X509_CRL *crl; X509_REVOKED *revoked; - - STACK_OF(X509) * cert_stack; EVP_PKEY *pubkey; - struct nc_session *session; - struct nc_server_tls_opts *opts; const ASN1_INTEGER *serial; - int i, n, rc, depth; - char *cp; const ASN1_TIME *last_update = NULL, *next_update = NULL; + char *cp; - /* get the thread session */ - session = pthread_getspecific(verify_key); - if (!session) { - ERRINT; - return 0; - } + store_ctx = X509_STORE_CTX_new(); + if (!store_ctx) { + ERRMEM; + ret = -1; + goto cleanup; + } + + /* init store context */ + ret = X509_STORE_CTX_init(store_ctx, crl_store, NULL, NULL); + if (!ret) { + ERR(NULL, "Initializing x509 store ctx failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = -1; + goto cleanup; + } + ret = 0; + + /* try to find a CRL entry that corresponds to the current certificate in question */ + obj = X509_STORE_CTX_get_obj_by_subject(store_ctx, X509_LU_CRL, subject); + crl = X509_OBJECT_get0_X509_CRL(obj); + X509_OBJECT_free(obj); + if (crl) { + /* found it */ + cp = X509_NAME_oneline(subject, NULL, 0); + VRB(NULL, "Cert verify CRL: issuer: %s.", cp); + OPENSSL_free(cp); + + last_update = X509_CRL_get0_lastUpdate(crl); + next_update = X509_CRL_get0_nextUpdate(crl); + cp = asn1time_to_str(last_update); + VRB(NULL, "Cert verify CRL: last update: %s.", cp); + free(cp); + cp = asn1time_to_str(next_update); + VRB(NULL, "Cert verify CRL: next update: %s.", cp); + free(cp); - opts = session->data; + /* verify the signature on this CRL */ + pubkey = X509_get0_pubkey(cert); + if (X509_CRL_verify(crl, pubkey) <= 0) { + ERR(NULL, "Cert verify CRL: invalid signature."); + X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); + ret = -1; + goto cleanup; + } - /* get the last certificate, that is the peer (client) certificate */ - if (!session->opts.server.client_cert) { - cert_stack = X509_STORE_CTX_get1_chain(x509_ctx); - session->opts.server.client_cert = sk_X509_value(cert_stack, 0); - X509_up_ref(session->opts.server.client_cert); - sk_X509_pop_free(cert_stack, X509_free); + /* check date of CRL to make sure it's not expired */ + if (!next_update) { + ERR(NULL, "Cert verify CRL: invalid nextUpdate field."); + X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); + ret = -1; + goto cleanup; + } + + if (X509_cmp_current_time(next_update) < 0) { + ERR(NULL, "Cert verify CRL: expired - revoking all certificates."); + X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED); + ret = -1; + goto cleanup; + } } - /* standard certificate verification failed, so a trusted client cert must match to continue */ - if (!preverify_ok) { - subject = X509_get_subject_name(session->opts.server.client_cert); - cert_stack = X509_STORE_CTX_get1_certs(x509_ctx, subject); - if (cert_stack) { - for (i = 0; i < sk_X509_num(cert_stack); ++i) { - if (cert_pubkey_match(session->opts.server.client_cert, sk_X509_value(cert_stack, i))) { - /* we are just overriding the failed standard certificate verification (preverify_ok == 0), - * this callback will be called again with the same current certificate and preverify_ok == 1 */ - VRB(NULL, "Cert verify: fail (%s), but the client certificate is trusted, continuing.", - X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx))); - X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); - sk_X509_pop_free(cert_stack, X509_free); - return 1; - } + /* try to retrieve a CRL corresponding to the _issuer_ of + * the current certificate in order to check for revocation */ + obj = X509_STORE_CTX_get_obj_by_subject(store_ctx, X509_LU_CRL, issuer); + crl = X509_OBJECT_get0_X509_CRL(obj); + if (crl) { + n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); + for (i = 0; i < n; i++) { + revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); + serial = X509_REVOKED_get0_serialNumber(revoked); + if (ASN1_INTEGER_cmp(serial, X509_get_serialNumber(cert)) == 0) { + cp = X509_NAME_oneline(issuer, NULL, 0); + ERR(NULL, "Cert verify CRL: certificate with serial %ld (0x%lX) revoked per CRL from issuer %s.", + serial, serial, cp); + OPENSSL_free(cp); + X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED); + ret = -1; + goto cleanup; } - sk_X509_pop_free(cert_stack, X509_free); } - - ERR(NULL, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx))); - return 0; } - /* print cert verify info */ - depth = X509_STORE_CTX_get_error_depth(x509_ctx); - VRB(NULL, "Cert verify: depth %d.", depth); - - cert = X509_STORE_CTX_get_current_cert(x509_ctx); - subject = X509_get_subject_name(cert); - issuer = X509_get_issuer_name(cert); - - cp = X509_NAME_oneline(subject, NULL, 0); - VRB(NULL, "Cert verify: subject: %s.", cp); - OPENSSL_free(cp); - cp = X509_NAME_oneline(issuer, NULL, 0); - VRB(NULL, "Cert verify: issuer: %s.", cp); - OPENSSL_free(cp); +cleanup: + X509_STORE_CTX_free(store_ctx); + X509_OBJECT_free(obj); + return ret; +} - /* check for revocation if set */ - if (opts->crl_store) { - /* try to retrieve a CRL corresponding to the _subject_ of - * the current certificate in order to verify it's integrity */ - store_ctx = X509_STORE_CTX_new(); - obj = X509_OBJECT_new(); - X509_STORE_CTX_init(store_ctx, opts->crl_store, NULL, NULL); - rc = X509_STORE_CTX_get_by_subject(store_ctx, X509_LU_CRL, subject, obj); - X509_STORE_CTX_free(store_ctx); - crl = X509_OBJECT_get0_X509_CRL(obj); - if ((rc > 0) && crl) { - cp = X509_NAME_oneline(subject, NULL, 0); - VRB(NULL, "Cert verify CRL: issuer: %s.", cp); - OPENSSL_free(cp); - - last_update = X509_CRL_get0_lastUpdate(crl); - next_update = X509_CRL_get0_nextUpdate(crl); - cp = asn1time_to_str(last_update); - VRB(NULL, "Cert verify CRL: last update: %s.", cp); - free(cp); - cp = asn1time_to_str(next_update); - VRB(NULL, "Cert verify CRL: next update: %s.", cp); - free(cp); - - /* verify the signature on this CRL */ - pubkey = X509_get_pubkey(cert); - if (X509_CRL_verify(crl, pubkey) <= 0) { - ERR(NULL, "Cert verify CRL: invalid signature."); - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); - X509_OBJECT_free(obj); - if (pubkey) { - EVP_PKEY_free(pubkey); - } - return 0; - } - if (pubkey) { - EVP_PKEY_free(pubkey); - } +static int +nc_server_tls_ts_ref_get_certs(const char *referenced_name, struct nc_certificate **certs, uint16_t *cert_count) +{ + uint16_t i; + struct nc_truststore *ts = &server_opts.truststore; - /* check date of CRL to make sure it's not expired */ - if (!next_update) { - ERR(NULL, "Cert verify CRL: invalid nextUpdate field."); - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); - X509_OBJECT_free(obj); - return 0; - } - if (X509_cmp_current_time(next_update) < 0) { - ERR(NULL, "Cert verify CRL: expired - revoking all certificates."); - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED); - X509_OBJECT_free(obj); - return 0; - } - X509_OBJECT_free(obj); - } + *certs = NULL; + *cert_count = 0; - /* try to retrieve a CRL corresponding to the _issuer_ of - * the current certificate in order to check for revocation */ - store_ctx = X509_STORE_CTX_new(); - obj = X509_OBJECT_new(); - X509_STORE_CTX_init(store_ctx, opts->crl_store, NULL, NULL); - rc = X509_STORE_CTX_get_by_subject(store_ctx, X509_LU_CRL, issuer, obj); - X509_STORE_CTX_free(store_ctx); - crl = X509_OBJECT_get0_X509_CRL(obj); - if ((rc > 0) && crl) { - /* check if the current certificate is revoked by this CRL */ - n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); - for (i = 0; i < n; i++) { - revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); - serial = X509_REVOKED_get0_serialNumber(revoked); - if (ASN1_INTEGER_cmp(serial, X509_get_serialNumber(cert)) == 0) { - cp = X509_NAME_oneline(issuer, NULL, 0); - ERR(NULL, "Cert verify CRL: certificate with serial %ld (0x%lX) revoked per CRL from issuer %s.", - serial, serial, cp); - OPENSSL_free(cp); - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED); - X509_OBJECT_free(obj); - return 0; - } - } - X509_OBJECT_free(obj); + /* lookup name */ + for (i = 0; i < ts->cert_bag_count; i++) { + if (!strcmp(referenced_name, ts->cert_bags[i].name)) { + break; } } - /* cert-to-name already successful */ - if (session->username) { - return 1; + if (i == ts->cert_bag_count) { + ERR(NULL, "Truststore entry \"%s\" not found.", referenced_name); + return -1; } - /* cert-to-name */ - rc = nc_tls_cert_to_name(session, opts->ctn, cert); - if (rc) { - if (rc == -1) { - /* fatal error */ - depth = 0; - } - /* rc == 1 is a normal CTN fail (no match found) */ - goto fail; - } + *certs = ts->cert_bags[i].certs; + *cert_count = ts->cert_bags[i].cert_count; + return 0; +} - VRB(NULL, "Cert verify CTN: new client username recognized as \"%s\".", session->username); +/* In case a CA chain verification failed an end-entity certificate must match. + * The meaning of local_or_referenced is that it states, which end-entity certificates to check + * (1 = current endpoint's, 2 = referenced endpoint's). + */ +static int +nc_server_tls_do_preverify(struct nc_session *session, X509_STORE_CTX *x509_ctx, int local_or_referenced) +{ + X509_STORE *store; + struct nc_cert_grouping *ee_certs; + int i, ret; + X509 *cert; + struct nc_certificate *certs; + uint16_t cert_count; - if (server_opts.user_verify_clb && !server_opts.user_verify_clb(session)) { - VRB(NULL, "Cert verify: user verify callback revoked authorization."); - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_APPLICATION_VERIFICATION); - return 0; + store = X509_STORE_CTX_get0_store(x509_ctx); + if (!store) { + ERR(session, "Error getting store from context (%s).", ERR_reason_error_string(ERR_get_error())); + return -1; } - return 1; + /* get the data from the store */ + ee_certs = X509_STORE_get_ex_data(store, local_or_referenced); + if (!ee_certs) { + ERR(session, "Error getting data from store (%s).", ERR_reason_error_string(ERR_get_error())); + return -1; + } -fail: - if (depth > 0) { - VRB(NULL, "Cert verify CTN: cert fail, cert-to-name will continue on the next cert in chain."); - return 1; + if (ee_certs->store == NC_STORE_LOCAL) { + /* local definition */ + certs = ee_certs->certs; + cert_count = ee_certs->cert_count; + } else { + /* truststore reference */ + if (nc_server_tls_ts_ref_get_certs(ee_certs->ts_ref, &certs, &cert_count)) { + ERR(NULL, "Error getting end-entity certificates from the truststore reference \"%s\".", ee_certs->ts_ref); + return -1; + } + } + + for (i = 0; i < cert_count; i++) { + cert = base64der_to_cert(certs[i].data); + ret = cert_pubkey_match(session->opts.server.client_cert, cert); + X509_free(cert); + if (ret) { + /* we are just overriding the failed standard certificate verification (preverify_ok == 0), + * this callback will be called again with the same current certificate and preverify_ok == 1 */ + VRB(session, "Cert verify: fail (%s), but the end-entity certificate is trusted, continuing.", + X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx))); + X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); + return 1; + } } - VRB(NULL, "Cert-to-name unsuccessful, dropping the new client."); - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_APPLICATION_VERIFICATION); return 0; } -#else - static int nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) { - X509_STORE_CTX store_ctx; - X509_OBJECT obj; X509_NAME *subject; X509_NAME *issuer; X509 *cert; - X509_CRL *crl; - X509_REVOKED *revoked; + char *cp; STACK_OF(X509) * cert_stack; - EVP_PKEY *pubkey; struct nc_session *session; struct nc_server_tls_opts *opts; - long serial; - int i, n, rc, depth; - char *cp; - ASN1_TIME *last_update = NULL, *next_update = NULL; + int rc, depth; /* get the thread session */ session = pthread_getspecific(verify_key); @@ -730,32 +705,33 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) /* get the last certificate, that is the peer (client) certificate */ if (!session->opts.server.client_cert) { cert_stack = X509_STORE_CTX_get1_chain(x509_ctx); - while ((cert = sk_X509_pop(cert_stack))) { - X509_free(session->opts.server.client_cert); - session->opts.server.client_cert = cert; - } + session->opts.server.client_cert = sk_X509_value(cert_stack, 0); + X509_up_ref(session->opts.server.client_cert); sk_X509_pop_free(cert_stack, X509_free); } - /* standard certificate verification failed, so a trusted client cert must match to continue */ + /* standard certificate verification failed, so an end-entity client cert must match to continue */ if (!preverify_ok) { - subject = X509_get_subject_name(session->opts.server.client_cert); - cert_stack = X509_STORE_get1_certs(x509_ctx, subject); - if (cert_stack) { - for (i = 0; i < sk_X509_num(cert_stack); ++i) { - if (cert_pubkey_match(session->opts.server.client_cert, sk_X509_value(cert_stack, i))) { - /* we are just overriding the failed standard certificate verification (preverify_ok == 0), - * this callback will be called again with the same current certificate and preverify_ok == 1 */ - VRB(session, "Cert verify: fail (%s), but the client certificate is trusted, continuing.", - X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx))); - X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); - sk_X509_pop_free(cert_stack, X509_free); - return 1; - } + /* check current endpoint's end-entity certs */ + rc = nc_server_tls_do_preverify(session, x509_ctx, 1); + if (rc == -1) { + return 0; + } else if (rc == 1) { + return 1; + } + + /* no match, continue */ + if (opts->endpt_client_ref) { + /* check referenced endpoint's end-entity certs */ + rc = nc_server_tls_do_preverify(session, x509_ctx, 2); + if (rc == -1) { + return 0; + } else if (rc == 1) { + return 1; } - sk_X509_pop_free(cert_stack, X509_free); } + /* no match, fail */ ERR(session, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx))); return 0; } @@ -775,84 +751,11 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) VRB(session, "Cert verify: issuer: %s.", cp); OPENSSL_free(cp); - /* check for revocation if set */ + /* check if the current certificate is revoked if CRL is set */ if (opts->crl_store) { - /* try to retrieve a CRL corresponding to the _subject_ of - * the current certificate in order to verify it's integrity */ - memset((char *)&obj, 0, sizeof(obj)); - X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL); - rc = X509_STORE_CTX_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj); - X509_STORE_CTX_cleanup(&store_ctx); - crl = obj.data.crl; - if ((rc > 0) && crl) { - cp = X509_NAME_oneline(subject, NULL, 0); - VRB(session, "Cert verify CRL: issuer: %s.", cp); - OPENSSL_free(cp); - - last_update = X509_CRL_get_lastUpdate(crl); - next_update = X509_CRL_get_nextUpdate(crl); - cp = asn1time_to_str(last_update); - VRB(session, "Cert verify CRL: last update: %s.", cp); - free(cp); - cp = asn1time_to_str(next_update); - VRB(session, "Cert verify CRL: next update: %s.", cp); - free(cp); - - /* verify the signature on this CRL */ - pubkey = X509_get_pubkey(cert); - if (X509_CRL_verify(crl, pubkey) <= 0) { - ERR(session, "Cert verify CRL: invalid signature."); - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); - X509_OBJECT_free_contents(&obj); - if (pubkey) { - EVP_PKEY_free(pubkey); - } - return 0; - } - if (pubkey) { - EVP_PKEY_free(pubkey); - } - - /* check date of CRL to make sure it's not expired */ - if (!next_update) { - ERR(session, "Cert verify CRL: invalid nextUpdate field."); - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); - X509_OBJECT_free_contents(&obj); - return 0; - } - if (X509_cmp_current_time(next_update) < 0) { - ERR(session, "Cert verify CRL: expired - revoking all certificates."); - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED); - X509_OBJECT_free_contents(&obj); - return 0; - } - X509_OBJECT_free_contents(&obj); - } - - /* try to retrieve a CRL corresponding to the _issuer_ of - * the current certificate in order to check for revocation */ - memset((char *)&obj, 0, sizeof(obj)); - X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL); - rc = X509_STORE_CTX_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj); - X509_STORE_CTX_cleanup(&store_ctx); - crl = obj.data.crl; - if ((rc > 0) && crl) { - /* check if the current certificate is revoked by this CRL */ - n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); - for (i = 0; i < n; i++) { - revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); - if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(cert)) == 0) { - serial = ASN1_INTEGER_get(revoked->serialNumber); - cp = X509_NAME_oneline(issuer, NULL, 0); - ERR(session, "Cert verify CRL: certificate with serial %ld (0x%lX) revoked per CRL from issuer %s.", - serial, serial, cp); - OPENSSL_free(cp); - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED); - X509_OBJECT_free_contents(&obj); - return 0; - } - } - X509_OBJECT_free_contents(&obj); + rc = nc_server_tls_check_crl(opts->crl_store, x509_ctx, cert, subject, issuer); + if (rc) { + return 0; } } @@ -863,13 +766,24 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) /* cert-to-name */ rc = nc_tls_cert_to_name(session, opts->ctn, cert); - if (rc) { - if (rc == -1) { - /* fatal error */ - depth = 0; - } - /* rc == 1 is a normal CTN fail (no match found) */ + if (rc == -1) { + /* fatal error */ + depth = 0; + goto fail; + } else if ((rc == 1) && !opts->endpt_client_ref) { + /* no match found and no referenced endpoint */ goto fail; + } else if ((rc == 1) && opts->endpt_client_ref) { + /* no match found, but has a referenced endpoint so try it */ + rc = nc_tls_cert_to_name(session, opts->endpt_client_ref->opts.tls->ctn, cert); + if (rc) { + if (rc == -1) { + /* fatal error */ + depth = 0; + } + /* rc == 1 is a normal CTN fail (no match found) */ + goto fail; + } } VRB(session, "Cert verify CTN: new client username recognized as \"%s\".", session->username); @@ -893,29 +807,51 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) return 0; } -#endif - static int -nc_server_tls_set_server_cert(const char *name, struct nc_server_tls_opts *opts) +nc_server_tls_get_ctn(uint32_t *id, char **fingerprint, NC_TLS_CTN_MAPTYPE *map_type, char **name, + struct nc_server_tls_opts *opts) { - if (!name) { - if (opts->server_cert) { - free(opts->server_cert); + struct nc_ctn *ctn; + int ret = -1; + + for (ctn = opts->ctn; ctn; ctn = ctn->next) { + if (id && *id && (*id != ctn->id)) { + continue; + } + if (fingerprint && *fingerprint && (!ctn->fingerprint || strcmp(*fingerprint, ctn->fingerprint))) { + continue; + } + if (map_type && *map_type && (!ctn->map_type || (*map_type != ctn->map_type))) { + continue; + } + if (name && *name && (!ctn->name || strcmp(*name, ctn->name))) { + continue; + } + + /* first match, good enough */ + if (id && !(*id)) { + *id = ctn->id; + } + if (fingerprint && !(*fingerprint) && ctn->fingerprint) { + *fingerprint = strdup(ctn->fingerprint); + } + if (map_type && !(*map_type) && ctn->map_type) { + *map_type = ctn->map_type; + } + if (name && !(*name) && ctn->name) { + *name = strdup(ctn->name); } - opts->server_cert = NULL; - return 0; - } - if (opts->server_cert) { - free(opts->server_cert); + ret = 0; + break; } - opts->server_cert = strdup(name); - return 0; + return ret; } API int -nc_server_tls_endpt_set_server_cert(const char *endpt_name, const char *name) +nc_server_tls_endpt_get_ctn(const char *endpt_name, uint32_t *id, char **fingerprint, NC_TLS_CTN_MAPTYPE *map_type, + char **name) { int ret; struct nc_endpt *endpt; @@ -927,7 +863,7 @@ nc_server_tls_endpt_set_server_cert(const char *endpt_name, const char *name) if (!endpt) { return -1; } - ret = nc_server_tls_set_server_cert(name, endpt->opts.tls); + ret = nc_server_tls_get_ctn(id, fingerprint, map_type, name, endpt->opts.tls); /* UNLOCK */ pthread_rwlock_unlock(&server_opts.config_lock); @@ -935,7 +871,8 @@ nc_server_tls_endpt_set_server_cert(const char *endpt_name, const char *name) } API int -nc_server_tls_ch_client_endpt_set_server_cert(const char *client_name, const char *endpt_name, const char *name) +nc_server_tls_ch_client_endpt_get_ctn(const char *client_name, const char *endpt_name, uint32_t *id, char **fingerprint, + NC_TLS_CTN_MAPTYPE *map_type, char **name) { int ret; struct nc_ch_client *client; @@ -947,7 +884,7 @@ nc_server_tls_ch_client_endpt_set_server_cert(const char *client_name, const cha return -1; } - ret = nc_server_tls_set_server_cert(name, endpt->opts.tls); + ret = nc_server_tls_get_ctn(id, fingerprint, map_type, name, endpt->opts.tls); /* UNLOCK */ nc_server_ch_client_unlock(client); @@ -955,886 +892,499 @@ nc_server_tls_ch_client_endpt_set_server_cert(const char *client_name, const cha return ret; } -API void -nc_server_tls_set_server_cert_clb(int (*cert_clb)(const char *name, void *user_data, char **cert_path, char **cert_data, - char **privkey_path, char **privkey_data, NC_SSH_KEY_TYPE *privkey_type), void *user_data, - void (*free_user_data)(void *user_data)) +API const X509 * +nc_session_get_client_cert(const struct nc_session *session) { - if (!cert_clb) { - ERRARG(NULL, "cert_clb"); - return; + if (!session || (session->side != NC_SERVER)) { + ERRARG(session, "session"); + return NULL; } - server_opts.server_cert_clb = cert_clb; - server_opts.server_cert_data = user_data; - server_opts.server_cert_data_free = free_user_data; + return session->opts.server.client_cert; } API void -nc_server_tls_set_server_cert_chain_clb(int (*cert_chain_clb)(const char *name, void *user_data, char ***cert_paths, - int *cert_path_count, char ***cert_data, int *cert_data_count), void *user_data, void (*free_user_data)(void *user_data)) +nc_server_tls_set_verify_clb(int (*verify_clb)(const struct nc_session *session)) { - if (!cert_chain_clb) { - ERRARG(NULL, "cert_chain_clb"); - return; - } + server_opts.user_verify_clb = verify_clb; +} - server_opts.server_cert_chain_clb = cert_chain_clb; - server_opts.server_cert_chain_data = user_data; - server_opts.server_cert_chain_data_free = free_user_data; +static void +nc_tls_make_verify_key(void) +{ + pthread_key_create(&verify_key, NULL); } static int -nc_server_tls_add_trusted_cert_list(const char *name, struct nc_server_tls_opts *opts) +nc_server_tls_ks_ref_get_cert_key(const char *referenced_key_name, const char *referenced_cert_name, + char **privkey_data, NC_PRIVKEY_FORMAT *privkey_type, char **cert_data) { - NC_CHECK_ARG_RET(NULL, name, -1); + uint16_t i, j; + struct nc_keystore *ks = &server_opts.keystore; - ++opts->trusted_cert_list_count; - opts->trusted_cert_lists = nc_realloc(opts->trusted_cert_lists, - opts->trusted_cert_list_count * sizeof *opts->trusted_cert_lists); - if (!opts->trusted_cert_lists) { - ERRMEM; + *privkey_data = NULL; + *cert_data = NULL; + + /* lookup name */ + for (i = 0; i < ks->asym_key_count; i++) { + if (!strcmp(referenced_key_name, ks->asym_keys[i].name)) { + break; + } + } + if (i == ks->asym_key_count) { + ERR(NULL, "Keystore entry \"%s\" not found.", referenced_key_name); + return -1; + } + + for (j = 0; j < ks->asym_keys[i].cert_count; j++) { + if (!strcmp(referenced_cert_name, ks->asym_keys[i].certs[i].name)) { + break; + } + } + if (j == ks->asym_keys[i].cert_count) { + ERR(NULL, "Keystore certificate entry \"%s\" associated with the key \"%s\" not found.", + referenced_cert_name, referenced_key_name); return -1; } - opts->trusted_cert_lists[opts->trusted_cert_list_count - 1] = strdup(name); + *privkey_data = ks->asym_keys[i].privkey_data; + *privkey_type = ks->asym_keys[i].privkey_type; + *cert_data = ks->asym_keys[i].certs[j].data; return 0; } -API int -nc_server_tls_endpt_add_trusted_cert_list(const char *endpt_name, const char *name) +static int +nc_tls_ctx_set_server_cert_key(SSL_CTX *tls_ctx, struct nc_server_tls_opts *opts) { - int ret; - struct nc_endpt *endpt; + char *privkey_data = NULL, *cert_data = NULL; + int ret = 0; + NC_PRIVKEY_FORMAT privkey_type; + X509 *cert = NULL; + EVP_PKEY *pkey = NULL; - NC_CHECK_ARG_RET(NULL, endpt_name, -1); + NC_CHECK_ARG_RET(NULL, tls_ctx, opts, -1); - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); - if (!endpt) { - return -1; + /* get data needed for setting the server cert */ + if (opts->store == NC_STORE_LOCAL) { + /* local definition */ + cert_data = opts->cert_data; + privkey_data = opts->privkey_data; + privkey_type = opts->privkey_type; + } else { + /* keystore */ + ret = nc_server_tls_ks_ref_get_cert_key(opts->key_ref, opts->cert_ref, &privkey_data, &privkey_type, &cert_data); + if (ret) { + ERR(NULL, "Getting server certificate from the keystore reference \"%s\" failed.", opts->key_ref); + return -1; + } } - ret = nc_server_tls_add_trusted_cert_list(name, endpt->opts.tls); - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.config_lock); - return ret; -} - -API int -nc_server_tls_ch_client_endpt_add_trusted_cert_list(const char *client_name, const char *endpt_name, const char *name) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_OPENSSL, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_tls_add_trusted_cert_list(name, endpt->opts.tls); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -API void -nc_server_tls_set_trusted_cert_list_clb(int (*cert_list_clb)(const char *name, void *user_data, char ***cert_paths, - int *cert_path_count, char ***cert_data, int *cert_data_count), - void *user_data, void (*free_user_data)(void *user_data)) -{ - if (!cert_list_clb) { - ERRARG(NULL, "cert_list_clb"); - return; - } - - server_opts.trusted_cert_list_clb = cert_list_clb; - server_opts.trusted_cert_list_data = user_data; - server_opts.trusted_cert_list_data_free = free_user_data; -} - -static int -nc_server_tls_del_trusted_cert_list(const char *name, struct nc_server_tls_opts *opts) -{ - uint16_t i; - - if (!name) { - for (i = 0; i < opts->trusted_cert_list_count; ++i) { - free(opts->trusted_cert_lists[i]); - } - free(opts->trusted_cert_lists); - opts->trusted_cert_lists = NULL; - opts->trusted_cert_list_count = 0; - return 0; - } else { - for (i = 0; i < opts->trusted_cert_list_count; ++i) { - if (!strcmp(opts->trusted_cert_lists[i], name)) { - free(opts->trusted_cert_lists[i]); - - --opts->trusted_cert_list_count; - if (i < opts->trusted_cert_list_count - 1) { - memmove(opts->trusted_cert_lists + i, opts->trusted_cert_lists + i + 1, - (opts->trusted_cert_list_count - i) * sizeof *opts->trusted_cert_lists); - } - return 0; - } - } - } - - ERR(NULL, "Certificate list \"%s\" not found.", name); - return -1; -} - -API int -nc_server_tls_endpt_del_trusted_cert_list(const char *endpt_name, const char *name) -{ - int ret; - struct nc_endpt *endpt; - - NC_CHECK_ARG_RET(NULL, endpt_name, -1); - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); - if (!endpt) { - return -1; - } - ret = nc_server_tls_del_trusted_cert_list(name, endpt->opts.tls); - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.config_lock); - - return ret; -} - -API int -nc_server_tls_ch_client_endpt_del_trusted_cert_list(const char *client_name, const char *endpt_name, const char *name) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_OPENSSL, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_tls_del_trusted_cert_list(name, endpt->opts.tls); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -static int -nc_server_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir, struct nc_server_tls_opts *opts) -{ - if (!ca_file && !ca_dir) { - ERRARG(NULL, "ca_file and ca_dir"); - return -1; - } - - if (ca_file) { - free(opts->trusted_ca_file); - opts->trusted_ca_file = strdup(ca_file); - } - - if (ca_dir) { - free(opts->trusted_ca_dir); - opts->trusted_ca_dir = strdup(ca_dir); - } - - return 0; -} - -API int -nc_server_tls_endpt_set_trusted_ca_paths(const char *endpt_name, const char *ca_file, const char *ca_dir) -{ - int ret; - struct nc_endpt *endpt; - - NC_CHECK_ARG_RET(NULL, endpt_name, -1); - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); - if (!endpt) { - return -1; - } - ret = nc_server_tls_set_trusted_ca_paths(ca_file, ca_dir, endpt->opts.tls); - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.config_lock); - - return ret; -} - -API int -nc_server_tls_ch_client_endpt_set_trusted_ca_paths(const char *client_name, const char *endpt_name, const char *ca_file, - const char *ca_dir) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_OPENSSL, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_tls_set_trusted_ca_paths(ca_file, ca_dir, endpt->opts.tls); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -static int -nc_server_tls_set_crl_paths(const char *crl_file, const char *crl_dir, struct nc_server_tls_opts *opts) -{ - X509_LOOKUP *lookup; - - if (!crl_file && !crl_dir) { - ERRARG(NULL, "crl_file and crl_dir"); - return -1; - } - - if (!opts->crl_store) { - opts->crl_store = X509_STORE_new(); - } - - if (crl_file) { - lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_file()); - if (!lookup) { - ERR(NULL, "Failed to add a lookup method."); - goto fail; - } - - if (X509_LOOKUP_load_file(lookup, crl_file, X509_FILETYPE_PEM) != 1) { - ERR(NULL, "Failed to add a revocation lookup file (%s).", ERR_reason_error_string(ERR_get_error())); - goto fail; - } - } - - if (crl_dir) { - lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_hash_dir()); - if (!lookup) { - ERR(NULL, "Failed to add a lookup method."); - goto fail; - } - - if (X509_LOOKUP_add_dir(lookup, crl_dir, X509_FILETYPE_PEM) != 1) { - ERR(NULL, "Failed to add a revocation lookup directory (%s).", ERR_reason_error_string(ERR_get_error())); - goto fail; - } - } - - return 0; - -fail: - return -1; -} - -API int -nc_server_tls_endpt_set_crl_paths(const char *endpt_name, const char *crl_file, const char *crl_dir) -{ - int ret; - struct nc_endpt *endpt; - - NC_CHECK_ARG_RET(NULL, endpt_name, -1); - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); - if (!endpt) { - return -1; - } - ret = nc_server_tls_set_crl_paths(crl_file, crl_dir, endpt->opts.tls); - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.config_lock); - - return ret; -} - -API int -nc_server_tls_ch_client_set_crl_paths(const char *client_name, const char *endpt_name, const char *crl_file, - const char *crl_dir) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_OPENSSL, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_tls_set_crl_paths(crl_file, crl_dir, endpt->opts.tls); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -static void -nc_server_tls_clear_crls(struct nc_server_tls_opts *opts) -{ - if (!opts->crl_store) { - return; - } - - X509_STORE_free(opts->crl_store); - opts->crl_store = NULL; -} - -API void -nc_server_tls_endpt_clear_crls(const char *endpt_name) -{ - struct nc_endpt *endpt; - - if (!endpt_name) { - ERRARG(NULL, "endpt_name"); - return; - } - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); - if (!endpt) { - return; - } - nc_server_tls_clear_crls(endpt->opts.tls); - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.config_lock); -} - -API void -nc_server_tls_ch_client_endpt_clear_crls(const char *client_name, const char *endpt_name) -{ - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_OPENSSL, &client); - if (!endpt) { - return; - } - - nc_server_tls_clear_crls(endpt->opts.tls); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); -} - -static int -nc_server_tls_add_ctn(uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, - struct nc_server_tls_opts *opts) -{ - struct nc_ctn *ctn, *new; - - if (!opts->ctn) { - /* the first item */ - opts->ctn = new = calloc(1, sizeof *new); - if (!new) { - ERRMEM; - return -1; - } - } else if (opts->ctn->id > id) { - /* insert at the beginning */ - new = calloc(1, sizeof *new); - if (!new) { - ERRMEM; - return -1; - } - new->next = opts->ctn; - opts->ctn = new; - } else { - for (ctn = opts->ctn; ctn->next && ctn->next->id <= id; ctn = ctn->next) {} - if (ctn->id == id) { - /* it exists already */ - new = ctn; - } else { - /* insert after ctn */ - new = calloc(1, sizeof *new); - if (!new) { - ERRMEM; - return -1; - } - new->next = ctn->next; - ctn->next = new; - } - } - - new->id = id; - if (fingerprint) { - free(new->fingerprint); - new->fingerprint = strdup(fingerprint); - } - if (map_type) { - new->map_type = map_type; - } - if (name) { - free(new->name); - new->name = strdup(name); - } - - return 0; -} - -API int -nc_server_tls_endpt_add_ctn(const char *endpt_name, uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, - const char *name) -{ - int ret; - struct nc_endpt *endpt; - - NC_CHECK_ARG_RET(NULL, endpt_name, -1); - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); - if (!endpt) { - return -1; - } - ret = nc_server_tls_add_ctn(id, fingerprint, map_type, name, endpt->opts.tls); - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.config_lock); - - return ret; -} - -API int -nc_server_tls_ch_client_endpt_add_ctn(const char *client_name, const char *endpt_name, uint32_t id, - const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_OPENSSL, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_tls_add_ctn(id, fingerprint, map_type, name, endpt->opts.tls); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -static int -nc_server_tls_del_ctn(int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, - struct nc_server_tls_opts *opts) -{ - struct nc_ctn *ctn, *next, *prev; - int ret = -1; - - if ((id < 0) && !fingerprint && !map_type && !name) { - ctn = opts->ctn; - while (ctn) { - free(ctn->fingerprint); - free(ctn->name); - - next = ctn->next; - free(ctn); - ctn = next; - - ret = 0; - } - opts->ctn = NULL; - } else { - prev = NULL; - ctn = opts->ctn; - while (ctn) { - if (((id < 0) || (ctn->id == id)) && - (!fingerprint || !strcmp(ctn->fingerprint, fingerprint)) && - (!map_type || (ctn->map_type == map_type)) && - (!name || (ctn->name && !strcmp(ctn->name, name)))) { - free(ctn->fingerprint); - free(ctn->name); - - if (prev) { - prev->next = ctn->next; - next = ctn->next; - } else { - opts->ctn = ctn->next; - next = ctn->next; - } - free(ctn); - ctn = next; - - ret = 0; - } else { - prev = ctn; - ctn = ctn->next; - } - } - } - - return ret; -} - -API int -nc_server_tls_endpt_del_ctn(const char *endpt_name, int64_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, - const char *name) -{ - int ret; - struct nc_endpt *endpt; - - NC_CHECK_ARG_RET(NULL, endpt_name, -1); - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); - if (!endpt) { - return -1; + /* load the cert */ + cert = base64der_to_cert(cert_data); + if (!cert) { + ERR(NULL, "Converting certificate data to certificate format failed."); + ret = -1; + goto cleanup; } - ret = nc_server_tls_del_ctn(id, fingerprint, map_type, name, endpt->opts.tls); - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.config_lock); - - return ret; -} -API int -nc_server_tls_ch_client_endpt_del_ctn(const char *client_name, const char *endpt_name, int64_t id, - const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_OPENSSL, &client); - if (!endpt) { - return -1; + /* set server cert */ + ret = SSL_CTX_use_certificate(tls_ctx, cert); + if (ret != 1) { + ERR(NULL, "Loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = -1; + goto cleanup; } - ret = nc_server_tls_del_ctn(id, fingerprint, map_type, name, endpt->opts.tls); + /* load the private key */ + pkey = base64der_to_privatekey(privkey_data, nc_privkey_format_to_str(privkey_type)); + if (!pkey) { + ERR(NULL, "Converting private key data to private key format failed."); + ret = -1; + goto cleanup; + } - /* UNLOCK */ - nc_server_ch_client_unlock(client); + /* set server key */ + ret = SSL_CTX_use_PrivateKey(tls_ctx, pkey); + if (ret != 1) { + ERR(NULL, "Loading the server private key failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = -1; + goto cleanup; + } + + ret = 0; +cleanup: + X509_free(cert); + EVP_PKEY_free(pkey); return ret; } static int -nc_server_tls_get_ctn(uint32_t *id, char **fingerprint, NC_TLS_CTN_MAPTYPE *map_type, char **name, - struct nc_server_tls_opts *opts) +tls_store_add_trusted_cert(X509_STORE *cert_store, const char *cert_data) { - struct nc_ctn *ctn; - int ret = -1; + X509 *cert; - for (ctn = opts->ctn; ctn; ctn = ctn->next) { - if (id && *id && (*id != ctn->id)) { - continue; - } - if (fingerprint && *fingerprint && (!ctn->fingerprint || strcmp(*fingerprint, ctn->fingerprint))) { - continue; - } - if (map_type && *map_type && (!ctn->map_type || (*map_type != ctn->map_type))) { - continue; - } - if (name && *name && (!ctn->name || strcmp(*name, ctn->name))) { - continue; - } + cert = base64der_to_cert(cert_data); - /* first match, good enough */ - if (id && !(*id)) { - *id = ctn->id; - } - if (fingerprint && !(*fingerprint) && ctn->fingerprint) { - *fingerprint = strdup(ctn->fingerprint); - } - if (map_type && !(*map_type) && ctn->map_type) { - *map_type = ctn->map_type; - } - if (name && !(*name) && ctn->name) { - *name = strdup(ctn->name); - } + if (!cert) { + ERR(NULL, "Loading a trusted certificate (data \"%s\") failed (%s).", cert_data, + ERR_reason_error_string(ERR_get_error())); + return -1; + } - ret = 0; - break; + /* add the trusted certificate */ + if (X509_STORE_add_cert(cert_store, cert) != 1) { + ERR(NULL, "Adding a trusted certificate failed (%s).", ERR_reason_error_string(ERR_get_error())); + X509_free(cert); + return -1; } + X509_free(cert); - return ret; + return 0; } -API int -nc_server_tls_endpt_get_ctn(const char *endpt_name, uint32_t *id, char **fingerprint, NC_TLS_CTN_MAPTYPE *map_type, - char **name) +static int +nc_tls_store_set_trusted_certs(X509_STORE *cert_store, struct nc_cert_grouping *ca_certs) { - int ret; - struct nc_endpt *endpt; + uint16_t i; + struct nc_certificate *certs; + uint16_t cert_count; - NC_CHECK_ARG_RET(NULL, endpt_name, -1); + if (ca_certs->store == NC_STORE_LOCAL) { + /* local definition */ + certs = ca_certs->certs; + cert_count = ca_certs->cert_count; + } else { + /* truststore */ + if (nc_server_tls_ts_ref_get_certs(ca_certs->ts_ref, &certs, &cert_count)) { + ERR(NULL, "Error getting certificate-authority certificates from the truststore reference \"%s\".", ca_certs->ts_ref); + return -1; + } + } - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); - if (!endpt) { - return -1; + for (i = 0; i < cert_count; i++) { + if (tls_store_add_trusted_cert(cert_store, certs[i].data)) { + return -1; + } } - ret = nc_server_tls_get_ctn(id, fingerprint, map_type, name, endpt->opts.tls); - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.config_lock); - return ret; + return 0; } -API int -nc_server_tls_ch_client_endpt_get_ctn(const char *client_name, const char *endpt_name, uint32_t *id, char **fingerprint, - NC_TLS_CTN_MAPTYPE *map_type, char **name) +static int +nc_server_tls_crl_path(struct nc_session *session, const char *crl_path, X509_STORE *store) { - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; + int ret = 0; + X509_CRL *crl = NULL; + FILE *f; - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_OPENSSL, &client); - if (!endpt) { + f = fopen(crl_path, "r"); + if (!f) { + ERR(session, "Unable to open CRL file \"%s\".", crl_path); return -1; } - ret = nc_server_tls_get_ctn(id, fingerprint, map_type, name, endpt->opts.tls); + /* try DER first */ + crl = d2i_X509_CRL_fp(f, NULL); + if (crl) { + /* success */ + goto ok; + } - /* UNLOCK */ - nc_server_ch_client_unlock(client); + /* DER failed, try PEM */ + rewind(f); + crl = PEM_read_X509_CRL(f, NULL, NULL, NULL); + if (!crl) { + ERR(session, "Reading CRL from file \"%s\" failed.", crl_path); + ret = -1; + goto cleanup; + } +ok: + ret = X509_STORE_add_crl(store, crl); + if (!ret) { + ERR(session, "Error adding CRL to store (%s).", ERR_reason_error_string(ERR_get_error())); + ret = -1; + goto cleanup; + } + /* ok */ + ret = 0; + +cleanup: + fclose(f); + X509_CRL_free(crl); return ret; } -API const X509 * -nc_session_get_client_cert(const struct nc_session *session) +static size_t +nc_server_tls_curl_cb(char *ptr, size_t size, size_t nmemb, void *userdata) { - if (!session || (session->side != NC_SERVER)) { - ERRARG(session, "session"); - return NULL; + struct nc_curl_data *data; + + size = nmemb; + + data = (struct nc_curl_data *)userdata; + + data->data = nc_realloc(data->data, data->size + size); + if (!data->data) { + ERRMEM; + return 0; } - return session->opts.server.client_cert; -} + memcpy(&data->data[data->size], ptr, size); + data->size += size; -API void -nc_server_tls_set_verify_clb(int (*verify_clb)(const struct nc_session *session)) -{ - server_opts.user_verify_clb = verify_clb; + return size; } -void -nc_server_tls_clear_opts(struct nc_server_tls_opts *opts) +static int +nc_server_tls_curl_init(struct nc_session *session, CURL **handle, struct nc_curl_data *data) { - free(opts->server_cert); - nc_server_tls_del_trusted_cert_list(NULL, opts); - free(opts->trusted_ca_file); - free(opts->trusted_ca_dir); - nc_server_tls_clear_crls(opts); - nc_server_tls_del_ctn(-1, NULL, 0, NULL, opts); -} + NC_CHECK_ARG_RET(session, handle, data, -1); -static void -nc_tls_make_verify_key(void) -{ - pthread_key_create(&verify_key, NULL); -} + *handle = NULL; -static X509 * -tls_load_cert(const char *cert_path, const char *cert_data) -{ - X509 *cert; + *handle = curl_easy_init(); + if (!*handle) { + ERR(session, "Initializing CURL failed."); + return -1; + } - if (cert_path) { - cert = pem_to_cert(cert_path); - } else { - cert = base64der_to_cert(cert_data); + if (curl_easy_setopt(*handle, CURLOPT_WRITEFUNCTION, nc_server_tls_curl_cb)) { + ERR(session, "Setting curl callback failed."); + return -1; } - if (!cert) { - if (cert_path) { - ERR(NULL, "Loading a trusted certificate (path \"%s\") failed (%s).", cert_path, - ERR_reason_error_string(ERR_get_error())); - } else { - ERR(NULL, "Loading a trusted certificate (data \"%s\") failed (%s).", cert_data, - ERR_reason_error_string(ERR_get_error())); - } + if (curl_easy_setopt(*handle, CURLOPT_WRITEDATA, data)) { + ERR(session, "Setting curl callback data failed."); + return -1; } - return cert; + + return 0; } static int -nc_tls_ctx_set_server_cert_chain(SSL_CTX *tls_ctx, const char *cert_name) +nc_server_tls_curl_fetch(struct nc_session *session, CURL *handle, const char *url) { - char **cert_paths = NULL, **cert_data = NULL; - int cert_path_count = 0, cert_data_count = 0, ret = 0, i = 0; - X509 *cert = NULL; + char err_buf[CURL_ERROR_SIZE]; - if (!server_opts.server_cert_chain_clb) { - /* This is optional, so return OK */ - return 0; + /* set uri */ + if (curl_easy_setopt(handle, CURLOPT_URL, url)) { + ERR(session, "Setting URI \"%s\" to download CRL from failed.", url); + return -1; } - if (server_opts.server_cert_chain_clb(cert_name, server_opts.server_cert_chain_data, &cert_paths, - &cert_path_count, &cert_data, &cert_data_count)) { - ERR(NULL, "Server certificate chain callback failed."); + /* set err buf */ + curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, err_buf); + + /* download */ + if (curl_easy_perform(handle)) { + ERR(session, "Downloading CRL from \"%s\" failed (%s).", url, err_buf); return -1; } - for (i = 0; i < cert_path_count; ++i) { - cert = tls_load_cert(cert_paths[i], NULL); - if (!cert || (SSL_CTX_add_extra_chain_cert(tls_ctx, cert) != 1)) { - ERR(NULL, "Loading the server certificate chain failed (%s).", ERR_reason_error_string(ERR_get_error())); - ret = -1; - goto cleanup; - } + return 0; +} + +static int +nc_server_tls_add_crl_to_store(struct nc_session *session, struct nc_curl_data *downloaded, X509_STORE *store) +{ + int ret = 0; + X509_CRL *crl = NULL; + BIO *bio = NULL; + + /* try DER first */ + crl = d2i_X509_CRL(NULL, (const unsigned char **) &downloaded->data, downloaded->size); + if (crl) { + /* it was DER */ + goto ok; } - for (i = 0; i < cert_data_count; ++i) { - cert = tls_load_cert(NULL, cert_data[i]); - if (!cert || (SSL_CTX_add_extra_chain_cert(tls_ctx, cert) != 1)) { - ERR(NULL, "Loading the server certificate chain failed (%s).", ERR_reason_error_string(ERR_get_error())); - ret = -1; - goto cleanup; - } + /* DER failed, try PEM next */ + bio = BIO_new_mem_buf(downloaded->data, downloaded->size); + if (!bio) { + ERR(session, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = -1; + goto cleanup; } -cleanup: - for (i = 0; i < cert_path_count; ++i) { - free(cert_paths[i]); + + /* try to parse PEM from the downloaded data */ + crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL); + if (!crl) { + ERR(session, "Reading downloaded CRL failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = -1; + goto cleanup; } - free(cert_paths); - for (i = 0; i < cert_data_count; ++i) { - free(cert_data[i]); + +ok: + /* we obtained the CRL, now add it to the CRL store */ + ret = X509_STORE_add_crl(store, crl); + if (!ret) { + ERR(session, "Error adding CRL to store (%s).", ERR_reason_error_string(ERR_get_error())); + ret = -1; + goto cleanup; } - free(cert_data); - /* cert is owned by the SSL_CTX */ + /* ok */ + ret = 0; +cleanup: + X509_CRL_free(crl); + BIO_free(bio); return ret; } static int -nc_tls_ctx_set_server_cert_key(SSL_CTX *tls_ctx, const char *cert_name) +nc_server_tls_crl_url(struct nc_session *session, const char *url, X509_STORE *store) { - char *cert_path = NULL, *cert_data = NULL, *privkey_path = NULL, *privkey_data = NULL; int ret = 0; - NC_SSH_KEY_TYPE privkey_type; - X509 *cert = NULL; - EVP_PKEY *pkey = NULL; + CURL *handle = NULL; + struct nc_curl_data downloaded = {0}; - if (!cert_name) { - ERR(NULL, "Server certificate not set."); - return -1; - } else if (!server_opts.server_cert_clb) { - ERR(NULL, "Callback for retrieving the server certificate is not set."); - return -1; + /* init curl */ + ret = nc_server_tls_curl_init(session, &handle, &downloaded); + if (ret) { + goto cleanup; } - if (server_opts.server_cert_clb(cert_name, server_opts.server_cert_data, &cert_path, &cert_data, &privkey_path, - &privkey_data, &privkey_type)) { - ERR(NULL, "Server certificate callback failed."); - return -1; - } + VRB(session, "Downloading CRL from \"%s\".", url); - /* load the certificate */ - if (cert_path) { - if (SSL_CTX_use_certificate_file(tls_ctx, cert_path, SSL_FILETYPE_PEM) != 1) { - ERR(NULL, "Loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error())); - ret = -1; - goto cleanup; - } - } else { - cert = base64der_to_cert(cert_data); - if (!cert || (SSL_CTX_use_certificate(tls_ctx, cert) != 1)) { - ERR(NULL, "Loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error())); - ret = -1; - goto cleanup; - } + /* download the CRL */ + ret = nc_server_tls_curl_fetch(session, handle, url); + if (ret) { + goto cleanup; } - /* load the private key */ - if (privkey_path) { - if (SSL_CTX_use_PrivateKey_file(tls_ctx, privkey_path, SSL_FILETYPE_PEM) != 1) { - ERR(NULL, "Loading the server private key failed (%s).", ERR_reason_error_string(ERR_get_error())); - ret = -1; - goto cleanup; - } - } else { - pkey = base64der_to_privatekey(privkey_data, nc_keytype2str(privkey_type)); - if (!pkey || (SSL_CTX_use_PrivateKey(tls_ctx, pkey) != 1)) { - ERR(NULL, "Loading the server private key failed (%s).", ERR_reason_error_string(ERR_get_error())); - ret = -1; - goto cleanup; - } + /* convert the downloaded data to CRL and add it to the store */ + ret = nc_server_tls_add_crl_to_store(session, &downloaded, store); + if (ret) { + goto cleanup; } - ret = nc_tls_ctx_set_server_cert_chain(tls_ctx, cert_name); - cleanup: - X509_free(cert); - EVP_PKEY_free(pkey); - free(cert_path); - free(cert_data); - free(privkey_path); - free(privkey_data); + curl_easy_cleanup(handle); return ret; } -static void -tls_store_add_trusted_cert(X509_STORE *cert_store, const char *cert_path, const char *cert_data) +static int +nc_server_tls_crl_cert_ext(struct nc_session *session, X509_STORE *cert_store, X509_STORE *crl_store) { - X509 *cert = tls_load_cert(cert_path, cert_data); + int ret = 0, i, j, k, gtype; + CURL *handle = NULL; + struct nc_curl_data downloaded = {0}; - if (!cert) { - return; - } + STACK_OF(X509_OBJECT) * objs; + X509_OBJECT *obj; + X509 *cert; - /* add the trusted certificate */ - if (X509_STORE_add_cert(cert_store, cert) != 1) { - ERR(NULL, "Adding a trusted certificate failed (%s).", ERR_reason_error_string(ERR_get_error())); - X509_free(cert); - return; + STACK_OF(DIST_POINT) * dist_points; + DIST_POINT *dist_point; + GENERAL_NAMES *general_names; + GENERAL_NAME *general_name; + ASN1_STRING *asn_string_uri; + const char *crl_distpoint_uri; + + /* init curl */ + ret = nc_server_tls_curl_init(session, &handle, &downloaded); + if (ret) { + goto cleanup; + } + + /* treat all entries in the cert_store as X509_OBJECTs */ + objs = X509_STORE_get0_objects(cert_store); + if (!objs) { + ERR(session, "Getting certificates from store failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = -1; + goto cleanup; + } + + /* iterate over all the CAs */ + for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { + obj = sk_X509_OBJECT_value(objs, i); + cert = X509_OBJECT_get0_X509(obj); + if (!cert) { + /* the object on this index was not a certificate */ + continue; + } + + /* get all the distribution points for this CA */ + dist_points = X509_get_ext_d2i(cert, NID_crl_distribution_points, NULL, NULL); + + /* iterate over all the dist points (there can be multiple for a single cert) */ + for (j = 0; j < sk_DIST_POINT_num(dist_points); j++) { + dist_point = sk_DIST_POINT_value(dist_points, j); + if (!dist_point) { + continue; + } + general_names = dist_point->distpoint->name.fullname; + + /* iterate over all the GeneralesNames in the distribution point */ + for (k = 0; k < sk_GENERAL_NAME_num(general_names); k++) { + general_name = sk_GENERAL_NAME_value(general_names, k); + asn_string_uri = GENERAL_NAME_get0_value(general_name, >ype); + + /* check if the general name is a URI and has a valid length */ + if ((gtype != GEN_URI) || (ASN1_STRING_length(asn_string_uri) <= 6)) { + continue; + } + + crl_distpoint_uri = (const char *) ASN1_STRING_get0_data(asn_string_uri); + + VRB(session, "Downloading CRL from \"%s\".", crl_distpoint_uri); + + /* download the CRL */ + ret = nc_server_tls_curl_fetch(session, handle, crl_distpoint_uri); + if (ret) { + /* failed to download the CRL from this entry, try th next */ + continue; + } + + /* convert the downloaded data to CRL and add it to the store */ + ret = nc_server_tls_add_crl_to_store(session, &downloaded, crl_store); + if (ret) { + goto cleanup; + } + + /* the CRL was downloaded, no need to download it again using different protocol */ + break; + } + } } - X509_free(cert); + +cleanup: + curl_easy_cleanup(handle); + return ret; } static int -nc_tls_store_set_trusted_certs(X509_STORE *cert_store, char **trusted_cert_lists, uint16_t trusted_cert_list_count) +nc_tls_store_set_crl(struct nc_session *session, struct nc_server_tls_opts *opts, X509_STORE *store) { - uint16_t i; - int j; - char **cert_paths, **cert_data; - int cert_path_count, cert_data_count; - - if (!server_opts.trusted_cert_list_clb) { - ERR(NULL, "Callback for retrieving trusted certificate lists is not set."); - return -1; + if (!opts->crl_store) { + /* first call on this endpoint */ + opts->crl_store = X509_STORE_new(); + if (!opts->crl_store) { + ERRMEM; + goto fail; + } } - for (i = 0; i < trusted_cert_list_count; ++i) { - cert_paths = cert_data = NULL; - cert_path_count = cert_data_count = 0; - if (server_opts.trusted_cert_list_clb(trusted_cert_lists[i], server_opts.trusted_cert_list_data, - &cert_paths, &cert_path_count, &cert_data, &cert_data_count)) { - ERR(NULL, "Trusted certificate list callback for \"%s\" failed.", trusted_cert_lists[i]); - return -1; + if (opts->crl_path) { + if (nc_server_tls_crl_path(session, opts->crl_path, opts->crl_store)) { + goto fail; } - - for (j = 0; j < cert_path_count; ++j) { - tls_store_add_trusted_cert(cert_store, cert_paths[j], NULL); - free(cert_paths[j]); + } else if (opts->crl_url) { + if (nc_server_tls_crl_url(session, opts->crl_url, opts->crl_store)) { + goto fail; } - free(cert_paths); - - for (j = 0; j < cert_data_count; ++j) { - tls_store_add_trusted_cert(cert_store, NULL, cert_data[j]); - free(cert_data[j]); + } else { + if (nc_server_tls_crl_cert_ext(session, store, opts->crl_store)) { + goto fail; } - free(cert_data); } return 0; + +fail: + return -1; } static int @@ -1872,62 +1422,67 @@ nc_server_tls_accept_check(int accept_ret, struct nc_session *session) } int -nc_accept_tls_session(struct nc_session *session, int sock, int timeout) +nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opts, int sock, int timeout) { X509_STORE *cert_store; SSL_CTX *tls_ctx; - X509_LOOKUP *lookup; - struct nc_server_tls_opts *opts; int ret; struct timespec ts_timeout; - opts = session->data; - /* SSL_CTX */ -#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0 tls_ctx = SSL_CTX_new(TLS_server_method()); -#else - tls_ctx = SSL_CTX_new(TLSv1_2_server_method()); -#endif + if (!tls_ctx) { ERR(session, "Failed to create TLS context."); goto error; } + SSL_CTX_set_verify(tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify); - if (nc_tls_ctx_set_server_cert_key(tls_ctx, opts->server_cert)) { + if (nc_tls_ctx_set_server_cert_key(tls_ctx, opts)) { goto error; } /* X509_STORE, managed (freed) with the context */ cert_store = X509_STORE_new(); - SSL_CTX_set_cert_store(tls_ctx, cert_store); + if (!cert_store) { + ERR(session, "Creating certificate store failed (%s).", ERR_reason_error_string(ERR_get_error())); + goto error; + } - if (nc_tls_store_set_trusted_certs(cert_store, opts->trusted_cert_lists, opts->trusted_cert_list_count)) { + /* set end-entity certs as cert store data, retrieve them if verification fails later */ + ret = X509_STORE_set_ex_data(cert_store, 1, &opts->ee_certs); + if (!ret) { + ERR(session, "Setting certificate store data failed (%s).", ERR_reason_error_string(ERR_get_error())); goto error; } - if (opts->trusted_ca_file) { - lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_file()); - if (!lookup) { - ERR(session, "Failed to add a lookup method."); + /* do the same for referenced endpoint's end entity certs */ + if (opts->endpt_client_ref) { + ret = X509_STORE_set_ex_data(cert_store, 2, &opts->endpt_client_ref->opts.tls->ee_certs); + if (!ret) { + ERR(session, "Setting certificate store data failed (%s).", ERR_reason_error_string(ERR_get_error())); goto error; } + } - if (X509_LOOKUP_load_file(lookup, opts->trusted_ca_file, X509_FILETYPE_PEM) != 1) { - ERR(session, "Failed to add a trusted cert file (%s).", ERR_reason_error_string(ERR_get_error())); - goto error; - } + /* set store to the context */ + SSL_CTX_set_cert_store(tls_ctx, cert_store); + + /* set certificate authority certs */ + if (nc_tls_store_set_trusted_certs(cert_store, &opts->ca_certs)) { + goto error; } - if (opts->trusted_ca_dir) { - lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_hash_dir()); - if (!lookup) { - ERR(session, "Failed to add a lookup method."); + /* set referenced endpoint's CA certs if set */ + if (opts->endpt_client_ref) { + if (nc_tls_store_set_trusted_certs(cert_store, &opts->endpt_client_ref->opts.tls->ca_certs)) { goto error; } + } - if (X509_LOOKUP_add_dir(lookup, opts->trusted_ca_dir, X509_FILETYPE_PEM) != 1) { - ERR(session, "Failed to add a trusted cert directory (%s).", ERR_reason_error_string(ERR_get_error())); + /* set Certificate Revocation List if configured */ + if (opts->crl_path || opts->crl_url || opts->crl_cert_ext) { + if (nc_tls_store_set_crl(session, opts, cert_store)) { goto error; } } @@ -1944,6 +1499,30 @@ nc_accept_tls_session(struct nc_session *session, int sock, int timeout) goto error; } + /* set TLS versions for the current SSL session */ + if (opts->tls_versions) { + if (!(opts->tls_versions & NC_TLS_VERSION_10)) { + SSL_set_options(session->ti.tls, SSL_OP_NO_TLSv1); + } + if (!(opts->tls_versions & NC_TLS_VERSION_11)) { + SSL_set_options(session->ti.tls, SSL_OP_NO_TLSv1_1); + } + if (!(opts->tls_versions & NC_TLS_VERSION_12)) { + SSL_set_options(session->ti.tls, SSL_OP_NO_TLSv1_2); + } + if (!(opts->tls_versions & NC_TLS_VERSION_13)) { + SSL_set_options(session->ti.tls, SSL_OP_NO_TLSv1_3); + } + } + + /* set TLS cipher suites */ + if (opts->ciphers) { + /* set for TLS1.2 and lower */ + SSL_set_cipher_list(session->ti.tls, opts->ciphers); + /* set for TLS1.3 */ + SSL_set_ciphersuites(session->ti.tls, opts->ciphers); + } + SSL_set_fd(session->ti.tls, sock); sock = -1; SSL_set_mode(session->ti.tls, SSL_MODE_AUTO_RETRY); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 68aee07b..24d769c2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,7 @@ endif() # list of all the tests in each directory #set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages) -set(tests test_two_channels test_keystore test_unix_socket test_config_new test_truststore test_ec test_ed25519 test_replace test_endpt_share_clients) +set(tests test_unix_socket) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) @@ -37,15 +37,12 @@ foreach(mock_func IN LISTS ${test}_mock_funcs) endforeach() #append tests depending on SSH/TLS -if(ENABLE_SSH OR ENABLE_TLS) - #list(APPEND tests test_server_thread) - if(ENABLE_SSH) - list(APPEND client_tests test_client_ssh) - endif() - - if(ENABLE_TLS) - list(APPEND client_tests test_client_tls) - endif() +if(ENABLE_SSH) + list(APPEND tests test_two_channels test_keystore test_config_new test_truststore test_ec test_ed25519 test_replace test_endpt_share_clients) +endif() + +if(ENABLE_TLS) + list(APPEND tests test_tls) endif() foreach(src IN LISTS libsrc) diff --git a/tests/test_config_new.c b/tests/test_config_new.c index b82c6f20..0289ddc8 100644 --- a/tests/test_config_new.c +++ b/tests/test_config_new.c @@ -152,11 +152,11 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new hostkey data */ - ret = nc_server_config_new_ssh_hostkey(TESTS_DIR "/data/server.key", NULL, ctx, "endpt", "hostkey", &tree); + ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/server.key", NULL, &tree); assert_int_equal(ret, 0); /* create new address and port data */ - ret = nc_server_config_new_ssh_address_port("127.0.0.1", "10005", ctx, "endpt", &tree); + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", "10005", &tree); assert_int_equal(ret, 0); /* create the host-key algorithms data */ @@ -164,7 +164,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create the client authentication data, password only */ - ret = nc_server_config_new_ssh_client_auth_password("testpassword123", ctx, "endpt", "client", &tree); + ret = nc_server_config_new_ssh_client_auth_password(ctx, "endpt", "client", "testpassword123", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_ec.c b/tests/test_ec.c index ad95a4e8..95f82ace 100644 --- a/tests/test_ec.c +++ b/tests/test_ec.c @@ -215,19 +215,19 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_hostkey(TESTS_DIR "/data/key_ecdsa", NULL, ctx, "endpt", "hostkey", &tree); + ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_address_port("127.0.0.1", "10009", ctx, "endpt", &tree); + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa256.pub", ctx, "endpt", "test_ec256", "pubkey", &tree); + ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_ec256", "pubkey", TESTS_DIR "/data/id_ecdsa256.pub", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa384.pub", ctx, "endpt", "test_ec384", "pubkey", &tree); + ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_ec384", "pubkey", TESTS_DIR "/data/id_ecdsa384.pub", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(TESTS_DIR "/data/id_ecdsa521.pub", ctx, "endpt", "test_ec521", "pubkey", &tree); + ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_ec521", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_ed25519.c b/tests/test_ed25519.c index 3a84f22b..7b27d7f9 100644 --- a/tests/test_ed25519.c +++ b/tests/test_ed25519.c @@ -152,13 +152,13 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_hostkey(TESTS_DIR "/data/server.key", NULL, ctx, "endpt", "hostkey", &tree); + ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/server.key", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_address_port("127.0.0.1", "10009", ctx, "endpt", &tree); + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(TESTS_DIR "/data/id_ed25519.pub", ctx, "endpt", "test_ed25519", "pubkey", &tree); + ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_ed25519", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_tls.c b/tests/test_tls.c new file mode 100644 index 00000000..66930162 --- /dev/null +++ b/tests/test_tls.c @@ -0,0 +1,207 @@ +/** + * @file test_tls.c + * @author Roman Janota + * @brief libnetconf2 TLS authentication test + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 + +struct ly_ctx *ctx; + +struct test_state { + pthread_barrier_t barrier; +}; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + (void) arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_thread_destroy(); + return NULL; +} + +static void * +client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set client cert */ + ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key"); + assert_int_equal(ret, 0); + + /* set client ca */ + ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_tls("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + nc_thread_destroy(); + return NULL; +} + +static void +test_nc_tls(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* create new address and port data */ + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", "10005", &tree); + assert_int_equal(ret, 0); + + /* create new server certificate data */ + ret = nc_server_config_new_tls_server_certificate(ctx, "endpt", NULL, TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &tree); + assert_int_equal(ret, 0); + + /* create new end entity client cert data */ + ret = nc_server_config_new_tls_client_certificate(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); + assert_int_equal(ret, 0); + + /* create new client ca data */ + ret = nc_server_config_new_tls_client_ca(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_tls_ctn(ctx, "endpt", 1, + "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", + NC_TLS_CTN_SPECIFIED, "client", &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + /* initialize client */ + nc_client_init(); + + ret = nc_server_init(); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_tls, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/test_unix_socket.c b/tests/test_unix_socket.c index deed6f96..ec48496e 100644 --- a/tests/test_unix_socket.c +++ b/tests/test_unix_socket.c @@ -83,9 +83,13 @@ server_thread(void *arg) static void * client_thread(void *arg) { + int ret = 0; struct nc_session *session = NULL; struct test_state *state = arg; + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + pthread_barrier_wait(&state->barrier); session = nc_connect_unix("/tmp/nc2_test_unix_sock", NULL); assert_non_null(session); From 1ff3cf52ee92121314520870d2e59c74de648029 Mon Sep 17 00:00:00 2001 From: roman Date: Tue, 6 Jun 2023 10:00:26 +0200 Subject: [PATCH 031/134] libnetconf2 UPDATE merge SSH and TLS req into one In this commit I made the changes that if you want to use TLS, you have to have both OpenSSL and libssh installed and viceversa. Set the minimum required OpenSSL version to 3.0 and 0.9.5 for libssh. --- CMakeLists.txt | 45 ++--- examples/client.c | 2 - nc_client.h.in | 5 +- nc_server.h.in | 5 +- src/config_new.c | 41 ++--- src/config_new.h | 8 +- src/io.c | 36 ++-- src/log.c | 8 +- src/log.h | 4 +- src/server_config.c | 251 +++++++++------------------- src/server_config.h | 5 +- src/server_config_p.h | 24 +-- src/session.c | 271 ++----------------------------- src/session.h | 29 +--- src/session_client.c | 51 ++---- src/session_client.h | 20 +-- src/session_client_ch.h | 16 +- src/session_client_ssh.c | 50 +----- src/session_client_tls.c | 115 ------------- src/session_p.h | 140 ++++++++-------- src/session_server.h | 18 +- src/session_server_ch.h | 12 +- tests/CMakeLists.txt | 13 +- tests/client/test_client_tls.c | 2 - tests/test_auth.c | 8 - tests/test_client_thread.c | 2 - tests/test_config_new.c | 5 - tests/test_ec.c | 5 - tests/test_ed25519.c | 5 - tests/test_endpt_share_clients.c | 5 - tests/test_init_destroy_client.c | 2 - tests/test_keystore.c | 5 - tests/test_replace.c | 5 - tests/test_server_thread.c | 3 - tests/test_tls.c | 5 - tests/test_truststore.c | 5 - tests/test_two_channels.c | 5 - tests/test_unix_socket.c | 5 - 38 files changed, 275 insertions(+), 961 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c08b017..98b4ad88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,9 +90,7 @@ else() endif() option(ENABLE_EXAMPLES "Build examples" ON) option(ENABLE_COVERAGE "Build code coverage report from tests" OFF) -option(ENABLE_SSH "Enable NETCONF over SSH support (via libssh)" ON) -option(ENABLE_TLS "Enable NETCONF over TLS support (via OpenSSL)" ON) -# option(ENABLE_SSH_TLS "Enable NETCONF over SSH and TLS support (via libssh and OpenSSL)" ON) +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) set(READ_INACTIVE_TIMEOUT 20 CACHE STRING "Maximum number of seconds waiting for new data once some data have arrived") set(READ_ACTIVE_TIMEOUT 300 CACHE STRING "Maximum number of seconds for receiving a full message") @@ -114,24 +112,19 @@ set(libsrc src/session_client.c src/session_server.c src/server_config.c - src/server_config_ks.c - src/server_config_ts.c src/config_new.c) -if(ENABLE_SSH) +if(ENABLE_SSH_TLS) list(APPEND libsrc src/session_client_ssh.c src/session_server_ssh.c - src/config_new_ssh.c) - set(SSH_MACRO "#ifndef NC_ENABLED_SSH\n#define NC_ENABLED_SSH\n#endif") -endif() - -if(ENABLE_TLS) - list(APPEND libsrc + src/config_new_ssh.c src/session_client_tls.c src/session_server_tls.c - src/config_new_tls.c) - set(TLS_MACRO "#ifndef NC_ENABLED_TLS\n#define NC_ENABLED_TLS\n#endif") + src/config_new_tls.c + src/server_config_ks.c + src/server_config_ts.c) + set(SSH_TLS_MACRO "#ifndef NC_ENABLED_SSH_TLS\n#define NC_ENABLED_SSH_TLS\n#endif") endif() set(headers @@ -175,7 +168,7 @@ set(format_sources # # checks # -if(ENABLE_DNSSEC AND NOT ENABLE_SSH) +if(ENABLE_DNSSEC AND NOT ENABLE_SSH_TLS) message(WARNING "DNSSEC SSHFP retrieval cannot be used without SSH support.") set(ENABLE_DNSSEC OFF) endif() @@ -234,26 +227,17 @@ target_link_libraries(netconf2 ${CMAKE_THREAD_LIBS_INIT}) set(CMAKE_REQUIRED_LIBRARIES pthread) check_function_exists(pthread_rwlockattr_setkind_np HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) -# dependencies - openssl -if(ENABLE_TLS OR ENABLE_DNSSEC OR ENABLE_SSH) +if(ENABLE_SSH_TLS) + # dependencies - openssl find_package(OpenSSL 3.0.0 REQUIRED) - if(ENABLE_TLS) - message(STATUS "OpenSSL found, required for TLS") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_ENABLED_TLS") - endif() - target_link_libraries(netconf2 ${OPENSSL_LIBRARIES}) include_directories(${OPENSSL_INCLUDE_DIR}) -endif() -# dependencies - libssh -if(ENABLE_SSH) + # dependencies - libssh find_package(LibSSH 0.9.5 REQUIRED) - target_link_libraries(netconf2 ${LIBSSH_LIBRARIES}) list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBSSH_LIBRARIES}) include_directories(${LIBSSH_INCLUDE_DIRS}) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_ENABLED_SSH") # crypt if(${CMAKE_SYSTEM_NAME} MATCHES "QNX") @@ -282,6 +266,9 @@ if(ENABLE_SSH) else() message(WARNING "LibPAM not found, PAM-based keyboard-interactive SSH server authentication method is disabled") endif() + + # set compiler flag + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_ENABLED_SSH_TLS") endif() # dependencies - libval @@ -347,8 +334,8 @@ endif() # examples if(ENABLE_EXAMPLES) - if(NOT ENABLE_SSH) - message(WARNING "Examples will not be compiled because SSH is disabled.") + if(NOT ENABLE_SSH_TLS) + message(WARNING "Examples will not be compiled because SSH and TLS are disabled.") else() add_subdirectory(examples) endif() diff --git a/examples/client.c b/examples/client.c index 88c38ff8..65f26422 100644 --- a/examples/client.c +++ b/examples/client.c @@ -149,8 +149,6 @@ main(int argc, char **argv) goto cleanup; } - nc_client_init(); - /* set the path to search for schemas */ nc_client_set_schema_searchpath(MODULES_DIR); diff --git a/nc_client.h.in b/nc_client.h.in index 86664842..32a24abc 100644 --- a/nc_client.h.in +++ b/nc_client.h.in @@ -16,13 +16,12 @@ #ifndef NC_CLIENT_H_ #define NC_CLIENT_H_ -@SSH_MACRO@ -@TLS_MACRO@ - #ifdef __cplusplus extern "C" { #endif +#cmakedefine SSH_TLS_MACRO + #include #include #include diff --git a/nc_server.h.in b/nc_server.h.in index c1f4bdc7..52176620 100644 --- a/nc_server.h.in +++ b/nc_server.h.in @@ -16,13 +16,12 @@ #ifndef NC_SERVER_H_ #define NC_SERVER_H_ -@SSH_MACRO@ -@TLS_MACRO@ - #ifdef __cplusplus extern "C" { #endif +#cmakedefine SSH_TLS_MACRO + #include #include #include diff --git a/src/config_new.c b/src/config_new.c index 4a20fe59..b727538a 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -15,15 +15,17 @@ #define _GNU_SOURCE +#include #include #include #include +#ifdef NC_ENABLED_SSH_TLS #include -#include #include #include #include +#endif /* NC_ENABLED_SSH_TLS */ #include "compat.h" #include "config_new.h" @@ -47,6 +49,8 @@ nc_config_new_check_add_operation(const struct ly_ctx *ctx, struct lyd_node *top return 0; } +#ifdef NC_ENABLED_SSH_TLS + const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT format) { @@ -272,8 +276,6 @@ nc_server_config_new_read_pubkey_openssl(FILE *f, char **pubkey) return ret; } -#ifdef NC_ENABLED_SSH - static int nc_server_config_new_read_pubkey_libssh(const char *pubkey_path, char **pubkey) { @@ -295,8 +297,6 @@ nc_server_config_new_read_pubkey_libssh(const char *pubkey_path, char **pubkey) return ret; } -#endif /* NC_ENABLED_SSH */ - int nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_PUBKEY_FORMAT *pubkey_type) { @@ -332,13 +332,11 @@ nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_PUBKE ret = nc_server_config_new_read_ssh2_pubkey(f, pubkey); *pubkey_type = NC_PUBKEY_FORMAT_SSH2; } -#ifdef NC_ENABLED_SSH else { /* it's probably OpenSSH public key */ ret = nc_server_config_new_read_pubkey_libssh(pubkey_path, pubkey); *pubkey_type = NC_PUBKEY_FORMAT_SSH2; } -#endif /* NC_ENABLED_SSH */ if (ret) { ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path); @@ -490,13 +488,11 @@ static int nc_server_config_new_privkey_to_pubkey(EVP_PKEY *priv_pkey, const ssh_key priv_sshkey, NC_PRIVKEY_FORMAT privkey_type, char **pubkey, NC_PUBKEY_FORMAT *pubkey_type) { switch (privkey_type) { -#ifdef NC_ENABLED_SSH case NC_PRIVKEY_FORMAT_RSA: case NC_PRIVKEY_FORMAT_EC: case NC_PRIVKEY_FORMAT_OPENSSH: *pubkey_type = NC_PUBKEY_FORMAT_SSH2; return nc_server_config_new_privkey_to_pubkey_libssh(priv_sshkey, pubkey); -#endif /* NC_ENABLED_SSH */ case NC_PRIVKEY_FORMAT_X509: *pubkey_type = NC_PUBKEY_FORMAT_X509; return nc_server_config_new_privkey_to_pubkey_openssl(priv_pkey, pubkey); @@ -507,8 +503,6 @@ nc_server_config_new_privkey_to_pubkey(EVP_PKEY *priv_pkey, const ssh_key priv_s return 1; } -#ifdef NC_ENABLED_SSH - static int nc_server_config_new_get_privkey_libssh(const char *privkey_path, char **privkey, ssh_key *priv_sshkey) { @@ -530,8 +524,6 @@ nc_server_config_new_get_privkey_libssh(const char *privkey_path, char **privkey return ret; } -#endif /* NC_ENABLED_SSH */ - int nc_server_config_new_get_keys(const char *privkey_path, const char *pubkey_path, char **privkey, char **pubkey, NC_PRIVKEY_FORMAT *privkey_type, NC_PUBKEY_FORMAT *pubkey_type) @@ -567,9 +559,7 @@ nc_server_config_new_get_keys(const char *privkey_path, const char *pubkey_path, /* it's PKCS8 (X.509) private key */ *privkey_type = NC_PRIVKEY_FORMAT_X509; ret = nc_server_config_new_get_privkey_openssl(f_privkey, privkey, &priv_pkey); - } -#ifdef NC_ENABLED_SSH - else if (!strncmp(header, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) { + } else if (!strncmp(header, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) { /* it's OpenSSH private key */ *privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; ret = nc_server_config_new_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); @@ -581,9 +571,7 @@ nc_server_config_new_get_keys(const char *privkey_path, const char *pubkey_path, /* it's EC privkey in SEC1 format */ *privkey_type = NC_PRIVKEY_FORMAT_EC; ret = nc_server_config_new_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); - } -#endif /* NC_ENABLED_SSH */ - else { + } else { ERR(NULL, "Private key format not supported."); ret = 1; goto cleanup; @@ -628,18 +616,17 @@ nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_na NC_CHECK_ARG_RET(NULL, address, port, ctx, endpt_name, config, 1); /* prepare path for instertion of leaves later */ -#ifdef NC_ENABLED_SSH if (transport == NC_TI_LIBSSH) { asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/tcp-server-parameters", endpt_name); - } -#endif -#ifdef NC_ENABLED_TLS - if (transport == NC_TI_OPENSSL) { + } else if (transport == NC_TI_OPENSSL) { asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tcp-server-parameters", endpt_name); + } else { + ERR(NULL, "Transport not supported."); + ret = 1; + goto cleanup; } -#endif if (!tree_path) { - ERR(NULL, "Transport not supported or memory allocation error."); + ERRMEM; ret = 1; goto cleanup; } @@ -691,3 +678,5 @@ nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_na free(tree_path); return ret; } + +#endif /* NC_ENABLED_SSH_TLS */ diff --git a/src/config_new.h b/src/config_new.h index 747b648a..129998ed 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -24,6 +24,8 @@ extern "C" { #endif +#ifdef NC_ENABLED_SSH_TLS + /* private key's pkcs8 header */ #define NC_PKCS8_PRIVKEY_HEADER "-----BEGIN PRIVATE KEY-----\n" @@ -77,10 +79,12 @@ int nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_P int nc_server_config_new_read_certificate(const char *cert_path, char **cert); -int nc_config_new_check_add_operation(const struct ly_ctx *ctx, struct lyd_node *top); - const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT format); +#endif /* NC_ENABLED_SSH_TLS */ + +int nc_config_new_check_add_operation(const struct ly_ctx *ctx, struct lyd_node *top); + #ifdef __cplusplus } #endif diff --git a/src/io.c b/src/io.c index eb9360ae..47894d41 100644 --- a/src/io.c +++ b/src/io.c @@ -29,10 +29,10 @@ #include #include -#ifdef NC_ENABLED_TLS +#ifdef NC_ENABLED_SSH_TLS # include # include -#endif +#endif /* NC_ENABLED_SSH_TLS */ #include @@ -58,7 +58,7 @@ const char *nc_msgtype2str[] = { #define BUFFERSIZE 512 -#ifdef NC_ENABLED_TLS +#ifdef NC_ENABLED_SSH_TLS static char * nc_ssl_error_get_reasons(void) @@ -92,7 +92,7 @@ nc_ssl_error_get_reasons(void) return reasons; } -#endif +#endif /* NC_ENABLED_SSH_TLS */ static ssize_t nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_timeout, struct timespec *ts_act_timeout) @@ -147,7 +147,7 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time } break; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS case NC_TI_LIBSSH: /* read via libssh */ r = ssh_channel_read(session->ti.libssh.channel, buf + readd, count - readd, 0); @@ -169,9 +169,7 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time break; } break; -#endif -#ifdef NC_ENABLED_TLS case NC_TI_OPENSSL: /* read via OpenSSL */ ERR_clear_error(); @@ -210,7 +208,7 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time } } break; -#endif +#endif /* NC_ENABLED_SSH_TLS */ } if (r == 0) { @@ -484,7 +482,7 @@ nc_read_poll(struct nc_session *session, int io_timeout) } switch (session->ti_type) { -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS case NC_TI_LIBSSH: /* EINTR is handled, it resumes waiting */ ret = ssh_channel_poll_timeout(session->ti.libssh.channel, io_timeout, 0); @@ -506,8 +504,6 @@ nc_read_poll(struct nc_session *session, int io_timeout) fds.revents = 0; } break; -#endif -#ifdef NC_ENABLED_TLS case NC_TI_OPENSSL: ret = SSL_pending(session->ti.tls); if (ret) { @@ -518,7 +514,7 @@ nc_read_poll(struct nc_session *session, int io_timeout) } fds.fd = SSL_get_fd(session->ti.tls); -#endif +#endif /* NC_ENABLED_SSH_TLS */ /* fallthrough */ case NC_TI_FD: case NC_TI_UNIX: @@ -617,15 +613,13 @@ nc_session_is_connected(struct nc_session *session) case NC_TI_UNIX: fds.fd = session->ti.unixsock.sock; break; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS case NC_TI_LIBSSH: return ssh_is_connected(session->ti.libssh.session); -#endif -#ifdef NC_ENABLED_TLS case NC_TI_OPENSSL: fds.fd = SSL_get_fd(session->ti.tls); break; -#endif +#endif /* NC_ENABLED_SSH_TLS */ default: return 0; } @@ -663,9 +657,9 @@ nc_write(struct nc_session *session, const void *buf, size_t count) int c, fd, interrupted; size_t written = 0; -#ifdef NC_ENABLED_TLS +#ifdef NC_ENABLED_SSH_TLS unsigned long e; -#endif +#endif /* NC_ENABLED_SSH_TLS */ if ((session->status != NC_STATUS_RUNNING) && (session->status != NC_STATUS_STARTING)) { return -1; @@ -699,7 +693,7 @@ nc_write(struct nc_session *session, const void *buf, size_t count) } break; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS case NC_TI_LIBSSH: if (ssh_channel_is_closed(session->ti.libssh.channel) || ssh_channel_is_eof(session->ti.libssh.channel)) { if (ssh_channel_is_closed(session->ti.libssh.channel)) { @@ -717,8 +711,6 @@ nc_write(struct nc_session *session, const void *buf, size_t count) return -1; } break; -#endif -#ifdef NC_ENABLED_TLS case NC_TI_OPENSSL: c = SSL_write(session->ti.tls, (char *)(buf + written), count - written); if (c < 1) { @@ -746,7 +738,7 @@ nc_write(struct nc_session *session, const void *buf, size_t count) } } break; -#endif +#endif /* NC_ENABLED_SSH_TLS */ default: ERRINT; return -1; diff --git a/src/log.c b/src/log.c index f5d2feec..682293f7 100644 --- a/src/log.c +++ b/src/log.c @@ -21,9 +21,9 @@ #include -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS #include -#endif +#endif /* NC_ENABLED_SSH_TLS */ #include "compat.h" #include "config.h" @@ -56,7 +56,7 @@ struct { {NC_VERB_DEBUG_LOWLVL, "[DBL]"} }; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS API void nc_libssh_thread_verbosity(int level) @@ -64,7 +64,7 @@ nc_libssh_thread_verbosity(int level) ssh_set_log_level(level); } -#endif +#endif /* NC_ENABLED_SSH_TLS */ static void prv_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 1e4978e3..4bf69cea 100644 --- a/src/log.h +++ b/src/log.h @@ -50,7 +50,7 @@ typedef enum NC_VERB_LEVEL { */ void nc_verbosity(NC_VERB_LEVEL level); -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS /** * @brief Set libssh verbosity level. @@ -69,7 +69,7 @@ void nc_verbosity(NC_VERB_LEVEL level); */ void nc_libssh_thread_verbosity(int level); -#endif +#endif /* NC_ENABLED_SSH_TLS */ /** * @brief Deprecated, use ::nc_set_print_clb_session() instead. diff --git a/src/server_config.c b/src/server_config.c index 9dc94366..174b42c4 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -30,7 +31,7 @@ #include "server_config_p.h" #include "session_p.h" -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS /* All libssh supported host-key, key-exchange, encryption and mac algorithms as of version 0.10.90 */ @@ -60,7 +61,7 @@ static const char *supported_mac_algs[] = { "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL }; -#endif /* NC_ENABLED_SSH */ +#endif /* NC_ENABLED_SSH_TLS */ extern struct nc_server_opts server_opts; @@ -102,7 +103,7 @@ nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, return 1; } -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS int nc_server_config_get_hostkey(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_hostkey **hostkey) @@ -210,10 +211,6 @@ nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_client_ return 1; } -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS - int nc_server_config_get_cert(const struct lyd_node *node, struct nc_cert_grouping *auth_client, struct nc_certificate **cert) { @@ -288,7 +285,24 @@ nc_server_config_get_ctn(const struct lyd_node *node, struct nc_endpt *endpt, st return 1; } -#endif /* NC_ENABLED_TLS */ +NC_PRIVKEY_FORMAT +nc_server_config_get_private_key_type(const char *format) +{ + if (!strcmp(format, "rsa-private-key-format")) { + return NC_PRIVKEY_FORMAT_RSA; + } else if (!strcmp(format, "ec-private-key-format")) { + return NC_PRIVKEY_FORMAT_EC; + } else if (!strcmp(format, "subject-private-key-info-format")) { + return NC_PRIVKEY_FORMAT_X509; + } else if (!strcmp(format, "openssh-private-key-format")) { + return NC_PRIVKEY_FORMAT_OPENSSH; + } else { + ERR(NULL, "Private key format (%s) not supported.", format); + return NC_PRIVKEY_FORMAT_UNKNOWN; + } +} + +#endif /* NC_ENABLED_SSH_TLS */ int equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name) @@ -309,22 +323,6 @@ equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char return 0; } -NC_PRIVKEY_FORMAT -nc_server_config_get_private_key_type(const char *format) -{ - if (!strcmp(format, "rsa-private-key-format")) { - return NC_PRIVKEY_FORMAT_RSA; - } else if (!strcmp(format, "ec-private-key-format")) { - return NC_PRIVKEY_FORMAT_EC; - } else if (!strcmp(format, "subject-private-key-info-format")) { - return NC_PRIVKEY_FORMAT_X509; - } else if (!strcmp(format, "openssh-private-key-format")) { - return NC_PRIVKEY_FORMAT_OPENSSH; - } else { - ERR(NULL, "Private key format (%s) not supported.", format); - return NC_PRIVKEY_FORMAT_UNKNOWN; - } -} int nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count) @@ -360,6 +358,8 @@ nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_ return ret; } +#ifdef NC_ENABLED_SSH_TLS + static int is_listen(const struct lyd_node *node) { @@ -390,8 +390,6 @@ is_listen(const struct lyd_node *node) // return node != NULL; // } -#ifdef NC_ENABLED_SSH - static int is_ssh(const struct lyd_node *node) { @@ -407,9 +405,6 @@ is_ssh(const struct lyd_node *node) return node != NULL; } -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS static int is_tls(const struct lyd_node *node) { @@ -425,7 +420,7 @@ is_tls(const struct lyd_node *node) return node != NULL; } -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ static void nc_server_config_del_endpt_name(struct nc_endpt *endpt) @@ -434,6 +429,8 @@ nc_server_config_del_endpt_name(struct nc_endpt *endpt) endpt->name = NULL; } +#ifdef NC_ENABLED_SSH_TLS + static void nc_server_config_del_local_address(struct nc_bind *bind) { @@ -441,8 +438,6 @@ nc_server_config_del_local_address(struct nc_bind *bind) bind->address = NULL; } -#ifdef NC_ENABLED_SSH - static void nc_server_config_del_auth_client_pam_name(struct nc_client_auth *auth_client) { @@ -642,7 +637,7 @@ nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) } } -#endif /* NC_ENABLED_SSH */ +#endif /* NC_ENABLED_SSH_TLS */ void nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts) @@ -655,7 +650,6 @@ nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opt free(opts->address); free(opts); - opts = NULL; } void @@ -673,7 +667,7 @@ nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *b } } -#ifdef NC_ENABLED_TLS +#ifdef NC_ENABLED_SSH_TLS static void nc_server_config_tls_del_public_key(struct nc_server_tls_opts *opts) @@ -823,7 +817,7 @@ nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind) } } -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ /* presence container */ int @@ -839,16 +833,14 @@ nc_server_config_listen(struct lyd_node *node, NC_OPERATION op) endpt_count = server_opts.endpt_count; for (i = 0; i < endpt_count; i++) { switch (server_opts.endpts[i].ti) { -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS case NC_TI_LIBSSH: nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]); break; -#endif /* NC_ENABLED_SSH */ -#ifdef NC_ENABLED_TLS case NC_TI_OPENSSL: nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]); break; -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ case NC_TI_UNIX: nc_server_config_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]); break; @@ -938,16 +930,14 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) } switch (endpt->ti) { -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS case NC_TI_LIBSSH: nc_server_config_del_endpt_ssh(endpt, bind); break; -#endif /* NC_ENABLED_SSH */ -#ifdef NC_ENABLED_TLS case NC_TI_OPENSSL: nc_server_config_del_endpt_tls(endpt, bind); break; -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ case NC_TI_UNIX: nc_server_config_del_endpt_unix_socket(endpt, bind); break; @@ -963,7 +953,7 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) return ret; } -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS static int nc_server_config_create_ssh(struct nc_endpt *endpt) @@ -1006,10 +996,6 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) return ret; } -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS - static int nc_server_config_create_tls(struct nc_endpt *endpt) { @@ -1050,7 +1036,7 @@ nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op) return ret; } -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ static int nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port) @@ -1096,16 +1082,14 @@ nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, case NC_TI_UNIX: VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address); break; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS case NC_TI_LIBSSH: VRB(NULL, "Listening on %s:%u for SSH connections.", address, port); break; -#endif -#ifdef NC_ENABLED_TLS case NC_TI_OPENSSL: VRB(NULL, "Listening on %s:%u for TLS connections.", address, port); break; -#endif +#endif /* NC_ENABLED_SSH_TLS */ default: ERRINT; ret = 1; @@ -1117,6 +1101,8 @@ nc_server_config_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, return ret; } +#ifdef NC_ENABLED_SSH_TLS + /* mandatory leaf */ static int nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op) @@ -1310,8 +1296,6 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) return ret; } -#ifdef NC_ENABLED_SSH - static int nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_ssh_opts *opts) { @@ -1363,8 +1347,6 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) return ret; } -#endif /* NC_ENABLED_SSH */ - /* mandatory leaf */ static int nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) @@ -1373,12 +1355,9 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) int ret = 0; NC_PUBKEY_FORMAT pubkey_type; struct nc_endpt *endpt; - -#ifdef NC_ENABLED_SSH struct nc_client_auth *auth_client; struct nc_public_key *pubkey; struct nc_hostkey *hostkey; -#endif /* NC_ENABLED_SSH */ assert(!strcmp(LYD_NAME(node), "public-key-format")); @@ -1393,7 +1372,6 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } -#ifdef NC_ENABLED_SSH if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; @@ -1427,10 +1405,7 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { hostkey->key.pubkey_type = pubkey_type; } - } -#endif /* NC_ENABLED_SSH */ -#ifdef NC_ENABLED_TLS - if (equal_parent_name(node, 3, "server-identity") && is_tls(node) && is_listen(node)) { + } else if (equal_parent_name(node, 3, "server-identity") && is_tls(node) && is_listen(node)) { /* TLS listen server-identity */ if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; @@ -1441,7 +1416,6 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) endpt->opts.tls->pubkey_type = pubkey_type; } } -#endif /* NC_ENABLED_TLS */ cleanup: return ret; @@ -1455,10 +1429,7 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op const char *format; struct nc_endpt *endpt; NC_PRIVKEY_FORMAT privkey_type; - -#ifdef NC_ENABLED_SSH struct nc_hostkey *hostkey; -#endif /* NC_ENABLED_SSH */ (void) op; @@ -1481,7 +1452,6 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op goto cleanup; } -#ifdef NC_ENABLED_SSH if ((is_ssh(node)) && (is_listen(node))) { /* listen ssh */ if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { @@ -1490,22 +1460,15 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op } hostkey->key.privkey_type = privkey_type; - } -#endif /* NC_ENABLED_SSH */ -#ifdef NC_ENABLED_TLS - if ((is_tls(node)) && (is_listen(node))) { + } else if ((is_tls(node)) && (is_listen(node))) { /* listen tls */ - endpt->opts.tls->privkey_type = privkey_type; } -#endif /* NC_ENABLED_TLS */ cleanup: return ret; } -#ifdef NC_ENABLED_SSH - static int nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey) { @@ -1519,9 +1482,6 @@ nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, stru return 0; } -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS static int nc_server_config_tls_replace_cleartext_private_key(const struct lyd_node *node, struct nc_server_tls_opts *opts) { @@ -1535,17 +1495,12 @@ nc_server_config_tls_replace_cleartext_private_key(const struct lyd_node *node, return 0; } -#endif /* NC_ENABLED_TLS */ - static int nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_endpt *endpt; - -#ifdef NC_ENABLED_SSH struct nc_hostkey *hostkey; -#endif /* NC_ENABLED_SSH */ assert(!strcmp(LYD_NAME(node), "cleartext-private-key")); @@ -1554,7 +1509,6 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION goto cleanup; } -#ifdef NC_ENABLED_SSH if ((is_ssh(node)) && (is_listen(node))) { if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; @@ -1569,12 +1523,8 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION } else { nc_server_config_del_private_key(hostkey); } - } -#endif /* NC_ENABLED_SSH */ -#ifdef NC_ENABLED_TLS - if ((is_tls(node)) && (is_listen(node))) { + } else if ((is_tls(node)) && (is_listen(node))) { /* listen tls */ - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { ret = nc_server_config_tls_replace_cleartext_private_key(node, endpt->opts.tls); if (ret) { @@ -1584,14 +1534,11 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION nc_server_config_tls_del_cleartext_private_key(endpt->opts.tls); } } -#endif /* NC_ENABLED_TLS */ cleanup: return ret; } -#ifdef NC_ENABLED_SSH - static int nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey) { @@ -1691,9 +1638,6 @@ nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct return 0; } -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS static int nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts) { @@ -1708,19 +1652,14 @@ nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, stru return 0; } -#endif /* NC_ENABLED_TLS */ - static int nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_endpt *endpt; - -#ifdef NC_ENABLED_SSH struct nc_hostkey *hostkey; struct nc_client_auth *auth_client; struct nc_public_key *pubkey; -#endif /* NC_ENABLED_SSH */ assert(!strcmp(LYD_NAME(node), "public-key")); @@ -1729,7 +1668,6 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } -#ifdef NC_ENABLED_SSH if ((equal_parent_name(node, 3, "host-key")) && (is_ssh(node)) && (is_listen(node))) { /* server's public-key, mandatory leaf */ if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { @@ -1789,12 +1727,8 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } else { nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); } - } -#endif /* NC_ENABLED_SSH */ -#ifdef NC_ENABLED_TLS - if ((equal_parent_name(node, 3, "server-identity")) && (is_tls(node)) && (is_listen(node))) { + } else if ((equal_parent_name(node, 3, "server-identity")) && (is_tls(node)) && (is_listen(node))) { /* tls listen server-identity */ - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to local */ endpt->opts.tls->store = NC_STORE_LOCAL; @@ -1805,14 +1739,11 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } } } -#endif /* NC_ENABLED_TLS */ cleanup: return ret; } -#ifdef NC_ENABLED_SSH - static int nc_server_config_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts) { @@ -1926,9 +1857,6 @@ nc_server_config_replace_truststore_reference(const struct lyd_node *node, struc return 0; } -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS static int nc_server_config_tls_replace_truststore_reference(const struct lyd_node *node, struct nc_cert_grouping *auth_client) { @@ -1952,18 +1880,13 @@ nc_server_config_tls_replace_truststore_reference(const struct lyd_node *node, s return 0; } -#endif /* NC_ENABLED_TLS */ - /* leaf */ static int nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_endpt *endpt; - -#ifdef NC_ENABLED_SSH struct nc_client_auth *auth_client; -#endif /* NC_ENABLED_SSH */ assert(!strcmp(LYD_NAME(node), "truststore-reference")); @@ -1972,7 +1895,6 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION goto cleanup; } -#ifdef NC_ENABLED_SSH if ((equal_parent_name(node, 1, "public-keys")) && (is_ssh(node)) && (is_listen(node))) { if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; @@ -1990,10 +1912,7 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION } else { auth_client->ts_ref = NULL; } - } -#endif /* NC_ENABLED_SSH */ -#ifdef NC_ENABLED_TLS - if ((equal_parent_name(node, 1, "ca-certs")) && (is_listen(node))) { + } else if ((equal_parent_name(node, 1, "ca-certs")) && (is_listen(node))) { if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to truststore */ endpt->opts.tls->ca_certs.store = NC_STORE_TRUSTSTORE; @@ -2018,14 +1937,11 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION endpt->opts.tls->ee_certs.ts_ref = NULL; } } -#endif /* NC_ENABLED_TLS */ cleanup: return ret; } -#ifdef NC_ENABLED_SSH - static int nc_server_config_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client) { @@ -2433,7 +2349,7 @@ nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op) return ret; } -#endif /* NC_ENABLED_SSH */ +#endif /* NC_ENABLED_SSH_TLS */ static int nc_server_config_create_unix_socket(struct nc_endpt *endpt) @@ -2521,7 +2437,7 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) return ret; } -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS /** * @brief Set all endpoint client auth references, which couldn't be set beforehand. @@ -2646,10 +2562,6 @@ nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION return ret; } -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS - static int nc_server_config_tls_replace_cert_data(const struct lyd_node *node, struct nc_server_tls_opts *opts) { @@ -3088,7 +3000,7 @@ nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op) return ret; } -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ static int nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op) @@ -3107,15 +3019,17 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_endpoint(node, op)) { goto error; } + } else if (!strcmp(name, "unix-socket")) { + if (nc_server_config_unix_socket(node, op)) { + goto error; + } } -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS else if (!strcmp(name, "ssh")) { if (nc_server_config_ssh(node, op)) { goto error; } - } -#endif /* NC_ENABLED_SSH */ - else if (!strcmp(name, "local-address")) { + } else if (!strcmp(name, "local-address")) { if (nc_server_config_local_address(node, op)) { goto error; } @@ -3139,15 +3053,11 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_probe_interval(node, op)) { goto error; } - } -#ifdef NC_ENABLED_SSH - else if (!strcmp(name, "host-key")) { + } else if (!strcmp(name, "host-key")) { if (nc_server_config_host_key(node, op)) { goto error; } - } -#endif /* NC_ENABLED_SSH */ - else if (!strcmp(name, "public-key-format")) { + } else if (!strcmp(name, "public-key-format")) { if (nc_server_config_public_key_format(node, op)) { goto error; } @@ -3163,9 +3073,7 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_cleartext_private_key(node, op)) { goto error; } - } -#ifdef NC_ENABLED_SSH - else if (!strcmp(name, "keystore-reference")) { + } else if (!strcmp(name, "keystore-reference")) { if (nc_server_config_keystore_reference(node, op)) { goto error; } @@ -3181,15 +3089,11 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_auth_timeout(node, op)) { goto error; } - } -#endif /* NC_ENABLED_SSH */ - else if (!strcmp(name, "truststore-reference")) { + } else if (!strcmp(name, "truststore-reference")) { if (nc_server_config_truststore_reference(node, op)) { goto error; } - } -#ifdef NC_ENABLED_SSH - else if (!strcmp(name, "password")) { + } else if (!strcmp(name, "password")) { if (nc_server_config_password(node, op)) { goto error; } @@ -3221,22 +3125,11 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_mac_alg(node, op)) { goto error; } - } -#endif /* NC_ENABLED_SSH */ - else if (!strcmp(name, "unix-socket")) { - if (nc_server_config_unix_socket(node, op)) { - goto error; - } - } -#ifdef NC_ENABLED_SSH - else if (!strcmp(name, "endpoint-client-auth")) { + } else if (!strcmp(name, "endpoint-client-auth")) { if (nc_server_config_endpoint_client_auth(node, op)) { goto error; } - } -#endif /* NC_ENABLED_SSH */ -#ifdef NC_ENABLED_TLS - else if (!strcmp(name, "tls")) { + } else if (!strcmp(name, "tls")) { if (nc_server_config_tls(node, op)) { goto error; } @@ -3261,7 +3154,7 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION goto error; } } -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ return 0; @@ -3309,12 +3202,15 @@ nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent_op, case NC_OP_CREATE: case NC_OP_DELETE: case NC_OP_REPLACE: - if (module == NC_MODULE_NETCONF_SERVER) { - ret = nc_server_config_parse_netconf_server(node, current_op); - } else if (module == NC_MODULE_KEYSTORE) { +#ifdef NC_ENABLED_SSH_TLS + if (module == NC_MODULE_KEYSTORE) { ret = nc_server_config_parse_keystore(node, current_op); - } else { + } else if (module == NC_MODULE_TRUSTSTORE) { ret = nc_server_config_parse_truststore(node, current_op); + } else +#endif /* NC_ENABLED_SSH_TLS */ + { + ret = nc_server_config_parse_netconf_server(node, current_op); } if (ret) { return ret; @@ -3435,12 +3331,13 @@ nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION o goto cleanup; } -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS + /* backward check of client auth reference */ if (nc_server_config_fill_endpt_client_auth()) { ret = 1; goto cleanup; } -#endif /* NC_ENABLED_SSH */ +#endif /* NC_ENABLED_SSH_TLS */ cleanup: return ret; @@ -3454,6 +3351,7 @@ nc_server_config_setup_diff(const struct lyd_node *data) /* LOCK */ pthread_rwlock_wrlock(&server_opts.config_lock); +#ifdef NC_ENABLED_SSH_TLS /* configure keystore */ ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN); if (ret) { @@ -3467,6 +3365,7 @@ nc_server_config_setup_diff(const struct lyd_node *data) ERR(NULL, "Filling truststore failed."); goto cleanup; } +#endif /* NC_ENABLED_SSH_TLS */ /* configure netconf-server */ ret = nc_server_config_fill_nectonf_server(data, NC_OP_UNKNOWN); @@ -3511,6 +3410,7 @@ nc_server_config_setup_data(const struct lyd_node *data) /* delete the current configuration */ nc_server_config_listen(NULL, NC_OP_DELETE); +#ifdef NC_ENABLED_SSH_TLS nc_server_config_ks_keystore(NULL, NC_OP_DELETE); nc_server_config_ts_truststore(NULL, NC_OP_DELETE); @@ -3527,6 +3427,7 @@ nc_server_config_setup_data(const struct lyd_node *data) ERR(NULL, "Filling truststore failed."); goto cleanup; } +#endif /* NC_ENABLED_SSH_TLS */ /* configure netconf-server */ ret = nc_server_config_fill_nectonf_server(data, NC_OP_CREATE); diff --git a/src/server_config.h b/src/server_config.h index 63b30eeb..ebebf180 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -82,6 +82,8 @@ int nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path); */ int nc_server_config_load_modules(struct ly_ctx **ctx); +#ifdef NC_ENABLED_SSH_TLS + /** * @brief Creates new YANG configuration data nodes for a local-address and local-port. * @@ -259,7 +261,6 @@ int nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const ch int nc_server_config_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config); -#ifdef NC_ENABLED_TLS /** * @brief Creates new YANG configuration data nodes for a server's certificate. * @@ -327,7 +328,7 @@ int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *end int nc_server_config_new_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); -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ #ifdef __cplusplus } diff --git a/src/server_config_p.h b/src/server_config_p.h index 7866bf99..f412981d 100644 --- a/src/server_config_p.h +++ b/src/server_config_p.h @@ -45,7 +45,7 @@ typedef enum { */ int nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind); -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS /** * @brief Get the pointer to a hostkey structure based on node's location in the YANG data. * @@ -76,7 +76,15 @@ int nc_server_config_get_auth_client(const struct lyd_node *node, const struct n */ int nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_public_key **pubkey); -#endif /* NC_ENABLED_SSH */ +/** + * @brief Get private key type from YANG identity stored in a string. + * + * @param[in] format Value of the YANG identityref. + * @return Private key format on success, NC_PRIVKEY_FORMAT_UNKNOWN otherwise. + */ +NC_PRIVKEY_FORMAT nc_server_config_get_private_key_type(const char *format); + +#endif /* NC_ENABLED_SSH_TLS */ /** * @brief Compares the nth-parent name. @@ -88,14 +96,6 @@ int nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_cli */ int equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name); -/** - * @brief Get private key type from YANG identity stored in a string. - * - * @param[in] format Value of the YANG identityref. - * @return Private key format on success, NC_PRIVKEY_FORMAT_UNKNOWN otherwise. - */ -NC_PRIVKEY_FORMAT nc_server_config_get_private_key_type(const char *format); - /** * @brief Generic realloc function for arrays of structures representing YANG lists whose first member is the key (char *) * @@ -126,6 +126,8 @@ int nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent */ int nc_server_config_listen(struct lyd_node *node, NC_OPERATION op); +#ifdef NC_ENABLED_SSH_TLS + /** KEYSTORE **/ /** @@ -184,6 +186,8 @@ int nc_server_config_parse_truststore(const struct lyd_node *node, NC_OPERATION */ int nc_server_config_ts_truststore(const struct lyd_node *node, NC_OPERATION op); +#endif /* NC_ENABLED_SSH_TLS */ + #ifdef __cplusplus } #endif diff --git a/src/session.c b/src/session.c index a3c7fb02..3851a1d1 100644 --- a/src/session.c +++ b/src/session.c @@ -33,18 +33,13 @@ #include "netconf.h" #include "session_p.h" -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS -# include +#include +#include +#include -#endif /* NC_ENABLED_SSH */ - -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) - -# include -# include - -#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ /* in seconds */ #define NC_CLIENT_HELLO_TIMEOUT 60 @@ -106,6 +101,8 @@ nc_realtime_get(struct timespec *ts) } } +#ifdef NC_ENABLED_SSH_TLS + const char * nc_privkey_format_to_str(NC_PRIVKEY_FORMAT format) { @@ -123,6 +120,8 @@ nc_privkey_format_to_str(NC_PRIVKEY_FORMAT format) } } +#endif /* NC_ENABLED_SSH_TLS */ + int nc_sock_configure_keepalive(int sock, struct nc_keepalives *ka) { @@ -657,7 +656,7 @@ nc_session_free_transport(struct nc_session *session, int *multisession) (void)siter; break; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS case NC_TI_LIBSSH: { int r; @@ -723,9 +722,6 @@ nc_session_free_transport(struct nc_session *session, int *multisession) } break; } -#endif - -#ifdef NC_ENABLED_TLS case NC_TI_OPENSSL: /* remember sock so we can close it */ sock = SSL_get_fd(session->ti.tls); @@ -739,7 +735,7 @@ nc_session_free_transport(struct nc_session *session, int *multisession) X509_free(session->opts.server.client_cert); } break; -#endif +#endif /* NC_ENABLED_SSH_TLS */ case NC_TI_NONE: break; } @@ -839,7 +835,7 @@ nc_session_free(struct nc_session *session, void (*data_free)(void *)) } /* LY ext data */ -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS struct nc_session *siter; if ((session->flags & NC_SESSION_SHAREDCTX) && session->ti.libssh.next) { @@ -853,7 +849,7 @@ nc_session_free(struct nc_session *session, void (*data_free)(void *)) } } } else -#endif +#endif /* NC_ENABLED_SSH_TLS */ { lyd_free_siblings(session->opts.client.ext_data); } @@ -1457,244 +1453,3 @@ nc_handshake_io(struct nc_session *session) return type; } - -#ifdef NC_ENABLED_SSH - -static void -nc_ssh_init(void) -{ -#if (LIBSSH_VERSION_INT < SSH_VERSION_INT(0, 8, 0)) - ssh_threads_set_callbacks(ssh_threads_get_pthread()); - ssh_init(); -#endif -} - -static void -nc_ssh_destroy(void) -{ -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - FIPS_mode_set(0); - CONF_modules_unload(1); - nc_thread_destroy(); -#endif - -#if (LIBSSH_VERSION_INT < SSH_VERSION_INT(0, 8, 0)) - ssh_finalize(); -#endif -} - -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS - -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - -struct CRYPTO_dynlock_value { - pthread_mutex_t lock; -}; - -static struct CRYPTO_dynlock_value * -tls_dyn_create_func(const char *UNUSED(file), int UNUSED(line)) -{ - struct CRYPTO_dynlock_value *value; - - value = malloc(sizeof *value); - if (!value) { - ERRMEM; - return NULL; - } - pthread_mutex_init(&value->lock, NULL); - - return value; -} - -static void -tls_dyn_lock_func(int mode, struct CRYPTO_dynlock_value *l, const char *UNUSED(file), int UNUSED(line)) -{ - /* mode can also be CRYPTO_READ or CRYPTO_WRITE, but all the examples - * I found ignored this fact, what do I know... */ - if (mode & CRYPTO_LOCK) { - pthread_mutex_lock(&l->lock); - } else { - pthread_mutex_unlock(&l->lock); - } -} - -static void -tls_dyn_destroy_func(struct CRYPTO_dynlock_value *l, const char *UNUSED(file), int UNUSED(line)) -{ - pthread_mutex_destroy(&l->lock); - free(l); -} - -#endif - -#endif /* NC_ENABLED_TLS */ - -#if defined (NC_ENABLED_TLS) && !defined (NC_ENABLED_SSH) - -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 -static pthread_mutex_t *tls_locks; - -static void -tls_thread_locking_func(int mode, int n, const char *UNUSED(file), int UNUSED(line)) -{ - if (mode & CRYPTO_LOCK) { - pthread_mutex_lock(tls_locks + n); - } else { - pthread_mutex_unlock(tls_locks + n); - } -} - -static void -tls_thread_id_func(CRYPTO_THREADID *tid) -{ - CRYPTO_THREADID_set_numeric(tid, (unsigned long)pthread_self()); -} - -#endif - -static void -nc_tls_init(void) -{ -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - SSL_load_error_strings(); - ERR_load_BIO_strings(); - SSL_library_init(); - - int i; - - tls_locks = malloc(CRYPTO_num_locks() * sizeof *tls_locks); - if (!tls_locks) { - ERRMEM; - return; - } - for (i = 0; i < CRYPTO_num_locks(); ++i) { - pthread_mutex_init(tls_locks + i, NULL); - } - - CRYPTO_THREADID_set_callback(tls_thread_id_func); - CRYPTO_set_locking_callback(tls_thread_locking_func); - - CRYPTO_set_dynlock_create_callback(tls_dyn_create_func); - CRYPTO_set_dynlock_lock_callback(tls_dyn_lock_func); - CRYPTO_set_dynlock_destroy_callback(tls_dyn_destroy_func); -#endif -} - -static void -nc_tls_destroy(void) -{ -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - FIPS_mode_set(0); - CRYPTO_cleanup_all_ex_data(); - nc_thread_destroy(); - EVP_cleanup(); - ERR_free_strings(); -#if OPENSSL_VERSION_NUMBER < 0x10002000L // < 1.0.2 - sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); -#elif OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - SSL_COMP_free_compression_methods(); -#endif - - int i; - - CRYPTO_THREADID_set_callback(NULL); - CRYPTO_set_locking_callback(NULL); - for (i = 0; i < CRYPTO_num_locks(); ++i) { - pthread_mutex_destroy(tls_locks + i); - } - free(tls_locks); - - CRYPTO_set_dynlock_create_callback(NULL); - CRYPTO_set_dynlock_lock_callback(NULL); - CRYPTO_set_dynlock_destroy_callback(NULL); -#endif -} - -#endif /* NC_ENABLED_TLS && !NC_ENABLED_SSH */ - -#if defined (NC_ENABLED_SSH) && defined (NC_ENABLED_TLS) - -static void -nc_ssh_tls_init(void) -{ -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - SSL_load_error_strings(); - ERR_load_BIO_strings(); - SSL_library_init(); -#endif - - nc_ssh_init(); - -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - CRYPTO_set_dynlock_create_callback(tls_dyn_create_func); - CRYPTO_set_dynlock_lock_callback(tls_dyn_lock_func); - CRYPTO_set_dynlock_destroy_callback(tls_dyn_destroy_func); -#endif -} - -static void -nc_ssh_tls_destroy(void) -{ -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - ERR_free_strings(); -# if OPENSSL_VERSION_NUMBER < 0x10002000L // < 1.0.2 - sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); -# elif OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - SSL_COMP_free_compression_methods(); -# endif -#endif - - nc_ssh_destroy(); - -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - CRYPTO_set_dynlock_create_callback(NULL); - CRYPTO_set_dynlock_lock_callback(NULL); - CRYPTO_set_dynlock_destroy_callback(NULL); -#endif -} - -#endif /* NC_ENABLED_SSH && NC_ENABLED_TLS */ - -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) - -API void -nc_thread_destroy(void) -{ - /* caused data-races and seems not neccessary for avoiding valgrind reachable memory */ - // CRYPTO_cleanup_all_ex_data(); - -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - CRYPTO_THREADID crypto_tid; - - CRYPTO_THREADID_current(&crypto_tid); - ERR_remove_thread_state(&crypto_tid); -#endif -} - -#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */ - -void -nc_init(void) -{ -#if defined (NC_ENABLED_SSH) && defined (NC_ENABLED_TLS) - nc_ssh_tls_init(); -#elif defined (NC_ENABLED_SSH) - nc_ssh_init(); -#elif defined (NC_ENABLED_TLS) - nc_tls_init(); -#endif -} - -void -nc_destroy(void) -{ -#if defined (NC_ENABLED_SSH) && defined (NC_ENABLED_TLS) - nc_ssh_tls_destroy(); -#elif defined (NC_ENABLED_SSH) - nc_ssh_destroy(); -#elif defined (NC_ENABLED_TLS) - nc_tls_destroy(); -#endif -} diff --git a/src/session.h b/src/session.h index eb3b36fa..5f256ec2 100644 --- a/src/session.h +++ b/src/session.h @@ -23,7 +23,7 @@ extern "C" { #include "netconf.h" -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS /** * @brief Enumeration of NETCONF SSH authentication methods @@ -45,10 +45,6 @@ typedef enum { NC_SSH_KNOWNHOSTS_SKIP /**< do not add a known_hosts entry and skip all host key checks */ } NC_SSH_KNOWNHOSTS_MODE; -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS - /** * @brief Enumeration of cert-to-name mapping types */ @@ -62,7 +58,7 @@ typedef enum { NC_TLS_CTN_COMMON_NAME /**< common name as username */ } NC_TLS_CTN_MAPTYPE; -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ /** * @brief Enumeration of possible session statuses @@ -83,12 +79,11 @@ 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 +#ifdef NC_ENABLED_SSH_TLS NC_TI_LIBSSH, /**< libssh - use libssh library, only for NETCONF over SSH transport */ -#endif -#ifdef NC_ENABLED_TLS + NC_TI_OPENSSL /**< OpenSSL - use OpenSSL library, only for NETCONF over TLS transport */ -#endif +#endif /* NC_ENABLED_SSH_TLS */ } NC_TRANSPORT_IMPL; /** @@ -234,20 +229,6 @@ int nc_session_is_callhome(const struct nc_session *session); */ void nc_session_free(struct nc_session *session, void (*data_free)(void *)); -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) - -/** - * @brief Free all the dynamically allocated thread-specific libssl/libcrypto - * resources. - * - * This function should be called only if init (nc_client_init(), respectively nc_server_init()) was called. - * Call it in every thread your application creates just before the thread exits. In the last thread - * (usually the main one) call nc_client_destroy(), respectively nc_server_destroy(). - */ -void nc_thread_destroy(void); - -#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */ - #ifdef __cplusplus } #endif diff --git a/src/session_client.c b/src/session_client.c index 69d0bf91..2588e68d 100644 --- a/src/session_client.c +++ b/src/session_client.c @@ -54,11 +54,11 @@ static const char *ncds2str[] = {NULL, "config", "url", "running", "startup", "candidate"}; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS 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 */ +#endif /* NC_ENABLED_SSH_TLS */ static pthread_once_t nc_client_context_once = PTHREAD_ONCE_INIT; static pthread_key_t nc_client_context_key; @@ -70,7 +70,7 @@ static struct nc_client_context context_main = { .max_probes = 10, .probe_interval = 5 }, -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS .ssh_opts = { .auth_pref = {{NC_SSH_AUTH_INTERACTIVE, 1}, {NC_SSH_AUTH_PASSWORD, 2}, {NC_SSH_AUTH_PUBLICKEY, 3}}, .auth_password = sshauth_password, @@ -83,7 +83,7 @@ static struct nc_client_context context_main = { .auth_interactive = sshauth_interactive, .auth_privkey_passphrase = sshauth_privkey_passphrase }, -#endif /* NC_ENABLED_SSH */ +#endif /* NC_ENABLED_SSH_TLS */ /* .tls_ structures zeroed */ .refcount = 0 }; @@ -110,7 +110,7 @@ nc_client_context_free(void *ptr) /* for the main thread the same is done in nc_client_destroy() */ free(c->opts.schema_searchpath); -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) +#ifdef NC_ENABLED_SSH_TLS int i; for (i = 0; i < c->opts.ch_bind_count; ++i) { @@ -120,15 +120,13 @@ nc_client_context_free(void *ptr) free(c->opts.ch_binds); c->opts.ch_binds = NULL; c->opts.ch_bind_count = 0; -#endif -#ifdef NC_ENABLED_SSH + _nc_client_ssh_destroy_opts(&c->ssh_opts); _nc_client_ssh_destroy_opts(&c->ssh_ch_opts); -#endif -#ifdef NC_ENABLED_TLS + _nc_client_tls_destroy_opts(&c->tls_opts); _nc_client_tls_destroy_opts(&c->tls_ch_opts); -#endif +#endif /* NC_ENABLED_SSH_TLS */ free(c); } } @@ -162,7 +160,7 @@ nc_client_context_location(void) e = calloc(1, sizeof *e); /* set default values */ e->refcount = 1; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS e->ssh_opts.auth_pref[0].type = NC_SSH_AUTH_INTERACTIVE; e->ssh_opts.auth_pref[0].value = 1; e->ssh_opts.auth_pref[1].type = NC_SSH_AUTH_PASSWORD; @@ -178,7 +176,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 */ +#endif /* NC_ENABLED_SSH_TLS */ } pthread_setspecific(nc_client_context_key, e); } @@ -1750,7 +1748,7 @@ nc_sock_connect(const char *host, uint16_t port, int timeout_ms, struct nc_keepa return -1; } -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) +#ifdef NC_ENABLED_SSH_TLS int nc_client_ch_add_bind_listen(const char *address, uint16_t port, const char *hostname, NC_TRANSPORT_IMPL ti) @@ -1862,18 +1860,12 @@ nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **session) return sock; } -#ifdef NC_ENABLED_SSH if (client_opts.ch_binds_aux[idx].ti == NC_TI_LIBSSH) { *session = nc_accept_callhome_ssh_sock(sock, host, port, ctx, NC_TRANSPORT_TIMEOUT); - } else -#endif -#ifdef NC_ENABLED_TLS - if (client_opts.ch_binds_aux[idx].ti == NC_TI_OPENSSL) { + } else if (client_opts.ch_binds_aux[idx].ti == NC_TI_OPENSSL) { *session = nc_accept_callhome_tls_sock(sock, host, port, ctx, NC_TRANSPORT_TIMEOUT, client_opts.ch_binds_aux[idx].hostname); - } else -#endif - { + } else { close(sock); *session = NULL; } @@ -1887,7 +1879,7 @@ nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **session) return 1; } -#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ API const char * const * nc_session_get_cpblts(const struct nc_session *session) @@ -1927,26 +1919,15 @@ nc_session_ntf_thread_running(const struct nc_session *session) return ATOMIC_LOAD_RELAXED(session->opts.client.ntf_thread_running); } -API void -nc_client_init(void) -{ - nc_init(); -} - API void nc_client_destroy(void) { nc_client_set_schema_searchpath(NULL); -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) +#ifdef NC_ENABLED_SSH_TLS nc_client_ch_del_bind(NULL, 0, 0); -#endif -#ifdef NC_ENABLED_SSH nc_client_ssh_destroy_opts(); -#endif -#ifdef NC_ENABLED_TLS nc_client_tls_destroy_opts(); -#endif - nc_destroy(); +#endif /* NC_ENABLED_SSH_TLS */ } static NC_MSG_TYPE diff --git a/src/session_client.h b/src/session_client.h index 84e3ce8c..834908cc 100644 --- a/src/session_client.h +++ b/src/session_client.h @@ -22,13 +22,10 @@ extern "C" { #include -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS # include -#endif - -#ifdef NC_ENABLED_TLS # include -#endif +#endif /* NC_ENABLED_SSH_TLS */ #include "messages_client.h" #include "netconf.h" @@ -115,11 +112,6 @@ void nc_client_set_thread_context(void *context); */ void *nc_client_get_thread_context(void); -/** - * @brief Initialize libssh and/or libssl/libcrypto for use in the client. - */ -void nc_client_init(void); - /** * @brief Destroy all libssh and/or libssl/libcrypto dynamic memory and * the client options, for both SSH and TLS, and for Call Home too. @@ -169,7 +161,7 @@ struct nc_session *nc_connect_unix(const char *address, struct ly_ctx *ctx); /** @} Client Session */ -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS /** * @defgroup client_ssh Client SSH @@ -392,10 +384,6 @@ struct nc_session *nc_connect_ssh_channel(struct nc_session *session, struct ly_ /** @} Client SSH */ -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS - /** * @defgroup client_tls Client TLS * @ingroup client @@ -491,7 +479,7 @@ struct nc_session *nc_connect_libssl(SSL *tls, struct ly_ctx *ctx); /** @} Client TLS */ -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ /** * @addtogroup client_session diff --git a/src/session_client_ch.h b/src/session_client_ch.h index 33ea39c3..a19b5268 100644 --- a/src/session_client_ch.h +++ b/src/session_client_ch.h @@ -22,15 +22,15 @@ extern "C" { #include -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS # include -#endif +#endif /* NC_ENABLED_SSH_TLS */ #include "messages_client.h" #include "netconf.h" #include "session.h" -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) +#ifdef NC_ENABLED_SSH_TLS /** * @defgroup client_ch Client-side Call Home @@ -55,10 +55,6 @@ int nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **sess /** @} Client-side Call Home */ -#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */ - -#ifdef NC_ENABLED_SSH - /** * @defgroup client_ch_ssh Client-side Call Home on SSH * @ingroup client_ch @@ -257,10 +253,6 @@ const char *nc_client_ssh_ch_get_username(void); /** @} Client-side Call Home on SSH */ -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS - /** * @defgroup client_ch_tls Client-side Call Home on TLS * @ingroup client_ch @@ -353,7 +345,7 @@ void nc_client_tls_ch_get_crl_paths(const char **crl_file, const char **crl_dir) /** @} Client-side Call Home on TLS */ -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ #ifdef __cplusplus } diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c index 500fdbe4..c5bcbe5b 100644 --- a/src/session_client_ssh.c +++ b/src/session_client_ssh.c @@ -284,12 +284,7 @@ nc_client_ssh_update_known_hosts(ssh_session session, const char *hostname) { int ret; -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) ret = ssh_session_update_known_hosts(session); -#else - ret = ssh_write_knownhost(session); -#endif - if (ret != SSH_OK) { WRN(NULL, "Adding the known host \"%s\" failed (%s).", hostname, ssh_get_error(session)); } @@ -307,11 +302,7 @@ nc_client_ssh_get_srv_pubkey_data(ssh_session session, enum ssh_keytypes_e *srv_ *hexa = NULL; *hash_sha1 = NULL; -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 8, 0)) ret = ssh_get_server_publickey(session, &srv_pubkey); -#else - ret = ssh_get_publickey(session, &srv_pubkey); -#endif if (ret < 0) { ERR(NULL, "Unable to get server's public key."); return -1; @@ -338,7 +329,7 @@ nc_client_ssh_get_srv_pubkey_data(ssh_session session, enum ssh_keytypes_e *srv_ static int nc_client_ssh_do_dnssec_sshfp_check(ssh_session session, enum ssh_keytypes_e srv_pubkey_type, const char *hostname, unsigned char *hash_sha1) { - int ret; + int ret = 0; if ((srv_pubkey_type != SSH_KEYTYPE_UNKNOWN) && (srv_pubkey_type != SSH_KEYTYPE_RSA1)) { if (srv_pubkey_type == SSH_KEYTYPE_DSS) { @@ -353,11 +344,7 @@ nc_client_ssh_do_dnssec_sshfp_check(ssh_session session, enum ssh_keytypes_e srv /* DNSSEC SSHFP check successful, that's enough */ if (!ret) { VRB(NULL, "DNSSEC SSHFP check successful."); -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) ssh_session_update_known_hosts(session); -#else - ssh_write_knownhost(session); -#endif } return ret; @@ -392,25 +379,12 @@ nc_client_ssh_auth_hostkey_check(const char *hostname, uint16_t port, ssh_sessio goto error; } -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) - state = ssh_session_is_known_server(session); -#else - state = ssh_is_server_known(session); -#endif + state = ssh_session_is_known_server(session); switch (state) { -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) case SSH_KNOWN_HOSTS_OK: -#else - case SSH_SERVER_KNOWN_OK: -#endif break; /* ok */ - -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) case SSH_KNOWN_HOSTS_CHANGED: -#else - case SSH_SERVER_KNOWN_CHANGED: -#endif if (knownhosts_mode == NC_SSH_KNOWNHOSTS_ACCEPT) { /* is the mode is set to accept, then accept any connection even if the remote key changed */ WRN(NULL, "Remote host key changed, but you have requested accept mode so the connection will not be terminated."); @@ -419,28 +393,13 @@ nc_client_ssh_auth_hostkey_check(const char *hostname, uint16_t port, ssh_sessio ERR(NULL, "Remote host key changed, the connection will be terminated!"); goto error; } - -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) case SSH_KNOWN_HOSTS_OTHER: -#else - case SSH_SERVER_FOUND_OTHER: -#endif WRN(NULL, "Remote host key is not known, but a key of another type for this host is known. Continue with caution."); goto hostkey_not_known; - -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) case SSH_KNOWN_HOSTS_NOT_FOUND: -#else - case SSH_SERVER_FILE_NOT_FOUND: -#endif WRN(NULL, "Could not find the known hosts file."); goto hostkey_not_known; - -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) case SSH_KNOWN_HOSTS_UNKNOWN: -#else - case SSH_SERVER_NOT_KNOWN: -#endif hostkey_not_known: #ifdef ENABLE_DNSSEC /* do dnssec check, if it's ok then we're done otherwise continue */ @@ -529,12 +488,7 @@ nc_client_ssh_auth_hostkey_check(const char *hostname, uint16_t port, ssh_sessio } while (strcmp(answer, "yes") && strcmp(answer, "no")); break; - -#if (LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)) case SSH_KNOWN_HOSTS_ERROR: -#else - case SSH_SERVER_ERROR: -#endif ERR(NULL, "SSH error: %s", ssh_get_error(session)); goto error; } diff --git a/src/session_client_tls.c b/src/session_client_tls.c index 26b22e42..4cfc5e8f 100644 --- a/src/session_client_tls.c +++ b/src/session_client_tls.c @@ -34,10 +34,6 @@ #include "session_client_ch.h" #include "session_p.h" -#if OPENSSL_VERSION_NUMBER < 0x10100000L -#define X509_STORE_CTX_get_by_subject X509_STORE_get_by_subject -#endif - struct nc_client_context *nc_client_context_location(void); #define client_opts nc_client_context_location()->opts @@ -46,8 +42,6 @@ struct nc_client_context *nc_client_context_location(void); static int tlsauth_ch; -#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0 - static int tlsauth_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { @@ -142,102 +136,6 @@ tlsauth_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) return 1; /* success */ } -#else - -static int -tlsauth_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) -{ - X509_STORE_CTX store_ctx; - X509_OBJECT obj; - X509_NAME *subject, *issuer; - X509 *cert; - X509_CRL *crl; - X509_REVOKED *revoked; - EVP_PKEY *pubkey; - int i, n, rc; - ASN1_TIME *next_update = NULL; - struct nc_client_tls_opts *opts; - - if (!preverify_ok) { - return 0; - } - - opts = (tlsauth_ch ? &tls_ch_opts : &tls_opts); - - if (!opts->crl_store) { - /* nothing to check */ - return 1; - } - - cert = X509_STORE_CTX_get_current_cert(x509_ctx); - subject = X509_get_subject_name(cert); - issuer = X509_get_issuer_name(cert); - - /* try to retrieve a CRL corresponding to the _subject_ of - * the current certificate in order to verify it's integrity */ - memset((char *)&obj, 0, sizeof obj); - X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL); - rc = X509_STORE_CTX_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj); - X509_STORE_CTX_cleanup(&store_ctx); - crl = obj.data.crl; - if ((rc > 0) && crl) { - next_update = X509_CRL_get_nextUpdate(crl); - - /* verify the signature on this CRL */ - pubkey = X509_get_pubkey(cert); - if (X509_CRL_verify(crl, pubkey) <= 0) { - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); - X509_OBJECT_free_contents(&obj); - if (pubkey) { - EVP_PKEY_free(pubkey); - } - return 0; /* fail */ - } - if (pubkey) { - EVP_PKEY_free(pubkey); - } - - /* check date of CRL to make sure it's not expired */ - if (!next_update) { - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); - X509_OBJECT_free_contents(&obj); - return 0; /* fail */ - } - if (X509_cmp_current_time(next_update) < 0) { - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED); - X509_OBJECT_free_contents(&obj); - return 0; /* fail */ - } - X509_OBJECT_free_contents(&obj); - } - - /* try to retrieve a CRL corresponding to the _issuer_ of - * the current certificate in order to check for revocation */ - memset((char *)&obj, 0, sizeof obj); - X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL); - rc = X509_STORE_CTX_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj); - X509_STORE_CTX_cleanup(&store_ctx); - crl = obj.data.crl; - if ((rc > 0) && crl) { - /* check if the current certificate is revoked by this CRL */ - n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); - for (i = 0; i < n; i++) { - revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); - if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(cert)) == 0) { - ERR(NULL, "Certificate revoked!"); - X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED); - X509_OBJECT_free_contents(&obj); - return 0; /* fail */ - } - } - X509_OBJECT_free_contents(&obj); - } - - return 1; /* success */ -} - -#endif - void _nc_client_tls_destroy_opts(struct nc_client_tls_opts *opts) { @@ -510,14 +408,8 @@ nc_client_tls_update_opts(struct nc_client_tls_opts *opts, const char *peername) if (!opts->tls_ctx || opts->tls_ctx_change) { SSL_CTX_free(opts->tls_ctx); - -#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0 /* prepare global SSL context, highest available method is negotiated autmatically */ if (!(opts->tls_ctx = SSL_CTX_new(TLS_client_method()))) -#else - /* prepare global SSL context, allow only mandatory TLS 1.2 */ - if (!(opts->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()))) -#endif { ERR(NULL, "Unable to create OpenSSL context (%s).", ERR_reason_error_string(ERR_get_error())); rc = -1; @@ -553,7 +445,6 @@ nc_client_tls_update_opts(struct nc_client_tls_opts *opts, const char *peername) goto cleanup; } -#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0 if (peername) { /* server identity (hostname) verification */ vpm = X509_VERIFY_PARAM_new(); @@ -568,7 +459,6 @@ nc_client_tls_update_opts(struct nc_client_tls_opts *opts, const char *peername) goto cleanup; } } -#endif } if (opts->crl_store_change || (!opts->crl_store && (opts->crl_file || opts->crl_dir))) { @@ -582,11 +472,6 @@ nc_client_tls_update_opts(struct nc_client_tls_opts *opts, const char *peername) goto cleanup; } -#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0 - /* whaveter this does... */ - opts->crl_store->cache = 0; -#endif - if (opts->crl_file) { if (!(lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_file()))) { ERR(NULL, "Failed to add lookup method to CRL checking."); diff --git a/src/session_p.h b/src/session_p.h index 6af60a0a..a6004466 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -23,7 +23,6 @@ #include #include -#include #include "compat.h" #include "config.h" @@ -40,7 +39,6 @@ typedef enum { NC_OP_REPLACE } NC_OPERATION; -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) /** * Enumeration of key or certificate store type. @@ -51,6 +49,17 @@ typedef enum { NC_STORE_TRUSTSTORE /**< key/certificate is stored externally in a truststore module YANG data */ } NC_STORE_TYPE; +#ifdef NC_ENABLED_SSH_TLS + +#include +#include + +/* seconds */ +#define NC_SSH_TIMEOUT 10 + +/* number of all supported authentication methods */ +#define NC_SSH_AUTH_COUNT 3 + /** * Enumeration of SSH public key formats. */ @@ -141,15 +150,6 @@ struct nc_keystore { uint16_t sym_key_count; /**< Count of stored symmetric keys. */ }; -#endif - -#ifdef NC_ENABLED_SSH - -/* seconds */ -# define NC_SSH_TIMEOUT 10 -/* number of all supported authentication methods */ -# define NC_SSH_AUTH_COUNT 3 - /** * @brief Tracks the state of a client's authentication. */ @@ -213,25 +213,6 @@ struct nc_server_ssh_opts { uint16_t auth_timeout; /**< Authentication timeout. */ }; -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS - -/* ACCESS unlocked */ -struct nc_client_tls_opts { - char *cert_path; - char *key_path; - char *ca_file; - char *ca_dir; - int8_t tls_ctx_change; - SSL_CTX *tls_ctx; - - char *crl_file; - char *crl_dir; - int8_t crl_store_change; - X509_STORE *crl_store; -}; - /** * @brief Certificate grouping (either local-definition or truststore reference). */ @@ -285,7 +266,7 @@ struct nc_server_tls_opts { struct nc_ctn *ctn; /**< Cert-to-name entries */ }; -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ /** * @brief Keepalives configuration data. @@ -317,9 +298,8 @@ struct nc_bind { int pollin; /**< Specifies, which sockets to poll on. */ }; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS -/* ACCESS unlocked */ struct nc_client_ssh_opts { char *knownhosts_path; /**< path to known_hosts file */ NC_SSH_KNOWNHOSTS_MODE knownhosts_mode; /**< implies whether to check known_hosts or not */ @@ -351,7 +331,21 @@ struct nc_client_ssh_opts { char *username; }; -#endif +struct nc_client_tls_opts { + char *cert_path; + char *key_path; + char *ca_file; + char *ca_dir; + int8_t tls_ctx_change; + SSL_CTX *tls_ctx; + + char *crl_file; + char *crl_dir; + int8_t crl_store_change; + X509_STORE *crl_store; +}; + +#endif /* NC_ENABLED_SSH_TLS */ /* ACCESS unlocked */ struct nc_client_opts { @@ -375,14 +369,13 @@ struct nc_client_context { unsigned int refcount; struct nc_client_opts opts; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS struct nc_client_ssh_opts ssh_opts; struct nc_client_ssh_opts ssh_ch_opts; -#endif /* NC_ENABLED_SSH */ -#ifdef NC_ENABLED_TLS + struct nc_client_tls_opts tls_opts; struct nc_client_tls_opts tls_ch_opts; -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ }; struct nc_server_opts { @@ -401,7 +394,7 @@ struct nc_server_opts { ATOMIC_T hello_timeout; ATOMIC_T idle_timeout; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS int (*passwd_auth_clb)(const struct nc_session *session, const char *password, void *user_data); void *passwd_auth_data; void (*passwd_auth_data_free)(void *data); @@ -417,32 +410,32 @@ struct nc_server_opts { int (*interactive_auth_clb)(const struct nc_session *session, ssh_message msg, void *user_data); void *interactive_auth_data; void (*interactive_auth_data_free)(void *data); -#endif -#ifdef NC_ENABLED_TLS + int (*user_verify_clb)(const struct nc_session *session); -#endif +#endif /* NC_ENABLED_SSH_TLS */ pthread_rwlock_t config_lock; -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) - struct nc_keystore keystore; /**< store for server's keys/certificates */ +#ifdef NC_ENABLED_SSH_TLS + struct nc_keystore keystore; /**< store for server's keys/certificates */ struct nc_truststore truststore; /**< store for server client's keys/certificates */ -#endif +#endif /* NC_ENABLED_SSH_TLS */ struct nc_bind *binds; struct nc_endpt { char *name; +#ifdef NC_ENABLED_SSH_TLS char *referenced_endpt_name; +#endif /* NC_ENABLED_SSH_TLS */ NC_TRANSPORT_IMPL ti; struct nc_keepalives ka; union { -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS struct nc_server_ssh_opts *ssh; -#endif -#ifdef NC_ENABLED_TLS + struct nc_server_tls_opts *tls; -#endif +#endif /* NC_ENABLED_SSH_TLS */ struct nc_server_unix_opts *unixsock; } opts; } *endpts; @@ -461,12 +454,11 @@ struct nc_server_opts { struct nc_keepalives ka; union { -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS struct nc_server_ssh_opts *ssh; -#endif -#ifdef NC_ENABLED_TLS + struct nc_server_tls_opts *tls; -#endif +#endif /* NC_ENABLED_SSH_TLS */ } opts; } *ch_endpts; uint16_t ch_endpt_count; @@ -588,7 +580,7 @@ struct nc_session { struct { int sock; /**< socket file descriptor */ } unixsock; /**< NC_TI_UNIX transport implementation structure */ -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS struct { ssh_channel channel; ssh_session session; @@ -596,10 +588,9 @@ struct nc_session { SSH session, but different SSH channel. If no such session exists, it is NULL. otherwise there is a ring list of the NETCONF sessions */ } libssh; -#endif -#ifdef NC_ENABLED_TLS + SSL *tls; -#endif +#endif /* NC_ENABLED_SSH_TLS */ } ti; /**< transport implementation data */ char *username; char *host; @@ -646,16 +637,15 @@ struct nc_session { pthread_cond_t ch_cond; /**< Call Home thread condition */ /* server flags */ -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS /* SSH session authenticated */ # define NC_SESSION_SSH_AUTHENTICATED 0x10 /* netconf subsystem requested */ # define NC_SESSION_SSH_SUBSYS_NETCONF 0x20 uint16_t ssh_auth_attempts; /**< number of failed SSH authentication attempts */ -#endif -#ifdef NC_ENABLED_TLS + X509 *client_cert; /**< TLS client certificate if used for authentication */ -#endif +#endif /* NC_ENABLED_SSH_TLS */ } server; } opts; }; @@ -692,7 +682,7 @@ struct nc_ntf_thread_arg { void (*free_data)(void *); }; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS /** * @brief PAM callback arguments. @@ -703,7 +693,17 @@ struct nc_pam_thread_arg { struct nc_server_ssh_opts *opts; /**< SSH server opts */ }; -#endif +/** + * @brief Converts private key format to a string. + * This string is the same, as in a PKCS#1 Private key format, meaning + * ---- BEGIN (string) PRIVATE KEY ----. The string can be empty for some types. + * + * @param[in] format Private key format. + * @return String representing the private key or NULL. + */ +const char *nc_privkey_format_to_str(NC_PRIVKEY_FORMAT format); + +#endif /* NC_ENABLED_SSH_TLS */ void *nc_realloc(void *ptr, size_t size); @@ -734,8 +734,6 @@ int32_t nc_timeouttime_cur_diff(const struct timespec *ts); */ void nc_realtime_get(struct timespec *ts); -const char *nc_privkey_format_to_str(NC_PRIVKEY_FORMAT format); - int nc_sock_configure_keepalive(int sock, struct nc_keepalives *ka); struct nc_session *nc_new_session(NC_SIDE side, int shared_ti); @@ -932,11 +930,7 @@ int nc_client_ch_del_bind(const char *address, uint16_t port, NC_TRANSPORT_IMPL */ NC_MSG_TYPE nc_connect_callhome(const char *host, uint16_t port, NC_TRANSPORT_IMPL ti, struct nc_session **session); -void nc_init(void); - -void nc_destroy(void); - -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS /** * @brief Accept a server Call Home connection on a socket. @@ -976,10 +970,6 @@ void nc_server_ssh_clear_opts(struct nc_server_ssh_opts *opts); void nc_client_ssh_destroy_opts(void); void _nc_client_ssh_destroy_opts(struct nc_client_ssh_opts *opts); -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS - struct nc_session *nc_accept_callhome_tls_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout, const char *peername); @@ -998,7 +988,7 @@ void nc_server_tls_clear_opts(struct nc_server_tls_opts *opts); void nc_client_tls_destroy_opts(void); void _nc_client_tls_destroy_opts(struct nc_client_tls_opts *opts); -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ /** * Functions diff --git a/src/session_server.h b/src/session_server.h index 64dadbcd..612bb929 100644 --- a/src/session_server.h +++ b/src/session_server.h @@ -24,15 +24,13 @@ extern "C" { #include #include -#ifdef NC_ENABLED_TLS +#ifdef NC_ENABLED_SSH_TLS # include -#endif -#ifdef NC_ENABLED_SSH # include # include # include -#endif +#endif /* NC_ENABLED_SSH_TLS */ #include "netconf.h" #include "session.h" @@ -343,10 +341,10 @@ uint16_t nc_ps_session_count(struct nc_pollsession *ps); #define NC_PSPOLL_SESSION_ERROR 0x0040 /**< Some session was terminated incorrectly (not by a \ or \ RPC). */ #define NC_PSPOLL_ERROR 0x0080 /**< Other fatal errors (they are printed). */ -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS # define NC_PSPOLL_SSH_MSG 0x00100 /**< SSH message received (and processed, if relevant, only with SSH support). */ # define NC_PSPOLL_SSH_CHANNEL 0x0200 /**< New SSH channel opened on an existing session (only with SSH support). */ -#endif +#endif /* NC_ENABLED_SSH_TLS */ /** * @brief Poll sessions and process any received RPCs. @@ -516,7 +514,7 @@ int nc_server_endpt_set_keepalives(const char *endpt_name, int idle_time, int ma */ NC_MSG_TYPE nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session); -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS /** * @brief Accept a new NETCONF session on an SSH session of a running NETCONF @p orig_session. @@ -734,10 +732,6 @@ int nc_server_ssh_endpt_set_auth_timeout(const char *endpt_name, uint16_t auth_t /** @} Server SSH */ -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS - /** * @defgroup server_tls Server TLS * @ingroup server @@ -926,7 +920,7 @@ void nc_server_tls_set_verify_clb(int (*verify_clb)(const struct nc_session *ses /** @} Server TLS */ -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ /** * @addtogroup server_session diff --git a/src/session_server_ch.h b/src/session_server_ch.h index bf59ce4a..76b6adf3 100644 --- a/src/session_server_ch.h +++ b/src/session_server_ch.h @@ -27,7 +27,7 @@ extern "C" { #include "netconf.h" #include "session.h" -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) +#ifdef NC_ENABLED_SSH_TLS /** * @defgroup server_ch Server-side Call Home @@ -234,10 +234,6 @@ int nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_ /** @} Server-side Call Home */ -#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */ - -#ifdef NC_ENABLED_SSH - /** * @defgroup server_ch_ssh Server-side Call Home on SSH * @ingroup server_ch @@ -323,10 +319,6 @@ int nc_server_ssh_ch_client_endpt_set_auth_timeout(const char *client_name, cons /** @} Server-side Call Home on SSH */ -#endif /* NC_ENABLED_SSH */ - -#ifdef NC_ENABLED_TLS - /** * @defgroup server_ch_tls Server-side Call Home on TLS * @ingroup server_ch @@ -457,7 +449,7 @@ int nc_server_tls_ch_client_endpt_get_ctn(const char *client_name, const char *e /** @} Server-side Call Home on TLS */ -#endif /* NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ #ifdef __cplusplus } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 24d769c2..74b57208 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,8 +7,7 @@ if(${SOURCE_FORMAT_ENABLED}) add_test(NAME format WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND cmake --build ${CMAKE_BINARY_DIR} --target format-check) endif() -# list of all the tests in each directory -#set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages) +# list of all the tests that don't require SSH and TLS set(tests test_unix_socket) # only enable PAM tests if the version of PAM is greater than 1.4 @@ -16,7 +15,7 @@ if(LIBPAM_HAVE_CONFDIR) list(APPEND tests test_auth) endif() -set(client_tests test_client test_client_messages) +# set(client_tests test_client test_client_messages) # add -Wl,--wrap flags set(test test_client_ssh) @@ -37,12 +36,8 @@ foreach(mock_func IN LISTS ${test}_mock_funcs) endforeach() #append tests depending on SSH/TLS -if(ENABLE_SSH) - list(APPEND tests test_two_channels test_keystore test_config_new test_truststore test_ec test_ed25519 test_replace test_endpt_share_clients) -endif() - -if(ENABLE_TLS) - list(APPEND tests test_tls) +if(ENABLE_SSH_TLS) + list(APPEND tests test_two_channels test_keystore test_config_new test_truststore test_ec test_ed25519 test_replace test_endpt_share_clients test_tls) endif() foreach(src IN LISTS libsrc) diff --git a/tests/client/test_client_tls.c b/tests/client/test_client_tls.c index a3fd4b74..2ead67b4 100644 --- a/tests/client/test_client_tls.c +++ b/tests/client/test_client_tls.c @@ -87,8 +87,6 @@ test_nc_client_tls_setting_cert_key_paths(void **state) const char *cert, *key; int ret; - nc_client_init(); - /* no certificats are set, nc_client_tls_get_cert_key_paths should output NULL */ nc_client_tls_get_cert_key_paths(&cert, &key); assert_null(cert); diff --git a/tests/test_auth.c b/tests/test_auth.c index a5a53d56..3dd18450 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -141,7 +141,6 @@ server_thread(void *arg) nc_ps_clear(ps, 1, NULL); nc_ps_free(ps); - nc_thread_destroy(); return NULL; } @@ -191,7 +190,6 @@ client_thread_interactive(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -254,7 +252,6 @@ client_thread_password(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -304,7 +301,6 @@ client_thread_pubkey(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -347,7 +343,6 @@ client_thread_none(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -404,9 +399,6 @@ setup_f(void **state) ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); - /* initialize client */ - nc_client_init(); - ret = nc_server_init(); assert_int_equal(ret, 0); diff --git a/tests/test_client_thread.c b/tests/test_client_thread.c index 9d0eda0e..bede794e 100644 --- a/tests/test_client_thread.c +++ b/tests/test_client_thread.c @@ -53,8 +53,6 @@ main(void) pthread_t t; int r; - nc_client_init(); - /* * TEST sharing the thread context */ diff --git a/tests/test_config_new.c b/tests/test_config_new.c index 0289ddc8..bfdd1104 100644 --- a/tests/test_config_new.c +++ b/tests/test_config_new.c @@ -61,7 +61,6 @@ server_thread(void *arg) nc_ps_clear(ps, 1, NULL); nc_ps_free(ps); - nc_thread_destroy(); return NULL; } @@ -99,7 +98,6 @@ client_thread(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -171,9 +169,6 @@ setup_f(void **state) ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); - /* initialize client */ - nc_client_init(); - ret = nc_server_init(); assert_int_equal(ret, 0); diff --git a/tests/test_ec.c b/tests/test_ec.c index 95f82ace..a8b67be9 100644 --- a/tests/test_ec.c +++ b/tests/test_ec.c @@ -68,7 +68,6 @@ server_thread(void *arg) nc_ps_clear(ps, 1, NULL); nc_ps_free(ps); - nc_thread_destroy(); return NULL; } @@ -100,7 +99,6 @@ client_thread(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -234,9 +232,6 @@ setup_f(void **state) ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); - /* initialize client */ - nc_client_init(); - /* initialize server */ ret = nc_server_init(); assert_int_equal(ret, 0); diff --git a/tests/test_ed25519.c b/tests/test_ed25519.c index 7b27d7f9..96c09531 100644 --- a/tests/test_ed25519.c +++ b/tests/test_ed25519.c @@ -65,7 +65,6 @@ server_thread(void *arg) nc_ps_clear(ps, 1, NULL); nc_ps_free(ps); - nc_thread_destroy(); return NULL; } @@ -97,7 +96,6 @@ client_thread(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -165,9 +163,6 @@ setup_f(void **state) ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); - /* initialize client */ - nc_client_init(); - /* initialize server */ ret = nc_server_init(); assert_int_equal(ret, 0); diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c index 21cc2f69..837748fc 100644 --- a/tests/test_endpt_share_clients.c +++ b/tests/test_endpt_share_clients.c @@ -151,7 +151,6 @@ server_thread(void *arg) nc_ps_clear(ps, 1, NULL); nc_ps_free(ps); - nc_thread_destroy(); return NULL; } @@ -185,7 +184,6 @@ client_thread(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -245,9 +243,6 @@ setup_f(void **state) ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); - /* initialize the client */ - nc_client_init(); - /* initialize the server */ ret = nc_server_init(); assert_int_equal(ret, 0); diff --git a/tests/test_init_destroy_client.c b/tests/test_init_destroy_client.c index a9ee0dbc..097fa69e 100644 --- a/tests/test_init_destroy_client.c +++ b/tests/test_init_destroy_client.c @@ -39,8 +39,6 @@ setup_client(void **state) { (void)state; - nc_client_init(); - return 0; } diff --git a/tests/test_keystore.c b/tests/test_keystore.c index 93129682..8200d0dc 100644 --- a/tests/test_keystore.c +++ b/tests/test_keystore.c @@ -132,7 +132,6 @@ server_thread(void *arg) nc_ps_clear(ps, 1, NULL); nc_ps_free(ps); - nc_thread_destroy(); return NULL; } @@ -164,7 +163,6 @@ client_thread_pubkey(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -221,9 +219,6 @@ setup_f(void **state) ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); - /* initialize client */ - nc_client_init(); - ret = nc_server_init(); assert_int_equal(ret, 0); diff --git a/tests/test_replace.c b/tests/test_replace.c index 28fd032d..446ca4ba 100644 --- a/tests/test_replace.c +++ b/tests/test_replace.c @@ -149,7 +149,6 @@ server_thread(void *arg) nc_ps_clear(ps, 1, NULL); nc_ps_free(ps); - nc_thread_destroy(); return NULL; } @@ -183,7 +182,6 @@ client_thread(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -253,9 +251,6 @@ setup_f(void **state) ret = nc_server_config_setup_data(new_tree); assert_int_equal(ret, 0); - /* initialize the client */ - nc_client_init(); - /* initialize the server */ ret = nc_server_init(); assert_int_equal(ret, 0); diff --git a/tests/test_server_thread.c b/tests/test_server_thread.c index c1f2b575..2af23de7 100644 --- a/tests/test_server_thread.c +++ b/tests/test_server_thread.c @@ -618,7 +618,6 @@ client_fork(void) nc_assert(pipe(pipes + clients * 2) == 0); if (!(pids[clients] = fork())) { - nc_client_init(); ret = nc_client_set_schema_searchpath(TESTS_DIR "/data/modules"); nc_assert(!ret); @@ -640,8 +639,6 @@ client_fork(void) nc_assert(pipe(pipes + clients * 2) == 0); if (!(pids[clients] = fork())) { - nc_client_init(); - ret = nc_client_set_schema_searchpath(TESTS_DIR "/data/modules"); nc_assert(!ret); diff --git a/tests/test_tls.c b/tests/test_tls.c index 66930162..bb3867e1 100644 --- a/tests/test_tls.c +++ b/tests/test_tls.c @@ -63,7 +63,6 @@ server_thread(void *arg) nc_ps_clear(ps, 1, NULL); nc_ps_free(ps); - nc_thread_destroy(); return NULL; } @@ -90,7 +89,6 @@ client_thread(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -164,9 +162,6 @@ setup_f(void **state) ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); - /* initialize client */ - nc_client_init(); - ret = nc_server_init(); assert_int_equal(ret, 0); diff --git a/tests/test_truststore.c b/tests/test_truststore.c index 5b386588..9ba1352f 100644 --- a/tests/test_truststore.c +++ b/tests/test_truststore.c @@ -133,7 +133,6 @@ server_thread(void *arg) nc_ps_clear(ps, 1, NULL); nc_ps_free(ps); - nc_thread_destroy(); return NULL; } @@ -165,7 +164,6 @@ client_thread(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -225,9 +223,6 @@ setup_f(void **state) ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); - /* initialize client */ - nc_client_init(); - /* initialize server */ ret = nc_server_init(); assert_int_equal(ret, 0); diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c index d56beccc..30ae580f 100644 --- a/tests/test_two_channels.c +++ b/tests/test_two_channels.c @@ -148,7 +148,6 @@ server_thread(void *arg) } nc_ps_free(ps); - nc_thread_destroy(); return NULL; } @@ -159,9 +158,6 @@ client_thread(void *arg) int ret; struct nc_session *session_cl1, *session_cl2; - /* initialize client */ - nc_client_init(); - /* skip all hostkey and known_hosts checks */ nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); @@ -190,7 +186,6 @@ client_thread(void *arg) nc_client_destroy(); nc_session_free(session_cl1, NULL); nc_session_free(session_cl2, NULL); - nc_thread_destroy(); return NULL; } diff --git a/tests/test_unix_socket.c b/tests/test_unix_socket.c index ec48496e..77938dac 100644 --- a/tests/test_unix_socket.c +++ b/tests/test_unix_socket.c @@ -76,7 +76,6 @@ server_thread(void *arg) nc_ps_clear(ps, 1, NULL); nc_ps_free(ps); - nc_thread_destroy(); return NULL; } @@ -95,7 +94,6 @@ client_thread(void *arg) assert_non_null(session); nc_session_free(session, NULL); - nc_thread_destroy(); return NULL; } @@ -154,9 +152,6 @@ setup_f(void **state) ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); - /* initialize client */ - nc_client_init(); - /* initialize server */ ret = nc_server_init(); assert_int_equal(ret, 0); From 51d3a8e664ca5b5f15b475bec52832427d8400bb Mon Sep 17 00:00:00 2001 From: roman Date: Tue, 6 Jun 2023 10:06:44 +0200 Subject: [PATCH 032/134] ci UPDATE changed CI to use both SSH,TLS and none --- .github/workflows/libnetconf3-ci.yml | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/.github/workflows/libnetconf3-ci.yml b/.github/workflows/libnetconf3-ci.yml index 9db5445c..8b6d2c56 100644 --- a/.github/workflows/libnetconf3-ci.yml +++ b/.github/workflows/libnetconf3-ci.yml @@ -68,41 +68,17 @@ jobs: make-target: "" } - { - name: "SSH Only", + name: "No SSH nor TLS", os: "ubuntu-22.04", build-type: "Debug", dep-build-type: "Release", cc: "gcc", - options: "-DENABLE_TLS=OFF -DENABLE_SSH=ON", + options: "-DENABLE_TESTS=ON -DENABLE_SSH_TLS=OFF", packages: "valgrind", snaps: "", make-prepend: "", make-target: "" } - # - { - # name: "TLS Only", - # os: "ubuntu-22.04", - # build-type: "Debug", - # dep-build-type: "Release", - # cc: "gcc", - # options: "-DENABLE_TLS=ON -DENABLE_SSH=OFF", - # packages: "valgrind", - # snaps: "", - # make-prepend: "", - # make-target: "" - # } - # - { - # name: "No SSH nor TLS", - # os: "ubuntu-22.04", - # build-type: "Debug", - # dep-build-type: "Release", - # cc: "gcc", - # options: "-DENABLE_TLS=OFF -DENABLE_SSH=OFF", - # packages: "valgrind", - # snaps: "", - # make-prepend: "", - # make-target: "" - # } - { name: "ASAN and UBSAN", os: "ubuntu-22.04", From 776cb7b7b1fe8c926fd21d186cbe7d516bdc221a Mon Sep 17 00:00:00 2001 From: roman Date: Tue, 6 Jun 2023 13:14:53 +0200 Subject: [PATCH 033/134] config UPDATE update all models to newest versions --- ...h.yang => iana-crypt-hash@2014-04-04.yang} | 0 .../iana-ssh-encryption-algs@2022-06-16.yang | 13 +- ...iana-ssh-key-exchange-algs@2022-06-16.yang | 18 +- modules/iana-ssh-mac-algs@2022-06-16.yang | 9 +- .../iana-ssh-public-key-algs@2022-06-16.yang | 13 +- ...iana-tls-cipher-suite-algs@2022-06-16.yang | 29 ++- ...yang => ietf-crypto-types@2023-04-17.yang} | 177 +++++++++++------- ...-24.yang => ietf-keystore@2023-04-17.yang} | 63 +++---- ...ng => ietf-netconf-server@2023-04-17.yang} | 69 +++---- ...8.yang => ietf-ssh-common@2023-04-17.yang} | 29 ++- ...8.yang => ietf-ssh-server@2023-04-17.yang} | 127 +++++++------ ...4.yang => ietf-tcp-client@2023-04-17.yang} | 40 ++-- ...4.yang => ietf-tcp-common@2023-04-17.yang} | 8 +- ...4.yang => ietf-tcp-server@2023-04-17.yang} | 7 +- ...8.yang => ietf-tls-common@2023-04-17.yang} | 9 +- ...8.yang => ietf-tls-server@2023-04-17.yang} | 69 +++---- ...4.yang => ietf-truststore@2023-04-17.yang} | 30 +-- src/config_new.c | 3 +- src/config_new_ssh.c | 4 +- src/config_new_tls.c | 8 +- src/server_config.c | 42 +++-- src/session_client_ssh.c | 1 - src/session_client_tls.c | 3 +- src/session_p.h | 3 +- tests/test_auth.c | 8 +- tests/test_endpt_share_clients.c | 16 +- tests/test_keystore.c | 4 +- tests/test_replace.c | 12 +- tests/test_truststore.c | 4 +- tests/test_two_channels.c | 12 +- 30 files changed, 447 insertions(+), 383 deletions(-) rename modules/{iana-crypt-hash.yang => iana-crypt-hash@2014-04-04.yang} (100%) rename modules/{ietf-crypto-types@2022-07-07.yang => ietf-crypto-types@2023-04-17.yang} (87%) rename modules/{ietf-keystore@2022-05-24.yang => ietf-keystore@2023-04-17.yang} (90%) rename modules/{ietf-netconf-server@2022-05-24.yang => ietf-netconf-server@2023-04-17.yang} (93%) rename modules/{ietf-ssh-common@2022-07-18.yang => ietf-ssh-common@2023-04-17.yang} (90%) rename modules/{ietf-ssh-server@2022-07-18.yang => ietf-ssh-server@2023-04-17.yang} (76%) rename modules/{ietf-tcp-client@2022-05-24.yang => ietf-tcp-client@2023-04-17.yang} (89%) rename modules/{ietf-tcp-common@2022-05-24.yang => ietf-tcp-common@2023-04-17.yang} (95%) rename modules/{ietf-tcp-server@2022-05-24.yang => ietf-tcp-server@2023-04-17.yang} (96%) rename modules/{ietf-tls-common@2022-07-18.yang => ietf-tls-common@2023-04-17.yang} (97%) rename modules/{ietf-tls-server@2022-07-18.yang => ietf-tls-server@2023-04-17.yang} (89%) rename modules/{ietf-truststore@2022-05-24.yang => ietf-truststore@2023-04-17.yang} (94%) diff --git a/modules/iana-crypt-hash.yang b/modules/iana-crypt-hash@2014-04-04.yang similarity index 100% rename from modules/iana-crypt-hash.yang rename to modules/iana-crypt-hash@2014-04-04.yang diff --git a/modules/iana-ssh-encryption-algs@2022-06-16.yang b/modules/iana-ssh-encryption-algs@2022-06-16.yang index fabfd96b..516396b1 100644 --- a/modules/iana-ssh-encryption-algs@2022-06-16.yang +++ b/modules/iana-ssh-encryption-algs@2022-06-16.yang @@ -36,13 +36,8 @@ module iana-ssh-encryption-algs { revision 2022-06-16 { description - "Updated to reflect contents of the encryption algorithms - registry on June 16, 2022."; - } - - revision 2021-06-01 { - description - "Initial version"; + "Reflects contents of the encryption algorithms registry + on June 16, 2022."; reference "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; } @@ -108,7 +103,6 @@ module iana-ssh-encryption-algs { "RFC 4253: The Secure Shell (SSH) Transport Layer Protocol"; } - identity twofish128-cbc { base encryption-alg-base; description @@ -138,6 +132,7 @@ module iana-ssh-encryption-algs { identity aes128-cbc { base encryption-alg-base; + status deprecated; description "AES128-CBC"; reference @@ -208,6 +203,7 @@ module iana-ssh-encryption-algs { "RFC 4253: The Secure Shell (SSH) Transport Layer Protocol"; } + identity des-cbc { base encryption-alg-base; status obsolete; @@ -240,6 +236,7 @@ module iana-ssh-encryption-algs { identity aes128-ctr { base encryption-alg-base; + status deprecated; description "AES128-CTR"; reference diff --git a/modules/iana-ssh-key-exchange-algs@2022-06-16.yang b/modules/iana-ssh-key-exchange-algs@2022-06-16.yang index c4bab5b9..73b1895a 100644 --- a/modules/iana-ssh-key-exchange-algs@2022-06-16.yang +++ b/modules/iana-ssh-key-exchange-algs@2022-06-16.yang @@ -36,13 +36,8 @@ module iana-ssh-key-exchange-algs { revision 2022-06-16 { description - "Updated to reflect contents of the key exchange algorithms - registry on June 16, 2022."; - } - - revision 2021-06-01 { - description - "Initial version"; + "Reflects contents of the key exchange algorithms registry + on June 16, 2022."; reference "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; } @@ -66,6 +61,7 @@ module iana-ssh-key-exchange-algs { identity diffie-hellman-group-exchange-sha1 { base key-exchange-alg-base; + status deprecated; description "DIFFIE-HELLMAN-GROUP-EXCHANGE-SHA1"; reference @@ -86,6 +82,7 @@ module iana-ssh-key-exchange-algs { identity diffie-hellman-group1-sha1 { base key-exchange-alg-base; + status deprecated; description "DIFFIE-HELLMAN-GROUP1-SHA1"; reference @@ -95,6 +92,7 @@ module iana-ssh-key-exchange-algs { identity diffie-hellman-group14-sha1 { base key-exchange-alg-base; + status deprecated; description "DIFFIE-HELLMAN-GROUP14-SHA1"; reference @@ -104,6 +102,7 @@ module iana-ssh-key-exchange-algs { identity diffie-hellman-group14-sha256 { base key-exchange-alg-base; + status deprecated; description "DIFFIE-HELLMAN-GROUP14-SHA256"; reference @@ -154,6 +153,7 @@ module iana-ssh-key-exchange-algs { identity ecdh-sha2-nistp256 { base key-exchange-alg-base; + status deprecated; description "ECDH-SHA2-NISTP256 (secp256r1)"; reference @@ -292,7 +292,6 @@ module iana-ssh-key-exchange-algs { Generic Security Service Application Program Interface (GSS-API) Key Exchange with SHA-2"; } - identity gss-group1-sha1-nistp384 { base key-exchange-alg-base; status deprecated; @@ -534,6 +533,7 @@ module iana-ssh-key-exchange-algs { Generic Security Service Application Program Interface (GSS-API) Key Exchange with SHA-2"; } + identity gss-group14-sha1-1.3.132.0.36 { base key-exchange-alg-base; status deprecated; @@ -676,7 +676,6 @@ module iana-ssh-key-exchange-algs { Generic Security Service Application Program Interface (GSS-API) Key Exchange with SHA-2"; } - identity gss-gex-sha1-1.3.132.0.16 { base key-exchange-alg-base; status deprecated; @@ -821,7 +820,6 @@ module iana-ssh-key-exchange-algs { Generic Security Service Application Program Interface (GSS-API) Key Exchange with SHA-2"; } - identity gss-group14-sha256-1.2.840.10045.3.1.1 { base key-exchange-alg-base; description diff --git a/modules/iana-ssh-mac-algs@2022-06-16.yang b/modules/iana-ssh-mac-algs@2022-06-16.yang index c2574007..9cf3ae01 100644 --- a/modules/iana-ssh-mac-algs@2022-06-16.yang +++ b/modules/iana-ssh-mac-algs@2022-06-16.yang @@ -36,13 +36,8 @@ module iana-ssh-mac-algs { revision 2022-06-16 { description - "Updated to reflect contents of the MAC algorithms - registry on June 16, 2022."; - } - - revision 2021-06-01 { - description - "Initial version"; + "Reflects contents of the MAC algorithms registry on + June 16, 2022."; reference "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; } diff --git a/modules/iana-ssh-public-key-algs@2022-06-16.yang b/modules/iana-ssh-public-key-algs@2022-06-16.yang index 647a7edb..ae25bbc0 100644 --- a/modules/iana-ssh-public-key-algs@2022-06-16.yang +++ b/modules/iana-ssh-public-key-algs@2022-06-16.yang @@ -5,7 +5,6 @@ module iana-ssh-public-key-algs { organization "Internet Assigned Numbers Authority (IANA)"; - contact "Postal: ICANN 12025 Waterfront Drive, Suite 300 @@ -36,13 +35,8 @@ module iana-ssh-public-key-algs { revision 2022-06-16 { description - "Updated to reflect contents of the public key algorithms - registry on June 16, 2022."; - } - - revision 2021-06-01 { - description - "Initial version"; + "Reflects contents of the public key algorithms registry + on June 16, 2022."; reference "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; } @@ -58,7 +52,6 @@ module iana-ssh-public-key-algs { } // Identities - identity public-key-alg-base { description "Base identity used to identify public key algorithms."; @@ -151,6 +144,7 @@ module iana-ssh-public-key-algs { identity ecdsa-sha2-nistp256 { base public-key-alg-base; + status deprecated; description "ECDSA-SHA2-NISTP256 (secp256r1)"; reference @@ -289,6 +283,7 @@ module iana-ssh-public-key-algs { identity x509v3-rsa2048-sha256 { base public-key-alg-base; + status deprecated; description "X509V3-RSA2048-SHA256"; reference diff --git a/modules/iana-tls-cipher-suite-algs@2022-06-16.yang b/modules/iana-tls-cipher-suite-algs@2022-06-16.yang index 78d310d4..2b914d80 100644 --- a/modules/iana-tls-cipher-suite-algs@2022-06-16.yang +++ b/modules/iana-tls-cipher-suite-algs@2022-06-16.yang @@ -36,15 +36,10 @@ module iana-tls-cipher-suite-algs { revision 2022-06-16 { description - "Updated to reflect contents of the public key algorithms - registry on June 16, 2022."; - } - - revision 2021-06-02 { - description - "Initial version"; + "Reflect contents of the public key algorithms registry + on June 16, 2022."; reference - "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + "RFC FFFF: YANG Groupings for TLS Clients and TLS Servers"; } // Typedefs @@ -56,6 +51,7 @@ module iana-tls-cipher-suite-algs { description "A reference to a TLS cipher suite algorithm identifier."; } + // Identities identity cipher-suite-alg-base { @@ -104,6 +100,7 @@ module iana-tls-cipher-suite-algs { RFC 6347: Datagram Transport Layer Security version 1.2"; } + identity tls-rsa-with-rc4-128-md5 { base cipher-suite-alg-base; status deprecated; @@ -528,7 +525,6 @@ module iana-tls-cipher-suite-algs { Addition of Kerberos Cipher Suites to Transport Layer Security (TLS)"; } - identity tls-krb5-export-with-rc4-40-md5 { base cipher-suite-alg-base; status deprecated; @@ -584,6 +580,7 @@ module iana-tls-cipher-suite-algs { "RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2"; } + identity tls-dh-dss-with-aes-128-cbc-sha { base cipher-suite-alg-base; status deprecated; @@ -1592,6 +1589,7 @@ module iana-tls-cipher-suite-algs { ShangMi (SM) Cipher Suites for Transport Layer Security (TLS) Protocol Version 1.3"; } + identity tls-sm4-ccm-sm3 { base cipher-suite-alg-base; status deprecated; @@ -1631,7 +1629,6 @@ module iana-tls-cipher-suite-algs { "RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3"; } - identity tls-chacha20-poly1305-sha256 { base cipher-suite-alg-base; description @@ -1640,6 +1637,7 @@ module iana-tls-cipher-suite-algs { "RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3"; } + identity tls-aes-128-ccm-sha256 { base cipher-suite-alg-base; description @@ -2024,6 +2022,7 @@ module iana-tls-cipher-suite-algs { "RFC 5054: Using SRP for TLS Authentication"; } + identity tls-srp-sha-rsa-with-aes-256-cbc-sha { base cipher-suite-alg-base; status deprecated; @@ -2120,6 +2119,7 @@ module iana-tls-cipher-suite-algs { TLS Elliptic Curve Cipher Suites with SHA-256/384 and AES Galois Counter Mode"; } + identity tls-ecdh-rsa-with-aes-256-cbc-sha384 { base cipher-suite-alg-base; status deprecated; @@ -2493,7 +2493,6 @@ module iana-tls-cipher-suite-algs { Addition of the ARIA Cipher Suites to Transport Layer Security (TLS)"; } - identity tls-ecdhe-rsa-with-aria-256-cbc-sha384 { base cipher-suite-alg-base; status deprecated; @@ -2504,6 +2503,7 @@ module iana-tls-cipher-suite-algs { Addition of the ARIA Cipher Suites to Transport Layer Security (TLS)"; } + identity tls-ecdh-rsa-with-aria-128-cbc-sha256 { base cipher-suite-alg-base; status deprecated; @@ -2877,7 +2877,6 @@ module iana-tls-cipher-suite-algs { Addition of the ARIA Cipher Suites to Transport Layer Security (TLS)"; } - identity tls-ecdhe-psk-with-aria-128-cbc-sha256 { base cipher-suite-alg-base; status deprecated; @@ -2888,6 +2887,7 @@ module iana-tls-cipher-suite-algs { Addition of the ARIA Cipher Suites to Transport Layer Security (TLS)"; } + identity tls-ecdhe-psk-with-aria-256-cbc-sha384 { base cipher-suite-alg-base; status deprecated; @@ -3261,7 +3261,6 @@ module iana-tls-cipher-suite-algs { Addition of the Camellia Cipher Suites to Transport Layer Security (TLS)"; } - identity tls-rsa-psk-with-camellia-256-gcm-sha384 { base cipher-suite-alg-base; status deprecated; @@ -3272,6 +3271,7 @@ module iana-tls-cipher-suite-algs { Addition of the Camellia Cipher Suites to Transport Layer Security (TLS)"; } + identity tls-psk-with-camellia-128-cbc-sha256 { base cipher-suite-alg-base; status deprecated; @@ -3693,7 +3693,6 @@ module iana-tls-cipher-suite-algs { ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS)"; } - identity tls-ecdhe-psk-with-chacha20-poly1305-sha256 { base cipher-suite-alg-base; description @@ -3742,7 +3741,6 @@ module iana-tls-cipher-suite-algs { "RFC 8442: ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites"; } - identity tls-ecdhe-psk-with-aes-128-ccm-8-sha256 { base cipher-suite-alg-base; status deprecated; @@ -3752,6 +3750,7 @@ module iana-tls-cipher-suite-algs { "RFC 8442: ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites"; } + identity tls-ecdhe-psk-with-aes-128-ccm-sha256 { base cipher-suite-alg-base; description diff --git a/modules/ietf-crypto-types@2022-07-07.yang b/modules/ietf-crypto-types@2023-04-17.yang similarity index 87% rename from modules/ietf-crypto-types@2022-07-07.yang rename to modules/ietf-crypto-types@2023-04-17.yang index 19b658d1..ddabbeec 100644 --- a/modules/ietf-crypto-types@2022-07-07.yang +++ b/modules/ietf-crypto-types@2023-04-17.yang @@ -27,7 +27,7 @@ module ietf-crypto-types { "This module defines common YANG types for cryptographic applications. - Copyright (c) 2022 IETF Trust and the persons identified + Copyright (c) 2023 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with @@ -48,7 +48,7 @@ module ietf-crypto-types { (RFC 8174) when, and only when, they appear in all capitals, as shown here."; - revision 2022-07-07 { + revision 2023-04-17 { description "Initial version"; reference @@ -94,15 +94,9 @@ module ietf-crypto-types { "Indicates that the server supports the 'cms-encrypted-data-format' identity."; } - feature csr-generation { - description - "Indicates that the server implements the - 'generate-csr' action."; - } - - feature p10-based-csrs { + feature p10-csr-format { description - "Indicates that the erver implements support + "Indicates that the server implements support for generating P10-based CSRs, as defined in RFC 2986."; reference @@ -110,30 +104,59 @@ module ietf-crypto-types { Specification Version 1.7"; } + feature csr-generation { + description + "Indicates that the server implements the + 'generate-csr' action."; + } + feature certificate-expiration-notification { description "Indicates that the server implements the 'certificate-expiration' notification."; } - feature hidden-keys { + feature cleartext-passwords { description - "Indicates that the server supports hidden keys."; + "Indicates that the server supports cleartext + passwords."; } - feature password-encryption { + feature encrypted-passwords { description "Indicates that the server supports password encryption."; } - feature symmetric-key-encryption { + feature cleartext-symmetric-keys { + description + "Indicates that the server supports cleartext + symmetric keys."; + } + + feature hidden-symmetric-keys { + description + "Indicates that the server supports hidden keys."; + } + + feature encrypted-symmetric-keys { description "Indicates that the server supports encryption of symmetric keys."; } - feature private-key-encryption { + feature cleartext-private-keys { + description + "Indicates that the server supports cleartext + private keys."; + } + + feature hidden-private-keys { + description + "Indicates that the server supports hidden keys."; + } + + feature encrypted-private-keys { description "Indicates that the server supports encryption of private keys."; @@ -142,6 +165,7 @@ module ietf-crypto-types { /*************************************************/ /* Base Identities for Key Format Structures */ /*************************************************/ + identity symmetric-key-format { description "Base key-format identity for symmetric keys."; @@ -164,20 +188,35 @@ module ietf-crypto-types { identity rsa-private-key-format { base private-key-format; description - "Indicates that the private key value is encoded - as an RSAPrivateKey (from RFC 3447)."; + "Indicates that the private key value is encoded as + an RSAPrivateKey (from RFC 3447), encoded using ASN.1 + distinguished encoding rules (DER), as specified in + ITU-T X.690."; reference - "RFC 3447: PKCS #1: RSA Cryptography - Specifications Version 2.2"; + "RFC 3447: + PKCS #1: RSA Cryptography Specifications Version 2.2 + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER) 02/2021."; } identity ec-private-key-format { base private-key-format; description - "Indicates that the private key value is encoded - as an ECPrivateKey (from RFC 5915)"; + "Indicates that the private key value is encoded as + an ECPrivateKey (from RFC 5915), encoded using ASN.1 + distinguished encoding rules (DER), as specified in + ITU-T X.690."; reference - "RFC 5915: Elliptic Curve Private Key Structure"; + "RFC 5915: + Elliptic Curve Private Key Structure + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER) 02/2021."; } identity one-asymmetric-key-format { @@ -194,7 +233,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } /***************************************************/ @@ -229,7 +268,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } /******************************************************/ @@ -243,11 +282,10 @@ module ietf-crypto-types { The length of the octet string MUST be appropriate for the associated algorithm's block size. - How the associated algorithm is known is outside the - scope of this module. This statement also applies when - the octet string has been encrypted."; + The identity of the associated algorithm is outside the + scope of this specification. This is also true when + the octet string has been encrypted."; } - identity one-symmetric-key-format { if-feature "one-symmetric-key-format"; base symmetric-key-format; @@ -263,7 +301,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } /*************************************************/ @@ -304,7 +342,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } identity cms-enveloped-data-format { @@ -341,7 +379,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } /*********************************************************/ @@ -355,8 +393,8 @@ module ietf-crypto-types { by future efforts."; } - identity p10-csr { - if-feature "p10-based-csrs"; + identity p10-csr-format { + if-feature "p10-csr-format"; base csr-format; description "Indicates the 'CertificationRequest' structure @@ -383,7 +421,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } typedef p10-csr { @@ -400,7 +438,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } /***************************************************/ @@ -421,7 +459,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } typedef crl { @@ -438,7 +476,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } /***************************************************/ @@ -459,7 +497,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } typedef oscp-response { @@ -476,7 +514,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } /***********************************************/ @@ -496,7 +534,7 @@ module ietf-crypto-types { Information technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished - Encoding Rules (DER)."; + Encoding Rules (DER) 02/2021."; } typedef data-content-cms { @@ -590,7 +628,7 @@ module ietf-crypto-types { The CMS MUST contain only a single chain of certificates. The client or end-entity certificate MUST only authenticate - to last intermediate CA certificate listed in the chain. + to the last intermediate CA certificate listed in the chain. In all cases, the chain MUST include a self-signed root certificate. In the case where the root certificate is @@ -603,12 +641,15 @@ module ietf-crypto-types { verify the revocation status of the certificates. This CMS encodes the degenerate form of the SignedData - structure that is commonly used to disseminate X.509 - certificates and revocation objects (RFC 5280)."; + structure (RFC 5652, Section 5.2) that is commonly used + to disseminate X.509 certificates and revocation objects + (RFC 5280)."; reference "RFC 5280: Internet X.509 Public Key Infrastructure Certificate - and Certificate Revocation List (CRL) Profile."; + and Certificate Revocation List (CRL) Profile. + RFC 5652: + Cryptographic Message Syntax (CMS)"; } typedef end-entity-cert-cms { @@ -629,12 +670,16 @@ module ietf-crypto-types { verify the revocation status of the certificates. This CMS encodes the degenerate form of the SignedData - structure that is commonly used to disseminate X.509 - certificates and revocation objects (RFC 5280)."; + structure (RFC 5652, Section 5.2) that is commonly + used to disseminate X.509 certificates and revocation + objects (RFC 5280)."; + reference "RFC 5280: Internet X.509 Public Key Infrastructure Certificate - and Certificate Revocation List (CRL) Profile."; + and Certificate Revocation List (CRL) Profile. + RFC 5652: + Cryptographic Message Syntax (CMS)"; } /*****************/ @@ -657,7 +702,8 @@ module ietf-crypto-types { via a leaf node called 'asymmetric-key-ref'. The leaf nodes MUST be direct descendants in the data tree, - and MAY be direct descendants in the schema tree."; + and MAY be direct descendants in the schema tree (e.g., + choice/case statements are allowed, but not a container)."; } leaf encrypted-value-format { type identityref { @@ -690,13 +736,14 @@ module ietf-crypto-types { grouping password-grouping { description - "A password that MAY be encrypted."; + "A password that may be encrypted."; choice password-type { nacm:default-deny-write; mandatory true; description "Choice between password types."; case cleartext-password { + if-feature "cleartext-passwords"; leaf cleartext-password { nacm:default-deny-all; type string; @@ -705,7 +752,7 @@ module ietf-crypto-types { } } case encrypted-password { - if-feature "password-encryption"; + if-feature "encrypted-passwords"; container encrypted-password { description "A container for the encrypted password value."; @@ -728,8 +775,9 @@ module ietf-crypto-types { SHOULD ensure that the incoming symmetric key value is encoded in the specified format. - For encrypted keys, the value is the same as it would - have been if the key were not encrypted."; + For encrypted keys, the value is the decrypted key's + format (i.e., the 'encrypted-value-format' conveys the + encrypted key's format."; } choice key-type { nacm:default-deny-write; @@ -738,6 +786,7 @@ module ietf-crypto-types { "Choice between key types."; case cleartext-key { leaf cleartext-key { + if-feature "cleartext-symmetric-keys"; nacm:default-deny-all; type binary; must '../key-format'; @@ -747,7 +796,7 @@ module ietf-crypto-types { } } case hidden-key { - if-feature "hidden-keys"; + if-feature "hidden-symmetric-keys"; leaf hidden-key { type empty; must 'not(../key-format)'; @@ -757,7 +806,7 @@ module ietf-crypto-types { } } case encrypted-key { - if-feature "symmetric-key-encryption"; + if-feature "encrypted-symmetric-keys"; container encrypted-key { must '../key-format'; description @@ -809,8 +858,9 @@ module ietf-crypto-types { ensure that the incoming private key value is encoded in the specified format. - For encrypted keys, the value is the same as it would have - been if the key were not encrypted."; + For encrypted keys, the value is the decrypted key's + format (i.e., the 'encrypted-value-format' conveys the + encrypted key's format."; } choice private-key-type { nacm:default-deny-write; @@ -818,6 +868,7 @@ module ietf-crypto-types { description "Choice between key types."; case cleartext-private-key { + if-feature "cleartext-private-keys"; leaf cleartext-private-key { nacm:default-deny-all; type binary; @@ -828,7 +879,7 @@ module ietf-crypto-types { } } case hidden-private-key { - if-feature "hidden-keys"; + if-feature "hidden-private-keys"; leaf hidden-private-key { type empty; must 'not(../private-key-format)'; @@ -838,7 +889,7 @@ module ietf-crypto-types { } } case encrypted-private-key { - if-feature "private-key-encryption"; + if-feature "encrypted-private-keys"; container encrypted-private-key { must '../private-key-format'; description @@ -928,7 +979,7 @@ module ietf-crypto-types { } mandatory true; description - "Specifies the format for the returned certifiacte."; + "Specifies the format for the returned certificate."; } leaf csr-info { type csr-info; @@ -982,7 +1033,7 @@ module ietf-crypto-types { grouping asymmetric-key-pair-with-cert-grouping { description "A private/public key pair and an associated certificate. - Implementations SHOULD assert that certificates contain + Implementations SHOULD assert that the certificate contains the matching public key."; uses asymmetric-key-pair-grouping; uses end-entity-cert-grouping; @@ -991,9 +1042,9 @@ module ietf-crypto-types { grouping asymmetric-key-pair-with-certs-grouping { description - "A private/public key pair and associated certificates. - Implementations SHOULD assert that certificates contain - the matching public key."; + "A private/public key pair and a list of associated + certificates. Implementations SHOULD assert that + certificates contain the matching public key."; uses asymmetric-key-pair-grouping; container certificates { nacm:default-deny-write; diff --git a/modules/ietf-keystore@2022-05-24.yang b/modules/ietf-keystore@2023-04-17.yang similarity index 90% rename from modules/ietf-keystore@2022-05-24.yang rename to modules/ietf-keystore@2023-04-17.yang index 345e0aa6..8e158fab 100644 --- a/modules/ietf-keystore@2022-05-24.yang +++ b/modules/ietf-keystore@2023-04-17.yang @@ -27,7 +27,7 @@ module ietf-keystore { "This module defines a 'keystore' to centralize management of security credentials. - Copyright (c) 2022 IETF Trust and the persons identified + Copyright (c) 2023 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with @@ -48,7 +48,7 @@ module ietf-keystore { (RFC 8174) when, and only when, they appear in all capitals, as shown here."; - revision 2022-05-24 { + revision 2023-04-17 { description "Initial version"; reference @@ -66,22 +66,23 @@ module ietf-keystore { 'ietf-keystore' module)."; } - feature local-definitions-supported { + feature inline-definitions-supported { description - "The 'local-definitions-supported' feature indicates that + "The 'inline-definitions-supported' feature indicates that the server supports locally-defined keys."; } feature asymmetric-keys { description "The 'asymmetric-keys' feature indicates that the server - supports asymmetric keys in keystores."; + implements the /keystore/asymmetric-keys subtree."; + } feature symmetric-keys { description "The 'symmetric-keys' feature indicates that the server - supports symmetric keys in keystores."; + implements the /keystore/symmetric-keys subtree."; } /****************/ @@ -177,9 +178,9 @@ module ietf-keystore { } } - // local-or-keystore-* groupings + // inline-or-keystore-* groupings - grouping local-or-keystore-symmetric-key-grouping { + grouping inline-or-keystore-symmetric-key-grouping { description "A grouping that expands to allow the symmetric key to be either stored locally, i.e., within the using data model, @@ -189,16 +190,15 @@ module ietf-keystore { 'central-keystore-supported' is not defined, SHOULD augment in custom 'case' statements enabling references to the alternate keystore locations."; - choice local-or-keystore { + choice inline-or-keystore { nacm:default-deny-write; mandatory true; description "A choice between an inlined definition and a definition that exists in the keystore."; - case local { - if-feature "local-definitions-supported"; - if-feature "symmetric-keys"; - container local-definition { + case inline { + if-feature "inline-definitions-supported"; + container inline-definition { description "Container to hold the local key definition."; uses ct:symmetric-key-grouping; @@ -216,7 +216,8 @@ module ietf-keystore { } } } - grouping local-or-keystore-asymmetric-key-grouping { + + grouping inline-or-keystore-asymmetric-key-grouping { description "A grouping that expands to allow the asymmetric key to be either stored locally, i.e., within the using data model, @@ -226,16 +227,15 @@ module ietf-keystore { 'central-keystore-supported' is not defined, SHOULD augment in custom 'case' statements enabling references to the alternate keystore locations."; - choice local-or-keystore { + choice inline-or-keystore { nacm:default-deny-write; mandatory true; description "A choice between an inlined definition and a definition that exists in the keystore."; - case local { - if-feature "local-definitions-supported"; - if-feature "asymmetric-keys"; - container local-definition { + case inline { + if-feature "inline-definitions-supported"; + container inline-definition { description "Container to hold the local key definition."; uses ct:asymmetric-key-pair-grouping; @@ -257,27 +257,27 @@ module ietf-keystore { } } - grouping local-or-keystore-asymmetric-key-with-certs-grouping { + grouping inline-or-keystore-asymmetric-key-with-certs-grouping { description "A grouping that expands to allow an asymmetric key and its associated certificates to be either stored locally, i.e., within the using data model, or a reference to an asymmetric key (and its associated certificates) stored in the keystore. + Servers that do not 'implement' this module, and hence 'central-keystore-supported' is not defined, SHOULD augment in custom 'case' statements enabling references to the alternate keystore locations."; - choice local-or-keystore { + choice inline-or-keystore { nacm:default-deny-write; mandatory true; description "A choice between an inlined definition and a definition that exists in the keystore."; - case local { - if-feature "local-definitions-supported"; - if-feature "asymmetric-keys"; - container local-definition { + case inline { + if-feature "inline-definitions-supported"; + container inline-definition { description "Container to hold the local key definition."; uses ct:asymmetric-key-pair-with-certs-grouping; @@ -297,7 +297,7 @@ module ietf-keystore { } } - grouping local-or-keystore-end-entity-cert-with-key-grouping { + grouping inline-or-keystore-end-entity-cert-with-key-grouping { description "A grouping that expands to allow an end-entity certificate (and its associated asymmetric key pair) to be either stored @@ -308,16 +308,15 @@ module ietf-keystore { 'central-keystore-supported' is not defined, SHOULD augment in custom 'case' statements enabling references to the alternate keystore locations."; - choice local-or-keystore { + choice inline-or-keystore { nacm:default-deny-write; mandatory true; description "A choice between an inlined definition and a definition that exists in the keystore."; - case local { - if-feature "local-definitions-supported"; - if-feature "asymmetric-keys"; - container local-definition { + case inline { + if-feature "inline-definitions-supported"; + container inline-definition { description "Container to hold the local key definition."; uses ct:asymmetric-key-pair-with-cert-grouping; @@ -341,7 +340,7 @@ module ietf-keystore { description "Grouping definition enables use in other contexts. If ever done, implementations MUST augment new 'case' statements - into the various local-or-keystore 'choice' statements to + into the various inline-or-keystore 'choice' statements to supply leafrefs to the model-specific location(s)."; container asymmetric-keys { nacm:default-deny-write; diff --git a/modules/ietf-netconf-server@2022-05-24.yang b/modules/ietf-netconf-server@2023-04-17.yang similarity index 93% rename from modules/ietf-netconf-server@2022-05-24.yang rename to modules/ietf-netconf-server@2023-04-17.yang index c48d5841..ddb05954 100644 --- a/modules/ietf-netconf-server@2022-05-24.yang +++ b/modules/ietf-netconf-server@2023-04-17.yang @@ -29,21 +29,18 @@ module ietf-netconf-server { import ietf-ssh-common { prefix sshcmn; - revision-date 2022-07-18; // stable grouping definitions reference "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; } import ietf-ssh-server { prefix sshs; - revision-date 2022-07-18; // stable grouping definitions reference "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; } import ietf-tls-server { prefix tlss; - revision-date 2022-07-18; // stable grouping definitions reference "RFC FFFF: YANG Groupings for TLS Clients and TLS Servers"; } @@ -54,16 +51,13 @@ module ietf-netconf-server { contact "WG Web: https://datatracker.ietf.org/wg/netconf WG List: NETCONF WG list - Author: Kent Watsen - Author: Gary Wu - Author: Juergen Schoenwaelder - "; + Author: Kent Watsen "; description "This module contains a collection of YANG definitions for configuring NETCONF servers. - Copyright (c) 2022 IETF Trust and the persons identified + Copyright (c) 2023 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with @@ -84,7 +78,7 @@ module ietf-netconf-server { (RFC 8174) when, and only when, they appear in all capitals, as shown here."; - revision 2022-05-24 { + revision 2023-04-17 { description "Initial version"; reference @@ -343,7 +337,7 @@ module ietf-netconf-server { description "The NETCONF server will attempt to connect to the IANA-assigned well-known port for - 'netconf-ch-tls' (4334) if no value is + 'netconf-ch-ssh' (4334) if no value is specified."; } } @@ -457,15 +451,13 @@ module ietf-netconf-server { leaf idle-timeout { type uint16; units "seconds"; - default "3600"; // one hour + default "180"; // three minutes description "Specifies the maximum number of seconds that a NETCONF session may remain idle. A NETCONF session will be dropped if it is idle for an interval longer than this number of seconds. If set to zero, then the server - will never drop a session because it is idle. Sessions - that have a notification subscription active are never - dropped."; + will never drop a session because it is idle."; } list endpoint { key "name"; @@ -551,9 +543,9 @@ module ietf-netconf-server { description "Periodically connect to the NETCONF client. - This connection type increases resource + This connection type decreases resource utilization, albeit with increased delay in - NETCONF client to NETCONF client interactions. + NETCONF client to NETCONF server interactions. The NETCONF client SHOULD gracefully close the connection using upon completing @@ -561,6 +553,10 @@ module ietf-netconf-server { not closed gracefully, the NETCONF server MUST immediately attempt to reestablish the connection. + Connections are established at the same start + time regardless how long the previous connection + stayed open. + In the case that the previous connection is still active (i.e., the NETCONF client has not closed it yet), establishing a new connection is NOT @@ -575,23 +571,30 @@ module ietf-netconf-server { leaf anchor-time { type yang:date-and-time { // constrained to minute-level granularity - pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}' - + '(Z|[\+\-]\d{2}:\d{2})'; + pattern '[0-9]{4}-(1[0-2]|0[1-9])-(0[1-9]|[1-2]' + + '[0-9]|3[0-1])T(0[0-9]|1[0-9]|2[0-3]):[' + + '0-5][0-9]:00(Z|[\+\-]((1[0-3]|0[0-9]):' + + '([0-5][0-9])|14:00))?'; } description "Designates a timestamp before or after which a series of periodic connections are determined. The periodic connections occur at a whole - multiple interval from the anchor time. For - example, for an anchor time is 15 minutes past - midnight and a period interval of 24 hours, then - a periodic connection will occur 15 minutes past - midnight everyday."; + multiple interval from the anchor time. + + If an 'anchor-time' is not provided, then the + server may implicitly set it to the time when + this configuraton is applied (e.g., on boot). + + For example, for an anchor time is 15 minutes + past midnight and a period interval of 24 hours, + then a periodic connection will occur 15 minutes + past midnight everyday."; } leaf idle-timeout { type uint16; units "seconds"; - default "120"; // two minutes + default "180"; // three minutes description "Specifies the maximum number of seconds that a NETCONF session may remain idle. A NETCONF @@ -642,15 +645,15 @@ module ietf-netconf-server { to connect to the NETCONF client."; } leaf max-wait { - type uint16 { - range "1..max"; - } - units "seconds"; - default "5"; - description - "Specifies the amount of time in seconds after which, - if the connection is not established, an endpoint - connection attempt is considered unsuccessful."; + type uint16 { + range "1..max"; + } + units "seconds"; + default "5"; + description + "Specifies the amount of time in seconds after which, + if the connection is not established, an endpoint + connection attempt is considered unsuccessful."; } leaf max-attempts { type uint8 { diff --git a/modules/ietf-ssh-common@2022-07-18.yang b/modules/ietf-ssh-common@2023-04-17.yang similarity index 90% rename from modules/ietf-ssh-common@2022-07-18.yang rename to modules/ietf-ssh-common@2023-04-17.yang index 00f32f4e..d331660f 100644 --- a/modules/ietf-ssh-common@2022-07-18.yang +++ b/modules/ietf-ssh-common@2023-04-17.yang @@ -52,9 +52,8 @@ module ietf-ssh-common { "This module defines a common features and groupings for Secure Shell (SSH). - Copyright (c) 2022 IETF Trust and the persons identified + Copyright (c) 2023 IETF Trust and the persons identified as authors of the code. All rights reserved. - Redistribution and use in source and binary forms, with or without modification, is permitted pursuant to, and subject to the license terms contained in, the Revised @@ -73,7 +72,7 @@ module ietf-ssh-common { (RFC 8174) when, and only when, they appear in all capitals, as shown here."; - revision 2022-07-18 { + revision 2023-04-17 { description "Initial version"; reference @@ -117,11 +116,8 @@ module ietf-ssh-common { } ordered-by user; description - "Acceptable host key algorithms in order of descending - preference. The configured host key algorithms should - be compatible with the algorithm used by the configured - private key. Please see Section 5 of RFC EEEE for - valid combinations. + "Acceptable host key algorithms in order of decreasing + preference. If this leaf-list is not configured (has zero elements) the acceptable host key algorithms are implementation- @@ -139,7 +135,7 @@ module ietf-ssh-common { } ordered-by user; description - "Acceptable key exchange algorithms in order of descending + "Acceptable key exchange algorithms in order of decreasing preference. If this leaf-list is not configured (has zero elements) @@ -156,7 +152,7 @@ module ietf-ssh-common { } ordered-by user; description - "Acceptable encryption algorithms in order of descending + "Acceptable encryption algorithms in order of decreasing preference. If this leaf-list is not configured (has zero elements) @@ -173,7 +169,7 @@ module ietf-ssh-common { } ordered-by user; description - "Acceptable MAC algorithms in order of descending + "Acceptable MAC algorithms in order of decreasing preference. If this leaf-list is not configured (has zero elements) @@ -204,19 +200,22 @@ module ietf-ssh-common { For RSA keys, the minimum size is 1024 bits and the default is 3072 bits. Generally, 3072 bits is considered sufficient. DSA keys must be exactly 1024 - bits as specified by FIPS 186-2. For ECDSA keys, the + bits as specified by FIPS 186-6. For ECDSA keys, the 'bits' value determines the key length by selecting from one of three elliptic curve sizes: 256, 384 or 521 bits. Attempting to use bit lengths other than these three values for ECDSA keys will fail. ECDSA-SK, Ed25519 and Ed25519-SK keys have a fixed length and the 'bits' value, if specified, will be ignored."; + reference + "FIPS 186-6: Digital Signature Standard (DSS)"; } choice private-key-encoding { - default cleartext; + mandatory true; description "A choice amongst optional private key handling."; case cleartext { + if-feature "ct:encrypted-private-keys"; leaf cleartext { type empty; description @@ -225,7 +224,7 @@ module ietf-ssh-common { } } case encrypt { - if-feature "ct:private-key-encryption"; + if-feature "ct:encrypted-private-keys"; container encrypt-with { description "Indicates that the key is to be encrypted using @@ -234,7 +233,7 @@ module ietf-ssh-common { } } case hide { - if-feature "ct:hidden-keys"; + if-feature "ct:hidden-private-keys"; leaf hide { type empty; description diff --git a/modules/ietf-ssh-server@2022-07-18.yang b/modules/ietf-ssh-server@2023-04-17.yang similarity index 76% rename from modules/ietf-ssh-server@2022-07-18.yang rename to modules/ietf-ssh-server@2023-04-17.yang index 2dd04bd9..b5b564e7 100644 --- a/modules/ietf-ssh-server@2022-07-18.yang +++ b/modules/ietf-ssh-server@2023-04-17.yang @@ -35,7 +35,6 @@ module ietf-ssh-server { import ietf-ssh-common { prefix sshcmn; - revision-date 2022-07-18; // stable grouping definitions reference "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; } @@ -46,14 +45,13 @@ module ietf-ssh-server { contact "WG Web: https://datatracker.ietf.org/wg/netconf WG List: NETCONF WG list - Author: Kent Watsen - Author: Gary Wu "; + Author: Kent Watsen "; description - "This module defines reusable groupings for SSH servers that + "This module defines a reusable grouping for SSH servers that can be used as a basis for specific SSH server instances. - Copyright (c) 2022 IETF Trust and the persons identified + Copyright (c) 2023 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with @@ -74,7 +72,7 @@ module ietf-ssh-server { (RFC 8174) when, and only when, they appear in all capitals, as shown here."; - revision 2022-07-18 { + revision 2023-04-17 { description "Initial version"; reference @@ -129,7 +127,6 @@ module ietf-ssh-server { "RFC 4252: The Secure Shell (SSH) Authentication Protocol"; } - feature local-user-auth-none { if-feature "local-users-supported"; description @@ -150,7 +147,7 @@ module ietf-ssh-server { established. Note that this grouping uses fairly typical descendant - node names such that a stack of 'uses' statements will + node names such that a nesting of 'uses' statements will have name conflicts. It is intended that the consuming data model will resolve the issue (e.g., by wrapping the 'uses' statement in a container called @@ -168,12 +165,13 @@ module ietf-ssh-server { min-elements 1; ordered-by user; description - "An ordered list of host keys the SSH server will use to - construct its ordered list of algorithms, when sending - its SSH_MSG_KEXINIT message, as defined in Section 7.1 - of RFC 4253."; + "An ordered list of host keys (see RFC 4251) the SSH + server will use to construct its ordered list of + algorithms, when sending its SSH_MSG_KEXINIT message, + as defined in Section 7.1 of RFC 4253."; reference - "RFC 4253: The Secure Shell (SSH) Transport Layer + "RFC 4251: The Secure Shell (SSH) Protocol Architecture + RFC 4253: The Secure Shell (SSH) Transport Layer Protocol"; leaf name { type string; @@ -190,15 +188,16 @@ module ietf-ssh-server { to be used for the SSH server's host key."; reference "RFC CCCC: A YANG Data Model for a Keystore"; - uses ks:local-or-keystore-asymmetric-key-grouping { - refine "local-or-keystore/local/local-definition" { - must - 'public-key-format = "ct:ssh-public-key-format"'; + uses ks:inline-or-keystore-asymmetric-key-grouping { + refine "inline-or-keystore/inline/inline-definition" { + must 'derived-from-or-self(public-key-format,' + + ' "ct:ssh-public-key-format")'; + } - refine "local-or-keystore/keystore/" + refine "inline-or-keystore/keystore/" + "keystore-reference" { - must 'deref(.)/../ks:public-key-format' - + ' = "ct:ssh-public-key-format"'; + must 'derived-from-or-self(deref(.)/../ks:public-' + + 'key-format, "ct:ssh-public-key-format")'; } } } @@ -211,15 +210,16 @@ module ietf-ssh-server { reference "RFC CCCC: A YANG Data Model for a Keystore"; uses - ks:local-or-keystore-end-entity-cert-with-key-grouping { - refine "local-or-keystore/local/local-definition" { - must 'public-key-format' - + ' = "ct:subject-public-key-info-format"'; + ks:inline-or-keystore-end-entity-cert-with-key-grouping{ + refine "inline-or-keystore/inline/inline-definition" { + must 'derived-from-or-self(public-key-format,' + + ' "ct:subject-public-key-info-format")'; } - refine "local-or-keystore/keystore/keystore-reference" - + "/asymmetric-key" { - must 'deref(.)/../ks:public-key-format' - + ' = "ct:subject-public-key-info-format"'; + refine "inline-or-keystore/keystore/keystore-reference" + + "/asymmetric-key" { + must + 'derived-from-or-self(deref(.)/../ks:public-key-' + + 'format, "ct:subject-public-key-info-format")'; } } } @@ -230,7 +230,11 @@ module ietf-ssh-server { container client-authentication { nacm:default-deny-write; description - "Specifies how the SSH server can authenticate SSH clients."; + "Specifies how the SSH server can be configured to + authenticate SSH clients. See RFC 4252 for a general + discussion about SSH authentication."; + reference + "RFC 4252: The Secure Shell (SSH) Transport Layer"; container users { if-feature "local-users-supported"; description @@ -255,6 +259,9 @@ module ietf-ssh-server { description "The 'user name' for the SSH client, as defined in the SSH_MSG_USERAUTH_REQUEST message in RFC 4253."; + reference + "RFC 4253: The Secure Shell (SSH) Transport Layer + Protocol"; } container public-keys { if-feature "local-user-auth-publickey"; @@ -270,16 +277,17 @@ module ietf-ssh-server { match to a configured public key."; reference "RFC BBBB: A YANG Data Model for a Truststore"; - uses ts:local-or-truststore-public-keys-grouping { - refine "local-or-truststore/local/local-definition" - + "/public-key" { - must 'public-key-format' - + ' = "ct:ssh-public-key-format"'; + uses ts:inline-or-truststore-public-keys-grouping { + refine "inline-or-truststore/inline/inline-definition/" + + "public-key" { + must 'derived-from-or-self(public-key-format,' + + ' "ct:ssh-public-key-format")'; } - refine "local-or-truststore/truststore/" - + "truststore-reference" { - must 'deref(.)/../*/ts:public-key-format' - + ' = "ct:ssh-public-key-format"'; + refine "inline-or-truststore/truststore/truststore-" + + "reference" { + must 'not(deref(.)/../ts:public-key/ts:public-key-' + + 'format[not(derived-from-or-self(., "ct:ssh-' + + 'public-key-format"))])'; } } } @@ -292,28 +300,29 @@ module ietf-ssh-server { container hostbased { if-feature "local-user-auth-hostbased"; presence - "Indicates that hostbased keys have been configured. - This statement is present so the mandatory descendant - nodes do not imply that this node must be - configured."; + "Indicates that hostbased [RFC4252] keys have been + configured. This statement is present so the + mandatory descendant nodes do not imply that this + node must be configured."; description "A set of SSH host keys used by the SSH server to authenticate this user's host. A user's host is authenticated if its host key is an exact match to a configured host key."; reference - "RFC 4253: The Secure Shell (SSH) Transport Layer + "RFC 4252: The Secure Shell (SSH) Transport Layer RFC BBBB: A YANG Data Model for a Truststore"; - uses ts:local-or-truststore-public-keys-grouping { - refine "local-or-truststore/local/local-definition" - + "/public-key" { - must 'public-key-format' - + ' = "ct:ssh-public-key-format"'; + uses ts:inline-or-truststore-public-keys-grouping { + refine "inline-or-truststore/inline/inline-definition/" + + "public-key" { + must 'derived-from-or-self(public-key-format,' + + ' "ct:ssh-public-key-format")'; } - refine "local-or-truststore/truststore" - + "/truststore-reference" { - must 'deref(.)/../*/ts:public-key-format' - + ' = "ct:ssh-public-key-format"'; + refine "inline-or-truststore/truststore/truststore-" + + "reference" { + must 'not(deref(.)/../ts:public-key/ts:public-key-' + + 'format[not(derived-from-or-self(., "ct:ssh-' + + 'public-key-format"))])'; } } } @@ -342,7 +351,7 @@ module ietf-ssh-server { chain of trust to a configured CA certificate."; reference "RFC BBBB: A YANG Data Model for a Truststore"; - uses ts:local-or-truststore-certs-grouping; + uses ts:inline-or-truststore-certs-grouping; } container ee-certs { if-feature "sshcmn:ssh-x509-certs"; @@ -358,7 +367,7 @@ module ietf-ssh-server { to a configured end-entity certificate."; reference "RFC BBBB: A YANG Data Model for a Truststore"; - uses ts:local-or-truststore-certs-grouping; + uses ts:inline-or-truststore-certs-grouping; } } // container client-authentication @@ -378,7 +387,7 @@ module ietf-ssh-server { aliveness of the remote SSH client."; description "Configures the keep-alive policy, to proactively test - the aliveness of the SSL client. An unresponsive SSL + the aliveness of the SSH client. An unresponsive SSH client is dropped after approximately max-wait * max-attempts seconds. Per Section 4 of RFC 4254, the SSH server SHOULD send an SSH_MSG_GLOBAL_REQUEST @@ -395,9 +404,9 @@ module ietf-ssh-server { default "30"; description "Sets the amount of time in seconds after which - if no data has been received from the SSL client, - a SSL-level message will be sent to test the - aliveness of the SSL client."; + if no data has been received from the SSH client, + a SSH-level message will be sent to test the + aliveness of the SSH client."; } leaf max-attempts { type uint8; @@ -405,7 +414,7 @@ module ietf-ssh-server { description "Sets the maximum number of sequential keep-alive messages that can fail to obtain a response from - the SSL client before assuming the SSL client is + the SSH client before assuming the SSH client is no longer alive."; } } diff --git a/modules/ietf-tcp-client@2022-05-24.yang b/modules/ietf-tcp-client@2023-04-17.yang similarity index 89% rename from modules/ietf-tcp-client@2022-05-24.yang rename to modules/ietf-tcp-client@2023-04-17.yang index 4426353e..95e62149 100644 --- a/modules/ietf-tcp-client@2022-05-24.yang +++ b/modules/ietf-tcp-client@2023-04-17.yang @@ -38,7 +38,7 @@ module ietf-tcp-client { "This module defines reusable groupings for TCP clients that can be used as a basis for specific TCP client instances. - Copyright (c) 2022 IETF Trust and the persons identified + Copyright (c) 2023 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with @@ -59,7 +59,7 @@ module ietf-tcp-client { (RFC 8174) when, and only when, they appear in all capitals, as shown here."; - revision 2022-05-24 { + revision 2023-04-17 { description "Initial version"; reference @@ -79,28 +79,39 @@ module ietf-tcp-client { description "Per socket TCP keepalive parameters are configurable for TCP clients on the server implementing this feature."; + reference + "RFC 9293: Transmission Control Protocol (TCP)"; } feature proxy-connect { description "Proxy connection configuration is configurable for - TCP clients on the server implementing this feature."; + TCP clients on the server implementing this feature. + Currently supports SOCKS 4, SOCKS 4a, and SOCKS 5."; + reference + "SOCKS Proceedings: + 1992 Usenix Security Symposium. + OpenSSH message: + SOCKS 4A: A Simple Extension to SOCKS 4 Protocol + https://www.openssh.com/txt/socks4a.protocol + RFC 1928: + SOCKS Protocol Version 5"; } feature socks5-gss-api { description - "Indicates that the server supports authenticating - using GSSAPI when initiating TCP connections via - and SOCKS Version 5 proxy server."; + "Indicates that the server, when acting as a TCP-client, + supports authenticating to a SOCKS Version 5 proxy server + using GSSAPI credentials."; reference "RFC 1928: SOCKS Protocol Version 5"; } feature socks5-username-password { description - "Indicates that the server supports authenticating using - username/password when initiating TCP connections via - and SOCKS Version 5 proxy server."; + "Indicates that the server, when acting as a TCP-client, + supports authenticating to a SOCKS Version 5 proxy server + using 'username' and 'password' credentials."; reference "RFC 1928: SOCKS Protocol Version 5"; } @@ -111,7 +122,7 @@ module ietf-tcp-client { description "A reusable grouping for configuring a TCP client. - Note that this grouping uses fairly typical descendant + Note that this grouping uses fairly typical descendant node names such that a stack of 'uses' statements will have name conflicts. It is intended that the consuming data model will resolve the issue (e.g., by wrapping @@ -138,16 +149,15 @@ module ietf-tcp-client { default "0"; description "The IP port number for the remote peer to establish a - connection with. An invalid default value (0) is used - (instead of 'mandatory true') so that as application - level data model may 'refine' it with an application - specific default port number value."; + connection with. An invalid default value is used + so that importing modules may 'refine' it with the + appropriate default port number value."; } leaf local-address { if-feature "local-binding-supported"; type inet:ip-address; description - "The local IP address/interface (VRF?) to bind to for when + "The local IP address/interface to bind to for when connecting to the remote peer. INADDR_ANY ('0.0.0.0') or INADDR6_ANY ('0:0:0:0:0:0:0:0' a.k.a. '::') MAY be used to explicitly indicate the implicit default, that the server diff --git a/modules/ietf-tcp-common@2022-05-24.yang b/modules/ietf-tcp-common@2023-04-17.yang similarity index 95% rename from modules/ietf-tcp-common@2022-05-24.yang rename to modules/ietf-tcp-common@2023-04-17.yang index e9a927d5..100380ff 100644 --- a/modules/ietf-tcp-common@2022-05-24.yang +++ b/modules/ietf-tcp-common@2023-04-17.yang @@ -20,7 +20,7 @@ module ietf-tcp-common { "This module defines reusable groupings for TCP commons that can be used as a basis for specific TCP common instances. - Copyright (c) 2022 IETF Trust and the persons identified + Copyright (c) 2023 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with @@ -41,7 +41,7 @@ module ietf-tcp-common { (RFC 8174) when, and only when, they appear in all capitals, as shown here."; - revision 2022-05-24 { + revision 2023-04-17 { description "Initial version"; reference @@ -56,7 +56,6 @@ module ietf-tcp-common { } // Groupings - grouping tcp-common-grouping { description "A reusable grouping for configuring TCP parameters common @@ -73,6 +72,9 @@ module ietf-tcp-common { aliveness of the TCP peer. An unresponsive TCP peer is dropped after approximately (idle-time + max-probes * probe-interval) seconds."; + reference + "RFC 9293: + Transmission Control Protocol (TCP), Section 3.8.4.."; leaf idle-time { type uint16 { range "1..max"; diff --git a/modules/ietf-tcp-server@2022-05-24.yang b/modules/ietf-tcp-server@2023-04-17.yang similarity index 96% rename from modules/ietf-tcp-server@2022-05-24.yang rename to modules/ietf-tcp-server@2023-04-17.yang index b465dfe5..73449448 100644 --- a/modules/ietf-tcp-server@2022-05-24.yang +++ b/modules/ietf-tcp-server@2023-04-17.yang @@ -27,12 +27,11 @@ module ietf-tcp-server { Authors: Kent Watsen Michael Scharf "; - description "This module defines reusable groupings for TCP servers that can be used as a basis for specific TCP server instances. - Copyright (c) 2022 IETF Trust and the persons identified + Copyright (c) 2023 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with @@ -53,7 +52,7 @@ module ietf-tcp-server { (RFC 8174) when, and only when, they appear in all capitals, as shown here."; - revision 2022-05-24 { + revision 2023-04-17 { description "Initial version"; reference @@ -66,6 +65,8 @@ module ietf-tcp-server { description "Per socket TCP keepalive parameters are configurable for TCP servers on the server implementing this feature."; + reference + "RFC 9293: Transmission Control Protocol (TCP)"; } // Groupings diff --git a/modules/ietf-tls-common@2022-07-18.yang b/modules/ietf-tls-common@2023-04-17.yang similarity index 97% rename from modules/ietf-tls-common@2022-07-18.yang rename to modules/ietf-tls-common@2023-04-17.yang index fb48c4cd..5ad06f41 100644 --- a/modules/ietf-tls-common@2022-07-18.yang +++ b/modules/ietf-tls-common@2023-04-17.yang @@ -35,7 +35,7 @@ module ietf-tls-common { "This module defines a common features and groupings for Transport Layer Security (TLS). - Copyright (c) 2022 IETF Trust and the persons identified + Copyright (c) 2023 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with @@ -56,7 +56,7 @@ module ietf-tls-common { (RFC 8174) when, and only when, they appear in all capitals, as shown here."; - revision 2022-07-18 { + revision 2023-04-17 { description "Initial version"; reference @@ -271,6 +271,7 @@ module ietf-tls-common { description "A choice amongst optional private key handling."; case cleartext { + if-feature "ct:cleartext-private-keys"; leaf cleartext { type empty; description @@ -279,7 +280,7 @@ module ietf-tls-common { } } case encrypt { - if-feature "ct:private-key-encryption"; + if-feature "ct:encrypted-private-keys"; container encrypt-with { description "Indicates that the key is to be encrypted using @@ -288,7 +289,7 @@ module ietf-tls-common { } } case hide { - if-feature "ct:hidden-keys"; + if-feature "ct:hidden-private-keys"; leaf hide { type empty; description diff --git a/modules/ietf-tls-server@2022-07-18.yang b/modules/ietf-tls-server@2023-04-17.yang similarity index 89% rename from modules/ietf-tls-server@2022-07-18.yang rename to modules/ietf-tls-server@2023-04-17.yang index 971bd18c..70db1502 100644 --- a/modules/ietf-tls-server@2022-07-18.yang +++ b/modules/ietf-tls-server@2023-04-17.yang @@ -29,7 +29,6 @@ module ietf-tls-server { import ietf-tls-common { prefix tlscmn; - revision-date 2022-07-18; // stable grouping definitions reference "RFC FFFF: YANG Groupings for TLS Clients and TLS Servers"; } @@ -41,14 +40,13 @@ module ietf-tls-server { "WG List: NETCONF WG list WG Web: https://datatracker.ietf.org/wg/netconf Author: Kent Watsen - Author: Jeff Hartley - Author: Gary Wu "; + Author: Jeff Hartley "; description "This module defines reusable groupings for TLS servers that can be used as a basis for specific TLS server instances. - Copyright (c) 2022 IETF Trust and the persons identified + Copyright (c) 2023 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with @@ -69,7 +67,7 @@ module ietf-tls-server { (RFC 8174) when, and only when, they appear in all capitals, as shown here."; - revision 2022-07-18 { + revision 2023-04-17 { description "Initial version"; reference @@ -212,15 +210,17 @@ module ietf-tls-server { description "Specifies the server identity using a certificate."; uses - ks:local-or-keystore-end-entity-cert-with-key-grouping{ - refine "local-or-keystore/local/local-definition" { - must 'public-key-format' - + ' = "ct:subject-public-key-info-format"'; + "ks:inline-or-keystore-end-entity-cert-with-key-" + + "grouping" { + refine "inline-or-keystore/inline/inline-definition" { + must 'derived-from-or-self(public-key-format,' + + ' "ct:subject-public-key-info-format")'; } - refine "local-or-keystore/keystore/keystore-reference" + refine "inline-or-keystore/keystore/keystore-reference" + "/asymmetric-key" { - must 'deref(.)/../ks:public-key-format' - + ' = "ct:subject-public-key-info-format"'; + must 'derived-from-or-self(deref(.)/../ks:public-' + + 'key-format, "ct:subject-public-key-info-' + + 'format")'; } } } @@ -231,14 +231,16 @@ module ietf-tls-server { description "Specifies the server identity using a raw private key."; - uses ks:local-or-keystore-asymmetric-key-grouping { - refine "local-or-keystore/local/local-definition" { - must 'public-key-format' - + ' = "ct:subject-public-key-info-format"'; + uses ks:inline-or-keystore-asymmetric-key-grouping { + refine "inline-or-keystore/inline/inline-definition" { + must 'derived-from-or-self(public-key-format,' + + ' "ct:subject-public-key-info-format")'; } - refine "local-or-keystore/keystore/keystore-reference"{ - must 'deref(.)/../ks:public-key-format' - + ' = "ct:subject-public-key-info-format"'; + refine + "inline-or-keystore/keystore/keystore-reference" { + must 'derived-from-or-self(deref(.)/../ks:public-' + + 'key-format, "ct:subject-public-key-info-' + + 'format")'; } } } @@ -249,7 +251,7 @@ module ietf-tls-server { description "Specifies the server identity using a PSK (pre-shared or pairwise-symmetric key)."; - uses ks:local-or-keystore-symmetric-key-grouping; + uses ks:inline-or-keystore-symmetric-key-grouping; leaf id_hint { type string; description @@ -281,7 +283,7 @@ module ietf-tls-server { and the EPSK input fields detailed in I-D draft-ietf-tls-external-psk-importer Section 3.1. The base-key is based upon - ks:local-or-keystore-symmetric-key-grouping + ks:inline-or-keystore-symmetric-key-grouping in order to provide users with flexible and secure storage options."; reference @@ -291,7 +293,7 @@ module ietf-tls-server { External PSKs for TLS I-D.ietf-tls-external-psk-guidance: Guidance for External PSK Usage in TLS"; - uses ks:local-or-keystore-symmetric-key-grouping; + uses ks:inline-or-keystore-symmetric-key-grouping; leaf external-identity { type string; mandatory true; @@ -396,7 +398,7 @@ module ietf-tls-server { chain of trust to a configured CA certificate."; reference "RFC BBBB: A YANG Data Model for a Truststore"; - uses ts:local-or-truststore-certs-grouping; + uses ts:inline-or-truststore-certs-grouping; } container ee-certs { if-feature "client-auth-x509-cert"; @@ -412,7 +414,7 @@ module ietf-tls-server { match to a configured client certificate."; reference "RFC BBBB: A YANG Data Model for a Truststore"; - uses ts:local-or-truststore-certs-grouping; + uses ts:inline-or-truststore-certs-grouping; } container raw-public-keys { if-feature "client-auth-raw-public-key"; @@ -427,16 +429,17 @@ module ietf-tls-server { is an exact match to a configured raw public key."; reference "RFC BBBB: A YANG Data Model for a Truststore"; - uses ts:local-or-truststore-public-keys-grouping { - refine "local-or-truststore/local/local-definition" - + "/public-key" { - must 'public-key-format' - + ' = "ct:subject-public-key-info-format"'; + uses ts:inline-or-truststore-public-keys-grouping { + refine "inline-or-truststore/inline/inline-definition/" + + "public-key" { + must 'derived-from-or-self(public-key-format,' + + ' "ct:subject-public-key-info-format")'; } - refine "local-or-truststore/truststore" - + "/truststore-reference" { - must 'deref(.)/../*/ts:public-key-format' - + ' = "ct:subject-public-key-info-format"'; + refine "inline-or-truststore/truststore/truststore-" + + "reference" { + must 'not(deref(.)/../ts:public-key/ts:public-key-' + + 'format[not(derived-from-or-self(., "ct:subject-' + + 'public-key-info-format"))])'; } } } diff --git a/modules/ietf-truststore@2022-05-24.yang b/modules/ietf-truststore@2023-04-17.yang similarity index 94% rename from modules/ietf-truststore@2022-05-24.yang rename to modules/ietf-truststore@2023-04-17.yang index 7aaf7a29..cd0d875f 100644 --- a/modules/ietf-truststore@2022-05-24.yang +++ b/modules/ietf-truststore@2023-04-17.yang @@ -26,7 +26,7 @@ module ietf-truststore { "This module defines a 'truststore' to centralize management of trust anchors including certificates and public keys. - Copyright (c) 2021 IETF Trust and the persons identified + Copyright (c) 2023 IETF Trust and the persons identified as authors of the code. All rights reserved. Redistribution and use in source and binary forms, with @@ -47,7 +47,7 @@ module ietf-truststore { (RFC 8174) when, and only when, they appear in all capitals, as shown here."; - revision 2022-05-24 { + revision 2023-04-17 { description "Initial version"; reference @@ -65,9 +65,9 @@ module ietf-truststore { 'ietf-truststore' module)."; } - feature local-definitions-supported { + feature inline-definitions-supported { description - "The 'local-definitions-supported' feature indicates that + "The 'inline-definitions-supported' feature indicates that the server supports locally-defined trust anchors."; } feature certificates { @@ -138,7 +138,7 @@ module ietf-truststore { /* Groupings */ /*****************/ - grouping local-or-truststore-certs-grouping { + grouping inline-or-truststore-certs-grouping { description "A grouping that allows the certificates to be either configured locally, within the using data model, or be a @@ -148,15 +148,15 @@ module ietf-truststore { 'central-truststore-supported' is not defined, SHOULD augment in custom 'case' statements enabling references to the alternate truststore locations."; - choice local-or-truststore { + choice inline-or-truststore { nacm:default-deny-write; mandatory true; description "A choice between an inlined definition and a definition that exists in the truststore."; - case local { - if-feature "local-definitions-supported"; - container local-definition { + case inline { + if-feature "inline-definitions-supported"; + container inline-definition { description "A container for locally configured trust anchor certificates."; @@ -191,7 +191,7 @@ module ietf-truststore { } } - grouping local-or-truststore-public-keys-grouping { + grouping inline-or-truststore-public-keys-grouping { description "A grouping that allows the public keys to be either configured locally, within the using data model, or be a @@ -201,15 +201,15 @@ module ietf-truststore { 'central-truststore-supported' is not defined, SHOULD augment in custom 'case' statements enabling references to the alternate truststore locations."; - choice local-or-truststore { + choice inline-or-truststore { nacm:default-deny-write; mandatory true; description "A choice between an inlined definition and a definition that exists in the truststore."; - case local { - if-feature "local-definitions-supported"; - container local-definition { + case inline { + if-feature "inline-definitions-supported"; + container inline-definition { description "A container to hold local public key definitions."; list public-key { @@ -242,7 +242,7 @@ module ietf-truststore { description "A grouping definition that enables use in other contexts. Where used, implementations MUST augment new 'case' - statements into the various local-or-truststore 'choice' + statements into the various inline-or-truststore 'choice' statements to supply leafrefs to the model-specific location(s)."; container certificate-bags { diff --git a/src/config_new.c b/src/config_new.c index b727538a..9aeed73b 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -331,8 +331,7 @@ nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_PUBKE /* it's ssh2 public key */ ret = nc_server_config_new_read_ssh2_pubkey(f, pubkey); *pubkey_type = NC_PUBKEY_FORMAT_SSH2; - } - else { + } else { /* it's probably OpenSSH public key */ ret = nc_server_config_new_read_pubkey_libssh(pubkey_path, pubkey); *pubkey_type = NC_PUBKEY_FORMAT_SSH2; diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index a64a8a14..9d915675 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -57,7 +57,7 @@ nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, /* prepare path where leaves will get inserted */ asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "server-identity/host-key[name='%s']/public-key/local-definition", endpt_name, hostkey_name); + "server-identity/host-key[name='%s']/public-key/inline-definition", endpt_name, hostkey_name); if (!tree_path) { ERRMEM; ret = 1; @@ -428,7 +428,7 @@ nc_server_config_new_ssh_client_auth_pubkey(const struct ly_ctx *ctx, const char /* prepare path where leaves will get inserted */ asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/local-definition/public-key[name='%s']", endpt_name, user_name, pubkey_name); + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", endpt_name, user_name, pubkey_name); if (!tree_path) { ERRMEM; ret = 1; diff --git a/src/config_new_tls.c b/src/config_new_tls.c index 078b73c7..7dafe87a 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -160,7 +160,7 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char } /* prepare path for instertion of leaves later */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate/local-definition", endpt_name); + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate/inline-definition", endpt_name); if (!tree_path) { ERRMEM; ret = 1; @@ -184,7 +184,7 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); } if (ret) { - ERR(NULL, "Unable to find local-definition container."); + ERR(NULL, "Unable to find inline-definition container."); goto cleanup; } @@ -285,7 +285,7 @@ nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char /* prepare path for instertion of leaves later */ asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ee-certs/local-definition/certificate[name='%s']", endpt_name, cert_name); + "client-authentication/ee-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name); if (!tree_path) { ERRMEM; ret = 1; @@ -354,7 +354,7 @@ nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_n /* prepare path for instertion of leaves later */ asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ca-certs/local-definition/certificate[name='%s']", endpt_name, cert_name); + "client-authentication/ca-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name); if (!tree_path) { ERRMEM; ret = 1; diff --git a/src/server_config.c b/src/server_config.c index 174b42c4..4182cbd7 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -323,7 +323,6 @@ equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char return 0; } - int nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count) { @@ -3247,17 +3246,24 @@ nc_server_config_load_modules(struct ly_ctx **ctx) const char *ietf_nectonf_server[] = {"ssh-listen", "tls-listen", "ssh-call-home", "tls-call-home", "central-netconf-server-supported", NULL}; /* all features */ const char *ietf_x509_cert_to_name[] = {NULL}; - /* no private-key-encryption and csr-generation */ + /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification, + * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys + */ const char *ietf_crypto_types[] = { "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format", "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format", - "p10-based-csrs", "certificate-expiration-notification", "hidden-keys", "password-encryption", - "symmetric-key-encryption", NULL + "cleartext-passwords", "cleartext-symmetric-keys", "cleartext-private-keys", NULL }; /* all features */ const char *ietf_tcp_common[] = {"keepalives-supported", NULL}; + /* all features */ + const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL}; + /* all features */ + const char *ietf_tcp_client[] = {"local-binding-supported", "tcp-client-keepalives", "proxy-connect", "socks5-gss-api", "socks5-username-password", NULL}; /* no ssh-x509-certs */ const char *ietf_ssh_common[] = {"transport-params", "public-key-generation", NULL}; + /* no ssh-server-keepalives and local-user-auth-hostbased */ + const char *ietf_ssh_server[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL}; /* all features */ const char *iana_ssh_encryption_algs[] = {NULL}; /* all features */ @@ -3266,12 +3272,14 @@ nc_server_config_load_modules(struct ly_ctx **ctx) const char *iana_ssh_mac_algs[] = {NULL}; /* all features */ const char *iana_ssh_public_key_algs[] = {NULL}; + /* all features */ + const char *iana_crypt_hash[] = {"crypt-hash-md5", "crypt-hash-sha-256", "crypt-hash-sha-512", NULL}; /* no symmetric-keys */ - const char *ietf_keystore[] = {"central-keystore-supported", "local-definitions-supported", "asymmetric-keys", NULL}; - /* no ssh-server-keepalives and local-user-auth-hostbased */ - const char *ietf_ssh_server[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL}; + const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL}; + /* all features */ + const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL}; /* all features */ - const char *ietf_truststore[] = {"central-truststore-supported", "local-definitions-supported", "certificates", "public-keys", NULL}; + const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", "public-key-generation", NULL}; /* all features */ const char *ietf_tls_server[] = { "tls-server-keepalives", "server-ident-x509-cert", "server-ident-raw-public-key", "server-ident-tls12-psk", @@ -3282,19 +3290,17 @@ nc_server_config_load_modules(struct ly_ctx **ctx) const char *libnetconf2_netconf_server[] = {NULL}; const char *module_names[] = { - "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", - "ietf-tcp-common", "ietf-ssh-common", "iana-ssh-encryption-algs", - "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", - "ietf-keystore", "ietf-ssh-server", "ietf-truststore", - "ietf-tls-server", "libnetconf2-netconf-server", NULL + "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", "libnetconf2-netconf-server", NULL }; const char **module_features[] = { - ietf_nectonf_server, ietf_x509_cert_to_name, ietf_crypto_types, - ietf_tcp_common, ietf_ssh_common, iana_ssh_encryption_algs, - iana_ssh_key_exchange_algs, iana_ssh_mac_algs, iana_ssh_public_key_algs, - ietf_keystore, ietf_ssh_server, ietf_truststore, - ietf_tls_server, libnetconf2_netconf_server, NULL + ietf_nectonf_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, libnetconf2_netconf_server, NULL }; for (i = 0; module_names[i] != NULL; i++) { diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c index c5bcbe5b..50eb1d2c 100644 --- a/src/session_client_ssh.c +++ b/src/session_client_ssh.c @@ -379,7 +379,6 @@ nc_client_ssh_auth_hostkey_check(const char *hostname, uint16_t port, ssh_sessio goto error; } - state = ssh_session_is_known_server(session); switch (state) { case SSH_KNOWN_HOSTS_OK: diff --git a/src/session_client_tls.c b/src/session_client_tls.c index 4cfc5e8f..1d4aa120 100644 --- a/src/session_client_tls.c +++ b/src/session_client_tls.c @@ -409,8 +409,7 @@ nc_client_tls_update_opts(struct nc_client_tls_opts *opts, const char *peername) if (!opts->tls_ctx || opts->tls_ctx_change) { SSL_CTX_free(opts->tls_ctx); /* prepare global SSL context, highest available method is negotiated autmatically */ - if (!(opts->tls_ctx = SSL_CTX_new(TLS_client_method()))) - { + if (!(opts->tls_ctx = SSL_CTX_new(TLS_client_method()))) { ERR(NULL, "Unable to create OpenSSL context (%s).", ERR_reason_error_string(ERR_get_error())); rc = -1; goto cleanup; diff --git a/src/session_p.h b/src/session_p.h index a6004466..7935b4ef 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -39,7 +39,6 @@ typedef enum { NC_OP_REPLACE } NC_OPERATION; - /** * Enumeration of key or certificate store type. */ @@ -51,8 +50,8 @@ typedef enum { #ifdef NC_ENABLED_SSH_TLS -#include #include +#include /* seconds */ #define NC_SSH_TIMEOUT 10 diff --git a/tests/test_auth.c b/tests/test_auth.c index 3dd18450..07cf8599 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -52,12 +52,12 @@ const char *data = " \n" " key\n" " \n" - " \n" + " \n" " ct:ssh-public-key-format\n" " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" " ct:rsa-private-key-format\n" " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" + " \n" " \n" " \n" " \n" @@ -66,13 +66,13 @@ const char *data = " \n" " test_pk\n" " \n" - " \n" + " \n" " \n" " test\n" " ct:ssh-public-key-format\n" " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" " \n" - " \n" + " \n" " \n" " \n" " \n" diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c index 837748fc..35e3b1a1 100644 --- a/tests/test_endpt_share_clients.c +++ b/tests/test_endpt_share_clients.c @@ -52,12 +52,12 @@ const char *data = " \n" " hostkey\n" " \n" - " \n" + " \n" " ct:ssh-public-key-format\n" " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" " ct:rsa-private-key-format\n" " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" + " \n" " \n" " \n" " \n" @@ -66,13 +66,13 @@ const char *data = " \n" " client\n" " \n" - " \n" + " \n" " \n" " test\n" " ct:ssh-public-key-format\n" " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -93,12 +93,12 @@ const char *data = " \n" " hostkey\n" " \n" - " \n" + " \n" " ct:ssh-public-key-format\n" " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" " ct:rsa-private-key-format\n" " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" + " \n" " \n" " \n" " \n" @@ -107,13 +107,13 @@ const char *data = " \n" " client2\n" " \n" - " \n" + " \n" " \n" " test\n" " ct:ssh-public-key-format\n" " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" " \n" - " \n" + " \n" " \n" " \n" " \n" diff --git a/tests/test_keystore.c b/tests/test_keystore.c index 8200d0dc..48322a39 100644 --- a/tests/test_keystore.c +++ b/tests/test_keystore.c @@ -61,13 +61,13 @@ const char *data = " \n" " test_ts\n" " \n" - " \n" + " \n" " \n" " test\n" " ct:ssh-public-key-format\n" " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" " \n" - " \n" + " \n" " \n" " \n" " \n" diff --git a/tests/test_replace.c b/tests/test_replace.c index 446ca4ba..6f43d40d 100644 --- a/tests/test_replace.c +++ b/tests/test_replace.c @@ -52,12 +52,12 @@ const char *old_data = " \n" " old_key\n" " \n" - " \n" + " \n" " ct:ssh-public-key-format\n" " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" " ct:rsa-private-key-format\n" " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" + " \n" " \n" " \n" " \n" @@ -91,12 +91,12 @@ const char *new_data = " \n" " new_key\n" " \n" - " \n" + " \n" " ct:ssh-public-key-format\n" " AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDRIB2eNSRWU+HNWRUGKr76ghCLg8RaMlUCps9lBjnc6ggaJl2Q+TOLn8se2wAdK3lYBMz3dcqR+SlU7eB8wJAc=\n" " ct:ec-private-key-format\n" " MHcCAQEEICQ2fr9Jt2xluom0YQQ7HseE8YTo5reZRVcQENKUWOrooAoGCCqGSM49AwEHoUQDQgAENEgHZ41JFZT4c1ZFQYqvvqCEIuDxFoyVQKmz2UGOdzqCBomXZD5M4ufyx7bAB0reVgEzPd1ypH5KVTt4HzAkBw==\n" - " \n" + " \n" " \n" " \n" " \n" @@ -105,13 +105,13 @@ const char *new_data = " \n" " new_user\n" " \n" - " \n" + " \n" " \n" " test\n" " ct:ssh-public-key-format\n" " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" " \n" - " \n" + " \n" " \n" " \n" " \n" diff --git a/tests/test_truststore.c b/tests/test_truststore.c index 9ba1352f..9ed41431 100644 --- a/tests/test_truststore.c +++ b/tests/test_truststore.c @@ -52,12 +52,12 @@ const char *data = " \n" " key\n" " \n" - " \n" + " \n" " ct:ssh-public-key-format\n" " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" " ct:rsa-private-key-format\n" " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" + " \n" " \n" " \n" " \n" diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c index 30ae580f..16e17d2a 100644 --- a/tests/test_two_channels.c +++ b/tests/test_two_channels.c @@ -50,12 +50,12 @@ const char *data = " \n" " key\n" " \n" - " \n" + " \n" " ct:ssh-public-key-format\n" " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" " ct:rsa-private-key-format\n" " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" + " \n" " \n" " \n" " \n" @@ -64,25 +64,25 @@ const char *data = " \n" " test1\n" " \n" - " \n" + " \n" " \n" " client\n" " ct:ssh-public-key-format\n" " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" " \n" - " \n" + " \n" " \n" " \n" " \n" " test2\n" " \n" - " \n" + " \n" " \n" " client\n" " ct:ssh-public-key-format\n" " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" " \n" - " \n" + " \n" " \n" " \n" " \n" From 0d15a62437cbb1e8e8875601c60706eb3be3efb2 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 8 Jun 2023 11:06:42 +0200 Subject: [PATCH 034/134] config UPDATE support for TLS verions and ciphers --- src/config_new_tls.c | 370 +++++++++++++++++++++++++++++++------------ src/server_config.c | 185 +++++++++++++++++++++- src/server_config.h | 35 ++++ src/session.h | 10 ++ src/session_p.h | 3 + tests/test_tls.c | 9 ++ 6 files changed, 506 insertions(+), 106 deletions(-) diff --git a/src/config_new_tls.c b/src/config_new_tls.c index 7dafe87a..1d2939b1 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -15,6 +15,7 @@ #define _GNU_SOURCE +#include #include #include #include @@ -30,108 +31,6 @@ #include "session.h" #include "session_p.h" -API int -nc_server_config_new_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) -{ - int ret = 0; - char *tree_path = NULL; - struct lyd_node *new_tree; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, map_type, name, 1); - NC_CHECK_ARG_RET(NULL, config, 1); - - /* prepare path for instertion of leaves later */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']", endpt_name, id); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } - if (ret) { - ERR(NULL, "Unable to find netconf-server-parameters container."); - goto cleanup; - } - - /* not mandatory */ - if (fingerprint) { - ret = lyd_new_term(new_tree, NULL, "fingerprint", fingerprint, 0, NULL); - if (ret) { - goto cleanup; - } - } - - /* insert map-type */ - switch (map_type) { - case NC_TLS_CTN_SPECIFIED: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:specified", 0, NULL); - break; - case NC_TLS_CTN_SAN_RFC822_NAME: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-rfc822-name", 0, NULL); - break; - case NC_TLS_CTN_SAN_DNS_NAME: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-dns-name", 0, NULL); - break; - case NC_TLS_CTN_SAN_IP_ADDRESS: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-ip-address", 0, NULL); - break; - case NC_TLS_CTN_SAN_ANY: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-any", 0, NULL); - break; - case NC_TLS_CTN_COMMON_NAME: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:common-name", 0, NULL); - break; - case NC_TLS_CTN_UNKNOWN: - default: - ERR(NULL, "Unknown map_type."); - ret = 1; - break; - } - if (ret) { - goto cleanup; - } - - /* insert name */ - ret = lyd_new_term(new_tree, NULL, "name", name, 0, NULL); - if (ret) { - goto cleanup; - } - - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { - goto cleanup; - } - - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; - } - -cleanup: - free(tree_path); - return ret; -} - API int nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *pubkey_path, const char *privkey_path, const char *certificate_path, struct lyd_node **config) @@ -404,3 +303,270 @@ nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_n free(tree_path); return ret; } + +API int +nc_server_config_new_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) +{ + int ret = 0; + char *tree_path = NULL; + struct lyd_node *new_tree; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, map_type, name, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + /* prepare path for instertion of leaves later */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']", endpt_name, id); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } + if (ret) { + ERR(NULL, "Unable to find netconf-server-parameters container."); + goto cleanup; + } + + /* not mandatory */ + if (fingerprint) { + ret = lyd_new_term(new_tree, NULL, "fingerprint", fingerprint, 0, NULL); + if (ret) { + goto cleanup; + } + } + + /* insert map-type */ + switch (map_type) { + case NC_TLS_CTN_SPECIFIED: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:specified", 0, NULL); + break; + case NC_TLS_CTN_SAN_RFC822_NAME: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-rfc822-name", 0, NULL); + break; + case NC_TLS_CTN_SAN_DNS_NAME: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-dns-name", 0, NULL); + break; + case NC_TLS_CTN_SAN_IP_ADDRESS: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-ip-address", 0, NULL); + break; + case NC_TLS_CTN_SAN_ANY: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-any", 0, NULL); + break; + case NC_TLS_CTN_COMMON_NAME: + ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:common-name", 0, NULL); + break; + case NC_TLS_CTN_UNKNOWN: + default: + ERR(NULL, "Unknown map_type."); + ret = 1; + break; + } + if (ret) { + goto cleanup; + } + + /* insert name */ + ret = lyd_new_term(new_tree, NULL, "name", name, 0, NULL); + if (ret) { + goto cleanup; + } + + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(tree_path); + return ret; +} + +API int +nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config) +{ + int ret = 0; + struct lyd_node *new_tree; + char *tree_path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + /* prepare path for instertion of leaves later */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "hello-params/tls-versions", endpt_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } + if (ret) { + goto cleanup; + } + + switch (tls_version) { + case NC_TLS_VERSION_10: + ret = lyd_new_term(new_tree, NULL, "tls-version", "ietf-tls-common:tls10", 0, NULL); + break; + case NC_TLS_VERSION_11: + ret = lyd_new_term(new_tree, NULL, "tls-version", "ietf-tls-common:tls11", 0, NULL); + break; + case NC_TLS_VERSION_12: + ret = lyd_new_term(new_tree, NULL, "tls-version", "ietf-tls-common:tls12", 0, NULL); + break; + case NC_TLS_VERSION_13: + ret = lyd_new_term(new_tree, NULL, "tls-version", "ietf-tls-common:tls13", 0, NULL); + break; + default: + ERR(NULL, "Unknown TLS version."); + ret = 1; + break; + } + if (ret) { + ERR(NULL, "Creating new tls-version node failed."); + goto cleanup; + } + + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(tree_path); + return ret; +} + +API int +nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + uint16_t cipher_count, ...) +{ + int ret = 0; + struct lyd_node *new_tree = NULL, *old = NULL; + va_list ap; + char *tree_path = NULL, *cipher = NULL, *cipher_ident = NULL; + uint16_t i; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + /* prepare path */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/hello-params", endpt_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } + if (ret) { + goto cleanup; + } + + /* delete all older algorithms (if any) se they can be replaced by the new ones */ + lyd_find_path(new_tree, "cipher-suites", 0, &old); + if (old) { + lyd_free_tree(old); + } + + va_start(ap, cipher_count); + for (i = 0; i < cipher_count; i++) { + cipher = va_arg(ap, char *); + + asprintf(&cipher_ident, "iana-tls-cipher-suite-algs:%s", cipher); + if (!cipher_ident) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create the leaf list */ + ret = lyd_new_path(new_tree, ctx, "cipher-suites/cipher-suite", cipher_ident, 0, NULL); + free(cipher_ident); + + if (ret) { + ERR(NULL, "Creating new cipher-suites leaf-list failed."); + goto cleanup; + } + } + + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + va_end(ap); + free(tree_path); + return ret; +} diff --git a/src/server_config.c b/src/server_config.c index 4182cbd7..a143839e 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -16,6 +16,7 @@ #define _GNU_SOURCE #include +#include #include #include #include @@ -668,6 +669,13 @@ nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *b #ifdef NC_ENABLED_SSH_TLS +static void +nc_server_config_tls_del_ciphers(struct nc_server_tls_opts *opts) +{ + free(opts->ciphers); + opts->ciphers = NULL; +} + static void nc_server_config_tls_del_public_key(struct nc_server_tls_opts *opts) { @@ -764,7 +772,7 @@ nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn) } static void -nc_server_config_del_ctns(struct nc_server_tls_opts *opts) +nc_server_config_tls_del_ctns(struct nc_server_tls_opts *opts) { struct nc_ctn *cur, *next; @@ -796,7 +804,8 @@ nc_server_config_del_tls(struct nc_bind *bind, struct nc_server_tls_opts *opts) nc_server_config_tls_del_certs(&opts->ca_certs); nc_server_config_tls_del_certs(&opts->ee_certs); - nc_server_config_del_ctns(opts); + nc_server_config_tls_del_ctns(opts); + nc_server_config_tls_del_ciphers(opts); free(opts); } @@ -2999,6 +3008,163 @@ nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op) return ret; } +static void +nc_server_config_set_tls_version(struct nc_server_tls_opts *opts, NC_TLS_VERSION version, NC_OPERATION op) +{ + if (op == NC_OP_CREATE) { + /* add the version if it isn't there already */ + opts->tls_versions |= version; + } else if ((op == NC_OP_DELETE) && (opts->tls_versions & version)) { + /* delete the version if it is there */ + opts->tls_versions -= version; + } +} + +static int +nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + const char *version = NULL; + + assert(!strcmp(LYD_NAME(node), "tls-version")); + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + version = ((struct lyd_node_term *)node)->value.ident->name; + if (!strcmp(version, "tls10")) { + nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_10, op); + } else if (!strcmp(version, "tls11")) { + nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_11, op); + } else if (!strcmp(version, "tls12")) { + nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_12, op); + } else if (!strcmp(version, "tls13")) { + nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_13, op); + } else { + ERR(NULL, "TLS version \"%s\" not supported.", version); + ret = 1; + goto cleanup; + } + +cleanup: + return ret; +} + +static int +nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher) +{ + int ret = 0; + char *ssl_cipher = NULL; + uint16_t i; + + ssl_cipher = malloc(strlen(cipher) + 1); + if (!ssl_cipher) { + ERRMEM; + ret = 1; + goto cleanup; + } + + for (i = 0; cipher[i]; i++) { + if (cipher[i] == '-') { + /* OpenSSL requires _ instead of - in cipher names */ + ssl_cipher[i] = '_'; + } else { + /* and requires uppercase unlike the identities */ + ssl_cipher[i] = toupper(cipher[i]); + } + } + ssl_cipher[i] = '\0'; + + if (!opts->ciphers) { + /* first entry */ + opts->ciphers = strdup(ssl_cipher); + if (!opts->ciphers) { + ERRMEM; + ret = 1; + goto cleanup; + } + } else { + /* + 1 because of : between entries */ + opts->ciphers = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(ssl_cipher) + 1 + 1); + if (!opts->ciphers) { + ERRMEM; + ret = 1; + goto cleanup; + } + sprintf(opts->ciphers, "%s:%s", opts->ciphers, ssl_cipher); + } + +cleanup: + free(ssl_cipher); + return ret; +} + +static int +nc_server_config_del_concrete_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher) +{ + int cipher_found = 0; + char *haystack, *substr; + size_t cipher_len = strlen(cipher); + + /* delete */ + haystack = opts->ciphers; + while ((substr = strstr(haystack, cipher))) { + /* iterate over all the substrings */ + if (((substr == haystack) && (*(substr + cipher_len) == ':')) || + ((substr != haystack) && (*(substr - 1) == ':') && (*(substr + cipher_len) == ':'))) { + /* either the first element of the string or somewhere in the middle */ + memmove(substr, substr + cipher_len + 1, strlen(substr + cipher_len + 1)); + cipher_found = 1; + break; + } else if ((*(substr - 1) == ':') && (*(substr + cipher_len) == '\0')) { + /* the last element of the string */ + *(substr - 1) = '\0'; + cipher_found = 1; + break; + } + haystack++; + } + + if (!cipher_found) { + ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher); + return 1; + } + + return 0; +} + +static int +nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + const char *cipher = NULL; + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + cipher = ((struct lyd_node_term *)node)->value.ident->name; + if (op == NC_OP_CREATE) { + ret = nc_server_config_create_cipher_suite(endpt->opts.tls, cipher); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + ret = nc_server_config_del_concrete_cipher_suite(endpt->opts.tls, cipher); + if (ret) { + goto cleanup; + } + } + +cleanup: + return ret; +} + #endif /* NC_ENABLED_SSH_TLS */ static int @@ -3152,6 +3318,14 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_fingerprint(node, op)) { goto error; } + } else if (!strcmp(name, "tls-version")) { + if (nc_server_config_tls_version(node, op)) { + goto error; + } + } else if (!strcmp(name, "cipher-suite")) { + if (nc_server_config_cipher_suite(node, op)) { + goto error; + } } #endif /* NC_ENABLED_SSH_TLS */ @@ -3286,6 +3460,7 @@ nc_server_config_load_modules(struct ly_ctx **ctx) "server-ident-tls13-epsk", "client-auth-supported", "client-auth-x509-cert", "client-auth-raw-public-key", "client-auth-tls12-psk", "client-auth-tls13-epsk", NULL }; + const char *iana_tls_cipher_suite_algs[] = {NULL}; /* all features */ const char *libnetconf2_netconf_server[] = {NULL}; @@ -3293,14 +3468,16 @@ nc_server_config_load_modules(struct ly_ctx **ctx) "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", "libnetconf2-netconf-server", NULL + "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs", + "libnetconf2-netconf-server", NULL }; const char **module_features[] = { ietf_nectonf_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, libnetconf2_netconf_server, NULL + ietf_keystore, ietf_truststore, ietf_tls_common, ietf_tls_server, iana_tls_cipher_suite_algs, + libnetconf2_netconf_server, NULL }; for (i = 0; module_names[i] != NULL; i++) { diff --git a/src/server_config.h b/src/server_config.h index ebebf180..2a97dca3 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -328,6 +328,41 @@ int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *end int nc_server_config_new_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 Creates new YANG configuration data nodes for a TLS version. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's contents will be changed. + * @param[in] tls_version TLS version to be used. Call this multiple times to set + * the accepted versions of the TLS protocol and let the client and server negotiate + * the given version. + * @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_new_tls_version(const struct ly_ctx *ctx, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a TLS cipher. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's 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[in] cipher_count Number of ciphers. + * @param[in] ... TLS ciphers. These ciphers MUST be in the format as listed in the + * iana-tls-cipher-suite-algs YANG model (lowercase and separated by dashes). Regardless + * of the TLS protocol version used, all of these ciphers will be tried and some of them + * might not be set (TLS handshake might fail then). For the list of supported ciphers see + * the OpenSSL documentation. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + uint16_t cipher_count, ...); + #endif /* NC_ENABLED_SSH_TLS */ #ifdef __cplusplus diff --git a/src/session.h b/src/session.h index 5f256ec2..52626e8a 100644 --- a/src/session.h +++ b/src/session.h @@ -58,6 +58,16 @@ typedef enum { NC_TLS_CTN_COMMON_NAME /**< common name as username */ } NC_TLS_CTN_MAPTYPE; +/** + * @brief Enumeration of TLS versions. + */ +typedef enum { + NC_TLS_VERSION_10 = 1, /**< TLS1.0 */ + NC_TLS_VERSION_11 = 2, /**< TLS1.1 */ + NC_TLS_VERSION_12 = 4, /**< TLS1.2 */ + NC_TLS_VERSION_13 = 8 /**< TLS1.3 */ +} NC_TLS_VERSION; + #endif /* NC_ENABLED_SSH_TLS */ /** diff --git a/src/session_p.h b/src/session_p.h index 7935b4ef..16100c4c 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -262,6 +262,9 @@ struct nc_server_tls_opts { struct nc_cert_grouping ca_certs; /**< Client certificate authorities */ struct nc_cert_grouping ee_certs; /**< Client end-entity certificates */ + unsigned int tls_versions; /**< TLS versions */ + char *ciphers; /**< TLS ciphers */ + struct nc_ctn *ctn; /**< Cert-to-name entries */ }; diff --git a/tests/test_tls.c b/tests/test_tls.c index bb3867e1..ba427d7f 100644 --- a/tests/test_tls.c +++ b/tests/test_tls.c @@ -153,11 +153,20 @@ setup_f(void **state) ret = nc_server_config_new_tls_client_ca(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); assert_int_equal(ret, 0); + /* create new cert-to-name */ ret = nc_server_config_new_tls_ctn(ctx, "endpt", 1, "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", NC_TLS_CTN_SPECIFIED, "client", &tree); assert_int_equal(ret, 0); + /* limit TLS version to 1.3 */ + ret = nc_server_config_new_tls_version(ctx, "endpt", NC_TLS_VERSION_13, &tree); + assert_int_equal(ret, 0); + + /* set the TLS cipher */ + ret = nc_server_config_new_tls_ciphers(ctx, "endpt", &tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); + assert_int_equal(ret, 0); + /* configure the server based on the data */ ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); From 3f562ccfce7018c1805be541daf516aee8aa9163 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 8 Jun 2023 13:51:54 +0200 Subject: [PATCH 035/134] config BUGFIX fix sprintf and va undef behaviour --- src/config_new_tls.c | 4 ++-- src/server_config.c | 6 ++++-- src/server_config.h | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/config_new_tls.c b/src/config_new_tls.c index 1d2939b1..eb05ba95 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -487,13 +487,13 @@ nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt_nam API int nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - uint16_t cipher_count, ...) + int cipher_count, ...) { int ret = 0; struct lyd_node *new_tree = NULL, *old = NULL; va_list ap; char *tree_path = NULL, *cipher = NULL, *cipher_ident = NULL; - uint16_t i; + int i; NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); diff --git a/src/server_config.c b/src/server_config.c index a143839e..ff0265f8 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -2153,7 +2153,8 @@ nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OP ret = 1; goto cleanup; } - sprintf(*alg_store, "%s,%s", *alg_store, alg); + strcat(*alg_store, ","); + strcat(*alg_store, alg); } } else { /* delete */ @@ -3094,7 +3095,8 @@ nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char ret = 1; goto cleanup; } - sprintf(opts->ciphers, "%s:%s", opts->ciphers, ssl_cipher); + strcat(opts->ciphers, ":"); + strcat(opts->ciphers, ssl_cipher); } cleanup: diff --git a/src/server_config.h b/src/server_config.h index 2a97dca3..d75de3b8 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -361,7 +361,7 @@ int nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - uint16_t cipher_count, ...); + int cipher_count, ...); #endif /* NC_ENABLED_SSH_TLS */ From c2983f31a969c4707d7c89e0d6792f4bdf7626c9 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 15 Jun 2023 16:13:31 +0200 Subject: [PATCH 036/134] config UPDATE implemented CRL for TLS Certificate Revocation List now supported, this means a new dependency - libcurl. --- .github/workflows/libnetconf3-ci.yml | 2 +- CMakeLists.txt | 4 + modules/libnetconf2-netconf-server.yang | 46 +++++ src/config_new_tls.c | 228 ++++++++++++++++++++++++ src/server_config.c | 118 ++++++++++++ src/server_config.h | 50 ++++++ src/session_p.h | 12 ++ src/session_server_tls.c | 44 +++++ tests/CMakeLists.txt | 2 +- tests/data/crl.pem | 12 ++ tests/test_crl.c | 223 +++++++++++++++++++++++ 11 files changed, 739 insertions(+), 2 deletions(-) create mode 100644 tests/data/crl.pem create mode 100644 tests/test_crl.c diff --git a/.github/workflows/libnetconf3-ci.yml b/.github/workflows/libnetconf3-ci.yml index 8b6d2c56..1d41a045 100644 --- a/.github/workflows/libnetconf3-ci.yml +++ b/.github/workflows/libnetconf3-ci.yml @@ -8,7 +8,7 @@ on: - libnetconf3 env: - DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev + DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev libcurl4-openssl-dev jobs: build: diff --git a/CMakeLists.txt b/CMakeLists.txt index 98b4ad88..ac26d47f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,6 +239,10 @@ if(ENABLE_SSH_TLS) list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBSSH_LIBRARIES}) include_directories(${LIBSSH_INCLUDE_DIRS}) + # dependencies - libcurl + find_package(CURL 7.30.0 REQUIRED) + target_link_libraries(netconf2 CURL::libcurl) + # crypt if(${CMAKE_SYSTEM_NAME} MATCHES "QNX") target_link_libraries(netconf2 -llogin) diff --git a/modules/libnetconf2-netconf-server.yang b/modules/libnetconf2-netconf-server.yang index 185dafc1..ec0d6f0a 100644 --- a/modules/libnetconf2-netconf-server.yang +++ b/modules/libnetconf2-netconf-server.yang @@ -27,6 +27,10 @@ module libnetconf2-netconf-server { prefix sshma; } + import ietf-tls-server { + prefix tlss; + } + /* identity ed25519-private-key-format { base ct:private-key-format; @@ -309,4 +313,46 @@ module libnetconf2-netconf-server { must "deref(.)/../*[local-name() = 'tls']"; } } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { + description + "Indicates that the TLS server is using a Certificate Revocation List + to authenticate clients or to deny access for certain certificates. + The given Certificate Revocation List must be PEM or DER encoded."; + + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile"; + + choice certificate-revocation-list { + leaf crl-url { + type string; + description + "An URL from which the Certificate Revocation List will be + downloaded and used. The HTTP protocol works, but other + protocols, such as FTP, may work as well."; + } + + leaf crl-path { + type string; + description + "A path to a Certificate Revocation List file."; + } + + leaf crl-cert-ext { + type empty; + description + "Indicates that the Certificate Revocation List + Distribution Points extension will be used to fetch + Certificate Revocation Lists from. This will be done + for all the configured Certificate Authority certificates."; + + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile, Section 4.2.1.13"; + } + } + } } diff --git a/src/config_new_tls.c b/src/config_new_tls.c index eb05ba95..2a2036ce 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -570,3 +570,231 @@ nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_nam free(tree_path); return ret; } + +API int +nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, const char *path, struct lyd_node **config) +{ + int ret = 0; + struct lyd_node *new_tree, *node = NULL; + char *tree_path = NULL; + struct lys_module *mod; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, path, config, 1); + + /* prepare path for instertion of leaves later */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", endpt_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } + if (ret) { + goto cleanup; + } + + /* delete other choice nodes if they are present */ + lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-url", 0, &node); + lyd_free_tree(node); + lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-cert-ext", 0, &node); + lyd_free_tree(node); + + /* get the wanted module, because parent of the inserted node has a different one */ + mod = ly_ctx_get_module_implemented(ctx, "libnetconf2-netconf-server"); + if (!mod) { + ERR(NULL, "Error getting libnetconf2-netconf-server module."); + ret = 1; + goto cleanup; + } + + ret = lyd_new_term(new_tree, mod, "crl-path", path, 0, NULL); + if (ret) { + ERR(NULL, "Creating new Certificate Revocation List node failed."); + goto cleanup; + } + + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(tree_path); + return ret; +} + +API int +nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *url, struct lyd_node **config) +{ + int ret = 0; + struct lyd_node *new_tree, *node = NULL; + char *tree_path = NULL; + struct lys_module *mod; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, url, config, 1); + + /* prepare path for instertion of leaves later */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", endpt_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } + if (ret) { + goto cleanup; + } + + /* delete other choice nodes if they are present */ + lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-path", 0, &node); + lyd_free_tree(node); + lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-cert-ext", 0, &node); + lyd_free_tree(node); + + /* get the wanted module, because parent of the inserted node has a different one */ + mod = ly_ctx_get_module_implemented(ctx, "libnetconf2-netconf-server"); + if (!mod) { + ERR(NULL, "Error getting libnetconf2-netconf-server module."); + ret = 1; + goto cleanup; + } + + ret = lyd_new_term(new_tree, mod, "crl-url", url, 0, NULL); + if (ret) { + ERR(NULL, "Creating new Certificate Revocation List node failed."); + goto cleanup; + } + + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(tree_path); + return ret; +} + +API int +nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config) +{ + int ret = 0; + struct lyd_node *new_tree, *node = NULL; + char *tree_path = NULL; + struct lys_module *mod; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + /* prepare path for instertion of leaves later */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", endpt_name); + if (!tree_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + if (ret) { + goto cleanup; + } + if (!*config) { + *config = new_tree; + } + + if (!new_tree) { + /* no new nodes were created */ + ret = lyd_find_path(*config, tree_path, 0, &new_tree); + } else { + /* config was NULL */ + ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); + } + if (ret) { + goto cleanup; + } + + /* delete other choice nodes if they are present */ + lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-path", 0, &node); + lyd_free_tree(node); + lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-url", 0, &node); + lyd_free_tree(node); + + /* get the wanted module, because parent of the inserted node has a different one */ + mod = ly_ctx_get_module_implemented(ctx, "libnetconf2-netconf-server"); + if (!mod) { + ERR(NULL, "Error getting libnetconf2-netconf-server module."); + ret = 1; + goto cleanup; + } + + ret = lyd_new_term(new_tree, mod, "crl-cert-ext", NULL, 0, NULL); + if (ret) { + ERR(NULL, "Creating new Certificate Revocation List node failed."); + goto cleanup; + } + + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *config); + if (ret) { + goto cleanup; + } + + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(tree_path); + return ret; +} diff --git a/src/server_config.c b/src/server_config.c index ff0265f8..a94bc098 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -25,6 +25,10 @@ #include +#ifdef NC_ENABLED_SSH_TLS +#include // X509_STORE_free +#endif + #include "compat.h" #include "config.h" #include "log_p.h" @@ -669,6 +673,20 @@ nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *b #ifdef NC_ENABLED_SSH_TLS +static void +nc_server_config_del_url(struct nc_server_tls_opts *opts) +{ + free(opts->crl_url); + opts->crl_url = NULL; +} + +static void +nc_server_config_del_path(struct nc_server_tls_opts *opts) +{ + free(opts->crl_path); + opts->crl_path = NULL; +} + static void nc_server_config_tls_del_ciphers(struct nc_server_tls_opts *opts) { @@ -804,6 +822,11 @@ nc_server_config_del_tls(struct nc_bind *bind, struct nc_server_tls_opts *opts) nc_server_config_tls_del_certs(&opts->ca_certs); nc_server_config_tls_del_certs(&opts->ee_certs); + nc_server_config_del_path(opts); + nc_server_config_del_url(opts); + X509_STORE_free(opts->crl_store); + opts->crl_store = NULL; + nc_server_config_tls_del_ctns(opts); nc_server_config_tls_del_ciphers(opts); @@ -3145,6 +3168,8 @@ nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op) struct nc_endpt *endpt; const char *cipher = NULL; + assert(!strcmp(LYD_NAME(node), "cipher-suite")); + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -3167,6 +3192,87 @@ nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op) return ret; } +static int +nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + + assert(!strcmp(LYD_NAME(node), "crl-url")); + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + nc_server_config_del_url(endpt->opts.tls); + endpt->opts.tls->crl_url = strdup(lyd_get_value(node)); + if (!endpt->opts.tls->crl_url) { + ERRMEM; + ret = 1; + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + nc_server_config_del_url(endpt->opts.tls); + } + +cleanup: + return ret; +} + +static int +nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + + assert(!strcmp(LYD_NAME(node), "crl-path")); + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + nc_server_config_del_path(endpt->opts.tls); + endpt->opts.tls->crl_path = strdup(lyd_get_value(node)); + if (!endpt->opts.tls->crl_path) { + ERRMEM; + ret = 1; + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + nc_server_config_del_path(endpt->opts.tls); + } + +cleanup: + return ret; +} + +static int +nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + + assert(!strcmp(LYD_NAME(node), "crl-cert-ext")); + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + endpt->opts.tls->crl_cert_ext = 1; + } else if (op == NC_OP_DELETE) { + endpt->opts.tls->crl_cert_ext = 0; + } + +cleanup: + return ret; +} + #endif /* NC_ENABLED_SSH_TLS */ static int @@ -3328,6 +3434,18 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION if (nc_server_config_cipher_suite(node, op)) { goto error; } + } else if (!strcmp(name, "crl-url")) { + if (nc_server_config_crl_url(node, op)) { + goto error; + } + } else if (!strcmp(name, "crl-path")) { + if (nc_server_config_crl_path(node, op)) { + goto error; + } + } else if (!strcmp(name, "crl-cert-ext")) { + if (nc_server_config_crl_cert_ext(node, op)) { + goto error; + } } #endif /* NC_ENABLED_SSH_TLS */ diff --git a/src/server_config.h b/src/server_config.h index d75de3b8..02362f29 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -363,6 +363,56 @@ int nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt int nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int cipher_count, ...); +/** + * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via a local file. + * + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's contents will be changed. + * @param[in] path Path to a DER/PEM encoded CRL 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_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, const char *path, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via an URL. + * + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's contents will be changed. + * @param[in] url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. + * The allowed protocols are all the protocols supported by CURL. + * @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_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *url, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via certificate extensions. + * + * The chain of configured Certificate Authorities will be examined. For each certificate in this chain all the + * CRLs from the URLs specified in their extension fields CRL Distribution Points will be downloaded and used. + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, it's 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_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config); + #endif /* NC_ENABLED_SSH_TLS */ #ifdef __cplusplus diff --git a/src/session_p.h b/src/session_p.h index 16100c4c..13dfd319 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -226,6 +226,14 @@ struct nc_cert_grouping { }; }; +/** + * @brief Storing downloaded data via CURL. + */ +struct nc_curl_data { + unsigned char *data; /**< Downloaded data */ + size_t size; /**< Size of downloaded data */ +}; + /** * @brief Cert-to-name entries. */ @@ -261,6 +269,10 @@ struct nc_server_tls_opts { struct nc_cert_grouping ca_certs; /**< Client certificate authorities */ struct nc_cert_grouping ee_certs; /**< Client end-entity certificates */ + char *crl_url; /**< URI to download the CRL from */ + char *crl_path; /**< Path to a CRL file */ + int crl_cert_ext; /**< Indicates to use CA's distribution points to obtain CRLs */ + X509_STORE *crl_store; /**< Stores all the CRLs */ unsigned int tls_versions; /**< TLS versions */ char *ciphers; /**< TLS ciphers */ diff --git a/src/session_server_tls.c b/src/session_server_tls.c index 5f5c6ea5..ea63bc87 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -599,6 +599,7 @@ nc_server_tls_check_crl(X509_STORE *crl_store, X509_STORE_CTX *x509_ctx, X509 *c } static int +<<<<<<< HEAD nc_server_tls_ts_ref_get_certs(const char *referenced_name, struct nc_certificate **certs, uint16_t *cert_count) { uint16_t i; @@ -681,17 +682,29 @@ nc_server_tls_do_preverify(struct nc_session *session, X509_STORE_CTX *x509_ctx, } static int +======= +>>>>>>> d301c76 (config UPDATE implemented CRL for TLS) nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) { X509_NAME *subject; X509_NAME *issuer; X509 *cert; +<<<<<<< HEAD +======= + struct nc_cert_grouping *ee_certs; +>>>>>>> d301c76 (config UPDATE implemented CRL for TLS) char *cp; STACK_OF(X509) * cert_stack; struct nc_session *session; struct nc_server_tls_opts *opts; +<<<<<<< HEAD int rc, depth; +======= + int i, rc, depth; + const char *username = NULL; + NC_TLS_CTN_MAPTYPE map_type = 0; +>>>>>>> d301c76 (config UPDATE implemented CRL for TLS) /* get the thread session */ session = pthread_getspecific(verify_key); @@ -712,14 +725,23 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) /* standard certificate verification failed, so an end-entity client cert must match to continue */ if (!preverify_ok) { +<<<<<<< HEAD /* check current endpoint's end-entity certs */ rc = nc_server_tls_do_preverify(session, x509_ctx, 1); if (rc == -1) { +======= + /* get the store from the current context */ + X509_STORE *store = X509_STORE_CTX_get0_store(x509_ctx); + + if (!store) { + ERR(session, "Error getting store from context (%s).", ERR_reason_error_string(ERR_get_error())); +>>>>>>> d301c76 (config UPDATE implemented CRL for TLS) return 0; } else if (rc == 1) { return 1; } +<<<<<<< HEAD /* no match, continue */ if (opts->endpt_client_ref) { /* check referenced endpoint's end-entity certs */ @@ -727,11 +749,33 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) if (rc == -1) { return 0; } else if (rc == 1) { +======= + /* get the data from the store */ + ee_certs = X509_STORE_get_ex_data(store, 1); + if (!ee_certs) { + ERR(session, "Error getting data from store (%s).", ERR_reason_error_string(ERR_get_error())); + return 0; + } + + for (i = 0; i < ee_certs->cert_count; i++) { + cert = base64der_to_cert(ee_certs->certs[i].data); + rc = cert_pubkey_match(session->opts.server.client_cert, cert); + X509_free(cert); + if (rc) { + /* we are just overriding the failed standard certificate verification (preverify_ok == 0), + * this callback will be called again with the same current certificate and preverify_ok == 1 */ + VRB(session, "Cert verify: fail (%s), but the end-entity certificate is trusted, continuing.", + X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx))); + X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); +>>>>>>> d301c76 (config UPDATE implemented CRL for TLS) return 1; } } +<<<<<<< HEAD /* no match, fail */ +======= +>>>>>>> d301c76 (config UPDATE implemented CRL for TLS) ERR(session, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx))); return 0; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 74b57208..26ce69b6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -37,7 +37,7 @@ endforeach() #append tests depending on SSH/TLS if(ENABLE_SSH_TLS) - list(APPEND tests test_two_channels test_keystore test_config_new test_truststore test_ec test_ed25519 test_replace test_endpt_share_clients test_tls) + list(APPEND tests test_two_channels test_keystore test_config_new test_truststore test_ec test_ed25519 test_replace test_endpt_share_clients test_tls test_crl) endif() foreach(src IN LISTS libsrc) diff --git a/tests/data/crl.pem b/tests/data/crl.pem new file mode 100644 index 00000000..0becd573 --- /dev/null +++ b/tests/data/crl.pem @@ -0,0 +1,12 @@ +-----BEGIN X509 CRL----- +MIIB2zCBxAIBATANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJDWjETMBEGA1UE +CAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQww +CgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhFw0yMzA2MTUxMTMxMzBaFw0z +MzA2MTIxMTMxMzBaMBwwGgIJAJXrkmAO99aQFw0yMzA2MTIxNDAzMTJaoA8wDTAL +BgNVHRQEBAICEAUwDQYJKoZIhvcNAQELBQADggEBAMbxn/kkds6i60o31eQvaI49 +XXQiEnZ+15r8ehkeKv4VOQBeHbddrYuhoaESdVLeB2wzphbLLPAOsUvqHxtM4eO2 +faDDhpquHL3eKsHZA5UyAl9vEHyzONXiSoJvVNvC5dtQHflgUtqKwOnhrvxlUBqV +pcwVWfqE+opm19f8iNaA4OgFn9dFyaRnpgzWILGOykzW+aEzmCpkVYeUgR1RqBm5 +bgpzQBma2Mg9AjWIeTwGozoANt/Q7GJhdmeZEp41iDc1HElFMUyYspClaYfRKzuE +VvrHeKOFQIjhQcoPO6oH5QwYgXKUBFuTJD5who3hHbu+6u3upaJ6RZGcwVa+Ly8= +-----END X509 CRL----- diff --git a/tests/test_crl.c b/tests/test_crl.c new file mode 100644 index 00000000..dcf8da80 --- /dev/null +++ b/tests/test_crl.c @@ -0,0 +1,223 @@ +/** + * @file test_crl.c + * @author Roman Janota + * @brief libnetconf2 TLS CRL test + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 + +struct ly_ctx *ctx; + +struct test_state { + pthread_barrier_t barrier; +}; + +char buffer[512]; +char expected[512]; + +static void +test_msg_callback(const struct nc_session *session, NC_VERB_LEVEL level, const char *msg) +{ + (void) level; + (void) session; + + if (strstr(msg, expected)) { + strcpy(buffer, msg); + } + + printf("%s\n", msg); +} + +static void * +server_thread(void *arg) +{ + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct test_state *state = arg; + + /* set print clb so we get access to messages */ + nc_set_print_clb_session(test_msg_callback); + buffer[0] = '\0'; + strcpy(expected, "revoked per CRL"); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_ERROR); + + assert_int_not_equal(strlen(buffer), 0); + + nc_session_free(session, NULL); + return NULL; +} + +static void * +client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set client cert */ + ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key"); + assert_int_equal(ret, 0); + + /* set client ca */ + ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_tls("127.0.0.1", 10005, NULL); + + nc_session_free(session, NULL); + return NULL; +} + +static void +test_nc_tls(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* create new address and port data */ + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", "10005", &tree); + assert_int_equal(ret, 0); + + /* create new server certificate data */ + ret = nc_server_config_new_tls_server_certificate(ctx, "endpt", NULL, TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &tree); + assert_int_equal(ret, 0); + + /* create new end entity client cert data */ + ret = nc_server_config_new_tls_client_certificate(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); + assert_int_equal(ret, 0); + + /* create new client ca data */ + ret = nc_server_config_new_tls_client_ca(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); + assert_int_equal(ret, 0); + + /* create new cert-to-name */ + ret = nc_server_config_new_tls_ctn(ctx, "endpt", 1, + "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", + NC_TLS_CTN_SPECIFIED, "client", &tree); + assert_int_equal(ret, 0); + + /* limit TLS version to 1.3 */ + ret = nc_server_config_new_tls_version(ctx, "endpt", NC_TLS_VERSION_13, &tree); + assert_int_equal(ret, 0); + + /* set the TLS cipher */ + ret = nc_server_config_new_tls_ciphers(ctx, "endpt", &tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_tls_crl_url(ctx, "endpt", "abc", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_tls_crl_path(ctx, "endpt", TESTS_DIR "/data/crl.pem", &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + ret = nc_server_init(); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_tls, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} From 357f632ed13add98e53a8fe5ac9ac74333d299d7 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 16 Jun 2023 15:18:27 +0200 Subject: [PATCH 037/134] config_new REFACTOR update API calls code --- src/config_new.c | 135 ++++++--- src/config_new.h | 14 + src/config_new_ssh.c | 274 +++--------------- src/config_new_tls.c | 671 +++++++++++-------------------------------- tests/test_crl.c | 2 + 5 files changed, 314 insertions(+), 782 deletions(-) diff --git a/src/config_new.c b/src/config_new.c index 9aeed73b..1e57b258 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -16,6 +16,7 @@ #define _GNU_SOURCE #include +#include #include #include #include @@ -533,6 +534,7 @@ nc_server_config_new_get_keys(const char *privkey_path, const char *pubkey_path, FILE *f_privkey = NULL; char *header = NULL; size_t len = 0; + char *priv = NULL, *pub = NULL; NC_CHECK_ARG_RET(NULL, privkey_path, privkey, pubkey, privkey_type, 1); @@ -557,46 +559,87 @@ nc_server_config_new_get_keys(const char *privkey_path, const char *pubkey_path, if (!strncmp(header, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) { /* it's PKCS8 (X.509) private key */ *privkey_type = NC_PRIVKEY_FORMAT_X509; - ret = nc_server_config_new_get_privkey_openssl(f_privkey, privkey, &priv_pkey); + ret = nc_server_config_new_get_privkey_openssl(f_privkey, &priv, &priv_pkey); } else if (!strncmp(header, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) { /* it's OpenSSH private key */ *privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; - ret = nc_server_config_new_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); + ret = nc_server_config_new_get_privkey_libssh(privkey_path, &priv, &priv_sshkey); } else if (!strncmp(header, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) { /* it's RSA privkey in PKCS1 format */ *privkey_type = NC_PRIVKEY_FORMAT_RSA; - ret = nc_server_config_new_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); + ret = nc_server_config_new_get_privkey_libssh(privkey_path, &priv, &priv_sshkey); } else if (!strncmp(header, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) { /* it's EC privkey in SEC1 format */ *privkey_type = NC_PRIVKEY_FORMAT_EC; - ret = nc_server_config_new_get_privkey_libssh(privkey_path, privkey, &priv_sshkey); + ret = nc_server_config_new_get_privkey_libssh(privkey_path, &priv, &priv_sshkey); } else { ERR(NULL, "Private key format not supported."); ret = 1; goto cleanup; } - if (ret) { goto cleanup; } if (pubkey_path) { - ret = nc_server_config_new_get_pubkey(pubkey_path, pubkey, pubkey_type); + ret = nc_server_config_new_get_pubkey(pubkey_path, &pub, pubkey_type); } else { - ret = nc_server_config_new_privkey_to_pubkey(priv_pkey, priv_sshkey, *privkey_type, pubkey, pubkey_type); + ret = nc_server_config_new_privkey_to_pubkey(priv_pkey, priv_sshkey, *privkey_type, &pub, pubkey_type); } - if (ret) { ERR(NULL, "Getting public key failed."); goto cleanup; } + /* strip pubkey's header and footer only if it's generated from pkcs8 key (using OpenSSL), + * otherwise it's already stripped + */ + if (!pubkey_path && (*privkey_type == NC_PRIVKEY_FORMAT_X509)) { + *pubkey = strdup(pub + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER)); + if (!*pubkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + (*pubkey)[strlen(*pubkey) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER)] = '\0'; + } else { + *pubkey = strdup(pub); + if (!*pubkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + } + + /* strip private key's header and footer */ + if (*privkey_type == NC_PRIVKEY_FORMAT_OPENSSH) { + /* only OpenSSH private keys have different header and footer after processing */ + *privkey = strdup(priv + strlen(NC_OPENSSH_PRIVKEY_HEADER)); + if (!*privkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + (*privkey)[strlen(*privkey) - strlen(NC_OPENSSH_PRIVKEY_FOOTER)] = '\0'; + } else { + /* the rest share the same header and footer */ + *privkey = strdup(priv + strlen(NC_PKCS8_PRIVKEY_HEADER)); + if (!*privkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + (*privkey)[strlen(*privkey) - strlen(NC_PKCS8_PRIVKEY_FOOTER)] = '\0'; + } + cleanup: if (f_privkey) { fclose(f_privkey); } free(header); + free(pub); + free(priv); ssh_key_free(priv_sshkey); EVP_PKEY_free(priv_pkey); @@ -609,72 +652,82 @@ nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_na const char *address, const char *port, struct lyd_node **config) { int ret = 0; - char *tree_path = NULL; - struct lyd_node *new_tree, *port_node; + const char *address_fmt, *port_fmt; NC_CHECK_ARG_RET(NULL, address, port, ctx, endpt_name, config, 1); - /* prepare path for instertion of leaves later */ if (transport == NC_TI_LIBSSH) { - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/tcp-server-parameters", endpt_name); + /* SSH path */ + address_fmt = "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/tcp-server-parameters/local-address"; + port_fmt = "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/tcp-server-parameters/local-port"; } else if (transport == NC_TI_OPENSSL) { - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tcp-server-parameters", endpt_name); + /* TLS path */ + address_fmt = "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tcp-server-parameters/local-address"; + port_fmt = "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tcp-server-parameters/local-port"; } else { ERR(NULL, "Transport not supported."); ret = 1; goto cleanup; } - if (!tree_path) { - ERRMEM; - ret = 1; + + ret = nc_config_new_insert(ctx, config, address, address_fmt, endpt_name); + if (ret) { goto cleanup; } - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + ret = nc_config_new_insert(ctx, config, port, port_fmt, endpt_name); if (ret) { goto cleanup; } - if (!*config) { - *config = new_tree; - } - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } - if (ret) { - ERR(NULL, "Unable to find tcp-server-parameters container."); +cleanup: + return ret; +} + +int +nc_config_new_insert(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...) +{ + int ret = 0; + va_list ap; + char *path = NULL; + + va_start(ap, path_fmt); + + /* create the path from the format */ + ret = vasprintf(&path, path_fmt, ap); + if (ret == -1) { + ERRMEM; + path = NULL; goto cleanup; } - ret = lyd_new_term(new_tree, NULL, "local-address", address, 0, NULL); + /* create the nodes in the path */ + ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); if (ret) { goto cleanup; } - ret = lyd_find_path(new_tree, "local-port", 0, &port_node); - if (!ret) { - ret = lyd_change_term(port_node, port); - } else if (ret == LY_ENOTFOUND) { - ret = lyd_new_term(new_tree, NULL, "local-port", port, 0, NULL); + /* set out param to top level container */ + ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); + if (ret) { + goto cleanup; } - if (ret && (ret != LY_EEXIST) && (ret != LY_ENOT)) { - /* only fail if there was actually an error */ + /* check if top-level container has operation and if not, add it */ + ret = nc_config_new_check_add_operation(ctx, *tree); + if (ret) { goto cleanup; } - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + /* add all default nodes */ + ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { goto cleanup; } + cleanup: - free(tree_path); + free(path); + va_end(ap); return ret; } diff --git a/src/config_new.h b/src/config_new.h index 129998ed..6b49160a 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -16,6 +16,7 @@ #ifndef NC_CONFIG_NEW_H_ #define NC_CONFIG_NEW_H_ +#include #include #include "session_p.h" @@ -85,6 +86,19 @@ const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT forma int nc_config_new_check_add_operation(const struct ly_ctx *ctx, struct lyd_node *top); +/** + * @brief Creates YANG data nodes in a path and gives the final node a value. + * + * @param[in] ctx libyang context + * @param[in, out] tree The YANG data tree where the insertion will happen. On success + * the top level container is always returned. + * @param[in] value Value assigned to the final node in the path. + * @param[in] path_fmt Format of the path. + * @param[in] ... Parameters for the path format, essentially representing the lists' keys. + * @return 0 on success, 1 otherwise. + */ +int nc_config_new_insert(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...); + #ifdef __cplusplus } #endif diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index 9d915675..5960d2c0 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -39,12 +39,10 @@ nc_server_config_new_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 ret = 0; - char *pubkey = NULL, *privkey = NULL, *pubkey_stripped, *privkey_stripped; - struct lyd_node *new_tree; - char *tree_path = NULL; + char *pubkey = NULL, *privkey = NULL; NC_PRIVKEY_FORMAT privkey_type; NC_PUBKEY_FORMAT pubkey_type; - const char *privkey_identity; + const char *privkey_format, *pubkey_format; NC_CHECK_ARG_RET(NULL, privkey_path, config, ctx, endpt_name, hostkey_name, 1); @@ -55,92 +53,40 @@ nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, goto cleanup; } - /* prepare path where leaves will get inserted */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "server-identity/host-key[name='%s']/public-key/inline-definition", endpt_name, hostkey_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path if they weren't there */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - /* find the node where leaves will get inserted */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - if (ret) { - goto cleanup; - } - - /* insert pubkey format */ + /* pubkey format to str */ if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { - ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:ssh-public-key-format", 0, NULL); - } else { - ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:subject-public-key-info-format", 0, NULL); - } - if (ret) { - goto cleanup; - } - - /* strip pubkey's header and footer only if it's generated from pkcs8 key (using OpenSSL), - * otherwise it's already stripped - */ - if (!pubkey_path && (privkey_type == NC_PRIVKEY_FORMAT_X509)) { - pubkey_stripped = pubkey + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER); - pubkey_stripped[strlen(pubkey_stripped) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER)] = '\0'; + pubkey_format = "ietf-crypto-types:ssh-public-key-format"; } else { - pubkey_stripped = pubkey; - } - - /* insert pubkey b64 */ - ret = lyd_new_term(new_tree, NULL, "public-key", pubkey_stripped, 0, NULL); - if (ret) { - goto cleanup; + pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; } /* get privkey identityref value */ - privkey_identity = nc_config_new_privkey_format_to_identityref(privkey_type); - if (!privkey_identity) { + privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type); + if (!privkey_format) { ret = 1; goto cleanup; } - /* insert private key format */ - ret = lyd_new_term(new_tree, NULL, "private-key-format", privkey_identity, 0, NULL); + ret = nc_config_new_insert(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key[name='%s']/public-key/inline-definition/public-key-format", endpt_name, hostkey_name); if (ret) { goto cleanup; } - if (privkey_type == NC_PRIVKEY_FORMAT_OPENSSH) { - /* only OpenSSH private keys have different header and footer after processing */ - privkey_stripped = privkey + strlen(NC_OPENSSH_PRIVKEY_HEADER); - privkey_stripped[strlen(privkey_stripped) - strlen(NC_OPENSSH_PRIVKEY_FOOTER)] = '\0'; - } else { - /* the rest share the same header and footer */ - privkey_stripped = privkey + strlen(NC_PKCS8_PRIVKEY_HEADER); - privkey_stripped[strlen(privkey_stripped) - strlen(NC_PKCS8_PRIVKEY_FOOTER)] = '\0'; - } - - ret = lyd_new_term(new_tree, NULL, "cleartext-private-key", privkey_stripped, 0, NULL); + ret = nc_config_new_insert(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key[name='%s']/public-key/inline-definition/public-key", endpt_name, hostkey_name); if (ret) { goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); + ret = nc_config_new_insert(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key[name='%s']/public-key/inline-definition/private-key-format", endpt_name, hostkey_name); if (ret) { goto cleanup; } - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + ret = nc_config_new_insert(ctx, config, privkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key[name='%s']/public-key/inline-definition/cleartext-private-key", endpt_name, hostkey_name); if (ret) { goto cleanup; } @@ -148,7 +94,6 @@ nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, cleanup: free(privkey); free(pubkey); - free(tree_path); return ret; } @@ -417,69 +362,36 @@ nc_server_config_new_ssh_client_auth_pubkey(const struct ly_ctx *ctx, const char const char *user_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config) { int ret = 0; - char *pubkey = NULL, *tree_path = NULL; - struct lyd_node *new_tree; + char *pubkey = NULL; NC_PUBKEY_FORMAT pubkey_type; + const char *pubkey_format; + /* get pubkey data */ ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_type); if (ret) { goto cleanup; } - /* prepare path where leaves will get inserted */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", endpt_name, user_name, pubkey_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path if they weren't there */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - /* find the node where leaves will get inserted */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - if (ret) { - goto cleanup; - } - - /* insert pubkey format */ + /* get pubkey format */ if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { - ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:ssh-public-key-format", 0, NULL); + pubkey_format = "ietf-crypto-types:ssh-public-key-format"; } else { - ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:subject-public-key-info-format", 0, NULL); - } - if (ret) { - goto cleanup; + pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; } - /* insert pubkey b64 */ - ret = lyd_new_term(new_tree, NULL, "public-key", pubkey, 0, NULL); + ret = nc_config_new_insert(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/public-key-format", endpt_name, user_name, pubkey_name); if (ret) { goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { - goto cleanup; - } - - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + ret = nc_config_new_insert(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/public-key", endpt_name, user_name, pubkey_name); if (ret) { goto cleanup; } cleanup: - free(tree_path); free(pubkey); return ret; } @@ -489,38 +401,13 @@ nc_server_config_new_ssh_client_auth_password(const struct ly_ctx *ctx, const ch const char *user_name, const char *password, struct lyd_node **config) { int ret = 0; - char *tree_path = NULL, *hashed_pw = NULL; - struct lyd_node *new_tree; + char *hashed_pw = NULL; const char *salt = "$6$idsizuippipk$"; #ifdef HAVE_CRYPT_R struct crypt_data cdata; #endif - /* prepare path where the leaf will get inserted */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']", endpt_name, user_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path if they weren't there */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - /* find the node where the leaf will get inserted */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - if (ret) { - goto cleanup; - } - #ifdef HAVE_CRYPT_R cdata.initialized = 0; hashed_pw = crypt_r(password, salt, &data); @@ -536,26 +423,13 @@ nc_server_config_new_ssh_client_auth_password(const struct ly_ctx *ctx, const ch goto cleanup; } - /* insert SHA-512 hashed password */ - ret = lyd_new_term(new_tree, NULL, "password", hashed_pw, 0, NULL); - if (ret) { - goto cleanup; - } - - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { - goto cleanup; - } - - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + ret = nc_config_new_insert(ctx, config, hashed_pw, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/password", endpt_name, user_name); if (ret) { goto cleanup; } cleanup: - free(tree_path); return ret; } @@ -564,53 +438,14 @@ nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const char * const char *user_name, struct lyd_node **config) { int ret = 0; - char *tree_path = NULL; - struct lyd_node *new_tree; - - /* prepare path where the leaf will get inserted */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']", endpt_name, user_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path if they weren't there */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - /* find the node where the leaf will get inserted */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - if (ret) { - goto cleanup; - } - - /* insert none leaf */ - ret = lyd_new_term(new_tree, NULL, "none", NULL, 0, NULL); - if (ret) { - goto cleanup; - } - - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { - goto cleanup; - } - - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + ret = nc_config_new_insert(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/none", endpt_name, user_name); if (ret) { goto cleanup; } cleanup: - free(tree_path); return ret; } @@ -619,60 +454,19 @@ nc_server_config_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, const const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) { int ret = 0; - char *tree_path = NULL; - struct lyd_node *new_tree; - - /* prepare path where the leaf will get inserted */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - /* create all the nodes in the path if they weren't there */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); + ret = nc_config_new_insert(ctx, config, pam_config_name, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive/pam-config-file-name", endpt_name, user_name); if (ret) { goto cleanup; } - if (!*config) { - *config = new_tree; - } - /* find the node where the leaf will get inserted */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - if (ret) { - goto cleanup; - } - - /* insert file-name leaf */ - ret = lyd_new_term(new_tree, NULL, "pam-config-file-name", pam_config_name, 0, NULL); - if (ret) { - goto cleanup; - } - - if (pam_config_dir) { - /* insert file-path leaf */ - ret = lyd_new_term(new_tree, NULL, "pam-config-file-dir", pam_config_dir, 0, NULL); - if (ret) { - goto cleanup; - } - } - - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { - goto cleanup; - } - - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + ret = nc_config_new_insert(ctx, config, pam_config_dir, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive/pam-config-file-dir", endpt_name, user_name); if (ret) { goto cleanup; } cleanup: - free(tree_path); return ret; } diff --git a/src/config_new_tls.c b/src/config_new_tls.c index 2a2036ce..e0d03416 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -36,11 +36,10 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char const char *privkey_path, const char *certificate_path, struct lyd_node **config) { int ret = 0; - char *tree_path = NULL, *privkey = NULL, *pubkey = NULL, *pubkey_stripped = NULL, *privkey_stripped, *cert = NULL; - struct lyd_node *new_tree; + char *privkey = NULL, *pubkey = NULL, *cert = NULL; NC_PRIVKEY_FORMAT privkey_type; NC_PUBKEY_FORMAT pubkey_type; - const char *privkey_identity; + const char *privkey_format, *pubkey_format; NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, certificate_path, 1); NC_CHECK_ARG_RET(NULL, config, 1); @@ -52,108 +51,53 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char goto cleanup; } + /* get cert data from file */ ret = nc_server_config_new_read_certificate(certificate_path, &cert); if (ret) { ERR(NULL, "Getting certificate from file \"%s\" failed.", certificate_path); goto cleanup; } - /* prepare path for instertion of leaves later */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate/inline-definition", endpt_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } - if (ret) { - ERR(NULL, "Unable to find inline-definition container."); - goto cleanup; - } - - /* insert pubkey format */ + /* get pubkey format str */ if (pubkey_type == NC_PUBKEY_FORMAT_X509) { - ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:public-key-info-format", 0, NULL); + pubkey_format = "ietf-crypto-types:public-key-info-format"; } else { - ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:ssh-public-key-format", 0, NULL); - } - if (ret) { - goto cleanup; - } - - /* strip pubkey's header and footer only if it's generated from pkcs8 key (using OpenSSL), - * otherwise it's already stripped - */ - if (!pubkey_path && (privkey_type == NC_PRIVKEY_FORMAT_X509)) { - pubkey_stripped = pubkey + strlen("-----BEGIN PUBLIC KEY-----") + 1; - pubkey_stripped[strlen(pubkey_stripped) - strlen("-----END PUBLIC KEY-----") - 2] = '\0'; - } else { - pubkey_stripped = pubkey; - } - - /* insert pubkey b64 */ - ret = lyd_new_term(new_tree, NULL, "public-key", pubkey_stripped, 0, NULL); - if (ret) { - goto cleanup; + pubkey_format = "ietf-crypto-types:ssh-public-key-format"; } /* get privkey identityref value */ - privkey_identity = nc_config_new_privkey_format_to_identityref(privkey_type); - if (!privkey_identity) { + privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type); + if (!privkey_format) { ret = 1; goto cleanup; } - /* insert private key format */ - ret = lyd_new_term(new_tree, NULL, "private-key-format", privkey_identity, 0, NULL); + ret = nc_config_new_insert(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/inline-definition/public-key-format", endpt_name); if (ret) { goto cleanup; } - if (privkey_type == NC_PRIVKEY_FORMAT_OPENSSH) { - /* only OpenSSH private keys have different header and footer after processing */ - privkey_stripped = privkey + strlen(NC_OPENSSH_PRIVKEY_HEADER); - privkey_stripped[strlen(privkey_stripped) - strlen(NC_OPENSSH_PRIVKEY_FOOTER)] = '\0'; - } else { - /* the rest share the same header and footer */ - privkey_stripped = privkey + strlen(NC_PKCS8_PRIVKEY_HEADER); - privkey_stripped[strlen(privkey_stripped) - strlen(NC_PKCS8_PRIVKEY_FOOTER)] = '\0'; - } - - ret = lyd_new_term(new_tree, NULL, "cleartext-private-key", privkey_stripped, 0, NULL); + ret = nc_config_new_insert(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/inline-definition/public-key", endpt_name); if (ret) { goto cleanup; } - ret = lyd_new_term(new_tree, NULL, "cert-data", cert, 0, NULL); + ret = nc_config_new_insert(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/inline-definition/private-key-format", endpt_name); if (ret) { goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); + ret = nc_config_new_insert(ctx, config, privkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/inline-definition/cleartext-private-key", endpt_name); if (ret) { goto cleanup; } - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + ret = nc_config_new_insert(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/inline-definition/cert-data", endpt_name); if (ret) { goto cleanup; } @@ -162,7 +106,6 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char free(privkey); free(pubkey); free(cert); - free(tree_path); return ret; } @@ -171,8 +114,7 @@ nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char const char *cert_path, struct lyd_node **config) { int ret = 0; - struct lyd_node *new_tree; - char *tree_path = NULL, *cert = NULL; + char *cert = NULL; NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); @@ -182,56 +124,14 @@ nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char goto cleanup; } - /* prepare path for instertion of leaves later */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ee-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } - if (ret) { - goto cleanup; - } - - /* insert cert-data */ - ret = lyd_new_term(new_tree, NULL, "cert-data", cert, 0, NULL); - if (ret) { - goto cleanup; - } - - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { - goto cleanup; - } - - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + ret = nc_config_new_insert(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/inline-definition/certificate[name='%s']/cert-data", endpt_name, cert_name); if (ret) { goto cleanup; } cleanup: free(cert); - free(tree_path); return ret; } @@ -240,8 +140,7 @@ nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_n const char *cert_path, struct lyd_node **config) { int ret = 0; - struct lyd_node *new_tree; - char *tree_path = NULL, *cert = NULL; + char *cert = NULL; NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); @@ -251,237 +150,122 @@ nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_n goto cleanup; } - /* prepare path for instertion of leaves later */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ca-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } - if (ret) { - goto cleanup; - } - - /* insert cert-data */ - ret = lyd_new_term(new_tree, NULL, "cert-data", cert, 0, NULL); - if (ret) { - goto cleanup; - } - - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { - goto cleanup; - } - - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + ret = nc_config_new_insert(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/inline-definition/certificate[name='%s']/cert-data", endpt_name, cert_name); if (ret) { goto cleanup; } cleanup: free(cert); - free(tree_path); return ret; } +static const char * +nc_config_new_tls_maptype2str(NC_TLS_CTN_MAPTYPE map_type) +{ + switch (map_type) { + case NC_TLS_CTN_SPECIFIED: + return "ietf-x509-cert-to-name:specified"; + case NC_TLS_CTN_SAN_RFC822_NAME: + return "ietf-x509-cert-to-name:san-rfc822-name"; + case NC_TLS_CTN_SAN_DNS_NAME: + return "ietf-x509-cert-to-name:san-dns-name"; + case NC_TLS_CTN_SAN_IP_ADDRESS: + return "ietf-x509-cert-to-name:san-ip-address"; + case NC_TLS_CTN_SAN_ANY: + return "ietf-x509-cert-to-name:san-any"; + case NC_TLS_CTN_COMMON_NAME: + return "ietf-x509-cert-to-name:common-name"; + case NC_TLS_CTN_UNKNOWN: + default: + ERR(NULL, "Unknown map_type."); + return NULL; + } +} + API int nc_server_config_new_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) { int ret = 0; - char *tree_path = NULL; - struct lyd_node *new_tree; + const char *map; NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, map_type, name, 1); NC_CHECK_ARG_RET(NULL, config, 1); - /* prepare path for instertion of leaves later */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']", endpt_name, id); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } - if (ret) { - ERR(NULL, "Unable to find netconf-server-parameters container."); - goto cleanup; - } - - /* not mandatory */ if (fingerprint) { - ret = lyd_new_term(new_tree, NULL, "fingerprint", fingerprint, 0, NULL); + /* optional */ + ret = nc_config_new_insert(ctx, config, fingerprint, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/fingerprint", endpt_name, id); if (ret) { goto cleanup; } } - /* insert map-type */ - switch (map_type) { - case NC_TLS_CTN_SPECIFIED: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:specified", 0, NULL); - break; - case NC_TLS_CTN_SAN_RFC822_NAME: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-rfc822-name", 0, NULL); - break; - case NC_TLS_CTN_SAN_DNS_NAME: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-dns-name", 0, NULL); - break; - case NC_TLS_CTN_SAN_IP_ADDRESS: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-ip-address", 0, NULL); - break; - case NC_TLS_CTN_SAN_ANY: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:san-any", 0, NULL); - break; - case NC_TLS_CTN_COMMON_NAME: - ret = lyd_new_term(new_tree, NULL, "map-type", "ietf-x509-cert-to-name:common-name", 0, NULL); - break; - case NC_TLS_CTN_UNKNOWN: - default: - ERR(NULL, "Unknown map_type."); + /* get map str */ + map = nc_config_new_tls_maptype2str(map_type); + if (!map) { ret = 1; - break; - } - if (ret) { - goto cleanup; - } - - /* insert name */ - ret = lyd_new_term(new_tree, NULL, "name", name, 0, NULL); - if (ret) { goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); + ret = nc_config_new_insert(ctx, config, map, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/map-type", endpt_name, id); if (ret) { goto cleanup; } - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + ret = nc_config_new_insert(ctx, config, name, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/name", endpt_name, id); if (ret) { goto cleanup; } cleanup: - free(tree_path); return ret; } -API int -nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config) +static const char * +nc_config_new_tls_tlsversion2str(NC_TLS_VERSION version) { - int ret = 0; - struct lyd_node *new_tree; - char *tree_path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - /* prepare path for instertion of leaves later */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "hello-params/tls-versions", endpt_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } - if (ret) { - goto cleanup; - } - - switch (tls_version) { + switch (version) { case NC_TLS_VERSION_10: - ret = lyd_new_term(new_tree, NULL, "tls-version", "ietf-tls-common:tls10", 0, NULL); - break; + return "ietf-tls-common:tls10"; case NC_TLS_VERSION_11: - ret = lyd_new_term(new_tree, NULL, "tls-version", "ietf-tls-common:tls11", 0, NULL); - break; + return "ietf-tls-common:tls11"; case NC_TLS_VERSION_12: - ret = lyd_new_term(new_tree, NULL, "tls-version", "ietf-tls-common:tls12", 0, NULL); - break; + return "ietf-tls-common:tls12"; case NC_TLS_VERSION_13: - ret = lyd_new_term(new_tree, NULL, "tls-version", "ietf-tls-common:tls13", 0, NULL); - break; + return "ietf-tls-common:tls13"; default: ERR(NULL, "Unknown TLS version."); - ret = 1; - break; - } - if (ret) { - ERR(NULL, "Creating new tls-version node failed."); - goto cleanup; + return NULL; } +} - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { +API int +nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config) +{ + int ret = 0; + const char *version; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + version = nc_config_new_tls_tlsversion2str(tls_version); + if (!version) { + ret = 1; goto cleanup; } - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + ret = nc_config_new_insert(ctx, config, version, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "hello-params/tls-versions/tls-version", endpt_name); if (ret) { goto cleanup; } cleanup: - free(tree_path); return ret; } @@ -490,84 +274,52 @@ nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_nam int cipher_count, ...) { int ret = 0; - struct lyd_node *new_tree = NULL, *old = NULL; + struct lyd_node *old = NULL; va_list ap; - char *tree_path = NULL, *cipher = NULL, *cipher_ident = NULL; + char *cipher = NULL, *cipher_ident = NULL, *old_path = NULL; int i; NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - /* prepare path */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/hello-params", endpt_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } + va_start(ap, cipher_count); - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } - if (ret) { + ret = asprintf(&old_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/hello-params/cipher-suites", endpt_name); + if (ret == -1) { + ERRMEM; + old_path = NULL; goto cleanup; } /* delete all older algorithms (if any) se they can be replaced by the new ones */ - lyd_find_path(new_tree, "cipher-suites", 0, &old); - if (old) { + ret = lyd_find_path(*config, old_path, 0, &old); + if (!ret) { lyd_free_tree(old); } - va_start(ap, cipher_count); for (i = 0; i < cipher_count; i++) { cipher = va_arg(ap, char *); - asprintf(&cipher_ident, "iana-tls-cipher-suite-algs:%s", cipher); - if (!cipher_ident) { + ret = asprintf(&cipher_ident, "iana-tls-cipher-suite-algs:%s", cipher); + if (ret == -1) { ERRMEM; ret = 1; goto cleanup; } - /* create the leaf list */ - ret = lyd_new_path(new_tree, ctx, "cipher-suites/cipher-suite", cipher_ident, 0, NULL); - free(cipher_ident); - + ret = nc_config_new_insert(ctx, config, cipher_ident, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/hello-params/cipher-suites/cipher-suite", endpt_name); if (ret) { - ERR(NULL, "Creating new cipher-suites leaf-list failed."); goto cleanup; } - } - - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { - goto cleanup; - } - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; + free(cipher_ident); + cipher_ident = NULL; } cleanup: va_end(ap); - free(tree_path); + free(old_path); return ret; } @@ -575,75 +327,48 @@ API int nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, const char *path, struct lyd_node **config) { int ret = 0; - struct lyd_node *new_tree, *node = NULL; - char *tree_path = NULL; - struct lys_module *mod; + struct lyd_node *node = NULL; + char *url_path = NULL, *ext_path = NULL; NC_CHECK_ARG_RET(NULL, ctx, endpt_name, path, config, 1); - /* prepare path for instertion of leaves later */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", endpt_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } + ret = nc_config_new_insert(ctx, config, path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-path", endpt_name); if (ret) { goto cleanup; } - /* delete other choice nodes if they are present */ - lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-url", 0, &node); - lyd_free_tree(node); - lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-cert-ext", 0, &node); - lyd_free_tree(node); - - /* get the wanted module, because parent of the inserted node has a different one */ - mod = ly_ctx_get_module_implemented(ctx, "libnetconf2-netconf-server"); - if (!mod) { - ERR(NULL, "Error getting libnetconf2-netconf-server module."); + if (asprintf(&url_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-url", endpt_name) == -1) { + ERRMEM; + url_path = NULL; ret = 1; goto cleanup; } - ret = lyd_new_term(new_tree, mod, "crl-path", path, 0, NULL); - if (ret) { - ERR(NULL, "Creating new Certificate Revocation List node failed."); + if (asprintf(&ext_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-cert-ext", endpt_name) == -1) { + ERRMEM; + ext_path = NULL; + ret = 1; goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { - goto cleanup; + /* delete other choice nodes if they are present */ + ret = lyd_find_path(*config, url_path, 0, &node); + if (!ret) { + lyd_free_tree(node); } - - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; + ret = lyd_find_path(*config, ext_path, 0, &node); + if (!ret) { + lyd_free_tree(node); } + /* don't care about the return values from lyd_find_path */ + ret = 0; cleanup: - free(tree_path); + free(url_path); + free(ext_path); return ret; } @@ -651,75 +376,48 @@ API int nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *url, struct lyd_node **config) { int ret = 0; - struct lyd_node *new_tree, *node = NULL; - char *tree_path = NULL; - struct lys_module *mod; + struct lyd_node *node = NULL; + char *crl_path = NULL, *ext_path = NULL; NC_CHECK_ARG_RET(NULL, ctx, endpt_name, url, config, 1); - /* prepare path for instertion of leaves later */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", endpt_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } - - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } + ret = nc_config_new_insert(ctx, config, url, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-url", endpt_name); if (ret) { goto cleanup; } - /* delete other choice nodes if they are present */ - lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-path", 0, &node); - lyd_free_tree(node); - lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-cert-ext", 0, &node); - lyd_free_tree(node); - - /* get the wanted module, because parent of the inserted node has a different one */ - mod = ly_ctx_get_module_implemented(ctx, "libnetconf2-netconf-server"); - if (!mod) { - ERR(NULL, "Error getting libnetconf2-netconf-server module."); + if (asprintf(&crl_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-path", endpt_name) == -1) { + ERRMEM; + crl_path = NULL; ret = 1; goto cleanup; } - ret = lyd_new_term(new_tree, mod, "crl-url", url, 0, NULL); - if (ret) { - ERR(NULL, "Creating new Certificate Revocation List node failed."); + if (asprintf(&ext_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-cert-ext", endpt_name) == -1) { + ERRMEM; + ext_path = NULL; + ret = 1; goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { - goto cleanup; + /* delete other choice nodes if they are present */ + ret = lyd_find_path(*config, crl_path, 0, &node); + if (!ret) { + lyd_free_tree(node); } - - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; + ret = lyd_find_path(*config, ext_path, 0, &node); + if (!ret) { + lyd_free_tree(node); } + /* don't care about the return values from lyd_find_path */ + ret = 0; cleanup: - free(tree_path); + free(crl_path); + free(ext_path); return ret; } @@ -727,74 +425,45 @@ API int nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config) { int ret = 0; - struct lyd_node *new_tree, *node = NULL; - char *tree_path = NULL; - struct lys_module *mod; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - /* prepare path for instertion of leaves later */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", endpt_name); - if (!tree_path) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree); - if (ret) { - goto cleanup; - } - if (!*config) { - *config = new_tree; - } + struct lyd_node *node = NULL; + char *crl_path = NULL, *url_path = NULL; - if (!new_tree) { - /* no new nodes were created */ - ret = lyd_find_path(*config, tree_path, 0, &new_tree); - } else { - /* config was NULL */ - ret = lyd_find_path(new_tree, tree_path, 0, &new_tree); - } + ret = nc_config_new_insert(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-cert-ext", endpt_name); if (ret) { goto cleanup; } - /* delete other choice nodes if they are present */ - lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-path", 0, &node); - lyd_free_tree(node); - lyd_find_path(new_tree, "libnetconf2-netconf-server:crl-url", 0, &node); - lyd_free_tree(node); - - /* get the wanted module, because parent of the inserted node has a different one */ - mod = ly_ctx_get_module_implemented(ctx, "libnetconf2-netconf-server"); - if (!mod) { - ERR(NULL, "Error getting libnetconf2-netconf-server module."); + if (asprintf(&crl_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-path", endpt_name) == -1) { + ERRMEM; + crl_path = NULL; ret = 1; goto cleanup; } - ret = lyd_new_term(new_tree, mod, "crl-cert-ext", NULL, 0, NULL); - if (ret) { - ERR(NULL, "Creating new Certificate Revocation List node failed."); + if (asprintf(&url_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-url", endpt_name) == -1) { + ERRMEM; + url_path = NULL; + ret = 1; goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); - if (ret) { - goto cleanup; + /* delete other choice nodes if they are present */ + ret = lyd_find_path(*config, crl_path, 0, &node); + if (!ret) { + lyd_free_tree(node); } - - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; + ret = lyd_find_path(*config, url_path, 0, &node); + if (!ret) { + lyd_free_tree(node); } + /* don't care about the return values from lyd_find_path */ + ret = 0; cleanup: - free(tree_path); + free(crl_path); + free(url_path); return ret; } diff --git a/tests/test_crl.c b/tests/test_crl.c index dcf8da80..db8d83c0 100644 --- a/tests/test_crl.c +++ b/tests/test_crl.c @@ -173,9 +173,11 @@ setup_f(void **state) ret = nc_server_config_new_tls_ciphers(ctx, "endpt", &tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); assert_int_equal(ret, 0); + /* set this node, but it should be deleted by the next call, bcs only one choice node can be present */ ret = nc_server_config_new_tls_crl_url(ctx, "endpt", "abc", &tree); assert_int_equal(ret, 0); + /* set path to a CRL file */ ret = nc_server_config_new_tls_crl_path(ctx, "endpt", TESTS_DIR "/data/crl.pem", &tree); assert_int_equal(ret, 0); From 914e86fb76e1f5673ea939717212c4b3a5864491 Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 19 Jun 2023 10:47:49 +0200 Subject: [PATCH 038/134] config UPDATE add sharing TLS endpts client certs --- src/config_new.h | 2 +- src/config_new_ssh.c | 7 + src/config_new_tls.c | 23 +-- src/server_config.c | 52 +++++-- src/server_config.h | 36 +++++ src/session_p.h | 2 + src/session_server_tls.c | 44 ------ tests/test_endpt_share_clients.c | 239 ++++++++++++++++++------------- 8 files changed, 244 insertions(+), 161 deletions(-) diff --git a/src/config_new.h b/src/config_new.h index 6b49160a..61364b11 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -16,8 +16,8 @@ #ifndef NC_CONFIG_NEW_H_ #define NC_CONFIG_NEW_H_ -#include #include +#include #include "session_p.h" diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index 5960d2c0..5e8ead07 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -470,3 +470,10 @@ nc_server_config_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, const cleanup: return ret; } + +API int +nc_config_new_ssh_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config) +{ + return nc_config_new_insert(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); +} diff --git a/src/config_new_tls.c b/src/config_new_tls.c index e0d03416..e1bad253 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -73,31 +73,31 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char } ret = nc_config_new_insert(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition/public-key-format", endpt_name); + "tls/tls-server-parameters/server-identity/certificate/inline-definition/public-key-format", endpt_name); if (ret) { goto cleanup; } ret = nc_config_new_insert(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition/public-key", endpt_name); + "tls/tls-server-parameters/server-identity/certificate/inline-definition/public-key", endpt_name); if (ret) { goto cleanup; } ret = nc_config_new_insert(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition/private-key-format", endpt_name); + "tls/tls-server-parameters/server-identity/certificate/inline-definition/private-key-format", endpt_name); if (ret) { goto cleanup; } ret = nc_config_new_insert(ctx, config, privkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition/cleartext-private-key", endpt_name); + "tls/tls-server-parameters/server-identity/certificate/inline-definition/cleartext-private-key", endpt_name); if (ret) { goto cleanup; } ret = nc_config_new_insert(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition/cert-data", endpt_name); + "tls/tls-server-parameters/server-identity/certificate/inline-definition/cert-data", endpt_name); if (ret) { goto cleanup; } @@ -211,13 +211,13 @@ nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, u } ret = nc_config_new_insert(ctx, config, map, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/map-type", endpt_name, id); + "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/map-type", endpt_name, id); if (ret) { goto cleanup; } ret = nc_config_new_insert(ctx, config, name, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/name", endpt_name, id); + "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/name", endpt_name, id); if (ret) { goto cleanup; } @@ -308,7 +308,7 @@ nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_nam } ret = nc_config_new_insert(ctx, config, cipher_ident, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/hello-params/cipher-suites/cipher-suite", endpt_name); + "tls/tls-server-parameters/hello-params/cipher-suites/cipher-suite", endpt_name); if (ret) { goto cleanup; } @@ -467,3 +467,10 @@ nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endp free(url_path); return ret; } + +API int +nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config) +{ + return nc_config_new_insert(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); +} diff --git a/src/server_config.c b/src/server_config.c index a94bc098..f7f6e93a 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -837,6 +837,7 @@ static void nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind) { nc_server_config_del_endpt_name(endpt); + nc_server_config_del_endpt_reference(endpt); nc_server_config_del_tls(bind, endpt->opts.tls); server_opts.endpt_count--; @@ -2495,6 +2496,9 @@ nc_server_config_fill_endpt_client_auth(void) if (server_opts.endpts[i].ti == NC_TI_LIBSSH) { server_opts.endpts[i].opts.ssh->endpt_client_ref = &server_opts.endpts[j]; break; + } else if (server_opts.endpts[i].ti == NC_TI_OPENSSL) { + server_opts.endpts[i].opts.tls->endpt_client_ref = &server_opts.endpts[j]; + break; } else { ERRINT; return 1; @@ -2515,18 +2519,34 @@ nc_server_config_fill_endpt_client_auth(void) } static int -nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next, NC_TRANSPORT_IMPL transport) +nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next) { - if (transport == NC_TI_LIBSSH) { - if (next->opts.ssh->endpt_client_ref) { - if (next->opts.ssh->endpt_client_ref == original) { - return 1; - } else { - return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref, NC_TI_LIBSSH); - } + if (original->ti == NC_TI_LIBSSH) { + if (!next->opts.ssh->endpt_client_ref) { + /* no further reference -> no cycle */ + return 0; + } + + if (next->opts.ssh->endpt_client_ref == original) { + /* found cycle */ + return 1; } else { + /* continue further */ + return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref); + } + } else if (original->ti == NC_TI_OPENSSL) { + if (!next->opts.tls->endpt_client_ref) { + /* no further reference -> no cycle */ return 0; } + + if (next->opts.tls->endpt_client_ref == original) { + /* found cycle */ + return 1; + } else { + /* continue further */ + return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.tls->endpt_client_ref); + } } else { ERRINT; return 1; @@ -2550,7 +2570,11 @@ nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION } if (op == NC_OP_DELETE) { - endpt->opts.ssh->endpt_client_ref = NULL; + if (is_ssh(node)) { + endpt->opts.ssh->endpt_client_ref = NULL; + } else { + endpt->opts.tls->endpt_client_ref = NULL; + } goto cleanup; } @@ -2564,11 +2588,11 @@ nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION if (i == server_opts.endpt_count) { /* endpt not found, save the name and try to look it up later */ + nc_server_config_del_endpt_reference(endpt); endpt->referenced_endpt_name = strdup(endpt_name); if (!endpt->referenced_endpt_name) { ERRMEM; ret = 1; - goto cleanup; } goto cleanup; } @@ -2581,14 +2605,18 @@ nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION } /* check for cyclic references */ - ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i], endpt->ti); + ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i]); if (ret) { ERR(NULL, "Cyclic client authentication reference detected."); goto cleanup; } /* assign the current endpt the referrenced endpt */ - endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i]; + if (is_ssh(node)) { + endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i]; + } else { + endpt->opts.tls->endpt_client_ref = &server_opts.endpts[i]; + } cleanup: return ret; diff --git a/src/server_config.h b/src/server_config.h index 02362f29..71b50a73 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -261,6 +261,24 @@ int nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const ch int nc_server_config_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes, which will be a reference to another SSH endpoint's clients. + * + * Whenever an user 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 clients 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, it's 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_config_new_ssh_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, + const char *referenced_endpt, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a server's certificate. * @@ -413,6 +431,24 @@ int nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt */ int nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, 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, it's 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_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, + const char *referenced_endpt, struct lyd_node **config); + #endif /* NC_ENABLED_SSH_TLS */ #ifdef __cplusplus diff --git a/src/session_p.h b/src/session_p.h index 13dfd319..96c6614d 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -274,6 +274,8 @@ struct nc_server_tls_opts { int crl_cert_ext; /**< Indicates to use CA's distribution points to obtain CRLs */ X509_STORE *crl_store; /**< Stores all the CRLs */ + struct nc_endpt *endpt_client_ref; /**< Reference to another endpoint (used for client authentication). */ + unsigned int tls_versions; /**< TLS versions */ char *ciphers; /**< TLS ciphers */ diff --git a/src/session_server_tls.c b/src/session_server_tls.c index ea63bc87..5f5c6ea5 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -599,7 +599,6 @@ nc_server_tls_check_crl(X509_STORE *crl_store, X509_STORE_CTX *x509_ctx, X509 *c } static int -<<<<<<< HEAD nc_server_tls_ts_ref_get_certs(const char *referenced_name, struct nc_certificate **certs, uint16_t *cert_count) { uint16_t i; @@ -682,29 +681,17 @@ nc_server_tls_do_preverify(struct nc_session *session, X509_STORE_CTX *x509_ctx, } static int -======= ->>>>>>> d301c76 (config UPDATE implemented CRL for TLS) nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) { X509_NAME *subject; X509_NAME *issuer; X509 *cert; -<<<<<<< HEAD -======= - struct nc_cert_grouping *ee_certs; ->>>>>>> d301c76 (config UPDATE implemented CRL for TLS) char *cp; STACK_OF(X509) * cert_stack; struct nc_session *session; struct nc_server_tls_opts *opts; -<<<<<<< HEAD int rc, depth; -======= - int i, rc, depth; - const char *username = NULL; - NC_TLS_CTN_MAPTYPE map_type = 0; ->>>>>>> d301c76 (config UPDATE implemented CRL for TLS) /* get the thread session */ session = pthread_getspecific(verify_key); @@ -725,23 +712,14 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) /* standard certificate verification failed, so an end-entity client cert must match to continue */ if (!preverify_ok) { -<<<<<<< HEAD /* check current endpoint's end-entity certs */ rc = nc_server_tls_do_preverify(session, x509_ctx, 1); if (rc == -1) { -======= - /* get the store from the current context */ - X509_STORE *store = X509_STORE_CTX_get0_store(x509_ctx); - - if (!store) { - ERR(session, "Error getting store from context (%s).", ERR_reason_error_string(ERR_get_error())); ->>>>>>> d301c76 (config UPDATE implemented CRL for TLS) return 0; } else if (rc == 1) { return 1; } -<<<<<<< HEAD /* no match, continue */ if (opts->endpt_client_ref) { /* check referenced endpoint's end-entity certs */ @@ -749,33 +727,11 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) if (rc == -1) { return 0; } else if (rc == 1) { -======= - /* get the data from the store */ - ee_certs = X509_STORE_get_ex_data(store, 1); - if (!ee_certs) { - ERR(session, "Error getting data from store (%s).", ERR_reason_error_string(ERR_get_error())); - return 0; - } - - for (i = 0; i < ee_certs->cert_count; i++) { - cert = base64der_to_cert(ee_certs->certs[i].data); - rc = cert_pubkey_match(session->opts.server.client_cert, cert); - X509_free(cert); - if (rc) { - /* we are just overriding the failed standard certificate verification (preverify_ok == 0), - * this callback will be called again with the same current certificate and preverify_ok == 1 */ - VRB(session, "Cert verify: fail (%s), but the end-entity certificate is trusted, continuing.", - X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx))); - X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); ->>>>>>> d301c76 (config UPDATE implemented CRL for TLS) return 1; } } -<<<<<<< HEAD /* no match, fail */ -======= ->>>>>>> d301c76 (config UPDATE implemented CRL for TLS) ERR(session, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx))); return 0; } diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c index 35e3b1a1..7ba8e8cd 100644 --- a/tests/test_endpt_share_clients.c +++ b/tests/test_endpt_share_clients.c @@ -36,94 +36,6 @@ struct test_state { pthread_barrier_t barrier; }; -const char *data = - "\n" - " \n" - " 10\n" - " \n" - " endpoint_1\n" - " \n" - " \n" - " 127.0.0.1\n" - " 10005\n" - " \n" - " \n" - " \n" - " \n" - " hostkey\n" - " \n" - " \n" - " ct:ssh-public-key-format\n" - " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" - " ct:rsa-private-key-format\n" - " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " client\n" - " \n" - " \n" - " \n" - " test\n" - " ct:ssh-public-key-format\n" - " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " endpoint_2\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " endpoint_2\n" - " \n" - " \n" - " 127.0.0.1\n" - " 10006\n" - " \n" - " \n" - " \n" - " \n" - " hostkey\n" - " \n" - " \n" - " ct:ssh-public-key-format\n" - " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" - " ct:rsa-private-key-format\n" - " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " client2\n" - " \n" - " \n" - " \n" - " test\n" - " ct:ssh-public-key-format\n" - " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n"; - static void * server_thread(void *arg) { @@ -155,7 +67,7 @@ server_thread(void *arg) } static void * -client_thread(void *arg) +client_thread_ssh(void *arg) { int ret; struct nc_session *session = NULL; @@ -188,14 +100,59 @@ client_thread(void *arg) } static void -nc_test_endpt_share_clients(void **state) +nc_test_endpt_share_clients_ssh(void **state) { int ret, i; pthread_t tids[2]; assert_non_null(state); - ret = pthread_create(&tids[0], NULL, client_thread, *state); + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void * +client_thread_tls(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + /* set directory where to search for modules */ + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set client cert */ + ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key"); + assert_int_equal(ret, 0); + + /* set client ca */ + ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_tls("127.0.0.1", 10008, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + return NULL; +} + +static void +nc_test_endpt_share_clients_tls(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread_tls, *state); assert_int_equal(ret, 0); ret = pthread_create(&tids[1], NULL, server_thread, *state); assert_int_equal(ret, 0); @@ -206,7 +163,7 @@ nc_test_endpt_share_clients(void **state) } static int -setup_f(void **state) +setup_ssh(void **state) { int ret; struct lyd_node *tree = NULL; @@ -235,12 +192,101 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - /* parse yang data */ - ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + /* create the first SSH endpoint with a client reference to the second endpoint */ + ret = nc_server_config_new_ssh_hostkey(ctx, "SSH_endpt_1", "hostkey", TESTS_DIR "/data/key_rsa", NULL, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_address_port(ctx, "SSH_endpt_1", NC_TI_LIBSSH, "127.0.0.1", "10005", &tree); + assert_int_equal(ret, 0); + + ret = nc_config_new_ssh_endpoint_client_reference(ctx, "SSH_endpt_1", "SSH_endpt_2", &tree); + assert_int_equal(ret, 0); + + /* create the second SSH endpoint with a single client */ + ret = nc_server_config_new_ssh_hostkey(ctx, "SSH_endpt_2", "hostkey", TESTS_DIR "/data/key_rsa", NULL, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_address_port(ctx, "SSH_endpt_2", NC_TI_LIBSSH, "127.0.0.1", "10006", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "SSH_endpt_2", "client", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the yang data */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + /* initialize the server */ + ret = nc_server_init(); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + +static int +setup_tls(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + /* create new context */ + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* load default modules into context */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf-netconf-server module and it's imports into context */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* create the first TLS endpoint with a single end entity client cert and a CTN entry */ + ret = nc_server_config_new_tls_server_certificate(ctx, "TLS_endpt_1", NULL, + TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_address_port(ctx, "TLS_endpt_1", NC_TI_OPENSSL, "127.0.0.1", "10007", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_tls_client_certificate(ctx, "TLS_endpt_1", "cert_client", TESTS_DIR "/data/client.crt", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_tls_client_ca(ctx, "TLS_endpt_1", "cert_ca", TESTS_DIR "/data/serverca.pem", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_tls_ctn(ctx, "TLS_endpt_1", 1, + "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", + NC_TLS_CTN_SPECIFIED, "client", &tree); + assert_int_equal(ret, 0); + + /* create the second TLS endpoint with a reference to the first endpoint */ + ret = nc_server_config_new_tls_server_certificate(ctx, "TLS_endpt_2", NULL, + TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_address_port(ctx, "TLS_endpt_2", NC_TI_OPENSSL, "127.0.0.1", "10008", &tree); + assert_int_equal(ret, 0); + + ret = nc_config_new_tls_endpoint_client_reference(ctx, "TLS_endpt_2", "TLS_endpt_1", &tree); assert_int_equal(ret, 0); /* configure the server based on the yang data */ - ret = nc_server_config_setup_data(tree); + ret = nc_server_config_setup_diff(tree); assert_int_equal(ret, 0); /* initialize the server */ @@ -276,7 +322,8 @@ int main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(nc_test_endpt_share_clients, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(nc_test_endpt_share_clients_ssh, setup_ssh, teardown_f), + cmocka_unit_test_setup_teardown(nc_test_endpt_share_clients_tls, setup_tls, teardown_f), }; setenv("CMOCKA_TEST_ABORT", "1", 1); From 7dedeea9be28b880388fb4c2c8741e0e48ca6b42 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 22 Jun 2023 12:53:17 +0200 Subject: [PATCH 039/134] config UPDATE add basic SSH call-home --- modules/libnetconf2-netconf-server.yang | 18 + src/config_new.c | 153 ++- src/config_new.h | 6 +- src/config_new_ssh.c | 144 +- src/config_new_tls.c | 32 +- src/server_config.c | 1592 ++++++++++++++++++----- src/server_config.h | 11 + src/server_config_ks.c | 2 +- src/server_config_p.h | 2 + src/server_config_ts.c | 2 +- src/session_p.h | 3 + src/session_server_ch.h | 6 +- tests/CMakeLists.txt | 3 +- tests/test_ch.c | 252 ++++ 14 files changed, 1844 insertions(+), 382 deletions(-) create mode 100644 tests/test_ch.c diff --git a/modules/libnetconf2-netconf-server.yang b/modules/libnetconf2-netconf-server.yang index ec0d6f0a..07535228 100644 --- a/modules/libnetconf2-netconf-server.yang +++ b/modules/libnetconf2-netconf-server.yang @@ -237,6 +237,24 @@ module libnetconf2-netconf-server { } augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { + leaf auth-attempts { + type uint16; + default 3; + description + "Represents the number of failed attempts before an authentication is deemed unsuccessful."; + } + + leaf auth-timeout { + type uint16; + default 10; + units "seconds"; + description + "Represents the maximum amount of seconds an authentication can go on for."; + } + } + + // CH auth-attempts and auth-timeout + augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { leaf auth-attempts { type uint16; default 3; diff --git a/src/config_new.c b/src/config_new.c index 1e57b258..d6c4c522 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -35,15 +35,41 @@ #include "session_p.h" int -nc_config_new_check_add_operation(const struct ly_ctx *ctx, struct lyd_node *top) +nc_config_new_add_operation(const struct ly_ctx *ctx, struct lyd_node *node, NC_OPERATION op) { - if (lyd_find_meta(top->meta, NULL, "yang:operation")) { - /* it already has operation attribute */ - return 0; + struct lyd_meta *meta; + const char *op_str = NULL; + + meta = lyd_find_meta(node->meta, NULL, "yang:operation"); + if (meta) { + /* node already has operation attribute, delete it */ + lyd_free_meta_single(meta); + } + + /* get the operation as string */ + switch (op) { + case NC_OP_CREATE: + op_str = "create"; + break; + case NC_OP_REPLACE: + op_str = "replace"; + break; + case NC_OP_DELETE: + op_str = "delete"; + break; + case NC_OP_NONE: + op_str = "none"; + break; + default: + break; + } + if (!op_str) { + ERR(NULL, "Invalid operation to add to the tree."); + return 1; } - /* give the top level container create operation */ - if (lyd_new_meta(ctx, top, NULL, "yang:operation", "create", 0, NULL)) { + /* give the node the operation */ + if (lyd_new_meta(ctx, node, NULL, "yang:operation", op_str, 0, NULL)) { return 1; } @@ -670,12 +696,49 @@ nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_na goto cleanup; } - ret = nc_config_new_insert(ctx, config, address, address_fmt, endpt_name); + ret = nc_config_new_create(ctx, config, address, address_fmt, endpt_name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, port, port_fmt, endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + NC_TRANSPORT_IMPL transport, const char *address, const char *port, struct lyd_node **config) +{ + int ret = 0; + const char *address_fmt, *port_fmt; + + NC_CHECK_ARG_RET(NULL, address, port, ctx, endpt_name, config, 1); + + if (transport == NC_TI_LIBSSH) { + /* 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_OPENSSL) { + /* 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 { + ERR(NULL, "Transport not supported."); + ret = 1; + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, address, address_fmt, ch_client_name, endpt_name); if (ret) { goto cleanup; } - ret = nc_config_new_insert(ctx, config, port, port_fmt, endpt_name); + ret = nc_config_new_create(ctx, config, port, port_fmt, ch_client_name, endpt_name); if (ret) { goto cleanup; } @@ -684,8 +747,74 @@ nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_na return ret; } +API int +nc_server_config_new_del_ch_client(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1); + + return nc_config_new_delete(ctx, config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']", ch_client_name); +} + +int +nc_config_new_delete(const struct ly_ctx *ctx, struct lyd_node **tree, const char *path_fmt, ...) +{ + int ret = 0; + va_list ap; + char *path = NULL; + + va_start(ap, path_fmt); + + /* create the path from the format */ + ret = vasprintf(&path, path_fmt, ap); + if (ret == -1) { + ERRMEM; + path = NULL; + goto cleanup; + } + + /* create the nodes in the path */ + ret = lyd_new_path(*tree, ctx, path, NULL, LYD_NEW_PATH_UPDATE, tree); + if (ret) { + goto cleanup; + } + + /* set the node to the last node */ + ret = lyd_find_path(*tree, path, 0, tree); + if (ret) { + goto cleanup; + } + + /* add delete operation to the node */ + ret = nc_config_new_add_operation(ctx, *tree, NC_OP_DELETE); + if (ret) { + goto cleanup; + } + + /* set the node back to top level container */ + ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_add_operation(ctx, *tree, NC_OP_NONE); + if (ret) { + goto cleanup; + } + + /* add all default nodes */ + ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + va_end(ap); + return ret; +} + int -nc_config_new_insert(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...) +nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...) { int ret = 0; va_list ap; @@ -707,14 +836,14 @@ nc_config_new_insert(const struct ly_ctx *ctx, struct lyd_node **tree, const cha goto cleanup; } - /* set out param to top level container */ + /* set the node to the top level node */ ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); if (ret) { goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *tree); + /* add create operation to the top level node */ + ret = nc_config_new_add_operation(ctx, *tree, NC_OP_CREATE); if (ret) { goto cleanup; } diff --git a/src/config_new.h b/src/config_new.h index 61364b11..ba93dcb8 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -84,7 +84,9 @@ const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT forma #endif /* NC_ENABLED_SSH_TLS */ -int nc_config_new_check_add_operation(const struct ly_ctx *ctx, struct lyd_node *top); +int nc_config_new_add_operation(const struct ly_ctx *ctx, struct lyd_node *node, NC_OPERATION op); + +int nc_config_new_delete(const struct ly_ctx *ctx, struct lyd_node **tree, const char *path_fmt, ...); /** * @brief Creates YANG data nodes in a path and gives the final node a value. @@ -97,7 +99,7 @@ int nc_config_new_check_add_operation(const struct ly_ctx *ctx, struct lyd_node * @param[in] ... Parameters for the path format, essentially representing the lists' keys. * @return 0 on success, 1 otherwise. */ -int nc_config_new_insert(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...); +int nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...); #ifdef __cplusplus } diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index 5e8ead07..5266e309 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -35,8 +35,8 @@ extern pthread_mutex_t crypt_lock; #endif API int -nc_server_config_new_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) +nc_server_config_new_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 ret = 0; char *pubkey = NULL, *privkey = NULL; @@ -67,25 +67,25 @@ nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, goto cleanup; } - ret = nc_config_new_insert(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" "server-identity/host-key[name='%s']/public-key/inline-definition/public-key-format", endpt_name, hostkey_name); if (ret) { goto cleanup; } - ret = nc_config_new_insert(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" "server-identity/host-key[name='%s']/public-key/inline-definition/public-key", endpt_name, hostkey_name); if (ret) { goto cleanup; } - ret = nc_config_new_insert(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" "server-identity/host-key[name='%s']/public-key/inline-definition/private-key-format", endpt_name, hostkey_name); if (ret) { goto cleanup; } - ret = nc_config_new_insert(ctx, config, privkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + ret = nc_config_new_create(ctx, config, privkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" "server-identity/host-key[name='%s']/public-key/inline-definition/cleartext-private-key", endpt_name, hostkey_name); if (ret) { goto cleanup; @@ -226,7 +226,7 @@ nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *end } /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); + ret = nc_config_new_add_operation(ctx, *config, NC_OP_CREATE); if (ret) { goto cleanup; } @@ -265,7 +265,7 @@ nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char } /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); + ret = nc_config_new_add_operation(ctx, *config, NC_OP_CREATE); if (ret) { goto cleanup; } @@ -304,7 +304,7 @@ nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *e } /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); + ret = nc_config_new_add_operation(ctx, *config, NC_OP_CREATE); if (ret) { goto cleanup; } @@ -343,7 +343,7 @@ nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_na } /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_check_add_operation(ctx, *config); + ret = nc_config_new_add_operation(ctx, *config, NC_OP_CREATE); if (ret) { goto cleanup; } @@ -379,13 +379,13 @@ nc_server_config_new_ssh_client_auth_pubkey(const struct ly_ctx *ctx, const char pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; } - ret = nc_config_new_insert(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/public-key-format", endpt_name, user_name, pubkey_name); if (ret) { goto cleanup; } - ret = nc_config_new_insert(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/public-key", endpt_name, user_name, pubkey_name); if (ret) { goto cleanup; @@ -423,7 +423,7 @@ nc_server_config_new_ssh_client_auth_password(const struct ly_ctx *ctx, const ch goto cleanup; } - ret = nc_config_new_insert(ctx, config, hashed_pw, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + ret = nc_config_new_create(ctx, config, hashed_pw, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/password", endpt_name, user_name); if (ret) { goto cleanup; @@ -439,7 +439,7 @@ nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const char * { int ret = 0; - ret = nc_config_new_insert(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + ret = nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/none", endpt_name, user_name); if (ret) { goto cleanup; @@ -455,13 +455,13 @@ nc_server_config_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, const { int ret = 0; - ret = nc_config_new_insert(ctx, config, pam_config_name, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + ret = nc_config_new_create(ctx, config, pam_config_name, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive/pam-config-file-name", endpt_name, user_name); if (ret) { goto cleanup; } - ret = nc_config_new_insert(ctx, config, pam_config_dir, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + ret = nc_config_new_create(ctx, config, pam_config_dir, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive/pam-config-file-dir", endpt_name, user_name); if (ret) { goto cleanup; @@ -474,6 +474,116 @@ nc_server_config_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, const API int nc_config_new_ssh_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config) { - return nc_config_new_insert(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + return nc_config_new_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); } + +API int +nc_server_config_new_ssh_ch_hostkey(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + const char *hostkey_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config) +{ + int ret = 0; + char *pubkey = NULL, *privkey = NULL; + NC_PRIVKEY_FORMAT privkey_type; + NC_PUBKEY_FORMAT pubkey_type; + const char *privkey_format, *pubkey_format; + + NC_CHECK_ARG_RET(NULL, privkey_path, config, ctx, endpt_name, hostkey_name, 1); + + /* get the keys as a string from the given files */ + ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); + if (ret) { + ERR(NULL, "Getting keys from file(s) failed."); + goto cleanup; + } + + /* pubkey format to str */ + if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { + 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_config_new_privkey_format_to_identityref(privkey_type); + if (!privkey_format) { + ret = 1; + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/inline-definition/public-key-format", ch_client_name, endpt_name, hostkey_name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/inline-definition/public-key", ch_client_name, endpt_name, hostkey_name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/inline-definition/private-key-format", ch_client_name, endpt_name, hostkey_name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, privkey, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/inline-definition/cleartext-private-key", ch_client_name, endpt_name, hostkey_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(privkey); + free(pubkey); + return ret; +} + +API int +nc_server_config_new_ssh_ch_client_auth_pubkey(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + const char *user_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config) +{ + int ret = 0; + char *pubkey = NULL; + NC_PUBKEY_FORMAT pubkey_type; + const char *pubkey_format; + + /* get pubkey data */ + ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_type); + if (ret) { + goto cleanup; + } + + /* get pubkey format */ + if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { + pubkey_format = "ietf-crypto-types:ssh-public-key-format"; + } else { + pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; + } + + ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/" + "public-key-format", ch_client_name, endpt_name, user_name, pubkey_name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/" + "public-key", ch_client_name, endpt_name, user_name, pubkey_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(pubkey); + return ret; +} diff --git a/src/config_new_tls.c b/src/config_new_tls.c index e1bad253..3d14ad09 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -72,31 +72,31 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char goto cleanup; } - ret = nc_config_new_insert(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" "tls/tls-server-parameters/server-identity/certificate/inline-definition/public-key-format", endpt_name); if (ret) { goto cleanup; } - ret = nc_config_new_insert(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" "tls/tls-server-parameters/server-identity/certificate/inline-definition/public-key", endpt_name); if (ret) { goto cleanup; } - ret = nc_config_new_insert(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" "tls/tls-server-parameters/server-identity/certificate/inline-definition/private-key-format", endpt_name); if (ret) { goto cleanup; } - ret = nc_config_new_insert(ctx, config, privkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + ret = nc_config_new_create(ctx, config, privkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" "tls/tls-server-parameters/server-identity/certificate/inline-definition/cleartext-private-key", endpt_name); if (ret) { goto cleanup; } - ret = nc_config_new_insert(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + ret = nc_config_new_create(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" "tls/tls-server-parameters/server-identity/certificate/inline-definition/cert-data", endpt_name); if (ret) { goto cleanup; @@ -124,7 +124,7 @@ nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char goto cleanup; } - ret = nc_config_new_insert(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + ret = nc_config_new_create(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" "client-authentication/ee-certs/inline-definition/certificate[name='%s']/cert-data", endpt_name, cert_name); if (ret) { goto cleanup; @@ -150,7 +150,7 @@ nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_n goto cleanup; } - ret = nc_config_new_insert(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + ret = nc_config_new_create(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" "client-authentication/ca-certs/inline-definition/certificate[name='%s']/cert-data", endpt_name, cert_name); if (ret) { goto cleanup; @@ -196,7 +196,7 @@ nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, u if (fingerprint) { /* optional */ - ret = nc_config_new_insert(ctx, config, fingerprint, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + ret = nc_config_new_create(ctx, config, fingerprint, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/fingerprint", endpt_name, id); if (ret) { goto cleanup; @@ -210,13 +210,13 @@ nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, u goto cleanup; } - ret = nc_config_new_insert(ctx, config, map, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + ret = nc_config_new_create(ctx, config, map, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/map-type", endpt_name, id); if (ret) { goto cleanup; } - ret = nc_config_new_insert(ctx, config, name, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + ret = nc_config_new_create(ctx, config, name, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/name", endpt_name, id); if (ret) { goto cleanup; @@ -259,7 +259,7 @@ nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt_nam goto cleanup; } - ret = nc_config_new_insert(ctx, config, version, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + ret = nc_config_new_create(ctx, config, version, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" "hello-params/tls-versions/tls-version", endpt_name); if (ret) { goto cleanup; @@ -307,7 +307,7 @@ nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_nam goto cleanup; } - ret = nc_config_new_insert(ctx, config, cipher_ident, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + ret = nc_config_new_create(ctx, config, cipher_ident, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" "tls/tls-server-parameters/hello-params/cipher-suites/cipher-suite", endpt_name); if (ret) { goto cleanup; @@ -332,7 +332,7 @@ nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_na NC_CHECK_ARG_RET(NULL, ctx, endpt_name, path, config, 1); - ret = nc_config_new_insert(ctx, config, path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + ret = nc_config_new_create(ctx, config, path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" "client-authentication/libnetconf2-netconf-server:crl-path", endpt_name); if (ret) { goto cleanup; @@ -381,7 +381,7 @@ nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_nam NC_CHECK_ARG_RET(NULL, ctx, endpt_name, url, config, 1); - ret = nc_config_new_insert(ctx, config, url, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + ret = nc_config_new_create(ctx, config, url, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" "client-authentication/libnetconf2-netconf-server:crl-url", endpt_name); if (ret) { goto cleanup; @@ -428,7 +428,7 @@ nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endp struct lyd_node *node = NULL; char *crl_path = NULL, *url_path = NULL; - ret = nc_config_new_insert(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + ret = nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" "client-authentication/libnetconf2-netconf-server:crl-cert-ext", endpt_name); if (ret) { goto cleanup; @@ -471,6 +471,6 @@ nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endp API int nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config) { - return nc_config_new_insert(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + return nc_config_new_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); } diff --git a/src/server_config.c b/src/server_config.c index f7f6e93a..8e3d3e5e 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -108,6 +108,72 @@ nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, return 1; } +int +nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client **ch_client) +{ + uint16_t i; + const char *ch_client_name; + + while (node) { + if (!strcmp(LYD_NAME(node), "netconf-client")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a netconf-client subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + ch_client_name = lyd_get_value(node); + + for (i = 0; i < server_opts.ch_client_count; i++) { + if (!strcmp(server_opts.ch_clients[i].name, ch_client_name)) { + *ch_client = &server_opts.ch_clients[i]; + return 0; + } + } + + ERR(NULL, "Call-home client \"%s\" was not found.", ch_client_name); + return 1; +} + +int +nc_server_config_get_ch_endpt(const struct lyd_node *node, const struct nc_ch_client *ch_client, struct nc_ch_endpt **ch_endpt) +{ + uint16_t i; + const char *ch_endpt_name; + + while (node) { + if (!strcmp(LYD_NAME(node), "endpoint")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a call-home endpoint subtree.", LYD_NAME(node)); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + ch_endpt_name = lyd_get_value(node); + + for (i = 0; i < ch_client->ch_endpt_count; i++) { + if (!strcmp(ch_client->ch_endpts[i].name, ch_endpt_name)) { + *ch_endpt = &ch_client->ch_endpts[i]; + return 0; + } + } + + ERR(NULL, "Call-home client's \"%s\" endpoint \"%s\" was not found.", ch_client->name, ch_endpt_name); + return 1; +} + #ifdef NC_ENABLED_SSH_TLS int @@ -362,8 +428,6 @@ nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_ return ret; } -#ifdef NC_ENABLED_SSH_TLS - static int is_listen(const struct lyd_node *node) { @@ -379,20 +443,22 @@ is_listen(const struct lyd_node *node) return node != NULL; } -// static int -// is_ch(const struct lyd_node *node) -// { -// assert(node); +static int +is_ch(const struct lyd_node *node) +{ + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "call-home")) { + break; + } + node = lyd_parent(node); + } -// while (node) { -// if (!strcmp(LYD_NAME(node), "call-home")) { -// break; -// } -// node = lyd_parent(node); -// } + return node != NULL; +} -// return node != NULL; -// } +#ifdef NC_ENABLED_SSH_TLS static int is_ssh(const struct lyd_node *node) @@ -849,6 +915,13 @@ nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind) } } +static void +nc_server_config_del_remote_address(struct nc_ch_endpt *ch_endpt) +{ + free(ch_endpt->address); + ch_endpt->address = NULL; +} + #endif /* NC_ENABLED_SSH_TLS */ /* presence container */ @@ -887,6 +960,127 @@ nc_server_config_listen(struct lyd_node *node, NC_OPERATION op) return 0; } +#ifdef NC_ENABLED_SSH_TLS + +static void +nc_server_config_ch_del_ssh(struct nc_server_ssh_opts *opts) +{ + uint16_t i, hostkey_count, client_count; + + /* store in variable because it gets decremented in the function call */ + hostkey_count = opts->hostkey_count; + for (i = 0; i < hostkey_count; i++) { + nc_server_config_del_hostkey(opts, &opts->hostkeys[i]); + } + + client_count = opts->client_count; + for (i = 0; i < client_count; i++) { + nc_server_config_del_auth_client(opts, &opts->auth_clients[i]); + } + + nc_server_config_del_hostkey_algs(opts); + nc_server_config_del_kex_algs(opts); + nc_server_config_del_encryption_algs(opts); + nc_server_config_del_mac_algs(opts); + + free(opts); + opts = NULL; +} + +static void +nc_server_config_ch_del_endpt_address(struct nc_ch_endpt *ch_endpt) +{ + free(ch_endpt->address); + ch_endpt->address = NULL; +} + +#endif /* NC_ENABLED_SSH_TLS */ + +static void +nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt) +{ + free(ch_endpt->name); + ch_endpt->name = NULL; + +#ifdef NC_ENABLED_SSH_TLS + nc_server_config_ch_del_endpt_address(ch_endpt); + if (ch_endpt->sock_pending > -1) { + close(ch_endpt->sock_pending); + ch_endpt->sock_pending = -1; + } +#endif /* NC_ENABLED_SSH_TLS */ + + switch (ch_endpt->ti) { +#ifdef NC_ENABLED_SSH_TLS + case NC_TI_LIBSSH: + nc_server_config_ch_del_ssh(ch_endpt->opts.ssh); + break; +#endif /* NC_ENABLED_SSH_TLS */ + default: + ERRINT; + break; + } + + ch_client->ch_endpt_count--; + if (!ch_client->ch_endpt_count) { + free(ch_client->ch_endpts); + ch_client->ch_endpts = NULL; + } +} + +static void +nc_server_config_ch_del_client(struct nc_ch_client *ch_client) +{ + uint16_t i, ch_endpt_count; + + pthread_rwlock_wrlock(&server_opts.ch_client_lock); + + free(ch_client->name); + ch_client->name = NULL; + + if (ch_client->session) { + pthread_mutex_lock(&ch_client->session->opts.server.ch_lock); + pthread_cond_signal(&ch_client->session->opts.server.ch_cond); + pthread_mutex_unlock(&ch_client->session->opts.server.ch_lock); + } + + ch_client->session = NULL; + + pthread_rwlock_unlock(&server_opts.ch_client_lock); + + pthread_join(ch_client->tid, NULL); + + pthread_rwlock_wrlock(&server_opts.ch_client_lock); + + ch_endpt_count = ch_client->ch_endpt_count; + for (i = 0; i < ch_endpt_count; i++) { + nc_server_config_ch_del_endpt(ch_client, &ch_client->ch_endpts[i]); + } + + server_opts.ch_client_count--; + if (!server_opts.ch_client_count) { + free(server_opts.ch_clients); + server_opts.ch_clients = NULL; + } + + pthread_rwlock_unlock(&server_opts.ch_client_lock); +} + +void +nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op) +{ + uint16_t i, ch_client_count; + + (void) node; + + if (op == NC_OP_DELETE) { + ch_client_count = server_opts.ch_client_count; + for (i = 0; i < ch_client_count; i++) { + nc_server_config_ch_del_client(&server_opts.ch_clients[i]); + } + } +} + /* default leaf */ static int nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op) @@ -939,6 +1133,15 @@ nc_server_config_create_endpoint(const struct lyd_node *node) return nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.endpts, sizeof *server_opts.endpts, &server_opts.endpt_count); } +static int +nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client) +{ + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts, &ch_client->ch_endpt_count); +} + /* list */ static int nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) @@ -946,39 +1149,59 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_endpt *endpt; struct nc_bind *bind; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "endpoint")); - if (op == NC_OP_CREATE) { - ret = nc_server_config_create_endpoint(node); - if (ret) { - goto cleanup; - } - } else if (op == NC_OP_DELETE) { - /* free all children */ - if (nc_server_config_get_endpt(node, &endpt, &bind)) { - ret = 1; - goto cleanup; - } + if (is_listen(node)) { + /* listen */ + if (op == NC_OP_CREATE) { + ret = nc_server_config_create_endpoint(node); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + /* free all children */ + if (nc_server_config_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } - switch (endpt->ti) { + switch (endpt->ti) { #ifdef NC_ENABLED_SSH_TLS - case NC_TI_LIBSSH: - nc_server_config_del_endpt_ssh(endpt, bind); - break; - case NC_TI_OPENSSL: - nc_server_config_del_endpt_tls(endpt, bind); - break; + case NC_TI_LIBSSH: + nc_server_config_del_endpt_ssh(endpt, bind); + break; + case NC_TI_OPENSSL: + nc_server_config_del_endpt_tls(endpt, bind); + break; #endif /* NC_ENABLED_SSH_TLS */ - case NC_TI_UNIX: - nc_server_config_del_endpt_unix_socket(endpt, bind); - break; - case NC_TI_NONE: - case NC_TI_FD: - ERRINT; + case NC_TI_UNIX: + nc_server_config_del_endpt_unix_socket(endpt, bind); + break; + case NC_TI_NONE: + case NC_TI_FD: + ERRINT; + ret = 1; + goto cleanup; + } + } + } else if (is_ch(node)) { + /* ch */ + if (nc_server_config_get_ch_client(node, &ch_client)) { ret = 1; goto cleanup; } + + if (op == NC_OP_CREATE) { + ret = nc_server_config_ch_create_endpoint(node, ch_client); + if (ret) { + goto cleanup; + } + + /* init ch sock */ + ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1; + } } cleanup: @@ -1000,28 +1223,62 @@ nc_server_config_create_ssh(struct nc_endpt *endpt) return 0; } +static int +nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt) +{ + ch_endpt->ti = NC_TI_LIBSSH; + ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts)); + if (!ch_endpt->opts.ssh) { + ERRMEM; + return 1; + } + + return 0; +} + /* NP container */ static int nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_bind *bind; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; int ret = 0; assert(!strcmp(LYD_NAME(node), "ssh")); - if (nc_server_config_get_endpt(node, &endpt, &bind)) { - ret = 1; - goto cleanup; - } + if (is_listen(node)) { + if (nc_server_config_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } - if (op == NC_OP_CREATE) { - ret = nc_server_config_create_ssh(endpt); - if (ret) { + if (op == NC_OP_CREATE) { + ret = nc_server_config_create_ssh(endpt); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + nc_server_config_del_ssh(bind, endpt->opts.ssh); + } + } else { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; goto cleanup; } - } else if (op == NC_OP_DELETE) { - nc_server_config_del_ssh(bind, endpt->opts.ssh); + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + ret = nc_server_config_ch_create_ssh(ch_endpt); + if (ret) { + goto cleanup; + } + } } cleanup: @@ -1208,13 +1465,15 @@ nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; struct nc_bind *bind; - int ret = 0; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "keepalives")); - if (equal_parent_name(node, 1, "tcp-server-parameters")) { + if (is_listen(node) && equal_parent_name(node, 1, "tcp-server-parameters")) { if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; @@ -1229,6 +1488,22 @@ nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) if (ret) { goto cleanup; } + } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + ch_endpt->ka.enabled = 1; + } else { + ch_endpt->ka.enabled = 0; + } } cleanup: @@ -1239,13 +1514,15 @@ nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; struct nc_bind *bind; - int ret = 0; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "idle-time")); - if (equal_parent_name(node, 4, "listen")) { + if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) { if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; @@ -1260,23 +1537,41 @@ nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) if (ret) { goto cleanup; } - } + } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } -cleanup: - return ret; + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10); + } else { + ch_endpt->ka.idle_time = 0; + } + } + +cleanup: + return ret; } /* mandatory leaf */ static int nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; struct nc_bind *bind; - int ret = 0; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "max-probes")); - if (equal_parent_name(node, 4, "listen")) { + if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) { if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; @@ -1291,6 +1586,22 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) if (ret) { goto cleanup; } + } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10); + } else { + ch_endpt->ka.max_probes = 0; + } } cleanup: @@ -1301,13 +1612,15 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; struct nc_bind *bind; - int ret = 0; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "probe-interval")); - if (equal_parent_name(node, 4, "listen")) { + if (is_listen(node) && equal_parent_name(node, 2, "tcp-server-parameters")) { if (nc_server_config_get_endpt(node, &endpt, &bind)) { ret = 1; goto cleanup; @@ -1322,6 +1635,22 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) if (ret) { goto cleanup; } + } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10); + } else { + ch_endpt->ka.max_probes = 0; + } } cleanup: @@ -1341,13 +1670,15 @@ nc_server_config_create_host_key(const struct lyd_node *node, struct nc_server_s static int nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; struct nc_hostkey *hostkey; - int ret = 0; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "host-key")); - if ((equal_parent_name(node, 1, "server-identity")) && (equal_parent_name(node, 5, "listen"))) { + if (is_listen(node) && equal_parent_name(node, 1, "server-identity")) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -1363,16 +1694,31 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) ret = 1; goto cleanup; } - nc_server_config_del_hostkey(endpt->opts.ssh, hostkey); } - } else if (equal_parent_name(node, 1, "transport-params")) { - /* just a container with the name host-key, nothing to be done */ - goto cleanup; - } else { - ERRINT; - ret = 1; - goto cleanup; + } else if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + ret = nc_server_config_create_host_key(node, ch_endpt->opts.ssh); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; + } + nc_server_config_del_hostkey(ch_endpt->opts.ssh, hostkey); + } } cleanup: @@ -1383,13 +1729,15 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) { - const char *format; int ret = 0; + const char *format; NC_PUBKEY_FORMAT pubkey_type; struct nc_endpt *endpt; struct nc_client_auth *auth_client; struct nc_public_key *pubkey; struct nc_hostkey *hostkey; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "public-key-format")); @@ -1404,12 +1752,35 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } - if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) { + if (is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } + } else if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + } + + if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 4, "server-identity")) { + /* SSH hostkey public key fmt */ + if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; + } + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + hostkey->key.pubkey_type = pubkey_type; + } + } else if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { + /* SSH client auth public key fmt */ if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; @@ -1423,29 +1794,255 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { pubkey->type = pubkey_type; } - } else if (equal_parent_name(node, 5, "server-identity") && is_ssh(node) && is_listen(node)) { + } else if (is_listen(node) && is_tls(node) && equal_parent_name(node, 3, "server-identity")) { + /* TLS listen server-identity */ + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + endpt->opts.tls->pubkey_type = pubkey_type; + } + } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 4, "server-identity")) { + /* CH SSH server host-key public key fmt */ + if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + hostkey->key.pubkey_type = pubkey_type; + } + } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { + /* CH SSH client auth public key fmt */ + if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + pubkey->type = pubkey_type; + } + } + +cleanup: + return ret; +} + +static int +nc_server_config_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_client_auth *auth_client) +{ + assert(!strcmp(LYD_NAME(node), "public-key")); + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + return nc_server_config_realloc(lyd_get_value(node), (void **)&auth_client->pubkeys, sizeof *auth_client->pubkeys, &auth_client->pubkey_count); +} + +static int +nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey) +{ + nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); + + pubkey->data = strdup(lyd_get_value(node)); + if (!pubkey->data) { + ERRMEM; + return 1; + } + + return 0; +} + +static int +nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey) +{ + nc_server_config_del_public_key(hostkey); + + hostkey->key.pubkey_data = strdup(lyd_get_value(node)); + if (!hostkey->key.pubkey_data) { + ERRMEM; + return 1; + } + + return 0; +} + +static int +nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts) +{ + nc_server_config_tls_del_public_key(opts); + + opts->pubkey_data = strdup(lyd_get_value(node)); + if (!opts->pubkey_data) { + ERRMEM; + return 1; + } + + return 0; +} + +static int +nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + struct nc_hostkey *hostkey; + struct nc_client_auth *auth_client; + struct nc_public_key *pubkey; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; + + assert(!strcmp(LYD_NAME(node), "public-key")); + + if (is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } + } + if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + } + + if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 3, "host-key")) { + /* server's public-key, mandatory leaf */ if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - hostkey->key.pubkey_type = pubkey_type; + /* set to local */ + hostkey->store = NC_STORE_LOCAL; + + ret = nc_server_config_replace_host_key_public_key(node, hostkey); + if (ret) { + goto cleanup; + } } - } else if (equal_parent_name(node, 3, "server-identity") && is_tls(node) && is_listen(node)) { - /* TLS listen server-identity */ - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + } else if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) { + /* client auth pubkeys, list */ + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + /* set to local */ + auth_client->store = NC_STORE_LOCAL; + + ret = nc_server_config_create_auth_key_public_key_list(node, auth_client); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { + ret = 1; + goto cleanup; + } + + nc_server_config_del_auth_client_pubkey(auth_client, pubkey); + } + } else if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { + /* client auth pubkey, leaf */ + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->opts.tls->pubkey_type = pubkey_type; + ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey); + if (ret) { + goto cleanup; + } + } else { + nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); + } + } else if (is_listen(node) && is_tls(node) && equal_parent_name(node, 3, "server-identity")) { + /* tls listen server-identity */ + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* set to local */ + endpt->opts.tls->store = NC_STORE_LOCAL; + + ret = nc_server_config_tls_replace_server_public_key(node, endpt->opts.tls); + if (ret) { + goto cleanup; + } + } + } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 3, "host-key")) { + /* CH SSH hostkey's public key */ + if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* set to local */ + hostkey->store = NC_STORE_LOCAL; + + ret = nc_server_config_replace_host_key_public_key(node, hostkey); + if (ret) { + goto cleanup; + } + } + } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) { + /* CH SSH client auth list */ + if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + /* set to local */ + auth_client->store = NC_STORE_LOCAL; + + ret = nc_server_config_create_auth_key_public_key_list(node, auth_client); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { + ret = 1; + goto cleanup; + } + + nc_server_config_del_auth_client_pubkey(auth_client, pubkey); + } + } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { + /* CH SSH client auth leaf */ + if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey); + if (ret) { + goto cleanup; + } + } else { + nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); } } @@ -1459,19 +2056,16 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op { int ret = 0; const char *format; - struct nc_endpt *endpt; NC_PRIVKEY_FORMAT privkey_type; + struct nc_endpt *endpt; struct nc_hostkey *hostkey; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; (void) op; assert(!strcmp(LYD_NAME(node), "private-key-format")); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - format = ((struct lyd_node_term *)node)->value.ident->name; if (!format) { ret = 1; @@ -1480,11 +2074,29 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op privkey_type = nc_server_config_get_private_key_type(format); if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) { + ERR(NULL, "Unknown private key format."); ret = 1; goto cleanup; } - if ((is_ssh(node)) && (is_listen(node))) { + if (is_listen(node)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + } else if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + } + + if (is_listen(node) && is_ssh(node)) { /* listen ssh */ if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; @@ -1492,9 +2104,17 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op } hostkey->key.privkey_type = privkey_type; - } else if ((is_tls(node)) && (is_listen(node))) { + } else if (is_listen(node) && is_tls(node)) { /* listen tls */ endpt->opts.tls->privkey_type = privkey_type; + } else if (is_ch(node) && is_ssh(node)) { + /* ch ssh */ + if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { + ret = 1; + goto cleanup; + } + + hostkey->key.privkey_type = privkey_type; } cleanup: @@ -1533,15 +2153,29 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION int ret = 0; struct nc_endpt *endpt; struct nc_hostkey *hostkey; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "cleartext-private-key")); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; + if (is_listen(node)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + } else if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } } - if ((is_ssh(node)) && (is_listen(node))) { + if (is_listen(node) && is_ssh(node)) { if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; @@ -1555,7 +2189,7 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION } else { nc_server_config_del_private_key(hostkey); } - } else if ((is_tls(node)) && (is_listen(node))) { + } else if (is_listen(node) && is_tls(node)) { /* listen tls */ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { ret = nc_server_config_tls_replace_cleartext_private_key(node, endpt->opts.tls); @@ -1565,210 +2199,108 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION } else { nc_server_config_tls_del_cleartext_private_key(endpt->opts.tls); } - } - -cleanup: - return ret; -} - -static int -nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey) -{ - uint16_t i; - struct nc_keystore *ks = &server_opts.keystore; - - /* lookup name */ - for (i = 0; i < ks->asym_key_count; i++) { - if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) { - break; - } - } - - if (i == ks->asym_key_count) { - ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node)); - return 1; - } - - hostkey->ks_ref = &ks->asym_keys[i]; - - return 0; -} - -/* leaf */ -static int -nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op) -{ - struct nc_endpt *endpt; - struct nc_hostkey *hostkey; - int ret = 0; - - assert(!strcmp(LYD_NAME(node), "keystore-reference")); - - if ((equal_parent_name(node, 3, "server-identity")) && (is_ssh(node)) && (is_listen(node))) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + } else if (is_ch(node) && is_ssh(node)) { + if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to keystore */ - hostkey->store = NC_STORE_KEYSTORE; - - ret = nc_server_config_create_keystore_reference(node, hostkey); - if (ret) { - goto cleanup; - } - } else { - hostkey->ks_ref = NULL; - } - } - -cleanup: - return ret; -} - -static int -nc_server_config_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_client_auth *auth_client) -{ - assert(!strcmp(LYD_NAME(node), "public-key")); - - node = lyd_child(node); - assert(!strcmp(LYD_NAME(node), "name")); - - return nc_server_config_realloc(lyd_get_value(node), (void **)&auth_client->pubkeys, sizeof *auth_client->pubkeys, &auth_client->pubkey_count); -} - -static int -nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey) -{ - nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); - - pubkey->data = strdup(lyd_get_value(node)); - if (!pubkey->data) { - ERRMEM; - return 1; + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_replace_cleartext_private_key(node, hostkey); + if (ret) { + goto cleanup; + } + } else { + nc_server_config_del_private_key(hostkey); + } } - return 0; +cleanup: + return ret; } static int -nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey) +nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey) { - nc_server_config_del_public_key(hostkey); + uint16_t i; + struct nc_keystore *ks = &server_opts.keystore; - hostkey->key.pubkey_data = strdup(lyd_get_value(node)); - if (!hostkey->key.pubkey_data) { - ERRMEM; - return 1; + /* lookup name */ + for (i = 0; i < ks->asym_key_count; i++) { + if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) { + break; + } } - return 0; -} - -static int -nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts) -{ - nc_server_config_tls_del_public_key(opts); - - opts->pubkey_data = strdup(lyd_get_value(node)); - if (!opts->pubkey_data) { - ERRMEM; + if (i == ks->asym_key_count) { + ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node)); return 1; } + hostkey->ks_ref = &ks->asym_keys[i]; + return 0; } +/* leaf */ static int -nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_endpt *endpt; struct nc_hostkey *hostkey; - struct nc_client_auth *auth_client; - struct nc_public_key *pubkey; - - assert(!strcmp(LYD_NAME(node), "public-key")); + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } + assert(!strcmp(LYD_NAME(node), "keystore-reference")); - if ((equal_parent_name(node, 3, "host-key")) && (is_ssh(node)) && (is_listen(node))) { - /* server's public-key, mandatory leaf */ + if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 3, "server-identity")) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to local */ - hostkey->store = NC_STORE_LOCAL; + /* set to keystore */ + hostkey->store = NC_STORE_KEYSTORE; - ret = nc_server_config_replace_host_key_public_key(node, hostkey); + ret = nc_server_config_create_keystore_reference(node, hostkey); if (ret) { goto cleanup; } + } else { + hostkey->ks_ref = NULL; } - } else if ((equal_parent_name(node, 5, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) { - /* client auth pubkeys, list */ - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 3, "server-identity")) { + if (nc_server_config_get_ch_client(node, &ch_client)) { ret = 1; goto cleanup; } - if (op == NC_OP_CREATE) { - /* set to local */ - auth_client->store = NC_STORE_LOCAL; - - ret = nc_server_config_create_auth_key_public_key_list(node, auth_client); - if (ret) { - goto cleanup; - } - } else if (op == NC_OP_DELETE) { - if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { - ret = 1; - goto cleanup; - } - - nc_server_config_del_auth_client_pubkey(auth_client, pubkey); - } - } else if ((equal_parent_name(node, 6, "client-authentication")) && (is_ssh(node)) && (is_listen(node))) { - /* client auth pubkey, leaf */ - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { ret = 1; goto cleanup; } - if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { + if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey); - if (ret) { - goto cleanup; - } - } else { - nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); - } - } else if ((equal_parent_name(node, 3, "server-identity")) && (is_tls(node)) && (is_listen(node))) { - /* tls listen server-identity */ - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to local */ - endpt->opts.tls->store = NC_STORE_LOCAL; + /* set to keystore */ + hostkey->store = NC_STORE_KEYSTORE; - ret = nc_server_config_tls_replace_server_public_key(node, endpt->opts.tls); + ret = nc_server_config_create_keystore_reference(node, hostkey); if (ret) { goto cleanup; } + } else { + hostkey->ks_ref = NULL; } } @@ -1789,13 +2321,15 @@ nc_server_config_create_user(const struct lyd_node *node, struct nc_server_ssh_o static int nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; struct nc_client_auth *auth_client; - int ret = 0; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "user")); - if (equal_parent_name(node, 6, "listen")) { + if (is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -1814,6 +2348,30 @@ nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) nc_server_config_del_auth_client(endpt->opts.ssh, auth_client); } + } else if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_CREATE) { + ret = nc_server_config_create_user(node, ch_endpt->opts.ssh); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + nc_server_config_del_auth_client(ch_endpt->opts.ssh, auth_client); + } } cleanup: @@ -1823,12 +2381,14 @@ nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op) { - struct nc_endpt *endpt; int ret = 0; + struct nc_endpt *endpt; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "auth-attempts")); - if (equal_parent_name(node, 5, "listen")) { + if (is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -1837,6 +2397,20 @@ nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10); } + } else if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10); + } } cleanup: @@ -1846,12 +2420,14 @@ nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) { - struct nc_endpt *endpt; int ret = 0; + struct nc_endpt *endpt; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "auth-timeout")); - if (equal_parent_name(node, 5, "listen")) { + if (is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -1860,6 +2436,20 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10); } + } else if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10); + } } cleanup: @@ -1919,15 +2509,29 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION int ret = 0; struct nc_endpt *endpt; struct nc_client_auth *auth_client; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "truststore-reference")); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; + if (is_listen(node)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + } else if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } } - if ((equal_parent_name(node, 1, "public-keys")) && (is_ssh(node)) && (is_listen(node))) { + if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 1, "public-keys")) { if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; @@ -1944,7 +2548,7 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION } else { auth_client->ts_ref = NULL; } - } else if ((equal_parent_name(node, 1, "ca-certs")) && (is_listen(node))) { + } else if (is_listen(node) && equal_parent_name(node, 1, "ca-certs")) { if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to truststore */ endpt->opts.tls->ca_certs.store = NC_STORE_TRUSTSTORE; @@ -1956,7 +2560,7 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION } else { endpt->opts.tls->ca_certs.ts_ref = NULL; } - } else if ((equal_parent_name(node, 1, "ee-certs")) && (is_listen(node))) { + } else if (is_listen(node) && equal_parent_name(node, 1, "ee-certs")) { if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to truststore */ endpt->opts.tls->ee_certs.store = NC_STORE_TRUSTSTORE; @@ -1968,6 +2572,23 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION } else { endpt->opts.tls->ee_certs.ts_ref = NULL; } + } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 1, "public-keys")) { + if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* set to truststore */ + auth_client->store = NC_STORE_TRUSTSTORE; + + ret = nc_server_config_replace_truststore_reference(node, auth_client); + if (ret) { + goto cleanup; + } + } else { + auth_client->ts_ref = NULL; + } } cleanup: @@ -1992,30 +2613,124 @@ nc_server_config_replace_password(const struct lyd_node *node, struct nc_client_ static int nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; struct nc_client_auth *auth_client; - int ret = 0; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "password")); - if (equal_parent_name(node, 7, "listen")) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (is_listen(node)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_replace_password(node, auth_client); + if (ret) { + goto cleanup; + } + } else { + nc_server_config_del_auth_client_password(auth_client); + } + } else if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_replace_password(node, auth_client); + if (ret) { + goto cleanup; + } + } else { + nc_server_config_del_auth_client_password(auth_client); + } + } + +cleanup: + return ret; +} + +static int +nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_endpt *endpt; + struct nc_client_auth *auth_client; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; + + assert(!strcmp(LYD_NAME(node), "pam-config-file-name")); + + if (is_listen(node)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + nc_server_config_del_auth_client_pam_name(auth_client); + + auth_client->pam_config_name = strdup(lyd_get_value(node)); + if (!auth_client->pam_config_name) { + ERRMEM; + ret = 1; + goto cleanup; + } + } else { + nc_server_config_del_auth_client_pam_name(auth_client); + } + } else if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { ret = 1; goto cleanup; } - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_replace_password(node, auth_client); - if (ret) { + nc_server_config_del_auth_client_pam_name(auth_client); + + auth_client->pam_config_name = strdup(lyd_get_value(node)); + if (!auth_client->pam_config_name) { + ERRMEM; + ret = 1; goto cleanup; } } else { - nc_server_config_del_auth_client_password(auth_client); + nc_server_config_del_auth_client_pam_name(auth_client); } } @@ -2024,15 +2739,17 @@ nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; struct nc_client_auth *auth_client; - int ret = 0; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; - assert(!strcmp(LYD_NAME(node), "pam-config-file-name")); + assert(!strcmp(LYD_NAME(node), "pam-config-file-dir")); - if (equal_parent_name(node, 8, "listen")) { + if (is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -2044,37 +2761,28 @@ nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_auth_client_pam_name(auth_client); - - auth_client->pam_config_name = strdup(lyd_get_value(node)); - if (!auth_client->pam_config_name) { + nc_server_config_del_auth_client_pam_dir(auth_client); + auth_client->pam_config_dir = strdup(lyd_get_value(node)); + if (!auth_client->pam_config_dir) { ERRMEM; ret = 1; goto cleanup; } + } else { + nc_server_config_del_auth_client_pam_dir(auth_client); + } + } else if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; } - } - -cleanup: - return ret; -} - -static int -nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) -{ - struct nc_endpt *endpt; - struct nc_client_auth *auth_client; - int ret = 0; - - assert(!strcmp(LYD_NAME(node), "pam-config-file-dir")); - if (equal_parent_name(node, 8, "listen")) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { ret = 1; goto cleanup; } - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { ret = 1; goto cleanup; } @@ -2087,6 +2795,8 @@ nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) ret = 1; goto cleanup; } + } else { + nc_server_config_del_auth_client_pam_dir(auth_client); } } @@ -2098,13 +2808,15 @@ nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_none(const struct lyd_node *node, NC_OPERATION op) { + int ret = 0; struct nc_endpt *endpt; struct nc_client_auth *auth_client; - int ret = 0; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "none")); - if (equal_parent_name(node, 7, "listen")) { + if (is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -2115,6 +2827,27 @@ nc_server_config_none(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } + if (op == NC_OP_CREATE) { + auth_client->supports_none = 1; + } else { + auth_client->supports_none = 0; + } + } else if (is_ch(node)) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { + ret = 1; + goto cleanup; + } + if (op == NC_OP_CREATE) { auth_client->supports_none = 1; } else { @@ -2214,30 +2947,46 @@ nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OP static int nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op) { - struct nc_endpt *endpt; - int ret = 0, listen = 0; + int ret = 0; const char *alg; uint8_t i; + struct nc_endpt *endpt; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; + struct nc_server_ssh_opts *opts; - /* get the algorithm name and compare it with algs supported by libssh */ - alg = ((struct lyd_node_term *)node)->value.ident->name; + assert(!strcmp(LYD_NAME(node), "host-key-alg")); + assert(is_listen(node) || is_ch(node)); - if (equal_parent_name(node, 6, "listen")) { - listen = 1; + if (is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } + + opts = endpt->opts.ssh; + } else { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + opts = ch_endpt->opts.ssh; } + /* get the algorithm name and compare it with algs supported by libssh */ + alg = ((struct lyd_node_term *)node)->value.ident->name; i = 0; while (supported_hostkey_algs[i]) { if (!strcmp(supported_hostkey_algs[i], alg)) { - if (listen) { - if (nc_server_config_transport_params(alg, &endpt->opts.ssh->hostkey_algs, op)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) { + ret = 1; + goto cleanup; } break; } @@ -2257,30 +3006,46 @@ nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op) { - struct nc_endpt *endpt; - int ret = 0, listen = 0; + int ret = 0; const char *alg; uint8_t i; + struct nc_endpt *endpt; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; + struct nc_server_ssh_opts *opts; - /* get the algorithm name and compare it with algs supported by libssh */ - alg = ((struct lyd_node_term *)node)->value.ident->name; + assert(!strcmp(LYD_NAME(node), "key-exchange-alg")); + assert(is_listen(node) || is_ch(node)); - if (equal_parent_name(node, 6, "listen")) { - listen = 1; + if (is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } + + opts = endpt->opts.ssh; + } else { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + opts = ch_endpt->opts.ssh; } + /* get the algorithm name and compare it with algs supported by libssh */ + alg = ((struct lyd_node_term *)node)->value.ident->name; i = 0; while (supported_kex_algs[i]) { if (!strcmp(supported_kex_algs[i], alg)) { - if (listen) { - if (nc_server_config_transport_params(alg, &endpt->opts.ssh->kex_algs, op)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) { + ret = 1; + goto cleanup; } break; } @@ -2300,30 +3065,46 @@ nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op) { - struct nc_endpt *endpt; - int ret = 0, listen = 0; + int ret = 0; const char *alg; uint8_t i; + struct nc_endpt *endpt; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; + struct nc_server_ssh_opts *opts; - /* get the algorithm name and compare it with algs supported by libssh */ - alg = ((struct lyd_node_term *)node)->value.ident->name; + assert(!strcmp(LYD_NAME(node), "encryption-alg")); + assert(is_listen(node) || is_ch(node)); - if (equal_parent_name(node, 6, "listen")) { - listen = 1; + if (is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } + + opts = endpt->opts.ssh; + } else { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + opts = ch_endpt->opts.ssh; } + /* get the algorithm name and compare it with algs supported by libssh */ + alg = ((struct lyd_node_term *)node)->value.ident->name; i = 0; while (supported_encryption_algs[i]) { if (!strcmp(supported_encryption_algs[i], alg)) { - if (listen) { - if (nc_server_config_transport_params(alg, &endpt->opts.ssh->encryption_algs, op)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) { + ret = 1; + goto cleanup; } break; } @@ -2343,30 +3124,46 @@ nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op) { - struct nc_endpt *endpt; - int ret = 0, listen = 0; + int ret = 0; const char *alg; uint8_t i; + struct nc_endpt *endpt; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; + struct nc_server_ssh_opts *opts; - /* get the algorithm name and compare it with algs supported by libssh */ - alg = ((struct lyd_node_term *)node)->value.ident->name; + assert(!strcmp(LYD_NAME(node), "mac-alg")); + assert(is_listen(node) || is_ch(node)); - if (equal_parent_name(node, 6, "listen")) { - listen = 1; + if (is_listen(node)) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } + + opts = endpt->opts.ssh; + } else { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + opts = ch_endpt->opts.ssh; } + /* get the algorithm name and compare it with algs supported by libssh */ + alg = ((struct lyd_node_term *)node)->value.ident->name; i = 0; while (supported_mac_algs[i]) { if (!strcmp(supported_mac_algs[i], alg)) { - if (listen) { - if (nc_server_config_transport_params(alg, &endpt->opts.ssh->mac_algs, op)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) { + ret = 1; + goto cleanup; } break; } @@ -3303,6 +4100,125 @@ nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op) #endif /* NC_ENABLED_SSH_TLS */ +static int +nc_server_config_create_netconf_client(const struct lyd_node *node) +{ + int ret = 0; + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + + /* LOCK */ + pthread_rwlock_wrlock(&server_opts.ch_client_lock); + + ret = nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.ch_clients, sizeof *server_opts.ch_clients, &server_opts.ch_client_count); + if (ret) { + goto cleanup; + } + + server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id); + server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED; + server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3; // TODO + + pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL); + +cleanup: + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_client_lock); + return ret; +} + +static int +nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_ch_client *ch_client; + + assert(!strcmp(LYD_NAME(node), "netconf-client")); + + if (op == NC_OP_CREATE) { + ret = nc_server_config_create_netconf_client(node); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + nc_server_config_ch_del_client(ch_client); + } + +cleanup: + return ret; +} + +#ifdef NC_ENABLED_SSH_TLS + +static int +nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; + + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + nc_server_config_del_remote_address(ch_endpt); + + ch_endpt->address = strdup(lyd_get_value(node)); + if (!ch_endpt->address) { + ERRMEM; + ret = 1; + goto cleanup; + } + } else { + nc_server_config_del_remote_address(ch_endpt); + } + +cleanup: + return ret; +} + +static int +nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; + + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_endpt->port = strtoul(lyd_get_value(node), NULL, 10); + } else { + ch_endpt->port = 0; + } + +cleanup: + return ret; +} + +#endif /* NC_ENABLED_SSH_TLS */ + static int nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op) { @@ -3476,6 +4392,22 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION } } #endif /* NC_ENABLED_SSH_TLS */ + else if (!strcmp(name, "netconf-client")) { + if (nc_server_config_netconf_client(node, op)) { + goto error; + } + } +#ifdef NC_ENABLED_SSH_TLS + else if (!strcmp(name, "remote-address")) { + if (nc_server_config_remote_address(node, op)) { + goto error; + } + } else if (!strcmp(name, "remote-port")) { + if (nc_server_config_remote_port(node, op)) { + goto error; + } + } +#endif /* NC_ENABLED_SSH_TLS */ return 0; diff --git a/src/server_config.h b/src/server_config.h index 71b50a73..94ade5fc 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -449,6 +449,17 @@ int nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char * int nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config); +int nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + NC_TRANSPORT_IMPL transport, const char *address, const char *port, struct lyd_node **config); + +int nc_server_config_new_ssh_ch_hostkey(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + const char *hostkey_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config); + +int nc_server_config_new_ssh_ch_client_auth_pubkey(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + const char *user_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config); + +int nc_server_config_new_del_ch_client(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config); + #endif /* NC_ENABLED_SSH_TLS */ #ifdef __cplusplus diff --git a/src/server_config_ks.c b/src/server_config_ks.c index 25b67748..eb0ad988 100644 --- a/src/server_config_ks.c +++ b/src/server_config_ks.c @@ -476,7 +476,7 @@ nc_server_config_fill_keystore(const struct lyd_node *data, NC_OPERATION op) ret = lyd_find_path(data, "/ietf-keystore:keystore", 0, &tree); if (ret || (tree->flags & LYD_DEFAULT)) { - VRB(NULL, "Keystore container not found in the YANG data."); + /* not found */ ret = 0; goto cleanup; } diff --git a/src/server_config_p.h b/src/server_config_p.h index f412981d..ccfd9242 100644 --- a/src/server_config_p.h +++ b/src/server_config_p.h @@ -126,6 +126,8 @@ int nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent */ int nc_server_config_listen(struct lyd_node *node, NC_OPERATION op); +void nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op); + #ifdef NC_ENABLED_SSH_TLS /** KEYSTORE **/ diff --git a/src/server_config_ts.c b/src/server_config_ts.c index b0d318b8..e92028c5 100644 --- a/src/server_config_ts.c +++ b/src/server_config_ts.c @@ -617,7 +617,7 @@ nc_server_config_fill_truststore(const struct lyd_node *data, NC_OPERATION op) ret = lyd_find_path(data, "/ietf-truststore:truststore", 0, &tree); if (ret || (tree->flags & LYD_DEFAULT)) { - VRB(NULL, "Truststore container not found in the YANG data."); + /* not found */ ret = 0; goto cleanup; } diff --git a/src/session_p.h b/src/session_p.h index 96c6614d..833e9649 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -461,6 +461,9 @@ struct nc_server_opts { * modify CH clients - READ lock ch_client_lock + ch_client_lock */ struct nc_ch_client { char *name; + + struct nc_session *session; + pthread_t tid; struct nc_ch_endpt { char *name; NC_TRANSPORT_IMPL ti; diff --git a/src/session_server_ch.h b/src/session_server_ch.h index 76b6adf3..42597fe1 100644 --- a/src/session_server_ch.h +++ b/src/session_server_ch.h @@ -217,7 +217,7 @@ typedef void (*nc_server_ch_session_release_ctx_cb)(void *cb_data); * @return 0 on success; * @return non-zero on error and @p new_session is freed. */ -typedef int (*nc_server_ch_new_session_cb)(const char *client_name, struct nc_session *new_session); +typedef int (*nc_server_ch_new_session_cb)(const char *client_name, struct nc_session *new_session, void *user_data); /** * @brief Dispatch a thread connecting to a listening NETCONF client and creating Call Home sessions. @@ -227,10 +227,12 @@ typedef int (*nc_server_ch_new_session_cb)(const char *client_name, struct nc_se * @param[in] release_ctx_cb Callback for releasing session context. * @param[in] ctx_cb_data Arbitrary user data passed to @p acquire_ctx_cb and @p release_ctx_cb. * @param[in] new_session_cb Callback called for every established session on the client. + * @param[in] new_session_cb_data Arbitrary user data passed to @p new_session_cb. * @return 0 if the thread was successfully created, -1 on error. */ int nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb, - nc_server_ch_session_release_ctx_cb release_ctx_cb, void *ctx_cb_data, nc_server_ch_new_session_cb new_session_cb); + nc_server_ch_session_release_ctx_cb release_ctx_cb, void *ctx_cb_data, nc_server_ch_new_session_cb new_session_cb, + void *new_session_cb_data); /** @} Server-side Call Home */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 26ce69b6..931df0f7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -37,7 +37,8 @@ endforeach() #append tests depending on SSH/TLS if(ENABLE_SSH_TLS) - list(APPEND tests test_two_channels test_keystore test_config_new test_truststore test_ec test_ed25519 test_replace test_endpt_share_clients test_tls test_crl) + list(APPEND tests test_two_channels test_keystore test_config_new test_truststore test_ec + test_ed25519 test_replace test_endpt_share_clients test_tls test_crl test_ch) endif() foreach(src IN LISTS libsrc) diff --git a/tests/test_ch.c b/tests/test_ch.c new file mode 100644 index 00000000..c87d0891 --- /dev/null +++ b/tests/test_ch.c @@ -0,0 +1,252 @@ +/** + * @file test_ch.c + * @author Roman Janota + * @brief libnetconf2 Call-home test + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "tests/config.h" + +#define NC_PS_POLL_TIMEOUT 2000 + +#define NC_ACCEPT_TIMEOUT 2000 + +struct ly_ctx *ctx; + +struct test_state { + pthread_barrier_t barrier; +}; + +/* acquire ctx cb for dispatch */ +const struct ly_ctx * +ch_session_acquire_ctx_cb(void *cb_data) +{ + (void) cb_data; + return ctx; +} + +/* release ctx cb for dispatch */ +void +ch_session_release_ctx_cb(void *cb_data) +{ + (void) cb_data; + return; +} + +/* new session cb for dispatch */ +int +ch_new_session_cb(const char *client_name, struct nc_session *new_session, void *user_data) +{ + int ret = 0; + struct nc_pollsession *ps = (struct nc_pollsession *)user_data; + + (void) client_name; + + ret = nc_ps_add_session(ps, new_session); + assert_int_equal(ret, 0); + return 0; +} + +static void * +server_thread(void *arg) +{ + int ret; + struct test_state *state = arg; + struct nc_pollsession *ps; + struct lyd_node *tree = NULL; + + (void) arg; + + /* prepare data for deleting the call-home client */ + ret = nc_server_config_new_del_ch_client(ctx, "ch", &tree); + assert_int_equal(ret, 0); + + /* new poll session */ + ps = nc_ps_new(); + assert_non_null(ps); + + pthread_barrier_wait(&state->barrier); + /* create the call-home client thread */ + ret = nc_connect_ch_client_dispatch("ch", ch_session_acquire_ctx_cb, + ch_session_release_ctx_cb, NULL, ch_new_session_cb, ps); + assert_int_equal(ret, 0); + + /* poll */ + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + if (ret & (NC_PSPOLL_TIMEOUT | NC_PSPOLL_NOSESSIONS)) { + usleep(500); + } + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + /* delete the call-home client, the thread should end */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + lyd_free_tree(tree); + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_server_destroy(); + return NULL; +} + +static void * +client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + + /* set directory where to search for modules */ + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set ssh username */ + ret = nc_client_ssh_ch_set_username("test_ch"); + assert_int_equal(ret, 0); + + /* add client's key pair */ + ret = nc_client_ssh_ch_add_keypair(TESTS_DIR "/data/id_ed25519.pub", TESTS_DIR "/data/id_ed25519"); + assert_int_equal(ret, 0); + + /* add call-home bind */ + ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 10009); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + /* connect */ + ret = nc_accept_callhome(NC_ACCEPT_TIMEOUT, NULL, &session); + assert_int_equal(ret, 1); + + ret = nc_client_ssh_ch_del_bind("127.0.0.1", 10009); + assert_int_equal(ret, 0); + + nc_session_free(session, NULL); + return NULL; +} + +static void +test_nc_ch(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + /* client */ + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + + /* server */ + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + /* create new context */ + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* load default modules into context */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf-netconf-server module and it's imports into context */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ch_address_port(ctx, "ch", "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_ch_hostkey(ctx, "ch", "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_ch_client_auth_pubkey(ctx, "ch", "endpt", "test_ch", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + /* initialize server */ + ret = nc_server_init(); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_ch, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} From d75afa371fa2ed1c3d4aeadec0f504421fc82700 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 29 Jun 2023 09:15:29 +0200 Subject: [PATCH 040/134] config UPDATE add keystore new data API New API for creating keystore and truststore SSH data. Tests now use the new API. --- examples/client.c | 2 +- examples/example.h.in | 2 +- src/config_new.c | 187 ++++++++++------- src/config_new.h | 14 +- src/config_new_ssh.c | 46 ++--- src/server_config.h | 184 ++++++++++++++--- tests/CMakeLists.txt | 2 +- tests/test_auth.c | 98 ++------- tests/test_ch.c | 23 +-- tests/test_config_new.c | 4 +- tests/test_crl.c | 4 +- tests/test_ec.c | 4 +- tests/test_ed25519.c | 4 +- tests/test_endpt_share_clients.c | 12 +- tests/{test_keystore.c => test_ks_ts.c} | 41 ++-- tests/test_replace.c | 20 +- tests/test_tls.c | 4 +- tests/test_truststore.c | 264 ------------------------ tests/test_two_channels.c | 111 +++------- 19 files changed, 413 insertions(+), 613 deletions(-) rename tests/{test_keystore.c => test_ks_ts.c} (90%) delete mode 100644 tests/test_truststore.c diff --git a/examples/client.c b/examples/client.c index 65f26422..7612239f 100644 --- a/examples/client.c +++ b/examples/client.c @@ -194,7 +194,7 @@ main(int argc, char **argv) break; case SSH: - session = nc_connect_ssh(SSH_ADDRESS, atoi(SSH_PORT), NULL); + session = nc_connect_ssh(SSH_ADDRESS, SSH_PORT, NULL); break; case NONE: diff --git a/examples/example.h.in b/examples/example.h.in index 6e214f0b..e195dda6 100644 --- a/examples/example.h.in +++ b/examples/example.h.in @@ -31,7 +31,7 @@ #define SSH_ADDRESS "127.0.0.1" /* SSH listening port */ -#define SSH_PORT "830" +#define SSH_PORT 830 /* SSH 'password' authentication exptected username and password */ #define SSH_USERNAME "admin" diff --git a/src/config_new.c b/src/config_new.c index d6c4c522..d5591a8c 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -34,48 +34,6 @@ #include "session.h" #include "session_p.h" -int -nc_config_new_add_operation(const struct ly_ctx *ctx, struct lyd_node *node, NC_OPERATION op) -{ - struct lyd_meta *meta; - const char *op_str = NULL; - - meta = lyd_find_meta(node->meta, NULL, "yang:operation"); - if (meta) { - /* node already has operation attribute, delete it */ - lyd_free_meta_single(meta); - } - - /* get the operation as string */ - switch (op) { - case NC_OP_CREATE: - op_str = "create"; - break; - case NC_OP_REPLACE: - op_str = "replace"; - break; - case NC_OP_DELETE: - op_str = "delete"; - break; - case NC_OP_NONE: - op_str = "none"; - break; - default: - break; - } - if (!op_str) { - ERR(NULL, "Invalid operation to add to the tree."); - return 1; - } - - /* give the node the operation */ - if (lyd_new_meta(ctx, node, NULL, "yang:operation", op_str, 0, NULL)) { - return 1; - } - - return 0; -} - #ifdef NC_ENABLED_SSH_TLS const char * @@ -675,12 +633,13 @@ nc_server_config_new_get_keys(const char *privkey_path, const char *pubkey_path, API int nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_name, NC_TRANSPORT_IMPL transport, - const char *address, const char *port, struct lyd_node **config) + const char *address, uint16_t port, struct lyd_node **config) { int ret = 0; const char *address_fmt, *port_fmt; + char port_buf[6] = {0}; - NC_CHECK_ARG_RET(NULL, address, port, ctx, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, address, ctx, endpt_name, config, 1); if (transport == NC_TI_LIBSSH) { /* SSH path */ @@ -701,7 +660,8 @@ nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_na goto cleanup; } - ret = nc_config_new_create(ctx, config, port, port_fmt, endpt_name); + sprintf(port_buf, "%d", port); + ret = nc_config_new_create(ctx, config, port_buf, port_fmt, endpt_name); if (ret) { goto cleanup; } @@ -752,15 +712,16 @@ nc_server_config_new_del_ch_client(const struct ly_ctx *ctx, const char *ch_clie { NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1); - return nc_config_new_delete(ctx, config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']", ch_client_name); + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']", ch_client_name); } int -nc_config_new_delete(const struct ly_ctx *ctx, struct lyd_node **tree, const char *path_fmt, ...) +nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...) { int ret = 0; va_list ap; char *path = NULL; + struct lyd_node *sub = NULL; va_start(ap, path_fmt); @@ -772,35 +733,20 @@ nc_config_new_delete(const struct ly_ctx *ctx, struct lyd_node **tree, const cha goto cleanup; } - /* create the nodes in the path */ - ret = lyd_new_path(*tree, ctx, path, NULL, LYD_NEW_PATH_UPDATE, tree); - if (ret) { - goto cleanup; - } - - /* set the node to the last node */ - ret = lyd_find_path(*tree, path, 0, tree); + /* find the node we want to delete */ + ret = lyd_find_path(*tree, path, 0, &sub); if (ret) { goto cleanup; } - /* add delete operation to the node */ - ret = nc_config_new_add_operation(ctx, *tree, NC_OP_DELETE); - if (ret) { - goto cleanup; - } + lyd_free_tree(sub); - /* set the node back to top level container */ + /* set the node to top level container */ ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); if (ret) { goto cleanup; } - ret = nc_config_new_add_operation(ctx, *tree, NC_OP_NONE); - if (ret) { - goto cleanup; - } - /* add all default nodes */ ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -842,12 +788,6 @@ nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const cha goto cleanup; } - /* add create operation to the top level node */ - ret = nc_config_new_add_operation(ctx, *tree, NC_OP_CREATE); - if (ret) { - goto cleanup; - } - /* add all default nodes */ ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -860,4 +800,107 @@ nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const cha return ret; } +API int +nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *name, const char *privkey_path, + const char *pubkey_path, struct lyd_node **config) +{ + int ret = 0; + char *privkey = NULL, *pubkey = NULL; + NC_PRIVKEY_FORMAT privkey_type; + NC_PUBKEY_FORMAT pubkey_type; + const char *privkey_format, *pubkey_format; + + NC_CHECK_ARG_RET(NULL, ctx, name, privkey_path, config, 1); + + /* get the keys as a string from the given files */ + ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); + if (ret) { + ERR(NULL, "Getting keys from file(s) failed."); + goto cleanup; + } + + /* get pubkey format str */ + if (pubkey_type == NC_PUBKEY_FORMAT_X509) { + pubkey_format = "ietf-crypto-types:public-key-info-format"; + } else { + pubkey_format = "ietf-crypto-types:ssh-public-key-format"; + } + + /* get privkey identityref value */ + privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type); + if (!privkey_format) { + ret = 1; + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-keystore:keystore/asymmetric-keys/" + "asymmetric-key[name='%s']/public-key-format", name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, pubkey, "/ietf-keystore:keystore/asymmetric-keys/" + "asymmetric-key[name='%s']/public-key", name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-keystore:keystore/asymmetric-keys/" + "asymmetric-key[name='%s']/private-key-format", name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, privkey, "/ietf-keystore:keystore/asymmetric-keys/" + "asymmetric-key[name='%s']/cleartext-private-key", name); + if (ret) { + goto cleanup; + } + +cleanup: + free(privkey); + free(pubkey); + return ret; +} + +API int +nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag_name, const char *pubkey_name, + const char *pubkey_path, struct lyd_node **config) +{ + int ret = 0; + char *pubkey = NULL; + NC_PUBKEY_FORMAT pubkey_format; + const char *format; + + NC_CHECK_ARG_RET(NULL, ctx, bag_name, pubkey_name, pubkey_path, config, 1); + + ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_format); + if (ret) { + goto cleanup; + } + + /* pubkey format to str */ + if (pubkey_format == NC_PUBKEY_FORMAT_SSH2) { + format = "ietf-crypto-types:ssh-public-key-format"; + } else { + format = "ietf-crypto-types:subject-public-key-info-format"; + } + + ret = nc_config_new_create(ctx, config, format, "/ietf-truststore:truststore/public-key-bags/" + "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", bag_name, pubkey_name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, pubkey, "/ietf-truststore:truststore/public-key-bags/" + "public-key-bag[name='%s']/public-key[name='%s']/public-key", bag_name, pubkey_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(pubkey); + return ret; +} + #endif /* NC_ENABLED_SSH_TLS */ diff --git a/src/config_new.h b/src/config_new.h index ba93dcb8..3388f05b 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -84,10 +84,6 @@ const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT forma #endif /* NC_ENABLED_SSH_TLS */ -int nc_config_new_add_operation(const struct ly_ctx *ctx, struct lyd_node *node, NC_OPERATION op); - -int nc_config_new_delete(const struct ly_ctx *ctx, struct lyd_node **tree, const char *path_fmt, ...); - /** * @brief Creates YANG data nodes in a path and gives the final node a value. * @@ -101,6 +97,16 @@ int nc_config_new_delete(const struct ly_ctx *ctx, struct lyd_node **tree, const */ int nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...); +/** + * @brief Deletes a subtree from the YANG data. + * + * @param tree YANG data from which the subtree will be deleted. + * @param[in] path_fmt Format of the path + * @param[in] ... Parameters for the path format, essentially representing the lists' keys. + * @return 0 on success, non-zero otherwise. + */ +int nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...); + #ifdef __cplusplus } #endif diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index 5266e309..6fed43eb 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -225,12 +225,6 @@ nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *end goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_add_operation(ctx, *config, NC_OP_CREATE); - if (ret) { - goto cleanup; - } - /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -264,12 +258,6 @@ nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_add_operation(ctx, *config, NC_OP_CREATE); - if (ret) { - goto cleanup; - } - /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -303,12 +291,6 @@ nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *e goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_add_operation(ctx, *config, NC_OP_CREATE); - if (ret) { - goto cleanup; - } - /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -342,12 +324,6 @@ nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_na goto cleanup; } - /* check if top-level container has operation and if not, add it */ - ret = nc_config_new_add_operation(ctx, *config, NC_OP_CREATE); - if (ret) { - goto cleanup; - } - /* Add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { @@ -587,3 +563,25 @@ nc_server_config_new_ssh_ch_client_auth_pubkey(const struct ly_ctx *ctx, const c free(pubkey); return ret; } + +API int +nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, + const char *keystore_reference, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, keystore_reference, config, 1); + + return nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" + "keystore-reference", endpt_name, hostkey_name); +} + +API int +nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, + const char *truststore_reference, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, truststore_reference, config, 1); + + return nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" + "truststore-reference", endpt_name, user_name); +} diff --git a/src/server_config.h b/src/server_config.h index 94ade5fc..738e169d 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -92,22 +92,22 @@ int nc_server_config_load_modules(struct ly_ctx **ctx); * @param[in] transport Either SSH or TLS transport for the given endpoint. * @param[in] address New listening address. * @param[in] port New listening port. - * If an endpoint with this identifier already exists, it's address and port will be overriden. + * If an endpoint with this identifier already exists, its address and port will be overriden. * @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_new_address_port(const struct ly_ctx *ctx, const char *endpt_name, NC_TRANSPORT_IMPL transport, - const char *address, const char *port, struct lyd_node **config); + const char *address, uint16_t port, struct lyd_node **config); /** * @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, it's hostkey might be changed. + * 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, it's contents will be changed. + * 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 Path to a file containing a public key. If NULL, public key will be @@ -127,7 +127,7 @@ int nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, * * @param[in] ctx libyang context * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's host-key algorithms will be replaced. + * If an endpoint with this identifier already exists, its host-key algorithms will be replaced. * @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[in] alg_count Number of following algorithms. @@ -146,7 +146,7 @@ int nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char * * @param[in] ctx libyang context * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's key exchange algorithms will be replaced. + * If an endpoint with this identifier already exists, its key exchange algorithms will be replaced. * @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[in] alg_count Number of following algorithms. @@ -164,7 +164,7 @@ int nc_server_config_new_ssh_key_exchange_algs(const struct ly_ctx *ctx, const c * * @param[in] ctx libyang context * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's encryption algorithms will be replaced. + * If an endpoint with this identifier already exists, its encryption algorithms will be replaced. * @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[in] alg_count Number of following algorithms. @@ -181,7 +181,7 @@ int nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const cha * * @param[in] ctx libyang context * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's mac algorithms will be replaced. + * If an endpoint with this identifier already exists, its mac algorithms will be replaced. * @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[in] alg_count Number of following algorithms. @@ -196,11 +196,11 @@ int nc_server_config_new_ssh_mac_algs(const struct ly_ctx *ctx, const char *endp * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's user might be changed. + * 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, it's contents will be changed. + * 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, it's contents will be changed. + * 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. @@ -216,9 +216,9 @@ int nc_server_config_new_ssh_client_auth_pubkey(const struct ly_ctx *ctx, const * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's user might be changed. + * 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, it's contents will be changed. + * If an user with this identifier already exists, its contents will be changed. * @param[in] password Cleartext user's password. * @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. @@ -232,9 +232,9 @@ int nc_server_config_new_ssh_client_auth_password(const struct ly_ctx *ctx, cons * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's user might be changed. + * 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, it's contents will be changed. + * 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. @@ -247,9 +247,9 @@ int nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const ch * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's user might be changed. + * 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, it's contents will be changed. + * If an user with this identifier already exists, its contents will be changed. * @param[in] pam_config_name Name of the PAM configuration file. * @param[in] pam_config_name Optional. The absolute path to the directory in which the configuration file * with the name conf_name is located. A newer version (>= 1.4) of PAM library is required to be able to specify @@ -269,7 +269,7 @@ int nc_server_config_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, c * * @param[in] ctx libyang context * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's contents will be changed. + * 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. @@ -284,7 +284,7 @@ int nc_config_new_ssh_endpoint_client_reference(const struct ly_ctx *ctx, const * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's server certificate will be changed. + * If an endpoint with this identifier already exists, its server certificate will be changed. * @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] privkey_path Path to the server's private key file. @@ -301,7 +301,7 @@ int nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's contents will be changed. + * 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 indetifier already exists, it will be changed. * @param[in] cert_path Path to the client's certificate file. @@ -317,7 +317,7 @@ int nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's contents will be changed. + * 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 indetifier already exists, it will be changed. * @param[in] cert_path Path to the CA certificate file. @@ -333,7 +333,7 @@ int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *end * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's contents will be changed. + * 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. @@ -351,7 +351,7 @@ int nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_nam * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's contents will be changed. + * If an endpoint with this identifier already exists, its contents will be changed. * @param[in] tls_version TLS version to be used. Call this multiple times to set * the accepted versions of the TLS protocol and let the client and server negotiate * the given version. @@ -367,7 +367,7 @@ int nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's contents will be changed. + * If an endpoint 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[in] cipher_count Number of ciphers. @@ -389,7 +389,7 @@ int nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's contents will be changed. + * If an endpoint with this identifier already exists, its contents will be changed. * @param[in] path Path to a DER/PEM encoded CRL 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. @@ -405,7 +405,7 @@ int nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endp * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's contents will be changed. + * If an endpoint with this identifier already exists, its contents will be changed. * @param[in] url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. * The allowed protocols are all the protocols supported by CURL. * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. @@ -424,7 +424,7 @@ int nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's contents will be changed. + * If an endpoint 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. @@ -439,7 +439,7 @@ int nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char * * * @param[in] ctx libyang context * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, it's contents will be changed. + * 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. @@ -449,17 +449,145 @@ int nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char * int nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes for a call-home client's address and port. + * + * @param[in] ctx libyang context. + * @param[in] ch_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_new_ch_address_port(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, NC_TRANSPORT_IMPL transport, const char *address, const char *port, struct lyd_node **config); +/** + * @brief Creates new YANG data nodes for a call-home SSH hostkey. + * + * @param[in] ctx libyang context. + * @param[in] ch_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_new_ssh_ch_hostkey(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, const char *hostkey_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config); +/** + * @brief Creates new YANG data nodes for a call-home client's public key. + * + * @param[in] ctx libyang context. + * @param[in] ch_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_new_ssh_ch_client_auth_pubkey(const struct ly_ctx *ctx, const char *ch_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 client from the YANG data. + * + * @param[in] ctx libyang context. + * @param[in] ch_client_name The name of the client to be deleted from the data. + * The client has to be present in the data. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ int nc_server_config_new_del_ch_client(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config); +/** + * @brief Creates new YANG data nodes for an asymmetric key in the keystore. + * + * @param[in] ctx libyang context. + * @param[in] name Name of the asymmetric key pair. + * This name is used to reference the key pair. + * @param[in] privkey_path Path to a private key file. + * @param[in] pubkey_path Optional path a public key file. + * If not supplied, it 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_new_keystore_asym_key(const struct ly_ctx *ctx, const char *name, const char *privkey_path, + const char *pubkey_path, 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_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, + const char *keystore_reference, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a public key in the truststore. + * + * @param[in] ctx libyang context. + * @param[in] bag_name Arbitrary identifier of the public key bag. + * This name is used to reference the public keys in the bag. + * If a public key bag with this name already exists, its contents will be changed. + * @param[in] pubkey_name Arbitrary identifier of the public key. + * If a public key with this name 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_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag_name, const char *pubkey_name, + const char *pubkey_path, 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 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_new_ssh_truststore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, + const char *truststore_reference, struct lyd_node **config); + #endif /* NC_ENABLED_SSH_TLS */ #ifdef __cplusplus diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 931df0f7..70006545 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -37,7 +37,7 @@ endforeach() #append tests depending on SSH/TLS if(ENABLE_SSH_TLS) - list(APPEND tests test_two_channels test_keystore test_config_new test_truststore test_ec + list(APPEND tests test_two_channels test_ks_ts test_config_new test_ec test_ed25519 test_replace test_endpt_share_clients test_tls test_crl test_ch) endif() diff --git a/tests/test_auth.c b/tests/test_auth.c index 07cf8599..461f6e30 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -36,82 +36,6 @@ struct test_state { pthread_barrier_t barrier; }; -const char *data = - "\n" - " \n" - " 10\n" - " \n" - " default-ssh\n" - " \n" - " \n" - " 127.0.0.1\n" - " 10005\n" - " \n" - " \n" - " \n" - " \n" - " key\n" - " \n" - " \n" - " ct:ssh-public-key-format\n" - " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" - " ct:rsa-private-key-format\n" - " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " test_pk\n" - " \n" - " \n" - " \n" - " test\n" - " ct:ssh-public-key-format\n" - " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " test_int\n" - " \n" - " netconf.conf\n" - " " BUILD_DIR "/tests\n" - " \n" - " \n" - " \n" - " test_pw\n" - " $6$xyz$lomVe5tZ2Gz9uSKKywzXuPcHhqjIByhBbqdUTx/jAwUnw7JRp7QHd4ORiEVqxeZg1NEJkHux.mETo9BFPSh1x.\n" - " \n" - " \n" - " test_none\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " sshpka:rsa-sha2-512\n" - " \n" - " \n" - " sshkea:curve25519-sha256\n" - " \n" - " \n" - " sshea:aes256-ctr\n" - " \n" - " \n" - " sshma:hmac-sha2-512\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n"; - static void * server_thread(void *arg) { @@ -368,7 +292,7 @@ static int setup_f(void **state) { int ret; - struct lyd_node *tree; + struct lyd_node *tree = NULL; struct test_state *test_state; nc_verbosity(NC_VERB_VERBOSE); @@ -391,12 +315,26 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - /* parse yang data */ - ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_pk", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_client_auth_interactive(ctx, "endpt", "test_int", "netconf.conf", BUILD_DIR "/tests", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_client_auth_password(ctx, "endpt", "test_pw", "testpw", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_client_auth_none(ctx, "endpt", "test_none", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); ret = nc_server_init(); diff --git a/tests/test_ch.c b/tests/test_ch.c index c87d0891..7e8f72d4 100644 --- a/tests/test_ch.c +++ b/tests/test_ch.c @@ -35,6 +35,7 @@ struct ly_ctx *ctx; struct test_state { pthread_barrier_t barrier; + struct lyd_node *tree; }; /* acquire ctx cb for dispatch */ @@ -73,12 +74,9 @@ server_thread(void *arg) int ret; struct test_state *state = arg; struct nc_pollsession *ps; - struct lyd_node *tree = NULL; - - (void) arg; /* prepare data for deleting the call-home client */ - ret = nc_server_config_new_del_ch_client(ctx, "ch", &tree); + ret = nc_server_config_new_del_ch_client(ctx, "ch", &state->tree); assert_int_equal(ret, 0); /* new poll session */ @@ -100,10 +98,9 @@ server_thread(void *arg) } while (!(ret & NC_PSPOLL_SESSION_TERM)); /* delete the call-home client, the thread should end */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(state->tree); assert_int_equal(ret, 0); - lyd_free_tree(tree); nc_ps_clear(ps, 1, NULL); nc_ps_free(ps); nc_server_destroy(); @@ -173,7 +170,6 @@ static int setup_f(void **state) { int ret; - struct lyd_node *tree = NULL; struct test_state *test_state; nc_verbosity(NC_VERB_VERBOSE); @@ -185,6 +181,7 @@ setup_f(void **state) ret = pthread_barrier_init(&test_state->barrier, NULL, 2); assert_int_equal(ret, 0); + test_state->tree = NULL; *state = test_state; /* create new context */ @@ -199,25 +196,23 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_new_ch_address_port(ctx, "ch", "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &tree); + ret = nc_server_config_new_ch_address_port(ctx, "ch", "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &test_state->tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_ch_hostkey(ctx, "ch", "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); + ret = nc_server_config_new_ssh_ch_hostkey(ctx, "ch", "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &test_state->tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_ch_client_auth_pubkey(ctx, "ch", "endpt", "test_ch", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); + ret = nc_server_config_new_ssh_ch_client_auth_pubkey(ctx, "ch", "endpt", "test_ch", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->tree); assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(test_state->tree); assert_int_equal(ret, 0); /* initialize server */ ret = nc_server_init(); assert_int_equal(ret, 0); - lyd_free_all(tree); - return 0; } @@ -233,6 +228,8 @@ teardown_f(void **state) ret = pthread_barrier_destroy(&test_state->barrier); assert_int_equal(ret, 0); + lyd_free_tree(test_state->tree); + free(*state); nc_client_destroy(); ly_ctx_destroy(ctx); diff --git a/tests/test_config_new.c b/tests/test_config_new.c index bfdd1104..7b71f0cf 100644 --- a/tests/test_config_new.c +++ b/tests/test_config_new.c @@ -154,7 +154,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new address and port data */ - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", "10005", &tree); + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); /* create the host-key algorithms data */ @@ -166,7 +166,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); ret = nc_server_init(); diff --git a/tests/test_crl.c b/tests/test_crl.c index db8d83c0..126fda9d 100644 --- a/tests/test_crl.c +++ b/tests/test_crl.c @@ -144,7 +144,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new address and port data */ - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", "10005", &tree); + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); /* create new server certificate data */ @@ -182,7 +182,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); ret = nc_server_init(); diff --git a/tests/test_ec.c b/tests/test_ec.c index a8b67be9..0365816d 100644 --- a/tests/test_ec.c +++ b/tests/test_ec.c @@ -216,7 +216,7 @@ setup_f(void **state) ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &tree); + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10009, &tree); assert_int_equal(ret, 0); ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_ec256", "pubkey", TESTS_DIR "/data/id_ecdsa256.pub", &tree); @@ -229,7 +229,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); /* initialize server */ diff --git a/tests/test_ed25519.c b/tests/test_ed25519.c index 96c09531..2767ede6 100644 --- a/tests/test_ed25519.c +++ b/tests/test_ed25519.c @@ -153,14 +153,14 @@ setup_f(void **state) ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/server.key", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &tree); + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10009, &tree); assert_int_equal(ret, 0); ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_ed25519", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); /* initialize server */ diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c index 7ba8e8cd..f0c2f754 100644 --- a/tests/test_endpt_share_clients.c +++ b/tests/test_endpt_share_clients.c @@ -196,7 +196,7 @@ setup_ssh(void **state) ret = nc_server_config_new_ssh_hostkey(ctx, "SSH_endpt_1", "hostkey", TESTS_DIR "/data/key_rsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "SSH_endpt_1", NC_TI_LIBSSH, "127.0.0.1", "10005", &tree); + ret = nc_server_config_new_address_port(ctx, "SSH_endpt_1", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); ret = nc_config_new_ssh_endpoint_client_reference(ctx, "SSH_endpt_1", "SSH_endpt_2", &tree); @@ -206,14 +206,14 @@ setup_ssh(void **state) ret = nc_server_config_new_ssh_hostkey(ctx, "SSH_endpt_2", "hostkey", TESTS_DIR "/data/key_rsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "SSH_endpt_2", NC_TI_LIBSSH, "127.0.0.1", "10006", &tree); + ret = nc_server_config_new_address_port(ctx, "SSH_endpt_2", NC_TI_LIBSSH, "127.0.0.1", 10006, &tree); assert_int_equal(ret, 0); ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "SSH_endpt_2", "client", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the yang data */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); /* initialize the server */ @@ -260,7 +260,7 @@ setup_tls(void **state) TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "TLS_endpt_1", NC_TI_OPENSSL, "127.0.0.1", "10007", &tree); + ret = nc_server_config_new_address_port(ctx, "TLS_endpt_1", NC_TI_OPENSSL, "127.0.0.1", 10007, &tree); assert_int_equal(ret, 0); ret = nc_server_config_new_tls_client_certificate(ctx, "TLS_endpt_1", "cert_client", TESTS_DIR "/data/client.crt", &tree); @@ -279,14 +279,14 @@ setup_tls(void **state) TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "TLS_endpt_2", NC_TI_OPENSSL, "127.0.0.1", "10008", &tree); + ret = nc_server_config_new_address_port(ctx, "TLS_endpt_2", NC_TI_OPENSSL, "127.0.0.1", 10008, &tree); assert_int_equal(ret, 0); ret = nc_config_new_tls_endpoint_client_reference(ctx, "TLS_endpt_2", "TLS_endpt_1", &tree); assert_int_equal(ret, 0); /* configure the server based on the yang data */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); /* initialize the server */ diff --git a/tests/test_keystore.c b/tests/test_ks_ts.c similarity index 90% rename from tests/test_keystore.c rename to tests/test_ks_ts.c index 48322a39..fb179e06 100644 --- a/tests/test_keystore.c +++ b/tests/test_ks_ts.c @@ -1,10 +1,10 @@ /** - * @file test_keystore.c + * @file test_ks_ts.c * @author Roman Janota - * @brief libnetconf2 Linux PAM keyboard-interactive authentication test + * @brief libnetconf2 Keystore and trustore usage test. * * @copyright - * Copyright (c) 2022 CESNET, z.s.p.o. + * Copyright (c) 2023 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. @@ -136,7 +136,7 @@ server_thread(void *arg) } static void * -client_thread_pubkey(void *arg) +client_thread(void *arg) { int ret; struct nc_session *session = NULL; @@ -148,14 +148,10 @@ client_thread_pubkey(void *arg) ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); - ret = nc_client_ssh_set_username("test_ts"); + ret = nc_client_ssh_set_username("client"); assert_int_equal(ret, 0); - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); - - ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/id_ed25519.pub", TESTS_DIR "/data/id_ed25519"); assert_int_equal(ret, 0); pthread_barrier_wait(&state->barrier); @@ -167,14 +163,14 @@ client_thread_pubkey(void *arg) } static void -test_nc_auth_pubkey(void **state) +test_nc_ks_ts(void **state) { int ret, i; pthread_t tids[2]; assert_non_null(state); - ret = pthread_create(&tids[0], NULL, client_thread_pubkey, *state); + ret = pthread_create(&tids[0], NULL, client_thread, *state); assert_int_equal(ret, 0); ret = pthread_create(&tids[1], NULL, server_thread, *state); assert_int_equal(ret, 0); @@ -188,7 +184,7 @@ static int setup_f(void **state) { int ret; - struct lyd_node *tree; + struct lyd_node *tree = NULL; struct test_state *test_state; nc_verbosity(NC_VERB_VERBOSE); @@ -211,12 +207,23 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - /* parse yang data */ - ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_keystore_reference(ctx, "endpt", "hostkey", "test_keystore", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_truststore_reference(ctx, "endpt", "client", "test_truststore", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_keystore_asym_key(ctx, "test_keystore", TESTS_DIR "/data/key_rsa", NULL, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_truststore_pubkey(ctx, "test_truststore", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); ret = nc_server_init(); @@ -251,7 +258,7 @@ int main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_nc_auth_pubkey, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_ks_ts, setup_f, teardown_f), }; setenv("CMOCKA_TEST_ABORT", "1", 1); diff --git a/tests/test_replace.c b/tests/test_replace.c index 6f43d40d..2fba3bdb 100644 --- a/tests/test_replace.c +++ b/tests/test_replace.c @@ -167,7 +167,7 @@ client_thread(void *arg) assert_int_equal(ret, 0); /* set ssh username */ - ret = nc_client_ssh_set_username("new_user"); + ret = nc_client_ssh_set_username("new_client"); assert_int_equal(ret, 0); /* add client's key pair */ @@ -233,16 +233,26 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - /* parse yang data */ - ret = lyd_parse_data_mem(ctx, old_data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &old_tree); + ret = nc_server_config_new_address_port(ctx, "old", NC_TI_LIBSSH, "127.0.0.1", 10005, &old_tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_hostkey(ctx, "old", "old_key", TESTS_DIR "/data/key_rsa", NULL, &old_tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_client_auth_password(ctx, "old", "old_client", "passwd", &old_tree); assert_int_equal(ret, 0); /* configure the server based on the yang data, treat them as if every node had replace operation */ ret = nc_server_config_setup_data(old_tree); assert_int_equal(ret, 0); - /* parse the new yang data */ - ret = lyd_parse_data_mem(ctx, new_data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &new_tree); + ret = nc_server_config_new_address_port(ctx, "new", NC_TI_LIBSSH, "127.0.0.1", 10005, &new_tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_hostkey(ctx, "new", "new_key", TESTS_DIR "/data/key_rsa", NULL, &new_tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "new", "new_client", "pubkey", TESTS_DIR "/data/key_rsa.pub", &new_tree); assert_int_equal(ret, 0); /* configure the server based on the yang data, meaning diff --git a/tests/test_tls.c b/tests/test_tls.c index ba427d7f..90970ee0 100644 --- a/tests/test_tls.c +++ b/tests/test_tls.c @@ -138,7 +138,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new address and port data */ - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", "10005", &tree); + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); /* create new server certificate data */ @@ -168,7 +168,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); ret = nc_server_init(); diff --git a/tests/test_truststore.c b/tests/test_truststore.c deleted file mode 100644 index 9ed41431..00000000 --- a/tests/test_truststore.c +++ /dev/null @@ -1,264 +0,0 @@ -/** - * @file test_truststore.c - * @author Roman Janota - * @brief libnetconf2 Truststore configuration and authentication test. - * - * @copyright - * Copyright (c) 2023 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 - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "tests/config.h" - -#define NC_ACCEPT_TIMEOUT 2000 -#define NC_PS_POLL_TIMEOUT 2000 - -struct ly_ctx *ctx; - -struct test_state { - pthread_barrier_t barrier; -}; - -const char *data = - "\n" - " \n" - " 10\n" - " \n" - " default-ssh\n" - " \n" - " \n" - " 127.0.0.1\n" - " 10005\n" - " \n" - " \n" - " \n" - " \n" - " key\n" - " \n" - " \n" - " ct:ssh-public-key-format\n" - " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" - " ct:rsa-private-key-format\n" - " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " test_truststore\n" - " \n" - " test_truststore\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " sshpka:rsa-sha2-512\n" - " \n" - " \n" - " sshkea:curve25519-sha256\n" - " \n" - " \n" - " sshea:aes256-ctr\n" - " \n" - " \n" - " sshma:hmac-sha2-512\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n" - "\n" - "\n" - " \n" - " \n" - " test_truststore\n" - " Let's hope this works\n" - " \n" - " pubkey\n" - " ct:ssh-public-key-format\n" - " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" - " \n" - " \n" - " \n" - "\n" -; - -static void * -server_thread(void *arg) -{ - int ret; - NC_MSG_TYPE msgtype; - struct nc_session *session; - struct nc_pollsession *ps; - struct test_state *state = arg; - - ps = nc_ps_new(); - assert_non_null(ps); - - /* accept a session and add it to the poll session structure */ - pthread_barrier_wait(&state->barrier); - msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); - assert_int_equal(msgtype, NC_MSG_HELLO); - - ret = nc_ps_add_session(ps, session); - assert_int_equal(ret, 0); - - do { - ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); - assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); - } while (!(ret & NC_PSPOLL_SESSION_TERM)); - - nc_ps_clear(ps, 1, NULL); - nc_ps_free(ps); - return NULL; -} - -static void * -client_thread(void *arg) -{ - int ret; - struct nc_session *session = NULL; - struct test_state *state = arg; - - /* skip all hostkey and known_hosts checks */ - nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); - - /* set directory where to search for modules */ - ret = nc_client_set_schema_searchpath(MODULES_DIR); - assert_int_equal(ret, 0); - - /* set ssh username */ - ret = nc_client_ssh_set_username("test_truststore"); - assert_int_equal(ret, 0); - - /* add client's key pair */ - ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); - assert_int_equal(ret, 0); - - pthread_barrier_wait(&state->barrier); - /* connect */ - session = nc_connect_ssh("127.0.0.1", 10005, NULL); - assert_non_null(session); - - nc_session_free(session, NULL); - return NULL; -} - -static void -test_nc_auth_truststore(void **state) -{ - int ret, i; - pthread_t tids[2]; - - assert_non_null(state); - - ret = pthread_create(&tids[0], NULL, client_thread, *state); - assert_int_equal(ret, 0); - ret = pthread_create(&tids[1], NULL, server_thread, *state); - assert_int_equal(ret, 0); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static int -setup_f(void **state) -{ - int ret; - struct lyd_node *tree; - struct test_state *test_state; - - nc_verbosity(NC_VERB_VERBOSE); - - /* init barrier */ - test_state = malloc(sizeof *test_state); - assert_non_null(test_state); - - ret = pthread_barrier_init(&test_state->barrier, NULL, 2); - assert_int_equal(ret, 0); - - *state = test_state; - - /* create new context */ - ret = ly_ctx_new(MODULES_DIR, 0, &ctx); - assert_int_equal(ret, 0); - - /* load default modules into context */ - ret = nc_server_init_ctx(&ctx); - assert_int_equal(ret, 0); - - /* load ietf-netconf-server module and it's imports into context */ - ret = nc_server_config_load_modules(&ctx); - assert_int_equal(ret, 0); - - /* parse yang data */ - ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); - assert_int_equal(ret, 0); - - /* configure the server based on the data */ - ret = nc_server_config_setup_diff(tree); - assert_int_equal(ret, 0); - - /* initialize server */ - ret = nc_server_init(); - assert_int_equal(ret, 0); - - lyd_free_all(tree); - - return 0; -} - -static int -teardown_f(void **state) -{ - int ret = 0; - struct test_state *test_state; - - assert_non_null(state); - test_state = *state; - - ret = pthread_barrier_destroy(&test_state->barrier); - assert_int_equal(ret, 0); - - free(*state); - nc_client_destroy(); - nc_server_destroy(); - ly_ctx_destroy(ctx); - - return 0; -} - -int -main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_nc_auth_truststore, setup_f, teardown_f), - }; - - setenv("CMOCKA_TEST_ABORT", "1", 1); - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c index 16e17d2a..801264d1 100644 --- a/tests/test_two_channels.c +++ b/tests/test_two_channels.c @@ -1,10 +1,10 @@ /** - * @file test_pam.c + * @file test_two_channels.c * @author Roman Janota - * @brief libnetconf2 Linux PAM keyboard-interactive authentication test + * @brief libnetconf2 Openning a new session on an established SSH channel test. * * @copyright - * Copyright (c) 2022 CESNET, z.s.p.o. + * Copyright (c) 2023 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. @@ -32,80 +32,6 @@ #define BACKOFF_TIMEOUT_USECS 100 struct ly_ctx *ctx; -int flag = 0; - -const char *data = - "\n" - " \n" - " 10\n" - " \n" - " default-ssh\n" - " \n" - " \n" - " 127.0.0.1\n" - " 10005\n" - " \n" - " \n" - " \n" - " \n" - " key\n" - " \n" - " \n" - " ct:ssh-public-key-format\n" - " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" - " ct:rsa-private-key-format\n" - " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " test1\n" - " \n" - " \n" - " \n" - " client\n" - " ct:ssh-public-key-format\n" - " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " test2\n" - " \n" - " \n" - " \n" - " client\n" - " ct:ssh-public-key-format\n" - " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " sshpka:rsa-sha2-512\n" - " \n" - " \n" - " sshkea:curve25519-sha256\n" - " \n" - " \n" - " sshea:aes256-ctr\n" - " \n" - " \n" - " sshma:hmac-sha2-512\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n"; static void * server_thread(void *arg) @@ -164,20 +90,22 @@ client_thread(void *arg) ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); - - ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/id_ed25519.pub", TESTS_DIR "/data/id_ed25519"); assert_int_equal(ret, 0); - ret = nc_client_ssh_set_username("test1"); + ret = nc_client_ssh_set_username("client_1"); assert_int_equal(ret, 0); session_cl1 = nc_connect_ssh("127.0.0.1", 10005, NULL); assert_non_null(session_cl1); - ret = nc_client_ssh_set_username("test2"); + ret = nc_client_ssh_set_username("client_2"); + assert_int_equal(ret, 0); + + ret = nc_client_ssh_del_keypair(0); + assert_int_equal(ret, 0); + + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/id_ecdsa521.pub", TESTS_DIR "/data/id_ecdsa521"); assert_int_equal(ret, 0); session_cl2 = nc_connect_ssh_channel(session_cl1, NULL); @@ -211,7 +139,7 @@ static int setup_f(void **state) { int ret; - struct lyd_node *tree; + struct lyd_node *tree = NULL; (void) state; @@ -226,10 +154,19 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "client_1", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "client_2", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); ret = nc_server_init(); From d301202ba7bafa6111f04fd6d231aad302f7c573 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 29 Jun 2023 09:16:46 +0200 Subject: [PATCH 041/134] config REFACTOR getting list instances --- src/config_new.c | 12 +- src/config_new_ssh.c | 8 +- src/server_config.c | 1137 +++++++++++----------------------------- src/server_config_ks.c | 22 +- src/server_config_p.h | 39 -- src/server_config_ts.c | 43 +- 6 files changed, 354 insertions(+), 907 deletions(-) diff --git a/src/config_new.c b/src/config_new.c index d5591a8c..b36bfeff 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -834,25 +834,25 @@ nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *nam } ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/public-key-format", name); + "asymmetric-key[name='%s']/public-key-format", name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, pubkey, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/public-key", name); + "asymmetric-key[name='%s']/public-key", name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/private-key-format", name); + "asymmetric-key[name='%s']/private-key-format", name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, privkey, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/cleartext-private-key", name); + "asymmetric-key[name='%s']/cleartext-private-key", name); if (ret) { goto cleanup; } @@ -887,13 +887,13 @@ nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag } ret = nc_config_new_create(ctx, config, format, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", bag_name, pubkey_name); + "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", bag_name, pubkey_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, pubkey, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key[name='%s']/public-key", bag_name, pubkey_name); + "public-key-bag[name='%s']/public-key[name='%s']/public-key", bag_name, pubkey_name); if (ret) { goto cleanup; } diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index 6fed43eb..8ecd7f2d 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -571,8 +571,8 @@ nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, keystore_reference, config, 1); return nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" - "keystore-reference", endpt_name, hostkey_name); + "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" + "keystore-reference", endpt_name, hostkey_name); } API int @@ -582,6 +582,6 @@ nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, const ch NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, truststore_reference, config, 1); return nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" - "truststore-reference", endpt_name, user_name); + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" + "truststore-reference", endpt_name, user_name); } diff --git a/src/server_config.c b/src/server_config.c index 8e3d3e5e..1a46b213 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -70,13 +70,77 @@ static const char *supported_mac_algs[] = { extern struct nc_server_opts server_opts; -int +static int +is_listen(const struct lyd_node *node) +{ + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "listen")) { + break; + } + node = lyd_parent(node); + } + + return node != NULL; +} + +static int +is_ch(const struct lyd_node *node) +{ + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "call-home")) { + break; + } + node = lyd_parent(node); + } + + return node != NULL; +} + +#ifdef NC_ENABLED_SSH_TLS + +static int +is_ssh(const struct lyd_node *node) +{ + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "ssh")) { + break; + } + node = lyd_parent(node); + } + + return node != NULL; +} + +static int +is_tls(const struct lyd_node *node) +{ + assert(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "tls")) { + break; + } + node = lyd_parent(node); + } + + return node != NULL; +} + +#endif /* NC_ENABLED_SSH_TLS */ + +static int nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind) { uint16_t i; const char *endpt_name; - assert(node); + assert(node && endpt); while (node) { if (!strcmp(LYD_NAME(node), "endpoint")) { @@ -108,12 +172,14 @@ nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, return 1; } -int +static int nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client **ch_client) { uint16_t i; const char *ch_client_name; + assert(node && ch_client); + while (node) { if (!strcmp(LYD_NAME(node), "netconf-client")) { break; @@ -141,11 +207,20 @@ nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client return 1; } -int -nc_server_config_get_ch_endpt(const struct lyd_node *node, const struct nc_ch_client *ch_client, struct nc_ch_endpt **ch_endpt) +#ifdef NC_ENABLED_SSH_TLS + +static int +nc_server_config_get_ch_endpt(const struct lyd_node *node, struct nc_ch_endpt **ch_endpt) { uint16_t i; const char *ch_endpt_name; + struct nc_ch_client *ch_client; + + assert(node && ch_endpt); + + if (nc_server_config_get_ch_client(node, &ch_client)) { + return 1; + } while (node) { if (!strcmp(LYD_NAME(node), "endpoint")) { @@ -174,15 +249,51 @@ nc_server_config_get_ch_endpt(const struct lyd_node *node, const struct nc_ch_cl return 1; } -#ifdef NC_ENABLED_SSH_TLS +static int +nc_server_config_get_ssh_opts(const struct lyd_node *node, struct nc_server_ssh_opts **opts) +{ + struct nc_endpt *endpt; + struct nc_ch_endpt *ch_endpt; -int -nc_server_config_get_hostkey(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_hostkey **hostkey) + assert(node && opts); + + if (is_listen(node)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + return 1; + } + *opts = endpt->opts.ssh; + } else { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { + return 1; + } + *opts = ch_endpt->opts.ssh; + } + + return 0; +} + +static int +nc_server_config_get_hostkey(const struct lyd_node *node, struct nc_hostkey **hostkey) { uint16_t i; const char *hostkey_name; + struct nc_endpt *endpt; + struct nc_ch_endpt *ch_endpt; + struct nc_server_ssh_opts *opts; - assert(node && opts); + assert(node && hostkey); + + if (is_listen(node)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + return 1; + } + opts = endpt->opts.ssh; + } else { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { + return 1; + } + opts = ch_endpt->opts.ssh; + } while (node) { if (!strcmp(LYD_NAME(node), "host-key")) { @@ -211,13 +322,28 @@ nc_server_config_get_hostkey(const struct lyd_node *node, const struct nc_server return 1; } -int -nc_server_config_get_auth_client(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_client_auth **auth_client) +static int +nc_server_config_get_auth_client(const struct lyd_node *node, struct nc_client_auth **auth_client) { uint16_t i; const char *authkey_name; + struct nc_endpt *endpt; + struct nc_ch_endpt *ch_endpt; + struct nc_server_ssh_opts *opts; - assert(node && opts); + assert(node && auth_client); + + if (is_listen(node)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + return 1; + } + opts = endpt->opts.ssh; + } else { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { + return 1; + } + opts = ch_endpt->opts.ssh; + } while (node) { if (!strcmp(LYD_NAME(node), "user")) { @@ -246,13 +372,18 @@ nc_server_config_get_auth_client(const struct lyd_node *node, const struct nc_se return 1; } -int -nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_public_key **pubkey) +static int +nc_server_config_get_pubkey(const struct lyd_node *node, struct nc_public_key **pubkey) { uint16_t i; const char *pubkey_name; + struct nc_client_auth *auth_client; - assert(node && auth_client); + assert(node && pubkey); + + if (nc_server_config_get_auth_client(node, &auth_client)) { + return 1; + } node = lyd_parent(node); while (node) { @@ -282,13 +413,25 @@ nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_client_ return 1; } -int -nc_server_config_get_cert(const struct lyd_node *node, struct nc_cert_grouping *auth_client, struct nc_certificate **cert) +static int +nc_server_config_get_cert(const struct lyd_node *node, int is_ee, struct nc_certificate **cert) { uint16_t i; const char *cert_name; + struct nc_endpt *endpt; + struct nc_cert_grouping *auth_client; - assert(node && auth_client); + assert(node && cert); + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + return 1; + } + + if (is_ee) { + auth_client = &endpt->opts.tls->ee_certs; + } else { + auth_client = &endpt->opts.tls->ca_certs; + } while (node) { if (!strcmp(LYD_NAME(node), "certificate")) { @@ -318,12 +461,17 @@ nc_server_config_get_cert(const struct lyd_node *node, struct nc_cert_grouping * } static int -nc_server_config_get_ctn(const struct lyd_node *node, struct nc_endpt *endpt, struct nc_ctn **ctn) +nc_server_config_get_ctn(const struct lyd_node *node, struct nc_ctn **ctn) { uint32_t id; struct nc_ctn *iter; + struct nc_endpt *endpt; - assert(node && endpt); + assert(node && ctn); + + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + return 1; + } node = lyd_parent(node); while (node) { @@ -428,70 +576,6 @@ nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_ return ret; } -static int -is_listen(const struct lyd_node *node) -{ - assert(node); - - while (node) { - if (!strcmp(LYD_NAME(node), "listen")) { - break; - } - node = lyd_parent(node); - } - - return node != NULL; -} - -static int -is_ch(const struct lyd_node *node) -{ - assert(node); - - while (node) { - if (!strcmp(LYD_NAME(node), "call-home")) { - break; - } - node = lyd_parent(node); - } - - return node != NULL; -} - -#ifdef NC_ENABLED_SSH_TLS - -static int -is_ssh(const struct lyd_node *node) -{ - assert(node); - - while (node) { - if (!strcmp(LYD_NAME(node), "ssh")) { - break; - } - node = lyd_parent(node); - } - - return node != NULL; -} - -static int -is_tls(const struct lyd_node *node) -{ - assert(node); - - while (node) { - if (!strcmp(LYD_NAME(node), "tls")) { - break; - } - node = lyd_parent(node); - } - - return node != NULL; -} - -#endif /* NC_ENABLED_SSH_TLS */ - static void nc_server_config_del_endpt_name(struct nc_endpt *endpt) { @@ -550,13 +634,6 @@ nc_server_config_del_private_key(struct nc_hostkey *hostkey) hostkey->key.privkey_data = NULL; } -static void -nc_server_config_del_auth_client_username(struct nc_client_auth *auth_client) -{ - free(auth_client->username); - auth_client->username = NULL; -} - static void nc_server_config_del_auth_client_pubkey_name(struct nc_public_key *pubkey) { @@ -642,6 +719,9 @@ nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_clie { uint16_t i, pubkey_count; + free(auth_client->username); + auth_client->username = NULL; + if (auth_client->store == NC_STORE_LOCAL) { pubkey_count = auth_client->pubkey_count; for (i = 0; i < pubkey_count; i++) { @@ -652,7 +732,6 @@ nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_clie nc_server_config_del_auth_client_password(auth_client); nc_server_config_del_auth_client_pam_name(auth_client); nc_server_config_del_auth_client_pam_dir(auth_client); - nc_server_config_del_auth_client_username(auth_client); opts->client_count--; if (!opts->client_count) { @@ -1242,7 +1321,6 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_bind *bind; - struct nc_ch_client *ch_client; struct nc_ch_endpt *ch_endpt; int ret = 0; @@ -1263,12 +1341,7 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) nc_server_config_del_ssh(bind, endpt->opts.ssh); } } else { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; } @@ -1468,7 +1541,6 @@ nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_endpt *endpt; struct nc_bind *bind; - struct nc_ch_client *ch_client; struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "keepalives")); @@ -1489,12 +1561,7 @@ nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; } @@ -1517,7 +1584,6 @@ nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_endpt *endpt; struct nc_bind *bind; - struct nc_ch_client *ch_client; struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "idle-time")); @@ -1538,12 +1604,7 @@ nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; } @@ -1566,7 +1627,6 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_endpt *endpt; struct nc_bind *bind; - struct nc_ch_client *ch_client; struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "max-probes")); @@ -1587,12 +1647,7 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; } @@ -1615,7 +1670,6 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_endpt *endpt; struct nc_bind *bind; - struct nc_ch_client *ch_client; struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "probe-interval")); @@ -1636,12 +1690,7 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; } @@ -1671,53 +1720,28 @@ static int nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_hostkey *hostkey; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; + struct nc_server_ssh_opts *opts; assert(!strcmp(LYD_NAME(node), "host-key")); - if (is_listen(node) && equal_parent_name(node, 1, "server-identity")) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - if (op == NC_OP_CREATE) { - ret = nc_server_config_create_host_key(node, endpt->opts.ssh); - if (ret) { - goto cleanup; - } - } else if (op == NC_OP_DELETE) { - if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { - ret = 1; - goto cleanup; - } - nc_server_config_del_hostkey(endpt->opts.ssh, hostkey); - } - } else if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_get_ssh_opts(node, &opts)) { + ret = 1; + goto cleanup; + } + if (equal_parent_name(node, 1, "server-identity")) { if (op == NC_OP_CREATE) { - ret = nc_server_config_create_host_key(node, ch_endpt->opts.ssh); + ret = nc_server_config_create_host_key(node, opts); if (ret) { goto cleanup; } } else if (op == NC_OP_DELETE) { - if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_hostkey(node, &hostkey)) { ret = 1; goto cleanup; } - nc_server_config_del_hostkey(ch_endpt->opts.ssh, hostkey); + nc_server_config_del_hostkey(opts, hostkey); } } @@ -1733,11 +1757,8 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) const char *format; NC_PUBKEY_FORMAT pubkey_type; struct nc_endpt *endpt; - struct nc_client_auth *auth_client; struct nc_public_key *pubkey; struct nc_hostkey *hostkey; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "public-key-format")); @@ -1752,26 +1773,9 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - } else if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } - } - - if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 4, "server-identity")) { + if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) { /* SSH hostkey public key fmt */ - if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_hostkey(node, &hostkey)) { ret = 1; goto cleanup; } @@ -1779,14 +1783,9 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { hostkey->key.pubkey_type = pubkey_type; } - } else if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { + } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { /* SSH client auth public key fmt */ - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { + if (nc_server_config_get_pubkey(node, &pubkey)) { ret = 1; goto cleanup; } @@ -1796,33 +1795,13 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) } } else if (is_listen(node) && is_tls(node) && equal_parent_name(node, 3, "server-identity")) { /* TLS listen server-identity */ - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->opts.tls->pubkey_type = pubkey_type; - } - } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 4, "server-identity")) { - /* CH SSH server host-key public key fmt */ - if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - hostkey->key.pubkey_type = pubkey_type; - } - } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { - /* CH SSH client auth public key fmt */ - if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - pubkey->type = pubkey_type; + endpt->opts.tls->pubkey_type = pubkey_type; } } @@ -1891,33 +1870,12 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) struct nc_hostkey *hostkey; struct nc_client_auth *auth_client; struct nc_public_key *pubkey; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "public-key")); - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - } - - if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } - } - - if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 3, "host-key")) { + if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) { /* server's public-key, mandatory leaf */ - if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_hostkey(node, &hostkey)) { ret = 1; goto cleanup; } @@ -1931,9 +1889,9 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } - } else if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) { + } else if (is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) { /* client auth pubkeys, list */ - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_auth_client(node, &auth_client)) { ret = 1; goto cleanup; } @@ -1947,21 +1905,16 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { + if (nc_server_config_get_pubkey(node, &pubkey)) { ret = 1; goto cleanup; } nc_server_config_del_auth_client_pubkey(auth_client, pubkey); } - } else if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { + } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { /* client auth pubkey, leaf */ - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { + if (nc_server_config_get_pubkey(node, &pubkey)) { ret = 1; goto cleanup; } @@ -1976,73 +1929,19 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } } else if (is_listen(node) && is_tls(node) && equal_parent_name(node, 3, "server-identity")) { /* tls listen server-identity */ - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to local */ - endpt->opts.tls->store = NC_STORE_LOCAL; - - ret = nc_server_config_tls_replace_server_public_key(node, endpt->opts.tls); - if (ret) { - goto cleanup; - } - } - } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 3, "host-key")) { - /* CH SSH hostkey's public key */ - if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to local */ - hostkey->store = NC_STORE_LOCAL; - - ret = nc_server_config_replace_host_key_public_key(node, hostkey); - if (ret) { - goto cleanup; - } - } - } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) { - /* CH SSH client auth list */ - if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } - - if (op == NC_OP_CREATE) { - /* set to local */ - auth_client->store = NC_STORE_LOCAL; - - ret = nc_server_config_create_auth_key_public_key_list(node, auth_client); - if (ret) { - goto cleanup; - } - } else if (op == NC_OP_DELETE) { - if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { - ret = 1; - goto cleanup; - } - - nc_server_config_del_auth_client_pubkey(auth_client, pubkey); - } - } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { - /* CH SSH client auth leaf */ - if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_pubkey(node, auth_client, &pubkey)) { - ret = 1; - goto cleanup; - } + endpt->opts.tls->store = NC_STORE_LOCAL; - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey); + ret = nc_server_config_tls_replace_server_public_key(node, endpt->opts.tls); if (ret) { goto cleanup; } - } else { - nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); } } @@ -2059,8 +1958,6 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op NC_PRIVKEY_FORMAT privkey_type; struct nc_endpt *endpt; struct nc_hostkey *hostkey; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; (void) op; @@ -2079,26 +1976,9 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op goto cleanup; } - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - } else if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } - } - - if (is_listen(node) && is_ssh(node)) { - /* listen ssh */ - if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + if (is_ssh(node)) { + /* ssh */ + if (nc_server_config_get_hostkey(node, &hostkey)) { ret = 1; goto cleanup; } @@ -2106,15 +1986,12 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op hostkey->key.privkey_type = privkey_type; } else if (is_listen(node) && is_tls(node)) { /* listen tls */ - endpt->opts.tls->privkey_type = privkey_type; - } else if (is_ch(node) && is_ssh(node)) { - /* ch ssh */ - if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } - hostkey->key.privkey_type = privkey_type; + endpt->opts.tls->privkey_type = privkey_type; } cleanup: @@ -2153,30 +2030,12 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION int ret = 0; struct nc_endpt *endpt; struct nc_hostkey *hostkey; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "cleartext-private-key")); - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - } else if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } - } - - if (is_listen(node) && is_ssh(node)) { - if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { + if (is_ssh(node)) { + /* ssh */ + if (nc_server_config_get_hostkey(node, &hostkey)) { ret = 1; goto cleanup; } @@ -2191,27 +2050,18 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION } } else if (is_listen(node) && is_tls(node)) { /* listen tls */ - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_tls_replace_cleartext_private_key(node, endpt->opts.tls); - if (ret) { - goto cleanup; - } - } else { - nc_server_config_tls_del_cleartext_private_key(endpt->opts.tls); - } - } else if (is_ch(node) && is_ssh(node)) { - if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_replace_cleartext_private_key(node, hostkey); + ret = nc_server_config_tls_replace_cleartext_private_key(node, endpt->opts.tls); if (ret) { goto cleanup; } } else { - nc_server_config_del_private_key(hostkey); + nc_server_config_tls_del_cleartext_private_key(endpt->opts.tls); } } @@ -2247,46 +2097,12 @@ static int nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_hostkey *hostkey; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "keystore-reference")); - if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 3, "server-identity")) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - if (nc_server_config_get_hostkey(node, endpt->opts.ssh, &hostkey)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to keystore */ - hostkey->store = NC_STORE_KEYSTORE; - - ret = nc_server_config_create_keystore_reference(node, hostkey); - if (ret) { - goto cleanup; - } - } else { - hostkey->ks_ref = NULL; - } - } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 3, "server-identity")) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_hostkey(node, ch_endpt->opts.ssh, &hostkey)) { + if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) { + if (nc_server_config_get_hostkey(node, &hostkey)) { ret = 1; goto cleanup; } @@ -2322,56 +2138,28 @@ static int nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_client_auth *auth_client; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; + struct nc_server_ssh_opts *opts; assert(!strcmp(LYD_NAME(node), "user")); - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - if (op == NC_OP_CREATE) { - ret = nc_server_config_create_user(node, endpt->opts.ssh); - if (ret) { - goto cleanup; - } - } else if (op == NC_OP_DELETE) { - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_get_ssh_opts(node, &opts)) { + ret = 1; + goto cleanup; + } - nc_server_config_del_auth_client(endpt->opts.ssh, auth_client); - } - } else if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; + if (op == NC_OP_CREATE) { + ret = nc_server_config_create_user(node, opts); + if (ret) { goto cleanup; } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + } else if (op == NC_OP_DELETE) { + if (nc_server_config_get_auth_client(node, &auth_client)) { ret = 1; goto cleanup; } - if (op == NC_OP_CREATE) { - ret = nc_server_config_create_user(node, ch_endpt->opts.ssh); - if (ret) { - goto cleanup; - } - } else if (op == NC_OP_DELETE) { - if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } - - nc_server_config_del_auth_client(ch_endpt->opts.ssh, auth_client); - } + nc_server_config_del_auth_client(opts, auth_client); } cleanup: @@ -2382,35 +2170,17 @@ static int nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; + struct nc_server_ssh_opts *opts; assert(!strcmp(LYD_NAME(node), "auth-attempts")); - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10); - } - } else if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_get_ssh_opts(node, &opts)) { + ret = 1; + goto cleanup; + } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_endpt->opts.ssh->auth_attempts = strtoul(lyd_get_value(node), NULL, 10); - } + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + opts->auth_attempts = strtoul(lyd_get_value(node), NULL, 10); } cleanup: @@ -2421,35 +2191,17 @@ static int nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; + struct nc_server_ssh_opts *opts; assert(!strcmp(LYD_NAME(node), "auth-timeout")); - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10); - } - } else if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_get_ssh_opts(node, &opts)) { + ret = 1; + goto cleanup; + } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_endpt->opts.ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10); - } + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + opts->auth_timeout = strtoul(lyd_get_value(node), NULL, 10); } cleanup: @@ -2509,30 +2261,11 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION int ret = 0; struct nc_endpt *endpt; struct nc_client_auth *auth_client; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "truststore-reference")); - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - } else if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } - } - - if (is_listen(node) && is_ssh(node) && equal_parent_name(node, 1, "public-keys")) { - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { + if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) { + if (nc_server_config_get_auth_client(node, &auth_client)) { ret = 1; goto cleanup; } @@ -2549,6 +2282,11 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION auth_client->ts_ref = NULL; } } else if (is_listen(node) && equal_parent_name(node, 1, "ca-certs")) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + ret = 1; + goto cleanup; + } + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to truststore */ endpt->opts.tls->ca_certs.store = NC_STORE_TRUSTSTORE; @@ -2561,33 +2299,21 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION endpt->opts.tls->ca_certs.ts_ref = NULL; } } else if (is_listen(node) && equal_parent_name(node, 1, "ee-certs")) { - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to truststore */ - endpt->opts.tls->ee_certs.store = NC_STORE_TRUSTSTORE; - - ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ee_certs); - if (ret) { - goto cleanup; - } - } else { - endpt->opts.tls->ee_certs.ts_ref = NULL; - } - } else if (is_ch(node) && is_ssh(node) && equal_parent_name(node, 1, "public-keys")) { - if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to truststore */ - auth_client->store = NC_STORE_TRUSTSTORE; + endpt->opts.tls->ee_certs.store = NC_STORE_TRUSTSTORE; - ret = nc_server_config_replace_truststore_reference(node, auth_client); + ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ee_certs); if (ret) { goto cleanup; } } else { - auth_client->ts_ref = NULL; + endpt->opts.tls->ee_certs.ts_ref = NULL; } } @@ -2612,58 +2338,24 @@ nc_server_config_replace_password(const struct lyd_node *node, struct nc_client_ /* leaf */ static int nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) -{ - int ret = 0; - struct nc_endpt *endpt; - struct nc_client_auth *auth_client; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; - - assert(!strcmp(LYD_NAME(node), "password")); - - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_replace_password(node, auth_client); - if (ret) { - goto cleanup; - } - } else { - nc_server_config_del_auth_client_password(auth_client); - } - } else if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } +{ + int ret = 0; + struct nc_client_auth *auth_client; - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + assert(!strcmp(LYD_NAME(node), "password")); - if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_get_auth_client(node, &auth_client)) { + ret = 1; + goto cleanup; + } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_replace_password(node, auth_client); - if (ret) { - goto cleanup; - } - } else { - nc_server_config_del_auth_client_password(auth_client); + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ret = nc_server_config_replace_password(node, auth_client); + if (ret) { + goto cleanup; } + } else { + nc_server_config_del_auth_client_password(auth_client); } cleanup: @@ -2674,64 +2366,26 @@ static int nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_client_auth *auth_client; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "pam-config-file-name")); - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_auth_client_pam_name(auth_client); - - auth_client->pam_config_name = strdup(lyd_get_value(node)); - if (!auth_client->pam_config_name) { - ERRMEM; - ret = 1; - goto cleanup; - } - } else { - nc_server_config_del_auth_client_pam_name(auth_client); - } - } else if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_get_auth_client(node, &auth_client)) { + ret = 1; + goto cleanup; + } - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + nc_server_config_del_auth_client_pam_name(auth_client); - if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { + auth_client->pam_config_name = strdup(lyd_get_value(node)); + if (!auth_client->pam_config_name) { + ERRMEM; ret = 1; goto cleanup; } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_auth_client_pam_name(auth_client); - - auth_client->pam_config_name = strdup(lyd_get_value(node)); - if (!auth_client->pam_config_name) { - ERRMEM; - ret = 1; - goto cleanup; - } - } else { - nc_server_config_del_auth_client_pam_name(auth_client); - } + } else { + nc_server_config_del_auth_client_pam_name(auth_client); } cleanup: @@ -2742,62 +2396,25 @@ static int nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_client_auth *auth_client; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "pam-config-file-dir")); - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_auth_client_pam_dir(auth_client); - auth_client->pam_config_dir = strdup(lyd_get_value(node)); - if (!auth_client->pam_config_dir) { - ERRMEM; - ret = 1; - goto cleanup; - } - } else { - nc_server_config_del_auth_client_pam_dir(auth_client); - } - } else if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_get_auth_client(node, &auth_client)) { + ret = 1; + goto cleanup; + } - if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + nc_server_config_del_auth_client_pam_dir(auth_client); + auth_client->pam_config_dir = strdup(lyd_get_value(node)); + if (!auth_client->pam_config_dir) { + ERRMEM; ret = 1; goto cleanup; } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_auth_client_pam_dir(auth_client); - auth_client->pam_config_dir = strdup(lyd_get_value(node)); - if (!auth_client->pam_config_dir) { - ERRMEM; - ret = 1; - goto cleanup; - } - } else { - nc_server_config_del_auth_client_pam_dir(auth_client); - } + } else { + nc_server_config_del_auth_client_pam_dir(auth_client); } cleanup: @@ -2809,50 +2426,19 @@ static int nc_server_config_none(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_client_auth *auth_client; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; assert(!strcmp(LYD_NAME(node), "none")); - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_auth_client(node, endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } - - if (op == NC_OP_CREATE) { - auth_client->supports_none = 1; - } else { - auth_client->supports_none = 0; - } - } else if (is_ch(node)) { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_auth_client(node, ch_endpt->opts.ssh, &auth_client)) { - ret = 1; - goto cleanup; - } + if (nc_server_config_get_auth_client(node, &auth_client)) { + ret = 1; + goto cleanup; + } - if (op == NC_OP_CREATE) { - auth_client->supports_none = 1; - } else { - auth_client->supports_none = 0; - } + if (op == NC_OP_CREATE) { + auth_client->supports_none = 1; + } else { + auth_client->supports_none = 0; } cleanup: @@ -2950,33 +2536,13 @@ nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op) int ret = 0; const char *alg; uint8_t i; - struct nc_endpt *endpt; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; struct nc_server_ssh_opts *opts; assert(!strcmp(LYD_NAME(node), "host-key-alg")); - assert(is_listen(node) || is_ch(node)); - - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - opts = endpt->opts.ssh; - } else { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } - opts = ch_endpt->opts.ssh; + if (nc_server_config_get_ssh_opts(node, &opts)) { + ret = 1; + goto cleanup; } /* get the algorithm name and compare it with algs supported by libssh */ @@ -3009,33 +2575,13 @@ nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op) int ret = 0; const char *alg; uint8_t i; - struct nc_endpt *endpt; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; struct nc_server_ssh_opts *opts; assert(!strcmp(LYD_NAME(node), "key-exchange-alg")); - assert(is_listen(node) || is_ch(node)); - - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - opts = endpt->opts.ssh; - } else { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } - opts = ch_endpt->opts.ssh; + if (nc_server_config_get_ssh_opts(node, &opts)) { + ret = 1; + goto cleanup; } /* get the algorithm name and compare it with algs supported by libssh */ @@ -3068,33 +2614,13 @@ nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op) int ret = 0; const char *alg; uint8_t i; - struct nc_endpt *endpt; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; struct nc_server_ssh_opts *opts; assert(!strcmp(LYD_NAME(node), "encryption-alg")); - assert(is_listen(node) || is_ch(node)); - - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - opts = endpt->opts.ssh; - } else { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } - - opts = ch_endpt->opts.ssh; + if (nc_server_config_get_ssh_opts(node, &opts)) { + ret = 1; + goto cleanup; } /* get the algorithm name and compare it with algs supported by libssh */ @@ -3127,33 +2653,13 @@ nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op) int ret = 0; const char *alg; uint8_t i; - struct nc_endpt *endpt; - struct nc_ch_client *ch_client; - struct nc_ch_endpt *ch_endpt; struct nc_server_ssh_opts *opts; assert(!strcmp(LYD_NAME(node), "mac-alg")); - assert(is_listen(node) || is_ch(node)); - - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - opts = endpt->opts.ssh; - } else { - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } - - opts = ch_endpt->opts.ssh; + if (nc_server_config_get_ssh_opts(node, &opts)) { + ret = 1; + goto cleanup; } /* get the algorithm name and compare it with algs supported by libssh */ @@ -3467,7 +2973,7 @@ nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) } } } else if ((equal_parent_name(node, 3, "ca-certs")) && (is_listen(node))) { - if (nc_server_config_get_cert(node, &endpt->opts.tls->ca_certs, &cert)) { + if (nc_server_config_get_cert(node, 0, &cert)) { ret = 1; goto cleanup; } @@ -3481,7 +2987,7 @@ nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) nc_server_config_tls_del_cert_data_certificate(cert); } } else if ((equal_parent_name(node, 3, "ee-certs")) && (is_listen(node))) { - if (nc_server_config_get_cert(node, &endpt->opts.tls->ee_certs, &cert)) { + if (nc_server_config_get_cert(node, 1, &cert)) { ret = 1; goto cleanup; } @@ -3802,7 +3308,7 @@ nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op) /* find the given ctn entry */ lyd_find_path(node, "id", 0, &key); assert(key); - if (nc_server_config_get_ctn(node, endpt, &ctn)) { + if (nc_server_config_get_ctn(node, &ctn)) { ret = 1; goto cleanup; } @@ -3831,15 +3337,9 @@ static int nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_ctn *ctn; - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ctn(node, endpt, &ctn)) { + if (nc_server_config_get_ctn(node, &ctn)) { ret = 1; goto cleanup; } @@ -4160,15 +3660,9 @@ static int nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_ch_client *ch_client; struct nc_ch_endpt *ch_endpt; - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; } @@ -4194,15 +3688,9 @@ static int nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_ch_client *ch_client; struct nc_ch_endpt *ch_endpt; - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } - - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; } @@ -4673,6 +4161,7 @@ nc_server_config_setup_data(const struct lyd_node *data) /* delete the current configuration */ nc_server_config_listen(NULL, NC_OP_DELETE); + nc_server_config_ch(NULL, NC_OP_DELETE); #ifdef NC_ENABLED_SSH_TLS nc_server_config_ks_keystore(NULL, NC_OP_DELETE); nc_server_config_ts_truststore(NULL, NC_OP_DELETE); diff --git a/src/server_config_ks.c b/src/server_config_ks.c index eb0ad988..90243343 100644 --- a/src/server_config_ks.c +++ b/src/server_config_ks.c @@ -43,7 +43,7 @@ nc_server_config_get_asymmetric_key(const struct lyd_node *node, struct nc_asymm const char *askey_name; struct nc_keystore *ks; - assert(node); + assert(node && askey); while (node) { if (!strcmp(LYD_NAME(node), "asymmetric-key")) { @@ -81,12 +81,17 @@ nc_server_config_get_asymmetric_key(const struct lyd_node *node, struct nc_asymm * @return 0 on success, 1 on error. */ static int -nc_server_config_get_certificate(const struct lyd_node *node, const struct nc_asymmetric_key *askey, struct nc_certificate **cert) +nc_server_config_get_certificate(const struct lyd_node *node, struct nc_certificate **cert) { uint16_t i; const char *cert_name; + struct nc_asymmetric_key *askey; - assert(node); + assert(node && cert); + + if (nc_server_config_get_asymmetric_key(node, &askey)) { + return 1; + } while (node) { if (!strcmp(LYD_NAME(node), "certificate")) { @@ -371,7 +376,7 @@ nc_server_config_ks_certificate(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { ret = nc_server_config_ks_create_certificate(node, key); } else { - if (nc_server_config_get_certificate(node, key, &cert)) { + if (nc_server_config_get_certificate(node, &cert)) { ret = 1; goto cleanup; } @@ -386,19 +391,12 @@ nc_server_config_ks_certificate(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_ks_cert_data(const struct lyd_node *node, NC_OPERATION op) { - struct nc_asymmetric_key *key; struct nc_certificate *cert; - (void) op; - assert(!strcmp(LYD_NAME(node), "cert-data")); if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - if (nc_server_config_get_asymmetric_key(node, &key)) { - return 1; - } - - if (nc_server_config_get_certificate(node, key, &cert)) { + if (nc_server_config_get_certificate(node, &cert)) { return 1; } diff --git a/src/server_config_p.h b/src/server_config_p.h index ccfd9242..64636e7e 100644 --- a/src/server_config_p.h +++ b/src/server_config_p.h @@ -35,46 +35,7 @@ typedef enum { NC_MODULE_TRUSTSTORE } NC_MODULE; -/** - * @brief Get the pointer to an endpoint structure based on node's location in the YANG data. - * - * @param[in] node Node from which the endpoint containing this node is derived. - * @param[out] endpt Endpoint containing the node. - * @param[out] bind Bind corresponding to the endpoint. Optional. - * @return 0 on success, 1 on error. - */ -int nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind); - #ifdef NC_ENABLED_SSH_TLS -/** - * @brief Get the pointer to a hostkey structure based on node's location in the YANG data. - * - * @param[in] node Node from which the hotkey containing this node is derived. - * @param[in] opts Server SSH opts storing the array of the hostkey structures. - * @param[out] hostkey Hostkey containing the node. - * @return 0 on success, 1 on error. - */ -int nc_server_config_get_hostkey(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_hostkey **hostkey); - -/** - * @brief Get the pointer to a client authentication structure based on node's location in the YANG data. - * - * @param[in] node Node from which the client-authentication structure containing this node is derived. - * @param[in] opts Server SSH opts storing the array of the client authentication structures. - * @param[out] auth_client Client authentication structure containing the node. - * @return 0 on success, 1 on error. - */ -int nc_server_config_get_auth_client(const struct lyd_node *node, const struct nc_server_ssh_opts *opts, struct nc_client_auth **auth_client); - -/** - * @brief Get the pointer to a client authentication public key structure based on node's location in the YANG data. - * - * @param[in] node Node from which the ca-public key structure containing this node is derived. - * @param[in] auth_client Client authentication structure storing the array of the public key structures. - * @param[out] pubkey Public key structure containing the node. - * @return 0 on success, 1 on error. - */ -int nc_server_config_get_pubkey(const struct lyd_node *node, const struct nc_client_auth *auth_client, struct nc_public_key **pubkey); /** * @brief Get private key type from YANG identity stored in a string. diff --git a/src/server_config_ts.c b/src/server_config_ts.c index e92028c5..e32ef99b 100644 --- a/src/server_config_ts.c +++ b/src/server_config_ts.c @@ -43,7 +43,7 @@ nc_server_config_get_certificate_bag(const struct lyd_node *node, struct nc_cert const char *cbag_name; struct nc_truststore *ts; - assert(node); + assert(node && cbag); while (node) { if (!strcmp(LYD_NAME(node), "certificate-bag")) { @@ -77,17 +77,21 @@ nc_server_config_get_certificate_bag(const struct lyd_node *node, struct nc_cert * @brief Get the pointer to a certificate structure based on node's location in the YANG data. * * @param[in] node Node from which the certificate containing this node is derived. - * @param[in] cbag Certificate bag containing the certificate. * @param[out] cert Certificate containing the node. * @return 0 on success, 1 on error. */ static int -nc_server_config_get_certificate(const struct lyd_node *node, const struct nc_certificate_bag *cbag, struct nc_certificate **cert) +nc_server_config_get_certificate(const struct lyd_node *node, struct nc_certificate **cert) { uint16_t i; const char *cert_name; + struct nc_certificate_bag *cbag; - assert(node); + assert(node && cert); + + if (nc_server_config_get_certificate_bag(node, &cbag)) { + return 1; + } while (node) { if (!strcmp(LYD_NAME(node), "certificate")) { @@ -130,7 +134,7 @@ nc_server_config_get_public_key_bag(const struct lyd_node *node, struct nc_publi const char *pbag_name; struct nc_truststore *ts; - assert(node); + assert(node && pbag); while (node) { if (!strcmp(LYD_NAME(node), "public-key-bag")) { @@ -164,17 +168,21 @@ nc_server_config_get_public_key_bag(const struct lyd_node *node, struct nc_publi * @brief Get the pointer to a public key structure based on node's location in the YANG data. * * @param[in] node Node from which the public key containing this node is derived. - * @param[in] pbag Public key bag containing the public key. * @param[out] pkey Public key containing the node. * @return 0 on success, 1 on error. */ static int -nc_server_config_get_public_key(const struct lyd_node *node, const struct nc_public_key_bag *pbag, struct nc_public_key **pkey) +nc_server_config_get_public_key(const struct lyd_node *node, struct nc_public_key **pkey) { uint16_t i; const char *pkey_name; + struct nc_public_key_bag *pbag; - assert(node); + assert(node && pkey); + + if (nc_server_config_get_public_key_bag(node, &pbag)) { + return 1; + } while (node) { if (!strcmp(LYD_NAME(node), "public-key")) { @@ -401,7 +409,7 @@ nc_server_config_ts_certificate(const struct lyd_node *node, NC_OPERATION op) return 1; } } else { - if (nc_server_config_get_certificate(node, bag, &cert)) { + if (nc_server_config_get_certificate(node, &cert)) { return 1; } @@ -414,14 +422,10 @@ nc_server_config_ts_certificate(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_ts_cert_data(const struct lyd_node *node, NC_OPERATION op) { - struct nc_certificate_bag *bag; struct nc_certificate *cert; if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - if (nc_server_config_get_certificate_bag(node, &bag)) { - return 1; - } - if (nc_server_config_get_certificate(node, bag, &cert)) { + if (nc_server_config_get_certificate(node, &cert)) { return 1; } @@ -498,7 +502,7 @@ nc_server_config_ts_public_key(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else { - if (nc_server_config_get_public_key(node, bag, &pkey)) { + if (nc_server_config_get_public_key(node, &pkey)) { ret = 1; goto cleanup; } @@ -507,7 +511,7 @@ nc_server_config_ts_public_key(const struct lyd_node *node, NC_OPERATION op) } } else { /* public-key leaf */ - if (nc_server_config_get_public_key(node, bag, &pkey)) { + if (nc_server_config_get_public_key(node, &pkey)) { ret = 1; goto cleanup; } @@ -530,16 +534,11 @@ static int nc_server_config_ts_public_key_format(const struct lyd_node *node, NC_OPERATION op) { const char *format; - struct nc_public_key_bag *bag; struct nc_public_key *pkey; (void) op; - if (nc_server_config_get_public_key_bag(node, &bag)) { - return 1; - } - - if (nc_server_config_get_public_key(node, bag, &pkey)) { + if (nc_server_config_get_public_key(node, &pkey)) { return 1; } From 6e7466e7a029d81eb5bda8543c71c091255a7164 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 30 Jun 2023 15:07:56 +0200 Subject: [PATCH 042/134] config UPDATE Call Home over TLS Added support for Call Home over TLS. Call Home connection type and reconnect strategy parameters are now configurable. --- CMakeLists.txt | 1 - src/config.h.in | 5 - src/config_new.c | 323 +++++++++++++++++++----- src/config_new.h | 16 +- src/config_new_tls.c | 264 ++++++++++++++++--- src/server_config.c | 543 ++++++++++++++++++++++++++++++++-------- src/server_config.h | 145 +++++++++++ src/session_p.h | 15 +- src/session_server_ch.h | 36 --- tests/test_ch.c | 228 +++++++++++++++-- 10 files changed, 1307 insertions(+), 269 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac26d47f..0437dff1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,6 @@ set(MAX_PSPOLL_THREAD_COUNT 6 CACHE STRING "Maximum number of threads that could set(TIMEOUT_STEP 100 CACHE STRING "Number of microseconds tasks are repeated until timeout elapses") set(YANG_MODULE_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/yang/modules/libnetconf2" CACHE STRING "Directory where to copy the YANG modules to") set(CLIENT_SEARCH_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/yang/modules" CACHE STRING "Default NC client YANG module search directory") -set(CALL_HOME_BACKOFF_WAIT 2 CACHE STRING "Number of seconds to wait between Call Home connection attempts") # # sources diff --git a/src/config.h.in b/src/config.h.in index 7f36b819..6dc9fa16 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -80,11 +80,6 @@ */ #define NC_TIMEOUT_STEP @TIMEOUT_STEP@ -/* - * Time waited between Call Home endpoint session creation attempts (s). - */ -#define NC_CH_ENDPT_BACKOFF_WAIT @CALL_HOME_BACKOFF_WAIT@ - /* Portability feature-check macros. */ #cmakedefine HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP diff --git a/src/config_new.c b/src/config_new.c index b36bfeff..45a1e129 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -715,6 +715,111 @@ nc_server_config_new_del_ch_client(const struct ly_ctx *ctx, const char *ch_clie return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']", ch_client_name); } +API int +nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *name, const char *privkey_path, + const char *pubkey_path, struct lyd_node **config) +{ + int ret = 0; + char *privkey = NULL, *pubkey = NULL; + NC_PRIVKEY_FORMAT privkey_type; + NC_PUBKEY_FORMAT pubkey_type; + const char *privkey_format, *pubkey_format; + + NC_CHECK_ARG_RET(NULL, ctx, name, privkey_path, config, 1); + + /* get the keys as a string from the given files */ + ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); + if (ret) { + ERR(NULL, "Getting keys from file(s) failed."); + goto cleanup; + } + + /* get pubkey format str */ + if (pubkey_type == NC_PUBKEY_FORMAT_X509) { + pubkey_format = "ietf-crypto-types:public-key-info-format"; + } else { + pubkey_format = "ietf-crypto-types:ssh-public-key-format"; + } + + /* get privkey identityref value */ + privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type); + if (!privkey_format) { + ret = 1; + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-keystore:keystore/asymmetric-keys/" + "asymmetric-key[name='%s']/public-key-format", name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, pubkey, "/ietf-keystore:keystore/asymmetric-keys/" + "asymmetric-key[name='%s']/public-key", name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-keystore:keystore/asymmetric-keys/" + "asymmetric-key[name='%s']/private-key-format", name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, privkey, "/ietf-keystore:keystore/asymmetric-keys/" + "asymmetric-key[name='%s']/cleartext-private-key", name); + if (ret) { + goto cleanup; + } + +cleanup: + free(privkey); + free(pubkey); + return ret; +} + +API int +nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag_name, const char *pubkey_name, + const char *pubkey_path, struct lyd_node **config) +{ + int ret = 0; + char *pubkey = NULL; + NC_PUBKEY_FORMAT pubkey_format; + const char *format; + + NC_CHECK_ARG_RET(NULL, ctx, bag_name, pubkey_name, pubkey_path, config, 1); + + ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_format); + if (ret) { + goto cleanup; + } + + /* pubkey format to str */ + if (pubkey_format == NC_PUBKEY_FORMAT_SSH2) { + format = "ietf-crypto-types:ssh-public-key-format"; + } else { + format = "ietf-crypto-types:subject-public-key-info-format"; + } + + ret = nc_config_new_create(ctx, config, format, "/ietf-truststore:truststore/public-key-bags/" + "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", bag_name, pubkey_name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, pubkey, "/ietf-truststore:truststore/public-key-bags/" + "public-key-bag[name='%s']/public-key[name='%s']/public-key", bag_name, pubkey_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(pubkey); + return ret; +} + +#endif /* NC_ENABLED_SSH_TLS */ + int nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...) { @@ -800,107 +905,209 @@ nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const cha return ret; } -API int -nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *name, const char *privkey_path, - const char *pubkey_path, struct lyd_node **config) +int +nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name, + const char *value, struct lyd_node **tree) { int ret = 0; - char *privkey = NULL, *pubkey = NULL; - NC_PRIVKEY_FORMAT privkey_type; - NC_PUBKEY_FORMAT pubkey_type; - const char *privkey_format, *pubkey_format; - - NC_CHECK_ARG_RET(NULL, ctx, name, privkey_path, config, 1); + char *path = NULL; - /* get the keys as a string from the given files */ - ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); - if (ret) { - ERR(NULL, "Getting keys from file(s) failed."); + /* create the path by appending child to the parent path */ + ret = asprintf(&path, "%s/%s", parent_path, child_name); + if (ret == -1) { + ERRMEM; + path = NULL; goto cleanup; } - /* get pubkey format str */ - if (pubkey_type == NC_PUBKEY_FORMAT_X509) { - pubkey_format = "ietf-crypto-types:public-key-info-format"; - } else { - pubkey_format = "ietf-crypto-types:ssh-public-key-format"; + /* create the nodes in the path */ + ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); + if (ret) { + goto cleanup; } - /* get privkey identityref value */ - privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type); - if (!privkey_format) { - ret = 1; + /* set the node to the top level node */ + ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); + if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/public-key-format", name); + /* add all default nodes */ + ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/public-key", name); - if (ret) { +cleanup: + free(path); + return ret; +} + +int +nc_config_new_check_delete(struct lyd_node **tree, const char *path_fmt, ...) +{ + int ret = 0; + va_list ap; + char *path = NULL; + struct lyd_node *sub = NULL; + + va_start(ap, path_fmt); + + /* create the path from the format */ + ret = vasprintf(&path, path_fmt, ap); + if (ret == -1) { + ERRMEM; + path = NULL; goto cleanup; } - ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/private-key-format", name); - if (ret) { + /* find the node we want to delete */ + ret = lyd_find_path(*tree, path, 0, &sub); + if ((ret == LY_EINCOMPLETE) || (ret == LY_ENOTFOUND)) { + ret = 0; + goto cleanup; + } else if (ret) { + ERR(NULL, "Unable to delete node in the path \"%s\".", path); goto cleanup; } - ret = nc_config_new_create(ctx, config, privkey, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/cleartext-private-key", name); + lyd_free_tree(sub); + + /* set the node to top level container */ + ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); if (ret) { goto cleanup; } cleanup: - free(privkey); - free(pubkey); + free(path); + va_end(ap); return ret; } API int -nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag_name, const char *pubkey_name, - const char *pubkey_path, struct lyd_node **config) +nc_server_config_new_ch_persistent(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1); + + /* delete periodic tree if exists */ + if (nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/connection-type/periodic", ch_client_name)) { + return 1; + } + + return nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/connection-type/persistent", ch_client_name); +} + +API int +nc_server_config_new_ch_period(const struct ly_ctx *ctx, const char *ch_client_name, uint16_t period, + struct lyd_node **config) +{ + char buf[6] = {0}; + + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, period, 1); + + /* delete persistent tree if exists */ + if (nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) { + return 1; + } + + sprintf(buf, "%u", period); + return nc_config_new_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/connection-type/periodic/period", ch_client_name); +} + +API int +nc_server_config_new_ch_anchor_time(const struct ly_ctx *ctx, const char *ch_client_name, + const char *anchor_time, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, anchor_time, 1); + + /* delete persistent tree if exists */ + if (nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) { + return 1; + } + + return nc_config_new_create(ctx, config, anchor_time, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/connection-type/periodic/anchor-time", ch_client_name); +} + +API int +nc_server_config_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_client_name, + uint16_t idle_timeout, struct lyd_node **config) +{ + char buf[6] = {0}; + + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, 1); + + /* delete persistent tree if exists */ + if (nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) { + return 1; + } + + sprintf(buf, "%u", idle_timeout); + return nc_config_new_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/connection-type/periodic/idle-timeout", ch_client_name); +} + +API int +nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char *ch_client_name, + NC_CH_START_WITH start_with, uint8_t max_attempts, uint16_t max_wait, struct lyd_node **config) { int ret = 0; - char *pubkey = NULL; - NC_PUBKEY_FORMAT pubkey_format; - const char *format; + char *path = NULL; + char buf[6] = {0}; + const char *start_with_val; - NC_CHECK_ARG_RET(NULL, ctx, bag_name, pubkey_name, pubkey_path, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1); - ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_format); - if (ret) { + /* prepared the path */ + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/reconnect-strategy", ch_client_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; goto cleanup; } - /* pubkey format to str */ - if (pubkey_format == NC_PUBKEY_FORMAT_SSH2) { - format = "ietf-crypto-types:ssh-public-key-format"; - } else { - format = "ietf-crypto-types:subject-public-key-info-format"; + if (start_with) { + /* get string value from enum */ + if (start_with == NC_CH_FIRST_LISTED) { + start_with_val = "first-listed"; + } else if (start_with == NC_CH_LAST_CONNECTED) { + start_with_val = "last-connected"; + } else { + start_with_val = "random-selection"; + } + + ret = nc_config_new_create_append(ctx, path, "start-with", start_with_val, config); + if (ret) { + goto cleanup; + } } - ret = nc_config_new_create(ctx, config, format, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", bag_name, pubkey_name); - if (ret) { - goto cleanup; + if (max_attempts) { + sprintf(buf, "%u", max_attempts); + ret = nc_config_new_create_append(ctx, path, "max-attempts", buf, config); + if (ret) { + goto cleanup; + } + memset(buf, 0, 6); } - ret = nc_config_new_create(ctx, config, pubkey, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key[name='%s']/public-key", bag_name, pubkey_name); - if (ret) { - goto cleanup; + if (max_wait) { + sprintf(buf, "%u", max_wait); + ret = nc_config_new_create_append(ctx, path, "max-wait", buf, config); + if (ret) { + goto cleanup; + } } cleanup: - free(pubkey); + free(path); return ret; } - -#endif /* NC_ENABLED_SSH_TLS */ diff --git a/src/config_new.h b/src/config_new.h index 3388f05b..985ab347 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -87,7 +87,7 @@ const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT forma /** * @brief Creates YANG data nodes in a path and gives the final node a value. * - * @param[in] ctx libyang context + * @param[in] ctx libyang context. * @param[in, out] tree The YANG data tree where the insertion will happen. On success * the top level container is always returned. * @param[in] value Value assigned to the final node in the path. @@ -97,6 +97,20 @@ const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT forma */ int nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...); +/** + * @brief Creates new YANG data nodes in a path and gives the final node a value. + * + * @param[in] ctx libyang context. + * @param[in] parent_path Path to the parent node. + * @param[in] child_name Name of the parent's child node to be created. + * @param[in] value Value to give to the child node. + * @param[out] tree YANG data tree where the insertion will happen. On success + * the top level container is always returned. + * @return 0 on success, 1 otherwise. + */ +int nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name, + const char *value, struct lyd_node **tree); + /** * @brief Deletes a subtree from the YANG data. * diff --git a/src/config_new_tls.c b/src/config_new_tls.c index 3d14ad09..f1616cbf 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -31,8 +31,8 @@ #include "session.h" #include "session_p.h" -API int -nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *pubkey_path, +static int +_nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *pubkey_path, const char *privkey_path, const char *certificate_path, struct lyd_node **config) { int ret = 0; @@ -41,9 +41,6 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char NC_PUBKEY_FORMAT pubkey_type; const char *privkey_format, *pubkey_format; - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, certificate_path, 1); - NC_CHECK_ARG_RET(NULL, config, 1); - /* get the keys as a string from the given files */ ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); if (ret) { @@ -72,32 +69,27 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition/public-key-format", endpt_name); + ret = nc_config_new_create_append(ctx, tree_path, "public-key-format", pubkey_format, config); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition/public-key", endpt_name); + ret = nc_config_new_create_append(ctx, tree_path, "public-key", pubkey, config); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition/private-key-format", endpt_name); + ret = nc_config_new_create_append(ctx, tree_path, "private-key-format", privkey_format, config); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, privkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition/cleartext-private-key", endpt_name); + ret = nc_config_new_create_append(ctx, tree_path, "cleartext-private-key", privkey, config); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition/cert-data", endpt_name); + ret = nc_config_new_create_append(ctx, tree_path, "cert-data", cert, config); if (ret) { goto cleanup; } @@ -110,22 +102,79 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char } API int -nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, +nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *pubkey_path, + const char *privkey_path, const char *certificate_path, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, certificate_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/inline-definition", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_server_certificate(ctx, path, pubkey_path, privkey_path, + certificate_path, config); + if (ret) { + ERR(NULL, "Creating new TLS server certificate YANG data failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + const char *pubkey_path, const char *privkey_path, const char *certificate_path, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, endpt_name, privkey_path, certificate_path, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" + "certificate/inline-definition", ch_client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_server_certificate(ctx, path, pubkey_path, privkey_path, + certificate_path, config); + if (ret) { + ERR(NULL, "Creating new CH TLS server certificate YANG data failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +static int +_nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *cert_path, struct lyd_node **config) { int ret = 0; char *cert = NULL; - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); - ret = nc_server_config_new_read_certificate(cert_path, &cert); if (ret) { ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path); goto cleanup; } - ret = nc_config_new_create(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ee-certs/inline-definition/certificate[name='%s']/cert-data", endpt_name, cert_name); + ret = nc_config_new_create_append(ctx, tree_path, "cert-data", cert, config); if (ret) { goto cleanup; } @@ -135,29 +184,119 @@ nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char return ret; } +API int +nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, + const char *cert_path, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_client_certificate(ctx, path, cert_path, config); + if (ret) { + ERR(NULL, "Creating new TLS client certificate YANG data failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + const char *cert_name, const char *cert_path, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, endpt_name, cert_name, cert_path, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" + "inline-definition/certificate[name='%s']", ch_client_name, endpt_name, cert_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_client_certificate(ctx, path, cert_path, config); + if (ret) { + ERR(NULL, "Creating new CH TLS client certificate YANG data failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + API int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, const char *cert_path, struct lyd_node **config) { int ret = 0; - char *cert = NULL; + char *path = NULL; NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); - ret = nc_server_config_new_read_certificate(cert_path, &cert); + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_client_certificate(ctx, path, cert_path, config); if (ret) { - ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path); + ERR(NULL, "Creating new TLS client certificate authority YANG data failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + const char *cert_name, const char *cert_path, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, endpt_name, cert_name, cert_path, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" + "inline-definition/certificate[name='%s']", ch_client_name, endpt_name, cert_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; goto cleanup; } - ret = nc_config_new_create(ctx, config, cert, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ca-certs/inline-definition/certificate[name='%s']/cert-data", endpt_name, cert_name); + ret = _nc_server_config_new_tls_client_certificate(ctx, path, cert_path, config); if (ret) { + ERR(NULL, "Creating new CH TLS client certificate authority YANG data failed."); goto cleanup; } cleanup: - free(cert); + free(path); return ret; } @@ -184,20 +323,16 @@ nc_config_new_tls_maptype2str(NC_TLS_CTN_MAPTYPE map_type) } } -API int -nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, uint32_t id, const char *fingerprint, +static int +_nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *tree_path, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, struct lyd_node **config) { int ret = 0; const char *map; - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, map_type, name, 1); - NC_CHECK_ARG_RET(NULL, config, 1); - if (fingerprint) { /* optional */ - ret = nc_config_new_create(ctx, config, fingerprint, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/fingerprint", endpt_name, id); + ret = nc_config_new_create_append(ctx, tree_path, "fingerprint", fingerprint, config); if (ret) { goto cleanup; } @@ -210,19 +345,74 @@ nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, u goto cleanup; } - ret = nc_config_new_create(ctx, config, map, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/map-type", endpt_name, id); + ret = nc_config_new_create_append(ctx, tree_path, "map-type", map, config); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, name, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%d']/name", endpt_name, id); + ret = nc_config_new_create_append(ctx, tree_path, "name", name, config); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_new_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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, name, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/netconf-server-parameters/" + "client-identity-mappings/cert-to-name[id='%u']", endpt_name, id) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_ctn(ctx, path, fingerprint, map_type, name, config); + if (ret) { + ERR(NULL, "Creating new TLS cert-to-name YANG data failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *ch_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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ch_client_name, endpt_name, id, name, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" + "cert-to-name[id='%u']", ch_client_name, endpt_name, id) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_ctn(ctx, path, fingerprint, map_type, name, config); if (ret) { + ERR(NULL, "Creating new TLS cert-to-name YANG data failed."); goto cleanup; } cleanup: + free(path); return ret; } diff --git a/src/server_config.c b/src/server_config.c index 1a46b213..a33fbcfb 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -413,24 +413,47 @@ nc_server_config_get_pubkey(const struct lyd_node *node, struct nc_public_key ** return 1; } +static int +nc_server_config_get_tls_opts(const struct lyd_node *node, struct nc_server_tls_opts **opts) +{ + struct nc_endpt *endpt; + struct nc_ch_endpt *ch_endpt; + + assert(node && opts); + + if (is_listen(node)) { + if (nc_server_config_get_endpt(node, &endpt, NULL)) { + return 1; + } + *opts = endpt->opts.tls; + } else { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { + return 1; + } + *opts = ch_endpt->opts.tls; + } + + return 0; +} + static int nc_server_config_get_cert(const struct lyd_node *node, int is_ee, struct nc_certificate **cert) { uint16_t i; const char *cert_name; - struct nc_endpt *endpt; struct nc_cert_grouping *auth_client; + struct nc_server_tls_opts *opts; assert(node && cert); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_tls_opts(node, &opts)) { return 1; } if (is_ee) { - auth_client = &endpt->opts.tls->ee_certs; + auth_client = &opts->ee_certs; } else { - auth_client = &endpt->opts.tls->ca_certs; + auth_client = &opts->ca_certs; } while (node) { @@ -465,11 +488,11 @@ nc_server_config_get_ctn(const struct lyd_node *node, struct nc_ctn **ctn) { uint32_t id; struct nc_ctn *iter; - struct nc_endpt *endpt; + struct nc_server_tls_opts *opts; assert(node && ctn); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_tls_opts(node, &opts)) { return 1; } @@ -490,7 +513,7 @@ nc_server_config_get_ctn(const struct lyd_node *node, struct nc_ctn **ctn) assert(!strcmp(LYD_NAME(node), "id")); id = strtoul(lyd_get_value(node), NULL, 10); - iter = endpt->opts.tls->ctn; + iter = opts->ctn; while (iter) { if (iter->id == id) { *ctn = iter; @@ -1066,6 +1089,29 @@ nc_server_config_ch_del_ssh(struct nc_server_ssh_opts *opts) opts = NULL; } +static void +nc_server_config_ch_del_tls(struct nc_server_tls_opts *opts) +{ + if (opts->store == NC_STORE_LOCAL) { + nc_server_config_tls_del_public_key(opts); + nc_server_config_tls_del_cleartext_private_key(opts); + nc_server_config_tls_del_cert_data(opts); + } + + nc_server_config_tls_del_certs(&opts->ca_certs); + nc_server_config_tls_del_certs(&opts->ee_certs); + + nc_server_config_del_path(opts); + nc_server_config_del_url(opts); + X509_STORE_free(opts->crl_store); + opts->crl_store = NULL; + + nc_server_config_tls_del_ctns(opts); + nc_server_config_tls_del_ciphers(opts); + + free(opts); +} + static void nc_server_config_ch_del_endpt_address(struct nc_ch_endpt *ch_endpt) { @@ -1094,6 +1140,9 @@ nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt case NC_TI_LIBSSH: nc_server_config_ch_del_ssh(ch_endpt->opts.ssh); break; + case NC_TI_OPENSSL: + nc_server_config_ch_del_tls(ch_endpt->opts.tls); + break; #endif /* NC_ENABLED_SSH_TLS */ default: ERRINT; @@ -1121,13 +1170,14 @@ nc_server_config_ch_del_client(struct nc_ch_client *ch_client) pthread_mutex_lock(&ch_client->session->opts.server.ch_lock); pthread_cond_signal(&ch_client->session->opts.server.ch_cond); pthread_mutex_unlock(&ch_client->session->opts.server.ch_lock); + ch_client->session = NULL; } - ch_client->session = NULL; - pthread_rwlock_unlock(&server_opts.ch_client_lock); - pthread_join(ch_client->tid, NULL); + if (ch_client->tid) { + pthread_join(ch_client->tid, NULL); + } pthread_rwlock_wrlock(&server_opts.ch_client_lock); @@ -1164,15 +1214,28 @@ nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op) static int nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op) { + struct nc_ch_client *ch_client; + assert(!strcmp(LYD_NAME(node), "idle-timeout")); - if (equal_parent_name(node, 1, "listen")) { + if (is_listen(node)) { if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10); } else { /* default value */ server_opts.idle_timeout = 3600; } + } else { + /* call-home idle timeout */ + if (nc_server_config_get_ch_client(node, &ch_client)) { + return 1; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_client->idle_timeout = strtoul(lyd_get_value(node), NULL, 10); + } else if (op == NC_OP_DELETE) { + ch_client->idle_timeout = 180; + } } return 0; @@ -1351,6 +1414,8 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) if (ret) { goto cleanup; } + } else if (op == NC_OP_DELETE) { + nc_server_config_ch_del_ssh(ch_endpt->opts.ssh); } } @@ -1371,27 +1436,55 @@ nc_server_config_create_tls(struct nc_endpt *endpt) return 0; } +static int +nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt) +{ + ch_endpt->ti = NC_TI_OPENSSL; + ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts)); + if (!ch_endpt->opts.tls) { + ERRMEM; + return 1; + } + + return 0; +} + static int nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op) { struct nc_endpt *endpt; struct nc_bind *bind; + struct nc_ch_endpt *ch_endpt; int ret = 0; assert(!strcmp(LYD_NAME(node), "tls")); - if (nc_server_config_get_endpt(node, &endpt, &bind)) { - ret = 1; - goto cleanup; - } + if (is_listen(node)) { + if (nc_server_config_get_endpt(node, &endpt, &bind)) { + ret = 1; + goto cleanup; + } - if (op == NC_OP_CREATE) { - ret = nc_server_config_create_tls(endpt); - if (ret) { + if (op == NC_OP_CREATE) { + ret = nc_server_config_create_tls(endpt); + if (ret) { + goto cleanup; + } + } else if (op == NC_OP_DELETE) { + nc_server_config_del_tls(bind, endpt->opts.tls); + } + } else { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { + ret = 1; goto cleanup; } - } else if (op == NC_OP_DELETE) { - nc_server_config_del_tls(bind, endpt->opts.tls); + + if (op == NC_OP_CREATE) { + ret = nc_server_config_ch_create_tls(ch_endpt); + if (ret) { + goto cleanup; + } + } } cleanup: @@ -1756,9 +1849,9 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) int ret = 0; const char *format; NC_PUBKEY_FORMAT pubkey_type; - struct nc_endpt *endpt; struct nc_public_key *pubkey; struct nc_hostkey *hostkey; + struct nc_server_tls_opts *opts; assert(!strcmp(LYD_NAME(node), "public-key-format")); @@ -1793,15 +1886,15 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { pubkey->type = pubkey_type; } - } else if (is_listen(node) && is_tls(node) && equal_parent_name(node, 3, "server-identity")) { - /* TLS listen server-identity */ - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) { + /* TLS server-identity */ + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->opts.tls->pubkey_type = pubkey_type; + opts->pubkey_type = pubkey_type; } } @@ -1866,10 +1959,10 @@ static int nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_hostkey *hostkey; struct nc_client_auth *auth_client; struct nc_public_key *pubkey; + struct nc_server_tls_opts *opts; assert(!strcmp(LYD_NAME(node), "public-key")); @@ -1927,18 +2020,18 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } else { nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); } - } else if (is_listen(node) && is_tls(node) && equal_parent_name(node, 3, "server-identity")) { - /* tls listen server-identity */ - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) { + /* TLS server-identity */ + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to local */ - endpt->opts.tls->store = NC_STORE_LOCAL; + opts->store = NC_STORE_LOCAL; - ret = nc_server_config_tls_replace_server_public_key(node, endpt->opts.tls); + ret = nc_server_config_tls_replace_server_public_key(node, opts); if (ret) { goto cleanup; } @@ -1956,8 +2049,8 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op int ret = 0; const char *format; NC_PRIVKEY_FORMAT privkey_type; - struct nc_endpt *endpt; struct nc_hostkey *hostkey; + struct nc_server_tls_opts *opts; (void) op; @@ -1984,14 +2077,14 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op } hostkey->key.privkey_type = privkey_type; - } else if (is_listen(node) && is_tls(node)) { - /* listen tls */ - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + } else if (is_tls(node)) { + /* tls */ + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } - endpt->opts.tls->privkey_type = privkey_type; + opts->privkey_type = privkey_type; } cleanup: @@ -2028,8 +2121,8 @@ static int nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_hostkey *hostkey; + struct nc_server_tls_opts *opts; assert(!strcmp(LYD_NAME(node), "cleartext-private-key")); @@ -2048,20 +2141,20 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION } else { nc_server_config_del_private_key(hostkey); } - } else if (is_listen(node) && is_tls(node)) { - /* listen tls */ - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + } else if (is_tls(node)) { + /* tls */ + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_tls_replace_cleartext_private_key(node, endpt->opts.tls); + ret = nc_server_config_tls_replace_cleartext_private_key(node, opts); if (ret) { goto cleanup; } } else { - nc_server_config_tls_del_cleartext_private_key(endpt->opts.tls); + nc_server_config_tls_del_cleartext_private_key(opts); } } @@ -2955,24 +3048,24 @@ static int nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_certificate *cert; + struct nc_server_tls_opts *opts; assert(!strcmp(LYD_NAME(node), "cert-data")); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; - } + if (equal_parent_name(node, 3, "server-identity")) { + if (nc_server_config_get_tls_opts(node, &opts)) { + ret = 1; + goto cleanup; + } - if ((equal_parent_name(node, 3, "server-identity")) && (is_listen(node))) { if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_tls_replace_cert_data(node, endpt->opts.tls); + ret = nc_server_config_tls_replace_cert_data(node, opts); if (ret) { goto cleanup; } } - } else if ((equal_parent_name(node, 3, "ca-certs")) && (is_listen(node))) { + } else if (equal_parent_name(node, 3, "ca-certs")) { if (nc_server_config_get_cert(node, 0, &cert)) { ret = 1; goto cleanup; @@ -2986,7 +3079,7 @@ nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) } else { nc_server_config_tls_del_cert_data_certificate(cert); } - } else if ((equal_parent_name(node, 3, "ee-certs")) && (is_listen(node))) { + } else if (equal_parent_name(node, 3, "ee-certs")) { if (nc_server_config_get_cert(node, 1, &cert)) { ret = 1; goto cleanup; @@ -3059,7 +3152,7 @@ nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_config_tls_create_certificate_ref(const struct lyd_node *node, struct nc_endpt *endpt, struct nc_asymmetric_key *key) +nc_server_config_tls_create_certificate_ref(const struct lyd_node *node, struct nc_server_tls_opts *opts, struct nc_asymmetric_key *key) { uint16_t i; @@ -3075,13 +3168,13 @@ nc_server_config_tls_create_certificate_ref(const struct lyd_node *node, struct return 1; } - endpt->opts.tls->cert_ref = &key->certs[i]; + opts->cert_ref = &key->certs[i]; return 0; } static struct nc_asymmetric_key * -cert_get_asymmetric_key(const struct lyd_node *node) +nc_server_config_cert_get_asymmetric_key(const struct lyd_node *node) { uint16_t i; struct nc_keystore *ks = &server_opts.keystore; @@ -3131,62 +3224,61 @@ static int nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_asymmetric_key *key; + struct nc_server_tls_opts *opts; assert(!strcmp(LYD_NAME(node), "certificate")); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } - if ((equal_parent_name(node, 1, "keystore-reference")) && (is_listen(node))) { - /* server-identity TLS listen */ - + if (equal_parent_name(node, 1, "keystore-reference")) { + /* TLS server-identity */ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to keystore */ - endpt->opts.tls->store = NC_STORE_KEYSTORE; + opts->store = NC_STORE_KEYSTORE; - if (!endpt->opts.tls->key_ref) { + if (!opts->key_ref) { /* we don't have a key from which we need the cert yet */ - key = cert_get_asymmetric_key(node); + key = nc_server_config_cert_get_asymmetric_key(node); if (!key) { ret = 1; goto cleanup; } } else { /* we have the key */ - key = endpt->opts.tls->key_ref; + key = opts->key_ref; } /* find the given cert in the key and set it */ - ret = nc_server_config_tls_create_certificate_ref(node, endpt, key); + ret = nc_server_config_tls_create_certificate_ref(node, opts, key); if (ret) { goto cleanup; } } else { - endpt->opts.tls->cert_ref = NULL; + opts->cert_ref = NULL; } - } else if ((equal_parent_name(node, 2, "ca-certs")) && (is_listen(node))) { - /* client auth TLS listen */ + } else if (equal_parent_name(node, 2, "ca-certs")) { + /* TLS client auth certificate authority */ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_create_ca_certs_certificate(node, endpt->opts.tls); + ret = nc_server_config_create_ca_certs_certificate(node, opts); if (ret) { goto cleanup; } } else { - nc_server_config_tls_del_certs(&endpt->opts.tls->ca_certs); + nc_server_config_tls_del_certs(&opts->ca_certs); } - } else if ((equal_parent_name(node, 2, "ee-certs")) && (is_listen(node))) { - /* client auth TLS listen */ + } else if (equal_parent_name(node, 2, "ee-certs")) { + /* TLS client auth end entity */ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_create_ee_certs_certificate(node, endpt->opts.tls); + ret = nc_server_config_create_ee_certs_certificate(node, opts); if (ret) { goto cleanup; } } else { - nc_server_config_tls_del_certs(&endpt->opts.tls->ee_certs); + nc_server_config_tls_del_certs(&opts->ee_certs); } } @@ -3288,19 +3380,19 @@ static int nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; + struct nc_server_tls_opts *opts; struct lyd_node *key; struct nc_ctn *ctn; assert(!strcmp(LYD_NAME(node), "cert-to-name")); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_create_cert_to_name(node, endpt->opts.tls); + ret = nc_server_config_create_cert_to_name(node, opts); if (ret) { goto cleanup; } @@ -3312,7 +3404,7 @@ nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op) ret = 1; goto cleanup; } - nc_server_config_del_ctn(endpt->opts.tls, ctn); + nc_server_config_del_ctn(opts, ctn); } cleanup: @@ -3373,25 +3465,25 @@ static int nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; + struct nc_server_tls_opts *opts; const char *version = NULL; assert(!strcmp(LYD_NAME(node), "tls-version")); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } version = ((struct lyd_node_term *)node)->value.ident->name; if (!strcmp(version, "tls10")) { - nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_10, op); + nc_server_config_set_tls_version(opts, NC_TLS_VERSION_10, op); } else if (!strcmp(version, "tls11")) { - nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_11, op); + nc_server_config_set_tls_version(opts, NC_TLS_VERSION_11, op); } else if (!strcmp(version, "tls12")) { - nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_12, op); + nc_server_config_set_tls_version(opts, NC_TLS_VERSION_12, op); } else if (!strcmp(version, "tls13")) { - nc_server_config_set_tls_version(endpt->opts.tls, NC_TLS_VERSION_13, op); + nc_server_config_set_tls_version(opts, NC_TLS_VERSION_13, op); } else { ERR(NULL, "TLS version \"%s\" not supported.", version); ret = 1; @@ -3453,7 +3545,7 @@ nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char } static int -nc_server_config_del_concrete_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher) +nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher) { int cipher_found = 0; char *haystack, *substr; @@ -3490,24 +3582,24 @@ static int nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; + struct nc_server_tls_opts *opts; const char *cipher = NULL; assert(!strcmp(LYD_NAME(node), "cipher-suite")); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } cipher = ((struct lyd_node_term *)node)->value.ident->name; if (op == NC_OP_CREATE) { - ret = nc_server_config_create_cipher_suite(endpt->opts.tls, cipher); + ret = nc_server_config_create_cipher_suite(opts, cipher); if (ret) { goto cleanup; } } else if (op == NC_OP_DELETE) { - ret = nc_server_config_del_concrete_cipher_suite(endpt->opts.tls, cipher); + ret = nc_server_config_del_cipher_suite(opts, cipher); if (ret) { goto cleanup; } @@ -3521,25 +3613,25 @@ static int nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; + struct nc_server_tls_opts *opts; assert(!strcmp(LYD_NAME(node), "crl-url")); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_url(endpt->opts.tls); - endpt->opts.tls->crl_url = strdup(lyd_get_value(node)); - if (!endpt->opts.tls->crl_url) { + nc_server_config_del_url(opts); + opts->crl_url = strdup(lyd_get_value(node)); + if (!opts->crl_url) { ERRMEM; ret = 1; goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_config_del_url(endpt->opts.tls); + nc_server_config_del_url(opts); } cleanup: @@ -3550,25 +3642,25 @@ static int nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; + struct nc_server_tls_opts *opts; assert(!strcmp(LYD_NAME(node), "crl-path")); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_path(endpt->opts.tls); - endpt->opts.tls->crl_path = strdup(lyd_get_value(node)); - if (!endpt->opts.tls->crl_path) { + nc_server_config_del_path(opts); + opts->crl_path = strdup(lyd_get_value(node)); + if (!opts->crl_path) { ERRMEM; ret = 1; goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_config_del_path(endpt->opts.tls); + nc_server_config_del_path(opts); } cleanup: @@ -3579,19 +3671,19 @@ static int nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; + struct nc_server_tls_opts *opts; assert(!strcmp(LYD_NAME(node), "crl-cert-ext")); - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->opts.tls->crl_cert_ext = 1; + opts->crl_cert_ext = 1; } else if (op == NC_OP_DELETE) { - endpt->opts.tls->crl_cert_ext = 0; + opts->crl_cert_ext = 0; } cleanup: @@ -3662,6 +3754,8 @@ nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_ch_endpt *ch_endpt; + assert(!strcmp(LYD_NAME(node), "remote-address")); + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; @@ -3690,6 +3784,8 @@ nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_ch_endpt *ch_endpt; + assert(!strcmp(LYD_NAME(node), "remote-port")); + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; @@ -3707,6 +3803,210 @@ nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op) #endif /* NC_ENABLED_SSH_TLS */ +static int +nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_ch_client *ch_client; + + assert(!strcmp(LYD_NAME(node), "persistent")); + + (void) op; + + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + ch_client->conn_type = NC_CH_PERSIST; + +cleanup: + return ret; +} + +static int +nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_ch_client *ch_client; + + assert(!strcmp(LYD_NAME(node), "periodic")); + + (void) op; + + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + ch_client->conn_type = NC_CH_PERIOD; + /* set default values */ + ch_client->period = 60; + ch_client->anchor_time = 0; + ch_client->idle_timeout = 180; + +cleanup: + return ret; +} + +static int +nc_server_config_period(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_ch_client *ch_client; + + assert(!strcmp(LYD_NAME(node), "period")); + + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_client->period = strtoul(lyd_get_value(node), NULL, 10); + } else if (op == NC_OP_DELETE) { + ch_client->period = 60; + } + +cleanup: + return ret; +} + +static int +nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_ch_client *ch_client; + time_t anchor_time = {0}; + + assert(!strcmp(LYD_NAME(node), "anchor-time")); + + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + ret = ly_time_str2time(lyd_get_value(node), &anchor_time, NULL); + if (ret) { + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_client->anchor_time = anchor_time; + } else if (op == NC_OP_DELETE) { + ch_client->anchor_time = 0; + } + +cleanup: + return ret; +} + +static int +nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_ch_client *ch_client; + + assert(!strcmp(LYD_NAME(node), "reconnect-strategy")); + + (void) op; + + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + /* set to default values */ + ch_client->start_with = NC_CH_FIRST_LISTED; + ch_client->max_wait = 5; + ch_client->max_attempts = 3; + +cleanup: + return ret; +} + +static int +nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_ch_client *ch_client; + const char *value; + + assert(!strcmp(LYD_NAME(node), "start-with")); + + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if (op == NC_OP_DELETE) { + ch_client->start_with = NC_CH_FIRST_LISTED; + goto cleanup; + } + + value = lyd_get_value(node); + if (!strcmp(value, "first-listed")) { + ch_client->start_with = NC_CH_FIRST_LISTED; + } else if (!strcmp(value, "last-connected")) { + ch_client->start_with = NC_CH_LAST_CONNECTED; + } else if (!strcmp(value, "random-selection")) { + ch_client->start_with = NC_CH_RANDOM; + } else { + ERR(NULL, "Unexpected start-with value \"%s\".", value); + ret = 1; + goto cleanup; + } + +cleanup: + return ret; +} + +static int +nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_ch_client *ch_client; + + assert(!strcmp(LYD_NAME(node), "max-wait")); + + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_client->max_wait = strtoul(lyd_get_value(node), NULL, 10); + } else { + ch_client->max_wait = 5; + } + +cleanup: + return ret; +} + +static int +nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op) +{ + int ret = 0; + struct nc_ch_client *ch_client; + + assert(!strcmp(LYD_NAME(node), "max-attempts")); + + if (nc_server_config_get_ch_client(node, &ch_client)) { + ret = 1; + goto cleanup; + } + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_client->max_attempts = strtoul(lyd_get_value(node), NULL, 10); + } else { + ch_client->max_attempts = 3; + } + +cleanup: + return ret; +} + static int nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op) { @@ -3896,11 +4196,44 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION } } #endif /* NC_ENABLED_SSH_TLS */ + else if (!strcmp(name, "persistent")) { + if (nc_server_config_persistent(node, op)) { + goto error; + } + } else if (!strcmp(name, "periodic")) { + if (nc_server_config_periodic(node, op)) { + goto error; + } + } else if (!strcmp(name, "period")) { + if (nc_server_config_period(node, op)) { + goto error; + } + } else if (!strcmp(name, "anchor-time")) { + if (nc_server_config_anchor_time(node, op)) { + goto error; + } + } else if (!strcmp(name, "reconnect-strategy")) { + if (nc_server_config_reconnect_strategy(node, op)) { + goto error; + } + } else if (!strcmp(name, "start-with")) { + if (nc_server_config_start_with(node, op)) { + goto error; + } + } else if (!strcmp(name, "max-wait")) { + if (nc_server_config_max_wait(node, op)) { + goto error; + } + } else if (!strcmp(name, "max-attempts")) { + if (nc_server_config_max_attempts(node, op)) { + goto error; + } + } return 0; error: - ERR(NULL, "Configuring (%s) failed.", LYD_NAME(node)); + ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node)); return 1; } diff --git a/src/server_config.h b/src/server_config.h index 738e169d..103416e5 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -588,8 +588,153 @@ int nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char int nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *truststore_reference, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes for a call-home server's certificate. + * + * @param[in] ctx libyang context. + * @param[in] ch_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] pubkey_path Optional path to the server's public key file. If not provided, + * it will be generated from the private key. + * @param[in] privkey_path Path to the server's private key file. + * @param[in] certificate_path Path to the server's certificate file. + * @param 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_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + const char *pubkey_path, const char *privkey_path, const char *certificate_path, 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] ch_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 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_new_ch_tls_client_certificate(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + const char *cert_name, const char *cert_path, 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] ch_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 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_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, + const char *cert_name, const char *cert_path, 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] ch_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. + * @param 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_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *ch_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); + #endif /* NC_ENABLED_SSH_TLS */ +/** + * @brief Creates new YANG configuration data nodes for the call-home persistent connection type. + * + * @param[in] ctx libyang context. + * @param[in] ch_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 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_new_ch_persistent(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for the period parameter of the call-home periodic connection type. + * + * @param[in] ctx libyang context. + * @param[in] ch_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] period Duration between periodic connections. + * @param 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_new_ch_period(const struct ly_ctx *ctx, const char *ch_client_name, uint16_t period, + struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for the anchor time parameter of the call-home periodic connection type. + * + * @param[in] ctx libyang context. + * @param[in] ch_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] anchor_time Timestamp before or after which a series of periodic connections are determined. + * @param 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_new_ch_anchor_time(const struct ly_ctx *ctx, const char *ch_client_name, + const char *anchor_time, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for the idle timeout parameter of the call-home periodic connection type. + * + * @param[in] ctx libyang context. + * @param[in] ch_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] idle_timeout Specifies the maximum number of seconds that a session may remain idle. + * @param 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_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_client_name, + uint16_t idle_timeout, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for the call-home reconnect strategy. + * + * @param[in] ctx libyang context. + * @param[in] ch_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] start_with Specifies which endpoint to try if a connection is unsuccessful. Default value is NC_CH_FIRST_LISTED. + * @param[in] max_attempts The number of unsuccessful connection attempts before moving to the next endpoint. Default value is 3. + * @param[in] max_wait The number of seconds after which a connection to an endpoint is deemed unsuccessful. Default value if 5. + * @param 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_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char *ch_client_name, + NC_CH_START_WITH start_with, uint8_t max_attempts, uint16_t max_wait, struct lyd_node **config); + #ifdef __cplusplus } #endif diff --git a/src/session_p.h b/src/session_p.h index 833e9649..3fe3ddd1 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -464,6 +464,7 @@ struct nc_server_opts { struct nc_session *session; pthread_t tid; + // data * - condition, mutex, thread_running struct nc_ch_endpt { char *name; NC_TRANSPORT_IMPL ti; @@ -481,17 +482,17 @@ struct nc_server_opts { } opts; } *ch_endpts; uint16_t ch_endpt_count; + NC_CH_CONN_TYPE conn_type; + struct { + uint16_t period; + time_t anchor_time; + uint16_t idle_timeout; + }; - union { - struct { - uint16_t period; - time_t anchor_time; - uint16_t idle_timeout; - } period; - } conn; NC_CH_START_WITH start_with; uint8_t max_attempts; + uint16_t max_wait; uint32_t id; pthread_mutex_t lock; } *ch_clients; diff --git a/src/session_server_ch.h b/src/session_server_ch.h index 42597fe1..f1b1b041 100644 --- a/src/session_server_ch.h +++ b/src/session_server_ch.h @@ -139,42 +139,6 @@ int nc_server_ch_client_endpt_enable_keepalives(const char *client_name, const c int nc_server_ch_client_endpt_set_keepalives(const char *client_name, const char *endpt_name, int idle_time, int max_probes, int probe_interval); -/** - * @brief Set Call Home client connection type. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] conn_type Call Home connection type. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_set_conn_type(const char *client_name, NC_CH_CONN_TYPE conn_type); - -/** - * @brief Set Call Home client periodic connection period for reconnecting. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] period Call Home periodic connection period in minutes. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_periodic_set_period(const char *client_name, uint16_t period); - -/** - * @brief Set Call Home client periodic connection period anchor time. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] anchor_time Call Home periodic connection anchor time for the period. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_periodic_set_anchor_time(const char *client_name, time_t anchor_time); - -/** - * @brief Set Call Home client periodic connection idle timeout. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] idle_timeout Call Home periodic idle timeout. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_periodic_set_idle_timeout(const char *client_name, uint16_t idle_timeout); - /** * @brief Set Call Home client start-with policy. * diff --git a/tests/test_ch.c b/tests/test_ch.c index 7e8f72d4..5b5daab4 100644 --- a/tests/test_ch.c +++ b/tests/test_ch.c @@ -35,7 +35,8 @@ struct ly_ctx *ctx; struct test_state { pthread_barrier_t barrier; - struct lyd_node *tree; + struct lyd_node *ssh_tree; + struct lyd_node *tls_tree; }; /* acquire ctx cb for dispatch */ @@ -69,14 +70,14 @@ ch_new_session_cb(const char *client_name, struct nc_session *new_session, void } static void * -server_thread(void *arg) +server_thread_ssh(void *arg) { int ret; struct test_state *state = arg; struct nc_pollsession *ps; /* prepare data for deleting the call-home client */ - ret = nc_server_config_new_del_ch_client(ctx, "ch", &state->tree); + ret = nc_server_config_new_del_ch_client(ctx, "ch_ssh", &state->ssh_tree); assert_int_equal(ret, 0); /* new poll session */ @@ -85,7 +86,7 @@ server_thread(void *arg) pthread_barrier_wait(&state->barrier); /* create the call-home client thread */ - ret = nc_connect_ch_client_dispatch("ch", ch_session_acquire_ctx_cb, + ret = nc_connect_ch_client_dispatch("ch_ssh", ch_session_acquire_ctx_cb, ch_session_release_ctx_cb, NULL, ch_new_session_cb, ps); assert_int_equal(ret, 0); @@ -98,7 +99,7 @@ server_thread(void *arg) } while (!(ret & NC_PSPOLL_SESSION_TERM)); /* delete the call-home client, the thread should end */ - ret = nc_server_config_setup_data(state->tree); + ret = nc_server_config_setup_data(state->ssh_tree); assert_int_equal(ret, 0); nc_ps_clear(ps, 1, NULL); @@ -108,7 +109,7 @@ server_thread(void *arg) } static void * -client_thread(void *arg) +client_thread_ssh(void *arg) { int ret; struct nc_session *session = NULL; @@ -122,7 +123,7 @@ client_thread(void *arg) assert_int_equal(ret, 0); /* set ssh username */ - ret = nc_client_ssh_ch_set_username("test_ch"); + ret = nc_client_ssh_ch_set_username("test_ch_ssh"); assert_int_equal(ret, 0); /* add client's key pair */ @@ -145,8 +146,183 @@ client_thread(void *arg) return NULL; } +static int +setup_ssh(void **state) +{ + int ret; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + test_state->ssh_tree = NULL; + *state = test_state; + + /* create new context */ + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* load default modules into context */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf-netconf-server module and it's imports into context */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* set call-home address and port */ + ret = nc_server_config_new_ch_address_port(ctx, "ch_ssh", "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &test_state->ssh_tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ch_persistent(ctx, "ch_ssh", &test_state->ssh_tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_new_ch_period(ctx, "ch_ssh", 3, &test_state->ssh_tree); + assert_int_equal(ret, 0); + + /* set call-home server hostkey */ + ret = nc_server_config_new_ssh_ch_hostkey(ctx, "ch_ssh", "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &test_state->ssh_tree); + assert_int_equal(ret, 0); + + /* set call-home client's pubkey */ + ret = nc_server_config_new_ssh_ch_client_auth_pubkey(ctx, "ch_ssh", "endpt", "test_ch_ssh", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->ssh_tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup_data(test_state->ssh_tree); + assert_int_equal(ret, 0); + + /* initialize server */ + ret = nc_server_init(); + assert_int_equal(ret, 0); + + return 0; +} + +static int +teardown_ssh(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + lyd_free_tree(test_state->ssh_tree); + + free(*state); + nc_client_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +static void +test_nc_ch_ssh(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + /* client */ + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + + /* server */ + ret = pthread_create(&tids[1], NULL, server_thread_ssh, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void * +server_thread_tls(void *arg) +{ + int ret; + struct test_state *state = arg; + struct nc_pollsession *ps; + + /* prepare data for deleting the call-home client */ + ret = nc_server_config_new_del_ch_client(ctx, "ch_tls", &state->tls_tree); + assert_int_equal(ret, 0); + + /* new poll session */ + ps = nc_ps_new(); + assert_non_null(ps); + + pthread_barrier_wait(&state->barrier); + /* create the call-home client thread */ + ret = nc_connect_ch_client_dispatch("ch_tls", ch_session_acquire_ctx_cb, + ch_session_release_ctx_cb, NULL, ch_new_session_cb, ps); + assert_int_equal(ret, 0); + + /* poll */ + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + if (ret & (NC_PSPOLL_TIMEOUT | NC_PSPOLL_NOSESSIONS)) { + usleep(500); + } + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + /* delete the call-home client, the thread should end */ + ret = nc_server_config_setup_data(state->tls_tree); + assert_int_equal(ret, 0); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + nc_server_destroy(); + return NULL; +} + +static void * +client_thread_tls(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + /* set directory where to search for modules */ + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* add client's cert */ + ret = nc_client_tls_ch_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key"); + assert_int_equal(ret, 0); + + /* set client ca */ + ret = nc_client_tls_ch_set_trusted_ca_paths(TESTS_DIR "/data/serverca.pem", NULL); + assert_int_equal(ret, 0); + + /* add call-home bind */ + ret = nc_client_tls_ch_add_bind_listen("127.0.0.1", 10010); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + /* connect */ + ret = nc_accept_callhome(NC_ACCEPT_TIMEOUT, NULL, &session); + assert_int_equal(ret, 1); + + ret = nc_client_tls_ch_del_bind("127.0.0.1", 10010); + assert_int_equal(ret, 0); + + nc_session_free(session, NULL); + return NULL; +} + static void -test_nc_ch(void **state) +test_nc_ch_tls(void **state) { int ret, i; pthread_t tids[2]; @@ -154,11 +330,11 @@ test_nc_ch(void **state) assert_non_null(state); /* client */ - ret = pthread_create(&tids[0], NULL, client_thread, *state); + ret = pthread_create(&tids[0], NULL, client_thread_tls, *state); assert_int_equal(ret, 0); /* server */ - ret = pthread_create(&tids[1], NULL, server_thread, *state); + ret = pthread_create(&tids[1], NULL, server_thread_tls, *state); assert_int_equal(ret, 0); for (i = 0; i < 2; i++) { @@ -167,7 +343,7 @@ test_nc_ch(void **state) } static int -setup_f(void **state) +setup_tls(void **state) { int ret; struct test_state *test_state; @@ -181,7 +357,7 @@ setup_f(void **state) ret = pthread_barrier_init(&test_state->barrier, NULL, 2); assert_int_equal(ret, 0); - test_state->tree = NULL; + test_state->tls_tree = NULL; *state = test_state; /* create new context */ @@ -196,17 +372,30 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_new_ch_address_port(ctx, "ch", "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &test_state->tree); + /* set call-home address and port */ + ret = nc_server_config_new_ch_address_port(ctx, "ch_tls", "endpt", NC_TI_OPENSSL, "127.0.0.1", "10010", &test_state->tls_tree); + assert_int_equal(ret, 0); + + /* set call-home server certificate */ + ret = nc_server_config_new_ch_tls_server_certificate(ctx, "ch_tls", "endpt", NULL, TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &test_state->tls_tree); + assert_int_equal(ret, 0); + + /* set call-home client end entity certificate */ + ret = nc_server_config_new_ch_tls_client_certificate(ctx, "ch_tls", "endpt", "ee-cert", TESTS_DIR "/data/client.crt", &test_state->tls_tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_ch_hostkey(ctx, "ch", "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &test_state->tree); + /* set call-home client certificate authority certificate */ + ret = nc_server_config_new_ch_tls_client_ca(ctx, "ch_tls", "endpt", "ca-cert", TESTS_DIR "/data/serverca.pem", &test_state->tls_tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_ch_client_auth_pubkey(ctx, "ch", "endpt", "test_ch", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->tree); + /* set call-home CTN */ + ret = nc_server_config_new_ch_tls_ctn(ctx, "ch_tls", "endpt", 1, + "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", + NC_TLS_CTN_SPECIFIED, "ch_client_tls", &test_state->tls_tree); assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup_data(test_state->tree); + ret = nc_server_config_setup_data(test_state->tls_tree); assert_int_equal(ret, 0); /* initialize server */ @@ -217,7 +406,7 @@ setup_f(void **state) } static int -teardown_f(void **state) +teardown_tls(void **state) { int ret = 0; struct test_state *test_state; @@ -228,7 +417,7 @@ teardown_f(void **state) ret = pthread_barrier_destroy(&test_state->barrier); assert_int_equal(ret, 0); - lyd_free_tree(test_state->tree); + lyd_free_tree(test_state->tls_tree); free(*state); nc_client_destroy(); @@ -241,7 +430,8 @@ int main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_nc_ch, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_ch_ssh, setup_ssh, teardown_ssh), + cmocka_unit_test_setup_teardown(test_nc_ch_tls, setup_tls, teardown_tls), }; setenv("CMOCKA_TEST_ABORT", "1", 1); From be3bc5b762487edcce602401e0116e1386999328 Mon Sep 17 00:00:00 2001 From: roman Date: Sat, 8 Jul 2023 11:55:13 +0200 Subject: [PATCH 043/134] config UPDATE fix deleting list instances --- src/server_config.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/server_config.c b/src/server_config.c index a33fbcfb..f9b48eb1 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -721,6 +721,8 @@ nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey if (!opts->hostkey_count) { free(opts->hostkeys); opts->hostkeys = NULL; + } else if (hostkey == &opts->hostkeys[opts->hostkey_count + 1]) { + memcpy(hostkey, &opts->hostkeys[opts->hostkey_count], sizeof *opts->hostkeys); } } @@ -734,6 +736,8 @@ nc_server_config_del_auth_client_pubkey(struct nc_client_auth *auth_client, stru if (!auth_client->pubkey_count) { free(auth_client->pubkeys); auth_client->pubkeys = NULL; + } else if (pubkey == &auth_client->pubkeys[auth_client->pubkey_count + 1]) { + memcpy(pubkey, &auth_client->pubkeys[auth_client->pubkey_count], sizeof *auth_client->pubkeys); } } @@ -760,6 +764,8 @@ nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_clie if (!opts->client_count) { free(opts->auth_clients); opts->auth_clients = NULL; + } else if (auth_client == &opts->auth_clients[opts->client_count + 1]) { + memcpy(auth_client, &opts->auth_clients[opts->client_count], sizeof *opts->auth_clients); } } @@ -806,6 +812,9 @@ nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) free(server_opts.binds); server_opts.endpts = NULL; server_opts.binds = NULL; + } else if (endpt == &server_opts.endpts[server_opts.endpt_count + 1]) { + memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts); + memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds); } } @@ -836,6 +845,9 @@ nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *b free(server_opts.binds); server_opts.endpts = NULL; server_opts.binds = NULL; + } else if (endpt == &server_opts.endpts[server_opts.endpt_count + 1]) { + memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts); + memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds); } } @@ -910,6 +922,8 @@ nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate if (!certs->cert_count) { free(certs->certs); certs->certs = NULL; + } else if (cert == &certs->certs[certs->cert_count + 1]) { + memcpy(cert, &certs->certs[certs->cert_count], sizeof *certs->certs); } } @@ -1014,6 +1028,9 @@ nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind) free(server_opts.binds); server_opts.endpts = NULL; server_opts.binds = NULL; + } else if (endpt == &server_opts.endpts[server_opts.endpt_count + 1]) { + memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts); + memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds); } } From cea374157c9aab9d00ca1c61d6ac0f48e0f58f10 Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 12 Jul 2023 15:27:52 +0200 Subject: [PATCH 044/134] config UPDATE add docs and refactor some API --- Doxyfile.in | 6 +- examples/server.c | 2 +- src/config_new.c | 429 +++++++++------ src/config_new.h | 2 + src/config_new_ssh.c | 251 ++++++++- src/config_new_tls.c | 187 ++++++- src/server_config.h | 890 +++++++++++++++++++++++-------- tests/test_auth.c | 8 +- tests/test_ch.c | 8 +- tests/test_config_new.c | 2 +- tests/test_ec.c | 6 +- tests/test_ed25519.c | 2 +- tests/test_endpt_share_clients.c | 4 +- tests/test_replace.c | 4 +- tests/test_two_channels.c | 4 +- 15 files changed, 1380 insertions(+), 425 deletions(-) diff --git a/Doxyfile.in b/Doxyfile.in index 445709fc..9ca117bb 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -561,7 +561,7 @@ INLINE_INFO = YES # name. If set to NO, the members will appear in declaration order. # The default value is: YES. -SORT_MEMBER_DOCS = YES +SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member @@ -588,7 +588,7 @@ SORT_MEMBERS_CTORS_1ST = YES # appear in their defined order. # The default value is: NO. -SORT_GROUP_NAMES = YES +SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will @@ -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 NC_ENABLED_TLS +PREDEFINED = NC_ENABLED_SSH_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/examples/server.c b/examples/server.c index bfa6ece8..e0d80566 100644 --- a/examples/server.c +++ b/examples/server.c @@ -250,7 +250,7 @@ init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_T } /* create client authentication configuration data */ - rc = nc_server_config_new_ssh_client_auth_password(*context, "endpt", SSH_USERNAME, SSH_PASSWORD, &config); + rc = nc_server_config_new_ssh_user_password(*context, "endpt", SSH_USERNAME, SSH_PASSWORD, &config); if (rc) { ERR_MSG_CLEANUP("Error creating client authentication configuration data.\n"); } diff --git a/src/config_new.c b/src/config_new.c index 45a1e129..8cea603c 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -34,6 +34,171 @@ #include "session.h" #include "session_p.h" +int +nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...) +{ + int ret = 0; + va_list ap; + char *path = NULL; + struct lyd_node *sub = NULL; + + va_start(ap, path_fmt); + + /* create the path from the format */ + ret = vasprintf(&path, path_fmt, ap); + if (ret == -1) { + ERRMEM; + path = NULL; + goto cleanup; + } + + /* find the node we want to delete */ + ret = lyd_find_path(*tree, path, 0, &sub); + if (ret) { + goto cleanup; + } + + lyd_free_tree(sub); + + /* set the node to top level container */ + ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); + if (ret) { + goto cleanup; + } + + /* add all default nodes */ + ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + va_end(ap); + return ret; +} + +int +nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...) +{ + int ret = 0; + va_list ap; + char *path = NULL; + + va_start(ap, path_fmt); + + /* create the path from the format */ + ret = vasprintf(&path, path_fmt, ap); + if (ret == -1) { + ERRMEM; + path = NULL; + goto cleanup; + } + + /* create the nodes in the path */ + ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); + if (ret) { + goto cleanup; + } + + /* set the node to the top level node */ + ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); + if (ret) { + goto cleanup; + } + + /* add all default nodes */ + ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + va_end(ap); + return ret; +} + +int +nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name, + const char *value, struct lyd_node **tree) +{ + int ret = 0; + char *path = NULL; + + /* create the path by appending child to the parent path */ + ret = asprintf(&path, "%s/%s", parent_path, child_name); + if (ret == -1) { + ERRMEM; + path = NULL; + goto cleanup; + } + + /* create the nodes in the path */ + ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); + if (ret) { + goto cleanup; + } + + /* set the node to the top level node */ + ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); + if (ret) { + goto cleanup; + } + + /* add all default nodes */ + ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +int +nc_config_new_check_delete(struct lyd_node **tree, const char *path_fmt, ...) +{ + int ret = 0; + va_list ap; + char *path = NULL; + struct lyd_node *sub = NULL; + + va_start(ap, path_fmt); + + /* create the path from the format */ + ret = vasprintf(&path, path_fmt, ap); + if (ret == -1) { + ERRMEM; + path = NULL; + goto cleanup; + } + + /* find the node we want to delete */ + ret = lyd_find_path(*tree, path, 0, &sub); + if ((ret == LY_EINCOMPLETE) || (ret == LY_ENOTFOUND)) { + ret = 0; + goto cleanup; + } else if (ret) { + ERR(NULL, "Unable to delete node in the path \"%s\".", path); + goto cleanup; + } + + lyd_free_tree(sub); + + /* set the node to top level container */ + ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + va_end(ap); + return ret; +} + #ifdef NC_ENABLED_SSH_TLS const char * @@ -671,7 +836,7 @@ nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_na } API int -nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +nc_server_config_new_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) { int ret = 0; @@ -693,12 +858,12 @@ nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *ch_cl goto cleanup; } - ret = nc_config_new_create(ctx, config, address, address_fmt, ch_client_name, endpt_name); + ret = nc_config_new_create(ctx, config, address, address_fmt, client_name, endpt_name); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, port, port_fmt, ch_client_name, endpt_name); + ret = nc_config_new_create(ctx, config, port, port_fmt, client_name, endpt_name); if (ret) { goto cleanup; } @@ -708,11 +873,41 @@ nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *ch_cl } API int -nc_server_config_new_del_ch_client(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config) +nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + if (endpt_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']", endpt_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint"); + } +} + +API int +nc_server_config_new_del_ch_client(const char *ch_client_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, config, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']", ch_client_name); + if (ch_client_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']", ch_client_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client"); + } +} + +API int +nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, config, 1); + + if (endpt_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']", client_name, endpt_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint", client_name); + } } API int @@ -778,6 +973,18 @@ nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *nam return ret; } +API int +nc_server_config_new_del_keystore_asym_key(const char *name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, config, 1); + + if (name) { + return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']", name); + } else { + return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key"); + } +} + API int nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config) @@ -818,172 +1025,22 @@ nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag return ret; } -#endif /* NC_ENABLED_SSH_TLS */ - -int -nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...) -{ - int ret = 0; - va_list ap; - char *path = NULL; - struct lyd_node *sub = NULL; - - va_start(ap, path_fmt); - - /* create the path from the format */ - ret = vasprintf(&path, path_fmt, ap); - if (ret == -1) { - ERRMEM; - path = NULL; - goto cleanup; - } - - /* find the node we want to delete */ - ret = lyd_find_path(*tree, path, 0, &sub); - if (ret) { - goto cleanup; - } - - lyd_free_tree(sub); - - /* set the node to top level container */ - ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); - if (ret) { - goto cleanup; - } - - /* add all default nodes */ - ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; - } - -cleanup: - free(path); - va_end(ap); - return ret; -} - -int -nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...) -{ - int ret = 0; - va_list ap; - char *path = NULL; - - va_start(ap, path_fmt); - - /* create the path from the format */ - ret = vasprintf(&path, path_fmt, ap); - if (ret == -1) { - ERRMEM; - path = NULL; - goto cleanup; - } - - /* create the nodes in the path */ - ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); - if (ret) { - goto cleanup; - } - - /* set the node to the top level node */ - ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); - if (ret) { - goto cleanup; - } - - /* add all default nodes */ - ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; - } - -cleanup: - free(path); - va_end(ap); - return ret; -} - -int -nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name, - const char *value, struct lyd_node **tree) +API int +nc_server_config_new_del_truststore_pubkey(const char *bag_name, + const char *pubkey_name, struct lyd_node **config) { - int ret = 0; - char *path = NULL; + NC_CHECK_ARG_RET(NULL, bag_name, config, 1); - /* create the path by appending child to the parent path */ - ret = asprintf(&path, "%s/%s", parent_path, child_name); - if (ret == -1) { - ERRMEM; - path = NULL; - goto cleanup; - } - - /* create the nodes in the path */ - ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); - if (ret) { - goto cleanup; - } - - /* set the node to the top level node */ - ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); - if (ret) { - goto cleanup; - } - - /* add all default nodes */ - ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; + if (pubkey_name) { + return nc_config_new_delete(config, "/ietf-truststore:truststore/public-key-bags/" + "public-key-bag[name='%s']/public-key[name='%s']", bag_name, pubkey_name); + } else { + return nc_config_new_delete(config, "/ietf-truststore:truststore/public-key-bags/" + "public-key-bag[name='%s']/public-key", bag_name); } - -cleanup: - free(path); - return ret; } -int -nc_config_new_check_delete(struct lyd_node **tree, const char *path_fmt, ...) -{ - int ret = 0; - va_list ap; - char *path = NULL; - struct lyd_node *sub = NULL; - - va_start(ap, path_fmt); - - /* create the path from the format */ - ret = vasprintf(&path, path_fmt, ap); - if (ret == -1) { - ERRMEM; - path = NULL; - goto cleanup; - } - - /* find the node we want to delete */ - ret = lyd_find_path(*tree, path, 0, &sub); - if ((ret == LY_EINCOMPLETE) || (ret == LY_ENOTFOUND)) { - ret = 0; - goto cleanup; - } else if (ret) { - ERR(NULL, "Unable to delete node in the path \"%s\".", path); - goto cleanup; - } - - lyd_free_tree(sub); - - /* set the node to top level container */ - ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); - if (ret) { - goto cleanup; - } - -cleanup: - free(path); - va_end(ap); - return ret; -} +#endif /* NC_ENABLED_SSH_TLS */ API int nc_server_config_new_ch_persistent(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config) @@ -1019,6 +1076,15 @@ nc_server_config_new_ch_period(const struct ly_ctx *ctx, const char *ch_client_n "netconf-client[name='%s']/connection-type/periodic/period", ch_client_name); } +API int +nc_server_config_new_ch_del_period(const char *ch_client_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/connection-type/periodic/period", ch_client_name); +} + API int nc_server_config_new_ch_anchor_time(const struct ly_ctx *ctx, const char *ch_client_name, const char *anchor_time, struct lyd_node **config) @@ -1035,6 +1101,15 @@ nc_server_config_new_ch_anchor_time(const struct ly_ctx *ctx, const char *ch_cli "netconf-client[name='%s']/connection-type/periodic/anchor-time", ch_client_name); } +API int +nc_server_config_new_ch_del_anchor_time(const char *ch_client_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/connection-type/periodic/anchor-time", ch_client_name); +} + API int nc_server_config_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_client_name, uint16_t idle_timeout, struct lyd_node **config) @@ -1054,9 +1129,18 @@ nc_server_config_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_cl "netconf-client[name='%s']/connection-type/periodic/idle-timeout", ch_client_name); } +API int +nc_server_config_new_ch_del_idle_timeout(const char *ch_client_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/connection-type/periodic/idle-timeout", ch_client_name); +} + API int nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char *ch_client_name, - NC_CH_START_WITH start_with, uint8_t max_attempts, uint16_t max_wait, struct lyd_node **config) + NC_CH_START_WITH start_with, uint16_t max_wait, uint8_t max_attempts, struct lyd_node **config) { int ret = 0; char *path = NULL; @@ -1111,3 +1195,12 @@ nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char free(path); return ret; } + +API int +nc_server_config_new_ch_del_reconnect_strategy(const char *ch_client_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/reconnect-strategy", ch_client_name); +} diff --git a/src/config_new.h b/src/config_new.h index 985ab347..76ae4815 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -121,6 +121,8 @@ int nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_pat */ int nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...); +int nc_config_new_check_delete(struct lyd_node **tree, const char *path_fmt, ...); + #ifdef __cplusplus } #endif diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index 8ecd7f2d..266ffc74 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -97,6 +97,21 @@ nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_nam return ret; } +API int +nc_server_config_new_ssh_del_hostkey(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + if (hostkey_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key[name='%s']", endpt_name, hostkey_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key", endpt_name); + } +} + static int nc_server_config_new_ssh_transport_params_prep(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node *config, struct lyd_node **new_tree, struct lyd_node **alg_tree) @@ -234,6 +249,21 @@ nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *end return ret; } +API int +nc_server_config_new_ssh_del_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/host-key/" + "host-key-alg[.='iana-ssh-public-key-algs:%s']", endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/host-key", endpt_name); + } +} + API int nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...) @@ -267,6 +297,21 @@ nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char return ret; } +API int +nc_server_config_new_ssh_del_key_exchange_alg(const char *endpt_name, const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/key-exchange/" + "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/key-exchange", endpt_name); + } +} + API int nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...) @@ -300,6 +345,21 @@ nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *e return ret; } +API int +nc_server_config_new_ssh_del_encryption_alg(const char *endpt_name, const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/encryption/" + "encryption-alg[.='iana-ssh-encryption-algs:%s']", endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/encryption", endpt_name); + } +} + API int nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...) @@ -334,7 +394,37 @@ nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_na } API int -nc_server_config_new_ssh_client_auth_pubkey(const struct ly_ctx *ctx, const char *endpt_name, +nc_server_config_new_ssh_del_mac_alg(const char *endpt_name, const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/mac/" + "mac-alg[.='iana-ssh-mac-algs:%s']", endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/mac", endpt_name); + } +} + +API int +nc_server_config_new_ssh_del_user(const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (user_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']", endpt_name, user_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user", endpt_name); + } +} + +API int +nc_server_config_new_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) { int ret = 0; @@ -373,7 +463,24 @@ nc_server_config_new_ssh_client_auth_pubkey(const struct ly_ctx *ctx, const char } API int -nc_server_config_new_ssh_client_auth_password(const struct ly_ctx *ctx, const char *endpt_name, +nc_server_config_new_ssh_del_user_pubkey(const char *endpt_name, const char *user_name, + const char *pubkey_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + + if (pubkey_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" + "public-key[name='%s']", endpt_name, user_name, pubkey_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" + "public-key", endpt_name, user_name); + } +} + +API int +nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *password, struct lyd_node **config) { int ret = 0; @@ -410,37 +517,53 @@ nc_server_config_new_ssh_client_auth_password(const struct ly_ctx *ctx, const ch } API int -nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const char *endpt_name, +nc_server_config_new_ssh_del_user_password(const char *endpt_name, const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/password", endpt_name, user_name); +} + +API int +nc_server_config_new_ssh_user_none(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, struct lyd_node **config) { - int ret = 0; + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, config, 1); - ret = nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + return nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/none", endpt_name, user_name); - if (ret) { - goto cleanup; - } +} -cleanup: - return ret; +API int +nc_server_config_new_ssh_del_user_none(const char *endpt_name, const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/none", endpt_name, user_name); } API int -nc_server_config_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, const char *endpt_name, +nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) { int ret = 0; + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pam_config_name, config, 1); + ret = nc_config_new_create(ctx, config, pam_config_name, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive/pam-config-file-name", endpt_name, user_name); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, pam_config_dir, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive/pam-config-file-dir", endpt_name, user_name); - if (ret) { - goto cleanup; + if (pam_config_dir) { + ret = nc_config_new_create(ctx, config, pam_config_dir, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive/pam-config-file-dir", endpt_name, user_name); + if (ret) { + goto cleanup; + } } cleanup: @@ -448,14 +571,36 @@ nc_server_config_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, const } API int -nc_config_new_ssh_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config) +nc_server_config_new_ssh_del_user_interactive(const char *endpt_name, const char *user_name, struct lyd_node **config) { + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name); +} + +API int +nc_config_new_ssh_endpoint_user_reference(const struct ly_ctx *ctx, const char *endpt_name, + const char *referenced_endpt, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); + return nc_config_new_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); } API int -nc_server_config_new_ssh_ch_hostkey(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +nc_config_new_ssh_del_endpoint_user_reference(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); +} + +API int +nc_server_config_new_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) { int ret = 0; @@ -489,28 +634,28 @@ nc_server_config_new_ssh_ch_hostkey(const struct ly_ctx *ctx, const char *ch_cli ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/inline-definition/public-key-format", ch_client_name, endpt_name, hostkey_name); + "host-key[name='%s']/public-key/inline-definition/public-key-format", client_name, endpt_name, hostkey_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/inline-definition/public-key", ch_client_name, endpt_name, hostkey_name); + "host-key[name='%s']/public-key/inline-definition/public-key", client_name, endpt_name, hostkey_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/inline-definition/private-key-format", ch_client_name, endpt_name, hostkey_name); + "host-key[name='%s']/public-key/inline-definition/private-key-format", client_name, endpt_name, hostkey_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, privkey, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/inline-definition/cleartext-private-key", ch_client_name, endpt_name, hostkey_name); + "host-key[name='%s']/public-key/inline-definition/cleartext-private-key", client_name, endpt_name, hostkey_name); if (ret) { goto cleanup; } @@ -522,7 +667,24 @@ nc_server_config_new_ssh_ch_hostkey(const struct ly_ctx *ctx, const char *ch_cli } API int -nc_server_config_new_ssh_ch_client_auth_pubkey(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +nc_server_config_new_ch_ssh_del_hostkey(const char *client_name, const char *endpt_name, + const char *hostkey_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (hostkey_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']", client_name, endpt_name, hostkey_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key", client_name, endpt_name); + } +} + +API int +nc_server_config_new_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) { int ret = 0; @@ -546,7 +708,7 @@ nc_server_config_new_ssh_ch_client_auth_pubkey(const struct ly_ctx *ctx, const c ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/" - "public-key-format", ch_client_name, endpt_name, user_name, pubkey_name); + "public-key-format", client_name, endpt_name, user_name, pubkey_name); if (ret) { goto cleanup; } @@ -554,7 +716,7 @@ nc_server_config_new_ssh_ch_client_auth_pubkey(const struct ly_ctx *ctx, const c ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/" - "public-key", ch_client_name, endpt_name, user_name, pubkey_name); + "public-key", client_name, endpt_name, user_name, pubkey_name); if (ret) { goto cleanup; } @@ -564,6 +726,25 @@ nc_server_config_new_ssh_ch_client_auth_pubkey(const struct ly_ctx *ctx, const c return ret; } +API int +nc_server_config_new_ch_ssh_del_user_pubkey(const char *client_name, const char *endpt_name, + const char *user_name, const char *pubkey_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + + if (pubkey_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, + endpt_name, user_name, pubkey_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key", client_name, + endpt_name, user_name); + } +} + API int nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, const char *keystore_reference, struct lyd_node **config) @@ -575,6 +756,17 @@ nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char "keystore-reference", endpt_name, hostkey_name); } +API int +nc_server_config_new_ssh_del_keystore_reference(const char *endpt_name, const char *hostkey_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" + "keystore-reference", endpt_name, hostkey_name); +} + API int nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *truststore_reference, struct lyd_node **config) @@ -585,3 +777,14 @@ nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, const ch "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" "truststore-reference", endpt_name, user_name); } + +API int +nc_server_config_new_ssh_del_truststore_reference(const char *endpt_name, const char *user_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" + "truststore-reference", endpt_name, user_name); +} diff --git a/src/config_new_tls.c b/src/config_new_tls.c index f1616cbf..988827b5 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -130,6 +130,15 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char return ret; } +API int +nc_server_config_new_tls_del_server_certificate(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/inline-definition", endpt_name); +} + API int nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, const char *pubkey_path, const char *privkey_path, const char *certificate_path, struct lyd_node **config) @@ -161,6 +170,17 @@ nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const c return ret; } +API int +nc_server_config_new_ch_tls_del_server_certificate(const char *ch_client_name, const char *endpt_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ch_client_name, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" + "certificate/inline-definition", ch_client_name, endpt_name); +} + static int _nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *cert_path, struct lyd_node **config) @@ -212,6 +232,22 @@ nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char return ret; } +API int +nc_server_config_new_tls_del_client_certificate(const char *endpt_name, const char *cert_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (cert_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/inline-definition/" + "certificate[name='%s']", endpt_name, cert_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/inline-definition/" + "certificate", endpt_name); + } +} + API int nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, const char *cert_name, const char *cert_path, struct lyd_node **config) @@ -242,6 +278,23 @@ nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, const c return ret; } +API int +nc_server_config_new_ch_tls_del_client_certificate(const char *ch_client_name, const char *endpt_name, + const char *cert_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ch_client_name, endpt_name, config, 1); + + if (cert_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" + "inline-definition/certificate[name='%s']", ch_client_name, endpt_name, cert_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" + "inline-definition/certificate", ch_client_name, endpt_name); + } +} + API int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, const char *cert_path, struct lyd_node **config) @@ -270,6 +323,22 @@ nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_n return ret; } +API int +nc_server_config_new_tls_del_client_ca(const char *endpt_name, const char *cert_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (cert_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/inline-definition/" + "certificate[name='%s']", endpt_name, cert_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/inline-definition/" + "certificate", endpt_name); + } +} + API int nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, const char *cert_name, const char *cert_path, struct lyd_node **config) @@ -300,6 +369,23 @@ nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char *ch_c return ret; } +API int +nc_server_config_new_ch_tls_del_client_ca(const char *ch_client_name, const char *endpt_name, + const char *cert_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ch_client_name, endpt_name, config, 1); + + if (cert_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" + "inline-definition/certificate[name='%s']", ch_client_name, endpt_name, cert_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" + "inline-definition/certificate", ch_client_name, endpt_name); + } +} + static const char * nc_config_new_tls_maptype2str(NC_TLS_CTN_MAPTYPE map_type) { @@ -387,6 +473,20 @@ nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, u return ret; } +API int +nc_server_config_new_tls_del_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (id) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%u']", endpt_name, id); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "netconf-server-parameters/client-identity-mappings/cert-to-name", endpt_name); + } +} + API int nc_server_config_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *ch_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) @@ -416,6 +516,23 @@ nc_server_config_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *ch_client_ return ret; } +API int +nc_server_config_new_ch_tls_del_ctn(const char *ch_client_name, const char *endpt_name, + uint32_t id, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ch_client_name, endpt_name, config, 1); + + if (id) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" + "cert-to-name[id='%u']", ch_client_name, endpt_name, id); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" + "cert-to-name", ch_client_name, endpt_name); + } +} + static const char * nc_config_new_tls_tlsversion2str(NC_TLS_VERSION version) { @@ -451,10 +568,28 @@ nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt_nam ret = nc_config_new_create(ctx, config, version, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" "hello-params/tls-versions/tls-version", endpt_name); - if (ret) { + +cleanup: + return ret; +} + +API int +nc_server_config_new_tls_del_version(const char *endpt_name, NC_TLS_VERSION tls_version, struct lyd_node **config) +{ + int ret = 0; + const char *version; + + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + version = nc_config_new_tls_tlsversion2str(tls_version); + if (!version) { + ret = 1; goto cleanup; } + ret = nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/hello-params/tls-versions/tls-version[.='%s']", endpt_name, version); + cleanup: return ret; } @@ -513,6 +648,16 @@ nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_nam return ret; } +API int +nc_server_config_new_tls_del_cipher(const char *endpt_name, const char *cipher, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, cipher, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/hello-params/cipher-suites/" + "cipher-suite[.='iana-tls-cipher-suite-algs:%s']", endpt_name, cipher); +} + API int nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, const char *path, struct lyd_node **config) { @@ -658,9 +803,49 @@ nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endp return ret; } +API int +nc_server_config_new_tls_del_crl(const char *endpt_name, struct lyd_node **config) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-path", endpt_name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-url", endpt_name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-cert-ext", endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + API int nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config) { + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); + return nc_config_new_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); } + +API int +nc_config_new_tls_del_endpoint_client_reference(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); +} diff --git a/src/server_config.h b/src/server_config.h index 103416e5..c5399146 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -27,6 +27,14 @@ extern "C" { #include "session.h" +/** + * @defgroup server_config Server Configuration + * @ingroup server + * + * @brief Server-side configuration creation and application + * @{ + */ + /** * @brief Configure server based on the given diff data. * @@ -100,99 +108,149 @@ int nc_server_config_load_modules(struct ly_ctx **ctx); int nc_server_config_new_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 Creates new YANG configuration data nodes for a hostkey. + * @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 Configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **config); + +#ifdef NC_ENABLED_SSH_TLS + +/** + * @brief Creates new YANG data nodes for an asymmetric key in the keystore. * * @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 Path to a file containing a public key. If NULL, public key will be - * generated from the private key. + * @param[in] name Name of the asymmetric key pair. + * This name is used to reference the key pair. + * @param[in] privkey_path Path to a private key file. + * @param[in] pubkey_path Optional path a public key file. + * If not supplied, it 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_new_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_new_keystore_asym_key(const struct ly_ctx *ctx, const char *name, const char *privkey_path, + const char *pubkey_path, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for host-key algorithms replacing any previous ones. + * @brief Deletes a keystore's asymmetric key from the YANG data. * - * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, - * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. + * @param[in] name Optional identifier of the asymmetric key to be deleted. + * If NULL, all of the asymmetric keys in the keystore will be deleted. + * @param[in,out] config Configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_del_keystore_asym_key(const char *name, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a public key in the truststore. * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its host-key algorithms will be replaced. + * @param[in] ctx libyang context. + * @param[in] bag_name Arbitrary identifier of the public key bag. + * This name is used to reference the public keys in the bag. + * If a public key bag with this name already exists, its contents will be changed. + * @param[in] pubkey_name Arbitrary identifier of the public key. + * If a public key with this name 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. - * @param[in] alg_count Number of following algorithms. - * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); +int nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag_name, const char *pubkey_name, + const char *pubkey_path, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for key exchange algorithms replacing any previous ones. - * - * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, - * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, - * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. + * @brief Deletes a truststore's public key from the YANG data. * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its key exchange algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. + * @param[in] bag_name Identifier of an existing public key bag. + * @param[in] pubkey_name Optional identifier of a public key to be deleted. + * If NULL, all of the public keys in the given bag will be deleted. + * @param[in,out] config Configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); +int nc_server_config_new_del_truststore_pubkey(const char *bag_name, const char *pubkey_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for encryption algorithms replacing any previous ones. + * @} + */ + +/** + * @defgroup server_config_ssh SSH Server Configuration + * @ingroup server_config * - * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc - * triple-des-cbc and none. + * @brief SSH server configuration creation and deletion + * @{ + */ + +/** + * @brief Creates new YANG configuration data nodes for a hostkey. * - * @param[in] ctx libyang context + * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its encryption algorithms will be replaced. + * 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 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. - * @param[in] alg_count Number of following algorithms. - * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); +int nc_server_config_new_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 Creates new YANG configuration data nodes for mac algorithms replacing any previous ones. + * @brief Deletes a hostkey from the YANG data. * - * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. + * @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. + */ +int nc_server_config_new_ssh_del_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. * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its mac algorithms will be replaced. + * 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. - * @param[in] alg_count Number of following algorithms. - * @param[in] ... String literals of mac algorithms in a decreasing order of preference. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ssh_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); +int nc_server_config_new_ssh_keystore_reference(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_new_ssh_del_keystore_reference(const char *endpt_name, const char *hostkey_name, + struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a client, which supports the public key authentication method. + * @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. @@ -206,29 +264,51 @@ int nc_server_config_new_ssh_mac_algs(const struct ly_ctx *ctx, const char *endp * 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_new_ssh_client_auth_pubkey(const struct ly_ctx *ctx, const char *endpt_name, +int nc_server_config_new_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 Creates new YANG configuration data nodes for a client, which supports the password authentication method. + * @brief Deletes an SSH user's public key from the YANG data. * - * This function sets the password for the given user. + * @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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_del_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'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 Cleartext user's password. + * @param[in] password Cleartext password to be set for the user. * @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_new_ssh_client_auth_password(const struct ly_ctx *ctx, const char *endpt_name, +int nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *password, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a client, which supports the none authentication method. + * @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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_del_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 none authentication method. * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. @@ -239,11 +319,22 @@ int nc_server_config_new_ssh_client_auth_password(const struct ly_ctx *ctx, cons * 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_new_ssh_client_auth_none(const struct ly_ctx *ctx, const char *endpt_name, +int nc_server_config_new_ssh_user_none(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a client, which supports the interactive authentication method. + * @brief Deletes an SSH user's none authentication 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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_del_user_none(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. * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. @@ -258,14 +349,66 @@ int nc_server_config_new_ssh_client_auth_none(const struct ly_ctx *ctx, const ch * 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_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, const char *endpt_name, +int nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes, which will be a reference to another SSH endpoint's clients. + * @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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_del_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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_del_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 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_new_ssh_truststore_reference(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. * - * Whenever an user 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 clients will be tried. + * @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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_del_truststore_reference(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. @@ -276,9 +419,146 @@ int nc_server_config_new_ssh_client_auth_interactive(const struct ly_ctx *ctx, c * 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_config_new_ssh_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, +int nc_config_new_ssh_endpoint_user_reference(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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_config_new_ssh_del_endpoint_user_reference(const char *endpt_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for host-key algorithms replacing any previous ones. + * + * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, + * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its host-key algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); + +/** + * @brief Deletes a hostkey algorithm from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] alg Optional algorithm to be deleted. + * If NULL, all of the hostkey algorithms on this endpoint will be deleted. + * @param[in,out] config Configuraiton YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_del_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for key exchange algorithms replacing any previous ones. + * + * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, + * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, + * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its key exchange algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +/** + * @brief Deletes a key exchange algorithm from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] alg Optional algorithm to be deleted. + * If NULL, all of the key exchange algorithms on this endpoint will be deleted. + * @param[in,out] config Configuraiton YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_del_key_exchange_alg(const char *endpt_name, const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for encryption algorithms replacing any previous ones. + * + * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc + * triple-des-cbc and none. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its encryption algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +/** + * @brief Deletes an encryption algorithm from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] alg Optional algorithm to be deleted. + * If NULL, all of the encryption algorithms on this endpoint will be deleted. + * @param[in,out] config Configuraiton YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_del_encryption_alg(const char *endpt_name, const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for mac algorithms replacing any previous ones. + * + * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its mac algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of mac algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +/** + * @brief Deletes a mac algorithm from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] alg Optional algorithm to be deleted. + * If NULL, all of the mac algorithms on this endpoint will be deleted. + * @param[in,out] config Configuraiton YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ssh_del_mac_alg(const char *endpt_name, const char *alg, struct lyd_node **config); + +/** + * @} + */ + +/** + * @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. * @@ -296,6 +576,15 @@ int nc_config_new_ssh_endpoint_client_reference(const struct ly_ctx *ctx, const int nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *pubkey_path, const char *privkey_path, const char *certificate_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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_del_server_certificate(const char *endpt_name, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a client's (end-entity) certificate. * @@ -312,6 +601,17 @@ int nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const int nc_server_config_new_tls_client_certificate(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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_del_client_certificate(const char *endpt_name, const char *cert_name, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a client certificate authority (trust-anchor) certificate. * @@ -328,6 +628,17 @@ int nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const int nc_server_config_new_tls_client_ca(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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_del_client_ca(const char *endpt_name, const char *cert_name, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a cert-to-name entry. * @@ -346,6 +657,17 @@ int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *end int nc_server_config_new_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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_del_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a TLS version. * @@ -359,8 +681,18 @@ int nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_nam * 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_new_tls_version(const struct ly_ctx *ctx, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config); +int nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config); + +/** + * @brief Deletes a TLS version from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] tls_version TLS version to be deleted. + * @param[in,out] config Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_del_version(const char *endpt_name, NC_TLS_VERSION tls_version, struct lyd_node **config); /** * @brief Creates new YANG configuration data nodes for a TLS cipher. @@ -381,6 +713,16 @@ int nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt int nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int cipher_count, ...); +/** + * @brief Deletes a TLS cipher from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] cipher TLS cipher to be deleted. + * @param[in,out] config Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_del_cipher(const char *endpt_name, const char *cipher, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via a local file. * @@ -431,6 +773,15 @@ int nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt */ int nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config); +/** + * @brief Deletes all the CRL nodes from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in,out] config Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_del_crl(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. * @@ -449,11 +800,32 @@ int nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char * int nc_config_new_tls_endpoint_client_reference(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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_config_new_tls_del_endpoint_client_reference(const char *endpt_name, struct lyd_node **config); + +/** + * @} + */ + +/** + * @defgroup server_config_ch Call-Home server Configuration + * @ingroup server_config + * + * @brief Call-Home server configuration creation and deletion + * @{ + */ + /** * @brief Creates new YANG configuration data nodes for a call-home client's address and port. * * @param[in] ctx libyang context. - * @param[in] ch_client_name Arbitrary identifier of the call-home client. + * @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. @@ -464,135 +836,251 @@ int nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const * 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_new_ch_address_port(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +int nc_server_config_new_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 Creates new YANG data nodes for a call-home SSH hostkey. + * @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,out] config Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_del_ch_client(const char *client_name, struct lyd_node **config); + +/** + * @brief Deletes a Call-Home endpoint from the YANG data. + * + * @param[in] client_name Identifier of an existing Call-Home client. + * @param[in] endpt_name Optional identifier of a CH endpoint to be deleted. + * If NULL, all of the CH endpoints which belong to the given client will be deleted. + * @param[in,out] config Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for the call-home persistent connection type. + * + * This is the default connection type. If periodic connection type was set before, it will be unset. * * @param[in] ctx libyang context. - * @param[in] ch_client_name Arbitrary identifier of the call-home client. + * @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. + * @param 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_new_ssh_ch_hostkey(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, - const char *hostkey_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config); +int nc_server_config_new_ch_persistent(const struct ly_ctx *ctx, const char *client_name, struct lyd_node **config); /** - * @brief Creates new YANG data nodes for a call-home client's public key. + * @brief Creates new YANG configuration data nodes for the period parameter of the call-home periodic connection type. + * + * If called, the persistent connection type will be replaced by periodic. * * @param[in] ctx libyang context. - * @param[in] ch_client_name Arbitrary identifier of the call-home client. + * @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. + * @param[in] period Duration between periodic connections in minutes. + * @param 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_new_ssh_ch_client_auth_pubkey(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, - const char *user_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config); +int nc_server_config_new_ch_period(const struct ly_ctx *ctx, const char *client_name, uint16_t period, + struct lyd_node **config); /** - * @brief Deletes a call-home client from the YANG data. + * @brief Deletes the Call-Home period parameter of the periodic connection type from the YANG data. + * + * This behaves the same as setting the period to 60 minutes, which is the default value of this node. + * + * @param[in] client_name Identifier of an existing Call-Home client. + * @param[in,out] config Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_del_period(const char *client_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for the anchor time parameter of the call-home periodic connection type. + * + * If called, the persistent connection type will be replaced by periodic. * * @param[in] ctx libyang context. - * @param[in] ch_client_name The name of the client to be deleted from the data. - * The client has to be present in the data. - * @param[in,out] config Modified configuration YANG data tree. + * @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] anchor_time Timestamp before or after which a series of periodic connections are determined. + * @param 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_new_del_ch_client(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config); +int nc_server_config_new_ch_anchor_time(const struct ly_ctx *ctx, const char *client_name, + const char *anchor_time, struct lyd_node **config); /** - * @brief Creates new YANG data nodes for an asymmetric key in the keystore. + * @brief Deletes the Call-Home anchor time parameter of the periodic connection type from the YANG data. + * + * @param[in] client_name Identifier of an existing Call-Home client. + * @param[in,out] config Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_del_anchor_time(const char *client_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for the idle timeout parameter of the call-home periodic connection type. + * + * If called, the persistent connection type will be replaced by periodic. * * @param[in] ctx libyang context. - * @param[in] name Name of the asymmetric key pair. - * This name is used to reference the key pair. - * @param[in] privkey_path Path to a private key file. - * @param[in] pubkey_path Optional path a public key file. - * If not supplied, it will be generated from the private key. - * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * @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] idle_timeout Specifies the maximum number of seconds that a session may remain idle. + * @param 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_new_keystore_asym_key(const struct ly_ctx *ctx, const char *name, const char *privkey_path, - const char *pubkey_path, struct lyd_node **config); +int nc_server_config_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *client_name, + uint16_t idle_timeout, struct lyd_node **config); /** - * @brief Creates new YANG data nodes for a reference to an asymmetric key located in the keystore. + * @brief Deletes the Call-Home idle timeout parameter of the periodic connection type from the YANG data. * - * This asymmetric key pair will be used as the SSH hostkey. + * This behaves the same as setting the timeout to 180 seconds, which is the default value of this node. + * + * @param[in] client_name Identifier of an existing Call-Home client. + * @param[in,out] config Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_del_idle_timeout(const char *client_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for the call-home reconnect strategy. * * @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. + * @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] start_with Specifies which endpoint to try if a connection is unsuccessful. Default value is NC_CH_FIRST_LISTED. + * @param[in] max_wait The number of seconds after which a connection to an endpoint is deemed unsuccessful. Default value if 5. + * @param[in] max_attempts The number of unsuccessful connection attempts before moving to the next endpoint. Default value is 3. + * @param 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_new_ssh_keystore_reference(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_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char *client_name, + NC_CH_START_WITH start_with, uint16_t max_wait, uint8_t max_attempts, struct lyd_node **config); /** - * @brief Creates new YANG data nodes for a public key in the truststore. + * @brief Resets the values of the Call-Home reconnect strategy nodes to their defaults. + * + * The default values are: start-with = NC_CH_FIRST_LISTED, max-wait = 5 and max-attempts = 3. + * + * @param[in] client_name Identifier of an existing Call-Home client. + * @param[in,out] config Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_del_reconnect_strategy(const char *client_name, struct lyd_node **config); + +/** + * @} + */ + +#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] bag_name Arbitrary identifier of the public key bag. - * This name is used to reference the public keys in the bag. - * If a public key bag with this name already exists, its contents will be changed. - * @param[in] pubkey_name Arbitrary identifier of the public key. - * If a public key with this name already exists, its contents will be changed. - * @param[in] pubkey_path Path to a file containing a public key. + * @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_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag_name, const char *pubkey_name, - const char *pubkey_path, struct lyd_node **config); +int nc_server_config_new_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 Creates new YANG data nodes for a reference to a public key bag located in the truststore. + * @brief Deletes a Call-home hostkey from the YANG data. * - * The public key's located in the bag will be used for client authentication. + * @param[in] client_name Identifier of an existing Call-home client. + * @param[in] endpt_name Identifier of an existing endpoint which 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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_ssh_del_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 call-home client's public key. * * @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] 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 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 config Configuration YANG data tree. If *config is NULL, it will be created. + * 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_new_ssh_truststore_reference(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_new_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 which belongs to the given CH client. + * @param[in] user_name Identifier of an existing SSH user which 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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_ssh_del_user_pubkey(const char *client_name, const char *endpt_name, + const char *user_name, const char *pubkey_name, struct lyd_node **config); + +/** + * @} + */ + +/** + * @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] ch_client_name Arbitrary identifier of the call-home client. + * @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. @@ -604,14 +1092,25 @@ int nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, cons * 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_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +int nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, const char *pubkey_path, const char *privkey_path, const char *certificate_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 which belongs to the given client. + * @param[in,out] config Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_tls_del_server_certificate(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] ch_client_name Arbitrary identifier of the call-home client. + * @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. @@ -622,14 +1121,27 @@ int nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, con * 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_new_ch_tls_client_certificate(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +int nc_server_config_new_ch_tls_client_certificate(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 which 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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_tls_del_client_certificate(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 client certificate authority (trust-anchor) certificate. * * @param[in] ctx libyang context. - * @param[in] ch_client_name Arbitrary identifier of the call-home client. + * @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. @@ -640,14 +1152,27 @@ int nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, con * 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_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +int nc_server_config_new_ch_tls_client_ca(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 which 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 Configuration YANG data. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_tls_del_client_ca(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 cert-to-name entry. * * @param[in] ctx libyang context. - * @param[in] ch_client_name Arbitrary identifier of the call-home client. + * @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. @@ -660,80 +1185,27 @@ int nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char * * 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_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +int nc_server_config_new_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); -#endif /* NC_ENABLED_SSH_TLS */ - -/** - * @brief Creates new YANG configuration data nodes for the call-home persistent connection type. - * - * @param[in] ctx libyang context. - * @param[in] ch_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 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_new_ch_persistent(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for the period parameter of the call-home periodic connection type. - * - * @param[in] ctx libyang context. - * @param[in] ch_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] period Duration between periodic connections. - * @param 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_new_ch_period(const struct ly_ctx *ctx, const char *ch_client_name, uint16_t period, - struct lyd_node **config); - /** - * @brief Creates new YANG configuration data nodes for the anchor time parameter of the call-home periodic connection type. + * @brief Deletes a Call-Home cert-to-name entry from the YANG data. * - * @param[in] ctx libyang context. - * @param[in] ch_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] anchor_time Timestamp before or after which a series of periodic connections are determined. - * @param 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[in] client_name Identifier of an existing Call-Home client. + * @param[in] endpt_name Identifier of an existing Call-Home endpoint which 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 Configuration YANG data. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_anchor_time(const struct ly_ctx *ctx, const char *ch_client_name, - const char *anchor_time, struct lyd_node **config); +int nc_server_config_new_ch_tls_del_ctn(const char *client_name, const char *endpt_name, + uint32_t id, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for the idle timeout parameter of the call-home periodic connection type. - * - * @param[in] ctx libyang context. - * @param[in] ch_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] idle_timeout Specifies the maximum number of seconds that a session may remain idle. - * @param 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_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_client_name, - uint16_t idle_timeout, struct lyd_node **config); -/** - * @brief Creates new YANG configuration data nodes for the call-home reconnect strategy. - * - * @param[in] ctx libyang context. - * @param[in] ch_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] start_with Specifies which endpoint to try if a connection is unsuccessful. Default value is NC_CH_FIRST_LISTED. - * @param[in] max_attempts The number of unsuccessful connection attempts before moving to the next endpoint. Default value is 3. - * @param[in] max_wait The number of seconds after which a connection to an endpoint is deemed unsuccessful. Default value if 5. - * @param 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_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char *ch_client_name, - NC_CH_START_WITH start_with, uint8_t max_attempts, uint16_t max_wait, struct lyd_node **config); +#endif /* NC_ENABLED_SSH_TLS */ #ifdef __cplusplus } diff --git a/tests/test_auth.c b/tests/test_auth.c index 461f6e30..e57405b8 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -321,16 +321,16 @@ setup_f(void **state) ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_pk", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); + ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "test_pk", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_interactive(ctx, "endpt", "test_int", "netconf.conf", BUILD_DIR "/tests", &tree); + ret = nc_server_config_new_ssh_user_interactive(ctx, "endpt", "test_int", "netconf.conf", BUILD_DIR "/tests", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_password(ctx, "endpt", "test_pw", "testpw", &tree); + ret = nc_server_config_new_ssh_user_password(ctx, "endpt", "test_pw", "testpw", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_none(ctx, "endpt", "test_none", &tree); + ret = nc_server_config_new_ssh_user_none(ctx, "endpt", "test_none", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_ch.c b/tests/test_ch.c index 5b5daab4..bad8fc62 100644 --- a/tests/test_ch.c +++ b/tests/test_ch.c @@ -77,7 +77,7 @@ server_thread_ssh(void *arg) struct nc_pollsession *ps; /* prepare data for deleting the call-home client */ - ret = nc_server_config_new_del_ch_client(ctx, "ch_ssh", &state->ssh_tree); + ret = nc_server_config_new_del_ch_client("ch_ssh", &state->ssh_tree); assert_int_equal(ret, 0); /* new poll session */ @@ -187,11 +187,11 @@ setup_ssh(void **state) assert_int_equal(ret, 0); /* set call-home server hostkey */ - ret = nc_server_config_new_ssh_ch_hostkey(ctx, "ch_ssh", "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &test_state->ssh_tree); + ret = nc_server_config_new_ch_ssh_hostkey(ctx, "ch_ssh", "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &test_state->ssh_tree); assert_int_equal(ret, 0); /* set call-home client's pubkey */ - ret = nc_server_config_new_ssh_ch_client_auth_pubkey(ctx, "ch_ssh", "endpt", "test_ch_ssh", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->ssh_tree); + ret = nc_server_config_new_ch_ssh_user_pubkey(ctx, "ch_ssh", "endpt", "test_ch_ssh", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->ssh_tree); assert_int_equal(ret, 0); /* configure the server based on the data */ @@ -255,7 +255,7 @@ server_thread_tls(void *arg) struct nc_pollsession *ps; /* prepare data for deleting the call-home client */ - ret = nc_server_config_new_del_ch_client(ctx, "ch_tls", &state->tls_tree); + ret = nc_server_config_new_del_ch_client("ch_tls", &state->tls_tree); assert_int_equal(ret, 0); /* new poll session */ diff --git a/tests/test_config_new.c b/tests/test_config_new.c index 7b71f0cf..c484c860 100644 --- a/tests/test_config_new.c +++ b/tests/test_config_new.c @@ -162,7 +162,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create the client authentication data, password only */ - ret = nc_server_config_new_ssh_client_auth_password(ctx, "endpt", "client", "testpassword123", &tree); + ret = nc_server_config_new_ssh_user_password(ctx, "endpt", "client", "testpassword123", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_ec.c b/tests/test_ec.c index 0365816d..669d93ce 100644 --- a/tests/test_ec.c +++ b/tests/test_ec.c @@ -219,13 +219,13 @@ setup_f(void **state) ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10009, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_ec256", "pubkey", TESTS_DIR "/data/id_ecdsa256.pub", &tree); + ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "test_ec256", "pubkey", TESTS_DIR "/data/id_ecdsa256.pub", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_ec384", "pubkey", TESTS_DIR "/data/id_ecdsa384.pub", &tree); + ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "test_ec384", "pubkey", TESTS_DIR "/data/id_ecdsa384.pub", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_ec521", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); + ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "test_ec521", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_ed25519.c b/tests/test_ed25519.c index 2767ede6..da6df765 100644 --- a/tests/test_ed25519.c +++ b/tests/test_ed25519.c @@ -156,7 +156,7 @@ setup_f(void **state) ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10009, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "test_ed25519", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); + ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "test_ed25519", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c index f0c2f754..a18210b6 100644 --- a/tests/test_endpt_share_clients.c +++ b/tests/test_endpt_share_clients.c @@ -199,7 +199,7 @@ setup_ssh(void **state) ret = nc_server_config_new_address_port(ctx, "SSH_endpt_1", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); - ret = nc_config_new_ssh_endpoint_client_reference(ctx, "SSH_endpt_1", "SSH_endpt_2", &tree); + ret = nc_config_new_ssh_endpoint_user_reference(ctx, "SSH_endpt_1", "SSH_endpt_2", &tree); assert_int_equal(ret, 0); /* create the second SSH endpoint with a single client */ @@ -209,7 +209,7 @@ setup_ssh(void **state) ret = nc_server_config_new_address_port(ctx, "SSH_endpt_2", NC_TI_LIBSSH, "127.0.0.1", 10006, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "SSH_endpt_2", "client", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); + ret = nc_server_config_new_ssh_user_pubkey(ctx, "SSH_endpt_2", "client", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the yang data */ diff --git a/tests/test_replace.c b/tests/test_replace.c index 2fba3bdb..ba09984d 100644 --- a/tests/test_replace.c +++ b/tests/test_replace.c @@ -239,7 +239,7 @@ setup_f(void **state) ret = nc_server_config_new_ssh_hostkey(ctx, "old", "old_key", TESTS_DIR "/data/key_rsa", NULL, &old_tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_password(ctx, "old", "old_client", "passwd", &old_tree); + ret = nc_server_config_new_ssh_user_password(ctx, "old", "old_client", "passwd", &old_tree); assert_int_equal(ret, 0); /* configure the server based on the yang data, treat them as if every node had replace operation */ @@ -252,7 +252,7 @@ setup_f(void **state) ret = nc_server_config_new_ssh_hostkey(ctx, "new", "new_key", TESTS_DIR "/data/key_rsa", NULL, &new_tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "new", "new_client", "pubkey", TESTS_DIR "/data/key_rsa.pub", &new_tree); + ret = nc_server_config_new_ssh_user_pubkey(ctx, "new", "new_client", "pubkey", TESTS_DIR "/data/key_rsa.pub", &new_tree); assert_int_equal(ret, 0); /* configure the server based on the yang data, meaning diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c index 801264d1..d5510147 100644 --- a/tests/test_two_channels.c +++ b/tests/test_two_channels.c @@ -160,10 +160,10 @@ setup_f(void **state) ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "client_1", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); + ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "client_1", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_client_auth_pubkey(ctx, "endpt", "client_2", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); + ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "client_2", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); assert_int_equal(ret, 0); ret = nc_server_config_setup_data(tree); From b23eb05e2cba8fd41d413df58f7eb54d26d4956e Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 14 Jul 2023 12:43:44 +0200 Subject: [PATCH 045/134] config UPDATE add more CH SSH & TLS APIs --- src/config_new_ssh.c | 803 +++++++++++++++++++++++++++++++------------ src/config_new_tls.c | 465 ++++++++++++++++++++----- src/server_config.h | 514 ++++++++++++++++++++++++--- 3 files changed, 1438 insertions(+), 344 deletions(-) diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index 266ffc74..d3c3d57e 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -34,8 +34,8 @@ extern pthread_mutex_t crypt_lock; #endif -API int -nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, +static int +_nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *tree_path, const char *privkey_path, const char *pubkey_path, struct lyd_node **config) { int ret = 0; @@ -44,8 +44,6 @@ nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_nam NC_PUBKEY_FORMAT pubkey_type; const char *privkey_format, *pubkey_format; - NC_CHECK_ARG_RET(NULL, privkey_path, config, ctx, endpt_name, hostkey_name, 1); - /* get the keys as a string from the given files */ ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); if (ret) { @@ -67,26 +65,22 @@ nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_nam goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "server-identity/host-key[name='%s']/public-key/inline-definition/public-key-format", endpt_name, hostkey_name); + ret = nc_config_new_create_append(ctx, tree_path, "public-key-format", pubkey_format, config); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "server-identity/host-key[name='%s']/public-key/inline-definition/public-key", endpt_name, hostkey_name); + ret = nc_config_new_create_append(ctx, tree_path, "public-key", pubkey, config); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "server-identity/host-key[name='%s']/public-key/inline-definition/private-key-format", endpt_name, hostkey_name); + ret = nc_config_new_create_append(ctx, tree_path, "private-key-format", privkey_format, config); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, privkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "server-identity/host-key[name='%s']/public-key/inline-definition/cleartext-private-key", endpt_name, hostkey_name); + ret = nc_config_new_create_append(ctx, tree_path, "cleartext-private-key", privkey, config); if (ret) { goto cleanup; } @@ -97,6 +91,64 @@ nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_nam return ret; } +API int +nc_server_config_new_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 ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, privkey_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key[name='%s']/public-key/inline-definition", endpt_name, hostkey_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_ssh_hostkey(ctx, path, privkey_path, pubkey_path, config); + if (ret) { + ERR(NULL, "Creating new hostkey YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_new_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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, privkey_path, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/inline-definition", client_name, endpt_name, hostkey_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_ssh_hostkey(ctx, path, privkey_path, pubkey_path, config); + if (ret) { + ERR(NULL, "Creating new Call-Home hostkey YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + API int nc_server_config_new_ssh_del_hostkey(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, struct lyd_node **config) @@ -112,16 +164,40 @@ nc_server_config_new_ssh_del_hostkey(const struct ly_ctx *ctx, const char *endpt } } +API int +nc_server_config_new_ch_ssh_del_hostkey(const char *client_name, const char *endpt_name, + const char *hostkey_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (hostkey_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']", client_name, endpt_name, hostkey_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key", client_name, endpt_name); + } +} + static int -nc_server_config_new_ssh_transport_params_prep(const struct ly_ctx *ctx, const char *endpt_name, - struct lyd_node *config, struct lyd_node **new_tree, struct lyd_node **alg_tree) +nc_server_config_new_ssh_transport_params_prep(const struct ly_ctx *ctx, const char *client_name, + const char *endpt_name, struct lyd_node *config, struct lyd_node **new_tree, struct lyd_node **alg_tree) { int ret = 0; char *tree_path = NULL; /* prepare path */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params", endpt_name); + if (client_name) { + /* ch */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/transport-params", client_name, endpt_name); + } else { + /* listen */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params", endpt_name); + } if (!tree_path) { ERRMEM; ret = 1; @@ -149,7 +225,7 @@ nc_server_config_new_ssh_transport_params_prep(const struct ly_ctx *ctx, const c } static int -nc_server_config_new_ssh_transport_params(const struct ly_ctx *ctx, NC_ALG_TYPE alg_type, int alg_count, va_list ap, +nc_server_config_new_ssh_transport_params_create(const struct ly_ctx *ctx, NC_ALG_TYPE alg_type, int alg_count, va_list ap, struct lyd_node *tree) { int i, ret = 0; @@ -212,19 +288,17 @@ nc_server_config_new_ssh_transport_params(const struct ly_ctx *ctx, NC_ALG_TYPE } cleanup: - va_end(ap); return ret; } -API int -nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) +static int +nc_server_config_new_ssh_transport_params(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + NC_ALG_TYPE alg_type, int alg_count, va_list ap, struct lyd_node **config) { int ret = 0; struct lyd_node *new_tree, *alg_tree; - va_list ap; - ret = nc_server_config_new_ssh_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + ret = nc_server_config_new_ssh_transport_params_prep(ctx, client_name, endpt_name, *config, &new_tree, &alg_tree); if (ret) { goto cleanup; } @@ -233,9 +307,7 @@ nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *end *config = new_tree; } - va_start(ap, alg_count); - - ret = nc_server_config_new_ssh_transport_params(ctx, NC_ALG_HOSTKEY, alg_count, ap, alg_tree); + ret = nc_server_config_new_ssh_transport_params_create(ctx, alg_type, alg_count, ap, alg_tree); if (ret) { goto cleanup; } @@ -249,6 +321,50 @@ nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *end return ret; } +API int +nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new hostkey algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_new_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new hostkey algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; +} + API int nc_server_config_new_ssh_del_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config) { @@ -265,35 +381,62 @@ nc_server_config_new_ssh_del_host_key_alg(const char *endpt_name, const char *al } API int -nc_server_config_ssh_new_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, +nc_server_config_new_ch_ssh_del_host_key_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key/" + "host-key-alg[.='iana-ssh-public-key-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key", client_name, endpt_name); + } +} + +API int +nc_server_config_new_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...) { int ret = 0; - struct lyd_node *new_tree, *alg_tree; va_list ap; - ret = nc_server_config_new_ssh_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); if (ret) { + ERR(NULL, "Creating new key exchange algorithms failed."); goto cleanup; } - if (!*config) { - *config = new_tree; - } +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_new_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); va_start(ap, alg_count); - ret = nc_server_config_new_ssh_transport_params(ctx, NC_ALG_KEY_EXCHANGE, alg_count, ap, alg_tree); + ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); if (ret) { + ERR(NULL, "Creating new key exchange algorithms failed."); goto cleanup; } - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; - } cleanup: + va_end(ap); return ret; } @@ -312,36 +455,63 @@ nc_server_config_new_ssh_del_key_exchange_alg(const char *endpt_name, const char } } +API int +nc_server_config_new_ch_ssh_del_key_exchange_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange/" + "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange", client_name, endpt_name); + } +} + API int nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...) { int ret = 0; - struct lyd_node *new_tree, *alg_tree; va_list ap; - ret = nc_server_config_new_ssh_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); if (ret) { + ERR(NULL, "Creating new encryption algorithms failed."); goto cleanup; } - if (!*config) { - *config = new_tree; - } +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_new_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); va_start(ap, alg_count); - ret = nc_server_config_new_ssh_transport_params(ctx, NC_ALG_ENCRYPTION, alg_count, ap, alg_tree); + ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); if (ret) { + ERR(NULL, "Creating new encryption algorithms failed."); goto cleanup; } - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; - } cleanup: + va_end(ap); return ret; } @@ -360,36 +530,63 @@ nc_server_config_new_ssh_del_encryption_alg(const char *endpt_name, const char * } } +API int +nc_server_config_new_ch_ssh_del_encryption_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption/" + "encryption-alg[.='iana-ssh-encryption-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption", client_name, endpt_name); + } +} + API int nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, int alg_count, ...) { int ret = 0; - struct lyd_node *new_tree, *alg_tree; va_list ap; - ret = nc_server_config_new_ssh_transport_params_prep(ctx, endpt_name, *config, &new_tree, &alg_tree); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_MAC, alg_count, ap, config); if (ret) { + ERR(NULL, "Creating new mac algorithms failed."); goto cleanup; } - if (!*config) { - *config = new_tree; - } +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_new_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); va_start(ap, alg_count); - ret = nc_server_config_new_ssh_transport_params(ctx, NC_ALG_MAC, alg_count, ap, alg_tree); + ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_MAC, alg_count, ap, config); if (ret) { + ERR(NULL, "Creating new mac algorithms failed."); goto cleanup; } - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; - } cleanup: + va_end(ap); return ret; } @@ -408,6 +605,22 @@ nc_server_config_new_ssh_del_mac_alg(const char *endpt_name, const char *alg, st } } +API int +nc_server_config_new_ch_ssh_del_mac_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac/" + "mac-alg[.='iana-ssh-mac-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac", client_name, endpt_name); + } +} + API int nc_server_config_new_ssh_del_user(const char *endpt_name, const char *user_name, struct lyd_node **config) @@ -424,8 +637,24 @@ nc_server_config_new_ssh_del_user(const char *endpt_name, } API int -nc_server_config_new_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) +nc_server_config_new_ch_ssh_del_user(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (user_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']", client_name, + endpt_name, user_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user", client_name, endpt_name); + } +} + +static int +_nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *tree_path, const char *pubkey_path, + struct lyd_node **config) { int ret = 0; char *pubkey = NULL; @@ -445,14 +674,12 @@ nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *endpt pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; } - ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/public-key-format", endpt_name, user_name, pubkey_name); + ret = nc_config_new_create_append(ctx, tree_path, "public-key-format", pubkey_format, config); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/public-key", endpt_name, user_name, pubkey_name); + ret = nc_config_new_create_append(ctx, tree_path, "public-key", pubkey, config); if (ret) { goto cleanup; } @@ -463,25 +690,105 @@ nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *endpt } API int -nc_server_config_new_ssh_del_user_pubkey(const char *endpt_name, const char *user_name, - const char *pubkey_name, struct lyd_node **config) +nc_server_config_new_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) { - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + int ret = 0; + char *path = NULL; - if (pubkey_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" - "public-key[name='%s']", endpt_name, user_name, pubkey_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" - "public-key", endpt_name, user_name); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pubkey_name, pubkey_path, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" + "public-key[name='%s']", endpt_name, user_name, pubkey_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_ssh_user_pubkey(ctx, path, pubkey_path, config); + if (ret) { + ERR(NULL, "Creating new user's public key failed."); + goto cleanup; } + +cleanup: + free(path); + return ret; } API int -nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, const char *password, struct lyd_node **config) +nc_server_config_new_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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pubkey_name, 1); + NC_CHECK_ARG_RET(NULL, pubkey_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, + endpt_name, user_name, pubkey_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_ssh_user_pubkey(ctx, path, pubkey_path, config); + if (ret) { + ERR(NULL, "Creating new user's public key failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_new_ssh_del_user_pubkey(const char *endpt_name, const char *user_name, + const char *pubkey_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + + if (pubkey_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" + "public-key[name='%s']", endpt_name, user_name, pubkey_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" + "public-key", endpt_name, user_name); + } +} + +API int +nc_server_config_new_ch_ssh_del_user_pubkey(const char *client_name, const char *endpt_name, + const char *user_name, const char *pubkey_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + + if (pubkey_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, + endpt_name, user_name, pubkey_name); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key", client_name, + endpt_name, user_name); + } +} + +static int +_nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *tree_path, + const char *password, struct lyd_node **config) { int ret = 0; char *hashed_pw = NULL; @@ -506,13 +813,70 @@ nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *end goto cleanup; } - ret = nc_config_new_create(ctx, config, hashed_pw, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/password", endpt_name, user_name); + ret = nc_config_new_create_append(ctx, tree_path, "password", hashed_pw, config); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *password, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, password, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/users/user[name='%s']", endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_ssh_user_password(ctx, path, password, config); if (ret) { + ERR(NULL, "Creating new user's public key failed."); goto cleanup; } cleanup: + free(path); + return ret; +} + +API int +nc_server_config_new_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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, password, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']", client_name, endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_ssh_user_password(ctx, path, password, config); + if (ret) { + ERR(NULL, "Creating new user's password failed."); + goto cleanup; + } + +cleanup: + free(path); return ret; } @@ -525,6 +889,17 @@ nc_server_config_new_ssh_del_user_password(const char *endpt_name, const char *u "ssh-server-parameters/client-authentication/users/user[name='%s']/password", endpt_name, user_name); } +API int +nc_server_config_new_ch_ssh_del_user_password(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/password", client_name, endpt_name, user_name); +} + API int nc_server_config_new_ssh_user_none(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, struct lyd_node **config) @@ -535,6 +910,17 @@ nc_server_config_new_ssh_user_none(const struct ly_ctx *ctx, const char *endpt_n "users/user[name='%s']/none", endpt_name, user_name); } +API int +nc_server_config_new_ch_ssh_user_none(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, config, 1); + + return nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/none", client_name, endpt_name, user_name); +} + API int nc_server_config_new_ssh_del_user_none(const char *endpt_name, const char *user_name, struct lyd_node **config) { @@ -545,22 +931,29 @@ nc_server_config_new_ssh_del_user_none(const char *endpt_name, const char *user_ } API int -nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) +nc_server_config_new_ch_ssh_del_user_none(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) { - int ret = 0; + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pam_config_name, config, 1); + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/none", client_name, endpt_name, user_name); +} - ret = nc_config_new_create(ctx, config, pam_config_name, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive/pam-config-file-name", endpt_name, user_name); +static int +_nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *tree_path, + const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) +{ + int ret = 0; + + ret = nc_config_new_create_append(ctx, tree_path, "pam-config-file-name", pam_config_name, config); if (ret) { goto cleanup; } if (pam_config_dir) { - ret = nc_config_new_create(ctx, config, pam_config_dir, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive/pam-config-file-dir", endpt_name, user_name); + ret = nc_config_new_create_append(ctx, tree_path, "pam-config-file-dir", pam_config_dir, config); if (ret) { goto cleanup; } @@ -571,178 +964,125 @@ nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char * } API int -nc_server_config_new_ssh_del_user_interactive(const char *endpt_name, const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/" - "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name); -} - -API int -nc_config_new_ssh_endpoint_user_reference(const struct ly_ctx *ctx, const char *endpt_name, - const char *referenced_endpt, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); - - return nc_config_new_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); -} - -API int -nc_config_new_ssh_del_endpoint_user_reference(const char *endpt_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); -} - -API int -nc_server_config_new_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) +nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) { int ret = 0; - char *pubkey = NULL, *privkey = NULL; - NC_PRIVKEY_FORMAT privkey_type; - NC_PUBKEY_FORMAT pubkey_type; - const char *privkey_format, *pubkey_format; - - NC_CHECK_ARG_RET(NULL, privkey_path, config, ctx, endpt_name, hostkey_name, 1); + char *path = NULL; - /* get the keys as a string from the given files */ - ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); - if (ret) { - ERR(NULL, "Getting keys from file(s) failed."); - goto cleanup; - } - - /* pubkey format to str */ - if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { - pubkey_format = "ietf-crypto-types:ssh-public-key-format"; - } else { - pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; - } + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pam_config_name, config, 1); - /* get privkey identityref value */ - privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type); - if (!privkey_format) { + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; ret = 1; goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/inline-definition/public-key-format", client_name, endpt_name, hostkey_name); + ret = _nc_server_config_new_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); if (ret) { + ERR(NULL, "Creating new user's keyboard interactive nodes failed."); goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/inline-definition/public-key", client_name, endpt_name, hostkey_name); - if (ret) { - goto cleanup; - } +cleanup: + free(path); + return ret; +} - ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/inline-definition/private-key-format", client_name, endpt_name, hostkey_name); - if (ret) { +API int +nc_server_config_new_ch_ssh_user_interactive(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pam_config_name, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; goto cleanup; } - ret = nc_config_new_create(ctx, config, privkey, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/inline-definition/cleartext-private-key", client_name, endpt_name, hostkey_name); + ret = _nc_server_config_new_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); if (ret) { + ERR(NULL, "Creating new user's keyboard interactive nodes failed."); goto cleanup; } cleanup: - free(privkey); - free(pubkey); + free(path); return ret; } API int -nc_server_config_new_ch_ssh_del_hostkey(const char *client_name, const char *endpt_name, - const char *hostkey_name, struct lyd_node **config) +nc_server_config_new_ssh_del_user_interactive(const char *endpt_name, const char *user_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - if (hostkey_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']", client_name, endpt_name, hostkey_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key", client_name, endpt_name); - } + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name); } API int -nc_server_config_new_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) +nc_server_config_new_ch_ssh_del_user_interactive(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) { - int ret = 0; - char *pubkey = NULL; - NC_PUBKEY_FORMAT pubkey_type; - const char *pubkey_format; + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - /* get pubkey data */ - ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_type); - if (ret) { - goto cleanup; - } + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name); +} - /* get pubkey format */ - if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { - pubkey_format = "ietf-crypto-types:ssh-public-key-format"; - } else { - pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; - } +API int +nc_config_new_ssh_endpoint_user_reference(const struct ly_ctx *ctx, const char *endpt_name, + const char *referenced_endpt, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); - ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/" - "public-key-format", client_name, endpt_name, user_name, pubkey_name); - if (ret) { - goto cleanup; - } + return nc_config_new_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); +} - ret = nc_config_new_create(ctx, config, pubkey, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']/" - "public-key", client_name, endpt_name, user_name, pubkey_name); - if (ret) { - goto cleanup; - } +API int +nc_config_new_ssh_del_endpoint_user_reference(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); -cleanup: - free(pubkey); - return ret; + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); } API int -nc_server_config_new_ch_ssh_del_user_pubkey(const char *client_name, const char *endpt_name, - const char *user_name, const char *pubkey_name, struct lyd_node **config) +nc_server_config_new_ch_ssh_keystore_reference(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) { - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, keystore_reference, 1); + NC_CHECK_ARG_RET(NULL, config, 1); - if (pubkey_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, - endpt_name, user_name, pubkey_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key", client_name, - endpt_name, user_name); - } + return nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); +} + +API int +nc_server_config_new_ch_ssh_del_keystore_reference(const char *client_name, const char *endpt_name, + const char *hostkey_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, hostkey_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); } API int @@ -778,6 +1118,18 @@ nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, const ch "truststore-reference", endpt_name, user_name); } +API int +nc_server_config_new_ch_ssh_truststore_reference(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) +{ + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, truststore_reference, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + return nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); +} + API int nc_server_config_new_ssh_del_truststore_reference(const char *endpt_name, const char *user_name, struct lyd_node **config) @@ -788,3 +1140,14 @@ nc_server_config_new_ssh_del_truststore_reference(const char *endpt_name, const "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" "truststore-reference", endpt_name, user_name); } + +API int +nc_server_config_new_ch_ssh_del_truststore_reference(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); +} diff --git a/src/config_new_tls.c b/src/config_new_tls.c index 988827b5..1ba72ddf 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -140,18 +140,18 @@ nc_server_config_new_tls_del_server_certificate(const char *endpt_name, struct l } API int -nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, const char *pubkey_path, const char *privkey_path, const char *certificate_path, struct lyd_node **config) { int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, endpt_name, privkey_path, certificate_path, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, privkey_path, certificate_path, 1); NC_CHECK_ARG_RET(NULL, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" - "certificate/inline-definition", ch_client_name, endpt_name) == -1) { + "certificate/inline-definition", client_name, endpt_name) == -1) { ERRMEM; path = NULL; ret = 1; @@ -171,14 +171,14 @@ nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const c } API int -nc_server_config_new_ch_tls_del_server_certificate(const char *ch_client_name, const char *endpt_name, +nc_server_config_new_ch_tls_del_server_certificate(const char *client_name, const char *endpt_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, ch_client_name, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" - "certificate/inline-definition", ch_client_name, endpt_name); + "certificate/inline-definition", client_name, endpt_name); } static int @@ -249,18 +249,18 @@ nc_server_config_new_tls_del_client_certificate(const char *endpt_name, const ch } API int -nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +nc_server_config_new_ch_tls_client_certificate(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) { int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, endpt_name, cert_name, cert_path, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, 1); NC_CHECK_ARG_RET(NULL, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" - "inline-definition/certificate[name='%s']", ch_client_name, endpt_name, cert_name) == -1) { + "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name) == -1) { ERRMEM; path = NULL; ret = 1; @@ -279,19 +279,19 @@ nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, const c } API int -nc_server_config_new_ch_tls_del_client_certificate(const char *ch_client_name, const char *endpt_name, +nc_server_config_new_ch_tls_del_client_certificate(const char *client_name, const char *endpt_name, const char *cert_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, ch_client_name, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); if (cert_name) { return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" - "inline-definition/certificate[name='%s']", ch_client_name, endpt_name, cert_name); + "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name); } else { return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" - "inline-definition/certificate", ch_client_name, endpt_name); + "inline-definition/certificate", client_name, endpt_name); } } @@ -340,18 +340,18 @@ nc_server_config_new_tls_del_client_ca(const char *endpt_name, const char *cert_ } API int -nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +nc_server_config_new_ch_tls_client_ca(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) { int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, endpt_name, cert_name, cert_path, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, 1); NC_CHECK_ARG_RET(NULL, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" - "inline-definition/certificate[name='%s']", ch_client_name, endpt_name, cert_name) == -1) { + "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name) == -1) { ERRMEM; path = NULL; ret = 1; @@ -370,19 +370,19 @@ nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char *ch_c } API int -nc_server_config_new_ch_tls_del_client_ca(const char *ch_client_name, const char *endpt_name, +nc_server_config_new_ch_tls_del_client_ca(const char *client_name, const char *endpt_name, const char *cert_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, ch_client_name, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); if (cert_name) { return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" - "inline-definition/certificate[name='%s']", ch_client_name, endpt_name, cert_name); + "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name); } else { return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" - "inline-definition/certificate", ch_client_name, endpt_name); + "inline-definition/certificate", client_name, endpt_name); } } @@ -488,17 +488,17 @@ nc_server_config_new_tls_del_ctn(const char *endpt_name, uint32_t id, struct lyd } API int -nc_server_config_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *ch_client_name, const char *endpt_name, +nc_server_config_new_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) { int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ch_client_name, endpt_name, id, name, config, 1); + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, id, name, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" - "cert-to-name[id='%u']", ch_client_name, endpt_name, id) == -1) { + "cert-to-name[id='%u']", client_name, endpt_name, id) == -1) { ERRMEM; path = NULL; ret = 1; @@ -517,19 +517,19 @@ nc_server_config_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *ch_client_ } API int -nc_server_config_new_ch_tls_del_ctn(const char *ch_client_name, const char *endpt_name, +nc_server_config_new_ch_tls_del_ctn(const char *client_name, const char *endpt_name, uint32_t id, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, ch_client_name, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); if (id) { return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" - "cert-to-name[id='%u']", ch_client_name, endpt_name, id); + "cert-to-name[id='%u']", client_name, endpt_name, id); } else { return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" - "cert-to-name", ch_client_name, endpt_name); + "cert-to-name", client_name, endpt_name); } } @@ -568,6 +568,37 @@ nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt_nam ret = nc_config_new_create(ctx, config, version, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" "hello-params/tls-versions/tls-version", endpt_name); + if (ret) { + ERR(NULL, "Creating new YANG data nodes for TLS version failed."); + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_new_ch_tls_version(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config) +{ + int ret = 0; + const char *version; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); + + version = nc_config_new_tls_tlsversion2str(tls_version); + if (!version) { + ret = 1; + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, version, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "hello-params/tls-versions/tls-version", client_name, endpt_name); + if (ret) { + ERR(NULL, "Creating new YANG data nodes for Call-Home TLS version failed."); + goto cleanup; + } cleanup: return ret; @@ -595,30 +626,39 @@ nc_server_config_new_tls_del_version(const char *endpt_name, NC_TLS_VERSION tls_ } API int -nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int cipher_count, ...) +nc_server_config_new_ch_tls_del_version(const char *client_name, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config) { int ret = 0; - struct lyd_node *old = NULL; - va_list ap; - char *cipher = NULL, *cipher_ident = NULL, *old_path = NULL; - int i; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + const char *version; - va_start(ap, cipher_count); + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - ret = asprintf(&old_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/hello-params/cipher-suites", endpt_name); - if (ret == -1) { - ERRMEM; - old_path = NULL; + version = nc_config_new_tls_tlsversion2str(tls_version); + if (!version) { + ret = 1; goto cleanup; } + ret = nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/" + "tls-server-parameters/hello-params/tls-versions/tls-version[.='%s']", client_name, endpt_name, version); + +cleanup: + return ret; +} + +static int +_nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *tree_path, + int cipher_count, va_list ap, struct lyd_node **config) +{ + int ret = 0, i; + struct lyd_node *old = NULL; + char *cipher = NULL, *cipher_ident = NULL; + /* delete all older algorithms (if any) se they can be replaced by the new ones */ - ret = lyd_find_path(*config, old_path, 0, &old); - if (!ret) { + lyd_find_path(*config, tree_path, 0, &old); + if (old) { lyd_free_tree(old); } @@ -632,8 +672,7 @@ nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_nam goto cleanup; } - ret = nc_config_new_create(ctx, config, cipher_ident, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/hello-params/cipher-suites/cipher-suite", endpt_name); + ret = nc_config_new_create_append(ctx, tree_path, "cipher-suite", cipher_ident, config); if (ret) { goto cleanup; } @@ -642,9 +681,69 @@ nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_nam cipher_ident = NULL; } +cleanup: + return ret; +} + +API int +nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int cipher_count, ...) +{ + int ret = 0; + va_list ap; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cipher_count, config, 1); + + va_start(ap, cipher_count); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/hello-params/cipher-suites", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_ciphers(ctx, path, cipher_count, ap, config); + if (ret) { + ERR(NULL, "Creating new TLS cipher YANG data nodes failed."); + } + cleanup: va_end(ap); - free(old_path); + free(path); + return ret; +} + +API int +nc_server_config_new_ch_tls_ciphers(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int cipher_count, ...) +{ + int ret = 0; + va_list ap; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cipher_count, config, 1); + + va_start(ap, cipher_count); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/tls/tls-server-parameters/hello-params/cipher-suites", client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_ciphers(ctx, path, cipher_count, ap, config); + if (ret) { + ERR(NULL, "Creating new Call-Home TLS cipher YANG data nodes failed."); + } + +cleanup: + va_end(ap); + free(path); return ret; } @@ -659,30 +758,32 @@ nc_server_config_new_tls_del_cipher(const char *endpt_name, const char *cipher, } API int -nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, const char *path, struct lyd_node **config) +nc_server_config_new_ch_tls_del_cipher(const char *client_name, const char *endpt_name, + const char *cipher, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, cipher, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/hello-params/cipher-suites/" + "cipher-suite[.='iana-tls-cipher-suite-algs:%s']", client_name, endpt_name, cipher); +} + +static int +_nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *tree_path, + const char *crl_path, struct lyd_node **config) { int ret = 0; struct lyd_node *node = NULL; char *url_path = NULL, *ext_path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, path, config, 1); - - ret = nc_config_new_create(ctx, config, path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-path", endpt_name); - if (ret) { - goto cleanup; - } - - if (asprintf(&url_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-url", endpt_name) == -1) { + if (asprintf(&url_path, "%s/libnetconf2-netconf-server:crl-url", tree_path) == -1) { ERRMEM; url_path = NULL; ret = 1; goto cleanup; } - if (asprintf(&ext_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-cert-ext", endpt_name) == -1) { + if (asprintf(&ext_path, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path) == -1) { ERRMEM; ext_path = NULL; ret = 1; @@ -698,8 +799,12 @@ nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_na if (!ret) { lyd_free_tree(node); } - /* don't care about the return values from lyd_find_path */ - ret = 0; + + /* create the crl path node */ + ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-path", crl_path, config); + if (ret) { + goto cleanup; + } cleanup: free(url_path); @@ -708,30 +813,78 @@ nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_na } API int -nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *url, struct lyd_node **config) +nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, + const char *crl_path, struct lyd_node **config) { int ret = 0; - struct lyd_node *node = NULL; - char *crl_path = NULL, *ext_path = NULL; + char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, url, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, crl_path, config, 1); - ret = nc_config_new_create(ctx, config, url, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-url", endpt_name); + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_crl_path(ctx, path, crl_path, config); if (ret) { + ERR(NULL, "Creating new CRL YANG data nodes failed."); goto cleanup; } - if (asprintf(&crl_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-path", endpt_name) == -1) { +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_new_ch_tls_crl_path(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *crl_path, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, crl_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_crl_path(ctx, path, crl_path, config); + if (ret) { + ERR(NULL, "Creating new Call-Home CRL YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +static int +_nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *tree_path, + const char *crl_url, struct lyd_node **config) +{ + int ret = 0; + struct lyd_node *node = NULL; + char *crl_path = NULL, *ext_path = NULL; + + if (asprintf(&crl_path, "%s/libnetconf2-netconf-server:crl-path", tree_path) == -1) { ERRMEM; crl_path = NULL; ret = 1; goto cleanup; } - if (asprintf(&ext_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-cert-ext", endpt_name) == -1) { + if (asprintf(&ext_path, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path) == -1) { ERRMEM; ext_path = NULL; ret = 1; @@ -747,8 +900,12 @@ nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_nam if (!ret) { lyd_free_tree(node); } - /* don't care about the return values from lyd_find_path */ - ret = 0; + + /* create the crl path node */ + ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-url", crl_url, config); + if (ret) { + goto cleanup; + } cleanup: free(crl_path); @@ -757,28 +914,76 @@ nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_nam } API int -nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config) +nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *crl_url, struct lyd_node **config) { int ret = 0; - struct lyd_node *node = NULL; - char *crl_path = NULL, *url_path = NULL; + char *path = NULL; - ret = nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-cert-ext", endpt_name); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, crl_url, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_crl_url(ctx, path, crl_url, config); if (ret) { + ERR(NULL, "Creating new CRL YANG data nodes failed."); goto cleanup; } - if (asprintf(&crl_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-path", endpt_name) == -1) { +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_new_ch_tls_crl_url(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *crl_url, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, crl_url, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_crl_url(ctx, path, crl_url, config); + if (ret) { + ERR(NULL, "Creating new Call-Home CRL YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +static int +_nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *tree_path, struct lyd_node **config) +{ + int ret = 0; + struct lyd_node *node = NULL; + char *crl_path = NULL, *url_path = NULL; + + if (asprintf(&crl_path, "%s/libnetconf2-netconf-server:crl-path", tree_path) == -1) { ERRMEM; crl_path = NULL; ret = 1; goto cleanup; } - if (asprintf(&url_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-url", endpt_name) == -1) { + if (asprintf(&url_path, "%s/libnetconf2-netconf-server:crl-url", tree_path) == -1) { ERRMEM; url_path = NULL; ret = 1; @@ -794,8 +999,12 @@ nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endp if (!ret) { lyd_free_tree(node); } - /* don't care about the return values from lyd_find_path */ - ret = 0; + + /* create the crl path node */ + ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-cert-ext", NULL, config); + if (ret) { + goto cleanup; + } cleanup: free(crl_path); @@ -803,6 +1012,62 @@ nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endp return ret; } +API int +nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_crl_cert_ext(ctx, path, config); + if (ret) { + ERR(NULL, "Creating new CRL YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_new_ch_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_crl_cert_ext(ctx, path, config); + if (ret) { + ERR(NULL, "Creating new Call-Home CRL YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + API int nc_server_config_new_tls_del_crl(const char *endpt_name, struct lyd_node **config) { @@ -832,6 +1097,38 @@ nc_server_config_new_tls_del_crl(const char *endpt_name, struct lyd_node **confi return ret; } +API int +nc_server_config_new_ch_tls_del_crl(const char *client_name, const char *endpt_name, struct lyd_node **config) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-path", client_name, endpt_name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-url", client_name, endpt_name); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-cert-ext", client_name, endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + API int nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config) { diff --git a/src/server_config.h b/src/server_config.h index c5399146..2687a4fa 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -274,7 +274,7 @@ int nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *e * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ssh_del_user_pubkey(const char *endpt_name, const char *user_name, @@ -301,7 +301,7 @@ int nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char * * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ssh_del_user_password(const char *endpt_name, const char *user_name, @@ -327,7 +327,7 @@ int nc_server_config_new_ssh_user_none(const struct ly_ctx *ctx, const char *end * * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ssh_del_user_none(const char *endpt_name, const char *user_name, @@ -357,7 +357,7 @@ int nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const ch * * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ssh_del_user_interactive(const char *endpt_name, const char *user_name, @@ -369,7 +369,7 @@ int nc_server_config_new_ssh_del_user_interactive(const char *endpt_name, const * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ssh_del_user(const char *endpt_name, @@ -398,7 +398,7 @@ int nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, cons * * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ssh_del_truststore_reference(const char *endpt_name, const char *user_name, @@ -426,7 +426,7 @@ int nc_config_new_ssh_endpoint_user_reference(const struct ly_ctx *ctx, const ch * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_config_new_ssh_del_endpoint_user_reference(const char *endpt_name, struct lyd_node **config); @@ -580,7 +580,7 @@ int nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const * @brief Deletes the server's certificate from the YANG data. * * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in,out] config Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_tls_del_server_certificate(const char *endpt_name, struct lyd_node **config); @@ -607,7 +607,7 @@ int nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_tls_del_client_certificate(const char *endpt_name, const char *cert_name, struct lyd_node **config); @@ -634,7 +634,7 @@ int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *end * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_tls_del_client_ca(const char *endpt_name, const char *cert_name, struct lyd_node **config); @@ -663,7 +663,7 @@ int nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_nam * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_tls_del_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config); @@ -689,7 +689,7 @@ int nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt * * @param[in] endpt_name Identifier of an existing endpoint. * @param[in] tls_version TLS version to be deleted. - * @param[in,out] config Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_tls_del_version(const char *endpt_name, NC_TLS_VERSION tls_version, struct lyd_node **config); @@ -718,7 +718,7 @@ int nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt * * @param[in] endpt_name Identifier of an existing endpoint. * @param[in] cipher TLS cipher to be deleted. - * @param[in,out] config Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_tls_del_cipher(const char *endpt_name, const char *cipher, struct lyd_node **config); @@ -732,12 +732,13 @@ int nc_server_config_new_tls_del_cipher(const char *endpt_name, const char *ciph * @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] path Path to a DER/PEM encoded CRL file. + * @param[in] crl_path Path to a DER/PEM encoded CRL 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_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, const char *path, struct lyd_node **config); +int nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, + const char *crl_path, struct lyd_node **config); /** * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via an URL. @@ -748,19 +749,20 @@ int nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endp * @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] url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. + * @param[in] crl_url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. * The allowed protocols are all the protocols supported by CURL. * @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_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *url, struct lyd_node **config); +int nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *crl_url, struct lyd_node **config); /** * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via certificate extensions. * * The chain of configured Certificate Authorities will be examined. For each certificate in this chain all the * CRLs from the URLs specified in their extension fields CRL Distribution Points will be downloaded and used. + * * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling * this function will remove any CRL YANG nodes created by the other two functions. * @@ -777,7 +779,7 @@ int nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char * * @brief Deletes all the CRL nodes from the YANG data. * * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in,out] config Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_tls_del_crl(const char *endpt_name, struct lyd_node **config); @@ -804,7 +806,7 @@ int nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_config_new_tls_del_endpoint_client_reference(const char *endpt_name, struct lyd_node **config); @@ -846,7 +848,7 @@ int nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *c * * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_del_ch_client(const char *client_name, struct lyd_node **config); @@ -857,7 +859,7 @@ int nc_server_config_new_del_ch_client(const char *client_name, struct lyd_node * @param[in] client_name Identifier of an existing Call-Home client. * @param[in] endpt_name Optional identifier of a CH endpoint to be deleted. * If NULL, all of the CH endpoints which belong to the given client will be deleted. - * @param[in,out] config Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt_name, struct lyd_node **config); @@ -898,7 +900,7 @@ int nc_server_config_new_ch_period(const struct ly_ctx *ctx, const char *client_ * This behaves the same as setting the period to 60 minutes, which is the default value of this node. * * @param[in] client_name Identifier of an existing Call-Home client. - * @param[in,out] config Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_del_period(const char *client_name, struct lyd_node **config); @@ -923,7 +925,7 @@ int nc_server_config_new_ch_anchor_time(const struct ly_ctx *ctx, const char *cl * @brief Deletes the Call-Home anchor time parameter of the periodic connection type from the YANG data. * * @param[in] client_name Identifier of an existing Call-Home client. - * @param[in,out] config Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_del_anchor_time(const char *client_name, struct lyd_node **config); @@ -950,7 +952,7 @@ int nc_server_config_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *c * This behaves the same as setting the timeout to 180 seconds, which is the default value of this node. * * @param[in] client_name Identifier of an existing Call-Home client. - * @param[in,out] config Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_del_idle_timeout(const char *client_name, struct lyd_node **config); @@ -977,7 +979,7 @@ int nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const c * The default values are: start-with = NC_CH_FIRST_LISTED, max-wait = 5 and max-attempts = 3. * * @param[in] client_name Identifier of an existing Call-Home client. - * @param[in,out] config Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_del_reconnect_strategy(const char *client_name, struct lyd_node **config); @@ -1021,17 +1023,49 @@ int nc_server_config_new_ch_ssh_hostkey(const struct ly_ctx *ctx, const char *cl * @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 which belongs to the given CH 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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_ssh_del_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 call-home client's public key. + * @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 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_new_ch_ssh_keystore_reference(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 config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_ssh_del_keystore_reference(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. @@ -1051,19 +1085,287 @@ int nc_server_config_new_ch_ssh_user_pubkey(const struct ly_ctx *ctx, const char 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. + * @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 which belongs to the given CH client. - * @param[in] user_name Identifier of an existing SSH user which belongs to the given CH endpoint. + * @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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_ssh_del_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 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 Cleartext password to be set for the user. + * @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_new_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_new_ch_ssh_del_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 none 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 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_new_ch_ssh_user_none(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 none authentication 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 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_new_ch_ssh_del_user_none(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. + * + * @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] pam_config_name Name of the PAM configuration file. + * @param[in] pam_config_name Optional. The absolute path to the directory in which the configuration file + * with the name conf_name is located. A newer version (>= 1.4) of PAM library is required to be able to specify + * the path. If NULL is passed, then the PAM's system directories will be searched (usually /etc/pam.d/). + * @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_new_ch_ssh_user_interactive(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *user_name, const char *pam_config_name, const char *pam_config_dir, 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_new_ch_ssh_del_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_new_ch_ssh_del_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 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_new_ch_ssh_truststore_reference(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_new_ch_ssh_del_truststore_reference(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for Call-Home host-key algorithms replacing any previous ones. + * + * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, + * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. + * + * @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 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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); + +/** + * @brief Deletes a Call-Home hostkey algorithm 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] alg Optional algorithm to be deleted. + * If NULL, all of the hostkey algorithms on this endpoint will be deleted. + * @param config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_ssh_del_host_key_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for Call-Home key exchange algorithms replacing any previous ones. + * + * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, + * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, + * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. + * + * @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 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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); + +/** + * @brief Deletes a Call-Home key exchange algorithm 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] alg Optional algorithm to be deleted. + * If NULL, all of the key exchange algorithms on this endpoint will be deleted. + * @param config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_ssh_del_key_exchange_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for Call-Home encryption algorithms replacing any previous ones. + * + * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc + * triple-des-cbc and none. + * + * @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 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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); + +/** + * @brief Deletes a Call-Home encryption algorithm 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] alg Optional algorithm to be deleted. + * If NULL, all of the encryption algorithms on this endpoint will be deleted. + * @param config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_ssh_del_encryption_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for Call-Home mac algorithms replacing any previous ones. + * + * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. + * + * @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 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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of mac algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); + +/** + * @brief Deletes a Call-Home mac algorithm 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] alg Optional algorithm to be deleted. + * If NULL, all of the mac algorithms on this endpoint will be deleted. + * @param config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_ssh_del_mac_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config); + /** * @} */ @@ -1099,8 +1401,8 @@ int nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, con * @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 which belongs to the given client. - * @param[in,out] config Configuration YANG data. + * @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. */ int nc_server_config_new_ch_tls_del_server_certificate(const char *client_name, const char *endpt_name, @@ -1128,10 +1430,10 @@ int nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, con * @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 which belongs to the given 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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_tls_del_client_certificate(const char *client_name, const char *endpt_name, @@ -1159,10 +1461,10 @@ int nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char * * @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 which belongs to the given 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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_tls_del_client_ca(const char *client_name, const char *endpt_name, @@ -1192,15 +1494,147 @@ int nc_server_config_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *client * @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 which belongs to the given 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 Configuration YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_tls_del_ctn(const char *client_name, const char *endpt_name, uint32_t id, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes for a Call-Home TLS version. + * + * @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] tls_version TLS version to be used. Call this multiple times to set the accepted versions + * of the TLS protocol and let the client and server negotiate the given version. + * @param 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_new_ch_tls_version(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config); + +/** + * @brief Deletes a TLS version 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] tls_version TLS version to be deleted. + * @param config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_tls_del_version(const char *client_name, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call-Home TLS cipher. + * + * @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 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[in] cipher_count Number of following ciphers. + * @param[in] ... TLS ciphers. These ciphers MUST be in the format as listed in the + * iana-tls-cipher-suite-algs YANG model (lowercase and separated by dashes). Regardless + * of the TLS protocol version used, all of these ciphers will be tried and some of them + * might not be set (TLS handshake might fail then). For the list of supported ciphers see + * the OpenSSL documentation. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_tls_ciphers(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int cipher_count, ...); + +/** + * @brief Deletes a Call-Home TLS cipher 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] cipher TLS cipher to be deleted. + * @param config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_tls_del_cipher(const char *client_name, const char *endpt_name, + const char *cipher, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call-Home Certificate Revocation List via a local file. + * + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @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] crl_path Path to a DER/PEM encoded CRL file. + * @param 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_new_ch_tls_crl_path(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *crl_path, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call-Home Certificate Revocation List via an URL. + * + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @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] crl_url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. + * The allowed protocols are all the protocols supported by CURL. + * @param 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_new_ch_tls_crl_url(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *crl_url, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call-Home Certificate Revocation List via certificate extensions. + * + * The chain of configured Certificate Authorities will be examined. For each certificate in this chain all the + * CRLs from the URLs specified in their extension fields CRL Distribution Points will be downloaded and used. + * + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @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 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_new_ch_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config); + +/** + * @brief Deletes all the CRL nodes 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 config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_ch_tls_del_crl(const char *client_name, const char *endpt_name, struct lyd_node **config); + /** * @} */ From e24ad0b594a88ca3c801b69ac90a6665fd49be43 Mon Sep 17 00:00:00 2001 From: roman Date: Tue, 18 Jul 2023 09:06:58 +0200 Subject: [PATCH 046/134] config BUGFIX node name possible segfault --- src/server_config.c | 155 +++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 82 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index f9b48eb1..53b1f28b 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -138,9 +138,10 @@ static int nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind) { uint16_t i; - const char *endpt_name; + const char *name; assert(node && endpt); + name = LYD_NAME(node); while (node) { if (!strcmp(LYD_NAME(node), "endpoint")) { @@ -150,16 +151,16 @@ nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in an endpoint subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in an endpoint subtree.", name); return 1; } node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); - endpt_name = lyd_get_value(node); + name = lyd_get_value(node); for (i = 0; i < server_opts.endpt_count; i++) { - if (!strcmp(server_opts.endpts[i].name, endpt_name)) { + if (!strcmp(server_opts.endpts[i].name, name)) { *endpt = &server_opts.endpts[i]; if (bind) { *bind = &server_opts.binds[i]; @@ -168,7 +169,7 @@ nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, } } - ERR(NULL, "Endpoint \"%s\" was not found.", endpt_name); + ERR(NULL, "Endpoint \"%s\" was not found.", name); return 1; } @@ -176,9 +177,10 @@ static int nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client **ch_client) { uint16_t i; - const char *ch_client_name; + const char *name; assert(node && ch_client); + name = LYD_NAME(node); while (node) { if (!strcmp(LYD_NAME(node), "netconf-client")) { @@ -188,22 +190,28 @@ nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a netconf-client subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a netconf-client subtree.", name); return 1; } node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); - ch_client_name = lyd_get_value(node); + name = lyd_get_value(node); + /* LOCK */ + pthread_rwlock_rdlock(&server_opts.ch_client_lock); for (i = 0; i < server_opts.ch_client_count; i++) { - if (!strcmp(server_opts.ch_clients[i].name, ch_client_name)) { + if (!strcmp(server_opts.ch_clients[i].name, name)) { *ch_client = &server_opts.ch_clients[i]; + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_client_lock); return 0; } } - ERR(NULL, "Call-home client \"%s\" was not found.", ch_client_name); + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_client_lock); + ERR(NULL, "Call-home client \"%s\" was not found.", name); return 1; } @@ -213,10 +221,11 @@ static int nc_server_config_get_ch_endpt(const struct lyd_node *node, struct nc_ch_endpt **ch_endpt) { uint16_t i; - const char *ch_endpt_name; + const char *name; struct nc_ch_client *ch_client; assert(node && ch_endpt); + name = LYD_NAME(node); if (nc_server_config_get_ch_client(node, &ch_client)) { return 1; @@ -230,22 +239,22 @@ nc_server_config_get_ch_endpt(const struct lyd_node *node, struct nc_ch_endpt ** } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a call-home endpoint subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a call-home endpoint subtree.", name); return 1; } node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); - ch_endpt_name = lyd_get_value(node); + name = lyd_get_value(node); for (i = 0; i < ch_client->ch_endpt_count; i++) { - if (!strcmp(ch_client->ch_endpts[i].name, ch_endpt_name)) { + if (!strcmp(ch_client->ch_endpts[i].name, name)) { *ch_endpt = &ch_client->ch_endpts[i]; return 0; } } - ERR(NULL, "Call-home client's \"%s\" endpoint \"%s\" was not found.", ch_client->name, ch_endpt_name); + ERR(NULL, "Call-home client's \"%s\" endpoint \"%s\" was not found.", ch_client->name, name); return 1; } @@ -276,24 +285,11 @@ static int nc_server_config_get_hostkey(const struct lyd_node *node, struct nc_hostkey **hostkey) { uint16_t i; - const char *hostkey_name; - struct nc_endpt *endpt; - struct nc_ch_endpt *ch_endpt; + const char *name; struct nc_server_ssh_opts *opts; assert(node && hostkey); - - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - return 1; - } - opts = endpt->opts.ssh; - } else { - if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { - return 1; - } - opts = ch_endpt->opts.ssh; - } + name = LYD_NAME(node); while (node) { if (!strcmp(LYD_NAME(node), "host-key")) { @@ -303,22 +299,25 @@ nc_server_config_get_hostkey(const struct lyd_node *node, struct nc_hostkey **ho } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a host-key subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a host-key subtree.", name); return 1; } node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); - hostkey_name = lyd_get_value(node); + name = lyd_get_value(node); + if (nc_server_config_get_ssh_opts(node, &opts)) { + return 1; + } for (i = 0; i < opts->hostkey_count; i++) { - if (!strcmp(opts->hostkeys[i].name, hostkey_name)) { + if (!strcmp(opts->hostkeys[i].name, name)) { *hostkey = &opts->hostkeys[i]; return 0; } } - ERR(NULL, "Host-key \"%s\" was not found.", hostkey_name); + ERR(NULL, "Host-key \"%s\" was not found.", name); return 1; } @@ -326,24 +325,11 @@ static int nc_server_config_get_auth_client(const struct lyd_node *node, struct nc_client_auth **auth_client) { uint16_t i; - const char *authkey_name; - struct nc_endpt *endpt; - struct nc_ch_endpt *ch_endpt; + const char *name; struct nc_server_ssh_opts *opts; assert(node && auth_client); - - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - return 1; - } - opts = endpt->opts.ssh; - } else { - if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { - return 1; - } - opts = ch_endpt->opts.ssh; - } + name = LYD_NAME(node); while (node) { if (!strcmp(LYD_NAME(node), "user")) { @@ -353,22 +339,25 @@ nc_server_config_get_auth_client(const struct lyd_node *node, struct nc_client_a } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a client-authentication subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a client-authentication subtree.", name); return 1; } node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); - authkey_name = lyd_get_value(node); + name = lyd_get_value(node); + if (nc_server_config_get_ssh_opts(node, &opts)) { + return 1; + } for (i = 0; i < opts->client_count; i++) { - if (!strcmp(opts->auth_clients[i].username, authkey_name)) { + if (!strcmp(opts->auth_clients[i].username, name)) { *auth_client = &opts->auth_clients[i]; return 0; } } - ERR(NULL, "Authorized key \"%s\" was not found.", authkey_name); + ERR(NULL, "Authorized key \"%s\" was not found.", name); return 1; } @@ -376,14 +365,11 @@ static int nc_server_config_get_pubkey(const struct lyd_node *node, struct nc_public_key **pubkey) { uint16_t i; - const char *pubkey_name; + const char *name; struct nc_client_auth *auth_client; assert(node && pubkey); - - if (nc_server_config_get_auth_client(node, &auth_client)) { - return 1; - } + name = LYD_NAME(node); node = lyd_parent(node); while (node) { @@ -394,22 +380,25 @@ nc_server_config_get_pubkey(const struct lyd_node *node, struct nc_public_key ** } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", name); return 1; } node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); - pubkey_name = lyd_get_value(node); + name = lyd_get_value(node); + if (nc_server_config_get_auth_client(node, &auth_client)) { + return 1; + } for (i = 0; i < auth_client->pubkey_count; i++) { - if (!strcmp(auth_client->pubkeys[i].name, pubkey_name)) { + if (!strcmp(auth_client->pubkeys[i].name, name)) { *pubkey = &auth_client->pubkeys[i]; return 0; } } - ERR(NULL, "Public key \"%s\" was not found.", pubkey_name); + ERR(NULL, "Public key \"%s\" was not found.", name); return 1; } @@ -440,21 +429,12 @@ static int nc_server_config_get_cert(const struct lyd_node *node, int is_ee, struct nc_certificate **cert) { uint16_t i; - const char *cert_name; + const char *name; struct nc_cert_grouping *auth_client; struct nc_server_tls_opts *opts; assert(node && cert); - - if (nc_server_config_get_tls_opts(node, &opts)) { - return 1; - } - - if (is_ee) { - auth_client = &opts->ee_certs; - } else { - auth_client = &opts->ca_certs; - } + name = LYD_NAME(node); while (node) { if (!strcmp(LYD_NAME(node), "certificate")) { @@ -464,22 +444,31 @@ nc_server_config_get_cert(const struct lyd_node *node, int is_ee, struct nc_cert } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", name); return 1; } node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); - cert_name = lyd_get_value(node); + name = lyd_get_value(node); + + if (nc_server_config_get_tls_opts(node, &opts)) { + return 1; + } + if (is_ee) { + auth_client = &opts->ee_certs; + } else { + auth_client = &opts->ca_certs; + } for (i = 0; i < auth_client->cert_count; i++) { - if (!strcmp(auth_client->certs[i].name, cert_name)) { + if (!strcmp(auth_client->certs[i].name, name)) { *cert = &auth_client->certs[i]; return 0; } } - ERR(NULL, "Certificate \"%s\" was not found.", cert_name); + ERR(NULL, "Certificate \"%s\" was not found.", name); return 1; } @@ -489,12 +478,10 @@ nc_server_config_get_ctn(const struct lyd_node *node, struct nc_ctn **ctn) uint32_t id; struct nc_ctn *iter; struct nc_server_tls_opts *opts; + const char *name; assert(node && ctn); - - if (nc_server_config_get_tls_opts(node, &opts)) { - return 1; - } + name = LYD_NAME(node); node = lyd_parent(node); while (node) { @@ -505,7 +492,7 @@ nc_server_config_get_ctn(const struct lyd_node *node, struct nc_ctn **ctn) } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a cert-to-name subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a cert-to-name subtree.", name); return 1; } @@ -513,6 +500,10 @@ nc_server_config_get_ctn(const struct lyd_node *node, struct nc_ctn **ctn) assert(!strcmp(LYD_NAME(node), "id")); id = strtoul(lyd_get_value(node), NULL, 10); + if (nc_server_config_get_tls_opts(node, &opts)) { + return 1; + } + iter = opts->ctn; while (iter) { if (iter->id == id) { From d9b30ed3608ab371b1cfcff146bc46c3c79d263c Mon Sep 17 00:00:00 2001 From: roman Date: Tue, 18 Jul 2023 14:36:48 +0200 Subject: [PATCH 047/134] config UPDATE Call Home synchronization Add getting locks when accessing CH client members. Change CH thread sleep to condition variable and waiting for a signal. --- src/server_config.c | 528 +++++++++++++++++++++++++++++++++++++++++--- src/session_p.h | 28 ++- tests/test_ch.c | 25 ++- 3 files changed, 541 insertions(+), 40 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 53b1f28b..ef36b735 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -537,6 +537,55 @@ nc_server_config_get_private_key_type(const char *format) #endif /* NC_ENABLED_SSH_TLS */ +static int +nc_server_config_get_ch_client_with_lock(const struct lyd_node *node, struct nc_ch_client **ch_client) +{ + uint16_t i; + const char *name; + + assert(node && ch_client); + name = LYD_NAME(node); + + while (node) { + if (!strcmp(LYD_NAME(node), "netconf-client")) { + break; + } + node = lyd_parent(node); + } + + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in a netconf-client subtree.", name); + return 1; + } + + node = lyd_child(node); + assert(!strcmp(LYD_NAME(node), "name")); + name = lyd_get_value(node); + + /* LOCK */ + pthread_rwlock_rdlock(&server_opts.ch_client_lock); + for (i = 0; i < server_opts.ch_client_count; i++) { + if (!strcmp(server_opts.ch_clients[i].name, name)) { + /* LOCK */ + pthread_mutex_lock(&server_opts.ch_clients[i].lock); + *ch_client = &server_opts.ch_clients[i]; + return 0; + } + } + + ERR(NULL, "Call-home client \"%s\" was not found.", name); + return 1; +} + +static void +nc_ch_client_unlock(struct nc_ch_client *client) +{ + assert(client); + + pthread_mutex_unlock(&client->lock); + pthread_rwlock_unlock(&server_opts.ch_client_lock); +} + int equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name) { @@ -1168,39 +1217,54 @@ static void nc_server_config_ch_del_client(struct nc_ch_client *ch_client) { uint16_t i, ch_endpt_count; + struct nc_ch_client client; + pthread_t tid; + /* WR LOCK */ pthread_rwlock_wrlock(&server_opts.ch_client_lock); - free(ch_client->name); - ch_client->name = NULL; + /* copy the client we want to delete into a local variable */ + memcpy(&client, ch_client, sizeof *ch_client); + /* get his tid */ + tid = client.tid; - if (ch_client->session) { - pthread_mutex_lock(&ch_client->session->opts.server.ch_lock); - pthread_cond_signal(&ch_client->session->opts.server.ch_cond); - pthread_mutex_unlock(&ch_client->session->opts.server.ch_lock); - ch_client->session = NULL; + /* delete the client */ + server_opts.ch_client_count--; + if (!server_opts.ch_client_count) { + free(server_opts.ch_clients); + server_opts.ch_clients = NULL; + } else { + memcpy(ch_client, &server_opts.ch_clients[server_opts.ch_client_count], sizeof *server_opts.ch_clients); } + /* WR UNLOCK */ pthread_rwlock_unlock(&server_opts.ch_client_lock); - if (ch_client->tid) { - pthread_join(ch_client->tid, NULL); - } + /* RD LOCK */ + pthread_rwlock_rdlock(&server_opts.ch_client_lock); - pthread_rwlock_wrlock(&server_opts.ch_client_lock); + if (client.thread_data->thread_running) { + /* CH COND LOCK */ + pthread_mutex_lock(&client.thread_data->cond_lock); + client.thread_data->thread_running = 0; + pthread_cond_signal(&client.thread_data->cond); + /* CH COND UNLOCK */ + pthread_mutex_unlock(&client.thread_data->cond_lock); - ch_endpt_count = ch_client->ch_endpt_count; - for (i = 0; i < ch_endpt_count; i++) { - nc_server_config_ch_del_endpt(ch_client, &ch_client->ch_endpts[i]); - } + /* RD UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_client_lock); - server_opts.ch_client_count--; - if (!server_opts.ch_client_count) { - free(server_opts.ch_clients); - server_opts.ch_clients = NULL; + /* wait for the thread to terminate */ + pthread_join(tid, NULL); } - pthread_rwlock_unlock(&server_opts.ch_client_lock); + /* free its members */ + free(client.name); + + ch_endpt_count = client.ch_endpt_count; + for (i = 0; i < ch_endpt_count; i++) { + nc_server_config_ch_del_endpt(&client, &client.ch_endpts[i]); + } } void @@ -1337,8 +1401,8 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) } } } else if (is_ch(node)) { - /* ch */ - if (nc_server_config_get_ch_client(node, &ch_client)) { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { ret = 1; goto cleanup; } @@ -1355,6 +1419,10 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -1393,6 +1461,7 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) struct nc_endpt *endpt; struct nc_bind *bind; struct nc_ch_endpt *ch_endpt; + struct nc_ch_client *ch_client; int ret = 0; assert(!strcmp(LYD_NAME(node), "ssh")); @@ -1412,6 +1481,12 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) nc_server_config_del_ssh(bind, endpt->opts.ssh); } } else { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + ret = 1; + goto cleanup; + } + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; @@ -1428,6 +1503,10 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -1463,6 +1542,7 @@ nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op) struct nc_endpt *endpt; struct nc_bind *bind; struct nc_ch_endpt *ch_endpt; + struct nc_ch_client *ch_client; int ret = 0; assert(!strcmp(LYD_NAME(node), "tls")); @@ -1482,6 +1562,12 @@ nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op) nc_server_config_del_tls(bind, endpt->opts.tls); } } else { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + ret = 1; + goto cleanup; + } + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; @@ -1496,6 +1582,10 @@ nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -1643,6 +1733,7 @@ nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) struct nc_endpt *endpt; struct nc_bind *bind; struct nc_ch_endpt *ch_endpt; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "keepalives")); @@ -1662,6 +1753,11 @@ nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; @@ -1675,6 +1771,10 @@ nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -1686,6 +1786,7 @@ nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) struct nc_endpt *endpt; struct nc_bind *bind; struct nc_ch_endpt *ch_endpt; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "idle-time")); @@ -1705,6 +1806,11 @@ nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; @@ -1718,6 +1824,10 @@ nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -1729,6 +1839,7 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) struct nc_endpt *endpt; struct nc_bind *bind; struct nc_ch_endpt *ch_endpt; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "max-probes")); @@ -1748,6 +1859,11 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; @@ -1761,6 +1877,10 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -1772,6 +1892,7 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) struct nc_endpt *endpt; struct nc_bind *bind; struct nc_ch_endpt *ch_endpt; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "probe-interval")); @@ -1791,6 +1912,11 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; @@ -1804,6 +1930,10 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -1823,6 +1953,7 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_hostkey *hostkey; struct nc_server_ssh_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "host-key")); @@ -1832,6 +1963,11 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) } if (equal_parent_name(node, 1, "server-identity")) { + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (op == NC_OP_CREATE) { ret = nc_server_config_create_host_key(node, opts); if (ret) { @@ -1847,6 +1983,10 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node) && equal_parent_name(node, 1, "server-identity")) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -1860,6 +2000,7 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) struct nc_public_key *pubkey; struct nc_hostkey *hostkey; struct nc_server_tls_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "public-key-format")); @@ -1874,6 +2015,11 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) { /* SSH hostkey public key fmt */ if (nc_server_config_get_hostkey(node, &hostkey)) { @@ -1907,6 +2053,10 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -1971,9 +2121,15 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) struct nc_client_auth *auth_client; struct nc_public_key *pubkey; struct nc_server_tls_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "public-key")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) { /* server's public-key, mandatory leaf */ if (nc_server_config_get_hostkey(node, &hostkey)) { @@ -2047,6 +2203,10 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2059,6 +2219,7 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op NC_PRIVKEY_FORMAT privkey_type; struct nc_hostkey *hostkey; struct nc_server_tls_opts *opts; + struct nc_ch_client *ch_client; (void) op; @@ -2077,6 +2238,11 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op goto cleanup; } + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (is_ssh(node)) { /* ssh */ if (nc_server_config_get_hostkey(node, &hostkey)) { @@ -2096,6 +2262,10 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2131,9 +2301,15 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION int ret = 0; struct nc_hostkey *hostkey; struct nc_server_tls_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "cleartext-private-key")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (is_ssh(node)) { /* ssh */ if (nc_server_config_get_hostkey(node, &hostkey)) { @@ -2167,6 +2343,10 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2199,9 +2379,15 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op { int ret = 0; struct nc_hostkey *hostkey; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "keystore-reference")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) { if (nc_server_config_get_hostkey(node, &hostkey)) { ret = 1; @@ -2222,6 +2408,10 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2241,9 +2431,15 @@ nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_client_auth *auth_client; struct nc_server_ssh_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "user")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ssh_opts(node, &opts)) { ret = 1; goto cleanup; @@ -2264,6 +2460,10 @@ nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2272,9 +2472,15 @@ nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_server_ssh_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "auth-attempts")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ssh_opts(node, &opts)) { ret = 1; goto cleanup; @@ -2285,6 +2491,10 @@ nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2293,9 +2503,15 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_server_ssh_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "auth-timeout")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ssh_opts(node, &opts)) { ret = 1; goto cleanup; @@ -2306,6 +2522,10 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2362,9 +2582,15 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION int ret = 0; struct nc_endpt *endpt; struct nc_client_auth *auth_client; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "truststore-reference")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) { if (nc_server_config_get_auth_client(node, &auth_client)) { ret = 1; @@ -2382,7 +2608,7 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION } else { auth_client->ts_ref = NULL; } - } else if (is_listen(node) && equal_parent_name(node, 1, "ca-certs")) { + } else if (is_tls(node) && equal_parent_name(node, 1, "ca-certs")) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -2399,7 +2625,7 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION } else { endpt->opts.tls->ca_certs.ts_ref = NULL; } - } else if (is_listen(node) && equal_parent_name(node, 1, "ee-certs")) { + } else if (is_tls(node) && equal_parent_name(node, 1, "ee-certs")) { if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -2419,6 +2645,10 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2442,9 +2672,15 @@ nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_client_auth *auth_client; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "password")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_auth_client(node, &auth_client)) { ret = 1; goto cleanup; @@ -2460,6 +2696,10 @@ nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2468,9 +2708,15 @@ nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_client_auth *auth_client; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "pam-config-file-name")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_auth_client(node, &auth_client)) { ret = 1; goto cleanup; @@ -2490,6 +2736,10 @@ nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2498,9 +2748,15 @@ nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_client_auth *auth_client; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "pam-config-file-dir")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_auth_client(node, &auth_client)) { ret = 1; goto cleanup; @@ -2519,6 +2775,10 @@ nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2528,9 +2788,15 @@ nc_server_config_none(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_client_auth *auth_client; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "none")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_auth_client(node, &auth_client)) { ret = 1; goto cleanup; @@ -2543,6 +2809,10 @@ nc_server_config_none(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2638,9 +2908,15 @@ nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op) const char *alg; uint8_t i; struct nc_server_ssh_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "host-key-alg")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ssh_opts(node, &opts)) { ret = 1; goto cleanup; @@ -2666,6 +2942,10 @@ nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2677,9 +2957,15 @@ nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op) const char *alg; uint8_t i; struct nc_server_ssh_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "key-exchange-alg")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ssh_opts(node, &opts)) { ret = 1; goto cleanup; @@ -2705,6 +2991,10 @@ nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2716,9 +3006,15 @@ nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op) const char *alg; uint8_t i; struct nc_server_ssh_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "encryption-alg")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ssh_opts(node, &opts)) { ret = 1; goto cleanup; @@ -2744,6 +3040,10 @@ nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -2755,9 +3055,15 @@ nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op) const char *alg; uint8_t i; struct nc_server_ssh_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "mac-alg")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ssh_opts(node, &opts)) { ret = 1; goto cleanup; @@ -2783,6 +3089,10 @@ nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -3058,9 +3368,15 @@ nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_certificate *cert; struct nc_server_tls_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "cert-data")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (equal_parent_name(node, 3, "server-identity")) { if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; @@ -3104,6 +3420,10 @@ nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -3135,9 +3455,15 @@ nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_endpt *endpt; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "asymmetric-key")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_endpt(node, &endpt, NULL)) { ret = 1; goto cleanup; @@ -3156,6 +3482,10 @@ nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -3234,9 +3564,15 @@ nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_asymmetric_key *key; struct nc_server_tls_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "certificate")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; @@ -3291,6 +3627,10 @@ nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -3391,9 +3731,15 @@ nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op) struct nc_server_tls_opts *opts; struct lyd_node *key; struct nc_ctn *ctn; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "cert-to-name")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; @@ -3416,6 +3762,10 @@ nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -3438,6 +3788,14 @@ nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_ctn *ctn; + struct nc_ch_client *ch_client; + + assert(!strcmp(LYD_NAME(node), "fingerprint")); + + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } if (nc_server_config_get_ctn(node, &ctn)) { ret = 1; @@ -3454,6 +3812,10 @@ nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -3475,9 +3837,15 @@ nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_server_tls_opts *opts; const char *version = NULL; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "tls-version")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; @@ -3499,6 +3867,10 @@ nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -3592,9 +3964,15 @@ nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_server_tls_opts *opts; const char *cipher = NULL; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "cipher-suite")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; @@ -3614,6 +3992,10 @@ nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -3622,9 +4004,15 @@ nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_server_tls_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "crl-url")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; @@ -3643,6 +4031,10 @@ nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -3651,9 +4043,15 @@ nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_server_tls_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "crl-path")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; @@ -3672,6 +4070,10 @@ nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -3680,9 +4082,15 @@ nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_server_tls_opts *opts; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "crl-cert-ext")); + /* LOCK */ + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; @@ -3695,6 +4103,10 @@ nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op) } cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + } return ret; } @@ -3761,9 +4173,15 @@ nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_ch_endpt *ch_endpt; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "remote-address")); + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; @@ -3783,6 +4201,8 @@ nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op) } cleanup: + /* UNLOCK */ + nc_ch_client_unlock(ch_client); return ret; } @@ -3791,9 +4211,15 @@ nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_ch_endpt *ch_endpt; + struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "remote-port")); + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; + } + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { ret = 1; goto cleanup; @@ -3806,6 +4232,8 @@ nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op) } cleanup: + /* UNLOCK */ + nc_ch_client_unlock(ch_client); return ret; } @@ -3821,13 +4249,17 @@ nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op) (void) op; - if (nc_server_config_get_ch_client(node, &ch_client)) { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { ret = 1; goto cleanup; } ch_client->conn_type = NC_CH_PERSIST; + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + cleanup: return ret; } @@ -3842,7 +4274,8 @@ nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op) (void) op; - if (nc_server_config_get_ch_client(node, &ch_client)) { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { ret = 1; goto cleanup; } @@ -3853,6 +4286,9 @@ nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op) ch_client->anchor_time = 0; ch_client->idle_timeout = 180; + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + cleanup: return ret; } @@ -3865,7 +4301,8 @@ nc_server_config_period(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "period")); - if (nc_server_config_get_ch_client(node, &ch_client)) { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { ret = 1; goto cleanup; } @@ -3876,6 +4313,9 @@ nc_server_config_period(const struct lyd_node *node, NC_OPERATION op) ch_client->period = 60; } + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + cleanup: return ret; } @@ -3889,9 +4329,9 @@ nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "anchor-time")); - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; } ret = ly_time_str2time(lyd_get_value(node), &anchor_time, NULL); @@ -3906,6 +4346,8 @@ nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op) } cleanup: + /* UNLOCK */ + nc_ch_client_unlock(ch_client); return ret; } @@ -3919,7 +4361,8 @@ nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op (void) op; - if (nc_server_config_get_ch_client(node, &ch_client)) { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { ret = 1; goto cleanup; } @@ -3929,6 +4372,9 @@ nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op ch_client->max_wait = 5; ch_client->max_attempts = 3; + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + cleanup: return ret; } @@ -3942,9 +4388,9 @@ nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "start-with")); - if (nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + return 1; } if (op == NC_OP_DELETE) { @@ -3966,6 +4412,8 @@ nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op) } cleanup: + /* UNLOCK */ + nc_ch_client_unlock(ch_client); return ret; } @@ -3977,7 +4425,8 @@ nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "max-wait")); - if (nc_server_config_get_ch_client(node, &ch_client)) { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { ret = 1; goto cleanup; } @@ -3988,6 +4437,9 @@ nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op) ch_client->max_wait = 5; } + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + cleanup: return ret; } @@ -4000,7 +4452,8 @@ nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "max-attempts")); - if (nc_server_config_get_ch_client(node, &ch_client)) { + /* LOCK */ + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { ret = 1; goto cleanup; } @@ -4011,6 +4464,9 @@ nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op) ch_client->max_attempts = 3; } + /* UNLOCK */ + nc_ch_client_unlock(ch_client); + cleanup: return ret; } diff --git a/src/session_p.h b/src/session_p.h index 3fe3ddd1..d6ca52df 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -394,6 +394,23 @@ struct nc_client_context { #endif /* NC_ENABLED_SSH_TLS */ }; +/** + * @brief Call Home client thread data. + */ +struct nc_ch_client_thread_arg { + char *client_name; + + const struct ly_ctx *(*acquire_ctx_cb)(void *cb_data); /**< acquiring libyang context cb */ + void (*release_ctx_cb)(void *cb_data); /**< releasing libyang context cb */ + void *ctx_cb_data; /**< acq/rel cb data */ + int (*new_session_cb)(const char *client_name, struct nc_session *new_session, void *user_data); /**< creating new session cb */ + void *new_session_cb_data; /**< new session cb data */ + + int thread_running; /**< A boolean value that is truthy while the underlying Call Home thread is running */ + pthread_mutex_t cond_lock; /**< Condition's lock used for signalling the thread to terminate */ + pthread_cond_t cond; /**< Condition used for signalling the thread to terminate */ +}; + struct nc_server_opts { /* ACCESS unlocked */ ATOMIC_T wd_basic_mode; @@ -462,9 +479,9 @@ struct nc_server_opts { struct nc_ch_client { char *name; - struct nc_session *session; - pthread_t tid; - // data * - condition, mutex, thread_running + pthread_t tid; /**< Call Home client's thread ID */ + struct nc_ch_client_thread_arg *thread_data; /**< Data of the Call Home client's thread */ + struct nc_ch_endpt { char *name; NC_TRANSPORT_IMPL ti; @@ -536,6 +553,11 @@ struct nc_server_opts { */ #define NC_CH_NO_ENDPT_WAIT 1000 +/** + * Time slept in msec between Call Home thread session idle timeout checks. + */ +#define NC_CH_THREAD_IDLE_TIMEOUT_SLEEP 1000 + /** * Timeout in msec for a Call Home socket to establish its connection. */ diff --git a/tests/test_ch.c b/tests/test_ch.c index bad8fc62..735267b9 100644 --- a/tests/test_ch.c +++ b/tests/test_ch.c @@ -39,6 +39,22 @@ struct test_state { struct lyd_node *tls_tree; }; +char buffer[512]; +char expected[512]; + +static void +test_msg_callback(const struct nc_session *session, NC_VERB_LEVEL level, const char *msg) +{ + (void) level; + (void) session; + + if (strstr(msg, expected)) { + strcpy(buffer, msg); + } + + printf("%s\n", msg); +} + /* acquire ctx cb for dispatch */ const struct ly_ctx * ch_session_acquire_ctx_cb(void *cb_data) @@ -76,6 +92,11 @@ server_thread_ssh(void *arg) struct test_state *state = arg; struct nc_pollsession *ps; + /* set print clb so we get access to messages */ + nc_set_print_clb_session(test_msg_callback); + buffer[0] = '\0'; + strcpy(expected, "reconnecting in"); + /* prepare data for deleting the call-home client */ ret = nc_server_config_new_del_ch_client("ch_ssh", &state->ssh_tree); assert_int_equal(ret, 0); @@ -96,7 +117,7 @@ server_thread_ssh(void *arg) if (ret & (NC_PSPOLL_TIMEOUT | NC_PSPOLL_NOSESSIONS)) { usleep(500); } - } while (!(ret & NC_PSPOLL_SESSION_TERM)); + } while (!strlen(buffer)); /* delete the call-home client, the thread should end */ ret = nc_server_config_setup_data(state->ssh_tree); @@ -180,9 +201,11 @@ setup_ssh(void **state) ret = nc_server_config_new_ch_address_port(ctx, "ch_ssh", "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &test_state->ssh_tree); assert_int_equal(ret, 0); + /* set connection type to persistent */ ret = nc_server_config_new_ch_persistent(ctx, "ch_ssh", &test_state->ssh_tree); assert_int_equal(ret, 0); + /* set the period of the periodic connection type, this should remove the persistent connection type */ ret = nc_server_config_new_ch_period(ctx, "ch_ssh", 3, &test_state->ssh_tree); assert_int_equal(ret, 0); From 0ca981b2579050262f20786df6acf1a2f09c8bbd Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 24 Jul 2023 10:40:03 +0200 Subject: [PATCH 048/134] examples BUGFIX change diff to data --- examples/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/server.c b/examples/server.c index e0d80566..c0ce0a89 100644 --- a/examples/server.c +++ b/examples/server.c @@ -256,7 +256,7 @@ init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_T } /* apply the created configuration data */ - rc = nc_server_config_setup_diff(config); + rc = nc_server_config_setup_data(config); if (rc) { ERR_MSG_CLEANUP("Application of configuration data failed.\n"); } From 88663ce25ebf8f6556792a5f018e43d9aa371199 Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 24 Jul 2023 10:40:59 +0200 Subject: [PATCH 049/134] config UPDATE add auth attempts and timeout Also moved around some functions, so the order of their definitions makes more sense. --- src/config_new_ssh.c | 1248 +++++++++++++++++++++++------------------- src/server_config.h | 64 +++ 2 files changed, 739 insertions(+), 573 deletions(-) diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index d3c3d57e..6f09c928 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -181,444 +181,542 @@ nc_server_config_new_ch_ssh_del_hostkey(const char *client_name, const char *end } } -static int -nc_server_config_new_ssh_transport_params_prep(const struct ly_ctx *ctx, const char *client_name, - const char *endpt_name, struct lyd_node *config, struct lyd_node **new_tree, struct lyd_node **alg_tree) +API int +nc_server_config_new_ch_ssh_keystore_reference(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) +{ + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, keystore_reference, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + return nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); +} + +API int +nc_server_config_new_ch_ssh_del_keystore_reference(const char *client_name, const char *endpt_name, + const char *hostkey_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, hostkey_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); +} + +API int +nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, + const char *keystore_reference, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, keystore_reference, config, 1); + + return nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" + "keystore-reference", endpt_name, hostkey_name); +} + +API int +nc_server_config_new_ssh_del_keystore_reference(const char *endpt_name, const char *hostkey_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" + "keystore-reference", endpt_name, hostkey_name); +} + +API int +nc_server_config_new_ssh_auth_attempts(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_attempts, + struct lyd_node **config) { int ret = 0; - char *tree_path = NULL; + char *attempts_buf = NULL; - /* prepare path */ - if (client_name) { - /* ch */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/transport-params", client_name, endpt_name); - } else { - /* listen */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params", endpt_name); - } - if (!tree_path) { + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + /* uint to str */ + if (asprintf(&attempts_buf, "%u", auth_attempts) == -1) { ERRMEM; + attempts_buf = NULL; ret = 1; goto cleanup; } - /* create all the nodes in the path */ - ret = lyd_new_path2(config, ctx, tree_path, NULL, 0, 0, LYD_NEW_PATH_UPDATE, new_tree, alg_tree); - if (ret) { - ERR(NULL, "Creating new path to transport-params failed."); + ret = nc_config_new_create(ctx, config, attempts_buf, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/libnetconf2-netconf-server:auth-attempts", endpt_name); + +cleanup: + free(attempts_buf); + return ret; +} + +API int +nc_server_config_new_ssh_auth_timeout(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_timeout, + struct lyd_node **config) +{ + int ret = 0; + char *timeout_buf = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + /* uint to str */ + if (asprintf(&timeout_buf, "%u", auth_timeout) == -1) { + ERRMEM; + timeout_buf = NULL; + ret = 1; goto cleanup; } - if (!*alg_tree) { - /* no new nodes added */ - ret = lyd_find_path(config, tree_path, 0, alg_tree); - if (ret) { - goto cleanup; - } - } + ret = nc_config_new_create(ctx, config, timeout_buf, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/libnetconf2-netconf-server:auth-timeout", endpt_name); cleanup: - free(tree_path); + free(timeout_buf); return ret; } -static int -nc_server_config_new_ssh_transport_params_create(const struct ly_ctx *ctx, NC_ALG_TYPE alg_type, int alg_count, va_list ap, - struct lyd_node *tree) +API int +nc_server_config_new_ch_ssh_auth_attempts(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + uint16_t auth_attempts, struct lyd_node **config) { - int i, ret = 0; - char *alg, *alg_ident; - const char *module, *alg_path, *old_path; - struct lyd_node *old = NULL; + int ret = 0; + char *attempts_buf = NULL; - /* get the correct module with the indentity base and the path in the ietf-netconf-server module */ - switch (alg_type) { - case NC_ALG_HOSTKEY: - module = "iana-ssh-public-key-algs"; - alg_path = "host-key/host-key-alg"; - old_path = "host-key"; - break; - case NC_ALG_KEY_EXCHANGE: - module = "iana-ssh-key-exchange-algs"; - alg_path = "key-exchange/key-exchange-alg"; - old_path = "key-exchange"; - break; - case NC_ALG_ENCRYPTION: - module = "iana-ssh-encryption-algs"; - alg_path = "encryption/encryption-alg"; - old_path = "encryption"; - break; - case NC_ALG_MAC: - module = "iana-ssh-mac-algs"; - alg_path = "mac/mac-alg"; - old_path = "mac"; - break; - default: + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); + + /* uint to str */ + if (asprintf(&attempts_buf, "%u", auth_attempts) == -1) { + ERRMEM; + attempts_buf = NULL; ret = 1; - ERR(NULL, "Unknown algorithm type."); goto cleanup; } - /* delete all older algorithms (if any) se they can be replaced by the new ones */ - lyd_find_path(tree, old_path, 0, &old); - if (old) { - lyd_free_tree(old); - } + ret = nc_config_new_create(ctx, config, attempts_buf, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "libnetconf2-netconf-server:auth-attempts", client_name, endpt_name); - for (i = 0; i < alg_count; i++) { - alg = va_arg(ap, char *); +cleanup: + free(attempts_buf); + return ret; +} - asprintf(&alg_ident, "%s:%s", module, alg); - if (!alg_ident) { - ERRMEM; - ret = 1; - goto cleanup; - } +API int +nc_server_config_new_ch_ssh_auth_timeout(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + uint16_t auth_timeout, struct lyd_node **config) +{ + int ret = 0; + char *timeout_buf = NULL; - /* create the leaf list */ - ret = lyd_new_path(tree, ctx, alg_path, alg_ident, 0, NULL); - if (ret) { - ERR(NULL, "Creating new algorithm leaf-list failed."); - goto cleanup; - } + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); - free(alg_ident); + /* uint to str */ + if (asprintf(&timeout_buf, "%u", auth_timeout) == -1) { + ERRMEM; + timeout_buf = NULL; + ret = 1; + goto cleanup; } + ret = nc_config_new_create(ctx, config, timeout_buf, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "libnetconf2-netconf-server:auth-timeout", client_name, endpt_name); + cleanup: + free(timeout_buf); return ret; } static int -nc_server_config_new_ssh_transport_params(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - NC_ALG_TYPE alg_type, int alg_count, va_list ap, struct lyd_node **config) +_nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *tree_path, const char *pubkey_path, + struct lyd_node **config) { int ret = 0; - struct lyd_node *new_tree, *alg_tree; + char *pubkey = NULL; + NC_PUBKEY_FORMAT pubkey_type; + const char *pubkey_format; - ret = nc_server_config_new_ssh_transport_params_prep(ctx, client_name, endpt_name, *config, &new_tree, &alg_tree); + /* get pubkey data */ + ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_type); if (ret) { goto cleanup; } - if (!*config) { - *config = new_tree; + /* get pubkey format */ + if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { + pubkey_format = "ietf-crypto-types:ssh-public-key-format"; + } else { + pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; } - ret = nc_server_config_new_ssh_transport_params_create(ctx, alg_type, alg_count, ap, alg_tree); + ret = nc_config_new_create_append(ctx, tree_path, "public-key-format", pubkey_format, config); if (ret) { goto cleanup; } - /* Add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + ret = nc_config_new_create_append(ctx, tree_path, "public-key", pubkey, config); if (ret) { goto cleanup; } + cleanup: + free(pubkey); return ret; } API int -nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) +nc_server_config_new_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) { int ret = 0; - va_list ap; + char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pubkey_name, pubkey_path, 1); + NC_CHECK_ARG_RET(NULL, config, 1); - va_start(ap, alg_count); + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" + "public-key[name='%s']", endpt_name, user_name, pubkey_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } - ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); + ret = _nc_server_config_new_ssh_user_pubkey(ctx, path, pubkey_path, config); if (ret) { - ERR(NULL, "Creating new hostkey algorithms failed."); + ERR(NULL, "Creating new user's public key failed."); goto cleanup; } cleanup: - va_end(ap); + free(path); return ret; } API int -nc_server_config_new_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) +nc_server_config_new_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) { int ret = 0; - va_list ap; + char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pubkey_name, 1); + NC_CHECK_ARG_RET(NULL, pubkey_path, config, 1); - va_start(ap, alg_count); + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, + endpt_name, user_name, pubkey_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } - ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); + ret = _nc_server_config_new_ssh_user_pubkey(ctx, path, pubkey_path, config); if (ret) { - ERR(NULL, "Creating new hostkey algorithms failed."); + ERR(NULL, "Creating new user's public key failed."); goto cleanup; } cleanup: - va_end(ap); + free(path); return ret; } API int -nc_server_config_new_ssh_del_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config) +nc_server_config_new_ssh_del_user_pubkey(const char *endpt_name, const char *user_name, + const char *pubkey_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/host-key/" - "host-key-alg[.='iana-ssh-public-key-algs:%s']", endpt_name, alg); + if (pubkey_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" + "public-key[name='%s']", endpt_name, user_name, pubkey_name); } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/host-key", endpt_name); + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" + "public-key", endpt_name, user_name); } } API int -nc_server_config_new_ch_ssh_del_host_key_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) +nc_server_config_new_ch_ssh_del_user_pubkey(const char *client_name, const char *endpt_name, + const char *user_name, const char *pubkey_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key/" - "host-key-alg[.='iana-ssh-public-key-algs:%s']", client_name, endpt_name, alg); + if (pubkey_name) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, + endpt_name, user_name, pubkey_name); } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key", client_name, endpt_name); + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key", client_name, + endpt_name, user_name); } } -API int -nc_server_config_new_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) +static int +_nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *tree_path, + const char *password, struct lyd_node **config) { int ret = 0; - va_list ap; + char *hashed_pw = NULL; + const char *salt = "$6$idsizuippipk$"; - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); +#ifdef HAVE_CRYPT_R + struct crypt_data cdata; +#endif - va_start(ap, alg_count); +#ifdef HAVE_CRYPT_R + cdata.initialized = 0; + hashed_pw = crypt_r(password, salt, &data); +#else + pthread_mutex_lock(&crypt_lock); + hashed_pw = crypt(password, salt); + pthread_mutex_unlock(&crypt_lock); +#endif - ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); + if (!hashed_pw) { + ERR(NULL, "Hashing password failed."); + ret = 1; + goto cleanup; + } + + ret = nc_config_new_create_append(ctx, tree_path, "password", hashed_pw, config); if (ret) { - ERR(NULL, "Creating new key exchange algorithms failed."); goto cleanup; } cleanup: - va_end(ap); return ret; } API int -nc_server_config_new_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) +nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *password, struct lyd_node **config) { int ret = 0; - va_list ap; + char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, password, config, 1); - va_start(ap, alg_count); + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/users/user[name='%s']", endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } - ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); + ret = _nc_server_config_new_ssh_user_password(ctx, path, password, config); if (ret) { - ERR(NULL, "Creating new key exchange algorithms failed."); + ERR(NULL, "Creating new user's public key failed."); goto cleanup; } cleanup: - va_end(ap); + free(path); return ret; } API int -nc_server_config_new_ssh_del_key_exchange_alg(const char *endpt_name, const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/key-exchange/" - "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/key-exchange", endpt_name); - } -} - -API int -nc_server_config_new_ch_ssh_del_key_exchange_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange/" - "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", client_name, endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange", client_name, endpt_name); - } -} - -API int -nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) +nc_server_config_new_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) { int ret = 0; - va_list ap; + char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, password, 1); + NC_CHECK_ARG_RET(NULL, config, 1); - va_start(ap, alg_count); + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']", client_name, endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } - ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); + ret = _nc_server_config_new_ssh_user_password(ctx, path, password, config); if (ret) { - ERR(NULL, "Creating new encryption algorithms failed."); + ERR(NULL, "Creating new user's password failed."); goto cleanup; } cleanup: - va_end(ap); + free(path); return ret; } API int -nc_server_config_new_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) +nc_server_config_new_ssh_del_user_password(const char *endpt_name, const char *user_name, struct lyd_node **config) { - int ret = 0; - va_list ap; + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/password", endpt_name, user_name); +} - va_start(ap, alg_count); +API int +nc_server_config_new_ch_ssh_del_user_password(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new encryption algorithms failed."); - goto cleanup; - } + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/password", client_name, endpt_name, user_name); +} -cleanup: - va_end(ap); - return ret; +API int +nc_server_config_new_ssh_user_none(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, config, 1); + + return nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/none", endpt_name, user_name); } API int -nc_server_config_new_ssh_del_encryption_alg(const char *endpt_name, const char *alg, struct lyd_node **config) +nc_server_config_new_ch_ssh_user_none(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, config, 1); - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/encryption/" - "encryption-alg[.='iana-ssh-encryption-algs:%s']", endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/encryption", endpt_name); - } + return nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/none", client_name, endpt_name, user_name); } API int -nc_server_config_new_ch_ssh_del_encryption_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) +nc_server_config_new_ssh_del_user_none(const char *endpt_name, const char *user_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption/" - "encryption-alg[.='iana-ssh-encryption-algs:%s']", client_name, endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption", client_name, endpt_name); - } + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/none", endpt_name, user_name); } API int -nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) +nc_server_config_new_ch_ssh_del_user_none(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) { - int ret = 0; - va_list ap; + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/none", client_name, endpt_name, user_name); +} - va_start(ap, alg_count); +static int +_nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *tree_path, + const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) +{ + int ret = 0; - ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_MAC, alg_count, ap, config); + ret = nc_config_new_create_append(ctx, tree_path, "pam-config-file-name", pam_config_name, config); if (ret) { - ERR(NULL, "Creating new mac algorithms failed."); goto cleanup; } + if (pam_config_dir) { + ret = nc_config_new_create_append(ctx, tree_path, "pam-config-file-dir", pam_config_dir, config); + if (ret) { + goto cleanup; + } + } + cleanup: - va_end(ap); return ret; } API int -nc_server_config_new_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) +nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) { int ret = 0; - va_list ap; + char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pam_config_name, config, 1); - va_start(ap, alg_count); + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } - ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_MAC, alg_count, ap, config); + ret = _nc_server_config_new_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); if (ret) { - ERR(NULL, "Creating new mac algorithms failed."); + ERR(NULL, "Creating new user's keyboard interactive nodes failed."); goto cleanup; } cleanup: - va_end(ap); + free(path); return ret; } API int -nc_server_config_new_ssh_del_mac_alg(const char *endpt_name, const char *alg, struct lyd_node **config) +nc_server_config_new_ch_ssh_user_interactive(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + int ret = 0; + char *path = NULL; - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/mac/" - "mac-alg[.='iana-ssh-mac-algs:%s']", endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/mac", endpt_name); - } + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pam_config_name, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); + if (ret) { + ERR(NULL, "Creating new user's keyboard interactive nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; } API int -nc_server_config_new_ch_ssh_del_mac_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) +nc_server_config_new_ssh_del_user_interactive(const char *endpt_name, const char *user_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac/" - "mac-alg[.='iana-ssh-mac-algs:%s']", client_name, endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac", client_name, endpt_name); - } + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name); +} + +API int +nc_server_config_new_ch_ssh_del_user_interactive(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name); } API int @@ -652,502 +750,506 @@ nc_server_config_new_ch_ssh_del_user(const char *client_name, const char *endpt_ } } -static int -_nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *tree_path, const char *pubkey_path, - struct lyd_node **config) +API int +nc_config_new_ssh_endpoint_user_reference(const struct ly_ctx *ctx, const char *endpt_name, + const char *referenced_endpt, struct lyd_node **config) { - int ret = 0; - char *pubkey = NULL; - NC_PUBKEY_FORMAT pubkey_type; - const char *pubkey_format; - - /* get pubkey data */ - ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_type); - if (ret) { - goto cleanup; - } - - /* get pubkey format */ - if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { - pubkey_format = "ietf-crypto-types:ssh-public-key-format"; - } else { - pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; - } - - ret = nc_config_new_create_append(ctx, tree_path, "public-key-format", pubkey_format, config); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "public-key", pubkey, config); - if (ret) { - goto cleanup; - } + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); -cleanup: - free(pubkey); - return ret; + return nc_config_new_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); } API int -nc_server_config_new_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) +nc_config_new_ssh_del_endpoint_user_reference(const char *endpt_name, struct lyd_node **config) { - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pubkey_name, pubkey_path, 1); - NC_CHECK_ARG_RET(NULL, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" - "public-key[name='%s']", endpt_name, user_name, pubkey_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_ssh_user_pubkey(ctx, path, pubkey_path, config); - if (ret) { - ERR(NULL, "Creating new user's public key failed."); - goto cleanup; - } + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); -cleanup: - free(path); - return ret; + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); } API int -nc_server_config_new_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) +nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, + const char *truststore_reference, struct lyd_node **config) { - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pubkey_name, 1); - NC_CHECK_ARG_RET(NULL, pubkey_path, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, truststore_reference, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, - endpt_name, user_name, pubkey_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + return nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" + "truststore-reference", endpt_name, user_name); +} - ret = _nc_server_config_new_ssh_user_pubkey(ctx, path, pubkey_path, config); - if (ret) { - ERR(NULL, "Creating new user's public key failed."); - goto cleanup; - } +API int +nc_server_config_new_ch_ssh_truststore_reference(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) +{ + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, truststore_reference, 1); + NC_CHECK_ARG_RET(NULL, config, 1); -cleanup: - free(path); - return ret; + return nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); } API int -nc_server_config_new_ssh_del_user_pubkey(const char *endpt_name, const char *user_name, - const char *pubkey_name, struct lyd_node **config) +nc_server_config_new_ssh_del_truststore_reference(const char *endpt_name, const char *user_name, + struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - if (pubkey_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" - "public-key[name='%s']", endpt_name, user_name, pubkey_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" - "public-key", endpt_name, user_name); - } + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" + "truststore-reference", endpt_name, user_name); } API int -nc_server_config_new_ch_ssh_del_user_pubkey(const char *client_name, const char *endpt_name, - const char *user_name, const char *pubkey_name, struct lyd_node **config) +nc_server_config_new_ch_ssh_del_truststore_reference(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - if (pubkey_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, - endpt_name, user_name, pubkey_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key", client_name, - endpt_name, user_name); - } + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); } static int -_nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *tree_path, - const char *password, struct lyd_node **config) +nc_server_config_new_ssh_transport_params_prep(const struct ly_ctx *ctx, const char *client_name, + const char *endpt_name, struct lyd_node *config, struct lyd_node **new_tree, struct lyd_node **alg_tree) { int ret = 0; - char *hashed_pw = NULL; - const char *salt = "$6$idsizuippipk$"; - -#ifdef HAVE_CRYPT_R - struct crypt_data cdata; -#endif - -#ifdef HAVE_CRYPT_R - cdata.initialized = 0; - hashed_pw = crypt_r(password, salt, &data); -#else - pthread_mutex_lock(&crypt_lock); - hashed_pw = crypt(password, salt); - pthread_mutex_unlock(&crypt_lock); -#endif + char *tree_path = NULL; - if (!hashed_pw) { - ERR(NULL, "Hashing password failed."); + /* prepare path */ + if (client_name) { + /* ch */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/transport-params", client_name, endpt_name); + } else { + /* listen */ + asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params", endpt_name); + } + if (!tree_path) { + ERRMEM; ret = 1; goto cleanup; } - ret = nc_config_new_create_append(ctx, tree_path, "password", hashed_pw, config); + /* create all the nodes in the path */ + ret = lyd_new_path2(config, ctx, tree_path, NULL, 0, 0, LYD_NEW_PATH_UPDATE, new_tree, alg_tree); if (ret) { + ERR(NULL, "Creating new path to transport-params failed."); goto cleanup; } + if (!*alg_tree) { + /* no new nodes added */ + ret = lyd_find_path(config, tree_path, 0, alg_tree); + if (ret) { + goto cleanup; + } + } + cleanup: + free(tree_path); return ret; } -API int -nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, const char *password, struct lyd_node **config) +static int +nc_server_config_new_ssh_transport_params_create(const struct ly_ctx *ctx, NC_ALG_TYPE alg_type, int alg_count, va_list ap, + struct lyd_node *tree) { - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, password, config, 1); + int i, ret = 0; + char *alg, *alg_ident; + const char *module, *alg_path, *old_path; + struct lyd_node *old = NULL; - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/users/user[name='%s']", endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; + /* get the correct module with the indentity base and the path in the ietf-netconf-server module */ + switch (alg_type) { + case NC_ALG_HOSTKEY: + module = "iana-ssh-public-key-algs"; + alg_path = "host-key/host-key-alg"; + old_path = "host-key"; + break; + case NC_ALG_KEY_EXCHANGE: + module = "iana-ssh-key-exchange-algs"; + alg_path = "key-exchange/key-exchange-alg"; + old_path = "key-exchange"; + break; + case NC_ALG_ENCRYPTION: + module = "iana-ssh-encryption-algs"; + alg_path = "encryption/encryption-alg"; + old_path = "encryption"; + break; + case NC_ALG_MAC: + module = "iana-ssh-mac-algs"; + alg_path = "mac/mac-alg"; + old_path = "mac"; + break; + default: + ret = 1; + ERR(NULL, "Unknown algorithm type."); goto cleanup; } - ret = _nc_server_config_new_ssh_user_password(ctx, path, password, config); - if (ret) { - ERR(NULL, "Creating new user's public key failed."); - goto cleanup; + /* delete all older algorithms (if any) se they can be replaced by the new ones */ + lyd_find_path(tree, old_path, 0, &old); + if (old) { + lyd_free_tree(old); + } + + for (i = 0; i < alg_count; i++) { + alg = va_arg(ap, char *); + + asprintf(&alg_ident, "%s:%s", module, alg); + if (!alg_ident) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create the leaf list */ + ret = lyd_new_path(tree, ctx, alg_path, alg_ident, 0, NULL); + if (ret) { + ERR(NULL, "Creating new algorithm leaf-list failed."); + goto cleanup; + } + + free(alg_ident); } cleanup: - free(path); return ret; } -API int -nc_server_config_new_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) +static int +nc_server_config_new_ssh_transport_params(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + NC_ALG_TYPE alg_type, int alg_count, va_list ap, struct lyd_node **config) { int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, password, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + struct lyd_node *new_tree, *alg_tree; - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']", client_name, endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; + ret = nc_server_config_new_ssh_transport_params_prep(ctx, client_name, endpt_name, *config, &new_tree, &alg_tree); + if (ret) { goto cleanup; } - ret = _nc_server_config_new_ssh_user_password(ctx, path, password, config); + if (!*config) { + *config = new_tree; + } + + ret = nc_server_config_new_ssh_transport_params_create(ctx, alg_type, alg_count, ap, alg_tree); if (ret) { - ERR(NULL, "Creating new user's password failed."); goto cleanup; } + /* Add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } cleanup: - free(path); return ret; } API int -nc_server_config_new_ssh_del_user_password(const char *endpt_name, const char *user_name, struct lyd_node **config) +nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) { - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/password", endpt_name, user_name); -} + int ret = 0; + va_list ap; -API int -nc_server_config_new_ch_ssh_del_user_password(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/password", client_name, endpt_name, user_name); -} + va_start(ap, alg_count); -API int -nc_server_config_new_ssh_user_none(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, config, 1); + ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new hostkey algorithms failed."); + goto cleanup; + } - return nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/none", endpt_name, user_name); +cleanup: + va_end(ap); + return ret; } API int -nc_server_config_new_ch_ssh_user_none(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) +nc_server_config_new_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) { - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, config, 1); + int ret = 0; + va_list ap; - return nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/none", client_name, endpt_name, user_name); -} + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); -API int -nc_server_config_new_ssh_del_user_none(const char *endpt_name, const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + va_start(ap, alg_count); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/none", endpt_name, user_name); + ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new hostkey algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; } API int -nc_server_config_new_ch_ssh_del_user_none(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) +nc_server_config_new_ssh_del_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/none", client_name, endpt_name, user_name); + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/host-key/" + "host-key-alg[.='iana-ssh-public-key-algs:%s']", endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/host-key", endpt_name); + } } -static int -_nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *tree_path, - const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) +API int +nc_server_config_new_ch_ssh_del_host_key_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) { - int ret = 0; - - ret = nc_config_new_create_append(ctx, tree_path, "pam-config-file-name", pam_config_name, config); - if (ret) { - goto cleanup; - } + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - if (pam_config_dir) { - ret = nc_config_new_create_append(ctx, tree_path, "pam-config-file-dir", pam_config_dir, config); - if (ret) { - goto cleanup; - } + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key/" + "host-key-alg[.='iana-ssh-public-key-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key", client_name, endpt_name); } - -cleanup: - return ret; } API int -nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) +nc_server_config_new_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) { int ret = 0; - char *path = NULL; + va_list ap; - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pam_config_name, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/users/user[name='%s']/" - "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + va_start(ap, alg_count); - ret = _nc_server_config_new_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); + ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); if (ret) { - ERR(NULL, "Creating new user's keyboard interactive nodes failed."); + ERR(NULL, "Creating new key exchange algorithms failed."); goto cleanup; } cleanup: - free(path); + va_end(ap); return ret; } API int -nc_server_config_new_ch_ssh_user_interactive(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) +nc_server_config_new_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) { int ret = 0; - char *path = NULL; + va_list ap; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pam_config_name, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" - "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + va_start(ap, alg_count); - ret = _nc_server_config_new_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); + ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); if (ret) { - ERR(NULL, "Creating new user's keyboard interactive nodes failed."); + ERR(NULL, "Creating new key exchange algorithms failed."); goto cleanup; } cleanup: - free(path); + va_end(ap); return ret; } API int -nc_server_config_new_ssh_del_user_interactive(const char *endpt_name, const char *user_name, struct lyd_node **config) +nc_server_config_new_ssh_del_key_exchange_alg(const char *endpt_name, const char *alg, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/" - "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name); + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/key-exchange/" + "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/key-exchange", endpt_name); + } } API int -nc_server_config_new_ch_ssh_del_user_interactive(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) +nc_server_config_new_ch_ssh_del_key_exchange_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" - "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name); + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange/" + "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange", client_name, endpt_name); + } } API int -nc_config_new_ssh_endpoint_user_reference(const struct ly_ctx *ctx, const char *endpt_name, - const char *referenced_endpt, struct lyd_node **config) +nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) { - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); + int ret = 0; + va_list ap; - return nc_config_new_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); -} + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); -API int -nc_config_new_ssh_del_endpoint_user_reference(const char *endpt_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + va_start(ap, alg_count); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); + ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new encryption algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; } API int -nc_server_config_new_ch_ssh_keystore_reference(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) +nc_server_config_new_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) { - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, keystore_reference, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + int ret = 0; + va_list ap; - return nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); -} + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); -API int -nc_server_config_new_ch_ssh_del_keystore_reference(const char *client_name, const char *endpt_name, - const char *hostkey_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, hostkey_name, config, 1); + va_start(ap, alg_count); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); + ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new encryption algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; } API int -nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, - const char *keystore_reference, struct lyd_node **config) +nc_server_config_new_ssh_del_encryption_alg(const char *endpt_name, const char *alg, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, keystore_reference, config, 1); + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - return nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" - "keystore-reference", endpt_name, hostkey_name); + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/encryption/" + "encryption-alg[.='iana-ssh-encryption-algs:%s']", endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/encryption", endpt_name); + } } API int -nc_server_config_new_ssh_del_keystore_reference(const char *endpt_name, const char *hostkey_name, - struct lyd_node **config) +nc_server_config_new_ch_ssh_del_encryption_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" - "keystore-reference", endpt_name, hostkey_name); + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption/" + "encryption-alg[.='iana-ssh-encryption-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption", client_name, endpt_name); + } } API int -nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, - const char *truststore_reference, struct lyd_node **config) +nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) { - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, truststore_reference, config, 1); + int ret = 0; + va_list ap; - return nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" - "truststore-reference", endpt_name, user_name); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_MAC, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new mac algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; } API int -nc_server_config_new_ch_ssh_truststore_reference(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) +nc_server_config_new_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) { - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, truststore_reference, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + int ret = 0; + va_list ap; - return nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_MAC, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new mac algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; } API int -nc_server_config_new_ssh_del_truststore_reference(const char *endpt_name, const char *user_name, - struct lyd_node **config) +nc_server_config_new_ssh_del_mac_alg(const char *endpt_name, const char *alg, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" - "truststore-reference", endpt_name, user_name); + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/mac/" + "mac-alg[.='iana-ssh-mac-algs:%s']", endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/mac", endpt_name); + } } API int -nc_server_config_new_ch_ssh_del_truststore_reference(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) +nc_server_config_new_ch_ssh_del_mac_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); + if (alg) { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac/" + "mac-alg[.='iana-ssh-mac-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac", client_name, endpt_name); + } } diff --git a/src/server_config.h b/src/server_config.h index 2687a4fa..b53036ac 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -249,6 +249,36 @@ int nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const int nc_server_config_new_ssh_del_keystore_reference(const char *endpt_name, const char *hostkey_name, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes for the maximum amount of failed SSH authentication attempts. + * + * @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] auth_attempts Maximum amount of failed SSH authentication attempts after which a + * client is disconnected. The default value is 3. + * @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_new_ssh_auth_attempts(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_attempts, + struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for an SSH authentication timeout. + * + * @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] auth_timeout Maximum amount of time in seconds after which the authentication is deemed + * unsuccessful. The default value is 10. + * @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_new_ssh_auth_timeout(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_timeout, + struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for an SSH user's public key authentication method. * @@ -1064,6 +1094,40 @@ int nc_server_config_new_ch_ssh_keystore_reference(const struct ly_ctx *ctx, con int nc_server_config_new_ch_ssh_del_keystore_reference(const char *client_name, const char *endpt_name, const char *hostkey_name, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes for the maximum amount of failed Call-Home SSH authentication attempts. + * + * @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] auth_attempts Maximum amount of failed SSH authentication attempts after which a + * client is disconnected. The default value is 3. + * @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_new_ch_ssh_auth_attempts(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + uint16_t auth_attempts, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call-Home SSH authentication timeout. + * + * @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] auth_timeout Maximum amount of time in seconds after which the authentication is deemed + * unsuccessful. The default value is 10. + * @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_new_ch_ssh_auth_timeout(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + uint16_t auth_timeout, struct lyd_node **config); + /** * @brief Creates new YANG data nodes for a Call-Home SSH user's public key authentication method. * From b3324d44d305435f72739a1a9c10f5a4188ece70 Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 24 Jul 2023 11:03:52 +0200 Subject: [PATCH 050/134] config UPDATE add missing CH augments to module --- modules/libnetconf2-netconf-server.yang | 75 ++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/modules/libnetconf2-netconf-server.yang b/modules/libnetconf2-netconf-server.yang index 07535228..8c62b9bd 100644 --- a/modules/libnetconf2-netconf-server.yang +++ b/modules/libnetconf2-netconf-server.yang @@ -254,20 +254,43 @@ module libnetconf2-netconf-server { } // CH auth-attempts and auth-timeout - augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { + augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ + ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { leaf auth-attempts { type uint16; default 3; + description + "Represents the number of failed attempts before an authentication is deemed unsuccessful."; } leaf auth-timeout { type uint16; default 10; units "seconds"; + description + "Represents the maximum amount of seconds an authentication can go on for."; + } + } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ + ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" { + container keyboard-interactive { + presence ""; + leaf pam-config-file-name { + type string; + mandatory true; + } + leaf pam-config-file-dir { + type string; + } + description + "Keyboard interactive SSH authentication method."; } } - augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" { + // CH KB int + augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ + ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" { container keyboard-interactive { presence ""; leaf pam-config-file-name { @@ -277,10 +300,14 @@ module libnetconf2-netconf-server { leaf pam-config-file-dir { type string; } + description + "Keyboard interactive SSH authentication method."; } } augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport" { + description + "Defines a new transport called UNIX socket."; case unix-socket { container unix-socket { leaf path { @@ -373,4 +400,48 @@ module libnetconf2-netconf-server { } } } + + // CH CRL + augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ + ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { + description + "Indicates that the Call Home TLS server is using a Certificate Revocation List + to authenticate clients or to deny access for certain certificates. + The given Certificate Revocation List must be PEM or DER encoded."; + + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile"; + + choice certificate-revocation-list { + leaf crl-url { + type string; + description + "An URL from which the Certificate Revocation List will be + downloaded and used. The HTTP protocol works, but other + protocols, such as FTP, may work as well."; + } + + leaf crl-path { + type string; + description + "A path to a Certificate Revocation List file."; + } + + leaf crl-cert-ext { + type empty; + description + "Indicates that the Certificate Revocation List + Distribution Points extension will be used to fetch + Certificate Revocation Lists from. This will be done + for all the configured Certificate Authority certificates."; + + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile, Section 4.2.1.13"; + } + } + } } From e51a48306d1b89af16027aa746796c292dbb5674 Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 26 Jul 2023 13:39:30 +0200 Subject: [PATCH 051/134] config UPDATE add TLS keystore and truststore --- src/config_new.c | 111 +++++++++++++++++++---- src/config_new_tls.c | 70 +++++++++++++++ src/server_config.h | 153 +++++++++++++++++++++++++++++--- tests/test_ks_ts.c | 204 +++++++++++++++++++++++++++---------------- 4 files changed, 437 insertions(+), 101 deletions(-) diff --git a/src/config_new.c b/src/config_new.c index 8cea603c..4cefadf6 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -911,7 +911,7 @@ nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt_nam } API int -nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *name, const char *privkey_path, +nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *asym_key_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config) { int ret = 0; @@ -920,7 +920,7 @@ nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *nam NC_PUBKEY_FORMAT pubkey_type; const char *privkey_format, *pubkey_format; - NC_CHECK_ARG_RET(NULL, ctx, name, privkey_path, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, asym_key_name, privkey_path, config, 1); /* get the keys as a string from the given files */ ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); @@ -944,25 +944,25 @@ nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *nam } ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/public-key-format", name); + "asymmetric-key[name='%s']/public-key-format", asym_key_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, pubkey, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/public-key", name); + "asymmetric-key[name='%s']/public-key", asym_key_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/private-key-format", name); + "asymmetric-key[name='%s']/private-key-format", asym_key_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, privkey, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/cleartext-private-key", name); + "asymmetric-key[name='%s']/cleartext-private-key", asym_key_name); if (ret) { goto cleanup; } @@ -974,19 +974,56 @@ nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *nam } API int -nc_server_config_new_del_keystore_asym_key(const char *name, struct lyd_node **config) +nc_server_config_new_del_keystore_asym_key(const char *asym_key_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, config, 1); - if (name) { - return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']", name); + if (asym_key_name) { + return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']", asym_key_name); } else { return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key"); } } API int -nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag_name, const char *pubkey_name, +nc_server_config_new_keystore_cert(const struct ly_ctx *ctx, const char *asym_key_name, const char *cert_name, + const char *cert_path, struct lyd_node **config) +{ + int ret = 0; + char *cert = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, asym_key_name, cert_name, cert_path, config, 1); + + /* get cert data */ + ret = nc_server_config_new_read_certificate(cert_path, &cert); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, cert, "/ietf-keystore:keystore/asymmetric-keys/" + "asymmetric-key[name='%s']/certificates/certificate[name='%s']/cert-data", asym_key_name, cert_name); + +cleanup: + free(cert); + return ret; +} + +API int +nc_server_config_new_del_keystore_cert(const char *asym_key_name, const char *cert_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, asym_key_name, config, 1); + + if (cert_name) { + return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/" + "certificates/certificate[name='%s']", asym_key_name, cert_name); + } else { + return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/" + "certificates/certificate", asym_key_name); + } +} + +API int +nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *pub_bag_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config) { int ret = 0; @@ -994,7 +1031,7 @@ nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag NC_PUBKEY_FORMAT pubkey_format; const char *format; - NC_CHECK_ARG_RET(NULL, ctx, bag_name, pubkey_name, pubkey_path, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, pub_bag_name, pubkey_name, pubkey_path, config, 1); ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_format); if (ret) { @@ -1009,13 +1046,13 @@ nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag } ret = nc_config_new_create(ctx, config, format, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", bag_name, pubkey_name); + "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", pub_bag_name, pubkey_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, pubkey, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key[name='%s']/public-key", bag_name, pubkey_name); + "public-key-bag[name='%s']/public-key[name='%s']/public-key", pub_bag_name, pubkey_name); if (ret) { goto cleanup; } @@ -1026,17 +1063,57 @@ nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag } API int -nc_server_config_new_del_truststore_pubkey(const char *bag_name, +nc_server_config_new_del_truststore_pubkey(const char *pub_bag_name, const char *pubkey_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, bag_name, config, 1); + NC_CHECK_ARG_RET(NULL, pub_bag_name, config, 1); if (pubkey_name) { return nc_config_new_delete(config, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key[name='%s']", bag_name, pubkey_name); + "public-key-bag[name='%s']/public-key[name='%s']", pub_bag_name, pubkey_name); } else { return nc_config_new_delete(config, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key", bag_name); + "public-key-bag[name='%s']/public-key", pub_bag_name); + } +} + +API int +nc_server_config_new_truststore_cert(const struct ly_ctx *ctx, const char *cert_bag_name, const char *cert_name, + const char *cert_path, struct lyd_node **config) +{ + int ret = 0; + char *cert = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, cert_bag_name, cert_name, cert_path, config, 1); + + ret = nc_server_config_new_read_certificate(cert_path, &cert); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, cert, "/ietf-truststore:truststore/certificate-bags/" + "certificate-bag[name='%s']/certificate[name='%s']/cert-data", cert_bag_name, cert_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(cert); + return ret; +} + +API int +nc_server_config_new_del_truststore_cert(const char *cert_bag_name, + const char *cert_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, cert_bag_name, config, 1); + + if (cert_name) { + return nc_config_new_delete(config, "/ietf-truststore:truststore/certificate-bags/" + "certificate-bag[name='%s']/certificate[name='%s']", cert_bag_name, cert_name); + } else { + return nc_config_new_delete(config, "/ietf-truststore:truststore/certificate-bags/" + "certificate-bag[name='%s']/certificate", cert_bag_name); } } diff --git a/src/config_new_tls.c b/src/config_new_tls.c index 1ba72ddf..d80af8a2 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -181,6 +181,38 @@ nc_server_config_new_ch_tls_del_server_certificate(const char *client_name, cons "certificate/inline-definition", client_name, endpt_name); } +API int +nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *asym_key_ref, + const char *cert_ref, struct lyd_node **config) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, asym_key_ref, cert_ref, config, 1); + + /* create asymmetric key pair reference */ + ret = nc_config_new_create(ctx, config, asym_key_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/keystore-reference/asymmetric-key", endpt_name); + if (ret) { + goto cleanup; + } + + /* create cert reference, this cert has to belong to the asym key */ + ret = nc_config_new_create(ctx, config, cert_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/keystore-reference/certificate", endpt_name); + +cleanup: + return ret; +} + +API int +nc_server_config_new_tls_del_keystore_reference(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/keystore-reference", endpt_name); +} + static int _nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *cert_path, struct lyd_node **config) @@ -295,6 +327,25 @@ nc_server_config_new_ch_tls_del_client_certificate(const char *client_name, cons } } +API int +nc_server_config_new_tls_client_cert_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, + const char *cert_bag_ref, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1); + + return nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/truststore-reference", endpt_name); +} + +API int +nc_server_config_new_tls_del_client_cert_truststore_ref(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/truststore-reference", endpt_name); +} + API int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, const char *cert_path, struct lyd_node **config) @@ -386,6 +437,25 @@ nc_server_config_new_ch_tls_del_client_ca(const char *client_name, const char *e } } +API int +nc_server_config_new_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, + const char *cert_bag_ref, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1); + + return nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/truststore-reference", endpt_name); +} + +API int +nc_server_config_new_tls_del_client_ca_truststore_ref(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/truststore-reference", endpt_name); +} + static const char * nc_config_new_tls_maptype2str(NC_TLS_CTN_MAPTYPE map_type) { diff --git a/src/server_config.h b/src/server_config.h index b53036ac..34562915 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -126,8 +126,8 @@ int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **con * @brief Creates new YANG data nodes for an asymmetric key in the keystore. * * @param[in] ctx libyang context. - * @param[in] name Name of the asymmetric key pair. - * This name is used to reference the key pair. + * @param[in] asym_key_name Identifier of the asymmetric key pair. + * This identifier is used to reference the key pair. * @param[in] privkey_path Path to a private key file. * @param[in] pubkey_path Optional path a public key file. * If not supplied, it will be generated from the private key. @@ -135,46 +135,109 @@ int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **con * 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_new_keystore_asym_key(const struct ly_ctx *ctx, const char *name, const char *privkey_path, +int nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *asym_key_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config); /** * @brief Deletes a keystore's asymmetric key from the YANG data. * - * @param[in] name Optional identifier of the asymmetric key to be deleted. + * @param[in] asym_key_name Optional identifier of the asymmetric key to be deleted. * If NULL, all of the asymmetric keys in the keystore will be deleted. * @param[in,out] config Configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_del_keystore_asym_key(const char *name, struct lyd_node **config); +int nc_server_config_new_del_keystore_asym_key(const char *asym_key_name, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a certificate in the keystore. + * + * A certificate can not exist without its asymmetric key, so you must call ::nc_server_config_new_keystore_asym_key() + * either before or after calling this with the same identifier for the asymmetric key. + * + * An asymmetric key pair can have zero or more certificates associated with this key pair, however a certificate must + * have exactly one key pair it belongs to. + * + * @param[in] ctx libyang context. + * @param[in] asym_key_name Arbitrary identifier of the asymmetric key. + * If an asymmetric key pair with this name already exists, its contents will be changed. + * @param[in] cert_name Arbitrary identifier of the key pair's certificate. + * If a certificate with this name already exists, its contents will be changed. + * @param[in] cert_path Path to the PEM encoded 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_new_keystore_cert(const struct ly_ctx *ctx, const char *asym_key_name, const char *cert_name, + const char *cert_path, struct lyd_node **config); + +/** + * @brief Deletes a keystore's certificate from the YANG data. + * + * @param[in] asym_key_name Identifier of an existing asymmetric key pair. + * @param[in] cert_name Optional identifier of a certificate to be deleted. + * If NULL, all of the certificates belonging to the asymmetric key pair will be deleted. + * @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_new_del_keystore_cert(const char *asym_key_name, const char *cert_name, struct lyd_node **config); /** * @brief Creates new YANG data nodes for a public key in the truststore. * * @param[in] ctx libyang context. - * @param[in] bag_name Arbitrary identifier of the public key bag. + * @param[in] pub_bag_name Arbitrary identifier of the public key bag. * This name is used to reference the public keys in the bag. * If a public key bag with this name already exists, its contents will be changed. * @param[in] pubkey_name Arbitrary identifier of the public key. - * If a public key with this name already exists, its contents will be changed. + * If a public key with this name already exists in the given bag, 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_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag_name, const char *pubkey_name, +int nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *pub_bag_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config); /** * @brief Deletes a truststore's public key from the YANG data. * - * @param[in] bag_name Identifier of an existing public key bag. + * @param[in] pub_bag_name Identifier of an existing public key bag. * @param[in] pubkey_name Optional identifier of a public key to be deleted. * If NULL, all of the public keys in the given bag will be deleted. * @param[in,out] config Configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_del_truststore_pubkey(const char *bag_name, const char *pubkey_name, struct lyd_node **config); +int nc_server_config_new_del_truststore_pubkey(const char *pub_bag_name, const char *pubkey_name, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a certificate in the truststore. + * + * @param[in] ctx libyang context. + * @param[in] cert_bag_name Arbitrary identifier of the certificate bag. + * This name is used to reference the certificates in the bag. + * If a certificate bag with this name already exists, its contents will be changed. + * @param[in] cert_name Arbitrary identifier of the certificate. + * If a certificate with this name already exists in the given bag, its contents will be changed. + * @param[in] cert_path Path to a file containing a PEM encoded certificate. + * @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_new_truststore_cert(const struct ly_ctx *ctx, const char *cert_bag_name, const char *cert_name, + const char *cert_path, struct lyd_node **config); + +/** + * @brief Deletes a truststore's certificate from the YANG data. + * + * @param[in] cert_bag_name Identifier of an existing certificate bag. + * @param[in] cert_name Optional identifier of a certificate to be deleted. + * If NULL, all of the certificates in the given bag will be deleted. + * @param[in,out] config Configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_del_truststore_cert(const char *cert_bag_name, + const char *cert_name, struct lyd_node **config); /** * @} @@ -615,6 +678,30 @@ int nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const */ int nc_server_config_new_tls_del_server_certificate(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_new_tls_keystore_reference(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. + */ +int nc_server_config_new_tls_del_keystore_reference(const char *endpt_name, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a client's (end-entity) certificate. * @@ -642,6 +729,29 @@ int nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const */ int nc_server_config_new_tls_del_client_certificate(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_new_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. + */ +int nc_server_config_new_tls_del_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. * @@ -669,6 +779,29 @@ int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *end */ int nc_server_config_new_tls_del_client_ca(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_new_tls_client_ca_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. + */ +int nc_server_config_new_tls_del_client_ca_truststore_ref(const char *endpt_name, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a cert-to-name entry. * diff --git a/tests/test_ks_ts.c b/tests/test_ks_ts.c index fb179e06..2d125fad 100644 --- a/tests/test_ks_ts.c +++ b/tests/test_ks_ts.c @@ -36,75 +36,6 @@ struct test_state { pthread_barrier_t barrier; }; -const char *data = - "\n" - " \n" - " 10\n" - " \n" - " default-ssh\n" - " \n" - " \n" - " 127.0.0.1\n" - " 10005\n" - " \n" - " \n" - " \n" - " \n" - " key\n" - " \n" - " test_keystore\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " test_ts\n" - " \n" - " \n" - " \n" - " test\n" - " ct:ssh-public-key-format\n" - " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " sshpka:rsa-sha2-512\n" - " \n" - " \n" - " sshkea:curve25519-sha256\n" - " \n" - " \n" - " sshea:aes256-ctr\n" - " \n" - " \n" - " sshma:hmac-sha2-512\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n" - "\n" - "\n" - " \n" - " \n" - " test_keystore\n" - " ct:ssh-public-key-format\n" - " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" - " ct:rsa-private-key-format\n" - " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" - " \n" - " \n" - "\n"; - static void * server_thread(void *arg) { @@ -136,7 +67,7 @@ server_thread(void *arg) } static void * -client_thread(void *arg) +client_thread_ssh(void *arg) { int ret; struct nc_session *session = NULL; @@ -163,14 +94,14 @@ client_thread(void *arg) } static void -test_nc_ks_ts(void **state) +test_nc_ks_ts_ssh(void **state) { int ret, i; pthread_t tids[2]; assert_non_null(state); - ret = pthread_create(&tids[0], NULL, client_thread, *state); + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); assert_int_equal(ret, 0); ret = pthread_create(&tids[1], NULL, server_thread, *state); assert_int_equal(ret, 0); @@ -181,7 +112,7 @@ test_nc_ks_ts(void **state) } static int -setup_f(void **state) +setup_ssh(void **state) { int ret; struct lyd_node *tree = NULL; @@ -234,6 +165,130 @@ setup_f(void **state) return 0; } +static void * +client_thread_tls(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set client cert */ + ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key"); + assert_int_equal(ret, 0); + + /* set client ca */ + ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_tls("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + return NULL; +} + +static void +test_nc_ks_ts_tls(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread_tls, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_tls(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + /* new ctx */ + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* init ctx */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf netconf server module and its requisities */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* new tls bind */ + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", 10005, &tree); + assert_int_equal(ret, 0); + + /* new keystore asym key pair */ + ret = nc_server_config_new_keystore_asym_key(ctx, "server_key", TESTS_DIR "/data/server.key", NULL, &tree); + assert_int_equal(ret, 0); + + /* new keystore cert belonging to the key pair */ + ret = nc_server_config_new_keystore_cert(ctx, "server_key", "server_cert", TESTS_DIR "/data/server.crt", &tree); + assert_int_equal(ret, 0); + + /* new truststore client cert */ + ret = nc_server_config_new_truststore_cert(ctx, "ee_cert_bag", "ee_cert", TESTS_DIR "/data/client.crt", &tree); + assert_int_equal(ret, 0); + + /* new truststore client CA cert */ + ret = nc_server_config_new_truststore_cert(ctx, "ca_cert_bag", "ca_cert", TESTS_DIR "/data/serverca.pem", &tree); + assert_int_equal(ret, 0); + + /* new keystore ref for the TLS server cert */ + ret = nc_server_config_new_tls_keystore_reference(ctx, "endpt", "server_key", "server_cert", &tree); + assert_int_equal(ret, 0); + + /* new truststore ref for the client cert */ + ret = nc_server_config_new_tls_client_cert_truststore_ref(ctx, "endpt", "ee_cert_bag", &tree); + assert_int_equal(ret, 0); + + /* new truststore ref for the client CA cert */ + ret = nc_server_config_new_tls_client_ca_truststore_ref(ctx, "endpt", "ca_cert_bag", &tree); + assert_int_equal(ret, 0); + + /* new cert-to-name */ + ret = nc_server_config_new_tls_ctn(ctx, "endpt", 1, + "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", + NC_TLS_CTN_SPECIFIED, "client", &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup_data(tree); + assert_int_equal(ret, 0); + + ret = nc_server_init(); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + static int teardown_f(void **state) { @@ -258,7 +313,8 @@ int main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_nc_ks_ts, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_ks_ts_ssh, setup_ssh, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_ks_ts_tls, setup_tls, teardown_f), }; setenv("CMOCKA_TEST_ABORT", "1", 1); From ecab07f345a6e04db8664bc1bc304c55738a2c01 Mon Sep 17 00:00:00 2001 From: Roytak Date: Thu, 27 Jul 2023 12:04:18 +0200 Subject: [PATCH 052/134] config UPDATE CH TLS keystore and truststore --- src/config_new_tls.c | 124 ++++++++++++++++++++++++++++++++++++++++--- src/server_config.h | 86 +++++++++++++++++++++++++++++- 2 files changed, 201 insertions(+), 9 deletions(-) diff --git a/src/config_new_tls.c b/src/config_new_tls.c index d80af8a2..d1e9f812 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -181,26 +181,52 @@ nc_server_config_new_ch_tls_del_server_certificate(const char *client_name, cons "certificate/inline-definition", client_name, endpt_name); } +static int +_nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const char *tree_path, const char *asym_key_ref, + const char *cert_ref, struct lyd_node **config) +{ + int ret = 0; + + /* create asymmetric key pair reference */ + ret = nc_config_new_create_append(ctx, tree_path, "asymmetric-key", asym_key_ref, config); + if (ret) { + goto cleanup; + } + + /* create cert reference, this cert has to belong to the asym key */ + ret = nc_config_new_create_append(ctx, tree_path, "certificate", cert_ref, config); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + API int nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *asym_key_ref, const char *cert_ref, struct lyd_node **config) { int ret = 0; + char *path = NULL; NC_CHECK_ARG_RET(NULL, ctx, endpt_name, asym_key_ref, cert_ref, config, 1); - /* create asymmetric key pair reference */ - ret = nc_config_new_create(ctx, config, asym_key_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/keystore-reference/asymmetric-key", endpt_name); - if (ret) { + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/keystore-reference", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; goto cleanup; } - /* create cert reference, this cert has to belong to the asym key */ - ret = nc_config_new_create(ctx, config, cert_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/keystore-reference/certificate", endpt_name); + ret = _nc_server_config_new_tls_keystore_reference(ctx, path, asym_key_ref, cert_ref, config); + if (ret) { + goto cleanup; + } cleanup: + free(path); return ret; } @@ -213,6 +239,46 @@ nc_server_config_new_tls_del_keystore_reference(const char *endpt_name, struct l "tls/tls-server-parameters/server-identity/certificate/keystore-reference", endpt_name); } +API int +nc_server_config_new_ch_tls_keystore_reference(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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, asym_key_ref, cert_ref, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate/" + "keystore-reference", client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_new_tls_keystore_reference(ctx, path, asym_key_ref, cert_ref, config); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_new_ch_tls_del_keystore_reference(const char *client_name, const char *endpt_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate/" + "keystore-reference", client_name, endpt_name); +} + static int _nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *cert_path, struct lyd_node **config) @@ -346,6 +412,28 @@ nc_server_config_new_tls_del_client_cert_truststore_ref(const char *endpt_name, "tls-server-parameters/client-authentication/ee-certs/truststore-reference", endpt_name); } +API int +nc_server_config_new_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) +{ + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_bag_ref, config, 1); + + return nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/truststore-reference", client_name, endpt_name); +} + +API int +nc_server_config_new_ch_tls_del_client_cert_truststore_ref(const char *client_name, const char *endpt_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/truststore-reference", client_name, endpt_name); +} + API int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, const char *cert_path, struct lyd_node **config) @@ -456,6 +544,28 @@ nc_server_config_new_tls_del_client_ca_truststore_ref(const char *endpt_name, st "tls-server-parameters/client-authentication/ca-certs/truststore-reference", endpt_name); } +API int +nc_server_config_new_ch_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *client_name, + const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_bag_ref, config, 1); + + return nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/truststore-reference", client_name, endpt_name); +} + +API int +nc_server_config_new_ch_tls_del_client_ca_truststore_ref(const char *client_name, const char *endpt_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/truststore-reference", client_name, endpt_name); +} + static const char * nc_config_new_tls_maptype2str(NC_TLS_CTN_MAPTYPE map_type) { diff --git a/src/server_config.h b/src/server_config.h index 34562915..daeb8226 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -1587,7 +1587,7 @@ int nc_server_config_new_ch_ssh_del_mac_alg(const char *client_name, const char * it will be generated from the private key. * @param[in] privkey_path Path to the server's private key file. * @param[in] certificate_path Path to the server's certificate file. - * @param config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1605,6 +1605,34 @@ int nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, con int nc_server_config_new_ch_tls_del_server_certificate(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_new_ch_tls_keystore_reference(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. + */ +int nc_server_config_new_ch_tls_del_keystore_reference(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. * @@ -1616,7 +1644,7 @@ int nc_server_config_new_ch_tls_del_server_certificate(const char *client_name, * @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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1636,6 +1664,33 @@ int nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, con int nc_server_config_new_ch_tls_del_client_certificate(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_new_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. + */ +int nc_server_config_new_ch_tls_del_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. * @@ -1667,6 +1722,33 @@ int nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char * int nc_server_config_new_ch_tls_del_client_ca(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_new_ch_tls_client_ca_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. + */ +int nc_server_config_new_ch_tls_del_client_ca_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. * From b1cf22debb420d1fd8cc6c3facb448cdf1a8cf25 Mon Sep 17 00:00:00 2001 From: Roytak Date: Thu, 27 Jul 2023 12:56:01 +0200 Subject: [PATCH 053/134] config UPDATE delete choice trees on data creation --- src/config_new_ssh.c | 142 ++++++++++++++++++++++++++++++++++--------- src/config_new_tls.c | 135 +++++++++++++++++++++++++++++++++++----- 2 files changed, 233 insertions(+), 44 deletions(-) diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index 6f09c928..290b70cd 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -65,22 +65,28 @@ _nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *tree_pat goto cleanup; } - ret = nc_config_new_create_append(ctx, tree_path, "public-key-format", pubkey_format, config); + ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/public-key-format", pubkey_format, config); if (ret) { goto cleanup; } - ret = nc_config_new_create_append(ctx, tree_path, "public-key", pubkey, config); + ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/public-key", pubkey, config); if (ret) { goto cleanup; } - ret = nc_config_new_create_append(ctx, tree_path, "private-key-format", privkey_format, config); + ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/private-key-format", privkey_format, config); if (ret) { goto cleanup; } - ret = nc_config_new_create_append(ctx, tree_path, "cleartext-private-key", privkey, config); + ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/cleartext-private-key", privkey, config); + if (ret) { + goto cleanup; + } + + /* delete keystore choice nodes if present */ + ret = nc_config_new_check_delete(config, "%s/keystore-reference", tree_path); if (ret) { goto cleanup; } @@ -101,7 +107,7 @@ nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_nam NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, privkey_path, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "server-identity/host-key[name='%s']/public-key/inline-definition", endpt_name, hostkey_name) == -1) { + "server-identity/host-key[name='%s']/public-key", endpt_name, hostkey_name) == -1) { ERRMEM; path = NULL; ret = 1; @@ -131,7 +137,7 @@ nc_server_config_new_ch_ssh_hostkey(const struct ly_ctx *ctx, const char *client if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/inline-definition", client_name, endpt_name, hostkey_name) == -1) { + "host-key[name='%s']/public-key", client_name, endpt_name, hostkey_name) == -1) { ERRMEM; path = NULL; ret = 1; @@ -182,37 +188,58 @@ nc_server_config_new_ch_ssh_del_hostkey(const char *client_name, const char *end } API int -nc_server_config_new_ch_ssh_keystore_reference(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) +nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, + const char *keystore_reference, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, keystore_reference, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + int ret = 0; - return nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, keystore_reference, config, 1); + + ret = nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" + "keystore-reference", endpt_name, hostkey_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition nodes if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" + "inline-definition", endpt_name, hostkey_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; } API int -nc_server_config_new_ch_ssh_del_keystore_reference(const char *client_name, const char *endpt_name, - const char *hostkey_name, struct lyd_node **config) +nc_server_config_new_ch_ssh_keystore_reference(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) { - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, hostkey_name, config, 1); + int ret = 0; - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, keystore_reference, 1); + NC_CHECK_ARG_RET(NULL, config, 1); + + ret = nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); -} + if (ret) { + goto cleanup; + } -API int -nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, - const char *keystore_reference, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, keystore_reference, config, 1); + /* delete inline definition nodes if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/inline-definition", client_name, endpt_name, hostkey_name); + if (ret) { + goto cleanup; + } - return nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" - "keystore-reference", endpt_name, hostkey_name); +cleanup: + return ret; } API int @@ -226,6 +253,17 @@ nc_server_config_new_ssh_del_keystore_reference(const char *endpt_name, const ch "keystore-reference", endpt_name, hostkey_name); } +API int +nc_server_config_new_ch_ssh_del_keystore_reference(const char *client_name, const char *endpt_name, + const char *hostkey_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, hostkey_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); +} + API int nc_server_config_new_ssh_auth_attempts(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_attempts, struct lyd_node **config) @@ -390,6 +428,14 @@ nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *endpt goto cleanup; } + /* delete truststore reference if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/truststore-reference", + endpt_name, user_name); + if (ret) { + goto cleanup; + } + cleanup: free(path); return ret; @@ -421,6 +467,14 @@ nc_server_config_new_ch_ssh_user_pubkey(const struct ly_ctx *ctx, const char *cl goto cleanup; } + /* delete truststore reference if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" + "public-keys/truststore-reference", client_name, endpt_name, user_name); + if (ret) { + goto cleanup; + } + cleanup: free(path); return ret; @@ -773,23 +827,55 @@ API int nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *truststore_reference, struct lyd_node **config) { + int ret = 0; + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, truststore_reference, config, 1); - return nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/listen/" + ret = nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/listen/" "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" "truststore-reference", endpt_name, user_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition nodes if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition", + endpt_name, user_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; } API int nc_server_config_new_ch_ssh_truststore_reference(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) { + int ret = 0; + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, truststore_reference, 1); NC_CHECK_ARG_RET(NULL, config, 1); - return nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/call-home/" + ret = nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition nodes if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" + "public-keys/inline-definition", client_name, endpt_name, user_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; } API int diff --git a/src/config_new_tls.c b/src/config_new_tls.c index d1e9f812..8e9cb9d5 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -69,27 +69,33 @@ _nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const cha goto cleanup; } - ret = nc_config_new_create_append(ctx, tree_path, "public-key-format", pubkey_format, config); + ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/public-key-format", pubkey_format, config); if (ret) { goto cleanup; } - ret = nc_config_new_create_append(ctx, tree_path, "public-key", pubkey, config); + ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/public-key", pubkey, config); if (ret) { goto cleanup; } - ret = nc_config_new_create_append(ctx, tree_path, "private-key-format", privkey_format, config); + ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/private-key-format", privkey_format, config); if (ret) { goto cleanup; } - ret = nc_config_new_create_append(ctx, tree_path, "cleartext-private-key", privkey, config); + ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/cleartext-private-key", privkey, config); if (ret) { goto cleanup; } - ret = nc_config_new_create_append(ctx, tree_path, "cert-data", cert, config); + ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/cert-data", cert, config); + if (ret) { + goto cleanup; + } + + /* delete keystore if present */ + ret = nc_config_new_check_delete(config, "%s/keystore-reference", tree_path); if (ret) { goto cleanup; } @@ -111,7 +117,7 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, certificate_path, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition", endpt_name) == -1) { + "tls/tls-server-parameters/server-identity/certificate", endpt_name) == -1) { ERRMEM; path = NULL; ret = 1; @@ -151,7 +157,7 @@ nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const c if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" - "certificate/inline-definition", client_name, endpt_name) == -1) { + "certificate", client_name, endpt_name) == -1) { ERRMEM; path = NULL; ret = 1; @@ -188,13 +194,19 @@ _nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const cha int ret = 0; /* create asymmetric key pair reference */ - ret = nc_config_new_create_append(ctx, tree_path, "asymmetric-key", asym_key_ref, config); + ret = nc_config_new_create_append(ctx, tree_path, "keystore-reference/asymmetric-key", asym_key_ref, config); if (ret) { goto cleanup; } /* create cert reference, this cert has to belong to the asym key */ - ret = nc_config_new_create_append(ctx, tree_path, "certificate", cert_ref, config); + ret = nc_config_new_create_append(ctx, tree_path, "keystore-reference/certificate", cert_ref, config); + if (ret) { + goto cleanup; + } + + /* delete inline definition if present */ + ret = nc_config_new_check_delete(config, "%s/inline-definition", tree_path); if (ret) { goto cleanup; } @@ -213,7 +225,7 @@ nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const char NC_CHECK_ARG_RET(NULL, ctx, endpt_name, asym_key_ref, cert_ref, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/keystore-reference", endpt_name) == -1) { + "tls/tls-server-parameters/server-identity/certificate", endpt_name) == -1) { ERRMEM; path = NULL; ret = 1; @@ -250,8 +262,7 @@ nc_server_config_new_ch_tls_keystore_reference(const struct ly_ctx *ctx, const c NC_CHECK_ARG_RET(NULL, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate/" - "keystore-reference", client_name, endpt_name) == -1) { + "endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate", client_name, endpt_name) == -1) { ERRMEM; path = NULL; ret = 1; @@ -325,6 +336,13 @@ nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char goto cleanup; } + /* delete truststore if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/truststore-reference", endpt_name); + if (ret) { + goto cleanup; + } + cleanup: free(path); return ret; @@ -371,6 +389,14 @@ nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, const c goto cleanup; } + /* delete truststore if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/truststore-reference", client_name, endpt_name); + if (ret) { + goto cleanup; + } + cleanup: free(path); return ret; @@ -397,10 +423,25 @@ API int nc_server_config_new_tls_client_cert_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config) { + int ret = 0; + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1); - return nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + ret = nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" "tls-server-parameters/client-authentication/ee-certs/truststore-reference", endpt_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/inline-definition", endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; } API int @@ -416,11 +457,27 @@ API int nc_server_config_new_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) { + int ret = 0; + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_bag_ref, config, 1); - return nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/" + ret = nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" "client-authentication/ee-certs/truststore-reference", client_name, endpt_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/inline-definition", client_name, endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; } API int @@ -457,6 +514,13 @@ nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_n goto cleanup; } + /* delete truststore if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/truststore-reference", endpt_name); + if (ret) { + goto cleanup; + } + cleanup: free(path); return ret; @@ -503,6 +567,14 @@ nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char *clie goto cleanup; } + /* delete truststore if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/truststore-reference", client_name, endpt_name); + if (ret) { + goto cleanup; + } + cleanup: free(path); return ret; @@ -529,10 +601,25 @@ API int nc_server_config_new_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config) { + int ret = 0; + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1); - return nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + ret = nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" "tls-server-parameters/client-authentication/ca-certs/truststore-reference", endpt_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/inline-definition", endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; } API int @@ -548,11 +635,27 @@ API int nc_server_config_new_ch_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config) { + int ret = 0; + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_bag_ref, config, 1); - return nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/" + ret = nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" "client-authentication/ca-certs/truststore-reference", client_name, endpt_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition if present */ + ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/inline-definition", client_name, endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; } API int From dcd89a89f7920cb702d0ad2751634f70ce4f3aba Mon Sep 17 00:00:00 2001 From: Roytak Date: Tue, 1 Aug 2023 22:18:27 +0200 Subject: [PATCH 054/134] config BUGFIX fix inserting CTNs --- src/server_config.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index ef36b735..7ffaad87 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -3691,14 +3691,14 @@ nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_serv if (!opts->ctn) { /* inserting the first one */ opts->ctn = new; - } else if (opts->ctn->id > new->id) { + } else if (opts->ctn->id > id) { /* insert at the beginning */ new->next = opts->ctn; opts->ctn = new; } else { /* have to find the right place */ - for (iter = opts->ctn; iter->next && iter->next->id <= new->id; iter = iter->next) {} - if (iter->id == new->id) { + for (iter = opts->ctn; iter->next && iter->next->id <= id; iter = iter->next) {} + if (iter->id == id) { /* collision */ new = iter; } else { From 45532c4e0ae5edacd6729ea3fae220d72e66da2c Mon Sep 17 00:00:00 2001 From: Roytak Date: Wed, 2 Aug 2023 15:04:42 +0200 Subject: [PATCH 055/134] docs UPDATE use only 'Call Home' --- src/server_config.h | 370 ++++++++++++++++++++++---------------------- 1 file changed, 185 insertions(+), 185 deletions(-) diff --git a/src/server_config.h b/src/server_config.h index daeb8226..4a9a17bd 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -979,19 +979,19 @@ int nc_config_new_tls_del_endpoint_client_reference(const char *endpt_name, stru */ /** - * @defgroup server_config_ch Call-Home server Configuration + * @defgroup server_config_ch Call Home server Configuration * @ingroup server_config * - * @brief Call-Home server configuration creation and deletion + * @brief Call Home server configuration creation and deletion * @{ */ /** - * @brief Creates new YANG configuration data nodes for a call-home client's address and port. + * @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] 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. @@ -1007,19 +1007,19 @@ int nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *c #endif /* NC_ENABLED_SSH_TLS */ /** - * @brief Deletes a Call-Home client from the YANG data. + * @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. + * 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. */ int nc_server_config_new_del_ch_client(const char *client_name, struct lyd_node **config); /** - * @brief Deletes a Call-Home endpoint from the YANG data. + * @brief Deletes a Call Home endpoint from the YANG data. * - * @param[in] client_name Identifier of an existing Call-Home client. + * @param[in] client_name Identifier of an existing Call Home client. * @param[in] endpt_name Optional identifier of a CH endpoint to be deleted. * If NULL, all of the CH endpoints which belong to the given client will be deleted. * @param[in,out] config Modified configuration YANG data tree. @@ -1028,13 +1028,13 @@ int nc_server_config_new_del_ch_client(const char *client_name, struct lyd_node int nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for the call-home persistent connection type. + * @brief Creates new YANG configuration data nodes for the Call Home persistent connection type. * * This is the default connection type. If periodic connection type was set before, it will be unset. * * @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] 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 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. @@ -1042,13 +1042,13 @@ int nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt int nc_server_config_new_ch_persistent(const struct ly_ctx *ctx, const char *client_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for the period parameter of the call-home periodic connection type. + * @brief Creates new YANG configuration data nodes for the period parameter of the Call Home periodic connection type. * * If called, the persistent connection type will be replaced by periodic. * * @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] 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] period Duration between periodic connections in minutes. * @param 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. @@ -1058,24 +1058,24 @@ int nc_server_config_new_ch_period(const struct ly_ctx *ctx, const char *client_ struct lyd_node **config); /** - * @brief Deletes the Call-Home period parameter of the periodic connection type from the YANG data. + * @brief Deletes the Call Home period parameter of the periodic connection type from the YANG data. * * This behaves the same as setting the period to 60 minutes, which is the default value of this node. * - * @param[in] client_name Identifier of an existing Call-Home client. + * @param[in] client_name Identifier of an existing Call Home client. * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_del_period(const char *client_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for the anchor time parameter of the call-home periodic connection type. + * @brief Creates new YANG configuration data nodes for the anchor time parameter of the Call Home periodic connection type. * * If called, the persistent connection type will be replaced by periodic. * * @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] 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] anchor_time Timestamp before or after which a series of periodic connections are determined. * @param 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. @@ -1085,22 +1085,22 @@ int nc_server_config_new_ch_anchor_time(const struct ly_ctx *ctx, const char *cl const char *anchor_time, struct lyd_node **config); /** - * @brief Deletes the Call-Home anchor time parameter of the periodic connection type from the YANG data. + * @brief Deletes the Call Home anchor time parameter of the periodic connection type from the YANG data. * - * @param[in] client_name Identifier of an existing Call-Home client. + * @param[in] client_name Identifier of an existing Call Home client. * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_del_anchor_time(const char *client_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for the idle timeout parameter of the call-home periodic connection type. + * @brief Creates new YANG configuration data nodes for the idle timeout parameter of the Call Home periodic connection type. * * If called, the persistent connection type will be replaced by periodic. * * @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] 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] idle_timeout Specifies the maximum number of seconds that a session may remain idle. * @param 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. @@ -1110,22 +1110,22 @@ int nc_server_config_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *c uint16_t idle_timeout, struct lyd_node **config); /** - * @brief Deletes the Call-Home idle timeout parameter of the periodic connection type from the YANG data. + * @brief Deletes the Call Home idle timeout parameter of the periodic connection type from the YANG data. * * This behaves the same as setting the timeout to 180 seconds, which is the default value of this node. * - * @param[in] client_name Identifier of an existing Call-Home client. + * @param[in] client_name Identifier of an existing Call Home client. * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_del_idle_timeout(const char *client_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for the call-home reconnect strategy. + * @brief Creates new YANG configuration data nodes for the Call Home reconnect strategy. * * @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] 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] start_with Specifies which endpoint to try if a connection is unsuccessful. Default value is NC_CH_FIRST_LISTED. * @param[in] max_wait The number of seconds after which a connection to an endpoint is deemed unsuccessful. Default value if 5. * @param[in] max_attempts The number of unsuccessful connection attempts before moving to the next endpoint. Default value is 3. @@ -1137,11 +1137,11 @@ int nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const c NC_CH_START_WITH start_with, uint16_t max_wait, uint8_t max_attempts, struct lyd_node **config); /** - * @brief Resets the values of the Call-Home reconnect strategy nodes to their defaults. + * @brief Resets the values of the Call Home reconnect strategy nodes to their defaults. * * The default values are: start-with = NC_CH_FIRST_LISTED, max-wait = 5 and max-attempts = 3. * - * @param[in] client_name Identifier of an existing Call-Home client. + * @param[in] client_name Identifier of an existing Call Home client. * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ @@ -1154,19 +1154,19 @@ int nc_server_config_new_ch_del_reconnect_strategy(const char *client_name, stru #ifdef NC_ENABLED_SSH_TLS /** - * @defgroup server_config_ch_ssh SSH Call-Home 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 SSH Call Home server configuration creation and deletion * @{ */ /** - * @brief Creates new YANG data nodes for a call-home SSH hostkey. + * @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] 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. @@ -1183,9 +1183,9 @@ int nc_server_config_new_ch_ssh_hostkey(const struct ly_ctx *ctx, const char *cl 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. + * @brief Deletes a Call Home hostkey from the YANG data. * - * @param[in] client_name Identifier of an existing Call-home client. + * @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. @@ -1198,11 +1198,11 @@ int nc_server_config_new_ch_ssh_del_hostkey(const char *client_name, const char /** * @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. + * 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] 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. @@ -1216,9 +1216,9 @@ int nc_server_config_new_ch_ssh_keystore_reference(const struct ly_ctx *ctx, con 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. + * @brief Deletes a Call Home keystore reference from the YANG data. * - * @param[in] client_name Identifier of an existing Call-home client. + * @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 config Modified configuration YANG data tree. @@ -1228,11 +1228,11 @@ int nc_server_config_new_ch_ssh_del_keystore_reference(const char *client_name, const char *hostkey_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for the maximum amount of failed Call-Home SSH authentication attempts. + * @brief Creates new YANG configuration data nodes for the maximum amount of failed Call Home SSH authentication attempts. * * @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] 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] auth_attempts Maximum amount of failed SSH authentication attempts after which a @@ -1245,11 +1245,11 @@ int nc_server_config_new_ch_ssh_auth_attempts(const struct ly_ctx *ctx, const ch uint16_t auth_attempts, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a Call-Home SSH authentication timeout. + * @brief Creates new YANG configuration data nodes for a Call Home SSH authentication timeout. * * @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] 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] auth_timeout Maximum amount of time in seconds after which the authentication is deemed @@ -1262,11 +1262,11 @@ int nc_server_config_new_ch_ssh_auth_timeout(const struct ly_ctx *ctx, const cha uint16_t auth_timeout, struct lyd_node **config); /** - * @brief Creates new YANG data nodes for a Call-Home SSH user's public key authentication method. + * @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] 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. @@ -1282,9 +1282,9 @@ int nc_server_config_new_ch_ssh_user_pubkey(const struct ly_ctx *ctx, const char 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. + * @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] 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. @@ -1296,11 +1296,11 @@ int nc_server_config_new_ch_ssh_del_user_pubkey(const char *client_name, const c const char *user_name, const char *pubkey_name, struct lyd_node **config); /** - * @brief Creates new YANG data nodes for a Call-Home SSH user's password authentication method. + * @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] 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. @@ -1314,9 +1314,9 @@ int nc_server_config_new_ch_ssh_user_password(const struct ly_ctx *ctx, const ch const char *user_name, const char *password, struct lyd_node **config); /** - * @brief Deletes a Call-Home SSH user's password from the YANG data. + * @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] 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. @@ -1326,11 +1326,11 @@ int nc_server_config_new_ch_ssh_del_user_password(const char *client_name, const const char *user_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a Call-Home SSH user's none authentication method. + * @brief Creates new YANG configuration data nodes for a Call Home SSH user's none 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] 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. @@ -1343,9 +1343,9 @@ int nc_server_config_new_ch_ssh_user_none(const struct ly_ctx *ctx, const char * const char *user_name, struct lyd_node **config); /** - * @brief Deletes a Call-Home SSH user's none authentication method from the YANG data. + * @brief Deletes a Call Home SSH user's none authentication method from the YANG data. * - * @param[in] client_name Identifier of an existing Call-home client. + * @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. @@ -1355,11 +1355,11 @@ int nc_server_config_new_ch_ssh_del_user_none(const char *client_name, const cha 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. + * @brief Creates new YANG configuration data nodes for a Call Home SSH user's keyboard interactive 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] 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. @@ -1376,9 +1376,9 @@ int nc_server_config_new_ch_ssh_user_interactive(const struct ly_ctx *ctx, const const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config); /** - * @brief Deletes a Call-Home SSH user's keyboard interactive authentication from the YANG data. + * @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] 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. @@ -1388,9 +1388,9 @@ int nc_server_config_new_ch_ssh_del_user_interactive(const char *client_name, co const char *user_name, struct lyd_node **config); /** - * @brief Deletes a Call-Home SSH user from the YANG data. + * @brief Deletes a Call Home SSH user from the YANG data. * - * @param[in] client_name Identifier of an existing Call-home client. + * @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. @@ -1402,11 +1402,11 @@ int nc_server_config_new_ch_ssh_del_user(const char *client_name, const char *en /** * @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. + * 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] 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. @@ -1420,9 +1420,9 @@ int nc_server_config_new_ch_ssh_truststore_reference(const struct ly_ctx *ctx, c 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. + * @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] 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. @@ -1432,14 +1432,14 @@ int nc_server_config_new_ch_ssh_del_truststore_reference(const char *client_name const char *user_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for Call-Home host-key algorithms replacing any previous ones. + * @brief Creates new YANG configuration data nodes for Call Home host-key algorithms replacing any previous ones. * * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. * * @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] 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 config Configuration YANG data tree. If *config is NULL, it will be created. @@ -1452,9 +1452,9 @@ int nc_server_config_new_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const ch struct lyd_node **config, int alg_count, ...); /** - * @brief Deletes a Call-Home hostkey algorithm from the YANG data. + * @brief Deletes a Call Home hostkey algorithm from the YANG data. * - * @param[in] client_name Identifier of an existing Call-home client. + * @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] alg Optional algorithm to be deleted. * If NULL, all of the hostkey algorithms on this endpoint will be deleted. @@ -1465,15 +1465,15 @@ int nc_server_config_new_ch_ssh_del_host_key_alg(const char *client_name, const const char *alg, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for Call-Home key exchange algorithms replacing any previous ones. + * @brief Creates new YANG configuration data nodes for Call Home key exchange algorithms replacing any previous ones. * * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. * * @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] 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 config Configuration YANG data tree. If *config is NULL, it will be created. @@ -1486,9 +1486,9 @@ int nc_server_config_new_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, cons struct lyd_node **config, int alg_count, ...); /** - * @brief Deletes a Call-Home key exchange algorithm from the YANG data. + * @brief Deletes a Call Home key exchange algorithm from the YANG data. * - * @param[in] client_name Identifier of an existing Call-home client. + * @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] alg Optional algorithm to be deleted. * If NULL, all of the key exchange algorithms on this endpoint will be deleted. @@ -1499,14 +1499,14 @@ int nc_server_config_new_ch_ssh_del_key_exchange_alg(const char *client_name, co const char *alg, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for Call-Home encryption algorithms replacing any previous ones. + * @brief Creates new YANG configuration data nodes for Call Home encryption algorithms replacing any previous ones. * * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc * triple-des-cbc and none. * * @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] 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 config Configuration YANG data tree. If *config is NULL, it will be created. @@ -1519,9 +1519,9 @@ int nc_server_config_new_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const struct lyd_node **config, int alg_count, ...); /** - * @brief Deletes a Call-Home encryption algorithm from the YANG data. + * @brief Deletes a Call Home encryption algorithm from the YANG data. * - * @param[in] client_name Identifier of an existing Call-home client. + * @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] alg Optional algorithm to be deleted. * If NULL, all of the encryption algorithms on this endpoint will be deleted. @@ -1532,13 +1532,13 @@ int nc_server_config_new_ch_ssh_del_encryption_alg(const char *client_name, cons const char *alg, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for Call-Home mac algorithms replacing any previous ones. + * @brief Creates new YANG configuration data nodes for Call Home mac algorithms replacing any previous ones. * * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. * * @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] 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 config Configuration YANG data tree. If *config is NULL, it will be created. @@ -1551,9 +1551,9 @@ int nc_server_config_new_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *c struct lyd_node **config, int alg_count, ...); /** - * @brief Deletes a Call-Home mac algorithm from the YANG data. + * @brief Deletes a Call Home mac algorithm from the YANG data. * - * @param[in] client_name Identifier of an existing Call-home client. + * @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] alg Optional algorithm to be deleted. * If NULL, all of the mac algorithms on this endpoint will be deleted. @@ -1568,21 +1568,21 @@ int nc_server_config_new_ch_ssh_del_mac_alg(const char *client_name, const char */ /** - * @defgroup server_config_ch_tls TLS 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 TLS Call Home server configuration creation and deletion * @{ */ /** - * @brief Creates new YANG configuration data nodes for a call-home server's certificate. + * @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] 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] pubkey_path Optional path to the server's public key file. If not provided, * it will be generated from the private key. * @param[in] privkey_path Path to the server's private key file. @@ -1595,10 +1595,10 @@ int nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, con const char *pubkey_path, const char *privkey_path, const char *certificate_path, struct lyd_node **config); /** - * @brief Deletes a Call-Home server certificate from the YANG data. + * @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] 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. */ @@ -1609,10 +1609,10 @@ int nc_server_config_new_ch_tls_del_server_certificate(const char *client_name, * @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] 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. @@ -1625,8 +1625,8 @@ int nc_server_config_new_ch_tls_keystore_reference(const struct ly_ctx *ctx, con /** * @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] 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. */ @@ -1634,15 +1634,15 @@ int nc_server_config_new_ch_tls_del_keystore_reference(const char *client_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a call-home client's (end-entity) certificate. + * @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] 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. @@ -1652,10 +1652,10 @@ int nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, con 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. + * @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] 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. @@ -1668,10 +1668,10 @@ int nc_server_config_new_ch_tls_del_client_certificate(const char *client_name, * @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] 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. @@ -1683,8 +1683,8 @@ int nc_server_config_new_ch_tls_client_cert_truststore_ref(const struct ly_ctx * /** * @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] 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. */ @@ -1695,12 +1695,12 @@ int nc_server_config_new_ch_tls_del_client_cert_truststore_ref(const char *clien * @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] 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 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. @@ -1710,10 +1710,10 @@ int nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char * 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. + * @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] 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. @@ -1726,10 +1726,10 @@ int nc_server_config_new_ch_tls_del_client_ca(const char *client_name, const cha * @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] 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. @@ -1741,8 +1741,8 @@ int nc_server_config_new_ch_tls_client_ca_truststore_ref(const struct ly_ctx *ct /** * @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] 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. */ @@ -1750,13 +1750,13 @@ int nc_server_config_new_ch_tls_del_client_ca_truststore_ref(const char *client_ struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a call-home cert-to-name entry. + * @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] 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. @@ -1770,11 +1770,11 @@ int nc_server_config_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *client 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. + * @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. + * @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. @@ -1783,13 +1783,13 @@ int nc_server_config_new_ch_tls_del_ctn(const char *client_name, const char *end uint32_t id, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a Call-Home TLS version. + * @brief Creates new YANG configuration data nodes for a Call Home TLS version. * * @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] 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] tls_version TLS version to be used. Call this multiple times to set the accepted versions * of the TLS protocol and let the client and server negotiate the given version. * @param config Configuration YANG data tree. If *config is NULL, it will be created. @@ -1802,8 +1802,8 @@ int nc_server_config_new_ch_tls_version(const struct ly_ctx *ctx, const char *cl /** * @brief Deletes a TLS version 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] 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] tls_version TLS version to be deleted. * @param config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. @@ -1812,13 +1812,13 @@ int nc_server_config_new_ch_tls_del_version(const char *client_name, const char NC_TLS_VERSION tls_version, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a Call-Home TLS cipher. + * @brief Creates new YANG configuration data nodes for a Call Home TLS cipher. * * @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] 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 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[in] cipher_count Number of following ciphers. @@ -1833,10 +1833,10 @@ int nc_server_config_new_ch_tls_ciphers(const struct ly_ctx *ctx, const char *cl struct lyd_node **config, int cipher_count, ...); /** - * @brief Deletes a Call-Home TLS cipher from the YANG data. + * @brief Deletes a Call Home TLS cipher 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] 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] cipher TLS cipher to be deleted. * @param config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. @@ -1845,16 +1845,16 @@ int nc_server_config_new_ch_tls_del_cipher(const char *client_name, const char * const char *cipher, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a Call-Home Certificate Revocation List via a local file. + * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via a local file. * * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling * this function will remove any CRL YANG nodes created by the other two functions. * * @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] 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] crl_path Path to a DER/PEM encoded CRL file. * @param 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. @@ -1864,16 +1864,16 @@ int nc_server_config_new_ch_tls_crl_path(const struct ly_ctx *ctx, const char *c const char *crl_path, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a Call-Home Certificate Revocation List via an URL. + * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via an URL. * * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling * this function will remove any CRL YANG nodes created by the other two functions. * * @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] 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] crl_url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. * The allowed protocols are all the protocols supported by CURL. * @param config Configuration YANG data tree. If *config is NULL, it will be created. @@ -1884,7 +1884,7 @@ int nc_server_config_new_ch_tls_crl_url(const struct ly_ctx *ctx, const char *cl const char *crl_url, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for a Call-Home Certificate Revocation List via certificate extensions. + * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via certificate extensions. * * The chain of configured Certificate Authorities will be examined. For each certificate in this chain all the * CRLs from the URLs specified in their extension fields CRL Distribution Points will be downloaded and used. @@ -1893,10 +1893,10 @@ int nc_server_config_new_ch_tls_crl_url(const struct ly_ctx *ctx, const char *cl * this function will remove any CRL YANG nodes created by the other two functions. * * @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] 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 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. @@ -1907,8 +1907,8 @@ int nc_server_config_new_ch_tls_crl_cert_ext(const struct ly_ctx *ctx, const cha /** * @brief Deletes all the CRL nodes 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] 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 config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ From 6b29c92c946583132461d57803bd87a1994800e6 Mon Sep 17 00:00:00 2001 From: Roytak Date: Wed, 2 Aug 2023 15:07:29 +0200 Subject: [PATCH 056/134] docs UPDATE add missing in,out param --- src/server_config.h | 56 ++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/server_config.h b/src/server_config.h index 4a9a17bd..52e08689 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -479,7 +479,7 @@ int nc_server_config_new_ssh_del_user(const char *endpt_name, * @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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1035,7 +1035,7 @@ int nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt * @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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1050,7 +1050,7 @@ int nc_server_config_new_ch_persistent(const struct ly_ctx *ctx, const char *cli * @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] period Duration between periodic connections in minutes. - * @param config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1077,7 +1077,7 @@ int nc_server_config_new_ch_del_period(const char *client_name, struct lyd_node * @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] anchor_time Timestamp before or after which a series of periodic connections are determined. - * @param config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1102,7 +1102,7 @@ int nc_server_config_new_ch_del_anchor_time(const char *client_name, struct lyd_ * @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] idle_timeout Specifies the maximum number of seconds that a session may remain idle. - * @param config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1129,7 +1129,7 @@ int nc_server_config_new_ch_del_idle_timeout(const char *client_name, struct lyd * @param[in] start_with Specifies which endpoint to try if a connection is unsuccessful. Default value is NC_CH_FIRST_LISTED. * @param[in] max_wait The number of seconds after which a connection to an endpoint is deemed unsuccessful. Default value if 5. * @param[in] max_attempts The number of unsuccessful connection attempts before moving to the next endpoint. Default value is 3. - * @param config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1208,7 +1208,7 @@ int nc_server_config_new_ch_ssh_del_hostkey(const char *client_name, const char * @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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1221,7 +1221,7 @@ int nc_server_config_new_ch_ssh_keystore_reference(const struct ly_ctx *ctx, con * @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 config Modified configuration YANG data tree. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_ssh_del_keystore_reference(const char *client_name, const char *endpt_name, @@ -1335,7 +1335,7 @@ int nc_server_config_new_ch_ssh_del_user_password(const char *client_name, const * 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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1412,7 +1412,7 @@ int nc_server_config_new_ch_ssh_del_user(const char *client_name, const char *en * @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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1442,7 +1442,7 @@ int nc_server_config_new_ch_ssh_del_truststore_reference(const char *client_name * 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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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[in] alg_count Number of following algorithms. * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. @@ -1458,7 +1458,7 @@ int nc_server_config_new_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const ch * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. * @param[in] alg Optional algorithm to be deleted. * If NULL, all of the hostkey algorithms on this endpoint will be deleted. - * @param config Modified configuration YANG data tree. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_ssh_del_host_key_alg(const char *client_name, const char *endpt_name, @@ -1476,7 +1476,7 @@ int nc_server_config_new_ch_ssh_del_host_key_alg(const char *client_name, const * 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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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[in] alg_count Number of following algorithms. * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. @@ -1492,7 +1492,7 @@ int nc_server_config_new_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, cons * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. * @param[in] alg Optional algorithm to be deleted. * If NULL, all of the key exchange algorithms on this endpoint will be deleted. - * @param config Modified configuration YANG data tree. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_ssh_del_key_exchange_alg(const char *client_name, const char *endpt_name, @@ -1509,7 +1509,7 @@ int nc_server_config_new_ch_ssh_del_key_exchange_alg(const char *client_name, co * 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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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[in] alg_count Number of following algorithms. * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. @@ -1525,7 +1525,7 @@ int nc_server_config_new_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. * @param[in] alg Optional algorithm to be deleted. * If NULL, all of the encryption algorithms on this endpoint will be deleted. - * @param config Modified configuration YANG data tree. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_ssh_del_encryption_alg(const char *client_name, const char *endpt_name, @@ -1541,7 +1541,7 @@ int nc_server_config_new_ch_ssh_del_encryption_alg(const char *client_name, cons * 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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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[in] alg_count Number of following algorithms. * @param[in] ... String literals of mac algorithms in a decreasing order of preference. @@ -1557,7 +1557,7 @@ int nc_server_config_new_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *c * @param[in] endpt_name Identifier of an existing endpoint that belongs to the given CH client. * @param[in] alg Optional algorithm to be deleted. * If NULL, all of the mac algorithms on this endpoint will be deleted. - * @param config Modified configuration YANG data tree. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_ssh_del_mac_alg(const char *client_name, const char *endpt_name, @@ -1702,7 +1702,7 @@ int nc_server_config_new_ch_tls_del_client_cert_truststore_ref(const char *clien * @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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1762,7 +1762,7 @@ int nc_server_config_new_ch_tls_del_client_ca_truststore_ref(const char *client_ * 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. - * @param config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1792,7 +1792,7 @@ int nc_server_config_new_ch_tls_del_ctn(const char *client_name, const char *end * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. * @param[in] tls_version TLS version to be used. Call this multiple times to set the accepted versions * of the TLS protocol and let the client and server negotiate the given version. - * @param config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1805,7 +1805,7 @@ int nc_server_config_new_ch_tls_version(const struct ly_ctx *ctx, const char *cl * @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] tls_version TLS version to be deleted. - * @param config Modified configuration YANG data tree. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_tls_del_version(const char *client_name, const char *endpt_name, @@ -1819,7 +1819,7 @@ int nc_server_config_new_ch_tls_del_version(const char *client_name, const char * 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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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[in] cipher_count Number of following ciphers. * @param[in] ... TLS ciphers. These ciphers MUST be in the format as listed in the @@ -1838,7 +1838,7 @@ int nc_server_config_new_ch_tls_ciphers(const struct ly_ctx *ctx, const char *cl * @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] cipher TLS cipher to be deleted. - * @param config Modified configuration YANG data tree. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_tls_del_cipher(const char *client_name, const char *endpt_name, @@ -1856,7 +1856,7 @@ int nc_server_config_new_ch_tls_del_cipher(const char *client_name, const char * * @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] crl_path Path to a DER/PEM encoded CRL file. - * @param config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1876,7 +1876,7 @@ int nc_server_config_new_ch_tls_crl_path(const struct ly_ctx *ctx, const char *c * If a Call Home client's endpoint with this identifier already exists, its contents will be changed. * @param[in] crl_url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. * The allowed protocols are all the protocols supported by CURL. - * @param config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1897,7 +1897,7 @@ int nc_server_config_new_ch_tls_crl_url(const struct ly_ctx *ctx, const char *cl * 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 config Configuration YANG data tree. If *config is NULL, it will be created. + * @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. */ @@ -1909,7 +1909,7 @@ int nc_server_config_new_ch_tls_crl_cert_ext(const struct ly_ctx *ctx, const cha * * @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 config Modified configuration YANG data tree. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ch_tls_del_crl(const char *client_name, const char *endpt_name, struct lyd_node **config); From 183aa7308274e030a45bd0126a9c7bae39877d97 Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 7 Aug 2023 09:03:24 +0200 Subject: [PATCH 057/134] doc UPDATE add correct links to docs --- src/messages_server.h | 4 ++-- src/server_config.h | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/messages_server.h b/src/messages_server.h index a3deacbc..f783bf81 100644 --- a/src/messages_server.h +++ b/src/messages_server.h @@ -109,7 +109,7 @@ struct nc_server_reply *nc_server_reply_data(struct lyd_node *data, NC_WD_MODE w /** * @brief Create an ERROR rpc-reply object. * - * @param[in] err Errors created by ::nc_err(). It will be freed with the returned object. + * @param[in] err Errors created by nc_err(). It will be freed with the returned object. * @return rpc-reply object, NULL on error. */ struct nc_server_reply *nc_server_reply_err(struct lyd_node *err); @@ -118,7 +118,7 @@ struct nc_server_reply *nc_server_reply_err(struct lyd_node *err); * @brief Add another error opaque data node tree to an ERROR rpc-reply object. * * @param[in] reply ERROR reply to add to. - * @param[in] err Error created by ::nc_err(). It will be freed with the returned object. + * @param[in] err Error created by nc_err(). It will be freed with the returned object. * @return 0 on success, -1 on errror. */ int nc_server_reply_add_err(struct nc_server_reply *reply, struct lyd_node *err); diff --git a/src/server_config.h b/src/server_config.h index 52e08689..2bddb316 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -41,7 +41,7 @@ extern "C" { * Expected data are a validated instance of a ietf-netconf-server YANG data. * The data must be in the diff format and supported operations are: create, replace, * delete and none. Context must already have implemented the required modules, see - * ::nc_config_load_modules(). + * ::nc_server_config_load_modules(). * * @param[in] diff ietf-netconf-server YANG diff data. * @return 0 on success, 1 on error. @@ -54,8 +54,8 @@ int nc_server_config_setup_diff(const struct lyd_node *diff); * Expected data is a validated instance of a ietf-netconf-server YANG data. * Behaves as if all the nodes in data had the replace operation. That means that the current configuration will be deleted * and just the given data will all be applied. - * The data must not contain any operation attribute, see ::nc_config_setup_diff() which works with diff. - * Context must already have implemented the required modules, see * ::nc_config_load_modules(). + * The data must not contain any operation attribute, see ::nc_server_config_setup_diff() which works with diff. + * Context must already have implemented the required modules, see ::nc_server_config_load_modules(). * * @param[in] data ietf-netconf-server YANG data. * @return 0 on success, 1 on error. @@ -64,7 +64,7 @@ int nc_server_config_setup_data(const struct lyd_node *data); /** * @brief Configure server based on the given ietf-netconf-server YANG data. - * Wrapper around ::nc_config_setup_server_data() hiding work with parsing the data. + * Wrapper around ::nc_server_config_setup_data() hiding work with parsing the data. * * @param[in] ctx libyang context. * @param[in] path Path to the file with YANG data in XML format. @@ -435,8 +435,8 @@ int nc_server_config_new_ssh_del_user_none(const char *endpt_name, const char *u * @param[in] user_name Arbitrary identifier of the user. * If an user with this identifier already exists, its contents will be changed. * @param[in] pam_config_name Name of the PAM configuration file. - * @param[in] pam_config_name Optional. The absolute path to the directory in which the configuration file - * with the name conf_name is located. A newer version (>= 1.4) of PAM library is required to be able to specify + * @param[in] pam_config_dir Optional. The absolute path to the directory in which the configuration file + * with the name pam_config_name is located. A newer version (>= 1.4) of PAM library is required to be able to specify * the path. If NULL is passed, then the PAM's system directories will be searched (usually /etc/pam.d/). * @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. @@ -1365,8 +1365,8 @@ int nc_server_config_new_ch_ssh_del_user_none(const char *client_name, const cha * @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] pam_config_name Name of the PAM configuration file. - * @param[in] pam_config_name Optional. The absolute path to the directory in which the configuration file - * with the name conf_name is located. A newer version (>= 1.4) of PAM library is required to be able to specify + * @param[in] pam_config_dir Optional. The absolute path to the directory in which the configuration file + * with the name pam_config_name is located. A newer version (>= 1.4) of PAM library is required to be able to specify * the path. If NULL is passed, then the PAM's system directories will be searched (usually /etc/pam.d/). * @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. From 8dafbfc6e7a65c6bb162e47b7d779622dbab49b2 Mon Sep 17 00:00:00 2001 From: roman Date: Tue, 8 Aug 2023 10:18:44 +0200 Subject: [PATCH 058/134] config tls REFACTOR change server cert param order --- src/config_new_tls.c | 6 +++--- src/server_config.h | 10 +++++----- tests/test_ch.c | 2 +- tests/test_crl.c | 2 +- tests/test_endpt_share_clients.c | 7 +++---- tests/test_tls.c | 2 +- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/config_new_tls.c b/src/config_new_tls.c index 8e9cb9d5..7e59c987 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -108,8 +108,8 @@ _nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const cha } API int -nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *pubkey_path, - const char *privkey_path, const char *certificate_path, struct lyd_node **config) +nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path, + const char *pubkey_path, const char *certificate_path, struct lyd_node **config) { int ret = 0; char *path = NULL; @@ -147,7 +147,7 @@ nc_server_config_new_tls_del_server_certificate(const char *endpt_name, struct l API int nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *pubkey_path, const char *privkey_path, const char *certificate_path, struct lyd_node **config) + const char *privkey_path, const char *pubkey_path, const char *certificate_path, struct lyd_node **config) { int ret = 0; char *path = NULL; diff --git a/src/server_config.h b/src/server_config.h index 2bddb316..50f7c32b 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -658,16 +658,16 @@ int nc_server_config_new_ssh_del_mac_alg(const char *endpt_name, const char *alg * @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] privkey_path Path to the server's private key file. * @param[in] certificate_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_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *pubkey_path, - const char *privkey_path, const char *certificate_path, struct lyd_node **config); +int nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path, + const char *pubkey_path, const char *certificate_path, struct lyd_node **config); /** * @brief Deletes the server's certificate from the YANG data. @@ -1583,16 +1583,16 @@ int nc_server_config_new_ch_ssh_del_mac_alg(const char *client_name, const char * 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] privkey_path Path to the server's private key file. * @param[in] certificate_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_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *pubkey_path, const char *privkey_path, const char *certificate_path, struct lyd_node **config); + const char *privkey_path, const char *pubkey_path, const char *certificate_path, struct lyd_node **config); /** * @brief Deletes a Call Home server certificate from the YANG data. diff --git a/tests/test_ch.c b/tests/test_ch.c index 735267b9..13ab75ee 100644 --- a/tests/test_ch.c +++ b/tests/test_ch.c @@ -400,7 +400,7 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* set call-home server certificate */ - ret = nc_server_config_new_ch_tls_server_certificate(ctx, "ch_tls", "endpt", NULL, TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &test_state->tls_tree); + ret = nc_server_config_new_ch_tls_server_certificate(ctx, "ch_tls", "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tls_tree); assert_int_equal(ret, 0); /* set call-home client end entity certificate */ diff --git a/tests/test_crl.c b/tests/test_crl.c index 126fda9d..7a9cf447 100644 --- a/tests/test_crl.c +++ b/tests/test_crl.c @@ -148,7 +148,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new server certificate data */ - ret = nc_server_config_new_tls_server_certificate(ctx, "endpt", NULL, TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_new_tls_server_certificate(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); /* create new end entity client cert data */ diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c index a18210b6..037da46e 100644 --- a/tests/test_endpt_share_clients.c +++ b/tests/test_endpt_share_clients.c @@ -256,8 +256,7 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* create the first TLS endpoint with a single end entity client cert and a CTN entry */ - ret = nc_server_config_new_tls_server_certificate(ctx, "TLS_endpt_1", NULL, - TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_new_tls_server_certificate(ctx, "TLS_endpt_1", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); ret = nc_server_config_new_address_port(ctx, "TLS_endpt_1", NC_TI_OPENSSL, "127.0.0.1", 10007, &tree); @@ -275,8 +274,8 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* create the second TLS endpoint with a reference to the first endpoint */ - ret = nc_server_config_new_tls_server_certificate(ctx, "TLS_endpt_2", NULL, - TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_new_tls_server_certificate(ctx, "TLS_endpt_2", + TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); ret = nc_server_config_new_address_port(ctx, "TLS_endpt_2", NC_TI_OPENSSL, "127.0.0.1", 10008, &tree); diff --git a/tests/test_tls.c b/tests/test_tls.c index 90970ee0..ed0966b1 100644 --- a/tests/test_tls.c +++ b/tests/test_tls.c @@ -142,7 +142,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new server certificate data */ - ret = nc_server_config_new_tls_server_certificate(ctx, "endpt", NULL, TESTS_DIR "/data/server.key", TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_new_tls_server_certificate(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); /* create new end entity client cert data */ From b508bd420965695ca21665d10ead9bb79d573603 Mon Sep 17 00:00:00 2001 From: roman Date: Tue, 8 Aug 2023 10:39:12 +0200 Subject: [PATCH 059/134] docs UPDATE new docs grouping, fix typos --- Doxyfile.in | 2 +- doc/libnetconf.doc | 2 + src/server_config.h | 104 ++++++++++++++++++++++++---------------- src/session_server_ch.h | 12 ++++- 4 files changed, 78 insertions(+), 42 deletions(-) diff --git a/Doxyfile.in b/Doxyfile.in index 9ca117bb..551c59b3 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -588,7 +588,7 @@ SORT_MEMBERS_CTORS_1ST = YES # appear in their defined order. # The default value is: NO. -SORT_GROUP_NAMES = NO +SORT_GROUP_NAMES = YES # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will diff --git a/doc/libnetconf.doc b/doc/libnetconf.doc index 83d0d450..c60ff5c9 100644 --- a/doc/libnetconf.doc +++ b/doc/libnetconf.doc @@ -634,4 +634,6 @@ /** * @defgroup server Server * @brief NETCONF server functionality. + * @{ + * @} Server */ diff --git a/src/server_config.h b/src/server_config.h index 50f7c32b..91350d6d 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -35,6 +35,36 @@ extern "C" { * @{ */ +/** + * @} Server Configuration + */ + +/** + * @defgroup server_config_functions Server Configuration Functions + * @ingroup server_config + * + * @brief Server-side configuration functions + * @{ + */ + +/** + * @brief Implements all the required modules and their features in the context. + * Needs to be called before any other configuration functions. + * + * If ctx is : + * - NULL: a new context will be created and if the call is successful you have to free it, + * - non NULL: modules will simply be implemented. + * + * Implemented modules: ietf-netconf-server, ietf-x509-cert-to-name, ietf-crypto-types, + * ietf-tcp-common, ietf-ssh-common, iana-ssh-encryption-algs, iana-ssh-key-exchange-algs, + * iana-ssh-mac-algs, iana-ssh-public-key-algs, ietf-keystore, ietf-ssh-server, ietf-truststore, + * ietf-tls-server and libnetconf2-netconf-server. + * + * @param[in, out] ctx Optional context in which the modules will be implemented. Created if ctx is null. + * @return 0 on success, 1 on error. + */ +int nc_server_config_load_modules(struct ly_ctx **ctx); + /** * @brief Configure server based on the given diff data. * @@ -63,44 +93,26 @@ int nc_server_config_setup_diff(const struct lyd_node *diff); int nc_server_config_setup_data(const struct lyd_node *data); /** - * @brief Configure server based on the given ietf-netconf-server YANG data. + * @brief Configure server based on the given ietf-netconf-server YANG data from a file. * Wrapper around ::nc_server_config_setup_data() hiding work with parsing the data. * * @param[in] ctx libyang context. - * @param[in] path Path to the file with YANG data in XML format. + * @param[in] path Path to the file with ietf-netconf-server YANG data. * @return 0 on success, 1 on error. */ int nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path); -/** - * @brief Implements all the required modules and their features in the context. - * Needs to be called before any other configuration functions. - * - * If ctx is : - * - NULL: a new context will be created and if the call is successful you have to free it, - * - non NULL: modules will simply be implemented. - * - * Implemented modules: ietf-netconf-server, ietf-x509-cert-to-name, ietf-crypto-types, - * ietf-tcp-common, ietf-ssh-common, iana-ssh-encryption-algs, iana-ssh-key-exchange-algs, - * iana-ssh-mac-algs, iana-ssh-public-key-algs, ietf-keystore, ietf-ssh-server, ietf-truststore, - * ietf-tls-server and libnetconf2-netconf-server. - * - * @param[in, out] ctx Optional context in which the modules will be implemented. Created if ctx is null. - * @return 0 on success, 1 on error. - */ -int nc_server_config_load_modules(struct ly_ctx **ctx); - #ifdef NC_ENABLED_SSH_TLS /** - * @brief Creates new YANG configuration data nodes for a local-address and local-port. + * @brief Creates new YANG configuration data nodes for local-address and local-port. * * @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] address New listening address. * @param[in] port New listening port. - * If an endpoint with this identifier already exists, its address and port will be overriden. * @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. @@ -115,7 +127,7 @@ int nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endp * * @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 Configuration YANG data tree. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **config); @@ -240,7 +252,7 @@ int nc_server_config_new_del_truststore_cert(const char *cert_bag_name, const char *cert_name, struct lyd_node **config); /** - * @} + * @} Server Configuration Functions */ /** @@ -261,7 +273,7 @@ int nc_server_config_new_del_truststore_cert(const char *cert_bag_name, * 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 Path to a file containing a public key. If NULL, public key will be + * @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. @@ -381,7 +393,7 @@ int nc_server_config_new_ssh_del_user_pubkey(const char *endpt_name, const char * 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 Cleartext password to be set for the user. + * @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. @@ -548,7 +560,7 @@ int nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char * @param[in] endpt_name Identifier of an existing endpoint. * @param[in] alg Optional algorithm to be deleted. * If NULL, all of the hostkey algorithms on this endpoint will be deleted. - * @param[in,out] config Configuraiton YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ssh_del_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config); @@ -578,7 +590,7 @@ int nc_server_config_new_ssh_key_exchange_algs(const struct ly_ctx *ctx, const c * @param[in] endpt_name Identifier of an existing endpoint. * @param[in] alg Optional algorithm to be deleted. * If NULL, all of the key exchange algorithms on this endpoint will be deleted. - * @param[in,out] config Configuraiton YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ssh_del_key_exchange_alg(const char *endpt_name, const char *alg, struct lyd_node **config); @@ -607,7 +619,7 @@ int nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const cha * @param[in] endpt_name Identifier of an existing endpoint. * @param[in] alg Optional algorithm to be deleted. * If NULL, all of the encryption algorithms on this endpoint will be deleted. - * @param[in,out] config Configuraiton YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ssh_del_encryption_alg(const char *endpt_name, const char *alg, struct lyd_node **config); @@ -635,13 +647,13 @@ int nc_server_config_new_ssh_mac_algs(const struct ly_ctx *ctx, const char *endp * @param[in] endpt_name Identifier of an existing endpoint. * @param[in] alg Optional algorithm to be deleted. * If NULL, all of the mac algorithms on this endpoint will be deleted. - * @param[in,out] config Configuraiton YANG data. + * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ int nc_server_config_new_ssh_del_mac_alg(const char *endpt_name, const char *alg, struct lyd_node **config); /** - * @} + * @} SSH Server Configuration */ /** @@ -709,7 +721,7 @@ int nc_server_config_new_tls_del_keystore_reference(const char *endpt_name, stru * @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 indetifier already exists, it will be changed. + * 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. @@ -759,7 +771,7 @@ int nc_server_config_new_tls_del_client_cert_truststore_ref(const char *endpt_na * @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 indetifier already exists, it will be changed. + * 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. @@ -865,7 +877,7 @@ int nc_server_config_new_tls_del_version(const char *endpt_name, NC_TLS_VERSION * If an endpoint 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[in] cipher_count Number of ciphers. + * @param[in] cipher_count Number of following ciphers. * @param[in] ... TLS ciphers. These ciphers MUST be in the format as listed in the * iana-tls-cipher-suite-algs YANG model (lowercase and separated by dashes). Regardless * of the TLS protocol version used, all of these ciphers will be tried and some of them @@ -975,17 +987,29 @@ int nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const int nc_config_new_tls_del_endpoint_client_reference(const char *endpt_name, struct lyd_node **config); /** - * @} + * @} TLS Server Configuration */ /** - * @defgroup server_config_ch Call Home 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. * @@ -1148,7 +1172,7 @@ int nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const c int nc_server_config_new_ch_del_reconnect_strategy(const char *client_name, struct lyd_node **config); /** - * @} + * @} Call Home Server Configuration Functions */ #ifdef NC_ENABLED_SSH_TLS @@ -1305,7 +1329,7 @@ int nc_server_config_new_ch_ssh_del_user_pubkey(const char *client_name, const c * 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 Cleartext password to be set for the user. + * @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. @@ -1564,7 +1588,7 @@ int nc_server_config_new_ch_ssh_del_mac_alg(const char *client_name, const char const char *alg, struct lyd_node **config); /** - * @} + * @} SSH Call Home Server Configuration */ /** @@ -1915,7 +1939,7 @@ int nc_server_config_new_ch_tls_crl_cert_ext(const struct ly_ctx *ctx, const cha int nc_server_config_new_ch_tls_del_crl(const char *client_name, const char *endpt_name, struct lyd_node **config); /** - * @} + * @} TLS Call Home Server Configuration */ #endif /* NC_ENABLED_SSH_TLS */ diff --git a/src/session_server_ch.h b/src/session_server_ch.h index f1b1b041..7626d966 100644 --- a/src/session_server_ch.h +++ b/src/session_server_ch.h @@ -37,6 +37,16 @@ extern "C" { * @{ */ +/** @} Server-side Call Home */ + +/** + * @defgroup server_ch_functions Server-side Call Home Functions + * @ingroup server_ch + * + * @brief Server-side Call Home functions. + * @{ + */ + /** * @brief Add a new Call Home client. * @@ -198,7 +208,7 @@ int nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_ nc_server_ch_session_release_ctx_cb release_ctx_cb, void *ctx_cb_data, nc_server_ch_new_session_cb new_session_cb, void *new_session_cb_data); -/** @} Server-side Call Home */ +/** @} Server-side Call Home Functions */ /** * @defgroup server_ch_ssh Server-side Call Home on SSH From bf0c59c1cd8e1b8f8d70a04a4f08b0dbbb27ff1c Mon Sep 17 00:00:00 2001 From: roman Date: Tue, 8 Aug 2023 10:56:04 +0200 Subject: [PATCH 060/134] config REFACTOR change reference to ref --- src/config_new_ssh.c | 20 ++++++++++---------- src/config_new_tls.c | 18 +++++++++--------- src/server_config.h | 32 ++++++++++++++++---------------- tests/test_endpt_share_clients.c | 4 ++-- tests/test_ks_ts.c | 6 +++--- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index 290b70cd..6c10e2f1 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -188,7 +188,7 @@ nc_server_config_new_ch_ssh_del_hostkey(const char *client_name, const char *end } API int -nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, +nc_server_config_new_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 ret = 0; @@ -215,7 +215,7 @@ nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char } API int -nc_server_config_new_ch_ssh_keystore_reference(const struct ly_ctx *ctx, const char *client_name, +nc_server_config_new_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) { int ret = 0; @@ -243,7 +243,7 @@ nc_server_config_new_ch_ssh_keystore_reference(const struct ly_ctx *ctx, const c } API int -nc_server_config_new_ssh_del_keystore_reference(const char *endpt_name, const char *hostkey_name, +nc_server_config_new_ssh_del_keystore_ref(const char *endpt_name, const char *hostkey_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); @@ -254,7 +254,7 @@ nc_server_config_new_ssh_del_keystore_reference(const char *endpt_name, const ch } API int -nc_server_config_new_ch_ssh_del_keystore_reference(const char *client_name, const char *endpt_name, +nc_server_config_new_ch_ssh_del_keystore_ref(const char *client_name, const char *endpt_name, const char *hostkey_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, endpt_name, hostkey_name, config, 1); @@ -805,7 +805,7 @@ nc_server_config_new_ch_ssh_del_user(const char *client_name, const char *endpt_ } API int -nc_config_new_ssh_endpoint_user_reference(const struct ly_ctx *ctx, const char *endpt_name, +nc_config_new_ssh_endpoint_user_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); @@ -815,7 +815,7 @@ nc_config_new_ssh_endpoint_user_reference(const struct ly_ctx *ctx, const char * } API int -nc_config_new_ssh_del_endpoint_user_reference(const char *endpt_name, struct lyd_node **config) +nc_config_new_ssh_del_endpoint_user_ref(const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); @@ -824,7 +824,7 @@ nc_config_new_ssh_del_endpoint_user_reference(const char *endpt_name, struct lyd } API int -nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, +nc_server_config_new_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 ret = 0; @@ -851,7 +851,7 @@ nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, const ch } API int -nc_server_config_new_ch_ssh_truststore_reference(const struct ly_ctx *ctx, const char *client_name, +nc_server_config_new_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) { int ret = 0; @@ -879,7 +879,7 @@ nc_server_config_new_ch_ssh_truststore_reference(const struct ly_ctx *ctx, const } API int -nc_server_config_new_ssh_del_truststore_reference(const char *endpt_name, const char *user_name, +nc_server_config_new_ssh_del_truststore_ref(const char *endpt_name, const char *user_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); @@ -890,7 +890,7 @@ nc_server_config_new_ssh_del_truststore_reference(const char *endpt_name, const } API int -nc_server_config_new_ch_ssh_del_truststore_reference(const char *client_name, const char *endpt_name, +nc_server_config_new_ch_ssh_del_truststore_ref(const char *client_name, const char *endpt_name, const char *user_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); diff --git a/src/config_new_tls.c b/src/config_new_tls.c index 7e59c987..985f1764 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -188,7 +188,7 @@ nc_server_config_new_ch_tls_del_server_certificate(const char *client_name, cons } static int -_nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const char *tree_path, const char *asym_key_ref, +_nc_server_config_new_tls_keystore_ref(const struct ly_ctx *ctx, const char *tree_path, const char *asym_key_ref, const char *cert_ref, struct lyd_node **config) { int ret = 0; @@ -216,7 +216,7 @@ _nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const cha } API int -nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *asym_key_ref, +nc_server_config_new_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) { int ret = 0; @@ -232,7 +232,7 @@ nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const char goto cleanup; } - ret = _nc_server_config_new_tls_keystore_reference(ctx, path, asym_key_ref, cert_ref, config); + ret = _nc_server_config_new_tls_keystore_ref(ctx, path, asym_key_ref, cert_ref, config); if (ret) { goto cleanup; } @@ -243,7 +243,7 @@ nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const char } API int -nc_server_config_new_tls_del_keystore_reference(const char *endpt_name, struct lyd_node **config) +nc_server_config_new_tls_del_keystore_ref(const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); @@ -252,7 +252,7 @@ nc_server_config_new_tls_del_keystore_reference(const char *endpt_name, struct l } API int -nc_server_config_new_ch_tls_keystore_reference(const struct ly_ctx *ctx, const char *client_name, +nc_server_config_new_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) { int ret = 0; @@ -269,7 +269,7 @@ nc_server_config_new_ch_tls_keystore_reference(const struct ly_ctx *ctx, const c goto cleanup; } - ret = _nc_server_config_new_tls_keystore_reference(ctx, path, asym_key_ref, cert_ref, config); + ret = _nc_server_config_new_tls_keystore_ref(ctx, path, asym_key_ref, cert_ref, config); if (ret) { goto cleanup; } @@ -280,7 +280,7 @@ nc_server_config_new_ch_tls_keystore_reference(const struct ly_ctx *ctx, const c } API int -nc_server_config_new_ch_tls_del_keystore_reference(const char *client_name, const char *endpt_name, +nc_server_config_new_ch_tls_del_keystore_ref(const char *client_name, const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); @@ -1413,7 +1413,7 @@ nc_server_config_new_ch_tls_del_crl(const char *client_name, const char *endpt_n } API int -nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config) +nc_config_new_tls_endpoint_client_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); @@ -1422,7 +1422,7 @@ nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const char } API int -nc_config_new_tls_del_endpoint_client_reference(const char *endpt_name, struct lyd_node **config) +nc_config_new_tls_del_endpoint_client_ref(const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); diff --git a/src/server_config.h b/src/server_config.h index 91350d6d..ec48fb21 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -310,7 +310,7 @@ int nc_server_config_new_ssh_del_hostkey(const struct ly_ctx *ctx, const char *e * 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_new_ssh_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, +int nc_server_config_new_ssh_keystore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, const char *keystore_reference, struct lyd_node **config); /** @@ -321,7 +321,7 @@ int nc_server_config_new_ssh_keystore_reference(const struct ly_ctx *ctx, const * @param[in,out] config Configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ssh_del_keystore_reference(const char *endpt_name, const char *hostkey_name, +int nc_server_config_new_ssh_del_keystore_ref(const char *endpt_name, const char *hostkey_name, struct lyd_node **config); /** @@ -495,7 +495,7 @@ int nc_server_config_new_ssh_del_user(const char *endpt_name, * 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_new_ssh_truststore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, +int nc_server_config_new_ssh_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *truststore_reference, struct lyd_node **config); /** @@ -506,7 +506,7 @@ int nc_server_config_new_ssh_truststore_reference(const struct ly_ctx *ctx, cons * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ssh_del_truststore_reference(const char *endpt_name, const char *user_name, +int nc_server_config_new_ssh_del_truststore_ref(const char *endpt_name, const char *user_name, struct lyd_node **config); /** @@ -524,7 +524,7 @@ int nc_server_config_new_ssh_del_truststore_reference(const char *endpt_name, co * 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_config_new_ssh_endpoint_user_reference(const struct ly_ctx *ctx, const char *endpt_name, +int nc_config_new_ssh_endpoint_user_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config); /** @@ -534,7 +534,7 @@ int nc_config_new_ssh_endpoint_user_reference(const struct ly_ctx *ctx, const ch * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_config_new_ssh_del_endpoint_user_reference(const char *endpt_name, struct lyd_node **config); +int nc_config_new_ssh_del_endpoint_user_ref(const char *endpt_name, struct lyd_node **config); /** * @brief Creates new YANG configuration data nodes for host-key algorithms replacing any previous ones. @@ -702,7 +702,7 @@ int nc_server_config_new_tls_del_server_certificate(const char *endpt_name, stru * 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_new_tls_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *asym_key_ref, +int nc_server_config_new_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); /** @@ -712,7 +712,7 @@ int nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_tls_del_keystore_reference(const char *endpt_name, struct lyd_node **config); +int nc_server_config_new_tls_del_keystore_ref(const char *endpt_name, struct lyd_node **config); /** * @brief Creates new YANG configuration data nodes for a client's (end-entity) certificate. @@ -974,7 +974,7 @@ int nc_server_config_new_tls_del_crl(const char *endpt_name, struct lyd_node **c * 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_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const char *endpt_name, +int nc_config_new_tls_endpoint_client_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config); /** @@ -984,7 +984,7 @@ int nc_config_new_tls_endpoint_client_reference(const struct ly_ctx *ctx, const * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_config_new_tls_del_endpoint_client_reference(const char *endpt_name, struct lyd_node **config); +int nc_config_new_tls_del_endpoint_client_ref(const char *endpt_name, struct lyd_node **config); /** * @} TLS Server Configuration @@ -1236,7 +1236,7 @@ int nc_server_config_new_ch_ssh_del_hostkey(const char *client_name, const char * 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_new_ch_ssh_keystore_reference(const struct ly_ctx *ctx, const char *client_name, +int nc_server_config_new_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); /** @@ -1248,7 +1248,7 @@ int nc_server_config_new_ch_ssh_keystore_reference(const struct ly_ctx *ctx, con * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_ssh_del_keystore_reference(const char *client_name, const char *endpt_name, +int nc_server_config_new_ch_ssh_del_keystore_ref(const char *client_name, const char *endpt_name, const char *hostkey_name, struct lyd_node **config); /** @@ -1440,7 +1440,7 @@ int nc_server_config_new_ch_ssh_del_user(const char *client_name, const char *en * 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_new_ch_ssh_truststore_reference(const struct ly_ctx *ctx, const char *client_name, +int nc_server_config_new_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); /** @@ -1452,7 +1452,7 @@ int nc_server_config_new_ch_ssh_truststore_reference(const struct ly_ctx *ctx, c * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_ssh_del_truststore_reference(const char *client_name, const char *endpt_name, +int nc_server_config_new_ch_ssh_del_truststore_ref(const char *client_name, const char *endpt_name, const char *user_name, struct lyd_node **config); /** @@ -1643,7 +1643,7 @@ int nc_server_config_new_ch_tls_del_server_certificate(const char *client_name, * 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_new_ch_tls_keystore_reference(const struct ly_ctx *ctx, const char *client_name, +int nc_server_config_new_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); /** @@ -1654,7 +1654,7 @@ int nc_server_config_new_ch_tls_keystore_reference(const struct ly_ctx *ctx, con * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_tls_del_keystore_reference(const char *client_name, const char *endpt_name, +int nc_server_config_new_ch_tls_del_keystore_ref(const char *client_name, const char *endpt_name, struct lyd_node **config); /** diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c index 037da46e..b6ccb1b4 100644 --- a/tests/test_endpt_share_clients.c +++ b/tests/test_endpt_share_clients.c @@ -199,7 +199,7 @@ setup_ssh(void **state) ret = nc_server_config_new_address_port(ctx, "SSH_endpt_1", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); - ret = nc_config_new_ssh_endpoint_user_reference(ctx, "SSH_endpt_1", "SSH_endpt_2", &tree); + ret = nc_config_new_ssh_endpoint_user_ref(ctx, "SSH_endpt_1", "SSH_endpt_2", &tree); assert_int_equal(ret, 0); /* create the second SSH endpoint with a single client */ @@ -281,7 +281,7 @@ setup_tls(void **state) ret = nc_server_config_new_address_port(ctx, "TLS_endpt_2", NC_TI_OPENSSL, "127.0.0.1", 10008, &tree); assert_int_equal(ret, 0); - ret = nc_config_new_tls_endpoint_client_reference(ctx, "TLS_endpt_2", "TLS_endpt_1", &tree); + ret = nc_config_new_tls_endpoint_client_ref(ctx, "TLS_endpt_2", "TLS_endpt_1", &tree); assert_int_equal(ret, 0); /* configure the server based on the yang data */ diff --git a/tests/test_ks_ts.c b/tests/test_ks_ts.c index 2d125fad..c76997f4 100644 --- a/tests/test_ks_ts.c +++ b/tests/test_ks_ts.c @@ -141,10 +141,10 @@ setup_ssh(void **state) ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_keystore_reference(ctx, "endpt", "hostkey", "test_keystore", &tree); + ret = nc_server_config_new_ssh_keystore_ref(ctx, "endpt", "hostkey", "test_keystore", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_truststore_reference(ctx, "endpt", "client", "test_truststore", &tree); + ret = nc_server_config_new_ssh_truststore_ref(ctx, "endpt", "client", "test_truststore", &tree); assert_int_equal(ret, 0); ret = nc_server_config_new_keystore_asym_key(ctx, "test_keystore", TESTS_DIR "/data/key_rsa", NULL, &tree); @@ -260,7 +260,7 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* new keystore ref for the TLS server cert */ - ret = nc_server_config_new_tls_keystore_reference(ctx, "endpt", "server_key", "server_cert", &tree); + ret = nc_server_config_new_tls_keystore_ref(ctx, "endpt", "server_key", "server_cert", &tree); assert_int_equal(ret, 0); /* new truststore ref for the client cert */ From 0df30061065717e47a59b9c49c13b5fb7fa995c1 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 17 Aug 2023 15:36:54 +0200 Subject: [PATCH 061/134] config UPDATE use correct public key types --- src/config_new.c | 804 ++++++++++++++++++++++++++--------------- src/config_new.h | 6 +- src/config_new_ssh.c | 24 +- src/config_new_tls.c | 12 +- src/server_config.c | 83 ++++- src/server_config.h | 5 +- src/server_config_ks.c | 2 +- src/server_config_ts.c | 2 +- src/session.c | 63 ++++ src/session_p.h | 13 +- tests/test_ks_ts.c | 4 +- 11 files changed, 687 insertions(+), 331 deletions(-) diff --git a/src/config_new.c b/src/config_new.c index 4cefadf6..fa8dca20 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -210,7 +210,7 @@ nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT format) case NC_PRIVKEY_FORMAT_EC: return "ietf-crypto-types:ec-private-key-format"; case NC_PRIVKEY_FORMAT_X509: - return "libnetconf2-netconf-server:subject-private-key-info-format"; + return "libnetconf2-netconf-server:private-key-info-format"; case NC_PRIVKEY_FORMAT_OPENSSH: return "libnetconf2-netconf-server:openssh-private-key-format"; default: @@ -219,6 +219,306 @@ nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT format) } } +static int +nc_server_config_new_pubkey_bin_to_b64(const unsigned char *pub_bin, int bin_len, char **pubkey) +{ + int ret = 0, b64_len; + char *pub_b64 = NULL; + + /* get b64 buffer len, for ever 3 bytes of bin 4 bytes of b64 + NULL terminator */ + if (bin_len % 3 == 0) { + pub_b64 = malloc((bin_len / 3) * 4 + 1); + } else { + /* bin len not divisible by 3, need to add 4 bytes for some padding so that the len is divisible by 4 */ + pub_b64 = malloc((bin_len / 3) * 4 + 4 + 1); + } + if (!pub_b64) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* bin to b64 */ + b64_len = EVP_EncodeBlock((unsigned char *)pub_b64, pub_bin, bin_len); + *pubkey = strndup(pub_b64, b64_len); + if (!*pubkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + +cleanup: + free(pub_b64); + return ret; +} + +static int +nc_server_config_new_bn_to_bin(const BIGNUM *bn, unsigned char **bin, int *bin_len) +{ + int ret = 0; + unsigned char *bin_tmp = NULL; + + NC_CHECK_ARG_RET(NULL, bn, bin, bin_len, 1); + + *bin = NULL; + + /* prepare buffer for converting BN to binary */ + bin_tmp = calloc(BN_num_bytes(bn), sizeof *bin_tmp); + if (!bin_tmp) { + ERRMEM; + return 1; + } + + /* convert to binary */ + *bin_len = BN_bn2bin(bn, bin_tmp); + + /* if the highest bit in the MSB is set a byte with the value 0 has to be prepended */ + if (bin_tmp[0] & 0x80) { + *bin = malloc(*bin_len + 1); + if (!*bin) { + ERRMEM; + ret = 1; + goto cleanup; + } + + (*bin)[0] = 0; + memcpy(*bin + 1, bin_tmp, *bin_len); + (*bin_len)++; + } else { + *bin = malloc(*bin_len); + if (!*bin) { + ERRMEM; + ret = 1; + goto cleanup; + } + + memcpy(*bin, bin_tmp, *bin_len); + } + +cleanup: + free(bin_tmp); + return ret; +} + +/* ssh pubkey defined in RFC 4253 section 6.6 */ +static int +nc_server_config_new_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) +{ + int ret = 0, e_len, n_len, p_len, bin_len; + BIGNUM *e = NULL, *n = NULL, *p = NULL; + unsigned char *e_bin = NULL, *n_bin = NULL, *p_bin = NULL, *bin = NULL, *bin_tmp; + const char *algorithm_name, *curve_name; + char *ec_group = NULL; + uint32_t alg_name_len, curve_name_len, alg_name_len_be, curve_name_len_be, p_len_be, e_len_be, n_len_be; + size_t ec_group_len; + + if (EVP_PKEY_is_a(pkey, "RSA")) { + /* RSA key */ + algorithm_name = "ssh-rsa"; + + /* get the public key params */ + if (!EVP_PKEY_get_bn_param(pkey, "e", &e) || !EVP_PKEY_get_bn_param(pkey, "n", &n)) { + ERR(NULL, "Getting public key parameters from RSA private key failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = 1; + goto cleanup; + } + + /* BIGNUM to bin */ + if (nc_server_config_new_bn_to_bin(e, &e_bin, &e_len) || nc_server_config_new_bn_to_bin(n, &n_bin, &n_len)) { + ret = 1; + goto cleanup; + } + + alg_name_len = strlen(algorithm_name); + /* buffer for public key in binary, which looks like this: + * alg_name len (4 bytes), alg_name, PK exponent len (4 bytes), PK exponent, modulus len (4 bytes), modulus + */ + bin_len = 4 + alg_name_len + 4 + e_len + 4 + n_len; + bin = malloc(bin_len); + if (!bin) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* to network byte order (big endian) */ + alg_name_len_be = htonl(alg_name_len); + e_len_be = htonl(e_len); + n_len_be = htonl(n_len); + + /* create the public key in binary */ + bin_tmp = bin; + memcpy(bin_tmp, &alg_name_len_be, 4); + bin_tmp += 4; + memcpy(bin_tmp, algorithm_name, alg_name_len); + bin_tmp += alg_name_len; + memcpy(bin_tmp, &e_len_be, 4); + bin_tmp += 4; + memcpy(bin_tmp, e_bin, e_len); + bin_tmp += e_len; + memcpy(bin_tmp, &n_len_be, 4); + bin_tmp += 4; + memcpy(bin_tmp, n_bin, n_len); + } else if (EVP_PKEY_is_a(pkey, "EC")) { + /* EC Private key, get it's group first */ + /* get group len */ + ret = EVP_PKEY_get_utf8_string_param(pkey, "group", NULL, 0, &ec_group_len); + if (!ret) { + ret = 1; + goto cleanup; + } + /* alloc mem for group + 1 for \0 */ + ec_group = malloc(ec_group_len + 1); + if (!ec_group) { + ERRMEM; + ret = 1; + goto cleanup; + } + /* get the group */ + ret = EVP_PKEY_get_utf8_string_param(pkey, "group", ec_group, ec_group_len + 1, NULL); + if (!ret) { + ERR(NULL, "Getting public key parameter from EC private key failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = 1; + goto cleanup; + } + + /* get alg and curve names */ + if (!strcmp(ec_group, "P-256") || !strcmp(ec_group, "secp256r1") || !strcmp(ec_group, "prime256v1")) { + algorithm_name = "ecdsa-sha2-nistp256"; + curve_name = "nistp256"; + } else if (!strcmp(ec_group, "P-384") || !strcmp(ec_group, "secp384r1")) { + algorithm_name = "ecdsa-sha2-nistp384"; + curve_name = "nistp384"; + } else if (!strcmp(ec_group, "P-521") || !strcmp(ec_group, "secp521r1")) { + algorithm_name = "ecdsa-sha2-nistp521"; + curve_name = "nistp521"; + } else { + ERR(NULL, "EC group \"%s\" not supported.", ec_group); + ret = 1; + goto cleanup; + } + + /* get the public key - p, which is a point on the elliptic curve */ + ret = EVP_PKEY_get_bn_param(pkey, "p", &p); + if (!ret) { + ERR(NULL, "Getting public key point from the EC private key failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = 1; + goto cleanup; + } + + /* prepare buffer for converting p to binary */ + p_bin = malloc(BN_num_bytes(p)); + if (!p_bin) { + ERRMEM; + ret = 1; + goto cleanup; + } + /* convert to binary */ + p_len = BN_bn2bin(p, p_bin); + + alg_name_len = strlen(algorithm_name); + curve_name_len = strlen(curve_name); + /* buffer for public key in binary, which looks like so: + * alg_name len (4 bytes), alg_name, curve_name len (4 bytes), curve_name, PK point p len (4 bytes), PK point p + */ + bin_len = 4 + alg_name_len + 4 + curve_name_len + 4 + p_len; + bin = malloc(bin_len); + if (!bin) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* to network byte order (big endian) */ + alg_name_len_be = htonl(alg_name_len); + curve_name_len_be = htonl(curve_name_len); + p_len_be = htonl(p_len); + + /* create the public key in binary */ + bin_tmp = bin; + memcpy(bin_tmp, &alg_name_len_be, 4); + bin_tmp += 4; + memcpy(bin_tmp, algorithm_name, alg_name_len); + bin_tmp += alg_name_len; + memcpy(bin_tmp, &curve_name_len_be, 4); + bin_tmp += 4; + memcpy(bin_tmp, curve_name, curve_name_len); + bin_tmp += curve_name_len; + memcpy(bin_tmp, &p_len_be, 4); + bin_tmp += 4; + memcpy(bin_tmp, p_bin, p_len); + } else if (EVP_PKEY_is_a(pkey, "ED25519")) { + ERR(NULL, "Generating PEM ED25519 key from OpenSSH is not supported by libssh yet."); + ret = 1; + goto cleanup; + } else { + ERR(NULL, "Unable to generate public key from private key (Private key type not supported)."); + ret = 1; + goto cleanup; + } + + ret = nc_server_config_new_pubkey_bin_to_b64(bin, bin_len, pubkey); + if (ret) { + ERR(NULL, "Converting public key from binary to base64 failed."); + goto cleanup; + } + +cleanup: + free(bin); + free(e_bin); + free(n_bin); + free(ec_group); + free(p_bin); + BN_free(e); + BN_free(n); + BN_free(p); + return ret; +} + +/* spki = subject public key info */ +static int +nc_server_config_new_evp_pkey_to_spki_pubkey(EVP_PKEY *pkey, char **pubkey) +{ + int ret = 0, len; + BIO *bio = NULL; + char *pub_b64 = NULL; + + bio = BIO_new(BIO_s_mem()); + if (!bio) { + ERR(NULL, "Creating new BIO failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = 1; + goto cleanup; + } + + /* write the evp_pkey contents to bio */ + if (!PEM_write_bio_PUBKEY(bio, pkey)) { + ERR(NULL, "Writing public key to BIO failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = 1; + goto cleanup; + } + + /* read the pubkey from bio */ + len = BIO_get_mem_data(bio, &pub_b64); + if (len <= 0) { + ERR(NULL, "Reading base64 private key from BIO failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = 1; + goto cleanup; + } + + /* copy the public key without the header and footer */ + *pubkey = strndup(pub_b64 + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER), + len - strlen(NC_SUBJECT_PUBKEY_INFO_HEADER) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER)); + if (!*pubkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + +cleanup: + BIO_free(bio); + return ret; +} + int nc_server_config_new_read_certificate(const char *cert_path, char **cert) { @@ -305,7 +605,7 @@ nc_server_config_new_read_certificate(const char *cert_path, char **cert) } static int -nc_server_config_new_read_ssh2_pubkey(FILE *f, char **pubkey) +nc_server_config_new_read_pubkey_ssh2(FILE *f, char **pubkey) { char *buffer = NULL; size_t size = 0, pubkey_len = 0; @@ -355,74 +655,20 @@ static int nc_server_config_new_read_pubkey_openssl(FILE *f, char **pubkey) { int ret = 0; - EVP_PKEY *pkey = NULL; - BIO *bio = NULL; - char *key = NULL; - int pub_len; - - /* read the pubkey from file */ - pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL); - if (!pkey) { - ret = -1; - goto cleanup; - } - - bio = BIO_new(BIO_s_mem()); - if (!bio) { - ret = -1; - goto cleanup; - } - - /* write the pubkey into bio */ - ret = PEM_write_bio_PUBKEY(bio, pkey); - if (!ret) { - ret = -1; - goto cleanup; - } - - pub_len = BIO_pending(bio); - if (pub_len <= 0) { - ret = -1; - goto cleanup; - } - - /* get pubkey's length */ - key = malloc(pub_len + 1); - if (!key) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* read the public key from bio */ - ret = BIO_read(bio, key, pub_len); - if (ret <= 0) { - ret = -1; - goto cleanup; - } - key[pub_len] = '\0'; - - /* strip the pubkey of the header and footer */ - *pubkey = strdup(key + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER)); - if (!*pubkey) { - ERRMEM; - ret = 1; - goto cleanup; - } + EVP_PKEY *pub_pkey = NULL; - (*pubkey)[strlen(*pubkey) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER)] = '\0'; + NC_CHECK_ARG_RET(NULL, f, pubkey, 1); - ret = 0; -cleanup: - if (ret == -1) { - ERR(NULL, "Error getting public key from file (OpenSSL Error): \"%s\".", ERR_reason_error_string(ERR_get_error())); - ret = 1; + /* read the pubkey from file */ + pub_pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL); + if (!pub_pkey) { + ERR(NULL, "Reading public key from file failed (%s).", ERR_reason_error_string(ERR_get_error())); + return 1; } - BIO_free(bio); - EVP_PKEY_free(pkey); - free(key); + ret = nc_server_config_new_evp_pkey_to_ssh_pubkey(pub_pkey, pubkey); + EVP_PKEY_free(pub_pkey); return ret; } @@ -432,6 +678,8 @@ nc_server_config_new_read_pubkey_libssh(const char *pubkey_path, char **pubkey) int ret = 0; ssh_key pub_sshkey = NULL; + NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1); + ret = ssh_pki_import_pubkey_file(pubkey_path, &pub_sshkey); if (ret) { ERR(NULL, "Importing public key from file \"%s\" failed.", pubkey_path); @@ -440,22 +688,24 @@ nc_server_config_new_read_pubkey_libssh(const char *pubkey_path, char **pubkey) ret = ssh_pki_export_pubkey_base64(pub_sshkey, pubkey); if (ret) { - ERR(NULL, "Exporting public key to base64 failed."); + ERR(NULL, "Importing pubkey failed."); + goto cleanup; } +cleanup: ssh_key_free(pub_sshkey); - return ret; + return 0; } int -nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_PUBKEY_FORMAT *pubkey_type) +nc_server_config_new_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey) { int ret = 0; FILE *f = NULL; char *header = NULL; size_t len = 0; - NC_CHECK_ARG_RET(NULL, pubkey, pubkey_type, 1); + NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1); *pubkey = NULL; @@ -466,6 +716,7 @@ nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_PUBKE goto cleanup; } + /* read the header */ if (getline(&header, &len, f) < 0) { ERR(NULL, "Error reading header from file \"%s\".", pubkey_path); ret = 1; @@ -476,17 +727,13 @@ nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_PUBKE if (!strncmp(header, NC_SUBJECT_PUBKEY_INFO_HEADER, strlen(NC_SUBJECT_PUBKEY_INFO_HEADER))) { /* it's subject public key info public key */ ret = nc_server_config_new_read_pubkey_openssl(f, pubkey); - *pubkey_type = NC_PUBKEY_FORMAT_X509; } else if (!strncmp(header, NC_SSH2_PUBKEY_HEADER, strlen(NC_SSH2_PUBKEY_HEADER))) { /* it's ssh2 public key */ - ret = nc_server_config_new_read_ssh2_pubkey(f, pubkey); - *pubkey_type = NC_PUBKEY_FORMAT_SSH2; + ret = nc_server_config_new_read_pubkey_ssh2(f, pubkey); } else { /* it's probably OpenSSH public key */ ret = nc_server_config_new_read_pubkey_libssh(pubkey_path, pubkey); - *pubkey_type = NC_PUBKEY_FORMAT_SSH2; } - if (ret) { ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path); goto cleanup; @@ -498,301 +745,289 @@ nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_PUBKE } free(header); + return ret; +} + +int +nc_server_config_new_get_spki_pubkey_file(const char *pubkey_path, char **pubkey) +{ + int ret = 0; + FILE *f = NULL; + EVP_PKEY *pub_pkey = NULL; + + NC_CHECK_ARG_RET(NULL, pubkey_path, pubkey, 1); + *pubkey = NULL; + + f = fopen(pubkey_path, "r"); + if (!f) { + ERR(NULL, "Unable to open file \"%s\".", pubkey_path); + ret = 1; + goto cleanup; + } + + /* read the pubkey from file */ + pub_pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL); + if (!pub_pkey) { + ERR(NULL, "Reading public key from file failed (%s).", ERR_reason_error_string(ERR_get_error())); + return 1; + } + + ret = nc_server_config_new_evp_pkey_to_spki_pubkey(pub_pkey, pubkey); + if (ret) { + goto cleanup; + } + +cleanup: + if (f) { + fclose(f); + } + + EVP_PKEY_free(pub_pkey); return ret; } static int -nc_server_config_new_get_privkey_openssl(FILE *f, char **privkey, EVP_PKEY **priv_pkey) +nc_server_config_new_privkey_header_to_format(FILE *f_privkey, const char *privkey_path, NC_PRIVKEY_FORMAT *privkey_format) { - int ret = 0, priv_len; - BIO *bio = NULL; + char *privkey_header = NULL; + size_t len = 0; - NC_CHECK_ARG_RET(NULL, privkey, priv_pkey, 1); + /* read header */ + if (getline(&privkey_header, &len, f_privkey) < 0) { + ERR(NULL, "Error reading header from file \"%s\".", privkey_path); + return 1; + } - /* read private key from file */ - *priv_pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL); - if (!*priv_pkey) { - ret = -1; - goto cleanup; + if (!strncmp(privkey_header, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) { + /* it's PKCS8 (X.509) private key */ + *privkey_format = NC_PRIVKEY_FORMAT_X509; + } else if (!strncmp(privkey_header, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) { + /* it's OpenSSH private key */ + *privkey_format = NC_PRIVKEY_FORMAT_OPENSSH; + } else if (!strncmp(privkey_header, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) { + /* it's RSA privkey in PKCS1 format */ + *privkey_format = NC_PRIVKEY_FORMAT_RSA; + } else if (!strncmp(privkey_header, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) { + /* it's EC privkey in SEC1 format */ + *privkey_format = NC_PRIVKEY_FORMAT_EC; + } else { + ERR(NULL, "Private key format (%s) not supported.", privkey_header); + free(privkey_header); + return 1; } + /* reset the reading head */ + rewind(f_privkey); + free(privkey_header); + return 0; +} + +static int +nc_server_config_new_get_privkey_openssl(const char *privkey_path, FILE *f_privkey, char **privkey, EVP_PKEY **pkey) +{ + int ret = 0, len; + BIO *bio = NULL; + char *priv_b64 = NULL; + bio = BIO_new(BIO_s_mem()); if (!bio) { - ret = -1; + ERR(NULL, "Creating new BIO failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = 1; goto cleanup; } - /* write the private key in to bio */ - ret = PEM_write_bio_PrivateKey(bio, *priv_pkey, NULL, NULL, 0, NULL, NULL); - if (!ret) { - ret = -1; + /* read the privkey file, create EVP_PKEY */ + *pkey = PEM_read_PrivateKey(f_privkey, NULL, NULL, NULL); + if (!*pkey) { + ERR(NULL, "Getting private key from file \"%s\" failed (%s).", privkey_path, ERR_reason_error_string(ERR_get_error())); + ret = 1; goto cleanup; } - priv_len = BIO_pending(bio); - if (priv_len <= 0) { - ret = -1; + /* write the privkey to bio */ + if (!PEM_write_bio_PrivateKey(bio, *pkey, NULL, NULL, 0, NULL, NULL)) { + ERR(NULL, "Writing private key to BIO failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = 1; goto cleanup; } - /* get private key's length */ - *privkey = malloc(priv_len + 1); - if (!*privkey) { - ERRMEM; + /* read the privkey from bio */ + len = BIO_get_mem_data(bio, &priv_b64); + if (len <= 0) { + ERR(NULL, "Reading base64 private key from BIO failed (%s).", ERR_reason_error_string(ERR_get_error())); ret = 1; goto cleanup; } - /* read the private key from bio */ - ret = BIO_read(bio, *privkey, priv_len); - if (ret <= 0) { - ret = -1; - goto cleanup; - } - (*privkey)[priv_len] = '\0'; + *privkey = strndup(priv_b64, len); - ret = 0; cleanup: - if (ret < 0) { - ERR(NULL, "Getting private key from file failed (%s).", ERR_reason_error_string(ERR_get_error())); - } BIO_free(bio); return ret; } static int -nc_server_config_new_privkey_to_pubkey_openssl(EVP_PKEY *priv_pkey, char **pubkey) +nc_server_config_new_get_privkey_libssh(const char *privkey_path, char **privkey, EVP_PKEY **pkey) { - int ret = 0, pub_len; + int ret = 0; BIO *bio = NULL; + char *priv_b64 = NULL; + ssh_key key = NULL; - bio = BIO_new(BIO_s_mem()); - if (!bio) { - ret = -1; + ret = ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, &key); + if (ret) { + ERR(NULL, "Importing privkey from file \"%s\" failed.", privkey_path); goto cleanup; } - /* write the pubkey into bio */ - ret = PEM_write_bio_PUBKEY(bio, priv_pkey); - if (!ret) { - ret = -1; + /* exports the key in a format in which OpenSSL can read it */ + ret = ssh_pki_export_privkey_base64(key, NULL, NULL, NULL, &priv_b64); + if (ret) { + ERR(NULL, "Exporting privkey to base64 failed."); goto cleanup; } - /* get the length of the pubkey */ - pub_len = BIO_pending(bio); - if (pub_len <= 0) { - ret = -1; + bio = BIO_new(BIO_s_mem()); + if (!bio) { + ERR(NULL, "Creating new BIO failed (%s).", ERR_reason_error_string(ERR_get_error())); + ret = 1; goto cleanup; } - *pubkey = malloc(pub_len + 1); - if (!*pubkey) { - ERRMEM; + ret = BIO_write(bio, priv_b64, strlen(priv_b64)); + if (ret <= 0) { + ERR(NULL, "Writing private key to BIO failed (%s).", ERR_reason_error_string(ERR_get_error())); ret = 1; goto cleanup; } - /* read the pubkey from the bio */ - ret = BIO_read(bio, *pubkey, pub_len); - if (ret <= 0) { - ret = -1; + /* create EVP_PKEY from the b64 */ + *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + if (!*pkey) { + ERR(NULL, "Getting private key from file \"%s\" failed (%s).", privkey_path, ERR_reason_error_string(ERR_get_error())); + ret = 1; goto cleanup; } - (*pubkey)[pub_len] = '\0'; + *privkey = strndup(priv_b64, ret); + + /* ok */ ret = 0; cleanup: - if (ret < 0) { - ERR(NULL, "Converting private to public key failed (%s).", ERR_reason_error_string(ERR_get_error())); - } + free(priv_b64); BIO_free(bio); + ssh_key_free(key); return ret; } static int -nc_server_config_new_privkey_to_pubkey_libssh(const ssh_key priv_sshkey, char **pubkey) +nc_server_config_new_get_privkey(const char *privkey_path, NC_PRIVKEY_FORMAT *privkey_format, char **privkey, EVP_PKEY **pkey) { - int ret; - ssh_key pub_sshkey = NULL; + int ret = 0; + FILE *f_privkey = NULL; + char *priv = NULL; - ret = ssh_pki_export_privkey_to_pubkey(priv_sshkey, &pub_sshkey); - if (ret) { - ERR(NULL, "Exporting privkey to pubkey failed."); - return ret; + f_privkey = fopen(privkey_path, "r"); + if (!f_privkey) { + ERR(NULL, "Unable to open file \"%s\".", privkey_path); + ret = 1; + goto cleanup; } - ret = ssh_pki_export_pubkey_base64(pub_sshkey, pubkey); + /* read the first line from the privkey to determine it's type */ + ret = nc_server_config_new_privkey_header_to_format(f_privkey, privkey_path, privkey_format); if (ret) { - ERR(NULL, "Exporting pubkey to base64 failed."); + ERR(NULL, "Getting private key format from file \"%s\" failed.", privkey_path); + goto cleanup; } - ssh_key_free(pub_sshkey); - return ret; -} - -static int -nc_server_config_new_privkey_to_pubkey(EVP_PKEY *priv_pkey, const ssh_key priv_sshkey, NC_PRIVKEY_FORMAT privkey_type, char **pubkey, NC_PUBKEY_FORMAT *pubkey_type) -{ - switch (privkey_type) { + switch (*privkey_format) { + /* fall-through */ case NC_PRIVKEY_FORMAT_RSA: case NC_PRIVKEY_FORMAT_EC: - case NC_PRIVKEY_FORMAT_OPENSSH: - *pubkey_type = NC_PUBKEY_FORMAT_SSH2; - return nc_server_config_new_privkey_to_pubkey_libssh(priv_sshkey, pubkey); case NC_PRIVKEY_FORMAT_X509: - *pubkey_type = NC_PUBKEY_FORMAT_X509; - return nc_server_config_new_privkey_to_pubkey_openssl(priv_pkey, pubkey); + /* OpenSSL solely can do this */ + ret = nc_server_config_new_get_privkey_openssl(privkey_path, f_privkey, &priv, pkey); + break; + case NC_PRIVKEY_FORMAT_OPENSSH: + /* need the help of libssh */ + ret = nc_server_config_new_get_privkey_libssh(privkey_path, &priv, pkey); + /* if the function returned successfully, the key is no longer OpenSSH, it was converted to x509 */ + *privkey_format = NC_PRIVKEY_FORMAT_X509; + break; default: + ERR(NULL, "Private key format not recognized."); + ret = 1; break; } - - return 1; -} - -static int -nc_server_config_new_get_privkey_libssh(const char *privkey_path, char **privkey, ssh_key *priv_sshkey) -{ - int ret; - - *priv_sshkey = NULL; - - ret = ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, priv_sshkey); if (ret) { - ERR(NULL, "Importing privkey from file \"%s\" failed.", privkey_path); - return ret; + goto cleanup; } - ret = ssh_pki_export_privkey_base64(*priv_sshkey, NULL, NULL, NULL, privkey); - if (ret) { - ERR(NULL, "Exporting privkey from file \"%s\" to base64 failed.", privkey_path); + /* strip private key's header and footer */ + *privkey = strdup(priv + strlen(NC_PKCS8_PRIVKEY_HEADER)); + if (!*privkey) { + ERRMEM; + ret = 1; + goto cleanup; + } + (*privkey)[strlen(*privkey) - strlen(NC_PKCS8_PRIVKEY_FOOTER)] = '\0'; + +cleanup: + if (f_privkey) { + fclose(f_privkey); } + free(priv); return ret; } int -nc_server_config_new_get_keys(const char *privkey_path, const char *pubkey_path, - char **privkey, char **pubkey, NC_PRIVKEY_FORMAT *privkey_type, NC_PUBKEY_FORMAT *pubkey_type) +nc_server_config_new_get_asym_key_pair(const char *privkey_path, const char *pubkey_path, NC_PUBKEY_FORMAT wanted_pubkey_format, + char **privkey, NC_PRIVKEY_FORMAT *privkey_type, char **pubkey) { int ret = 0; EVP_PKEY *priv_pkey = NULL; - ssh_key priv_sshkey = NULL; - FILE *f_privkey = NULL; - char *header = NULL; - size_t len = 0; - char *priv = NULL, *pub = NULL; - NC_CHECK_ARG_RET(NULL, privkey_path, privkey, pubkey, privkey_type, 1); + NC_CHECK_ARG_RET(NULL, privkey_path, privkey, privkey_type, pubkey, 1); *privkey = NULL; *pubkey = NULL; - /* get private key first */ - f_privkey = fopen(privkey_path, "r"); - if (!f_privkey) { - ERR(NULL, "Unable to open file \"%s\".", privkey_path); - ret = 1; - goto cleanup; - } - - if (getline(&header, &len, f_privkey) < 0) { - ERR(NULL, "Error reading header from file \"%s\".", privkey_path); - ret = 1; - goto cleanup; - } - rewind(f_privkey); - - if (!strncmp(header, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) { - /* it's PKCS8 (X.509) private key */ - *privkey_type = NC_PRIVKEY_FORMAT_X509; - ret = nc_server_config_new_get_privkey_openssl(f_privkey, &priv, &priv_pkey); - } else if (!strncmp(header, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) { - /* it's OpenSSH private key */ - *privkey_type = NC_PRIVKEY_FORMAT_OPENSSH; - ret = nc_server_config_new_get_privkey_libssh(privkey_path, &priv, &priv_sshkey); - } else if (!strncmp(header, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) { - /* it's RSA privkey in PKCS1 format */ - *privkey_type = NC_PRIVKEY_FORMAT_RSA; - ret = nc_server_config_new_get_privkey_libssh(privkey_path, &priv, &priv_sshkey); - } else if (!strncmp(header, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) { - /* it's EC privkey in SEC1 format */ - *privkey_type = NC_PRIVKEY_FORMAT_EC; - ret = nc_server_config_new_get_privkey_libssh(privkey_path, &priv, &priv_sshkey); - } else { - ERR(NULL, "Private key format not supported."); - ret = 1; - goto cleanup; - } - if (ret) { - goto cleanup; - } - - if (pubkey_path) { - ret = nc_server_config_new_get_pubkey(pubkey_path, &pub, pubkey_type); - } else { - ret = nc_server_config_new_privkey_to_pubkey(priv_pkey, priv_sshkey, *privkey_type, &pub, pubkey_type); - } + /* get private key base64 and EVP_PKEY */ + ret = nc_server_config_new_get_privkey(privkey_path, privkey_type, privkey, &priv_pkey); if (ret) { - ERR(NULL, "Getting public key failed."); + ERR(NULL, "Getting private key from file \"%s\" failed.", privkey_path); goto cleanup; } - /* strip pubkey's header and footer only if it's generated from pkcs8 key (using OpenSSL), - * otherwise it's already stripped - */ - if (!pubkey_path && (*privkey_type == NC_PRIVKEY_FORMAT_X509)) { - *pubkey = strdup(pub + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER)); - if (!*pubkey) { - ERRMEM; - ret = 1; - goto cleanup; + /* get public key, either from file or generate it from the EVP_PKEY */ + if (!pubkey_path) { + if (wanted_pubkey_format == NC_PUBKEY_FORMAT_SSH) { + ret = nc_server_config_new_evp_pkey_to_ssh_pubkey(priv_pkey, pubkey); + } else { + ret = nc_server_config_new_evp_pkey_to_spki_pubkey(priv_pkey, pubkey); } - (*pubkey)[strlen(*pubkey) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER)] = '\0'; } else { - *pubkey = strdup(pub); - if (!*pubkey) { - ERRMEM; - ret = 1; - goto cleanup; + if (wanted_pubkey_format == NC_PUBKEY_FORMAT_SSH) { + ret = nc_server_config_new_get_ssh_pubkey_file(pubkey_path, pubkey); + } else { + ret = nc_server_config_new_get_spki_pubkey_file(pubkey_path, pubkey); } } - - /* strip private key's header and footer */ - if (*privkey_type == NC_PRIVKEY_FORMAT_OPENSSH) { - /* only OpenSSH private keys have different header and footer after processing */ - *privkey = strdup(priv + strlen(NC_OPENSSH_PRIVKEY_HEADER)); - if (!*privkey) { - ERRMEM; - ret = 1; - goto cleanup; - } - (*privkey)[strlen(*privkey) - strlen(NC_OPENSSH_PRIVKEY_FOOTER)] = '\0'; - } else { - /* the rest share the same header and footer */ - *privkey = strdup(priv + strlen(NC_PKCS8_PRIVKEY_HEADER)); - if (!*privkey) { - ERRMEM; - ret = 1; - goto cleanup; + if (ret) { + if (pubkey_path) { + ERR(NULL, "Getting public key from file \"%s\" failed.", pubkey_path); + } else { + ERR(NULL, "Generating public key from private key failed."); } - (*privkey)[strlen(*privkey) - strlen(NC_PKCS8_PRIVKEY_FOOTER)] = '\0'; + goto cleanup; } cleanup: - if (f_privkey) { - fclose(f_privkey); - } - - free(header); - free(pub); - free(priv); - - ssh_key_free(priv_sshkey); EVP_PKEY_free(priv_pkey); - return ret; } @@ -911,29 +1146,36 @@ nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt_nam } API int -nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *asym_key_name, const char *privkey_path, - const char *pubkey_path, struct lyd_node **config) +nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, const char *asym_key_name, + const char *privkey_path, const char *pubkey_path, struct lyd_node **config) { int ret = 0; char *privkey = NULL, *pubkey = NULL; NC_PRIVKEY_FORMAT privkey_type; - NC_PUBKEY_FORMAT pubkey_type; const char *privkey_format, *pubkey_format; NC_CHECK_ARG_RET(NULL, ctx, asym_key_name, privkey_path, config, 1); /* get the keys as a string from the given files */ - ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); + if (ti == NC_TI_LIBSSH) { + ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_SSH, &privkey, &privkey_type, &pubkey); + } else if (ti == NC_TI_OPENSSL) { + ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey, &privkey_type, &pubkey); + } else { + ERR(NULL, "Only SSH and TLS transports can be used to create an asymmetric key pair in the keystore."); + ret = 1; + goto cleanup; + } if (ret) { ERR(NULL, "Getting keys from file(s) failed."); goto cleanup; } /* get pubkey format str */ - if (pubkey_type == NC_PUBKEY_FORMAT_X509) { - pubkey_format = "ietf-crypto-types:public-key-info-format"; - } else { + if (ti == NC_TI_LIBSSH) { pubkey_format = "ietf-crypto-types:ssh-public-key-format"; + } else { + pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; } /* get privkey identityref value */ @@ -1028,24 +1270,16 @@ nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *pub { int ret = 0; char *pubkey = NULL; - NC_PUBKEY_FORMAT pubkey_format; - const char *format; + const char *pubkey_format = "ietf-crypto-types:ssh-public-key-format"; NC_CHECK_ARG_RET(NULL, ctx, pub_bag_name, pubkey_name, pubkey_path, config, 1); - ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_format); + ret = nc_server_config_new_get_ssh_pubkey_file(pubkey_path, &pubkey); if (ret) { goto cleanup; } - /* pubkey format to str */ - if (pubkey_format == NC_PUBKEY_FORMAT_SSH2) { - format = "ietf-crypto-types:ssh-public-key-format"; - } else { - format = "ietf-crypto-types:subject-public-key-info-format"; - } - - ret = nc_config_new_create(ctx, config, format, "/ietf-truststore:truststore/public-key-bags/" + ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-truststore:truststore/public-key-bags/" "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", pub_bag_name, pubkey_name); if (ret) { goto cleanup; diff --git a/src/config_new.h b/src/config_new.h index 76ae4815..3b7401b0 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -73,10 +73,10 @@ typedef enum { NC_ALG_MAC } NC_ALG_TYPE; -int nc_server_config_new_get_keys(const char *privkey_path, const char *pubkey_path, - char **privkey, char **pubkey, NC_PRIVKEY_FORMAT *privkey_type, NC_PUBKEY_FORMAT *pubkey_type); +int nc_server_config_new_get_asym_key_pair(const char *privkey_path, const char *pubkey_path, NC_PUBKEY_FORMAT wanted_pubkey_type, + char **privkey, NC_PRIVKEY_FORMAT *privkey_type, char **pubkey); -int nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_PUBKEY_FORMAT *pubkey_type); +int nc_server_config_new_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey); int nc_server_config_new_read_certificate(const char *cert_path, char **cert); diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index 6c10e2f1..db9670e6 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -41,23 +41,15 @@ _nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *tree_pat int ret = 0; char *pubkey = NULL, *privkey = NULL; NC_PRIVKEY_FORMAT privkey_type; - NC_PUBKEY_FORMAT pubkey_type; - const char *privkey_format, *pubkey_format; + const char *privkey_format, *pubkey_format = "ietf-crypto-types:ssh-public-key-format"; /* get the keys as a string from the given files */ - ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); + ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_SSH, &privkey, &privkey_type, &pubkey); if (ret) { ERR(NULL, "Getting keys from file(s) failed."); goto cleanup; } - /* pubkey format to str */ - if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { - 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_config_new_privkey_format_to_identityref(privkey_type); if (!privkey_format) { @@ -372,22 +364,14 @@ _nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *tree { int ret = 0; char *pubkey = NULL; - NC_PUBKEY_FORMAT pubkey_type; - const char *pubkey_format; + const char *pubkey_format = "ietf-crypto-types:ssh-public-key-format"; /* get pubkey data */ - ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_type); + ret = nc_server_config_new_get_ssh_pubkey_file(pubkey_path, &pubkey); if (ret) { goto cleanup; } - /* get pubkey format */ - if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) { - pubkey_format = "ietf-crypto-types:ssh-public-key-format"; - } else { - pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; - } - ret = nc_config_new_create_append(ctx, tree_path, "public-key-format", pubkey_format, config); if (ret) { goto cleanup; diff --git a/src/config_new_tls.c b/src/config_new_tls.c index 985f1764..a094ec6f 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -38,11 +38,10 @@ _nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const cha int ret = 0; char *privkey = NULL, *pubkey = NULL, *cert = NULL; NC_PRIVKEY_FORMAT privkey_type; - NC_PUBKEY_FORMAT pubkey_type; - const char *privkey_format, *pubkey_format; + const char *privkey_format, *pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; /* get the keys as a string from the given files */ - ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); + ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey, &privkey_type, &pubkey); if (ret) { ERR(NULL, "Getting keys from file(s) failed."); goto cleanup; @@ -55,13 +54,6 @@ _nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const cha goto cleanup; } - /* get pubkey format str */ - if (pubkey_type == NC_PUBKEY_FORMAT_X509) { - pubkey_format = "ietf-crypto-types:public-key-info-format"; - } else { - pubkey_format = "ietf-crypto-types:ssh-public-key-format"; - } - /* get privkey identityref value */ privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type); if (!privkey_format) { diff --git a/src/server_config.c b/src/server_config.c index 7ffaad87..b6f693e0 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -26,6 +26,9 @@ #include #ifdef NC_ENABLED_SSH_TLS +#include +#include // EVP_PKEY_free +#include // d2i_PUBKEY #include // X509_STORE_free #endif @@ -525,7 +528,7 @@ nc_server_config_get_private_key_type(const char *format) return NC_PRIVKEY_FORMAT_RSA; } else if (!strcmp(format, "ec-private-key-format")) { return NC_PRIVKEY_FORMAT_EC; - } else if (!strcmp(format, "subject-private-key-info-format")) { + } else if (!strcmp(format, "private-key-info-format")) { return NC_PRIVKEY_FORMAT_X509; } else if (!strcmp(format, "openssh-private-key-format")) { return NC_PRIVKEY_FORMAT_OPENSSH; @@ -2006,7 +2009,7 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) format = ((struct lyd_node_term *)node)->value.ident->name; if (!strcmp(format, "ssh-public-key-format")) { - pubkey_type = NC_PUBKEY_FORMAT_SSH2; + pubkey_type = NC_PUBKEY_FORMAT_SSH; } else if (!strcmp(format, "subject-public-key-info-format")) { pubkey_type = NC_PUBKEY_FORMAT_X509; } else { @@ -2113,6 +2116,41 @@ nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, stru return 0; } +static int +nc_server_config_is_pk_subject_public_key_info(const char *b64) +{ + int ret = 0; + long len; + char *bin = NULL, *tmp; + EVP_PKEY *pkey = NULL; + + /* base64 2 binary */ + len = nc_base64_to_bin(b64, &bin); + if (len == -1) { + ERR(NULL, "Decoding base64 public key to binary failed."); + ret = -1; + goto cleanup; + } + + /* for deallocation later */ + tmp = bin; + + /* try to create EVP_PKEY from the supposed SubjectPublicKeyInfo binary data */ + pkey = d2i_PUBKEY(NULL, (const unsigned char **)&tmp, len); + if (pkey) { + /* success, it's most likely SubjectPublicKeyInfo pubkey */ + ret = 1; + } else { + /* fail, it's most likely not SubjectPublicKeyInfo pubkey */ + ret = 0; + } + +cleanup: + EVP_PKEY_free(pkey); + free(bin); + return ret; +} + static int nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) { @@ -2137,6 +2175,13 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } + /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */ + if (nc_server_config_is_pk_subject_public_key_info(lyd_get_value(node))) { + ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!"); + ret = 1; + goto cleanup; + } + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to local */ hostkey->store = NC_STORE_LOCAL; @@ -2176,6 +2221,13 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } + /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */ + if (nc_server_config_is_pk_subject_public_key_info(lyd_get_value(node))) { + ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!"); + ret = 1; + goto cleanup; + } + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey); if (ret) { @@ -2191,6 +2243,13 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } + /* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */ + if (!nc_server_config_is_pk_subject_public_key_info(lyd_get_value(node))) { + ERR(NULL, "TLS server certificate's Public Key must be in the SubjectPublicKeyInfo format!"); + ret = 1; + goto cleanup; + } + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to local */ opts->store = NC_STORE_LOCAL; @@ -2364,12 +2423,18 @@ nc_server_config_create_keystore_reference(const struct lyd_node *node, struct n } if (i == ks->asym_key_count) { - ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node)); + ERR(NULL, "Keystore entry \"%s\" not found.", lyd_get_value(node)); return 1; } hostkey->ks_ref = &ks->asym_keys[i]; + /* check if the referenced public key is SubjectPublicKeyInfo */ + if (nc_server_config_is_pk_subject_public_key_info(hostkey->ks_ref->pubkey_data)) { + ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!"); + return 1; + } + return 0; } @@ -2530,7 +2595,7 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_config_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth) +nc_server_config_ssh_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth) { uint16_t i; struct nc_truststore *ts = &server_opts.truststore; @@ -2549,6 +2614,14 @@ nc_server_config_replace_truststore_reference(const struct lyd_node *node, struc client_auth->ts_ref = &ts->pub_bags[i]; + /* check if any of the referenced public keys is SubjectPublicKeyInfo */ + for (i = 0; i < client_auth->ts_ref->pubkey_count; i++) { + if (nc_server_config_is_pk_subject_public_key_info(client_auth->ts_ref->pubkeys[i].data)) { + ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!"); + return 1; + } + } + return 0; } @@ -2601,7 +2674,7 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION /* set to truststore */ auth_client->store = NC_STORE_TRUSTSTORE; - ret = nc_server_config_replace_truststore_reference(node, auth_client); + ret = nc_server_config_ssh_replace_truststore_reference(node, auth_client); if (ret) { goto cleanup; } diff --git a/src/server_config.h b/src/server_config.h index ec48fb21..bf127570 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -138,6 +138,7 @@ int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **con * @brief Creates new YANG data nodes for an asymmetric key in the keystore. * * @param[in] ctx libyang context. + * @param[in] ti Transport in which the key pair will be used. Either SSH or TLS. * @param[in] asym_key_name Identifier of the asymmetric key pair. * This identifier is used to reference the key pair. * @param[in] privkey_path Path to a private key file. @@ -147,8 +148,8 @@ int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **con * 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_new_keystore_asym_key(const struct ly_ctx *ctx, const char *asym_key_name, const char *privkey_path, - const char *pubkey_path, struct lyd_node **config); +int nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, const char *asym_key_name, + const char *privkey_path, const char *pubkey_path, struct lyd_node **config); /** * @brief Deletes a keystore's asymmetric key from the YANG data. diff --git a/src/server_config_ks.c b/src/server_config_ks.c index 90243343..b39f8d8d 100644 --- a/src/server_config_ks.c +++ b/src/server_config_ks.c @@ -261,7 +261,7 @@ nc_server_config_ks_public_key_format(const struct lyd_node *node, NC_OPERATION format = ((struct lyd_node_term *)node)->value.ident->name; if (!strcmp(format, "ssh-public-key-format")) { - key->pubkey_type = NC_PUBKEY_FORMAT_SSH2; + key->pubkey_type = NC_PUBKEY_FORMAT_SSH; } else if (!strcmp(format, "subject-public-key-info-format")) { key->pubkey_type = NC_PUBKEY_FORMAT_X509; } else { diff --git a/src/server_config_ts.c b/src/server_config_ts.c index e32ef99b..11fec832 100644 --- a/src/server_config_ts.c +++ b/src/server_config_ts.c @@ -544,7 +544,7 @@ nc_server_config_ts_public_key_format(const struct lyd_node *node, NC_OPERATION format = ((struct lyd_node_term *)node)->value.ident->name; if (!strcmp(format, "ssh-public-key-format")) { - pkey->type = NC_PUBKEY_FORMAT_SSH2; + pkey->type = NC_PUBKEY_FORMAT_SSH; } else if (!strcmp(format, "subject-public-key-info-format")) { pkey->type = NC_PUBKEY_FORMAT_X509; } else { diff --git a/src/session.c b/src/session.c index 3851a1d1..ad96fc56 100644 --- a/src/session.c +++ b/src/session.c @@ -36,6 +36,7 @@ #ifdef NC_ENABLED_SSH_TLS #include +#include #include #include @@ -120,6 +121,68 @@ nc_privkey_format_to_str(NC_PRIVKEY_FORMAT format) } } +int +nc_base64_to_bin(const char *base64, char **bin) +{ + BIO *bio, *bio64; + size_t used = 0, size = 0, r = 0; + void *tmp = NULL; + int nl_count, i, remainder; + char *b64; + + /* insert new lines into the base64 string, so BIO_read works correctly */ + nl_count = strlen(base64) / 64; + remainder = strlen(base64) - 64 * nl_count; + b64 = calloc(strlen(base64) + nl_count + 1, 1); + if (!b64) { + ERRMEM; + return -1; + } + + for (i = 0; i < nl_count; i++) { + /* copy 64 bytes and add a NL */ + strncpy(b64 + i * 65, base64 + i * 64, 64); + b64[i * 65 + 64] = '\n'; + } + + /* copy the rest */ + strncpy(b64 + i * 65, base64 + i * 64, remainder); + + bio64 = BIO_new(BIO_f_base64()); + if (!bio64) { + ERR(NULL, "Error creating a bio (%s).", ERR_reason_error_string(ERR_get_error())); + return -1; + } + + bio = BIO_new_mem_buf(b64, strlen(b64)); + if (!bio) { + ERR(NULL, "Error creating a bio (%s).", ERR_reason_error_string(ERR_get_error())); + return -1; + } + + BIO_push(bio64, bio); + + /* store the decoded base64 in bin */ + *bin = NULL; + do { + size += 64; + + tmp = realloc(*bin, size); + if (!tmp) { + free(*bin); + return -1; + } + *bin = tmp; + + r = BIO_read(bio64, *bin + used, 64); + used += r; + } while (r == 64); + + free(b64); + BIO_free_all(bio64); + return size; +} + #endif /* NC_ENABLED_SSH_TLS */ int diff --git a/src/session_p.h b/src/session_p.h index d6ca52df..1b127330 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -63,8 +63,8 @@ typedef enum { * Enumeration of SSH public key formats. */ typedef enum { - NC_PUBKEY_FORMAT_SSH2, /**< begins with BEGIN SSH2 PUBLICKEY, see RFC 4716 */ - NC_PUBKEY_FORMAT_X509 /**< begins with BEGIN PUBLICKEY, see RFC 5280 sec. 4.1.2.7 */ + NC_PUBKEY_FORMAT_SSH, /**< see RFC 4253, section 6.6 */ + NC_PUBKEY_FORMAT_X509 /**< see RFC 5280 sec. 4.1.2.7 */ } NC_PUBKEY_FORMAT; /** @@ -745,6 +745,15 @@ struct nc_pam_thread_arg { */ const char *nc_privkey_format_to_str(NC_PRIVKEY_FORMAT format); +/** + * @brief Decodes base64 to binary. + * + * @param[in] base64 Base64 string. + * @param[out] bin Binary result, memory managed by the caller. + * @return Length of the binary data on success, -1 on error. + */ +int nc_base64_to_bin(const char *base64, char **bin); + #endif /* NC_ENABLED_SSH_TLS */ void *nc_realloc(void *ptr, size_t size); diff --git a/tests/test_ks_ts.c b/tests/test_ks_ts.c index c76997f4..cd8cd96a 100644 --- a/tests/test_ks_ts.c +++ b/tests/test_ks_ts.c @@ -147,7 +147,7 @@ setup_ssh(void **state) ret = nc_server_config_new_ssh_truststore_ref(ctx, "endpt", "client", "test_truststore", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_keystore_asym_key(ctx, "test_keystore", TESTS_DIR "/data/key_rsa", NULL, &tree); + ret = nc_server_config_new_keystore_asym_key(ctx, NC_TI_LIBSSH, "test_keystore", TESTS_DIR "/data/key_rsa", NULL, &tree); assert_int_equal(ret, 0); ret = nc_server_config_new_truststore_pubkey(ctx, "test_truststore", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); @@ -244,7 +244,7 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* new keystore asym key pair */ - ret = nc_server_config_new_keystore_asym_key(ctx, "server_key", TESTS_DIR "/data/server.key", NULL, &tree); + ret = nc_server_config_new_keystore_asym_key(ctx, NC_TI_OPENSSL, "server_key", TESTS_DIR "/data/server.key", NULL, &tree); assert_int_equal(ret, 0); /* new keystore cert belonging to the key pair */ From 0c5ea9fc1b55433d0ab985a9f9fa8878abc3a39a Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 18 Aug 2023 15:45:44 +0200 Subject: [PATCH 062/134] config BUGFIX avoid passing NULL to lyd_find_path --- src/config_new.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/config_new.c b/src/config_new.c index fa8dca20..dacb9d3c 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -96,7 +96,12 @@ nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const cha } /* create the nodes in the path */ - ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); + if (!*tree) { + ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); + } else { + /* this could output NULL if no new nodes, lyd_find_path would fail then */ + ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, NULL); + } if (ret) { goto cleanup; } @@ -135,7 +140,12 @@ nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, c } /* create the nodes in the path */ - ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); + if (!*tree) { + ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); + } else { + /* this could output NULL if no new nodes, lyd_find_path would fail then */ + ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, NULL); + } if (ret) { goto cleanup; } From 326fa6fe726dae5ddc8d77f8b0fe4051f188a845 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 18 Aug 2023 15:57:02 +0200 Subject: [PATCH 063/134] tests UPDATE add test for runtime config changes --- tests/CMakeLists.txt | 3 +- tests/test_runtime_changes.c | 534 +++++++++++++++++++++++++++++++++++ 2 files changed, 536 insertions(+), 1 deletion(-) create mode 100644 tests/test_runtime_changes.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 70006545..be94cf34 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -38,7 +38,8 @@ endforeach() #append tests depending on SSH/TLS if(ENABLE_SSH_TLS) list(APPEND tests test_two_channels test_ks_ts test_config_new test_ec - test_ed25519 test_replace test_endpt_share_clients test_tls test_crl test_ch) + test_ed25519 test_replace test_endpt_share_clients test_tls test_crl test_ch + test_runtime_changes) endif() foreach(src IN LISTS libsrc) diff --git a/tests/test_runtime_changes.c b/tests/test_runtime_changes.c new file mode 100644 index 00000000..be28f4a9 --- /dev/null +++ b/tests/test_runtime_changes.c @@ -0,0 +1,534 @@ +/** + * @file test_runtime_changes.c + * @author Roman Janota + * @brief libnetconf2 Runtime changes test. + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 + +struct test_state { + pthread_barrier_t start_barrier; + pthread_barrier_t end_barrier; + struct lyd_node *tree; +}; + +typedef enum { + NC_TEST_EXPECT_FAIL, + NC_TEST_EXPECT_OK +} NC_TEST_EXPECT; + +typedef enum { + NC_TEST_STATE_END, + NC_TEST_STATE_RUN +} NC_TEST_STATE; + +struct ly_ctx *ctx; +int test_running; +int expect_ok; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* just to wait for when new data is configured */ + pthread_barrier_wait(&state->end_barrier); + + while (1) { + /* config ready, wait for client/server to be ready */ + pthread_barrier_wait(&state->start_barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + + if (expect_ok) { + assert_int_equal(msgtype, NC_MSG_HELLO); + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + nc_ps_clear(ps, 1, NULL); + } else { + assert_int_equal(msgtype, NC_MSG_ERROR); + } + + if (!test_running) { + break; + } + + /* wait for next config */ + pthread_barrier_wait(&state->end_barrier); + } + + nc_ps_free(ps); + return NULL; +} + +static void * +client_thread_tls(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set client cert */ + ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key"); + assert_int_equal(ret, 0); + + /* set client ca */ + ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data"); + assert_int_equal(ret, 0); + + /* just to wait for when new data is configured */ + pthread_barrier_wait(&state->end_barrier); + + while (1) { + /* config ready, wait for client/server to be ready */ + pthread_barrier_wait(&state->start_barrier); + session = nc_connect_tls("127.0.0.1", 10005, NULL); + if (expect_ok) { + assert_non_null(session); + nc_session_free(session, NULL); + } else { + assert_null(session); + } + + if (!test_running) { + break; + } + + /* wait for next config */ + pthread_barrier_wait(&state->end_barrier); + } + + return NULL; +} + +static void * +client_thread_ssh(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + + /* set ssh username */ + ret = nc_client_ssh_set_username("client"); + assert_int_equal(ret, 0); + + /* add client's key pair */ + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/id_ed25519.pub", TESTS_DIR "/data/id_ed25519"); + assert_int_equal(ret, 0); + + /* just to wait for when new data is configured */ + pthread_barrier_wait(&state->end_barrier); + + while (1) { + /* config ready, wait for client/server to be ready */ + pthread_barrier_wait(&state->start_barrier); + session = nc_connect_ssh("127.0.0.1", 10006, NULL); + if (expect_ok) { + assert_non_null(session); + nc_session_free(session, NULL); + } else { + assert_null(session); + } + + if (!test_running) { + break; + } + + /* wait for next config */ + pthread_barrier_wait(&state->end_barrier); + } + + return NULL; +} + +static inline void +configure(struct test_state *state, NC_TEST_EXPECT ok_or_fail, NC_TEST_STATE run_or_end) +{ + int ret = 0; + + /* lidl synchronization */ + pthread_barrier_wait(&state->end_barrier); + + /* apply new config */ + ret = nc_server_config_setup_data(state->tree); + assert_int_equal(ret, 0); + + /* set test params */ + expect_ok = ok_or_fail; + test_running = run_or_end; + + /* it just works */ + pthread_barrier_wait(&state->start_barrier); +} + +static void +init_test_create_threads_tls(pthread_t tids[2], void **state) +{ + int ret; + + /* so threads dont quit immediately */ + test_running = NC_TEST_STATE_RUN; + ret = pthread_create(&tids[0], NULL, client_thread_tls, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); +} + +static void +init_test_create_threads_ssh(pthread_t tids[2], void **state) +{ + int ret; + + /* so threads dont quit immediately */ + test_running = NC_TEST_STATE_RUN; + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); +} + +static void +test_nc_change_tls_srv_crt(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + init_test_create_threads_tls(tids, state); + + ret = nc_server_config_new_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/client.key", NULL, TESTS_DIR "/data/client.crt", &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); + + ret = nc_server_config_new_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_nc_change_tls_client_crt(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + init_test_create_threads_tls(tids, state); + + ret = nc_server_config_new_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/server.crt", &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); + + ret = nc_server_config_new_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_nc_change_tls_ctn(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + init_test_create_threads_tls(tids, state); + + ret = nc_server_config_new_tls_ctn(ctx, "endpt_tls", 1, + "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF", + NC_TLS_CTN_SPECIFIED, "invalid-fingerprint", &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); + + ret = nc_server_config_new_tls_ctn(ctx, "endpt_tls", 1, + "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", + NC_TLS_CTN_SPECIFIED, "client", &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_nc_change_tls_version(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + init_test_create_threads_tls(tids, state); + + ret = nc_server_config_new_tls_version(ctx, "endpt_tls", NC_TLS_VERSION_11, &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); + + ret = nc_server_config_new_tls_version(ctx, "endpt_tls", NC_TLS_VERSION_13, &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_nc_change_tls_ciphers(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + init_test_create_threads_tls(tids, state); + + ret = nc_server_config_new_tls_ciphers(ctx, "endpt_tls", &test_state->tree, 1, "tls-rsa-with-null-sha"); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); + + ret = nc_server_config_new_tls_ciphers(ctx, "endpt_tls", &test_state->tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_nc_change_ssh_hostkey(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + init_test_create_threads_ssh(tids, state); + + ret = nc_server_config_new_ssh_hostkey(ctx, "endpt_ssh", "hostkey", TESTS_DIR "/data/server.key", NULL, &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_RUN); + + ret = nc_server_config_new_keystore_asym_key(ctx, NC_TI_LIBSSH, "keystore_hostkey", TESTS_DIR "/data/key_rsa", TESTS_DIR "/data/key_rsa.pub", &test_state->tree); + assert_int_equal(ret, 0); + ret = nc_server_config_new_ssh_keystore_ref(ctx, "endpt_ssh", "hostkey", "keystore_hostkey", &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_nc_change_ssh_usr_pubkey(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + init_test_create_threads_ssh(tids, state); + + ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt_ssh", "client", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); + + ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt_ssh", "client", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_nc_change_ssh_hostkey_algs(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + init_test_create_threads_ssh(tids, state); + + ret = nc_server_config_new_ssh_host_key_algs(ctx, "endpt_ssh", &test_state->tree, 1, "ssh-dss"); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); + + ret = nc_server_config_new_ssh_host_key_algs(ctx, "endpt_ssh", &test_state->tree, 1, "rsa-sha2-256"); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + /* init barriers */ + ret = pthread_barrier_init(&test_state->start_barrier, NULL, 3); + assert_int_equal(ret, 0); + ret = pthread_barrier_init(&test_state->end_barrier, NULL, 3); + assert_int_equal(ret, 0); + + test_state->tree = NULL; + *state = test_state; + + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* create new address and port data */ + ret = nc_server_config_new_address_port(ctx, "endpt_tls", NC_TI_OPENSSL, "127.0.0.1", 10005, &test_state->tree); + assert_int_equal(ret, 0); + + /* create new server certificate data */ + ret = nc_server_config_new_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); + assert_int_equal(ret, 0); + + /* create new end entity client cert data */ + ret = nc_server_config_new_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); + assert_int_equal(ret, 0); + + /* create new cert-to-name */ + ret = nc_server_config_new_tls_ctn(ctx, "endpt_tls", 1, + "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", + NC_TLS_CTN_SPECIFIED, "client", &test_state->tree); + assert_int_equal(ret, 0); + + /* create new address and port data */ + ret = nc_server_config_new_address_port(ctx, "endpt_ssh", NC_TI_LIBSSH, "127.0.0.1", 10006, &test_state->tree); + assert_int_equal(ret, 0); + + /* create new hostkey data */ + ret = nc_server_config_new_ssh_hostkey(ctx, "endpt_ssh", "hostkey", TESTS_DIR "/data/server.key", NULL, &test_state->tree); + assert_int_equal(ret, 0); + + /* create new ssh user pubkey data */ + ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt_ssh", "client", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->tree); + assert_int_equal(ret, 0); + + ret = nc_server_init(); + assert_int_equal(ret, 0); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->start_barrier); + assert_int_equal(ret, 0); + ret = pthread_barrier_destroy(&test_state->end_barrier); + assert_int_equal(ret, 0); + + lyd_free_all(test_state->tree); + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_change_tls_srv_crt, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_change_tls_client_crt, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_change_tls_ctn, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_change_tls_version, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_change_tls_ciphers, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_change_ssh_hostkey, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_change_ssh_usr_pubkey, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_change_ssh_hostkey_algs, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} From d8b75b9e0f8128c1458d0883d0e588e4132d947b Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 4 Sep 2023 10:18:05 +0200 Subject: [PATCH 064/134] cmake BUGFIX expand macro correctly --- nc_client.h.in | 2 +- nc_server.h.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nc_client.h.in b/nc_client.h.in index 32a24abc..471b5995 100644 --- a/nc_client.h.in +++ b/nc_client.h.in @@ -20,7 +20,7 @@ extern "C" { #endif -#cmakedefine SSH_TLS_MACRO +@SSH_TLS_MACRO@ #include #include diff --git a/nc_server.h.in b/nc_server.h.in index 52176620..2ef2e88b 100644 --- a/nc_server.h.in +++ b/nc_server.h.in @@ -20,7 +20,7 @@ extern "C" { #endif -#cmakedefine SSH_TLS_MACRO +@SSH_TLS_MACRO@ #include #include From 7ca491e3b2f5d638f50a7ae6996cf00003f5f169 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 14 Sep 2023 10:01:09 +0200 Subject: [PATCH 065/134] cmake UPDATE cmake version to 3.5 & fix var name --- CMakeLists.txt | 2 +- libnetconf2.pc.in | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0437dff1..6bbc53f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.5) project(libnetconf2 C) diff --git a/libnetconf2.pc.in b/libnetconf2.pc.in index 66da4697..10926a59 100644 --- a/libnetconf2.pc.in +++ b/libnetconf2.pc.in @@ -8,5 +8,5 @@ Version: @LIBNETCONF2_VERSION@ Libs: -L${libdir} -lnetconf2 Cflags: -I${includedir} -LNC2_MAX_THREAD_COUNT=@MAX_PSPOLL_THREAD_COUNT@ -LNC2_SCHEMAS_DIR=@SCHEMAS_DIR@ +LN2_MAX_THREAD_COUNT=@MAX_PSPOLL_THREAD_COUNT@ +LN2_SCHEMAS_DIR=@YANG_MODULE_DIR@ From 443f7ee5a1c9422203df5700a36587ace0cf6e62 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 14 Sep 2023 10:02:24 +0200 Subject: [PATCH 066/134] ietf-crypto-types UPDATE remove mandatory from pub --- modules/ietf-crypto-types@2023-04-17.yang | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/ietf-crypto-types@2023-04-17.yang b/modules/ietf-crypto-types@2023-04-17.yang index ddabbeec..517e0162 100644 --- a/modules/ietf-crypto-types@2023-04-17.yang +++ b/modules/ietf-crypto-types@2023-04-17.yang @@ -827,7 +827,6 @@ module ietf-crypto-types { type identityref { base public-key-format; } - mandatory true; description "Identifies the public key's format. Implementations SHOULD ensure that the incoming public key value is encoded in the @@ -836,7 +835,6 @@ module ietf-crypto-types { leaf public-key { nacm:default-deny-write; type binary; - mandatory true; description "The binary value of the public key. The interpretation of the value is defined by 'public-key-format' field."; From 67612a4539df5a943230f6bbc23e096c226369be Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 14 Sep 2023 10:03:40 +0200 Subject: [PATCH 067/134] modules UPDATE add revision to file names --- ...o-name.yang => ietf-x509-cert-to-name@2014-12-10.yang} | 0 ...er.yang => libnetconf2-netconf-server@2023-09-07.yang} | 8 +++++++- 2 files changed, 7 insertions(+), 1 deletion(-) rename modules/{ietf-x509-cert-to-name.yang => ietf-x509-cert-to-name@2014-12-10.yang} (100%) rename modules/{libnetconf2-netconf-server.yang => libnetconf2-netconf-server@2023-09-07.yang} (98%) diff --git a/modules/ietf-x509-cert-to-name.yang b/modules/ietf-x509-cert-to-name@2014-12-10.yang similarity index 100% rename from modules/ietf-x509-cert-to-name.yang rename to modules/ietf-x509-cert-to-name@2014-12-10.yang diff --git a/modules/libnetconf2-netconf-server.yang b/modules/libnetconf2-netconf-server@2023-09-07.yang similarity index 98% rename from modules/libnetconf2-netconf-server.yang rename to modules/libnetconf2-netconf-server@2023-09-07.yang index 8c62b9bd..2f9d26fa 100644 --- a/modules/libnetconf2-netconf-server.yang +++ b/modules/libnetconf2-netconf-server@2023-09-07.yang @@ -31,6 +31,10 @@ module libnetconf2-netconf-server { prefix tlss; } + revision "2023-09-07" { + description "Initial revision."; + } + /* identity ed25519-private-key-format { base ct:private-key-format; @@ -315,7 +319,9 @@ module libnetconf2-netconf-server { mandatory true; } leaf mode { - type uint16; + type string { + pattern '[0124567]{3}'; + } } leaf uid { type uint16; From 8fa31001f03c0b889d9a30ef3f2ed271bc0e6829 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 14 Sep 2023 10:04:36 +0200 Subject: [PATCH 068/134] nc_server BUGFIX add missing header include --- nc_server.h.in | 1 + 1 file changed, 1 insertion(+) diff --git a/nc_server.h.in b/nc_server.h.in index 2ef2e88b..a4ad8ca6 100644 --- a/nc_server.h.in +++ b/nc_server.h.in @@ -25,6 +25,7 @@ extern "C" { #include #include #include +#include #include #include From 7810bc5067935223fd0c2f7000cb5c89930c131f Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 14 Sep 2023 10:06:03 +0200 Subject: [PATCH 069/134] config UPDATE new unix socket API --- src/config_new.c | 63 ++++++++++++++++++++++++++++++++++++++++ src/server_config.c | 1 + src/server_config.h | 17 +++++++++++ tests/test_unix_socket.c | 26 +++++------------ 4 files changed, 89 insertions(+), 18 deletions(-) diff --git a/src/config_new.c b/src/config_new.c index dacb9d3c..01f63d6d 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -1363,6 +1363,69 @@ nc_server_config_new_del_truststore_cert(const char *cert_bag_name, #endif /* NC_ENABLED_SSH_TLS */ +API int +nc_server_config_new_unix_socket(const struct ly_ctx *ctx, const char *endpt_name, const char *path, + mode_t mode, uid_t uid, gid_t gid, struct lyd_node **config) +{ + int ret = 0; + char *tree_path = NULL; + char buf[12] = {0}; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, path, config, 1); + + if (asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/libnetconf2-netconf-server:unix-socket", endpt_name) == -1) { + ERRMEM; + tree_path = NULL; + ret = 1; + goto cleanup; + } + + /* path to unix socket */ + ret = nc_config_new_create_append(ctx, tree_path, "path", path, config); + if (ret) { + goto cleanup; + } + + /* mode */ + if (mode != (mode_t)-1) { + if (mode > 0777) { + ERR(NULL, "Invalid mode value (%o).", mode); + ret = 1; + goto cleanup; + } + + sprintf(buf, "%o", mode); + ret = nc_config_new_create_append(ctx, tree_path, "mode", buf, config); + if (ret) { + goto cleanup; + } + } + + /* uid */ + if (uid != (uid_t)-1) { + memset(buf, 0, 12); + sprintf(buf, "%u", uid); + ret = nc_config_new_create_append(ctx, tree_path, "uid", buf, config); + if (ret) { + goto cleanup; + } + } + + /* gid */ + if (gid != (gid_t)-1) { + memset(buf, 0, 12); + sprintf(buf, "%u", gid); + ret = nc_config_new_create_append(ctx, tree_path, "gid", buf, config); + if (ret) { + goto cleanup; + } + } + +cleanup: + free(tree_path); + return ret; +} + API int nc_server_config_new_ch_persistent(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config) { diff --git a/src/server_config.c b/src/server_config.c index b6f693e0..439071de 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -870,6 +870,7 @@ nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opt close(bind->sock); } + unlink(bind->address); free(bind->address); free(opts->address); diff --git a/src/server_config.h b/src/server_config.h index bf127570..1bfa8852 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -122,6 +122,23 @@ int nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endp #endif /* NC_ENABLED_SSH_TLS */ +/** + * @brief Creates new YANG data nodes for a UNIX socket. + * + * @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 socket. + * @param[in] mode New mode, use -1 for default. + * @param[in] uid New uid, use -1 for default + * @param[in] gid New gid, use -1 for default + * @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_new_unix_socket(const struct ly_ctx *ctx, const char *endpt_name, const char *path, + mode_t mode, uid_t uid, gid_t gid, struct lyd_node **config); + /** * @brief Deletes an endpoint from the YANG data. * diff --git a/tests/test_unix_socket.c b/tests/test_unix_socket.c index 77938dac..5743fd44 100644 --- a/tests/test_unix_socket.c +++ b/tests/test_unix_socket.c @@ -36,19 +36,6 @@ struct test_state { pthread_barrier_t barrier; }; -const char *data = - "\n" - " \n" - " 10\n" - " \n" - " default-unix-socket\n" - " \n" - " /tmp/nc2_test_unix_sock\n" - " \n" - " \n" - " \n" - "\n"; - static void * server_thread(void *arg) { @@ -119,7 +106,7 @@ static int setup_f(void **state) { int ret; - struct lyd_node *tree; + struct lyd_node *tree = NULL; struct test_state *test_state; nc_verbosity(NC_VERB_VERBOSE); @@ -144,20 +131,23 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - /* parse yang data */ - ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); + /* create the UNIX socket */ + ret = nc_server_config_new_unix_socket(ctx, "unix", "/tmp/nc2_test_unix_sock", 0700, -1, -1, &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ - ret = nc_server_config_setup_diff(tree); + ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); /* initialize server */ ret = nc_server_init(); assert_int_equal(ret, 0); - lyd_free_all(tree); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; } From 851f77969176b114ec9e86f04daed08309be782e Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 14 Sep 2023 10:07:26 +0200 Subject: [PATCH 070/134] session BUGFIX add bind lock for accepting The lack of this locked caused dataraces when the server was run in multiple threads. --- src/session_client.c | 16 +++++++++++++++- src/session_client.h | 7 +++++++ src/session_p.h | 5 ++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/session_client.c b/src/session_client.c index 2588e68d..047d6ed4 100644 --- a/src/session_client.c +++ b/src/session_client.c @@ -1854,7 +1854,7 @@ nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **session) return -1; } - sock = nc_sock_accept_binds(client_opts.ch_binds, client_opts.ch_bind_count, timeout, &host, &port, &idx); + sock = nc_sock_accept_binds(client_opts.ch_binds, client_opts.ch_bind_count, &client_opts.ch_bind_lock, timeout, &host, &port, &idx); if (sock < 1) { free(host); return sock; @@ -1919,9 +1919,23 @@ nc_session_ntf_thread_running(const struct nc_session *session) return ATOMIC_LOAD_RELAXED(session->opts.client.ntf_thread_running); } +API int +nc_client_init(void) +{ + int r; + + if ((r = pthread_mutex_init(&client_opts.ch_bind_lock, NULL))) { + ERR(NULL, "%s: failed to init bind lock(%s).", __func__, strerror(r)); + return -1; + } + + return 0; +} + API void nc_client_destroy(void) { + pthread_mutex_destroy(&client_opts.ch_bind_lock); nc_client_set_schema_searchpath(NULL); #ifdef NC_ENABLED_SSH_TLS nc_client_ch_del_bind(NULL, 0, 0); diff --git a/src/session_client.h b/src/session_client.h index 834908cc..3ac3c509 100644 --- a/src/session_client.h +++ b/src/session_client.h @@ -112,6 +112,13 @@ void nc_client_set_thread_context(void *context); */ void *nc_client_get_thread_context(void); +/** + * @brief Initialize client for establishing connections. + * + * @return 0 on success, -1 on error. + */ +int nc_client_init(void); + /** * @brief Destroy all libssh and/or libssl/libcrypto dynamic memory and * the client options, for both SSH and TLS, and for Call Home too. diff --git a/src/session_p.h b/src/session_p.h index 1b127330..30d4bf66 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -372,6 +372,7 @@ struct nc_client_opts { struct nc_keepalives ka; struct nc_bind *ch_binds; + pthread_mutex_t ch_bind_lock; /**< To avoid concurrent calls of poll and accept on the bound sockets **/ struct { NC_TRANSPORT_IMPL ti; @@ -455,6 +456,7 @@ struct nc_server_opts { #endif /* NC_ENABLED_SSH_TLS */ struct nc_bind *binds; + pthread_mutex_t bind_lock; /**< To avoid concurrent calls of poll and accept on the bound sockets **/ struct nc_endpt { char *name; #ifdef NC_ENABLED_SSH_TLS @@ -911,13 +913,14 @@ int nc_sock_listen_unix(const struct nc_server_unix_opts *opts); * * @param[in] binds Structure with the listening sockets. * @param[in] bind_count Number of @p binds. + * @param[in] bind_lock Lock for avoiding concurrent poll/accept on a single bind. * @param[in] timeout Timeout for accepting. * @param[out] host Host of the remote peer. Can be NULL. * @param[out] port Port of the new connection. Can be NULL. * @param[out] idx Index of the bind that was accepted. Can be NULL. * @return Accepted socket of the new connection, -1 on error. */ -int nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, char **host, uint16_t *port, uint16_t *idx); +int nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, pthread_mutex_t *bind_lock, int timeout, char **host, uint16_t *port, uint16_t *idx); /** * @brief Lock endpoint structures for reading and the specific endpoint. From 7b7f4f35b1ca62dcc1b0417e24e71dd1a45f0bf2 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 14 Sep 2023 10:10:08 +0200 Subject: [PATCH 071/134] tests UPDATE add nc_client_init --- tests/test_auth.c | 4 ++++ tests/test_ch.c | 8 ++++++++ tests/test_config_new.c | 4 ++++ tests/test_crl.c | 4 ++++ tests/test_ec.c | 4 ++++ tests/test_ed25519.c | 4 ++++ tests/test_endpt_share_clients.c | 8 ++++++++ tests/test_ks_ts.c | 8 ++++++++ tests/test_replace.c | 4 ++++ tests/test_runtime_changes.c | 4 ++++ tests/test_tls.c | 4 ++++ tests/test_two_channels.c | 4 ++++ 12 files changed, 60 insertions(+) diff --git a/tests/test_auth.c b/tests/test_auth.c index e57405b8..87f6e894 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -340,6 +340,10 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; diff --git a/tests/test_ch.c b/tests/test_ch.c index 13ab75ee..1218d2c3 100644 --- a/tests/test_ch.c +++ b/tests/test_ch.c @@ -225,6 +225,10 @@ setup_ssh(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + return 0; } @@ -425,6 +429,10 @@ setup_tls(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + return 0; } diff --git a/tests/test_config_new.c b/tests/test_config_new.c index c484c860..72dda366 100644 --- a/tests/test_config_new.c +++ b/tests/test_config_new.c @@ -172,6 +172,10 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; diff --git a/tests/test_crl.c b/tests/test_crl.c index 7a9cf447..253f45c0 100644 --- a/tests/test_crl.c +++ b/tests/test_crl.c @@ -188,6 +188,10 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; diff --git a/tests/test_ec.c b/tests/test_ec.c index 669d93ce..43d513f1 100644 --- a/tests/test_ec.c +++ b/tests/test_ec.c @@ -236,6 +236,10 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; diff --git a/tests/test_ed25519.c b/tests/test_ed25519.c index da6df765..b381c6ab 100644 --- a/tests/test_ed25519.c +++ b/tests/test_ed25519.c @@ -167,6 +167,10 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c index b6ccb1b4..f9284fe0 100644 --- a/tests/test_endpt_share_clients.c +++ b/tests/test_endpt_share_clients.c @@ -220,6 +220,10 @@ setup_ssh(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; @@ -292,6 +296,10 @@ setup_tls(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; diff --git a/tests/test_ks_ts.c b/tests/test_ks_ts.c index cd8cd96a..159b6cff 100644 --- a/tests/test_ks_ts.c +++ b/tests/test_ks_ts.c @@ -160,6 +160,10 @@ setup_ssh(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; @@ -284,6 +288,10 @@ setup_tls(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; diff --git a/tests/test_replace.c b/tests/test_replace.c index ba09984d..7a61cee7 100644 --- a/tests/test_replace.c +++ b/tests/test_replace.c @@ -265,6 +265,10 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(old_tree); lyd_free_all(new_tree); diff --git a/tests/test_runtime_changes.c b/tests/test_runtime_changes.c index be28f4a9..a7cd45df 100644 --- a/tests/test_runtime_changes.c +++ b/tests/test_runtime_changes.c @@ -489,6 +489,10 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + return 0; } diff --git a/tests/test_tls.c b/tests/test_tls.c index ed0966b1..dc5b502b 100644 --- a/tests/test_tls.c +++ b/tests/test_tls.c @@ -174,6 +174,10 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c index d5510147..38597c00 100644 --- a/tests/test_two_channels.c +++ b/tests/test_two_channels.c @@ -172,6 +172,10 @@ setup_f(void **state) ret = nc_server_init(); assert_int_equal(ret, 0); + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + lyd_free_all(tree); return 0; From 84317ba71580ddc999b4640c980ef58bb1898ff0 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 14 Sep 2023 10:13:45 +0200 Subject: [PATCH 072/134] session server UPDATE move and rename PK fmt check --- src/server_config.c | 43 ++++--------------------------------------- src/session.c | 37 +++++++++++++++++++++++++++++++++++++ src/session_p.h | 9 +++++++++ 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 439071de..a5f7b74a 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -2117,41 +2117,6 @@ nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, stru return 0; } -static int -nc_server_config_is_pk_subject_public_key_info(const char *b64) -{ - int ret = 0; - long len; - char *bin = NULL, *tmp; - EVP_PKEY *pkey = NULL; - - /* base64 2 binary */ - len = nc_base64_to_bin(b64, &bin); - if (len == -1) { - ERR(NULL, "Decoding base64 public key to binary failed."); - ret = -1; - goto cleanup; - } - - /* for deallocation later */ - tmp = bin; - - /* try to create EVP_PKEY from the supposed SubjectPublicKeyInfo binary data */ - pkey = d2i_PUBKEY(NULL, (const unsigned char **)&tmp, len); - if (pkey) { - /* success, it's most likely SubjectPublicKeyInfo pubkey */ - ret = 1; - } else { - /* fail, it's most likely not SubjectPublicKeyInfo pubkey */ - ret = 0; - } - -cleanup: - EVP_PKEY_free(pkey); - free(bin); - return ret; -} - static int nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) { @@ -2177,7 +2142,7 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */ - if (nc_server_config_is_pk_subject_public_key_info(lyd_get_value(node))) { + if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) { ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!"); ret = 1; goto cleanup; @@ -2223,7 +2188,7 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */ - if (nc_server_config_is_pk_subject_public_key_info(lyd_get_value(node))) { + if (nc_is_pk_subject_public_key_info(lyd_get_value(node))) { ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!"); ret = 1; goto cleanup; @@ -2245,7 +2210,7 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) } /* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */ - if (!nc_server_config_is_pk_subject_public_key_info(lyd_get_value(node))) { + if (!nc_is_pk_subject_public_key_info(lyd_get_value(node))) { ERR(NULL, "TLS server certificate's Public Key must be in the SubjectPublicKeyInfo format!"); ret = 1; goto cleanup; @@ -2617,7 +2582,7 @@ nc_server_config_ssh_replace_truststore_reference(const struct lyd_node *node, s /* check if any of the referenced public keys is SubjectPublicKeyInfo */ for (i = 0; i < client_auth->ts_ref->pubkey_count; i++) { - if (nc_server_config_is_pk_subject_public_key_info(client_auth->ts_ref->pubkeys[i].data)) { + if (nc_is_pk_subject_public_key_info(client_auth->ts_ref->pubkeys[i].data)) { ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!"); return 1; } diff --git a/src/session.c b/src/session.c index ad96fc56..78cec176 100644 --- a/src/session.c +++ b/src/session.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #endif /* NC_ENABLED_SSH_TLS */ @@ -183,6 +185,41 @@ nc_base64_to_bin(const char *base64, char **bin) return size; } +int +nc_is_pk_subject_public_key_info(const char *b64) +{ + int ret = 0; + long len; + char *bin = NULL, *tmp; + EVP_PKEY *pkey = NULL; + + /* base64 2 binary */ + len = nc_base64_to_bin(b64, &bin); + if (len == -1) { + ERR(NULL, "Decoding base64 public key to binary failed."); + ret = -1; + goto cleanup; + } + + /* for deallocation later */ + tmp = bin; + + /* try to create EVP_PKEY from the supposed SubjectPublicKeyInfo binary data */ + pkey = d2i_PUBKEY(NULL, (const unsigned char **)&tmp, len); + if (pkey) { + /* success, it's most likely SubjectPublicKeyInfo pubkey */ + ret = 1; + } else { + /* fail, it's most likely not SubjectPublicKeyInfo pubkey */ + ret = 0; + } + +cleanup: + EVP_PKEY_free(pkey); + free(bin); + return ret; +} + #endif /* NC_ENABLED_SSH_TLS */ int diff --git a/src/session_p.h b/src/session_p.h index 30d4bf66..160d9be5 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -756,6 +756,15 @@ const char *nc_privkey_format_to_str(NC_PRIVKEY_FORMAT format); */ int nc_base64_to_bin(const char *base64, char **bin); +/** + * @brief Checks if the given base64 belongs to a public key in the SubjectPublicKeyInfo format. + * + * @param[in] b64 Base64 encoded data. + * + * @return -1 on error, 0 if it is not SPKI public key, 1 if it is a public key in the SPKI format. + */ +int nc_is_pk_subject_public_key_info(const char *b64); + #endif /* NC_ENABLED_SSH_TLS */ void *nc_realloc(void *ptr, size_t size); From 700ef1d292352dc8d32ba29b0d510262f2b61ef1 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 14 Sep 2023 10:17:07 +0200 Subject: [PATCH 073/134] session server UPDATE access keystore dynamically Rather then storing the actual key from keystore when the keystore-reference node is being processed, store just the name of the referenced key and get the key based on this name when it's needed. --- src/server_config.c | 45 ++++++++++++++------------------------------- src/session_p.h | 8 ++++---- 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index a5f7b74a..5fa40108 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -749,6 +749,13 @@ nc_server_config_del_mac_algs(struct nc_server_ssh_opts *opts) opts->mac_algs = NULL; } +static void +nc_server_config_del_keystore_reference(struct nc_hostkey *hostkey) +{ + free(hostkey->ks_ref); + hostkey->ks_ref = NULL; +} + static void nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey) { @@ -757,6 +764,8 @@ nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey if (hostkey->store == NC_STORE_LOCAL) { nc_server_config_del_public_key(hostkey); nc_server_config_del_private_key(hostkey); + } else { + nc_server_config_del_keystore_reference(hostkey); } nc_server_config_del_hostkey_name(hostkey); @@ -2375,35 +2384,6 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION return ret; } -static int -nc_server_config_create_keystore_reference(const struct lyd_node *node, struct nc_hostkey *hostkey) -{ - uint16_t i; - struct nc_keystore *ks = &server_opts.keystore; - - /* lookup name */ - for (i = 0; i < ks->asym_key_count; i++) { - if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) { - break; - } - } - - if (i == ks->asym_key_count) { - ERR(NULL, "Keystore entry \"%s\" not found.", lyd_get_value(node)); - return 1; - } - - hostkey->ks_ref = &ks->asym_keys[i]; - - /* check if the referenced public key is SubjectPublicKeyInfo */ - if (nc_server_config_is_pk_subject_public_key_info(hostkey->ks_ref->pubkey_data)) { - ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!"); - return 1; - } - - return 0; -} - /* leaf */ static int nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op) @@ -2429,8 +2409,11 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op /* set to keystore */ hostkey->store = NC_STORE_KEYSTORE; - ret = nc_server_config_create_keystore_reference(node, hostkey); - if (ret) { + nc_server_config_del_keystore_reference(hostkey); + hostkey->ks_ref = strdup(lyd_get_value(node)); + if (!hostkey->ks_ref) { + ERRMEM; + ret = 1; goto cleanup; } } else { diff --git a/src/session_p.h b/src/session_p.h index 160d9be5..becd266b 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -182,12 +182,12 @@ struct nc_client_auth { * @brief The server's hostkey. */ struct nc_hostkey { - char *name; /**< Arbitrary name of the host key. */ + char *name; /**< Arbitrary name of the host key. */ - NC_STORE_TYPE store; /**< Specifies how/where the key is stored. */ + NC_STORE_TYPE store; /**< Specifies how/where the key is stored. */ union { - struct nc_asymmetric_key key; /**< The server's hostkey. */ - struct nc_asymmetric_key *ks_ref; /**< Reference to a key-store. */ + struct nc_asymmetric_key key; /**< The server's hostkey. */ + char *ks_ref; /**< Name of the referenced key. */ }; }; From 5005c510d4d2691377ad08f20aeecee03e1d64b8 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 14 Sep 2023 10:19:19 +0200 Subject: [PATCH 074/134] config UPDATE remove unsupported features --- src/server_config.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 5fa40108..38631a71 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -4808,21 +4808,20 @@ nc_server_config_load_modules(struct ly_ctx **ctx) /* all features */ const char *ietf_x509_cert_to_name[] = {NULL}; /* no private-key-encryption, csr-generation, p10-csr-format, certificate-expiration-notification, - * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys + * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys, + * one-symmetric-key-format, one-asymmetric-key-format, symmetrically-encrypted-value-format, + * asymmetrically-encrypted-value-format, cms-enveloped-data-format, cms-encrypted-data-format, + * cleartext-symmetric-keys */ - const char *ietf_crypto_types[] = { - "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format", - "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format", - "cleartext-passwords", "cleartext-symmetric-keys", "cleartext-private-keys", NULL - }; + const char *ietf_crypto_types[] = {"cleartext-passwords", "cleartext-private-keys", NULL}; /* all features */ const char *ietf_tcp_common[] = {"keepalives-supported", NULL}; /* all features */ const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL}; - /* all features */ - const char *ietf_tcp_client[] = {"local-binding-supported", "tcp-client-keepalives", "proxy-connect", "socks5-gss-api", "socks5-username-password", NULL}; - /* no ssh-x509-certs */ - const char *ietf_ssh_common[] = {"transport-params", "public-key-generation", NULL}; + /* no proxy-connect, socks5-gss-api, socks5-username-password */ + const char *ietf_tcp_client[] = {"local-binding-supported", "tcp-client-keepalives", NULL}; + /* no ssh-x509-certs, public-key-generation */ + const char *ietf_ssh_common[] = {"transport-params", NULL}; /* no ssh-server-keepalives and local-user-auth-hostbased */ const char *ietf_ssh_server[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL}; /* all features */ @@ -4839,14 +4838,12 @@ nc_server_config_load_modules(struct ly_ctx **ctx) const char *ietf_keystore[] = {"central-keystore-supported", "inline-definitions-supported", "asymmetric-keys", NULL}; /* all features */ const char *ietf_truststore[] = {"central-truststore-supported", "inline-definitions-supported", "certificates", "public-keys", NULL}; + /* no public-key-generation */ + const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", NULL}; + /* no tls-server-keepalives, server-ident-raw-public-key, server-ident-tls12-psk, server-ident-tls13-epsk, + * client-auth-raw-public-key, client-auth-tls12-psk, client-auth-tls13-epsk */ + const char *ietf_tls_server[] = {"server-ident-x509-cert", "client-auth-supported", "client-auth-x509-cert", NULL}; /* all features */ - const char *ietf_tls_common[] = {"tls10", "tls11", "tls12", "tls13", "hello-params", "public-key-generation", NULL}; - /* all features */ - const char *ietf_tls_server[] = { - "tls-server-keepalives", "server-ident-x509-cert", "server-ident-raw-public-key", "server-ident-tls12-psk", - "server-ident-tls13-epsk", "client-auth-supported", "client-auth-x509-cert", "client-auth-raw-public-key", - "client-auth-tls12-psk", "client-auth-tls13-epsk", NULL - }; const char *iana_tls_cipher_suite_algs[] = {NULL}; /* all features */ const char *libnetconf2_netconf_server[] = {NULL}; From ef0df4128dcfcc9bd15ba205d24ba08b72ec8448 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 14 Sep 2023 10:19:50 +0200 Subject: [PATCH 075/134] config UPDATE make netconf-server subtree optional --- src/server_config.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 38631a71..f6165846 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -4885,11 +4885,16 @@ static int nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op) { int ret = 0; + uint32_t prev_lo; struct lyd_node *tree; + /* silently search for ietf-netconf-server, it may not be present */ + prev_lo = ly_log_options(0); + ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree); - if (ret) { - ERR(NULL, "Unable to find the netconf-server container in the YANG data."); + if (ret || (tree->flags & LYD_DEFAULT)) { + /* not found */ + ret = 0; goto cleanup; } @@ -4907,6 +4912,8 @@ nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION o #endif /* NC_ENABLED_SSH_TLS */ cleanup: + /* reset the logging options back to what they were */ + ly_log_options(prev_lo); return ret; } @@ -4915,6 +4922,8 @@ nc_server_config_setup_diff(const struct lyd_node *data) { int ret = 0; + NC_CHECK_ARG_RET(NULL, data, 1); + /* LOCK */ pthread_rwlock_wrlock(&server_opts.config_lock); @@ -4953,6 +4962,8 @@ nc_server_config_setup_data(const struct lyd_node *data) int ret = 0; struct lyd_node *tree, *iter, *root; + NC_CHECK_ARG_RET(NULL, data, 1); + /* LOCK */ pthread_rwlock_wrlock(&server_opts.config_lock); From 2bb6c66b2ac7db0802763c27f5fce85d52a203a9 Mon Sep 17 00:00:00 2001 From: Roytak Date: Fri, 29 Sep 2023 15:25:14 +0200 Subject: [PATCH 076/134] headers UPDATE remove obsolete functions --- src/server_config.h | 54 +++---- src/session_server_ch.h | 318 ---------------------------------------- 2 files changed, 27 insertions(+), 345 deletions(-) diff --git a/src/server_config.h b/src/server_config.h index 1bfa8852..fb21cba4 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -832,6 +832,33 @@ int nc_server_config_new_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, */ int nc_server_config_new_tls_del_client_ca_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_config_new_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_config_new_tls_del_endpoint_client_ref(const char *endpt_name, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a cert-to-name entry. * @@ -977,33 +1004,6 @@ int nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char * */ int nc_server_config_new_tls_del_crl(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_config_new_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_config_new_tls_del_endpoint_client_ref(const char *endpt_name, struct lyd_node **config); - /** * @} TLS Server Configuration */ diff --git a/src/session_server_ch.h b/src/session_server_ch.h index 7626d966..a465c094 100644 --- a/src/session_server_ch.h +++ b/src/session_server_ch.h @@ -47,22 +47,6 @@ extern "C" { * @{ */ -/** - * @brief Add a new Call Home client. - * - * @param[in] name Arbitrary unique client name. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_add_client(const char *name); - -/** - * @brief Drop any connections, stop connecting and remove a client. - * - * @param[in] name Client name. NULL matches all the clients. - * @return 0 on success, -1 on not finding any match. - */ -int nc_server_ch_del_client(const char *name); - /** * @brief Check if a Call Home client exists. * @@ -71,28 +55,6 @@ int nc_server_ch_del_client(const char *name); */ int nc_server_ch_is_client(const char *name); -/** - * @brief Add a new Call Home client endpoint. - * - * @param[in] client_name Existing client name. - * @param[in] endpt_name Arbitrary unique (within the client) endpoint name. - * @param[in] ti Transport protocol to use. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_add_endpt(const char *client_name, const char *endpt_name, NC_TRANSPORT_IMPL ti); - -/** - * @brief Remove a Call Home client endpoint. - * - * @param[in] client_name Existing client name. - * @param[in] endpt_name Existing endpoint of @p client_name. NULL matches all endpoints. - * @param[in] ti Client transport protocol. NULL matches any protocol. - * Redundant to set if @p endpt_name is set, client names are - * unique disregarding their protocol. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_del_endpt(const char *client_name, const char *endpt_name, NC_TRANSPORT_IMPL ti); - /** * @brief Check if an endpoint of a Call Home client exists. * @@ -102,71 +64,6 @@ int nc_server_ch_client_del_endpt(const char *client_name, const char *endpt_nam */ int nc_server_ch_client_is_endpt(const char *client_name, const char *endpt_name); -/** - * @brief Change Call Home client endpoint listening address. - * - * On error the previous listening socket (if any) is left untouched. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of @p client_name. - * @param[in] address New listening address. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_endpt_set_address(const char *client_name, const char *endpt_name, const char *address); - -/** - * @brief Change Call Home client endpoint listening port. - * - * On error the previous listening socket (if any) is left untouched. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of @p client_name. - * @param[in] port New listening port. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_endpt_set_port(const char *client_name, const char *endpt_name, uint16_t port); - -/** - * @brief Change Call Home client endpoint keepalives state. Affects only new connections. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of @p client_name. - * @param[in] enable Whether to enable or disable keepalives. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_endpt_enable_keepalives(const char *client_name, const char *endpt_name, int enable); - -/** - * @brief Change Call Home client endpoint keepalives parameters. Affects only new connections. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of @p client_name. - * @param[in] idle_time Keepalive idle time in seconds, 1 by default, -1 to keep previous value. - * @param[in] max_probes Keepalive max probes sent, 10 by default, -1 to keep previous value. - * @param[in] probe_interval Keepalive probe interval in seconds, 5 by default, -1 to keep previous value. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_endpt_set_keepalives(const char *client_name, const char *endpt_name, int idle_time, - int max_probes, int probe_interval); - -/** - * @brief Set Call Home client start-with policy. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] start_with Call Home client start-with. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_set_start_with(const char *client_name, NC_CH_START_WITH start_with); - -/** - * @brief Set Call Home client overall max attempts. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] max_attempts Call Home overall max reconnect attempts. - * @return 0 on success, -1 on error. - */ -int nc_server_ch_client_set_max_attempts(const char *client_name, uint8_t max_attempts); - /** * @brief Callback for getting a locked context for new Call Home sessions. * @@ -210,221 +107,6 @@ int nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_ /** @} Server-side Call Home Functions */ -/** - * @defgroup server_ch_ssh Server-side Call Home on SSH - * @ingroup server_ch - * - * @brief SSH settings for the Call Home functionality - * @{ - */ - -/** - * @brief Add Call Home SSH host keys the server will identify itself with. Only the name is set, the key itself - * wil be retrieved using a callback. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] name Arbitrary name of the host key. - * @param[in] idx Optional index where to add the key. -1 adds at the end. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_ch_client_endpt_add_hostkey(const char *client_name, const char *endpt_name, const char *name, int16_t idx); - -/** - * @brief Delete Call Home SSH host keys. Their order is preserved. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] name Name of the host key. NULL matches all the keys, but if @p idx != -1 then this must be NULL. - * @param[in] idx Index of the hostkey. -1 matches all indices, but if @p name != NULL then this must be -1. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_ch_client_endpt_del_hostkey(const char *client_name, const char *endpt_name, const char *name, int16_t idx); - -/** - * @brief Move Call Home SSH host key. - * - * @param[in] client_name Exisitng Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] key_mov Name of the host key that will be moved. - * @param[in] key_after Name of the key that will preceed @p key_mov. NULL if @p key_mov is to be moved at the beginning. - * @return 0 in success, -1 on error. - */ -int nc_server_ssh_ch_client_endpt_mov_hostkey(const char *client_name, const char *endpt_name, const char *key_mov, - const char *key_after); - -/** - * @brief Set accepted Call Home SSH authentication methods. All (publickey, password, interactive) - * are supported by default. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] auth_methods Accepted authentication methods bit field of NC_SSH_AUTH_TYPE. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_ch_client_endpt_set_auth_methods(const char *client_name, const char *endpt_name, int auth_methods); - -/** - * @brief Get accepted Call Home SSH authentication methods. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @return Accepted authentication methods bit field of NC_SSH_AUTH_TYPE. - */ -int nc_server_ssh_ch_client_endpt_get_auth_methods(const char *client_name, const char *endpt_name); - -/** - * @brief Set Call Home SSH authentication attempts of every client. 3 by default. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] auth_attempts Failed authentication attempts before a client is dropped. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_ch_client_endpt_set_auth_attempts(const char *client_name, const char *endpt_name, uint16_t auth_attempts); - -/** - * @brief Set Call Home SSH authentication timeout. 30 seconds by default. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] auth_timeout Number of seconds before an unauthenticated client is dropped. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_ch_client_endpt_set_auth_timeout(const char *client_name, const char *endpt_name, uint16_t auth_timeout); - -/** @} Server-side Call Home on SSH */ - -/** - * @defgroup server_ch_tls Server-side Call Home on TLS - * @ingroup server_ch - * - * @brief TLS settings for the Call Home functionality - * @{ - */ - -/** - * @brief Set the server Call Home TLS certificate. Only the name is set, the certificate itself - * wil be retrieved using a callback. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] name Arbitrary certificate name. - * @return 0 on success, -1 on error. - */ -int nc_server_tls_ch_client_endpt_set_server_cert(const char *client_name, const char *endpt_name, const char *name); - -/** - * @brief Add a Call Home trusted certificate list. Can be both a CA or a client one. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] name Arbitary name identifying this certificate list. - * @return 0 on success, -1 on error. - */ -int nc_server_tls_ch_client_endpt_add_trusted_cert_list(const char *client_name, const char *endpt_name, const char *name); - -/** - * @brief Remove a set Call Home trusted certificate list. CRLs and CTN entries are not affected. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] name Name of the certificate list to delete. NULL deletes all the lists. - * @return 0 on success, -1 on not found. - */ -int nc_server_tls_ch_client_endpt_del_trusted_cert_list(const char *client_name, const char *endpt_name, const char *name); - -/** - * @brief Set trusted Call Home Certificate Authority certificate locations. There - * can only be one file and one directory, they are replaced if already set. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] ca_file Path to a trusted CA cert store file in PEM format. - * Can be NULL. - * @param[in] ca_dir Path to a trusted CA cert store hashed directory - * (c_rehash utility can be used to create hashes) - * with PEM files. Can be NULL. - * @return 0 on success, -1 on error. - */ -int nc_server_tls_ch_client_endpt_set_trusted_ca_paths(const char *client_name, const char *endpt_name, const char *ca_file, - const char *ca_dir); - -/** - * @brief Set Call Home Certificate Revocation List locations. There can only be - * one file and one directory, they are replaced if already set. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] crl_file Path to a CRL store file in PEM format. Can be NULL. - * @param[in] crl_dir Path to a CRL store hashed directory (c_rehash utility - * can be used to create hashes) with PEM files. Can be NULL. - * @return 0 on success, -1 on error. - */ -int nc_server_tls_ch_client_endpt_set_crl_paths(const char *client_name, const char *endpt_name, const char *crl_file, - const char *crl_dir); - -/** - * @brief Destroy and clean Call Home CRLs. Call Home certificates, private keys, - * and CTN entries are not affected. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - */ -void nc_server_tls_ch_client_endpt_clear_crls(const char *client_name, const char *endpt_name); - -/** - * @brief Add a cert-to-name entry. - * - * It is possible to add an entry step-by-step, specifying first only @p ip and in later calls - * @p fingerprint, @p map_type, and optionally @p name spearately. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] id Priority of the entry. It must be unique. If already exists, the entry with this id - * is modified. - * @param[in] fingerprint Matching certificate fingerprint. If NULL, kept temporarily unset. - * @param[in] map_type Type of username-certificate mapping. If 0, kept temporarily unset. - * @param[in] name Specific username used only if @p map_type == NC_TLS_CTN_SPECIFED. - * @return 0 on success, -1 on error. - */ -int nc_server_tls_ch_client_endpt_add_ctn(const char *client_name, const char *endpt_name, uint32_t id, - const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name); - -/** - * @brief Remove a Call Home cert-to-name entry. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in] id Priority of the entry. -1 matches all the priorities. - * @param[in] fingerprint Fingerprint fo the entry. NULL matches all the fingerprints. - * @param[in] map_type Mapping type of the entry. 0 matches all the mapping types. - * @param[in] name Specific username for the entry. NULL matches all the usernames. - * @return 0 on success, -1 on not finding any match. - */ -int nc_server_tls_ch_client_endpt_del_ctn(const char *client_name, const char *endpt_name, int64_t id, - const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name); - -/** - * @brief Get a Call Home cert-to-name entry. - * - * If a parameter is NULL, it is ignored. If its dereferenced value is NULL, - * it is filled and returned. If the value is set, it is used as a filter. - * Returns first matching entry. - * - * @param[in] client_name Existing Call Home client name. - * @param[in] endpt_name Existing endpoint name of the client. - * @param[in,out] id Priority of the entry. - * @param[in,out] fingerprint Fingerprint fo the entry. - * @param[in,out] map_type Mapping type of the entry. - * @param[in,out] name Specific username for the entry. - * @return 0 on success, -1 on not finding any match. - */ -int nc_server_tls_ch_client_endpt_get_ctn(const char *client_name, const char *endpt_name, uint32_t *id, char **fingerprint, - NC_TLS_CTN_MAPTYPE *map_type, char **name); - -/** @} Server-side Call Home on TLS */ - #endif /* NC_ENABLED_SSH_TLS */ #ifdef __cplusplus From ecb64e6045e96df3dde69cdcf88ceaea0264fdf8 Mon Sep 17 00:00:00 2001 From: Roytak Date: Fri, 29 Sep 2023 15:25:55 +0200 Subject: [PATCH 077/134] doc UPDATE update obsolete doc with new --- doc/libnetconf.doc | 308 ++++++++++++++++++++++++++++----------------- 1 file changed, 193 insertions(+), 115 deletions(-) diff --git a/doc/libnetconf.doc b/doc/libnetconf.doc index c60ff5c9..1b3e4a49 100644 --- a/doc/libnetconf.doc +++ b/doc/libnetconf.doc @@ -17,7 +17,8 @@ * - Creating NETCONF Call Home sessions ([RFC 8071](https://tools.ietf.org/html/rfc8071)). * - Creating, sending, receiving, and replying to RPCs ([RFC 4741](https://tools.ietf.org/html/rfc4741), * [RFC 6241](https://tools.ietf.org/html/rfc6241)). - * - Creating, sending and receiving NETCONF Event Notifications ([RFC 5277](https://tools.ietf.org/html/rfc5277)), + * - Creating, sending and receiving NETCONF Event Notifications ([RFC 5277](https://tools.ietf.org/html/rfc5277)). + * - Configuring the NETCONF server based on the [ietf-netconf-server](https://datatracker.ietf.org/doc/html/draft-ietf-netconf-netconf-client-server-29) YANG module * * @section about-license License * @@ -54,13 +55,11 @@ * @page howtoinit Init and Thread-safety Information * * Before working with the library, it must be initialized using ::nc_client_init() - * or ::nc_server_init(). Based on how the library was compiled, also _libssh_ and/or - * _libssh_/_libcrypto_ are initialized (for multi-threaded use) too. To prevent + * or ::nc_server_init(), based on how the library was compiled. To prevent * any reachable memory at the end of your application, there are complementary * destroy functions (::nc_server_destroy() and ::nc_client_destroy() available. If your * application is multi-threaded, call the destroy functions in the main thread, - * after all the other threads have ended. In every other thread you should call - * ::nc_thread_destroy() just before it exits. + * after all the other threads have ended. * * If _libnetconf2_ is used in accordance with this information, there should * not be memory leaks of any kind at program exit. For thread-safety details @@ -75,7 +74,7 @@ * specified via ::nc_client_set_schema_searchpath(). Alternatively, _libnetconf2_ can use callback * provided via ::nc_client_set_schema_callback(). If these ways do not succeed and the server * implements NETCONF \ operation, the schema is retrieved from the server and stored - * localy into the searchpath (if specified) for a future use. If none of these methods succeed to + * locally into the searchpath (if specified) for a future use. If none of these methods succeed to * load particular schema, the data from this schema are ignored during the communication with the * server. * @@ -121,10 +120,6 @@ * * - ::nc_server_init() * - ::nc_server_destroy() - * - * Available in both __nc_client.h__ and __nc_server.h__. - * - * - ::nc_thread_destroy() */ /** @@ -295,8 +290,7 @@ * cannot be learnt from the context are set with separate functions * ::nc_server_set_capab_withdefaults() and generally ::nc_server_set_capability(). * Timeout for receiving the _hello_ message on a new session can be set - * by ::nc_server_set_hello_timeout() and the timeout for disconnecting - * an inactive session by ::nc_server_set_idle_timeout(). + * by ::nc_server_set_hello_timeout(). * * Context does not only determine server modules, but its overall * functionality as well. For every RPC the server should support, @@ -309,11 +303,7 @@ * * Server options can be only set, there are no getters. * - * To be able to accept any connections, endpoints must first be added - * with ::nc_server_add_endpt() and configured with ::nc_server_endpt_set_address() - * and ::nc_server_endpt_set_port(). For unix sockets, ::nc_server_endpt_set_perms() - * is available to set the unix socket file permissions, and ::nc_server_endpt_set_port() - * is invalid. + * To be able to accept any connections, the server must first be configured. * * Functions List * -------------- @@ -323,44 +313,95 @@ * - ::nc_server_set_capab_withdefaults() * - ::nc_server_set_capability() * - ::nc_server_set_hello_timeout() - * - ::nc_server_set_idle_timeout() * - * - ::nc_server_add_endpt() - * - ::nc_server_del_endpt() - * - ::nc_server_endpt_set_address() - * - ::nc_server_endpt_set_port() - * - ::nc_server_endpt_set_perms() + * Server Configuration + * === + * + * To successfully accept connections on a server, you first need to configure it. + * There are two main ways to do this. The first is using __YANG data__ (see ::nc_server_config_setup_data). + * The second way is using __YANG diff__ (see ::nc_server_config_setup_diff). Optionally, you may do this + * by using __YANG data__ stored in a file (see ::nc_server_config_setup_path). + * However, to be able to configure the server, the required models first need to be implemented in the + * given libyang context using ::nc_server_config_load_modules(). + * + * If you wish not to create the __YANG data/diff__ yourself, you may use the library's functions to do this for you. + * For example ::nc_server_config_new_address_port() creates __YANG data__ corresponding to an SSH/TLS endpoint. + * The variant for UNIX socket is ::nc_server_config_new_unix_socket(). * + * You may also create entries in the keystore or trustore. For example the asymmetric key and certificate entries + * in the keystore can be then referenced as the SSH hostkeys or TLS server certificates, respectively. + * As for the truststore, you may create public key and certificate entries, which can then be used + * as SSH user's public keys or TLS server's end-entity/trust-anchor certificates, respectively. + * + * Functions List + * -------------- + * + * Available in __nc_server.h__. + * + * - ::nc_server_config_load_modules() + * - ::nc_server_config_setup_diff() + * - ::nc_server_config_setup_data() + * - ::nc_server_config_setup_path() + * + * - ::nc_server_config_new_address_port() + * - ::nc_server_config_new_unix_socket() + * - ::nc_server_config_new_del_endpt() + * - ::nc_server_config_new_keystore_asym_key() + * - ::nc_server_config_new_del_keystore_asym_key() + * - ::nc_server_config_new_keystore_cert() + * - ::nc_server_config_new_del_keystore_cert() + * - ::nc_server_config_new_truststore_pubkey() + * - ::nc_server_config_new_del_truststore_pubkey() + * - ::nc_server_config_new_truststore_cert() + * - ::nc_server_config_new_del_truststore_cert() * * SSH * === * - * To successfully accept an SSH session you must set at least the host key using - * ::nc_server_ssh_endpt_add_hostkey(), which are ordered. This way you simply add - * some hostkey identifier, but the key itself will be retrieved always when needed - * by calling the callback set by ::nc_server_ssh_set_hostkey_clb(). + * To successfully accept an SSH session you must configure at least one host key. + * You may create this data yourself or by using ::nc_server_config_new_ssh_hostkey(). * - * There are also some other optional settings. Note that authorized - * public keys are set for the server as a whole, not endpoint-specifically. + * On top of that, each SSH endpoint can define it's own authorized clients and their authentication methods. + * For example if you wish to create an SSH user that can authenticate using a password, use ::nc_server_config_new_ssh_user_password(). + * Another option for authorized clients is to reference another endpoint's clients, however be careful not to create a cyclic reference + * (see ::nc_config_new_ssh_endpoint_user_ref()). An authorized client MUST authenticate to all of it's configured authentication methods. + * + * There are also some other optional settings. * * Functions List * -------------- * * Available in __nc_server.h__. * - * - ::nc_server_ssh_endpt_add_hostkey() - * - ::nc_server_ssh_endpt_del_hostkey() - * - ::nc_server_ssh_endpt_mov_hostkey() - * - ::nc_server_ssh_endpt_mod_hostkey() - * - ::nc_server_ssh_endpt_set_auth_methods() - * - ::nc_server_ssh_endpt_set_auth_attempts() - * - ::nc_server_ssh_endpt_set_auth_timeout() - * - * - ::nc_server_ssh_set_hostkey_clb() - * - * - ::nc_server_ssh_add_authkey() - * - ::nc_server_ssh_add_authkey_path() - * - ::nc_server_ssh_del_authkey() + * - ::nc_server_config_new_ssh_hostkey() + * - ::nc_server_config_new_ssh_del_hostkey() + * - ::nc_server_config_new_ssh_keystore_ref() + * - ::nc_server_config_new_ssh_del_keystore_ref() + * - ::nc_server_config_new_ssh_auth_attempts() + * - ::nc_server_config_new_ssh_auth_timeout() + * + * - ::nc_server_config_new_ssh_user_pubkey() + * - ::nc_server_config_new_ssh_del_user_pubkey() + * - ::nc_server_config_new_ssh_user_password() + * - ::nc_server_config_new_ssh_del_user_password() + * - ::nc_server_config_new_ssh_user_none() + * - ::nc_server_config_new_ssh_del_user_none() + * - ::nc_server_config_new_ssh_user_interactive() + * - ::nc_server_config_new_ssh_del_user_interactive() + * - ::nc_server_config_new_ssh_del_user() + * - ::nc_server_config_new_ssh_truststore_ref() + * - ::nc_server_config_new_ssh_del_truststore_ref() + * - ::nc_config_new_ssh_endpoint_user_ref() + * - ::nc_config_new_ssh_del_endpoint_user_ref() + * + * - ::nc_server_config_new_ssh_host_key_algs() + * - ::nc_server_config_new_ssh_del_host_key_alg() + * - ::nc_server_config_new_ssh_key_exchange_algs() + * - ::nc_server_config_new_ssh_del_key_exchange_alg() + * - ::nc_server_config_new_ssh_encryption_algs() + * - ::nc_server_config_new_ssh_del_encryption_alg() + * - ::nc_server_config_new_ssh_mac_algs() + * - ::nc_server_config_new_ssh_del_mac_alg() * * * TLS @@ -369,47 +410,61 @@ * TLS works with endpoints too, but its options differ * significantly from the SSH ones, especially in the _cert-to-name_ * options that TLS uses to derive usernames from client certificates. - * So, after starting listening on an endpoint you need to set the server - * certificate (::nc_server_tls_endpt_set_server_cert()). Its actual content - * together with the matching private key will be loaded using a callback - * from ::nc_server_tls_set_server_cert_clb(). Additional certificates needed - * for the client to verify the server's certificate chain can be loaded using - * a callback from ::nc_server_tls_set_server_cert_chain_clb(). - * - * To accept client certificates, they must first be considered trusted, - * which you have three ways of achieving. You can add each of their Certificate Authority - * certificates to the trusted ones or mark a specific client certificate - * as trusted. Lastly, you can set paths with all the trusted CA certificates - * with ::nc_server_tls_endpt_set_trusted_ca_paths(). Adding specific certificates - * is also performed only as an arbitrary identificator and later retrieved from - * callback set by ::nc_server_tls_set_trusted_cert_list_clb(). But, you can add - * certficates as whole lists, not one-by-one. + * + * If you wish to listen on a TLS endpoint, you need to configure the endpoint's + * server certificate (see ::nc_server_config_new_tls_server_certificate()). + * + * To accept client certificates, they must first be considered trusted. + * For each TLS endpoint you may configure two types of client certificates. + * The first type are end-entity (client) certificates. These are certificates that belong + * to given clients. These certificates need to be trusted. + * The second type are trust-anchor (certificate authority) certificates, + * which carry over the trust (a chain of trust). + * Another option is to reference another TLS endpoint's end-entity certificates, however be careful not to create a cyclic reference + * (see ::nc_config_new_tls_endpoint_client_ref()). * * Then, from each trusted client certificate a username must be derived * for the NETCONF session. This is accomplished by finding a matching - * _cert-to-name_ entry. They are added using ::nc_server_tls_endpt_add_ctn(). + * _cert-to-name_ entry. * - * If you need to remove trusted certificates, you can do so with ::nc_server_tls_endpt_del_trusted_cert_list(). - * To clear all Certificate Revocation Lists use ::nc_server_tls_endpt_clear_crls(). + * There are some further options. For example you can configure the TLS + * version and ciphers to be used. You may also choose to use a Certificate + * Revoke List. There are three options, ::nc_server_config_new_tls_crl_path() + * attempts to get the list of revoked certificates from a file. ::nc_server_config_new_tls_crl_url() + * attempts to download the list from the given URL. Lastly, ::nc_server_config_new_tls_crl_cert_ext() + * attempts to download the CRLs from URLs specified in the extension fields of the configured certificates. * * Functions List * -------------- * * Available in __nc_server.h__. * - * - ::nc_server_tls_endpt_set_server_cert() - * - ::nc_server_tls_endpt_add_trusted_cert_list() - * - ::nc_server_tls_endpt_del_trusted_cert_list() - * - ::nc_server_tls_endpt_set_trusted_ca_paths() - * - ::nc_server_tls_endpt_set_crl_paths() - * - ::nc_server_tls_endpt_clear_crls() - * - ::nc_server_tls_endpt_add_ctn() - * - ::nc_server_tls_endpt_del_ctn() - * - ::nc_server_tls_endpt_get_ctn() - * - * - ::nc_server_tls_set_server_cert_clb() - * - ::nc_server_tls_set_server_cert_chain_clb() - * - ::nc_server_tls_set_trusted_cert_list_clb() + * - ::nc_server_config_new_tls_server_certificate() + * - ::nc_server_config_new_tls_del_server_certificate() + * - ::nc_server_config_new_tls_keystore_ref() + * - ::nc_server_config_new_tls_del_keystore_ref() + * + * - ::nc_server_config_new_tls_client_certificate() + * - ::nc_server_config_new_tls_del_client_certificate() + * - ::nc_server_config_new_tls_client_cert_truststore_ref() + * - ::nc_server_config_new_tls_del_client_cert_truststore_ref() + * - ::nc_server_config_new_tls_client_ca() + * - ::nc_server_config_new_tls_del_client_ca() + * - ::nc_server_config_new_tls_client_ca_truststore_ref() + * - ::nc_server_config_new_tls_del_client_ca_truststore_ref() + * - ::nc_config_new_tls_endpoint_client_ref() + * - ::nc_config_new_tls_del_endpoint_client_ref() + * - ::nc_server_config_new_tls_ctn() + * - ::nc_server_config_new_tls_del_ctn() + * + * - ::nc_server_config_new_tls_version() + * - ::nc_server_config_new_tls_del_version() + * - ::nc_server_config_new_tls_ciphers() + * - ::nc_server_config_new_tls_del_cipher() + * - ::nc_server_config_new_tls_crl_path() + * - ::nc_server_config_new_tls_crl_url() + * - ::nc_server_config_new_tls_crl_cert_ext() + * - ::nc_server_config_new_tls_del_crl() * * FD * == @@ -435,6 +490,7 @@ * once all the mandatory options are set, _libnetconf2_ __will not__ * immediately start connecting to a client. It will do so only after * calling ::nc_connect_ch_client_dispatch() in a separate thread. + * Unix socket _Call Home_ sessions are not supported. * * Lastly, monitoring of these sessions is up to the application. * @@ -443,41 +499,67 @@ * * Available in __nc_server.h__. * - * - ::nc_server_ch_add_client() - * - ::nc_server_ch_del_client() - * - ::nc_server_ch_is_client() - * - ::nc_server_ch_client_add_endpt() - * - ::nc_server_ch_client_del_endpt() - * - ::nc_server_ch_client_is_endpt() - * - ::nc_server_ch_client_endpt_set_address() - * - ::nc_server_ch_client_endpt_set_port() - * - ::nc_server_ch_client_endpt_enable_keepalives() - * - ::nc_server_ch_client_endpt_set_keepalives() - * - ::nc_server_ch_client_set_conn_type() - * - ::nc_server_ch_client_periodic_set_period() - * - ::nc_server_ch_client_periodic_set_anchor_time() - * - ::nc_server_ch_client_periodic_set_idle_timeout() - * - ::nc_server_ch_client_set_start_with() - * - ::nc_server_ch_client_set_max_attempts() - * - ::nc_connect_ch_client_dispatch() - * - * - ::nc_server_ssh_ch_client_endpt_add_hostkey() - * - ::nc_server_ssh_ch_client_endpt_del_hostkey() - * - ::nc_server_ssh_ch_client_endpt_mov_hostkey() - * - ::nc_server_ssh_ch_client_endpt_set_auth_methods() - * - ::nc_server_ssh_ch_client_endpt_get_auth_methods() - * - ::nc_server_ssh_ch_client_endpt_set_auth_attempts() - * - ::nc_server_ssh_ch_client_endpt_set_auth_timeout() - * - * - ::nc_server_tls_ch_client_endpt_set_server_cert() - * - ::nc_server_tls_ch_client_endpt_add_trusted_cert_list() - * - ::nc_server_tls_ch_client_endpt_del_trusted_cert_list() - * - ::nc_server_tls_ch_client_endpt_set_trusted_ca_paths() - * - ::nc_server_tls_ch_client_endpt_set_crl_paths() - * - ::nc_server_tls_ch_client_endpt_clear_crls() - * - ::nc_server_tls_ch_client_endpt_add_ctn() - * - ::nc_server_tls_ch_client_endpt_del_ctn() - * - ::nc_server_tls_ch_client_endpt_get_ctn() + * - ::nc_server_config_new_ch_address_port() + * - ::nc_server_config_new_del_ch_client() + * - ::nc_server_config_new_ch_del_endpt() + * - ::nc_server_config_new_ch_persistent() + * - ::nc_server_config_new_ch_period() + * - ::nc_server_config_new_ch_del_period() + * - ::nc_server_config_new_ch_anchor_time() + * - ::nc_server_config_new_ch_del_anchor_time() + * - ::nc_server_config_new_ch_idle_timeout() + * - ::nc_server_config_new_ch_del_idle_timeout() + * - ::nc_server_config_new_ch_reconnect_strategy() + * - ::nc_server_config_new_ch_del_reconnect_strategy() + * + * - ::nc_server_config_new_ch_ssh_hostkey() + * - ::nc_server_config_new_ch_ssh_del_hostkey() + * - ::nc_server_config_new_ch_ssh_keystore_ref() + * - ::nc_server_config_new_ch_ssh_del_keystore_ref() + * - ::nc_server_config_new_ch_ssh_auth_attempts() + * - ::nc_server_config_new_ch_ssh_auth_timeout() + * - ::nc_server_config_new_ch_ssh_user_pubkey() + * - ::nc_server_config_new_ch_ssh_del_user_pubkey() + * - ::nc_server_config_new_ch_ssh_user_password() + * - ::nc_server_config_new_ch_ssh_del_user_password() + * - ::nc_server_config_new_ch_ssh_user_none() + * - ::nc_server_config_new_ch_ssh_del_user_none() + * - ::nc_server_config_new_ch_ssh_user_interactive() + * - ::nc_server_config_new_ch_ssh_del_user_interactive() + * - ::nc_server_config_new_ch_ssh_del_user() + * - ::nc_server_config_new_ch_ssh_truststore_ref() + * - ::nc_server_config_new_ch_ssh_del_truststore_ref() + * - ::nc_server_config_new_ch_ssh_host_key_algs() + * - ::nc_server_config_new_ch_ssh_del_host_key_alg() + * - ::nc_server_config_new_ch_ssh_key_exchange_algs() + * - ::nc_server_config_new_ch_ssh_del_key_exchange_alg() + * - ::nc_server_config_new_ch_ssh_encryption_algs() + * - ::nc_server_config_new_ch_ssh_del_encryption_alg() + * - ::nc_server_config_new_ch_ssh_mac_algs() + * - ::nc_server_config_new_ch_ssh_del_mac_alg() + * + * - ::nc_server_config_new_ch_tls_server_certificate() + * - ::nc_server_config_new_ch_tls_del_server_certificate() + * - ::nc_server_config_new_ch_tls_keystore_ref() + * - ::nc_server_config_new_ch_tls_del_keystore_ref() + * - ::nc_server_config_new_ch_tls_client_certificate() + * - ::nc_server_config_new_ch_tls_del_client_certificate() + * - ::nc_server_config_new_ch_tls_client_cert_truststore_ref() + * - ::nc_server_config_new_ch_tls_del_client_cert_truststore_ref() + * - ::nc_server_config_new_ch_tls_client_ca() + * - ::nc_server_config_new_ch_tls_del_client_ca() + * - ::nc_server_config_new_ch_tls_client_ca_truststore_ref() + * - ::nc_server_config_new_ch_tls_del_client_ca_truststore_ref() + * - ::nc_server_config_new_ch_tls_ctn() + * - ::nc_server_config_new_ch_tls_del_ctn() + * - ::nc_server_config_new_ch_tls_version() + * - ::nc_server_config_new_ch_tls_del_version() + * - ::nc_server_config_new_ch_tls_ciphers() + * - ::nc_server_config_new_ch_tls_del_cipher() + * - ::nc_server_config_new_ch_tls_crl_path() + * - ::nc_server_config_new_ch_tls_crl_url() + * - ::nc_server_config_new_ch_tls_crl_cert_ext() + * - ::nc_server_config_new_ch_tls_del_crl() * * * Connecting And Cleanup @@ -580,7 +662,7 @@ * * There are several timeouts which are used throughout _libnetconf2_ to * assure that it will never indefinitely hang on any operation. Normally, - * you should not need to worry about them much necause they are set by + * you should not need to worry about them much because they are set by * default to reasonable values for common systems. However, if your * platform is not common (embedded, ...), adjusting these timeouts may * save a lot of debugging and time. @@ -602,7 +684,8 @@ * To free up some resources, it is possible to adjust the maximum idle period * of a session before it is disconnected. In _Call Home_, for both a persistent * and periodic connection can this idle timeout be specified separately for each - * client using corresponding functions. + * client using corresponding functions. Unlike other timeouts, the idle timeout + * can only be set via applying configuration data. * * Lastly, SSH user authentication timeout can be also modified. It is the time * a client has to successfully authenticate after connecting before it is disconnected. @@ -614,11 +697,6 @@ * * - ::nc_server_set_hello_timeout() * - ::nc_server_get_hello_timeout() - * - ::nc_server_set_idle_timeout() - * - ::nc_server_get_idle_timeout() - * - ::nc_server_ch_client_periodic_set_idle_timeout() - * - ::nc_server_ssh_ch_client_endpt_set_auth_timeout() - * - ::nc_server_ssh_ch_client_endpt_set_auth_timeout() */ /** From 27274a206e8c5c8adf81dd092016214561e1655a Mon Sep 17 00:00:00 2001 From: Roytak Date: Wed, 4 Oct 2023 14:05:47 +0200 Subject: [PATCH 078/134] log UPDATE increase arg check macro to 7 args --- src/log_p.h | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/log_p.h b/src/log_p.h index dbde9963..5f3e1d01 100644 --- a/src/log_p.h +++ b/src/log_p.h @@ -59,14 +59,28 @@ extern ATOMIC_T verbose_level; #define GETMACRO4(_1, _2, _3, _4, NAME, ...) NAME #define GETMACRO5(_1, _2, _3, _4, _5, NAME, ...) NAME #define GETMACRO6(_1, _2, _3, _4, _5, _6, NAME, ...) NAME +#define GETMACRO7(_1, _2, _3, _4, _5, _6, _7, NAME, ...) NAME +#define GETMACRO8(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME #define NC_CHECK_ARG_RET1(session, ARG, RETVAL) if (!(ARG)) {ERRARG(session, ARG);return RETVAL;} -#define NC_CHECK_ARG_RET2(session, ARG1, ARG2, RETVAL) NC_CHECK_ARG_RET1(session, ARG1, RETVAL);NC_CHECK_ARG_RET1(session, ARG2, RETVAL) -#define NC_CHECK_ARG_RET3(session, ARG1, ARG2, ARG3, RETVAL) NC_CHECK_ARG_RET2(session, ARG1, ARG2, RETVAL);NC_CHECK_ARG_RET1(session, ARG3, RETVAL) -#define NC_CHECK_ARG_RET4(session, ARG1, ARG2, ARG3, ARG4, RETVAL) NC_CHECK_ARG_RET3(session, ARG1, ARG2, ARG3, RETVAL);\ +#define NC_CHECK_ARG_RET2(session, ARG1, ARG2, RETVAL)\ + NC_CHECK_ARG_RET1(session, ARG1, RETVAL);\ + NC_CHECK_ARG_RET1(session, ARG2, RETVAL) +#define NC_CHECK_ARG_RET3(session, ARG1, ARG2, ARG3, RETVAL)\ + NC_CHECK_ARG_RET2(session, ARG1, ARG2, RETVAL);\ + NC_CHECK_ARG_RET1(session, ARG3, RETVAL) +#define NC_CHECK_ARG_RET4(session, ARG1, ARG2, ARG3, ARG4, RETVAL)\ + NC_CHECK_ARG_RET3(session, ARG1, ARG2, ARG3, RETVAL);\ NC_CHECK_ARG_RET1(session, ARG4, RETVAL) -#define NC_CHECK_ARG_RET5(session, ARG1, ARG2, ARG3, ARG4, ARG5, RETVAL) NC_CHECK_ARG_RET4(session, ARG1, ARG2, ARG3, ARG4, RETVAL);\ +#define NC_CHECK_ARG_RET5(session, ARG1, ARG2, ARG3, ARG4, ARG5, RETVAL)\ + NC_CHECK_ARG_RET4(session, ARG1, ARG2, ARG3, ARG4, RETVAL);\ NC_CHECK_ARG_RET1(session, ARG5, RETVAL) +#define NC_CHECK_ARG_RET6(session, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, RETVAL)\ + NC_CHECK_ARG_RET5(session, ARG1, ARG2, ARG3, ARG4, ARG5, RETVAL);\ + NC_CHECK_ARG_RET1(session, ARG6, RETVAL) +#define NC_CHECK_ARG_RET7(session, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, RETVAL)\ + NC_CHECK_ARG_RET6(session, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, RETVAL);\ + NC_CHECK_ARG_RET1(session, ARG7, RETVAL) /** * @brief Function's parameters checking macro @@ -74,7 +88,7 @@ extern ATOMIC_T verbose_level; * @param session Session that is logged. * @param ... Parameters of the function to check. The last parameter is the value that is returned on error. */ -#define NC_CHECK_ARG_RET(session, ...) GETMACRO6(__VA_ARGS__, NC_CHECK_ARG_RET5, NC_CHECK_ARG_RET4, NC_CHECK_ARG_RET3, \ - NC_CHECK_ARG_RET2, NC_CHECK_ARG_RET1, DUMMY) (session, __VA_ARGS__) +#define NC_CHECK_ARG_RET(session, ...) GETMACRO8(__VA_ARGS__, NC_CHECK_ARG_RET7, NC_CHECK_ARG_RET6, NC_CHECK_ARG_RET5,\ + NC_CHECK_ARG_RET4, NC_CHECK_ARG_RET3, NC_CHECK_ARG_RET2, NC_CHECK_ARG_RET1, DUMMY) (session, __VA_ARGS__) #endif /* NC_LOG_PRIVATE_H_ */ From 60ea5fe943d398a5ee23488a4a9f76d040a90de3 Mon Sep 17 00:00:00 2001 From: Roytak Date: Wed, 4 Oct 2023 14:06:38 +0200 Subject: [PATCH 079/134] config_new REFACTOR code review --- src/config_new.c | 106 ++++++++++++++++++++++++++++++-------------- src/config_new.h | 18 +++++--- src/server_config.h | 2 +- tests/test_ch.c | 4 +- 4 files changed, 89 insertions(+), 41 deletions(-) diff --git a/src/config_new.c b/src/config_new.c index 01f63d6d..2a957553 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -35,12 +35,13 @@ #include "session_p.h" int -nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...) +nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...) { int ret = 0; va_list ap; char *path = NULL; - struct lyd_node *sub = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, tree, path_fmt, 1); va_start(ap, path_fmt); @@ -52,15 +53,18 @@ nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...) goto cleanup; } - /* find the node we want to delete */ - ret = lyd_find_path(*tree, path, 0, &sub); + /* create the nodes in the path */ + if (!*tree) { + ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); + } else { + /* this could output NULL if no new nodes, lyd_find_path would fail then */ + ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, NULL); + } if (ret) { goto cleanup; } - lyd_free_tree(sub); - - /* set the node to top level container */ + /* set the node to the top level node */ ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); if (ret) { goto cleanup; @@ -79,16 +83,16 @@ nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...) } int -nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...) +nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name, + const char *value, struct lyd_node **tree) { int ret = 0; - va_list ap; char *path = NULL; - va_start(ap, path_fmt); + NC_CHECK_ARG_RET(NULL, ctx, parent_path, child_name, tree, 1); - /* create the path from the format */ - ret = vasprintf(&path, path_fmt, ap); + /* create the path by appending child to the parent path */ + ret = asprintf(&path, "%s/%s", parent_path, child_name); if (ret == -1) { ERRMEM; path = NULL; @@ -120,37 +124,38 @@ nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const cha cleanup: free(path); - va_end(ap); return ret; } int -nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name, - const char *value, struct lyd_node **tree) +nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...) { int ret = 0; + va_list ap; char *path = NULL; + struct lyd_node *sub = NULL; - /* create the path by appending child to the parent path */ - ret = asprintf(&path, "%s/%s", parent_path, child_name); + NC_CHECK_ARG_RET(NULL, tree, path_fmt, 1); + + va_start(ap, path_fmt); + + /* create the path from the format */ + ret = vasprintf(&path, path_fmt, ap); if (ret == -1) { ERRMEM; path = NULL; goto cleanup; } - /* create the nodes in the path */ - if (!*tree) { - ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, tree); - } else { - /* this could output NULL if no new nodes, lyd_find_path would fail then */ - ret = lyd_new_path(*tree, ctx, path, value, LYD_NEW_PATH_UPDATE, NULL); - } + /* find the node we want to delete */ + ret = lyd_find_path(*tree, path, 0, &sub); if (ret) { goto cleanup; } - /* set the node to the top level node */ + lyd_free_tree(sub); + + /* set the node to top level container */ ret = lyd_find_path(*tree, "/ietf-netconf-server:netconf-server", 0, tree); if (ret) { goto cleanup; @@ -164,6 +169,7 @@ nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, c cleanup: free(path); + va_end(ap); return ret; } @@ -175,6 +181,8 @@ nc_config_new_check_delete(struct lyd_node **tree, const char *path_fmt, ...) char *path = NULL; struct lyd_node *sub = NULL; + NC_CHECK_ARG_RET(NULL, tree, path_fmt, 1); + va_start(ap, path_fmt); /* create the path from the format */ @@ -235,6 +243,8 @@ nc_server_config_new_pubkey_bin_to_b64(const unsigned char *pub_bin, int bin_len int ret = 0, b64_len; char *pub_b64 = NULL; + NC_CHECK_ARG_RET(NULL, pub_bin, bin_len, pubkey, 1); + /* get b64 buffer len, for ever 3 bytes of bin 4 bytes of b64 + NULL terminator */ if (bin_len % 3 == 0) { pub_b64 = malloc((bin_len / 3) * 4 + 1); @@ -322,6 +332,8 @@ nc_server_config_new_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) uint32_t alg_name_len, curve_name_len, alg_name_len_be, curve_name_len_be, p_len_be, e_len_be, n_len_be; size_t ec_group_len; + NC_CHECK_ARG_RET(NULL, pkey, pubkey, 1); + if (EVP_PKEY_is_a(pkey, "RSA")) { /* RSA key */ algorithm_name = "ssh-rsa"; @@ -467,6 +479,7 @@ nc_server_config_new_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) goto cleanup; } + /* convert created bin to b64 */ ret = nc_server_config_new_pubkey_bin_to_b64(bin, bin_len, pubkey); if (ret) { ERR(NULL, "Converting public key from binary to base64 failed."); @@ -493,6 +506,8 @@ nc_server_config_new_evp_pkey_to_spki_pubkey(EVP_PKEY *pkey, char **pubkey) BIO *bio = NULL; char *pub_b64 = NULL; + NC_CHECK_ARG_RET(NULL, pkey, pubkey, 1); + bio = BIO_new(BIO_s_mem()); if (!bio) { ERR(NULL, "Creating new BIO failed (%s).", ERR_reason_error_string(ERR_get_error())); @@ -538,7 +553,7 @@ nc_server_config_new_read_certificate(const char *cert_path, char **cert) BIO *bio = NULL; char *c = NULL; - *cert = NULL; + NC_CHECK_ARG_RET(NULL, cert_path, cert, 1); f = fopen(cert_path, "r"); if (!f) { @@ -623,16 +638,22 @@ nc_server_config_new_read_pubkey_ssh2(FILE *f, char **pubkey) ssize_t read; int ret = 0; + NC_CHECK_ARG_RET(NULL, f, pubkey, 1); + + /* read lines from the file and create the public key without NL from it */ while ((read = getline(&buffer, &size, f)) > 0) { if (!strncmp(buffer, "----", 4)) { + /* skip header and footer */ continue; } if (!strncmp(buffer, "Comment:", 8)) { + /* skip a comment */ continue; } if (buffer[read - 1] == '\n') { + /* avoid NL */ read--; } @@ -803,6 +824,8 @@ nc_server_config_new_privkey_header_to_format(FILE *f_privkey, const char *privk char *privkey_header = NULL; size_t len = 0; + NC_CHECK_ARG_RET(NULL, f_privkey, privkey_path, privkey_format, 1); + /* read header */ if (getline(&privkey_header, &len, f_privkey) < 0) { ERR(NULL, "Error reading header from file \"%s\".", privkey_path); @@ -840,6 +863,8 @@ nc_server_config_new_get_privkey_openssl(const char *privkey_path, FILE *f_privk BIO *bio = NULL; char *priv_b64 = NULL; + NC_CHECK_ARG_RET(NULL, privkey_path, f_privkey, privkey, pkey, 1); + bio = BIO_new(BIO_s_mem()); if (!bio) { ERR(NULL, "Creating new BIO failed (%s).", ERR_reason_error_string(ERR_get_error())); @@ -871,8 +896,14 @@ nc_server_config_new_get_privkey_openssl(const char *privkey_path, FILE *f_privk } *privkey = strndup(priv_b64, len); + if (!*privkey) { + ERRMEM; + ret = 1; + goto cleanup; + } cleanup: + /* priv_b64 is freed with BIO */ BIO_free(bio); return ret; } @@ -885,6 +916,8 @@ nc_server_config_new_get_privkey_libssh(const char *privkey_path, char **privkey char *priv_b64 = NULL; ssh_key key = NULL; + NC_CHECK_ARG_RET(NULL, privkey_path, privkey, pkey, 1); + ret = ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, &key); if (ret) { ERR(NULL, "Importing privkey from file \"%s\" failed.", privkey_path); @@ -921,6 +954,11 @@ nc_server_config_new_get_privkey_libssh(const char *privkey_path, char **privkey } *privkey = strndup(priv_b64, ret); + if (!*privkey) { + ERRMEM; + ret = 1; + goto cleanup; + } /* ok */ ret = 0; @@ -939,6 +977,8 @@ nc_server_config_new_get_privkey(const char *privkey_path, NC_PRIVKEY_FORMAT *pr FILE *f_privkey = NULL; char *priv = NULL; + NC_CHECK_ARG_RET(NULL, privkey_path, privkey_format, privkey, pkey, 1); + f_privkey = fopen(privkey_path, "r"); if (!f_privkey) { ERR(NULL, "Unable to open file \"%s\".", privkey_path); @@ -1049,7 +1089,7 @@ nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_na const char *address_fmt, *port_fmt; char port_buf[6] = {0}; - NC_CHECK_ARG_RET(NULL, address, ctx, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, address, config, 1); if (transport == NC_TI_LIBSSH) { /* SSH path */ @@ -1060,7 +1100,7 @@ nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_na address_fmt = "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tcp-server-parameters/local-address"; port_fmt = "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tcp-server-parameters/local-port"; } else { - ERR(NULL, "Transport not supported."); + ERR(NULL, "Can not set address and port of a non SSH/TLS endpoint."); ret = 1; goto cleanup; } @@ -1087,7 +1127,7 @@ nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *clien int ret = 0; const char *address_fmt, *port_fmt; - NC_CHECK_ARG_RET(NULL, address, port, ctx, endpt_name, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, address, port, config, 1); if (transport == NC_TI_LIBSSH) { /* SSH path */ @@ -1130,7 +1170,7 @@ nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **config) } API int -nc_server_config_new_del_ch_client(const char *ch_client_name, struct lyd_node **config) +nc_server_config_new_ch_del_ch_client(const char *ch_client_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, config, 1); @@ -1447,7 +1487,7 @@ nc_server_config_new_ch_period(const struct ly_ctx *ctx, const char *ch_client_n { char buf[6] = {0}; - NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, period, 1); + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1); /* delete persistent tree if exists */ if (nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" @@ -1473,7 +1513,7 @@ API int nc_server_config_new_ch_anchor_time(const struct ly_ctx *ctx, const char *ch_client_name, const char *anchor_time, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, anchor_time, 1); + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, anchor_time, config, 1); /* delete persistent tree if exists */ if (nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" @@ -1500,7 +1540,7 @@ nc_server_config_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_cl { char buf[6] = {0}; - NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, 1); + NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1); /* delete persistent tree if exists */ if (nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" diff --git a/src/config_new.h b/src/config_new.h index 3b7401b0..3fae017c 100644 --- a/src/config_new.h +++ b/src/config_new.h @@ -89,7 +89,7 @@ const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT forma * * @param[in] ctx libyang context. * @param[in, out] tree The YANG data tree where the insertion will happen. On success - * the top level container is always returned. + * this is set to the top level container. * @param[in] value Value assigned to the final node in the path. * @param[in] path_fmt Format of the path. * @param[in] ... Parameters for the path format, essentially representing the lists' keys. @@ -98,14 +98,14 @@ const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT forma int nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...); /** - * @brief Creates new YANG data nodes in a path and gives the final node a value. + * @brief Creates a YANG data node by appending it to a specified parent node. * * @param[in] ctx libyang context. * @param[in] parent_path Path to the parent node. * @param[in] child_name Name of the parent's child node to be created. - * @param[in] value Value to give to the child node. + * @param[in] value Value given to the child node. * @param[out] tree YANG data tree where the insertion will happen. On success - * the top level container is always returned. + * this is set to the top level container. * @return 0 on success, 1 otherwise. */ int nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name, @@ -115,12 +115,20 @@ int nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_pat * @brief Deletes a subtree from the YANG data. * * @param tree YANG data from which the subtree will be deleted. - * @param[in] path_fmt Format of the path + * @param[in] path_fmt Format of the path. The last node will be the top level node of the deleted tree. * @param[in] ... Parameters for the path format, essentially representing the lists' keys. * @return 0 on success, non-zero otherwise. */ int nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...); +/** + * @brief Deletes a subtree from the YANG data, but doesn't return an error if the node doesn't exist. + * + * @param tree YANG data from which the subtree will be deleted. + * @param[in] path_fmt Format of the path. The last node will be the top level node of the deleted tree. + * @param[in] ... Parameters for the path format, essentially representing the lists' keys. + * @return 0 on success, non-zero otherwise. + */ int nc_config_new_check_delete(struct lyd_node **tree, const char *path_fmt, ...); #ifdef __cplusplus diff --git a/src/server_config.h b/src/server_config.h index fb21cba4..a028b0bb 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -1056,7 +1056,7 @@ int nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *c * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_del_ch_client(const char *client_name, struct lyd_node **config); +int nc_server_config_new_ch_del_ch_client(const char *client_name, struct lyd_node **config); /** * @brief Deletes a Call Home endpoint from the YANG data. diff --git a/tests/test_ch.c b/tests/test_ch.c index 1218d2c3..5e48cbc5 100644 --- a/tests/test_ch.c +++ b/tests/test_ch.c @@ -98,7 +98,7 @@ server_thread_ssh(void *arg) strcpy(expected, "reconnecting in"); /* prepare data for deleting the call-home client */ - ret = nc_server_config_new_del_ch_client("ch_ssh", &state->ssh_tree); + ret = nc_server_config_new_ch_del_ch_client("ch_ssh", &state->ssh_tree); assert_int_equal(ret, 0); /* new poll session */ @@ -282,7 +282,7 @@ server_thread_tls(void *arg) struct nc_pollsession *ps; /* prepare data for deleting the call-home client */ - ret = nc_server_config_new_del_ch_client("ch_tls", &state->tls_tree); + ret = nc_server_config_new_ch_del_ch_client("ch_tls", &state->tls_tree); assert_int_equal(ret, 0); /* new poll session */ From d6dad2c4d7ea93bc5bcc390554291e3c65e7e405 Mon Sep 17 00:00:00 2001 From: Roytak Date: Thu, 5 Oct 2023 14:32:23 +0200 Subject: [PATCH 080/134] config_new_ssh REFACTOR code review --- src/config_new_ssh.c | 65 +++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c index db9670e6..a61dd424 100644 --- a/src/config_new_ssh.c +++ b/src/config_new_ssh.c @@ -16,6 +16,7 @@ #define _GNU_SOURCE #include +#include #include #include #include @@ -43,6 +44,8 @@ _nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *tree_pat NC_PRIVKEY_FORMAT privkey_type; const char *privkey_format, *pubkey_format = "ietf-crypto-types:ssh-public-key-format"; + NC_CHECK_ARG_RET(NULL, ctx, tree_path, privkey_path, config, 1); + /* get the keys as a string from the given files */ ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_SSH, &privkey, &privkey_type, &pubkey); if (ret) { @@ -124,8 +127,7 @@ nc_server_config_new_ch_ssh_hostkey(const struct ly_ctx *ctx, const char *client int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, privkey_path, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, privkey_path, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" @@ -212,8 +214,7 @@ nc_server_config_new_ch_ssh_keystore_ref(const struct ly_ctx *ctx, const char *c { int ret = 0; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, keystore_reference, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, keystore_reference, config, 1); ret = nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" @@ -394,8 +395,7 @@ nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *endpt int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pubkey_name, pubkey_path, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pubkey_name, pubkey_path, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" @@ -408,7 +408,7 @@ nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *endpt ret = _nc_server_config_new_ssh_user_pubkey(ctx, path, pubkey_path, config); if (ret) { - ERR(NULL, "Creating new user's public key failed."); + ERR(NULL, "Creating new SSH user's public key failed."); goto cleanup; } @@ -432,8 +432,7 @@ nc_server_config_new_ch_ssh_user_pubkey(const struct ly_ctx *ctx, const char *cl int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pubkey_name, 1); - NC_CHECK_ARG_RET(NULL, pubkey_path, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pubkey_name, pubkey_path, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" @@ -447,7 +446,7 @@ nc_server_config_new_ch_ssh_user_pubkey(const struct ly_ctx *ctx, const char *cl ret = _nc_server_config_new_ssh_user_pubkey(ctx, path, pubkey_path, config); if (ret) { - ERR(NULL, "Creating new user's public key failed."); + ERR(NULL, "Creating new CH SSH user's public key failed."); goto cleanup; } @@ -508,6 +507,8 @@ _nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *tr char *hashed_pw = NULL; const char *salt = "$6$idsizuippipk$"; + NC_CHECK_ARG_RET(NULL, ctx, tree_path, password, config, 1); + #ifdef HAVE_CRYPT_R struct crypt_data cdata; #endif @@ -522,7 +523,7 @@ _nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *tr #endif if (!hashed_pw) { - ERR(NULL, "Hashing password failed."); + ERR(NULL, "Hashing password failed (%s).", strerror(errno)); ret = 1; goto cleanup; } @@ -555,7 +556,7 @@ nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *end ret = _nc_server_config_new_ssh_user_password(ctx, path, password, config); if (ret) { - ERR(NULL, "Creating new user's public key failed."); + ERR(NULL, "Creating new SSH user's password failed."); goto cleanup; } @@ -571,8 +572,7 @@ nc_server_config_new_ch_ssh_user_password(const struct ly_ctx *ctx, const char * int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, password, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, password, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" @@ -585,7 +585,7 @@ nc_server_config_new_ch_ssh_user_password(const struct ly_ctx *ctx, const char * ret = _nc_server_config_new_ssh_user_password(ctx, path, password, config); if (ret) { - ERR(NULL, "Creating new user's password failed."); + ERR(NULL, "Creating new CH SSH user's password failed."); goto cleanup; } @@ -697,7 +697,7 @@ nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char * ret = _nc_server_config_new_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); if (ret) { - ERR(NULL, "Creating new user's keyboard interactive nodes failed."); + ERR(NULL, "Creating new SSH user's keyboard interactive nodes failed."); goto cleanup; } @@ -713,8 +713,7 @@ nc_server_config_new_ch_ssh_user_interactive(const struct ly_ctx *ctx, const cha int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pam_config_name, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pam_config_name, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" @@ -727,7 +726,7 @@ nc_server_config_new_ch_ssh_user_interactive(const struct ly_ctx *ctx, const cha ret = _nc_server_config_new_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); if (ret) { - ERR(NULL, "Creating new user's keyboard interactive nodes failed."); + ERR(NULL, "Creating new CH SSH user's keyboard interactive nodes failed."); goto cleanup; } @@ -840,8 +839,7 @@ nc_server_config_new_ch_ssh_truststore_ref(const struct ly_ctx *ctx, const char { int ret = 0; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, truststore_reference, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, truststore_reference, config, 1); ret = nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" @@ -891,18 +889,21 @@ nc_server_config_new_ssh_transport_params_prep(const struct ly_ctx *ctx, const c int ret = 0; char *tree_path = NULL; + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, new_tree, alg_tree, 1); + /* prepare path */ if (client_name) { /* ch */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + ret = asprintf(&tree_path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" "endpoint[name='%s']/ssh/ssh-server-parameters/transport-params", client_name, endpt_name); } else { /* listen */ - asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + ret = asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" "ssh/ssh-server-parameters/transport-params", endpt_name); } - if (!tree_path) { + if (ret == -1) { ERRMEM; + tree_path = NULL; ret = 1; goto cleanup; } @@ -915,7 +916,7 @@ nc_server_config_new_ssh_transport_params_prep(const struct ly_ctx *ctx, const c } if (!*alg_tree) { - /* no new nodes added */ + /* no new nodes added, set the path correctly for adding child nodes later */ ret = lyd_find_path(config, tree_path, 0, alg_tree); if (ret) { goto cleanup; @@ -936,6 +937,8 @@ nc_server_config_new_ssh_transport_params_create(const struct ly_ctx *ctx, NC_AL const char *module, *alg_path, *old_path; struct lyd_node *old = NULL; + NC_CHECK_ARG_RET(NULL, ctx, tree, 1); + /* get the correct module with the indentity base and the path in the ietf-netconf-server module */ switch (alg_type) { case NC_ALG_HOSTKEY: @@ -973,8 +976,7 @@ nc_server_config_new_ssh_transport_params_create(const struct ly_ctx *ctx, NC_AL for (i = 0; i < alg_count; i++) { alg = va_arg(ap, char *); - asprintf(&alg_ident, "%s:%s", module, alg); - if (!alg_ident) { + if (asprintf(&alg_ident, "%s:%s", module, alg) == -1) { ERRMEM; ret = 1; goto cleanup; @@ -984,10 +986,12 @@ nc_server_config_new_ssh_transport_params_create(const struct ly_ctx *ctx, NC_AL ret = lyd_new_path(tree, ctx, alg_path, alg_ident, 0, NULL); if (ret) { ERR(NULL, "Creating new algorithm leaf-list failed."); + free(alg_ident); goto cleanup; } free(alg_ident); + alg_ident = NULL; } cleanup: @@ -1001,6 +1005,9 @@ nc_server_config_new_ssh_transport_params(const struct ly_ctx *ctx, const char * int ret = 0; struct lyd_node *new_tree, *alg_tree; + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + /* prepare the tree for appending child nodes (the params) */ ret = nc_server_config_new_ssh_transport_params_prep(ctx, client_name, endpt_name, *config, &new_tree, &alg_tree); if (ret) { goto cleanup; @@ -1010,16 +1017,18 @@ nc_server_config_new_ssh_transport_params(const struct ly_ctx *ctx, const char * *config = new_tree; } + /* create the child nodes */ ret = nc_server_config_new_ssh_transport_params_create(ctx, alg_type, alg_count, ap, alg_tree); if (ret) { goto cleanup; } - /* Add all default nodes */ + /* add all default nodes */ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); if (ret) { goto cleanup; } + cleanup: return ret; } From 114f22f6925bb9574abd63ac2103f76a407d0302 Mon Sep 17 00:00:00 2001 From: Roytak Date: Thu, 5 Oct 2023 15:10:18 +0200 Subject: [PATCH 081/134] config_new_tls REFACTOR code review --- src/config_new_tls.c | 148 ++++++++++++++++--------------------------- tests/test_crl.c | 5 ++ 2 files changed, 60 insertions(+), 93 deletions(-) diff --git a/src/config_new_tls.c b/src/config_new_tls.c index a094ec6f..2fb7a7bd 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -32,14 +32,16 @@ #include "session_p.h" static int -_nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *pubkey_path, - const char *privkey_path, const char *certificate_path, struct lyd_node **config) +_nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *privkey_path, + const char *pubkey_path, const char *certificate_path, struct lyd_node **config) { int ret = 0; char *privkey = NULL, *pubkey = NULL, *cert = NULL; NC_PRIVKEY_FORMAT privkey_type; const char *privkey_format, *pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; + NC_CHECK_ARG_RET(NULL, ctx, tree_path, privkey_path, certificate_path, config, 1); + /* get the keys as a string from the given files */ ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey, &privkey_type, &pubkey); if (ret) { @@ -116,7 +118,7 @@ nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char goto cleanup; } - ret = _nc_server_config_new_tls_server_certificate(ctx, path, pubkey_path, privkey_path, + ret = _nc_server_config_new_tls_server_certificate(ctx, path, privkey_path, pubkey_path, certificate_path, config); if (ret) { ERR(NULL, "Creating new TLS server certificate YANG data failed."); @@ -144,8 +146,7 @@ nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const c int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, privkey_path, certificate_path, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, privkey_path, certificate_path, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" @@ -156,7 +157,7 @@ nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const c goto cleanup; } - ret = _nc_server_config_new_tls_server_certificate(ctx, path, pubkey_path, privkey_path, + ret = _nc_server_config_new_tls_server_certificate(ctx, path, privkey_path, pubkey_path, certificate_path, config); if (ret) { ERR(NULL, "Creating new CH TLS server certificate YANG data failed."); @@ -250,8 +251,7 @@ nc_server_config_new_ch_tls_keystore_ref(const struct ly_ctx *ctx, const char *c int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, asym_key_ref, cert_ref, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, asym_key_ref, cert_ref, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" "endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate", client_name, endpt_name) == -1) { @@ -289,6 +289,8 @@ _nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const cha int ret = 0; char *cert = NULL; + NC_CHECK_ARG_RET(NULL, ctx, tree_path, cert_path, config, 1); + ret = nc_server_config_new_read_certificate(cert_path, &cert); if (ret) { ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path); @@ -363,8 +365,7 @@ nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, const c int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" @@ -541,8 +542,7 @@ nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char *clie int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, 1); - NC_CHECK_ARG_RET(NULL, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" @@ -679,7 +679,7 @@ nc_config_new_tls_maptype2str(NC_TLS_CTN_MAPTYPE map_type) return "ietf-x509-cert-to-name:common-name"; case NC_TLS_CTN_UNKNOWN: default: - ERR(NULL, "Unknown map_type."); + ERR(NULL, "Unknown CTN mapping type."); return NULL; } } @@ -691,6 +691,8 @@ _nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *tree_path, c int ret = 0; const char *map; + NC_CHECK_ARG_RET(NULL, ctx, tree_path, name, config, 1); + if (fingerprint) { /* optional */ ret = nc_config_new_create_append(ctx, tree_path, "fingerprint", fingerprint, config); @@ -769,7 +771,7 @@ nc_server_config_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *client_nam int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, id, name, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, id, name, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" @@ -782,7 +784,7 @@ nc_server_config_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *client_nam ret = _nc_server_config_new_tls_ctn(ctx, path, fingerprint, map_type, name, config); if (ret) { - ERR(NULL, "Creating new TLS cert-to-name YANG data failed."); + ERR(NULL, "Creating new CH TLS cert-to-name YANG data failed."); goto cleanup; } @@ -835,6 +837,7 @@ nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt_nam NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + /* version to str */ version = nc_config_new_tls_tlsversion2str(tls_version); if (!version) { ret = 1; @@ -861,6 +864,7 @@ nc_server_config_new_ch_tls_version(const struct ly_ctx *ctx, const char *client NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); + /* version to str */ version = nc_config_new_tls_tlsversion2str(tls_version); if (!version) { ret = 1; @@ -871,7 +875,7 @@ nc_server_config_new_ch_tls_version(const struct ly_ctx *ctx, const char *client "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" "hello-params/tls-versions/tls-version", client_name, endpt_name); if (ret) { - ERR(NULL, "Creating new YANG data nodes for Call-Home TLS version failed."); + ERR(NULL, "Creating new YANG data nodes for CH TLS version failed."); goto cleanup; } @@ -887,6 +891,7 @@ nc_server_config_new_tls_del_version(const char *endpt_name, NC_TLS_VERSION tls_ NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + /* version to str */ version = nc_config_new_tls_tlsversion2str(tls_version); if (!version) { ret = 1; @@ -909,6 +914,7 @@ nc_server_config_new_ch_tls_del_version(const char *client_name, const char *end NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + /* version to str */ version = nc_config_new_tls_tlsversion2str(tls_version); if (!version) { ret = 1; @@ -931,6 +937,8 @@ _nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *tree_pat struct lyd_node *old = NULL; char *cipher = NULL, *cipher_ident = NULL; + NC_CHECK_ARG_RET(NULL, ctx, tree_path, config, 1); + /* delete all older algorithms (if any) se they can be replaced by the new ones */ lyd_find_path(*config, tree_path, 0, &old); if (old) { @@ -940,8 +948,7 @@ _nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *tree_pat for (i = 0; i < cipher_count; i++) { cipher = va_arg(ap, char *); - ret = asprintf(&cipher_ident, "iana-tls-cipher-suite-algs:%s", cipher); - if (ret == -1) { + if (asprintf(&cipher_ident, "iana-tls-cipher-suite-algs:%s", cipher) == -1) { ERRMEM; ret = 1; goto cleanup; @@ -949,6 +956,7 @@ _nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *tree_pat ret = nc_config_new_create_append(ctx, tree_path, "cipher-suite", cipher_ident, config); if (ret) { + free(cipher_ident); goto cleanup; } @@ -983,6 +991,7 @@ nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_nam ret = _nc_server_config_new_tls_ciphers(ctx, path, cipher_count, ap, config); if (ret) { ERR(NULL, "Creating new TLS cipher YANG data nodes failed."); + goto cleanup; } cleanup: @@ -1014,6 +1023,7 @@ nc_server_config_new_ch_tls_ciphers(const struct ly_ctx *ctx, const char *client ret = _nc_server_config_new_tls_ciphers(ctx, path, cipher_count, ap, config); if (ret) { ERR(NULL, "Creating new Call-Home TLS cipher YANG data nodes failed."); + goto cleanup; } cleanup: @@ -1048,42 +1058,26 @@ _nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *tree_pa const char *crl_path, struct lyd_node **config) { int ret = 0; - struct lyd_node *node = NULL; - char *url_path = NULL, *ext_path = NULL; - if (asprintf(&url_path, "%s/libnetconf2-netconf-server:crl-url", tree_path) == -1) { - ERRMEM; - url_path = NULL; - ret = 1; - goto cleanup; - } + NC_CHECK_ARG_RET(NULL, ctx, tree_path, crl_path, config, 1); - if (asprintf(&ext_path, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path) == -1) { - ERRMEM; - ext_path = NULL; - ret = 1; + /* create the crl path node */ + ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-path", crl_path, config); + if (ret) { goto cleanup; } /* delete other choice nodes if they are present */ - ret = lyd_find_path(*config, url_path, 0, &node); - if (!ret) { - lyd_free_tree(node); - } - ret = lyd_find_path(*config, ext_path, 0, &node); - if (!ret) { - lyd_free_tree(node); + ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-url", tree_path); + if (ret) { + goto cleanup; } - - /* create the crl path node */ - ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-path", crl_path, config); + ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path); if (ret) { goto cleanup; } cleanup: - free(url_path); - free(ext_path); return ret; } @@ -1135,7 +1129,7 @@ nc_server_config_new_ch_tls_crl_path(const struct ly_ctx *ctx, const char *clien ret = _nc_server_config_new_tls_crl_path(ctx, path, crl_path, config); if (ret) { - ERR(NULL, "Creating new Call-Home CRL YANG data nodes failed."); + ERR(NULL, "Creating new CH CRL YANG data nodes failed."); goto cleanup; } @@ -1149,42 +1143,26 @@ _nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *tree_pat const char *crl_url, struct lyd_node **config) { int ret = 0; - struct lyd_node *node = NULL; - char *crl_path = NULL, *ext_path = NULL; - if (asprintf(&crl_path, "%s/libnetconf2-netconf-server:crl-path", tree_path) == -1) { - ERRMEM; - crl_path = NULL; - ret = 1; - goto cleanup; - } + NC_CHECK_ARG_RET(NULL, ctx, tree_path, crl_url, config, 1); - if (asprintf(&ext_path, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path) == -1) { - ERRMEM; - ext_path = NULL; - ret = 1; + /* create the crl path node */ + ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-url", crl_url, config); + if (ret) { goto cleanup; } /* delete other choice nodes if they are present */ - ret = lyd_find_path(*config, crl_path, 0, &node); - if (!ret) { - lyd_free_tree(node); - } - ret = lyd_find_path(*config, ext_path, 0, &node); - if (!ret) { - lyd_free_tree(node); + ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-path", tree_path); + if (ret) { + goto cleanup; } - - /* create the crl path node */ - ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-url", crl_url, config); + ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path); if (ret) { goto cleanup; } cleanup: - free(crl_path); - free(ext_path); return ret; } @@ -1235,7 +1213,7 @@ nc_server_config_new_ch_tls_crl_url(const struct ly_ctx *ctx, const char *client ret = _nc_server_config_new_tls_crl_url(ctx, path, crl_url, config); if (ret) { - ERR(NULL, "Creating new Call-Home CRL YANG data nodes failed."); + ERR(NULL, "Creating new CH CRL YANG data nodes failed."); goto cleanup; } @@ -1248,42 +1226,26 @@ static int _nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *tree_path, struct lyd_node **config) { int ret = 0; - struct lyd_node *node = NULL; - char *crl_path = NULL, *url_path = NULL; - if (asprintf(&crl_path, "%s/libnetconf2-netconf-server:crl-path", tree_path) == -1) { - ERRMEM; - crl_path = NULL; - ret = 1; - goto cleanup; - } + NC_CHECK_ARG_RET(NULL, ctx, tree_path, config, 1); - if (asprintf(&url_path, "%s/libnetconf2-netconf-server:crl-url", tree_path) == -1) { - ERRMEM; - url_path = NULL; - ret = 1; + /* create the crl path node */ + ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-cert-ext", NULL, config); + if (ret) { goto cleanup; } /* delete other choice nodes if they are present */ - ret = lyd_find_path(*config, crl_path, 0, &node); - if (!ret) { - lyd_free_tree(node); - } - ret = lyd_find_path(*config, url_path, 0, &node); - if (!ret) { - lyd_free_tree(node); + ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-path", tree_path); + if (ret) { + goto cleanup; } - - /* create the crl path node */ - ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-cert-ext", NULL, config); + ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-url", tree_path); if (ret) { goto cleanup; } cleanup: - free(crl_path); - free(url_path); return ret; } @@ -1334,7 +1296,7 @@ nc_server_config_new_ch_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *c ret = _nc_server_config_new_tls_crl_cert_ext(ctx, path, config); if (ret) { - ERR(NULL, "Creating new Call-Home CRL YANG data nodes failed."); + ERR(NULL, "Creating new CH CRL YANG data nodes failed."); goto cleanup; } diff --git a/tests/test_crl.c b/tests/test_crl.c index 253f45c0..213792b2 100644 --- a/tests/test_crl.c +++ b/tests/test_crl.c @@ -181,6 +181,11 @@ setup_f(void **state) ret = nc_server_config_new_tls_crl_path(ctx, "endpt", TESTS_DIR "/data/crl.pem", &tree); assert_int_equal(ret, 0); + /* check if the choice node was removed */ + ret = lyd_find_path(tree, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-url", 0, NULL); + assert_int_not_equal(ret, 0); + /* configure the server based on the data */ ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); From dadee5260939ab18013cda06718c93b40f9d1408 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 6 Oct 2023 10:20:31 +0200 Subject: [PATCH 082/134] server_config REFACTOR rename client_auth struct --- src/server_config.c | 37 ++++++++++++++++++++++--------------- src/session_p.h | 6 +++--- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index f6165846..f15792a1 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -659,14 +659,14 @@ nc_server_config_del_local_address(struct nc_bind *bind) } static void -nc_server_config_del_auth_client_pam_name(struct nc_client_auth *auth_client) +nc_server_config_del_auth_client_pam_name(struct nc_auth_client *auth_client) { free(auth_client->pam_config_name); auth_client->pam_config_name = NULL; } static void -nc_server_config_del_auth_client_pam_dir(struct nc_client_auth *auth_client) +nc_server_config_del_auth_client_pam_dir(struct nc_auth_client *auth_client) { free(auth_client->pam_config_dir); auth_client->pam_config_dir = NULL; @@ -715,7 +715,7 @@ nc_server_config_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey) } static void -nc_server_config_del_auth_client_password(struct nc_client_auth *auth_client) +nc_server_config_del_auth_client_password(struct nc_auth_client *auth_client) { free(auth_client->password); auth_client->password = NULL; @@ -779,7 +779,7 @@ nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey } static void -nc_server_config_del_auth_client_pubkey(struct nc_client_auth *auth_client, struct nc_public_key *pubkey) +nc_server_config_del_auth_client_pubkey(struct nc_auth_client *auth_client, struct nc_public_key *pubkey) { nc_server_config_del_auth_client_pubkey_name(pubkey); nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); @@ -794,7 +794,7 @@ nc_server_config_del_auth_client_pubkey(struct nc_client_auth *auth_client, stru } static void -nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_client_auth *auth_client) +nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_auth_client *auth_client) { uint16_t i, pubkey_count; @@ -2074,7 +2074,7 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_config_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_client_auth *auth_client) +nc_server_config_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_auth_client *auth_client) { assert(!strcmp(LYD_NAME(node), "public-key")); @@ -2131,7 +2131,7 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_hostkey *hostkey; - struct nc_client_auth *auth_client; + struct nc_auth_client *auth_client; struct nc_public_key *pubkey; struct nc_server_tls_opts *opts; struct nc_ch_client *ch_client; @@ -2140,6 +2140,7 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2443,7 +2444,7 @@ static int nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_client_auth *auth_client; + struct nc_auth_client *auth_client; struct nc_server_ssh_opts *opts; struct nc_ch_client *ch_client; @@ -2451,6 +2452,7 @@ nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2544,7 +2546,7 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) } static int -nc_server_config_ssh_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth) +nc_server_config_ssh_replace_truststore_reference(const struct lyd_node *node, struct nc_auth_client *client_auth) { uint16_t i; struct nc_truststore *ts = &server_opts.truststore; @@ -2603,13 +2605,14 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION { int ret = 0; struct nc_endpt *endpt; - struct nc_client_auth *auth_client; + struct nc_auth_client *auth_client; struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "truststore-reference")); /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2675,7 +2678,7 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION } static int -nc_server_config_replace_password(const struct lyd_node *node, struct nc_client_auth *auth_client) +nc_server_config_replace_password(const struct lyd_node *node, struct nc_auth_client *auth_client) { nc_server_config_del_auth_client_password(auth_client); @@ -2693,13 +2696,14 @@ static int nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_client_auth *auth_client; + struct nc_auth_client *auth_client; struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "password")); /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2729,13 +2733,14 @@ static int nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_client_auth *auth_client; + struct nc_auth_client *auth_client; struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "pam-config-file-name")); /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2769,13 +2774,14 @@ static int nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_client_auth *auth_client; + struct nc_auth_client *auth_client; struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "pam-config-file-dir")); /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2809,13 +2815,14 @@ static int nc_server_config_none(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_client_auth *auth_client; + struct nc_auth_client *auth_client; struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "none")); /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } diff --git a/src/session_p.h b/src/session_p.h index becd266b..a7fd8aa8 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -160,10 +160,10 @@ struct nc_auth_state { /** * @brief A server's authorized client. */ -struct nc_client_auth { +struct nc_auth_client { char *username; /**< Arbitrary username. */ - NC_STORE_TYPE store; /**< Specifies how/where the client's public key is stored. */ + NC_STORE_TYPE store; /**< Specifies how/where the client's public key is stored. */ union { struct { struct nc_public_key *pubkeys; /**< The client's public keys. */ @@ -198,7 +198,7 @@ struct nc_server_ssh_opts { struct nc_hostkey *hostkeys; /**< Server's hostkeys. */ uint16_t hostkey_count; /**< Number of server's hostkeys. */ - struct nc_client_auth *auth_clients; /**< Server's authorized clients. */ + struct nc_auth_client *auth_clients; /**< Server's authorized clients. */ uint16_t client_count; /**< Number of server's authorized clients. */ struct nc_endpt *endpt_client_ref; /**< Reference to another endpoint (used for client authentication). */ From e14cd2a17f9a2c231a1f3ec2f4a359ee7bdc6c7b Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 12 Oct 2023 11:28:06 +0200 Subject: [PATCH 083/134] session server UPDATE dynamically search ts and ks --- src/session_p.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/session_p.h b/src/session_p.h index a7fd8aa8..02658ad2 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -169,7 +169,7 @@ struct nc_auth_client { struct nc_public_key *pubkeys; /**< The client's public keys. */ uint16_t pubkey_count; /**< The number of client's public keys. */ }; - struct nc_public_key_bag *ts_ref; /**< Reference to a truststore. */ + char *ts_ref; /**< Name of the referenced truststore key. */ }; char *password; /**< Client's password */ @@ -219,10 +219,10 @@ struct nc_cert_grouping { NC_STORE_TYPE store; /**< Specifies how/where the certificates are stored. */ union { struct { - struct nc_certificate *certs; /**< Local-defined certificates */ - uint16_t cert_count; /**< Certificate count */ + struct nc_certificate *certs; /**< Local-defined certificates. */ + uint16_t cert_count; /**< Certificate count. */ }; - struct nc_certificate_bag *ts_ref; /**< Referenced trustore certificate bag */ + char *ts_ref; /**< Name of the referenced truststore certificate bag. */ }; }; @@ -262,8 +262,8 @@ struct nc_server_tls_opts { }; struct { - struct nc_asymmetric_key *key_ref; /**< Reference to the server's key */ - struct nc_certificate *cert_ref; /**< Reference to the concrete server's certificate */ + char *key_ref; /**< Reference to the server's key */ + char *cert_ref; /**< Reference to the concrete server's certificate */ }; }; From 4f6451484bf5888444c5b89a700901ecc9335225 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 12 Oct 2023 11:28:47 +0200 Subject: [PATCH 084/134] server_config REFACTOR code review --- src/server_config.c | 1258 ++++++++++++++--------------------------- src/server_config.h | 34 +- src/server_config_p.h | 11 +- 3 files changed, 452 insertions(+), 851 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index f15792a1..c5e68e10 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -73,6 +73,7 @@ static const char *supported_mac_algs[] = { extern struct nc_server_opts server_opts; +/* returns true if a node is a part of the listen subtree */ static int is_listen(const struct lyd_node *node) { @@ -88,6 +89,7 @@ is_listen(const struct lyd_node *node) return node != NULL; } +/* returns true if a node is a part of the Call Home subtree */ static int is_ch(const struct lyd_node *node) { @@ -105,6 +107,7 @@ is_ch(const struct lyd_node *node) #ifdef NC_ENABLED_SSH_TLS +/* returns true if a node is a part of the ssh subtree */ static int is_ssh(const struct lyd_node *node) { @@ -120,6 +123,7 @@ is_ssh(const struct lyd_node *node) return node != NULL; } +/* returns true if a node is a part of the tls subtree */ static int is_tls(const struct lyd_node *node) { @@ -137,6 +141,7 @@ is_tls(const struct lyd_node *node) #endif /* NC_ENABLED_SSH_TLS */ +/* gets the endpoint struct (and optionally bind) based on node's location in the YANG data tree */ static int nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind) { @@ -176,6 +181,7 @@ nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, return 1; } +/* gets the ch_client struct based on node's location in the YANG data tree */ static int nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client **ch_client) { @@ -218,8 +224,8 @@ nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client return 1; } -#ifdef NC_ENABLED_SSH_TLS +/* gets the ch_endpt struct based on node's location in the YANG data tree */ static int nc_server_config_get_ch_endpt(const struct lyd_node *node, struct nc_ch_endpt **ch_endpt) { @@ -250,17 +256,26 @@ nc_server_config_get_ch_endpt(const struct lyd_node *node, struct nc_ch_endpt ** assert(!strcmp(LYD_NAME(node), "name")); name = lyd_get_value(node); + /* LOCK */ + pthread_rwlock_rdlock(&server_opts.ch_client_lock); for (i = 0; i < ch_client->ch_endpt_count; i++) { if (!strcmp(ch_client->ch_endpts[i].name, name)) { *ch_endpt = &ch_client->ch_endpts[i]; + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_client_lock); return 0; } } + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_client_lock); ERR(NULL, "Call-home client's \"%s\" endpoint \"%s\" was not found.", ch_client->name, name); return 1; } +#ifdef NC_ENABLED_SSH_TLS + +/* gets the ssh_opts struct based on node's location in the YANG data tree */ static int nc_server_config_get_ssh_opts(const struct lyd_node *node, struct nc_server_ssh_opts **opts) { @@ -284,6 +299,7 @@ nc_server_config_get_ssh_opts(const struct lyd_node *node, struct nc_server_ssh_ return 0; } +/* gets the hostkey struct based on node's location in the YANG data tree */ static int nc_server_config_get_hostkey(const struct lyd_node *node, struct nc_hostkey **hostkey) { @@ -324,8 +340,9 @@ nc_server_config_get_hostkey(const struct lyd_node *node, struct nc_hostkey **ho return 1; } +/* gets the client_auth struct based on node's location in the YANG data tree */ static int -nc_server_config_get_auth_client(const struct lyd_node *node, struct nc_client_auth **auth_client) +nc_server_config_get_auth_client(const struct lyd_node *node, struct nc_auth_client **auth_client) { uint16_t i; const char *name; @@ -364,12 +381,13 @@ nc_server_config_get_auth_client(const struct lyd_node *node, struct nc_client_a return 1; } +/* gets the pubkey struct based on node's location in the YANG data tree */ static int nc_server_config_get_pubkey(const struct lyd_node *node, struct nc_public_key **pubkey) { uint16_t i; const char *name; - struct nc_client_auth *auth_client; + struct nc_auth_client *auth_client; assert(node && pubkey); name = LYD_NAME(node); @@ -405,6 +423,7 @@ nc_server_config_get_pubkey(const struct lyd_node *node, struct nc_public_key ** return 1; } +/* gets the tls_opts struct based on node's location in the YANG data tree */ static int nc_server_config_get_tls_opts(const struct lyd_node *node, struct nc_server_tls_opts **opts) { @@ -428,37 +447,58 @@ nc_server_config_get_tls_opts(const struct lyd_node *node, struct nc_server_tls_ return 0; } +/* gets the cert struct based on node's location in the YANG data tree */ static int -nc_server_config_get_cert(const struct lyd_node *node, int is_ee, struct nc_certificate **cert) +nc_server_config_get_cert(const struct lyd_node *node, struct nc_certificate **cert) { uint16_t i; const char *name; struct nc_cert_grouping *auth_client; struct nc_server_tls_opts *opts; + int is_cert_end_entity; + struct lyd_node *name_node; assert(node && cert); name = LYD_NAME(node); + /* check if node is in certificate subtree */ while (node) { if (!strcmp(LYD_NAME(node), "certificate")) { break; } node = lyd_parent(node); } - if (!node) { ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", name); return 1; } - node = lyd_child(node); - assert(!strcmp(LYD_NAME(node), "name")); - name = lyd_get_value(node); + /* it's child should be the list's key, check later */ + name_node = lyd_child(node); + + /* it's in certificate node, now check if it's end entity or certificate authority */ + while (node) { + if (!strcmp(LYD_NAME(node), "ee-certs")) { + is_cert_end_entity = 1; + break; + } else if (!strcmp(LYD_NAME(node), "ca-certs")) { + is_cert_end_entity = 0; + break; + } + node = lyd_parent(node); + } + if (!node) { + ERR(NULL, "Node \"%s\" is not contained in ee-certs nor ca-certs subtree.", name); + return 1; + } + + assert(!strcmp(LYD_NAME(name_node), "name")); + name = lyd_get_value(name_node); if (nc_server_config_get_tls_opts(node, &opts)) { return 1; } - if (is_ee) { + if (is_cert_end_entity) { auth_client = &opts->ee_certs; } else { auth_client = &opts->ca_certs; @@ -475,6 +515,7 @@ nc_server_config_get_cert(const struct lyd_node *node, int is_ee, struct nc_cert return 1; } +/* gets the ctn struct based on node's location in the YANG data tree */ static int nc_server_config_get_ctn(const struct lyd_node *node, struct nc_ctn **ctn) { @@ -540,6 +581,7 @@ nc_server_config_get_private_key_type(const char *format) #endif /* NC_ENABLED_SSH_TLS */ +/* gets the ch_client struct based on node's location in the YANG data tree and locks it for reading */ static int nc_server_config_get_ch_client_with_lock(const struct lyd_node *node, struct nc_ch_client **ch_client) { @@ -576,6 +618,8 @@ nc_server_config_get_ch_client_with_lock(const struct lyd_node *node, struct nc_ } } + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_client_lock); ERR(NULL, "Call-home client \"%s\" was not found.", name); return 1; } @@ -594,7 +638,7 @@ equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char { uint16_t i; - assert(node && parent_count > 0 && parent_name); + assert(node && parent_count && parent_name); node = lyd_parent(node); for (i = 1; i < parent_count; i++) { @@ -642,138 +686,27 @@ nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_ return ret; } -static void -nc_server_config_del_endpt_name(struct nc_endpt *endpt) -{ - free(endpt->name); - endpt->name = NULL; -} - #ifdef NC_ENABLED_SSH_TLS -static void -nc_server_config_del_local_address(struct nc_bind *bind) -{ - free(bind->address); - bind->address = NULL; -} - -static void -nc_server_config_del_auth_client_pam_name(struct nc_auth_client *auth_client) -{ - free(auth_client->pam_config_name); - auth_client->pam_config_name = NULL; -} - -static void -nc_server_config_del_auth_client_pam_dir(struct nc_auth_client *auth_client) -{ - free(auth_client->pam_config_dir); - auth_client->pam_config_dir = NULL; -} - -static void -nc_server_config_del_endpt_reference(struct nc_endpt *endpt) -{ - free(endpt->referenced_endpt_name); - endpt->referenced_endpt_name = NULL; -} - -static void -nc_server_config_del_hostkey_name(struct nc_hostkey *hostkey) -{ - free(hostkey->name); - hostkey->name = NULL; -} - -static void -nc_server_config_del_public_key(struct nc_hostkey *hostkey) -{ - free(hostkey->key.pubkey_data); - hostkey->key.pubkey_data = NULL; -} - -static void -nc_server_config_del_private_key(struct nc_hostkey *hostkey) -{ - free(hostkey->key.privkey_data); - hostkey->key.privkey_data = NULL; -} - -static void -nc_server_config_del_auth_client_pubkey_name(struct nc_public_key *pubkey) -{ - free(pubkey->name); - pubkey->name = NULL; -} - -static void -nc_server_config_del_auth_client_pubkey_pub_base64(struct nc_public_key *pubkey) -{ - free(pubkey->data); - pubkey->data = NULL; -} - -static void -nc_server_config_del_auth_client_password(struct nc_auth_client *auth_client) -{ - free(auth_client->password); - auth_client->password = NULL; -} - -static void -nc_server_config_del_hostkey_algs(struct nc_server_ssh_opts *opts) -{ - free(opts->hostkey_algs); - opts->hostkey_algs = NULL; -} - -static void -nc_server_config_del_kex_algs(struct nc_server_ssh_opts *opts) -{ - free(opts->kex_algs); - opts->kex_algs = NULL; -} - -static void -nc_server_config_del_encryption_algs(struct nc_server_ssh_opts *opts) -{ - free(opts->encryption_algs); - opts->encryption_algs = NULL; -} - -static void -nc_server_config_del_mac_algs(struct nc_server_ssh_opts *opts) -{ - free(opts->mac_algs); - opts->mac_algs = NULL; -} - -static void -nc_server_config_del_keystore_reference(struct nc_hostkey *hostkey) -{ - free(hostkey->ks_ref); - hostkey->ks_ref = NULL; -} - static void nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey *hostkey) { assert(hostkey->store == NC_STORE_LOCAL || hostkey->store == NC_STORE_KEYSTORE); + free(hostkey->name); + if (hostkey->store == NC_STORE_LOCAL) { - nc_server_config_del_public_key(hostkey); - nc_server_config_del_private_key(hostkey); + free(hostkey->key.pubkey_data); + free(hostkey->key.privkey_data); } else { - nc_server_config_del_keystore_reference(hostkey); + free(hostkey->ks_ref); } - nc_server_config_del_hostkey_name(hostkey); opts->hostkey_count--; if (!opts->hostkey_count) { free(opts->hostkeys); opts->hostkeys = NULL; - } else if (hostkey == &opts->hostkeys[opts->hostkey_count + 1]) { + } else if (hostkey != &opts->hostkeys[opts->hostkey_count]) { memcpy(hostkey, &opts->hostkeys[opts->hostkey_count], sizeof *opts->hostkeys); } } @@ -781,14 +714,14 @@ nc_server_config_del_hostkey(struct nc_server_ssh_opts *opts, struct nc_hostkey static void nc_server_config_del_auth_client_pubkey(struct nc_auth_client *auth_client, struct nc_public_key *pubkey) { - nc_server_config_del_auth_client_pubkey_name(pubkey); - nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); + free(pubkey->name); + free(pubkey->data); auth_client->pubkey_count--; if (!auth_client->pubkey_count) { free(auth_client->pubkeys); auth_client->pubkeys = NULL; - } else if (pubkey == &auth_client->pubkeys[auth_client->pubkey_count + 1]) { + } else if (pubkey != &auth_client->pubkeys[auth_client->pubkey_count]) { memcpy(pubkey, &auth_client->pubkeys[auth_client->pubkey_count], sizeof *auth_client->pubkeys); } } @@ -799,34 +732,35 @@ nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_auth uint16_t i, pubkey_count; free(auth_client->username); - auth_client->username = NULL; if (auth_client->store == NC_STORE_LOCAL) { pubkey_count = auth_client->pubkey_count; for (i = 0; i < pubkey_count; i++) { nc_server_config_del_auth_client_pubkey(auth_client, &auth_client->pubkeys[i]); } + } else { + free(auth_client->ts_ref); } - nc_server_config_del_auth_client_password(auth_client); - nc_server_config_del_auth_client_pam_name(auth_client); - nc_server_config_del_auth_client_pam_dir(auth_client); + free(auth_client->password); + free(auth_client->pam_config_name); + free(auth_client->pam_config_dir); opts->client_count--; if (!opts->client_count) { free(opts->auth_clients); opts->auth_clients = NULL; - } else if (auth_client == &opts->auth_clients[opts->client_count + 1]) { + } else if (auth_client != &opts->auth_clients[opts->client_count]) { memcpy(auth_client, &opts->auth_clients[opts->client_count], sizeof *opts->auth_clients); } } static void -nc_server_config_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts) +nc_server_config_del_ssh_opts(struct nc_bind *bind, struct nc_server_ssh_opts *opts) { uint16_t i, hostkey_count, client_count; - nc_server_config_del_local_address(bind); + free(bind->address); if (bind->sock > -1) { close(bind->sock); } @@ -842,21 +776,20 @@ nc_server_config_del_ssh(struct nc_bind *bind, struct nc_server_ssh_opts *opts) nc_server_config_del_auth_client(opts, &opts->auth_clients[i]); } - nc_server_config_del_hostkey_algs(opts); - nc_server_config_del_kex_algs(opts); - nc_server_config_del_encryption_algs(opts); - nc_server_config_del_mac_algs(opts); + free(opts->hostkey_algs); + free(opts->kex_algs); + free(opts->encryption_algs); + free(opts->mac_algs); free(opts); - opts = NULL; } void nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) { - nc_server_config_del_endpt_name(endpt); - nc_server_config_del_endpt_reference(endpt); - nc_server_config_del_ssh(bind, endpt->opts.ssh); + free(endpt->name); + free(endpt->referenced_endpt_name); + nc_server_config_del_ssh_opts(bind, endpt->opts.ssh); server_opts.endpt_count--; if (!server_opts.endpt_count) { @@ -864,7 +797,7 @@ nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) free(server_opts.binds); server_opts.endpts = NULL; server_opts.binds = NULL; - } else if (endpt == &server_opts.endpts[server_opts.endpt_count + 1]) { + } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) { memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts); memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds); } @@ -873,7 +806,7 @@ nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) #endif /* NC_ENABLED_SSH_TLS */ void -nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts) +nc_server_config_del_unix_socket_opts(struct nc_bind *bind, struct nc_server_unix_opts *opts) { if (bind->sock > -1) { close(bind->sock); @@ -889,8 +822,8 @@ nc_server_config_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opt void nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind) { - nc_server_config_del_endpt_name(endpt); - nc_server_config_del_unix_socket(bind, endpt->opts.unixsock); + free(endpt->name); + nc_server_config_del_unix_socket_opts(bind, endpt->opts.unixsock); server_opts.endpt_count--; if (!server_opts.endpt_count) { @@ -898,7 +831,7 @@ nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *b free(server_opts.binds); server_opts.endpts = NULL; server_opts.binds = NULL; - } else if (endpt == &server_opts.endpts[server_opts.endpt_count + 1]) { + } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) { memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts); memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds); } @@ -906,90 +839,35 @@ nc_server_config_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *b #ifdef NC_ENABLED_SSH_TLS -static void -nc_server_config_del_url(struct nc_server_tls_opts *opts) -{ - free(opts->crl_url); - opts->crl_url = NULL; -} - -static void -nc_server_config_del_path(struct nc_server_tls_opts *opts) -{ - free(opts->crl_path); - opts->crl_path = NULL; -} - -static void -nc_server_config_tls_del_ciphers(struct nc_server_tls_opts *opts) -{ - free(opts->ciphers); - opts->ciphers = NULL; -} - -static void -nc_server_config_tls_del_public_key(struct nc_server_tls_opts *opts) -{ - free(opts->pubkey_data); - opts->pubkey_data = NULL; -} - -static void -nc_server_config_tls_del_cleartext_private_key(struct nc_server_tls_opts *opts) -{ - free(opts->privkey_data); - opts->privkey_data = NULL; -} - -static void -nc_server_config_tls_del_cert_data(struct nc_server_tls_opts *opts) -{ - free(opts->cert_data); - opts->cert_data = NULL; -} - -static void -nc_server_config_tls_del_cert_data_certificate(struct nc_certificate *cert) -{ - free(cert->data); - cert->data = NULL; -} - -static void -nc_server_config_del_fingerprint(struct nc_ctn *ctn) -{ - free(ctn->fingerprint); - ctn->fingerprint = NULL; -} - static void nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert) { free(cert->name); - cert->name = NULL; - free(cert->data); - cert->data = NULL; certs->cert_count--; if (!certs->cert_count) { free(certs->certs); certs->certs = NULL; - } else if (cert == &certs->certs[certs->cert_count + 1]) { + } else if (cert != &certs->certs[certs->cert_count]) { memcpy(cert, &certs->certs[certs->cert_count], sizeof *certs->certs); } } static void -nc_server_config_tls_del_certs(struct nc_cert_grouping *ca) +nc_server_config_del_certs(struct nc_cert_grouping *certs_grp) { - uint16_t i, cert_count; + uint16_t i; - if (ca->store == NC_STORE_LOCAL) { - cert_count = ca->cert_count; - for (i = 0; i < cert_count; i++) { - nc_server_config_del_cert(ca, &ca->certs[i]); + if (certs_grp->store == NC_STORE_LOCAL) { + for (i = 0; i < certs_grp->cert_count; i++) { + free(certs_grp->certs[i].name); + free(certs_grp->certs[i].data); } + free(certs_grp->certs); + certs_grp->certs = NULL; + } else { + free(certs_grp->ts_ref); } } @@ -998,11 +876,8 @@ nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn) { struct nc_ctn *iter; - free(ctn->fingerprint); - ctn->fingerprint = NULL; - free(ctn->name); - ctn->name = NULL; + free(ctn->fingerprint); if (opts->ctn == ctn) { /* it's the first in the list */ @@ -1025,15 +900,15 @@ nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn) } static void -nc_server_config_tls_del_ctns(struct nc_server_tls_opts *opts) +nc_server_config_del_ctns(struct nc_server_tls_opts *opts) { struct nc_ctn *cur, *next; cur = opts->ctn; while (cur) { next = cur->next; - free(cur->fingerprint); free(cur->name); + free(cur->fingerprint); free(cur); cur = next; } @@ -1041,39 +916,41 @@ nc_server_config_tls_del_ctns(struct nc_server_tls_opts *opts) } static void -nc_server_config_del_tls(struct nc_bind *bind, struct nc_server_tls_opts *opts) +nc_server_config_del_tls_opts(struct nc_bind *bind, struct nc_server_tls_opts *opts) { - nc_server_config_del_local_address(bind); + free(bind->address); if (bind->sock > -1) { close(bind->sock); } if (opts->store == NC_STORE_LOCAL) { - nc_server_config_tls_del_public_key(opts); - nc_server_config_tls_del_cleartext_private_key(opts); - nc_server_config_tls_del_cert_data(opts); + free(opts->pubkey_data); + free(opts->privkey_data); + free(opts->cert_data); + } else { + free(opts->key_ref); + free(opts->cert_ref); } - nc_server_config_tls_del_certs(&opts->ca_certs); - nc_server_config_tls_del_certs(&opts->ee_certs); + nc_server_config_del_certs(&opts->ca_certs); + nc_server_config_del_certs(&opts->ee_certs); - nc_server_config_del_path(opts); - nc_server_config_del_url(opts); + free(opts->crl_path); + free(opts->crl_url); X509_STORE_free(opts->crl_store); - opts->crl_store = NULL; - - nc_server_config_tls_del_ctns(opts); - nc_server_config_tls_del_ciphers(opts); + nc_server_config_del_ctns(opts); + free(opts->ciphers); free(opts); } static void nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind) { - nc_server_config_del_endpt_name(endpt); - nc_server_config_del_endpt_reference(endpt); - nc_server_config_del_tls(bind, endpt->opts.tls); + free(endpt->name); + free(endpt->referenced_endpt_name); + + nc_server_config_del_tls_opts(bind, endpt->opts.tls); server_opts.endpt_count--; if (!server_opts.endpt_count) { @@ -1081,24 +958,17 @@ nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind) free(server_opts.binds); server_opts.endpts = NULL; server_opts.binds = NULL; - } else if (endpt == &server_opts.endpts[server_opts.endpt_count + 1]) { + } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) { memcpy(endpt, &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts); memcpy(bind, &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds); } } -static void -nc_server_config_del_remote_address(struct nc_ch_endpt *ch_endpt) -{ - free(ch_endpt->address); - ch_endpt->address = NULL; -} - #endif /* NC_ENABLED_SSH_TLS */ /* presence container */ int -nc_server_config_listen(struct lyd_node *node, NC_OPERATION op) +nc_server_config_listen(const struct lyd_node *node, NC_OPERATION op) { uint16_t i, endpt_count; @@ -1135,7 +1005,7 @@ nc_server_config_listen(struct lyd_node *node, NC_OPERATION op) #ifdef NC_ENABLED_SSH_TLS static void -nc_server_config_ch_del_ssh(struct nc_server_ssh_opts *opts) +nc_server_config_ch_del_ssh_opts(struct nc_server_ssh_opts *opts) { uint16_t i, hostkey_count, client_count; @@ -1150,55 +1020,44 @@ nc_server_config_ch_del_ssh(struct nc_server_ssh_opts *opts) nc_server_config_del_auth_client(opts, &opts->auth_clients[i]); } - nc_server_config_del_hostkey_algs(opts); - nc_server_config_del_kex_algs(opts); - nc_server_config_del_encryption_algs(opts); - nc_server_config_del_mac_algs(opts); + free(opts->hostkey_algs); + free(opts->kex_algs); + free(opts->encryption_algs); + free(opts->mac_algs); free(opts); - opts = NULL; } static void -nc_server_config_ch_del_tls(struct nc_server_tls_opts *opts) +nc_server_config_ch_del_tls_opts(struct nc_server_tls_opts *opts) { if (opts->store == NC_STORE_LOCAL) { - nc_server_config_tls_del_public_key(opts); - nc_server_config_tls_del_cleartext_private_key(opts); - nc_server_config_tls_del_cert_data(opts); + free(opts->pubkey_data); + free(opts->privkey_data); + free(opts->cert_data); } - nc_server_config_tls_del_certs(&opts->ca_certs); - nc_server_config_tls_del_certs(&opts->ee_certs); + nc_server_config_del_certs(&opts->ca_certs); + nc_server_config_del_certs(&opts->ee_certs); - nc_server_config_del_path(opts); - nc_server_config_del_url(opts); + free(opts->crl_path); + free(opts->crl_url); X509_STORE_free(opts->crl_store); - opts->crl_store = NULL; - - nc_server_config_tls_del_ctns(opts); - nc_server_config_tls_del_ciphers(opts); + nc_server_config_del_ctns(opts); + free(opts->ciphers); free(opts); } -static void -nc_server_config_ch_del_endpt_address(struct nc_ch_endpt *ch_endpt) -{ - free(ch_endpt->address); - ch_endpt->address = NULL; -} - #endif /* NC_ENABLED_SSH_TLS */ static void nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt) { free(ch_endpt->name); - ch_endpt->name = NULL; #ifdef NC_ENABLED_SSH_TLS - nc_server_config_ch_del_endpt_address(ch_endpt); + free(ch_endpt->address); if (ch_endpt->sock_pending > -1) { close(ch_endpt->sock_pending); ch_endpt->sock_pending = -1; @@ -1208,10 +1067,10 @@ nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt switch (ch_endpt->ti) { #ifdef NC_ENABLED_SSH_TLS case NC_TI_LIBSSH: - nc_server_config_ch_del_ssh(ch_endpt->opts.ssh); + nc_server_config_ch_del_ssh_opts(ch_endpt->opts.ssh); break; case NC_TI_OPENSSL: - nc_server_config_ch_del_tls(ch_endpt->opts.tls); + nc_server_config_ch_del_tls_opts(ch_endpt->opts.tls); break; #endif /* NC_ENABLED_SSH_TLS */ default: @@ -1280,7 +1139,7 @@ nc_server_config_ch_del_client(struct nc_ch_client *ch_client) } } -void +int nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op) { uint16_t i, ch_client_count; @@ -1293,6 +1152,8 @@ nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op) nc_server_config_ch_del_client(&server_opts.ch_clients[i]); } } + + return 0; } /* default leaf */ @@ -1308,11 +1169,12 @@ nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op) server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10); } else { /* default value */ - server_opts.idle_timeout = 3600; + server_opts.idle_timeout = 180; } } else { /* call-home idle timeout */ - if (nc_server_config_get_ch_client(node, &ch_client)) { + if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -1321,6 +1183,8 @@ nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op) } else if (op == NC_OP_DELETE) { ch_client->idle_timeout = 180; } + + nc_ch_client_unlock(ch_client); } return 0; @@ -1376,6 +1240,7 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) int ret = 0; struct nc_endpt *endpt; struct nc_bind *bind; + struct nc_ch_endpt *ch_endpt; struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "endpoint")); @@ -1416,8 +1281,8 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) } else if (is_ch(node)) { /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { - ret = 1; - goto cleanup; + /* to avoid unlock on fail */ + return 1; } if (op == NC_OP_CREATE) { @@ -1428,6 +1293,13 @@ nc_server_config_endpoint(const struct lyd_node *node, NC_OPERATION op) /* init ch sock */ ch_client->ch_endpts[ch_client->ch_endpt_count - 1].sock_pending = -1; + } else if (op == NC_OP_DELETE) { + if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { + ret = 1; + goto cleanup; + } + + nc_server_config_ch_del_endpt(ch_client, ch_endpt); } } @@ -1491,13 +1363,13 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_config_del_ssh(bind, endpt->opts.ssh); + nc_server_config_del_ssh_opts(bind, endpt->opts.ssh); } } else { /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { - ret = 1; - goto cleanup; + /* to avoid unlock on fail */ + return 1; } if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { @@ -1511,7 +1383,7 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_config_ch_del_ssh(ch_endpt->opts.ssh); + nc_server_config_ch_del_ssh_opts(ch_endpt->opts.ssh); } } @@ -1572,13 +1444,13 @@ nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_config_del_tls(bind, endpt->opts.tls); + nc_server_config_del_tls_opts(bind, endpt->opts.tls); } } else { /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { - ret = 1; - goto cleanup; + /* to avoid unlock on fail */ + return 1; } if (nc_server_config_get_ch_endpt(node, &ch_endpt)) { @@ -1591,6 +1463,8 @@ nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op) if (ret) { goto cleanup; } + } else if (op == NC_OP_DELETE) { + nc_server_config_ch_del_tls_opts(ch_endpt->opts.tls); } } @@ -1687,7 +1561,7 @@ nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } - nc_server_config_del_local_address(bind); + free(bind->address); bind->address = strdup(lyd_get_value(node)); if (!bind->address) { ERRMEM; @@ -1768,6 +1642,7 @@ nc_server_config_keepalives(const struct lyd_node *node, NC_OPERATION op) } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -1821,6 +1696,7 @@ nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -1837,7 +1713,7 @@ nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) } cleanup: - if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { + if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { /* UNLOCK */ nc_ch_client_unlock(ch_client); } @@ -1874,6 +1750,7 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -1890,7 +1767,7 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) } cleanup: - if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { + if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { /* UNLOCK */ nc_ch_client_unlock(ch_client); } @@ -1927,6 +1804,7 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -1943,7 +1821,7 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) } cleanup: - if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { + if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { /* UNLOCK */ nc_ch_client_unlock(ch_client); } @@ -1978,6 +1856,7 @@ nc_server_config_host_key(const struct lyd_node *node, NC_OPERATION op) if (equal_parent_name(node, 1, "server-identity")) { /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2030,6 +1909,7 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2087,8 +1967,7 @@ nc_server_config_create_auth_key_public_key_list(const struct lyd_node *node, st static int nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey) { - nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); - + free(pubkey->data); pubkey->data = strdup(lyd_get_value(node)); if (!pubkey->data) { ERRMEM; @@ -2101,8 +1980,7 @@ nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, s static int nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey) { - nc_server_config_del_public_key(hostkey); - + free(hostkey->key.pubkey_data); hostkey->key.pubkey_data = strdup(lyd_get_value(node)); if (!hostkey->key.pubkey_data) { ERRMEM; @@ -2115,8 +1993,7 @@ nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct static int nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts) { - nc_server_config_tls_del_public_key(opts); - + free(opts->pubkey_data); opts->pubkey_data = strdup(lyd_get_value(node)); if (!opts->pubkey_data) { ERRMEM; @@ -2209,8 +2086,9 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op) if (ret) { goto cleanup; } - } else { - nc_server_config_del_auth_client_pubkey_pub_base64(pubkey); + } else if (op == NC_OP_DELETE) { + free(pubkey->data); + pubkey->data = NULL; } } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) { /* TLS server-identity */ @@ -2275,6 +2153,7 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2304,32 +2183,6 @@ nc_server_config_private_key_format(const struct lyd_node *node, NC_OPERATION op return ret; } -static int -nc_server_config_replace_cleartext_private_key(const struct lyd_node *node, struct nc_hostkey *hostkey) -{ - nc_server_config_del_private_key(hostkey); - hostkey->key.privkey_data = strdup(lyd_get_value(node)); - if (!hostkey->key.privkey_data) { - ERRMEM; - return 1; - } - - return 0; -} - -static int -nc_server_config_tls_replace_cleartext_private_key(const struct lyd_node *node, struct nc_server_tls_opts *opts) -{ - nc_server_config_tls_del_cleartext_private_key(opts); - opts->privkey_data = strdup(lyd_get_value(node)); - if (!opts->privkey_data) { - ERRMEM; - return 1; - } - - return 0; -} - static int nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION op) { @@ -2342,6 +2195,7 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2353,12 +2207,16 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_replace_cleartext_private_key(node, hostkey); - if (ret) { + free(hostkey->key.privkey_data); + hostkey->key.privkey_data = strdup(lyd_get_value(node)); + if (!hostkey->key.privkey_data) { + ERRMEM; + ret = 1; goto cleanup; } } else { - nc_server_config_del_private_key(hostkey); + free(hostkey->key.privkey_data); + hostkey->key.privkey_data = NULL; } } else if (is_tls(node)) { /* tls */ @@ -2368,12 +2226,16 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_tls_replace_cleartext_private_key(node, opts); - if (ret) { - goto cleanup; + free(opts->privkey_data); + opts->privkey_data = strdup(lyd_get_value(node)); + if (!opts->privkey_data) { + ERRMEM; + ret = 1; + goto cleanup; } } else { - nc_server_config_tls_del_cleartext_private_key(opts); + free(opts->privkey_data); + opts->privkey_data = NULL; } } @@ -2397,6 +2259,7 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2410,14 +2273,15 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op /* set to keystore */ hostkey->store = NC_STORE_KEYSTORE; - nc_server_config_del_keystore_reference(hostkey); + free(hostkey->ks_ref); hostkey->ks_ref = strdup(lyd_get_value(node)); if (!hostkey->ks_ref) { ERRMEM; ret = 1; goto cleanup; } - } else { + } else if (op == NC_OP_DELETE) { + free(hostkey->ks_ref); hostkey->ks_ref = NULL; } } @@ -2431,7 +2295,7 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op } static int -nc_server_config_create_user(const struct lyd_node *node, struct nc_server_ssh_opts *opts) +nc_server_config_create_auth_client(const struct lyd_node *node, struct nc_server_ssh_opts *opts) { node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "name")); @@ -2462,7 +2326,7 @@ nc_server_config_user(const struct lyd_node *node, NC_OPERATION op) } if (op == NC_OP_CREATE) { - ret = nc_server_config_create_user(node, opts); + ret = nc_server_config_create_auth_client(node, opts); if (ret) { goto cleanup; } @@ -2494,6 +2358,7 @@ nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2525,6 +2390,7 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2545,68 +2411,15 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) return ret; } -static int -nc_server_config_ssh_replace_truststore_reference(const struct lyd_node *node, struct nc_auth_client *client_auth) -{ - uint16_t i; - struct nc_truststore *ts = &server_opts.truststore; - - /* lookup name */ - for (i = 0; i < ts->pub_bag_count; i++) { - if (!strcmp(lyd_get_value(node), ts->pub_bags[i].name)) { - break; - } - } - - if (i == ts->pub_bag_count) { - ERR(NULL, "Public-key bag \"%s\" not found in truststore.", lyd_get_value(node)); - return 1; - } - - client_auth->ts_ref = &ts->pub_bags[i]; - - /* check if any of the referenced public keys is SubjectPublicKeyInfo */ - for (i = 0; i < client_auth->ts_ref->pubkey_count; i++) { - if (nc_is_pk_subject_public_key_info(client_auth->ts_ref->pubkeys[i].data)) { - ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!"); - return 1; - } - } - - return 0; -} - -static int -nc_server_config_tls_replace_truststore_reference(const struct lyd_node *node, struct nc_cert_grouping *auth_client) -{ - uint16_t i; - struct nc_truststore *ts = &server_opts.truststore; - - /* lookup name */ - for (i = 0; i < ts->cert_bag_count; i++) { - if (!strcmp(lyd_get_value(node), ts->cert_bags[i].name)) { - break; - } - } - - if (i == ts->cert_bag_count) { - ERR(NULL, "Certificate bag \"%s\" not found in truststore.", lyd_get_value(node)); - return 1; - } - - auth_client->ts_ref = &ts->cert_bags[i]; - - return 0; -} - /* leaf */ static int nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; struct nc_auth_client *auth_client; struct nc_ch_client *ch_client; + struct nc_server_tls_opts *opts; + struct nc_cert_grouping *certs_grp; assert(!strcmp(LYD_NAME(node), "truststore-reference")); @@ -2626,46 +2439,44 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION /* set to truststore */ auth_client->store = NC_STORE_TRUSTSTORE; - ret = nc_server_config_ssh_replace_truststore_reference(node, auth_client); - if (ret) { + free(auth_client->ts_ref); + auth_client->ts_ref = strdup(lyd_get_value(node)); + if (!auth_client->ts_ref) { + ERRMEM; + ret = 1; goto cleanup; } - } else { + } else if (op == NC_OP_DELETE) { + free(auth_client->ts_ref); auth_client->ts_ref = NULL; } - } else if (is_tls(node) && equal_parent_name(node, 1, "ca-certs")) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + } else if (is_tls(node) && (equal_parent_name(node, 1, "ca-certs") || equal_parent_name(node, 1, "ee-certs"))) { + /* ee-certs or ca-certs */ + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to truststore */ - endpt->opts.tls->ca_certs.store = NC_STORE_TRUSTSTORE; - - ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ca_certs); - if (ret) { - goto cleanup; - } + if (equal_parent_name(node, 1, "ca-certs")) { + certs_grp = &opts->ca_certs; } else { - endpt->opts.tls->ca_certs.ts_ref = NULL; - } - } else if (is_tls(node) && equal_parent_name(node, 1, "ee-certs")) { - if (nc_server_config_get_endpt(node, &endpt, NULL)) { - ret = 1; - goto cleanup; + certs_grp = &opts->ee_certs; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to truststore */ - endpt->opts.tls->ee_certs.store = NC_STORE_TRUSTSTORE; + certs_grp->store = NC_STORE_TRUSTSTORE; - ret = nc_server_config_tls_replace_truststore_reference(node, &endpt->opts.tls->ee_certs); - if (ret) { + free(certs_grp->ts_ref); + certs_grp->ts_ref = strdup(lyd_get_value(node)); + if (!certs_grp->ts_ref) { + ERRMEM; + ret = 1; goto cleanup; } - } else { - endpt->opts.tls->ee_certs.ts_ref = NULL; + } else if (op == NC_OP_DELETE) { + free(certs_grp->ts_ref); + certs_grp->ts_ref = NULL; } } @@ -2677,20 +2488,6 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION return ret; } -static int -nc_server_config_replace_password(const struct lyd_node *node, struct nc_auth_client *auth_client) -{ - nc_server_config_del_auth_client_password(auth_client); - - auth_client->password = strdup(lyd_get_value(node)); - if (!auth_client->password) { - ERRMEM; - return 1; - } - - return 0; -} - /* leaf */ static int nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) @@ -2713,12 +2510,16 @@ nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_replace_password(node, auth_client); - if (ret) { + free(auth_client->password); + auth_client->password = strdup(lyd_get_value(node)); + if (!auth_client->password) { + ERRMEM; + ret = 1; goto cleanup; } } else { - nc_server_config_del_auth_client_password(auth_client); + free(auth_client->password); + auth_client->password = NULL; } cleanup: @@ -2750,8 +2551,7 @@ nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_auth_client_pam_name(auth_client); - + free(auth_client->pam_config_name); auth_client->pam_config_name = strdup(lyd_get_value(node)); if (!auth_client->pam_config_name) { ERRMEM; @@ -2759,7 +2559,8 @@ nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else { - nc_server_config_del_auth_client_pam_name(auth_client); + free(auth_client->pam_config_name); + auth_client->pam_config_name = NULL; } cleanup: @@ -2791,7 +2592,7 @@ nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_auth_client_pam_dir(auth_client); + free(auth_client->pam_config_dir); auth_client->pam_config_dir = strdup(lyd_get_value(node)); if (!auth_client->pam_config_dir) { ERRMEM; @@ -2799,7 +2600,8 @@ nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else { - nc_server_config_del_auth_client_pam_dir(auth_client); + free(auth_client->pam_config_dir); + auth_client->pam_config_dir = NULL; } cleanup: @@ -2854,17 +2656,17 @@ nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OP if (!strncmp(algorithm, "openssh-", 8)) { /* if the name starts with openssh, convert it to it's original libssh accepted form */ - asprintf(&alg, "%s@openssh.com", algorithm + 8); - if (!alg) { + if (asprintf(&alg, "%s@openssh.com", algorithm + 8) == -1) { ERRMEM; + alg = NULL; ret = 1; goto cleanup; } } else if (!strncmp(algorithm, "libssh-", 7)) { /* if the name starts with libssh, convert it to it's original libssh accepted form */ - asprintf(&alg, "%s@libssh.org", algorithm + 7); - if (!alg) { + if (asprintf(&alg, "%s@libssh.org", algorithm + 7) == -1) { ERRMEM; + alg = NULL; ret = 1; goto cleanup; } @@ -2916,7 +2718,7 @@ nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OP alg_found = 1; break; } - haystack++; + haystack = substr + 1; } if (!alg_found) { ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg); @@ -2943,6 +2745,7 @@ nc_server_config_host_key_alg(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -2992,6 +2795,7 @@ nc_server_config_kex_alg(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -3041,6 +2845,7 @@ nc_server_config_encryption_alg(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -3090,6 +2895,7 @@ nc_server_config_mac_alg(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -3206,7 +3012,7 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_config_del_unix_socket(bind, endpt->opts.unixsock); + nc_server_config_del_unix_socket_opts(bind, endpt->opts.unixsock); } cleanup: @@ -3216,10 +3022,7 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) #ifdef NC_ENABLED_SSH_TLS /** - * @brief Set all endpoint client auth references, which couldn't be set beforehand. - * - * The references that could not be set are those, which reference endpoints, which - * lie below the given endpoint in the YANG data (because of DFS tree parsing). + * @brief Set all endpoint client auth references, which couldn't be set while parsing data. * * @return 0 on success, 1 on error. */ @@ -3229,13 +3032,14 @@ nc_server_config_fill_endpt_client_auth(void) uint16_t i, j; for (i = 0; i < server_opts.endpt_count; i++) { - /* go through all the endpoint */ + /* go through all the endpoints */ if (server_opts.endpts[i].referenced_endpt_name) { /* endpt has a reference, that hasn't been set yet */ - for (j = i + 1; j < server_opts.endpt_count; j++) { - /* go through all the remaining endpts */ + for (j = 0; j < server_opts.endpt_count; j++) { + /* go through all the endpts */ if (!strcmp(server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[j].name)) { - /* found the endpoint we were looking for */ + /* found the endpoint we were looking for, + * assign the server opts from the referenced endpt */ if (server_opts.endpts[i].ti == NC_TI_LIBSSH) { server_opts.endpts[i].opts.ssh->endpt_client_ref = &server_opts.endpts[j]; break; @@ -3331,7 +3135,7 @@ nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION if (i == server_opts.endpt_count) { /* endpt not found, save the name and try to look it up later */ - nc_server_config_del_endpt_reference(endpt); + free(endpt->referenced_endpt_name); endpt->referenced_endpt_name = strdup(endpt_name); if (!endpt->referenced_endpt_name) { ERRMEM; @@ -3342,7 +3146,7 @@ nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION /* check for self reference */ if (endpt == &server_opts.endpts[i]) { - ERR(NULL, "Self client authentication reference detected."); + ERR(NULL, "Self endpoint reference detected for endpoint \"%s\".", endpt->name); ret = 1; goto cleanup; } @@ -3350,7 +3154,7 @@ nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION /* check for cyclic references */ ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i]); if (ret) { - ERR(NULL, "Cyclic client authentication reference detected."); + ERR(NULL, "Cyclic endpoint reference detected for endpoint \"%s\".", endpt->name); goto cleanup; } @@ -3365,32 +3169,6 @@ nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION return ret; } -static int -nc_server_config_tls_replace_cert_data(const struct lyd_node *node, struct nc_server_tls_opts *opts) -{ - nc_server_config_tls_del_cert_data(opts); - opts->cert_data = strdup(lyd_get_value(node)); - if (!opts->cert_data) { - ERRMEM; - return 1; - } - - return 0; -} - -static int -nc_server_config_tls_replace_cert_data_client_auth(const struct lyd_node *node, struct nc_certificate *cert) -{ - nc_server_config_tls_del_cert_data_certificate(cert); - cert->data = strdup(lyd_get_value(node)); - if (!cert->data) { - ERRMEM; - return 1; - } - - return 0; -} - static int nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) { @@ -3403,6 +3181,7 @@ nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -3413,38 +3192,31 @@ nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_tls_replace_cert_data(node, opts); - if (ret) { - goto cleanup; - } - } - } else if (equal_parent_name(node, 3, "ca-certs")) { - if (nc_server_config_get_cert(node, 0, &cert)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert); - if (ret) { + free(opts->cert_data); + opts->cert_data = strdup(lyd_get_value(node)); + if (!opts->cert_data) { + ERRMEM; + ret = 1; goto cleanup; } - } else { - nc_server_config_tls_del_cert_data_certificate(cert); } - } else if (equal_parent_name(node, 3, "ee-certs")) { - if (nc_server_config_get_cert(node, 1, &cert)) { + } else if (equal_parent_name(node, 3, "ca-certs") || equal_parent_name(node, 3, "ee-certs")) { + if (nc_server_config_get_cert(node, &cert)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_tls_replace_cert_data_client_auth(node, cert); - if (ret) { + free(cert->data); + cert->data = strdup(lyd_get_value(node)); + if (!cert->data) { + ERRMEM; + ret = 1; goto cleanup; } } else { - nc_server_config_tls_del_cert_data_certificate(cert); + free(cert->data); + cert->data = NULL; } } @@ -3456,29 +3228,6 @@ nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) return ret; } -static int -nc_server_config_tls_create_asymmetric_key_ref(const struct lyd_node *node, struct nc_endpt *endpt) -{ - uint16_t i; - struct nc_keystore *ks = &server_opts.keystore; - - /* lookup name */ - for (i = 0; i < ks->asym_key_count; i++) { - if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) { - break; - } - } - - if (i == ks->asym_key_count) { - ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node)); - return 1; - } - - endpt->opts.tls->key_ref = &ks->asym_keys[i]; - - return 0; -} - static int nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) { @@ -3490,6 +3239,7 @@ nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -3502,11 +3252,15 @@ nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) /* set to keystore */ endpt->opts.tls->store = NC_STORE_KEYSTORE; - ret = nc_server_config_tls_create_asymmetric_key_ref(node, endpt); - if (ret) { + free(endpt->opts.tls->key_ref); + endpt->opts.tls->key_ref = strdup(lyd_get_value(node)); + if (!endpt->opts.tls->key_ref) { + ERRMEM; + ret = 1; goto cleanup; } } else { + free(endpt->opts.tls->key_ref); endpt->opts.tls->key_ref = NULL; } @@ -3518,53 +3272,6 @@ nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) return ret; } -static int -nc_server_config_tls_create_certificate_ref(const struct lyd_node *node, struct nc_server_tls_opts *opts, struct nc_asymmetric_key *key) -{ - uint16_t i; - - /* lookup name */ - for (i = 0; i < key->cert_count; i++) { - if (!strcmp(lyd_get_value(node), key->certs[i].name)) { - break; - } - } - - if (i == key->cert_count) { - ERR(NULL, "Certificate \"%s\" not found in the asymmetric key \"%s\".", lyd_get_value(node), key->name); - return 1; - } - - opts->cert_ref = &key->certs[i]; - - return 0; -} - -static struct nc_asymmetric_key * -nc_server_config_cert_get_asymmetric_key(const struct lyd_node *node) -{ - uint16_t i; - struct nc_keystore *ks = &server_opts.keystore; - - /* starting with certificate node */ - assert(!strcmp(LYD_NAME(node), "certificate")); - - /* switch to it's only sibling, must be asymmetric-key */ - node = node->prev; - assert(!strcmp(LYD_NAME(node), "asymmetric-key")); - - /* find the given asymmetric key */ - for (i = 0; i < ks->asym_key_count; i++) { - if (!strcmp(lyd_get_value(node), ks->asym_keys[i].name)) { - return &ks->asym_keys[i]; - } - } - - /* didn't find it */ - ERR(NULL, "Asymmetric key \"%s\" not found in the keystore.", lyd_get_value(node)); - return NULL; -} - static int nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts) { @@ -3591,14 +3298,15 @@ static int nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_asymmetric_key *key; struct nc_server_tls_opts *opts; struct nc_ch_client *ch_client; + struct nc_certificate *cert; assert(!strcmp(LYD_NAME(node), "certificate")); /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -3613,24 +3321,15 @@ nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op) /* set to keystore */ opts->store = NC_STORE_KEYSTORE; - if (!opts->key_ref) { - /* we don't have a key from which we need the cert yet */ - key = nc_server_config_cert_get_asymmetric_key(node); - if (!key) { - ret = 1; - goto cleanup; - } - } else { - /* we have the key */ - key = opts->key_ref; - } - - /* find the given cert in the key and set it */ - ret = nc_server_config_tls_create_certificate_ref(node, opts, key); - if (ret) { + free(opts->cert_ref); + opts->cert_ref = strdup(lyd_get_value(node)); + if (!opts->cert_ref) { + ERRMEM; + ret = 1; goto cleanup; } } else { + free(opts->cert_ref); opts->cert_ref = NULL; } } else if (equal_parent_name(node, 2, "ca-certs")) { @@ -3641,7 +3340,11 @@ nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else { - nc_server_config_tls_del_certs(&opts->ca_certs); + if (nc_server_config_get_cert(node, &cert)) { + ret = 1; + goto cleanup; + } + nc_server_config_del_cert(&opts->ca_certs, cert); } } else if (equal_parent_name(node, 2, "ee-certs")) { /* TLS client auth end entity */ @@ -3651,7 +3354,11 @@ nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else { - nc_server_config_tls_del_certs(&opts->ee_certs); + if (nc_server_config_get_cert(node, &cert)) { + ret = 1; + goto cleanup; + } + nc_server_config_del_cert(&opts->ee_certs, cert); } } @@ -3675,14 +3382,6 @@ nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_serv assert(!strcmp(LYD_NAME(node), "cert-to-name")); - /* create new ctn */ - new = calloc(1, sizeof *new); - if (!new) { - ERRMEM; - ret = 1; - goto cleanup; - } - /* get all the data */ /* find the list's key */ lyd_find_path(node, "id", 0, &n); @@ -3716,6 +3415,14 @@ nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_serv goto cleanup; } + /* create new ctn */ + new = calloc(1, sizeof *new); + if (!new) { + ERRMEM; + ret = 1; + goto cleanup; + } + /* find the right place for insertion */ if (!opts->ctn) { /* inserting the first one */ @@ -3738,9 +3445,7 @@ nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_serv /* insert the right data */ new->id = id; - if (new->name) { - free(new->name); - } + free(new->name); new->name = strdup(name); if (!new->name) { ERRMEM; @@ -3758,7 +3463,6 @@ nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_server_tls_opts *opts; - struct lyd_node *key; struct nc_ctn *ctn; struct nc_ch_client *ch_client; @@ -3766,6 +3470,7 @@ nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -3781,8 +3486,6 @@ nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op) } } else { /* find the given ctn entry */ - lyd_find_path(node, "id", 0, &key); - assert(key); if (nc_server_config_get_ctn(node, &ctn)) { ret = 1; goto cleanup; @@ -3798,20 +3501,6 @@ nc_server_config_cert_to_name(const struct lyd_node *node, NC_OPERATION op) return ret; } -static int -nc_server_config_replace_fingerprint(const struct lyd_node *node, struct nc_ctn *ctn) -{ - nc_server_config_del_fingerprint(ctn); - - ctn->fingerprint = strdup(lyd_get_value(node)); - if (!ctn->fingerprint) { - ERRMEM; - return 1; - } - - return 0; -} - static int nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op) { @@ -3823,6 +3512,7 @@ nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -3832,12 +3522,16 @@ nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_replace_fingerprint(node, ctn); - if (ret) { + free(ctn->fingerprint); + ctn->fingerprint = strdup(lyd_get_value(node)); + if (!ctn->fingerprint) { + ERRMEM; + ret = 1; goto cleanup; } } else { - nc_server_config_del_fingerprint(ctn); + free(ctn->fingerprint); + ctn->fingerprint = NULL; } cleanup: @@ -3848,18 +3542,6 @@ nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op) return ret; } -static void -nc_server_config_set_tls_version(struct nc_server_tls_opts *opts, NC_TLS_VERSION version, NC_OPERATION op) -{ - if (op == NC_OP_CREATE) { - /* add the version if it isn't there already */ - opts->tls_versions |= version; - } else if ((op == NC_OP_DELETE) && (opts->tls_versions & version)) { - /* delete the version if it is there */ - opts->tls_versions -= version; - } -} - static int nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op) { @@ -3867,11 +3549,13 @@ nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op) struct nc_server_tls_opts *opts; const char *version = NULL; struct nc_ch_client *ch_client; + NC_TLS_VERSION tls_version; assert(!strcmp(LYD_NAME(node), "tls-version")); /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -3880,21 +3564,30 @@ nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } + /* str to tls_version */ version = ((struct lyd_node_term *)node)->value.ident->name; if (!strcmp(version, "tls10")) { - nc_server_config_set_tls_version(opts, NC_TLS_VERSION_10, op); + tls_version = NC_TLS_VERSION_10; } else if (!strcmp(version, "tls11")) { - nc_server_config_set_tls_version(opts, NC_TLS_VERSION_11, op); + tls_version = NC_TLS_VERSION_11; } else if (!strcmp(version, "tls12")) { - nc_server_config_set_tls_version(opts, NC_TLS_VERSION_12, op); + tls_version = NC_TLS_VERSION_12; } else if (!strcmp(version, "tls13")) { - nc_server_config_set_tls_version(opts, NC_TLS_VERSION_13, op); + tls_version = NC_TLS_VERSION_13; } else { ERR(NULL, "TLS version \"%s\" not supported.", version); ret = 1; goto cleanup; } + if (op == NC_OP_CREATE) { + /* add the version if it isn't there already */ + opts->tls_versions |= tls_version; + } else if ((op == NC_OP_DELETE) && (opts->tls_versions & tls_version)) { + /* delete the version if it is there */ + opts->tls_versions -= tls_version; + } + cleanup: if (is_ch(node)) { /* UNLOCK */ @@ -3909,6 +3602,7 @@ nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char int ret = 0; char *ssl_cipher = NULL; uint16_t i; + void *tmp; ssl_cipher = malloc(strlen(cipher) + 1); if (!ssl_cipher) { @@ -3938,12 +3632,13 @@ nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char } } else { /* + 1 because of : between entries */ - opts->ciphers = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(ssl_cipher) + 1 + 1); - if (!opts->ciphers) { + tmp = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(ssl_cipher) + 1 + 1); + if (!tmp) { ERRMEM; ret = 1; goto cleanup; } + opts->ciphers = tmp; strcat(opts->ciphers, ":"); strcat(opts->ciphers, ssl_cipher); } @@ -3960,10 +3655,9 @@ nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *c char *haystack, *substr; size_t cipher_len = strlen(cipher); - /* delete */ + /* iterate over all the substrings */ haystack = opts->ciphers; while ((substr = strstr(haystack, cipher))) { - /* iterate over all the substrings */ if (((substr == haystack) && (*(substr + cipher_len) == ':')) || ((substr != haystack) && (*(substr - 1) == ':') && (*(substr + cipher_len) == ':'))) { /* either the first element of the string or somewhere in the middle */ @@ -3976,7 +3670,7 @@ nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *c cipher_found = 1; break; } - haystack++; + haystack = substr + 1; } if (!cipher_found) { @@ -3999,6 +3693,7 @@ nc_server_config_cipher_suite(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -4039,6 +3734,7 @@ nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -4048,7 +3744,7 @@ nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_url(opts); + free(opts->crl_url); opts->crl_url = strdup(lyd_get_value(node)); if (!opts->crl_url) { ERRMEM; @@ -4056,7 +3752,8 @@ nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_config_del_url(opts); + free(opts->crl_url); + opts->crl_url = NULL; } cleanup: @@ -4078,6 +3775,7 @@ nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -4087,7 +3785,7 @@ nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_path(opts); + free(opts->crl_path); opts->crl_path = strdup(lyd_get_value(node)); if (!opts->crl_path) { ERRMEM; @@ -4095,7 +3793,8 @@ nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_config_del_path(opts); + free(opts->crl_path); + opts->crl_path = NULL; } cleanup: @@ -4117,6 +3816,7 @@ nc_server_config_crl_cert_ext(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -4159,7 +3859,7 @@ nc_server_config_create_netconf_client(const struct lyd_node *node) server_opts.ch_clients[server_opts.ch_client_count - 1].id = ATOMIC_INC_RELAXED(server_opts.new_client_id); server_opts.ch_clients[server_opts.ch_client_count - 1].start_with = NC_CH_FIRST_LISTED; - server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3; // TODO + server_opts.ch_clients[server_opts.ch_client_count - 1].max_attempts = 3; pthread_mutex_init(&server_opts.ch_clients[server_opts.ch_client_count - 1].lock, NULL); @@ -4208,6 +3908,7 @@ nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -4217,8 +3918,7 @@ nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - nc_server_config_del_remote_address(ch_endpt); - + free(ch_endpt->address); ch_endpt->address = strdup(lyd_get_value(node)); if (!ch_endpt->address) { ERRMEM; @@ -4226,7 +3926,8 @@ nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else { - nc_server_config_del_remote_address(ch_endpt); + free(ch_endpt->address); + ch_endpt->address = NULL; } cleanup: @@ -4246,6 +3947,7 @@ nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -4280,8 +3982,8 @@ nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { - ret = 1; - goto cleanup; + /* to avoid unlock on fail */ + return 1; } ch_client->conn_type = NC_CH_PERSIST; @@ -4289,7 +3991,6 @@ nc_server_config_persistent(const struct lyd_node *node, NC_OPERATION op) /* UNLOCK */ nc_ch_client_unlock(ch_client); -cleanup: return ret; } @@ -4305,8 +4006,8 @@ nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { - ret = 1; - goto cleanup; + /* to avoid unlock on fail */ + return 1; } ch_client->conn_type = NC_CH_PERIOD; @@ -4318,7 +4019,6 @@ nc_server_config_periodic(const struct lyd_node *node, NC_OPERATION op) /* UNLOCK */ nc_ch_client_unlock(ch_client); -cleanup: return ret; } @@ -4332,8 +4032,8 @@ nc_server_config_period(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { - ret = 1; - goto cleanup; + /* to avoid unlock on fail */ + return 1; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { @@ -4345,7 +4045,6 @@ nc_server_config_period(const struct lyd_node *node, NC_OPERATION op) /* UNLOCK */ nc_ch_client_unlock(ch_client); -cleanup: return ret; } @@ -4360,6 +4059,7 @@ nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -4392,8 +4092,8 @@ nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { - ret = 1; - goto cleanup; + /* to avoid unlock on fail */ + return 1; } /* set to default values */ @@ -4404,7 +4104,6 @@ nc_server_config_reconnect_strategy(const struct lyd_node *node, NC_OPERATION op /* UNLOCK */ nc_ch_client_unlock(ch_client); -cleanup: return ret; } @@ -4419,6 +4118,7 @@ nc_server_config_start_with(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ return 1; } @@ -4456,8 +4156,8 @@ nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { - ret = 1; - goto cleanup; + /* to avoid unlock on fail */ + return 1; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { @@ -4469,7 +4169,6 @@ nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op) /* UNLOCK */ nc_ch_client_unlock(ch_client); -cleanup: return ret; } @@ -4483,8 +4182,8 @@ nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op) /* LOCK */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { - ret = 1; - goto cleanup; + /* to avoid unlock on fail */ + return 1; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { @@ -4496,7 +4195,6 @@ nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op) /* UNLOCK */ nc_ch_client_unlock(ch_client); -cleanup: return ret; } @@ -4504,230 +4202,130 @@ static int nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION op) { const char *name = LYD_NAME(node); + int ret = 0; if (!strcmp(name, "listen")) { - if (nc_server_config_listen(NULL, op)) { - goto error; - } + ret = nc_server_config_listen(node, op); + } else if (!strcmp(name, "call-home")) { + ret = nc_server_config_ch(node, op); } else if (!strcmp(name, "idle-timeout")) { - if (nc_server_config_idle_timeout(node, op)) { - goto error; - } + ret = nc_server_config_idle_timeout(node, op); } else if (!strcmp(name, "endpoint")) { - if (nc_server_config_endpoint(node, op)) { - goto error; - } + ret = nc_server_config_endpoint(node, op); } else if (!strcmp(name, "unix-socket")) { - if (nc_server_config_unix_socket(node, op)) { - goto error; - } + ret = nc_server_config_unix_socket(node, op); } #ifdef NC_ENABLED_SSH_TLS else if (!strcmp(name, "ssh")) { - if (nc_server_config_ssh(node, op)) { - goto error; - } + ret = nc_server_config_ssh(node, op); } else if (!strcmp(name, "local-address")) { - if (nc_server_config_local_address(node, op)) { - goto error; - } + ret = nc_server_config_local_address(node, op); } else if (!strcmp(name, "local-port")) { - if (nc_server_config_local_port(node, op)) { - goto error; - } + ret = nc_server_config_local_port(node, op); } else if (!strcmp(name, "keepalives")) { - if (nc_server_config_keepalives(node, op)) { - goto error; - } + ret = nc_server_config_keepalives(node, op); } else if (!strcmp(name, "idle-time")) { - if (nc_server_config_idle_time(node, op)) { - goto error; - } + ret = nc_server_config_idle_time(node, op); } else if (!strcmp(name, "max-probes")) { - if (nc_server_config_max_probes(node, op)) { - goto error; - } + ret = nc_server_config_max_probes(node, op); } else if (!strcmp(name, "probe-interval")) { - if (nc_server_config_probe_interval(node, op)) { - goto error; - } + ret = nc_server_config_probe_interval(node, op); } else if (!strcmp(name, "host-key")) { - if (nc_server_config_host_key(node, op)) { - goto error; - } + ret = nc_server_config_host_key(node, op); } else if (!strcmp(name, "public-key-format")) { - if (nc_server_config_public_key_format(node, op)) { - goto error; - } + ret = nc_server_config_public_key_format(node, op); } else if (!strcmp(name, "public-key")) { - if (nc_server_config_public_key(node, op)) { - goto error; - } + ret = nc_server_config_public_key(node, op); } else if (!strcmp(name, "private-key-format")) { - if (nc_server_config_private_key_format(node, op)) { - goto error; - } + ret = nc_server_config_private_key_format(node, op); } else if (!strcmp(name, "cleartext-private-key")) { - if (nc_server_config_cleartext_private_key(node, op)) { - goto error; - } + ret = nc_server_config_cleartext_private_key(node, op); } else if (!strcmp(name, "keystore-reference")) { - if (nc_server_config_keystore_reference(node, op)) { - goto error; - } + ret = nc_server_config_keystore_reference(node, op); } else if (!strcmp(name, "user")) { - if (nc_server_config_user(node, op)) { - goto error; - } + ret = nc_server_config_user(node, op); } else if (!strcmp(name, "auth-attempts")) { - if (nc_server_config_auth_attempts(node, op)) { - goto error; - } + ret = nc_server_config_auth_attempts(node, op); } else if (!strcmp(name, "auth-timeout")) { - if (nc_server_config_auth_timeout(node, op)) { - goto error; - } + ret = nc_server_config_auth_timeout(node, op); } else if (!strcmp(name, "truststore-reference")) { - if (nc_server_config_truststore_reference(node, op)) { - goto error; - } + ret = nc_server_config_truststore_reference(node, op); } else if (!strcmp(name, "password")) { - if (nc_server_config_password(node, op)) { - goto error; - } + ret = nc_server_config_password(node, op); } else if (!strcmp(name, "pam-config-file-name")) { - if (nc_server_config_pam_name(node, op)) { - goto error; - } + ret = nc_server_config_pam_name(node, op); } else if (!strcmp(name, "pam-config-file-dir")) { - if (nc_server_config_pam_dir(node, op)) { - goto error; - } + ret = nc_server_config_pam_dir(node, op); } else if (!strcmp(name, "none")) { - if (nc_server_config_none(node, op)) { - goto error; - } + ret = nc_server_config_none(node, op); } else if (!strcmp(name, "host-key-alg")) { - if (nc_server_config_host_key_alg(node, op)) { - goto error; - } + ret = nc_server_config_host_key_alg(node, op); } else if (!strcmp(name, "key-exchange-alg")) { - if (nc_server_config_kex_alg(node, op)) { - goto error; - } + ret = nc_server_config_kex_alg(node, op); } else if (!strcmp(name, "encryption-alg")) { - if (nc_server_config_encryption_alg(node, op)) { - goto error; - } + ret = nc_server_config_encryption_alg(node, op); } else if (!strcmp(name, "mac-alg")) { - if (nc_server_config_mac_alg(node, op)) { - goto error; - } + ret = nc_server_config_mac_alg(node, op); } else if (!strcmp(name, "endpoint-client-auth")) { - if (nc_server_config_endpoint_client_auth(node, op)) { - goto error; - } + ret = nc_server_config_endpoint_client_auth(node, op); } else if (!strcmp(name, "tls")) { - if (nc_server_config_tls(node, op)) { - goto error; - } + ret = nc_server_config_tls(node, op); } else if (!strcmp(name, "cert-data")) { - if (nc_server_config_cert_data(node, op)) { - goto error; - } + ret = nc_server_config_cert_data(node, op); } else if (!strcmp(name, "asymmetric-key")) { - if (nc_server_config_asymmetric_key(node, op)) { - goto error; - } + ret = nc_server_config_asymmetric_key(node, op); } else if (!strcmp(name, "certificate")) { - if (nc_server_config_certificate(node, op)) { - goto error; - } + ret = nc_server_config_certificate(node, op); } else if (!strcmp(name, "cert-to-name")) { - if (nc_server_config_cert_to_name(node, op)) { - goto error; - } + ret = nc_server_config_cert_to_name(node, op); } else if (!strcmp(name, "fingerprint")) { - if (nc_server_config_fingerprint(node, op)) { - goto error; - } + ret = nc_server_config_fingerprint(node, op); } else if (!strcmp(name, "tls-version")) { - if (nc_server_config_tls_version(node, op)) { - goto error; - } + ret = nc_server_config_tls_version(node, op); } else if (!strcmp(name, "cipher-suite")) { - if (nc_server_config_cipher_suite(node, op)) { - goto error; - } + ret = nc_server_config_cipher_suite(node, op); } else if (!strcmp(name, "crl-url")) { - if (nc_server_config_crl_url(node, op)) { - goto error; - } + ret = nc_server_config_crl_url(node, op); } else if (!strcmp(name, "crl-path")) { - if (nc_server_config_crl_path(node, op)) { - goto error; - } + ret = nc_server_config_crl_path(node, op); } else if (!strcmp(name, "crl-cert-ext")) { - if (nc_server_config_crl_cert_ext(node, op)) { - goto error; - } + ret = nc_server_config_crl_cert_ext(node, op); } #endif /* NC_ENABLED_SSH_TLS */ else if (!strcmp(name, "netconf-client")) { - if (nc_server_config_netconf_client(node, op)) { - goto error; - } + ret = nc_server_config_netconf_client(node, op); } #ifdef NC_ENABLED_SSH_TLS else if (!strcmp(name, "remote-address")) { - if (nc_server_config_remote_address(node, op)) { - goto error; - } + ret = nc_server_config_remote_address(node, op); } else if (!strcmp(name, "remote-port")) { - if (nc_server_config_remote_port(node, op)) { - goto error; - } + ret = nc_server_config_remote_port(node, op); } #endif /* NC_ENABLED_SSH_TLS */ else if (!strcmp(name, "persistent")) { - if (nc_server_config_persistent(node, op)) { - goto error; - } + ret = nc_server_config_persistent(node, op); } else if (!strcmp(name, "periodic")) { - if (nc_server_config_periodic(node, op)) { - goto error; - } + ret = nc_server_config_periodic(node, op); } else if (!strcmp(name, "period")) { - if (nc_server_config_period(node, op)) { - goto error; - } + ret = nc_server_config_period(node, op); } else if (!strcmp(name, "anchor-time")) { - if (nc_server_config_anchor_time(node, op)) { - goto error; - } + ret = nc_server_config_anchor_time(node, op); } else if (!strcmp(name, "reconnect-strategy")) { - if (nc_server_config_reconnect_strategy(node, op)) { - goto error; - } + ret = nc_server_config_reconnect_strategy(node, op); } else if (!strcmp(name, "start-with")) { - if (nc_server_config_start_with(node, op)) { - goto error; - } + ret = nc_server_config_start_with(node, op); } else if (!strcmp(name, "max-wait")) { - if (nc_server_config_max_wait(node, op)) { - goto error; - } + ret = nc_server_config_max_wait(node, op); } else if (!strcmp(name, "max-attempts")) { - if (nc_server_config_max_attempts(node, op)) { - goto error; - } + ret = nc_server_config_max_attempts(node, op); } - return 0; + if (ret) { + ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node)); + return 1; + } -error: - ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node)); - return 1; + return 0; } int diff --git a/src/server_config.h b/src/server_config.h index a028b0bb..e3a8544c 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -60,20 +60,18 @@ extern "C" { * iana-ssh-mac-algs, iana-ssh-public-key-algs, ietf-keystore, ietf-ssh-server, ietf-truststore, * ietf-tls-server and libnetconf2-netconf-server. * - * @param[in, out] ctx Optional context in which the modules will be implemented. Created if ctx is null. + * @param[in, out] ctx Optional context in which the modules will be implemented. Created if *ctx is null. * @return 0 on success, 1 on error. */ int nc_server_config_load_modules(struct ly_ctx **ctx); /** - * @brief Configure server based on the given diff data. + * @brief Configure server based on the given diff. * - * Expected data are a validated instance of a ietf-netconf-server YANG data. - * The data must be in the diff format and supported operations are: create, replace, - * delete and none. Context must already have implemented the required modules, see - * ::nc_server_config_load_modules(). + * Context must already have implemented the required modules, see ::nc_server_config_load_modules(). * - * @param[in] diff ietf-netconf-server YANG diff data. + * @param[in] diff YANG diff belonging to either ietf-netconf-server, ietf-keystore or ietf-truststore modules. + * This diff should be validated. The top level node HAS to have an operation (create, replace, delete or none). * @return 0 on success, 1 on error. */ int nc_server_config_setup_diff(const struct lyd_node *diff); @@ -81,23 +79,24 @@ int nc_server_config_setup_diff(const struct lyd_node *diff); /** * @brief Configure server based on the given data. * - * Expected data is a validated instance of a ietf-netconf-server YANG data. * Behaves as if all the nodes in data had the replace operation. That means that the current configuration will be deleted - * and just the given data will all be applied. - * The data must not contain any operation attribute, see ::nc_server_config_setup_diff() which works with diff. + * and just the given data will be applied. * Context must already have implemented the required modules, see ::nc_server_config_load_modules(). * - * @param[in] data ietf-netconf-server YANG data. + * @param[in] data YANG data belonging to either ietf-netconf-server, ietf-keystore or ietf-truststore modules. + * This data should be validated. No node can have an operation attribute. * @return 0 on success, 1 on error. */ int nc_server_config_setup_data(const struct lyd_node *data); /** - * @brief Configure server based on the given ietf-netconf-server YANG data from a file. + * @brief Configure server based on the given data stored in a file. + * * Wrapper around ::nc_server_config_setup_data() hiding work with parsing the data. + * Context must already have implemented the required modules, see ::nc_server_config_load_modules(). * * @param[in] ctx libyang context. - * @param[in] path Path to the file with ietf-netconf-server YANG data. + * @param[in] path Path to a file with ietf-netconf-server, ietf-keystore or ietf-truststore YANG data. * @return 0 on success, 1 on error. */ int nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path); @@ -105,7 +104,7 @@ int nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path); #ifdef NC_ENABLED_SSH_TLS /** - * @brief Creates new YANG configuration data nodes for local-address and local-port. + * @brief Creates new YANG configuration data nodes for address and port. * * @param[in] ctx libyang context. * @param[in] endpt_name Arbitrary identifier of the endpoint. @@ -181,11 +180,8 @@ int nc_server_config_new_del_keystore_asym_key(const char *asym_key_name, struct /** * @brief Creates new YANG data nodes for a certificate in the keystore. * - * A certificate can not exist without its asymmetric key, so you must call ::nc_server_config_new_keystore_asym_key() - * either before or after calling this with the same identifier for the asymmetric key. - * - * An asymmetric key pair can have zero or more certificates associated with this key pair, however a certificate must - * have exactly one key pair it belongs to. + * A certificate can not exist without its asymmetric key, so you must create an asymmetric key + * with the same identifier you pass to this function. * * @param[in] ctx libyang context. * @param[in] asym_key_name Arbitrary identifier of the asymmetric key. diff --git a/src/server_config_p.h b/src/server_config_p.h index 64636e7e..a17f2f3d 100644 --- a/src/server_config_p.h +++ b/src/server_config_p.h @@ -85,9 +85,16 @@ int nc_server_config_parse_tree(const struct lyd_node *node, NC_OPERATION parent * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. * @return 0 on success, 1 on error. */ -int nc_server_config_listen(struct lyd_node *node, NC_OPERATION op); +int nc_server_config_listen(const struct lyd_node *node, NC_OPERATION op); -void nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op); +/** + * @brief Configures the Call Home subtree in the ietf-netconf-server module. + * + * @param[in] node call-home YANG data node. + * @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE. + * @return 0 on success, 1 on error. + */ +int nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op); #ifdef NC_ENABLED_SSH_TLS From d2116be7cb19e2604d8522c1699861299d074485 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 12 Oct 2023 11:44:04 +0200 Subject: [PATCH 085/134] server_config_ks REFACTOR code review --- src/server_config_ks.c | 97 ++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 66 deletions(-) diff --git a/src/server_config_ks.c b/src/server_config_ks.c index b39f8d8d..75003ff4 100644 --- a/src/server_config_ks.c +++ b/src/server_config_ks.c @@ -42,6 +42,7 @@ nc_server_config_get_asymmetric_key(const struct lyd_node *node, struct nc_asymm uint16_t i; const char *askey_name; struct nc_keystore *ks; + const char *node_name = LYD_NAME(node); assert(node && askey); @@ -53,7 +54,7 @@ nc_server_config_get_asymmetric_key(const struct lyd_node *node, struct nc_asymm } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in an asymmetric-key subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in an asymmetric-key subtree.", node_name); return 1; } @@ -86,6 +87,7 @@ nc_server_config_get_certificate(const struct lyd_node *node, struct nc_certific uint16_t i; const char *cert_name; struct nc_asymmetric_key *askey; + const char *node_name = LYD_NAME(node); assert(node && cert); @@ -101,7 +103,7 @@ nc_server_config_get_certificate(const struct lyd_node *node, struct nc_certific } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", node_name); return 1; } @@ -124,39 +126,17 @@ static void nc_server_config_ks_del_asymmetric_key_cert(struct nc_asymmetric_key *key, struct nc_certificate *cert) { free(cert->name); - cert->name = NULL; - free(cert->data); - cert->data = NULL; key->cert_count--; - if (key->cert_count == 0) { + if (!key->cert_count) { free(key->certs); key->certs = NULL; + } else if (cert != &key->certs[key->cert_count]) { + memcpy(cert, &key->certs[key->cert_count], sizeof *key->certs); } } -static void -nc_server_config_ks_del_public_key(struct nc_asymmetric_key *key) -{ - free(key->pubkey_data); - key->pubkey_data = NULL; -} - -static void -nc_server_config_ks_del_private_key(struct nc_asymmetric_key *key) -{ - free(key->privkey_data); - key->privkey_data = NULL; -} - -static void -nc_server_config_ks_del_cert_data(struct nc_certificate *cert) -{ - free(cert->data); - cert->data = NULL; -} - static void nc_server_config_ks_del_asymmetric_key(struct nc_asymmetric_key *key) { @@ -164,10 +144,8 @@ nc_server_config_ks_del_asymmetric_key(struct nc_asymmetric_key *key) struct nc_keystore *ks = &server_opts.keystore; free(key->name); - key->name = NULL; - - nc_server_config_ks_del_public_key(key); - nc_server_config_ks_del_private_key(key); + free(key->pubkey_data); + free(key->privkey_data); cert_count = key->cert_count; for (i = 0; i < cert_count; i++) { @@ -178,6 +156,8 @@ nc_server_config_ks_del_asymmetric_key(struct nc_asymmetric_key *key) if (!ks->asym_key_count) { free(ks->asym_keys); ks->asym_keys = NULL; + } else if (key != &ks->asym_keys[ks->asym_key_count]) { + memcpy(key, &ks->asym_keys[ks->asym_key_count], sizeof *ks->asym_keys); } } @@ -285,7 +265,7 @@ nc_server_config_ks_public_key(const struct lyd_node *node, NC_OPERATION op) } /* replace the pubkey */ - nc_server_config_ks_del_public_key(key); + free(key->pubkey_data); key->pubkey_data = strdup(lyd_get_value(node)); if (!key->pubkey_data) { ERRMEM; @@ -337,14 +317,15 @@ nc_server_config_ks_cleartext_private_key(const struct lyd_node *node, NC_OPERAT if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* replace the privkey */ - nc_server_config_ks_del_private_key(key); + free(key->privkey_data); key->privkey_data = strdup(lyd_get_value(node)); if (!key->privkey_data) { ERRMEM; return 1; } } else if (op == NC_OP_DELETE) { - nc_server_config_ks_del_private_key(key); + free(key->privkey_data); + key->privkey_data = NULL; } return 0; @@ -401,7 +382,7 @@ nc_server_config_ks_cert_data(const struct lyd_node *node, NC_OPERATION op) } /* replace the cert data */ - nc_server_config_ks_del_cert_data(cert); + free(cert->data); cert->data = strdup(lyd_get_value(node)); if (!cert->data) { ERRMEM; @@ -416,50 +397,34 @@ int nc_server_config_parse_keystore(const struct lyd_node *node, NC_OPERATION op) { const char *name = LYD_NAME(node); + int ret = 0; if (!strcmp(name, "keystore")) { - if (nc_server_config_ks_keystore(node, op)) { - goto error; - } + ret = nc_server_config_ks_keystore(node, op); } else if (!strcmp(name, "asymmetric-keys")) { - if (nc_server_config_ks_asymmetric_keys(node, op)) { - goto error; - } + ret = nc_server_config_ks_asymmetric_keys(node, op); } else if (!strcmp(name, "asymmetric-key")) { - if (nc_server_config_ks_asymmetric_key(node, op)) { - goto error; - } + ret = nc_server_config_ks_asymmetric_key(node, op); } else if (!strcmp(name, "public-key-format")) { - if (nc_server_config_ks_public_key_format(node, op)) { - goto error; - } + ret = nc_server_config_ks_public_key_format(node, op); } else if (!strcmp(name, "public-key")) { - if (nc_server_config_ks_public_key(node, op)) { - goto error; - } + ret = nc_server_config_ks_public_key(node, op); } else if (!strcmp(name, "private-key-format")) { - if (nc_server_config_ks_private_key_format(node, op)) { - goto error; - } + ret = nc_server_config_ks_private_key_format(node, op); } else if (!strcmp(name, "cleartext-private-key")) { - if (nc_server_config_ks_cleartext_private_key(node, op)) { - goto error; - } + ret = nc_server_config_ks_cleartext_private_key(node, op); } else if (!strcmp(name, "certificate")) { - if (nc_server_config_ks_certificate(node, op)) { - goto error; - } + ret = nc_server_config_ks_certificate(node, op); } else if (!strcmp(name, "cert-data")) { - if (nc_server_config_ks_cert_data(node, op)) { - goto error; - } + ret = nc_server_config_ks_cert_data(node, op); } - return 0; + if (ret) { + ERR(NULL, "Configuring (%s) failed.", name); + return 1; + } -error: - ERR(NULL, "Configuring (%s) failed.", name); - return 1; + return 0; } int From 6508f0d02565b4d31a562d4e17f2577d2c414a6f Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 12 Oct 2023 11:58:09 +0200 Subject: [PATCH 086/134] server_config_ts REFACTOR code review --- src/server_config_ts.c | 102 ++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 63 deletions(-) diff --git a/src/server_config_ts.c b/src/server_config_ts.c index 11fec832..d4004ddb 100644 --- a/src/server_config_ts.c +++ b/src/server_config_ts.c @@ -42,6 +42,7 @@ nc_server_config_get_certificate_bag(const struct lyd_node *node, struct nc_cert uint16_t i; const char *cbag_name; struct nc_truststore *ts; + const char *node_name = LYD_NAME(node); assert(node && cbag); @@ -53,7 +54,7 @@ nc_server_config_get_certificate_bag(const struct lyd_node *node, struct nc_cert } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a certificate-bag subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a certificate-bag subtree.", node_name); return 1; } @@ -86,6 +87,7 @@ nc_server_config_get_certificate(const struct lyd_node *node, struct nc_certific uint16_t i; const char *cert_name; struct nc_certificate_bag *cbag; + const char *node_name = LYD_NAME(node); assert(node && cert); @@ -101,7 +103,7 @@ nc_server_config_get_certificate(const struct lyd_node *node, struct nc_certific } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", node_name); return 1; } @@ -133,6 +135,7 @@ nc_server_config_get_public_key_bag(const struct lyd_node *node, struct nc_publi uint16_t i; const char *pbag_name; struct nc_truststore *ts; + const char *node_name = LYD_NAME(node); assert(node && pbag); @@ -144,7 +147,7 @@ nc_server_config_get_public_key_bag(const struct lyd_node *node, struct nc_publi } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a public-key-bag subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a public-key-bag subtree.", node_name); return 1; } @@ -177,6 +180,7 @@ nc_server_config_get_public_key(const struct lyd_node *node, struct nc_public_ke uint16_t i; const char *pkey_name; struct nc_public_key_bag *pbag; + const char *node_name = LYD_NAME(node); assert(node && pkey); @@ -196,7 +200,7 @@ nc_server_config_get_public_key(const struct lyd_node *node, struct nc_public_ke } if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", LYD_NAME(node)); + ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", node_name); return 1; } @@ -215,32 +219,18 @@ nc_server_config_get_public_key(const struct lyd_node *node, struct nc_public_ke return 1; } -static void -nc_server_config_ts_del_cert_data(struct nc_certificate *cert) -{ - free(cert->data); - cert->data = NULL; -} - -static void -nc_server_config_ts_del_public_key_base64(struct nc_public_key *pkey) -{ - free(pkey->data); - pkey->data = NULL; -} - static void nc_server_config_ts_del_certificate(struct nc_certificate_bag *cbag, struct nc_certificate *cert) { free(cert->name); - cert->name = NULL; - - nc_server_config_ts_del_cert_data(cert); + free(cert->data); cbag->cert_count--; - if (cbag->cert_count == 0) { + if (!cbag->cert_count) { free(cbag->certs); cbag->certs = NULL; + } else if (cert != &cbag->certs[cbag->cert_count]) { + memcpy(cert, &cbag->certs[cbag->cert_count], sizeof *cbag->certs); } } @@ -248,14 +238,14 @@ static void nc_server_config_ts_del_public_key(struct nc_public_key_bag *pbag, struct nc_public_key *pkey) { free(pkey->name); - pkey->name = NULL; - - nc_server_config_ts_del_public_key_base64(pkey); + free(pkey->data); pbag->pubkey_count--; - if (pbag->pubkey_count == 0) { + if (!pbag->pubkey_count) { free(pbag->pubkeys); pbag->pubkeys = NULL; + } else if (pkey != &pbag->pubkeys[pbag->pubkey_count]) { + memcpy(pkey, &pbag->pubkeys[pbag->pubkey_count], sizeof *pbag->pubkeys); } } @@ -266,7 +256,6 @@ nc_server_config_ts_del_certificate_bag(struct nc_certificate_bag *cbag) struct nc_truststore *ts = &server_opts.truststore; free(cbag->name); - cbag->name = NULL; cert_count = cbag->cert_count; for (i = 0; i < cert_count; i++) { @@ -274,9 +263,11 @@ nc_server_config_ts_del_certificate_bag(struct nc_certificate_bag *cbag) } ts->cert_bag_count--; - if (ts->cert_bag_count == 0) { + if (!ts->cert_bag_count) { free(ts->cert_bags); ts->cert_bags = NULL; + } else if (cbag != &ts->cert_bags[ts->cert_bag_count]) { + memcpy(cbag, &ts->cert_bags[ts->cert_bag_count], sizeof *ts->cert_bags); } } @@ -287,7 +278,6 @@ nc_server_config_ts_del_public_key_bag(struct nc_public_key_bag *pbag) struct nc_truststore *ts = &server_opts.truststore; free(pbag->name); - pbag->name = NULL; pubkey_count = pbag->pubkey_count; for (i = 0; i < pubkey_count; i++) { @@ -295,9 +285,11 @@ nc_server_config_ts_del_public_key_bag(struct nc_public_key_bag *pbag) } ts->pub_bag_count--; - if (ts->pub_bag_count == 0) { + if (!ts->pub_bag_count) { free(ts->pub_bags); ts->pub_bags = NULL; + } else if (pbag != &ts->pub_bags[ts->pub_bag_count]) { + memcpy(pbag, &ts->pub_bags[ts->pub_bag_count], sizeof *ts->pub_bags); } } @@ -429,7 +421,7 @@ nc_server_config_ts_cert_data(const struct lyd_node *node, NC_OPERATION op) return 1; } - nc_server_config_ts_del_cert_data(cert); + free(cert->data); cert->data = strdup(lyd_get_value(node)); if (!cert->data) { ERRMEM; @@ -517,7 +509,7 @@ nc_server_config_ts_public_key(const struct lyd_node *node, NC_OPERATION op) } /* replace the public key */ - nc_server_config_ts_del_public_key_base64(pkey); + free(pkey->data); pkey->data = strdup(lyd_get_value(node)); if (!pkey->data) { ERRMEM; @@ -558,50 +550,34 @@ int nc_server_config_parse_truststore(const struct lyd_node *node, NC_OPERATION op) { const char *name = LYD_NAME(node); + int ret = 0; if (!strcmp(name, "truststore")) { - if (nc_server_config_ts_truststore(node, op)) { - goto error; - } + ret = nc_server_config_ts_truststore(node, op); } else if (!strcmp(name, "certificate-bags")) { - if (nc_server_config_ts_certificate_bags(node, op)) { - goto error; - } + ret = nc_server_config_ts_certificate_bags(node, op); } else if (!strcmp(name, "certificate-bag")) { - if (nc_server_config_ts_certificate_bag(node, op)) { - goto error; - } + ret = nc_server_config_ts_certificate_bag(node, op); } else if (!strcmp(name, "certificate")) { - if (nc_server_config_ts_certificate(node, op)) { - goto error; - } + ret = nc_server_config_ts_certificate(node, op); } else if (!strcmp(name, "cert-data")) { - if (nc_server_config_ts_cert_data(node, op)) { - goto error; - } + ret = nc_server_config_ts_cert_data(node, op); } else if (!strcmp(name, "public-key-bags")) { - if (nc_server_config_ts_public_key_bags(node, op)) { - goto error; - } + ret = nc_server_config_ts_public_key_bags(node, op); } else if (!strcmp(name, "public-key-bag")) { - if (nc_server_config_ts_public_key_bag(node, op)) { - goto error; - } + ret = nc_server_config_ts_public_key_bag(node, op); } else if (!strcmp(name, "public-key")) { - if (nc_server_config_ts_public_key(node, op)) { - goto error; - } + ret = nc_server_config_ts_public_key(node, op); } else if (!strcmp(name, "public-key-format")) { - if (nc_server_config_ts_public_key_format(node, op)) { - goto error; - } + ret = nc_server_config_ts_public_key_format(node, op); } - return 0; + if (ret) { + ERR(NULL, "Configuring (%s) failed.", name); + return 1; + } -error: - ERR(NULL, "Configuring (%s) failed.", name); - return 1; + return 0; } int From df3734f0ff2ecfd01a64c446b29e1f3e9f63de5d Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 12 Oct 2023 16:29:17 +0200 Subject: [PATCH 087/134] session server tls BUGFIX ctn endpt reference fix --- src/server_config.c | 1 - src/session_server_tls.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index c5e68e10..56b03dc3 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -224,7 +224,6 @@ nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client return 1; } - /* gets the ch_endpt struct based on node's location in the YANG data tree */ static int nc_server_config_get_ch_endpt(const struct lyd_node *node, struct nc_ch_endpt **ch_endpt) diff --git a/src/session_server_tls.c b/src/session_server_tls.c index 5f5c6ea5..a48ae452 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -312,7 +312,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * return -1; } - if (!session || !ctn_first || !cert) { + if (!session || !cert) { free(buf); return -1; } From 4d2e68615ec0bb9bf1ff035454a1663c46d9ef52 Mon Sep 17 00:00:00 2001 From: Roytak Date: Wed, 18 Oct 2023 14:30:22 +0200 Subject: [PATCH 088/134] config UPDATE rename config_new and del some funcs --- CMakeLists.txt | 6 +- doc/libnetconf.doc | 282 ++-- examples/server.c | 6 +- src/config_new_ssh.c | 1334 ------------------- src/config_new_tls.c | 1385 -------------------- src/server_config.c | 7 +- src/server_config.h | 966 +------------- src/{config_new.c => server_config_util.c} | 236 ++-- src/{config_new.h => server_config_util.h} | 67 +- src/server_config_util_ssh.c | 691 ++++++++++ src/server_config_util_tls.c | 584 +++++++++ tests/CMakeLists.txt | 4 +- tests/test_auth.c | 15 +- tests/test_ch.c | 24 +- tests/test_config_new.c | 213 --- tests/test_crl.c | 30 +- tests/test_ec.c | 10 +- tests/test_ed25519.c | 6 +- tests/test_endpt_share_clients.c | 28 +- tests/test_init_destroy_client.c | 2 + tests/test_ks_ts.c | 38 +- tests/test_replace.c | 12 +- tests/test_runtime_changes.c | 123 +- tests/test_tls.c | 18 +- tests/test_two_channels.c | 8 +- tests/test_unix_socket.c | 6 +- 26 files changed, 1774 insertions(+), 4327 deletions(-) delete mode 100644 src/config_new_ssh.c delete mode 100644 src/config_new_tls.c rename src/{config_new.c => server_config_util.c} (79%) rename src/{config_new.h => server_config_util.h} (65%) create mode 100644 src/server_config_util_ssh.c create mode 100644 src/server_config_util_tls.c delete mode 100644 tests/test_config_new.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bbc53f9..78ddc7aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,16 +111,16 @@ set(libsrc src/session_client.c src/session_server.c src/server_config.c - src/config_new.c) + src/server_config_util.c) if(ENABLE_SSH_TLS) list(APPEND libsrc src/session_client_ssh.c src/session_server_ssh.c - src/config_new_ssh.c + src/server_config_util_ssh.c src/session_client_tls.c src/session_server_tls.c - src/config_new_tls.c + src/server_config_util_tls.c src/server_config_ks.c src/server_config_ts.c) set(SSH_TLS_MACRO "#ifndef NC_ENABLED_SSH_TLS\n#define NC_ENABLED_SSH_TLS\n#endif") diff --git a/doc/libnetconf.doc b/doc/libnetconf.doc index 1b3e4a49..b58f96fc 100644 --- a/doc/libnetconf.doc +++ b/doc/libnetconf.doc @@ -18,7 +18,7 @@ * - Creating, sending, receiving, and replying to RPCs ([RFC 4741](https://tools.ietf.org/html/rfc4741), * [RFC 6241](https://tools.ietf.org/html/rfc6241)). * - Creating, sending and receiving NETCONF Event Notifications ([RFC 5277](https://tools.ietf.org/html/rfc5277)). - * - Configuring the NETCONF server based on the [ietf-netconf-server](https://datatracker.ietf.org/doc/html/draft-ietf-netconf-netconf-client-server-29) YANG module + * - Configuring the NETCONF server based on the [ietf-netconf-server](https://datatracker.ietf.org/doc/html/draft-ietf-netconf-netconf-client-server-29) YANG module. * * @section about-license License * @@ -219,7 +219,7 @@ * If you authenticated the connection using some tunneling software, you * can pass its file descriptors to _libnetconf2_ using ::nc_connect_inout(), * which will continue to establish a full NETCONF session. To connect locally - * on a UNIX socket avoiding all cryptography use ::nc_connect_unix(). + * on a UNIX socket avoiding all cryptography use ::nc_connect_unix(). * * Funtions List * ------------- @@ -301,8 +301,6 @@ * establish SSH or TLS transport or do it yourself and only provide the file * descriptors of the connection. * - * Server options can be only set, there are no getters. - * * To be able to accept any connections, the server must first be configured. * * Functions List @@ -318,17 +316,51 @@ * === * * To successfully accept connections on a server, you first need to configure it. - * There are two main ways to do this. The first is using __YANG data__ (see ::nc_server_config_setup_data). - * The second way is using __YANG diff__ (see ::nc_server_config_setup_diff). Optionally, you may do this - * by using __YANG data__ stored in a file (see ::nc_server_config_setup_path). - * However, to be able to configure the server, the required models first need to be implemented in the - * given libyang context using ::nc_server_config_load_modules(). - * - * If you wish not to create the __YANG data/diff__ yourself, you may use the library's functions to do this for you. - * For example ::nc_server_config_new_address_port() creates __YANG data__ corresponding to an SSH/TLS endpoint. - * The variant for UNIX socket is ::nc_server_config_new_unix_socket(). - * - * You may also create entries in the keystore or trustore. For example the asymmetric key and certificate entries + * The *libnetconf2* server natively supports the *ietf-netconf-server YANG* module. + * This allows for a bigger scaling and flexibility of the *NETCONF* server. + * By using *ietf-netconf-server YANG* data you can express network configurations + * in a standardized and hierarchical format, enabling you to define complex network + * structures with greater ease. + * + * The process of configuring a server is comprised of two steps. The first step is creating the + * configuration data and the second is applying it. The server supports two forms of the configuration + * data - *YANG data* and *YANG diff*. + * + * YANG data + * --------- + * + * Configuring the server using YANG data simplifies the management of network services. + * With YANG data, you build a structured configuration tree and apply it as a whole. + * This approach is user-friendly, allowing you to modify the configuration by adding or deleting nodes, + * and then deploying the updated configuration tree in its entirety, providing a way to manage your server's settings. + * The *libnetconf2* library exports API functions that can help you with creation or deletion of the *YANG* data. + * Using this approach requires you to have access to the current configuration whenever you want to make any changes. + * + * YANG diff + * --------- + * + * YANG diff, enriched with operation attributes, offers advanced configuration control. + * It empowers the user to make precise changes within the configuration tree, + * enabling operations like specific node deletions, additions, and modifications. + * On the other hand, unlike YANG data, YANG diff represents only a subtree of the + * changes expecting the whole configuration to be managed externally. + * For example this approach is used by the tool [sysrepo](https://www.sysrepo.org/). + * + * Usage + * ----- + * + * To be able to configure the server, the required models first need to be implemented. + * To do this, see ::nc_server_config_load_modules(). + * Not all of the *ietf-netconf-server* (and all of its associated modules) features are enabled. + * If you wish to see which features are enabled, extract them from the context after calling the mentioned function. + * + * If you wish not to create the __YANG data__ yourself, you may use the library's functions to do this for you. + * For example ::nc_server_config_add_address_port() creates __YANG data__ corresponding to an SSH/TLS endpoint. + * The variant for UNIX socket is ::nc_server_config_add_unix_socket(). You can then apply this data + * by calling ::nc_server_config_setup_data() (or ::nc_server_config_setup_diff() for diff). + * See *examples/server.c* for a simple example. + * + * You may also create entries in the keystore or truststore. For example the asymmetric key and certificate entries * in the keystore can be then referenced as the SSH hostkeys or TLS server certificates, respectively. * As for the truststore, you may create public key and certificate entries, which can then be used * as SSH user's public keys or TLS server's end-entity/trust-anchor certificates, respectively. @@ -343,66 +375,52 @@ * - ::nc_server_config_setup_data() * - ::nc_server_config_setup_path() * - * - ::nc_server_config_new_address_port() - * - ::nc_server_config_new_unix_socket() - * - ::nc_server_config_new_del_endpt() - * - ::nc_server_config_new_keystore_asym_key() - * - ::nc_server_config_new_del_keystore_asym_key() - * - ::nc_server_config_new_keystore_cert() - * - ::nc_server_config_new_del_keystore_cert() - * - ::nc_server_config_new_truststore_pubkey() - * - ::nc_server_config_new_del_truststore_pubkey() - * - ::nc_server_config_new_truststore_cert() - * - ::nc_server_config_new_del_truststore_cert() + * - ::nc_server_config_add_address_port() + * - ::nc_server_config_add_unix_socket() + * - ::nc_server_config_del_endpt() + * + * - ::nc_server_config_add_keystore_asym_key() + * - ::nc_server_config_del_keystore_asym_key() + * - ::nc_server_config_add_keystore_cert() + * - ::nc_server_config_del_keystore_cert() + * - ::nc_server_config_add_truststore_pubkey() + * - ::nc_server_config_del_truststore_pubkey() + * - ::nc_server_config_add_truststore_cert() + * - ::nc_server_config_del_truststore_cert() * * SSH * === * * To successfully accept an SSH session you must configure at least one host key. - * You may create this data yourself or by using ::nc_server_config_new_ssh_hostkey(). + * You may create this data yourself or by using ::nc_server_config_add_ssh_hostkey(). * * On top of that, each SSH endpoint can define it's own authorized clients and their authentication methods. - * For example if you wish to create an SSH user that can authenticate using a password, use ::nc_server_config_new_ssh_user_password(). + * For example if you wish to create an SSH user that can authenticate using a password, use ::nc_server_config_add_ssh_user_password(). * Another option for authorized clients is to reference another endpoint's clients, however be careful not to create a cyclic reference - * (see ::nc_config_new_ssh_endpoint_user_ref()). An authorized client MUST authenticate to all of it's configured authentication methods. + * (see ::nc_server_config_add_ssh_endpoint_client_ref()). An authorized client MUST authenticate to all of it's configured authentication methods. * - * There are also some other optional settings. + * There are also some other optional settings. Like setting the authentication attempts and timeout of an authorized client, or + * setting the encryption/key exchange/mac/public key algorithms, etc. * * Functions List * -------------- * * Available in __nc_server.h__. * - * - ::nc_server_config_new_ssh_hostkey() - * - ::nc_server_config_new_ssh_del_hostkey() - * - ::nc_server_config_new_ssh_keystore_ref() - * - ::nc_server_config_new_ssh_del_keystore_ref() - * - ::nc_server_config_new_ssh_auth_attempts() - * - ::nc_server_config_new_ssh_auth_timeout() - * - * - ::nc_server_config_new_ssh_user_pubkey() - * - ::nc_server_config_new_ssh_del_user_pubkey() - * - ::nc_server_config_new_ssh_user_password() - * - ::nc_server_config_new_ssh_del_user_password() - * - ::nc_server_config_new_ssh_user_none() - * - ::nc_server_config_new_ssh_del_user_none() - * - ::nc_server_config_new_ssh_user_interactive() - * - ::nc_server_config_new_ssh_del_user_interactive() - * - ::nc_server_config_new_ssh_del_user() - * - ::nc_server_config_new_ssh_truststore_ref() - * - ::nc_server_config_new_ssh_del_truststore_ref() - * - ::nc_config_new_ssh_endpoint_user_ref() - * - ::nc_config_new_ssh_del_endpoint_user_ref() - * - * - ::nc_server_config_new_ssh_host_key_algs() - * - ::nc_server_config_new_ssh_del_host_key_alg() - * - ::nc_server_config_new_ssh_key_exchange_algs() - * - ::nc_server_config_new_ssh_del_key_exchange_alg() - * - ::nc_server_config_new_ssh_encryption_algs() - * - ::nc_server_config_new_ssh_del_encryption_alg() - * - ::nc_server_config_new_ssh_mac_algs() - * - ::nc_server_config_new_ssh_del_mac_alg() - * + * - ::nc_server_config_add_ssh_hostkey() + * - ::nc_server_config_del_ssh_hostkey() + * - ::nc_server_config_add_ssh_auth_attempts() + * - ::nc_server_config_add_ssh_auth_timeout() + * + * - ::nc_server_config_add_ssh_user_pubkey() + * - ::nc_server_config_del_ssh_user_pubkey() + * - ::nc_server_config_add_ssh_user_password() + * - ::nc_server_config_del_ssh_user_password() + * - ::nc_server_config_add_ssh_user_interactive() + * - ::nc_server_config_del_ssh_user_interactive() + * - ::nc_server_config_del_ssh_user() + * - ::nc_server_config_add_ssh_endpoint_client_ref() + * - ::nc_server_config_del_ssh_endpoint_client_ref() * * TLS * === @@ -412,7 +430,7 @@ * options that TLS uses to derive usernames from client certificates. * * If you wish to listen on a TLS endpoint, you need to configure the endpoint's - * server certificate (see ::nc_server_config_new_tls_server_certificate()). + * server certificate (see ::nc_server_config_add_tls_server_cert()). * * To accept client certificates, they must first be considered trusted. * For each TLS endpoint you may configure two types of client certificates. @@ -421,50 +439,31 @@ * The second type are trust-anchor (certificate authority) certificates, * which carry over the trust (a chain of trust). * Another option is to reference another TLS endpoint's end-entity certificates, however be careful not to create a cyclic reference - * (see ::nc_config_new_tls_endpoint_client_ref()). + * (see ::nc_server_config_add_tls_endpoint_client_ref()). * * Then, from each trusted client certificate a username must be derived * for the NETCONF session. This is accomplished by finding a matching * _cert-to-name_ entry. * * There are some further options. For example you can configure the TLS - * version and ciphers to be used. You may also choose to use a Certificate - * Revoke List. There are three options, ::nc_server_config_new_tls_crl_path() - * attempts to get the list of revoked certificates from a file. ::nc_server_config_new_tls_crl_url() - * attempts to download the list from the given URL. Lastly, ::nc_server_config_new_tls_crl_cert_ext() - * attempts to download the CRLs from URLs specified in the extension fields of the configured certificates. + * version and ciphers to be used or you can even use a Certificate Revocation List. * * Functions List * -------------- * * Available in __nc_server.h__. * - * - ::nc_server_config_new_tls_server_certificate() - * - ::nc_server_config_new_tls_del_server_certificate() - * - ::nc_server_config_new_tls_keystore_ref() - * - ::nc_server_config_new_tls_del_keystore_ref() - * - * - ::nc_server_config_new_tls_client_certificate() - * - ::nc_server_config_new_tls_del_client_certificate() - * - ::nc_server_config_new_tls_client_cert_truststore_ref() - * - ::nc_server_config_new_tls_del_client_cert_truststore_ref() - * - ::nc_server_config_new_tls_client_ca() - * - ::nc_server_config_new_tls_del_client_ca() - * - ::nc_server_config_new_tls_client_ca_truststore_ref() - * - ::nc_server_config_new_tls_del_client_ca_truststore_ref() - * - ::nc_config_new_tls_endpoint_client_ref() - * - ::nc_config_new_tls_del_endpoint_client_ref() - * - ::nc_server_config_new_tls_ctn() - * - ::nc_server_config_new_tls_del_ctn() - * - * - ::nc_server_config_new_tls_version() - * - ::nc_server_config_new_tls_del_version() - * - ::nc_server_config_new_tls_ciphers() - * - ::nc_server_config_new_tls_del_cipher() - * - ::nc_server_config_new_tls_crl_path() - * - ::nc_server_config_new_tls_crl_url() - * - ::nc_server_config_new_tls_crl_cert_ext() - * - ::nc_server_config_new_tls_del_crl() + * - ::nc_server_config_add_tls_server_cert() + * - ::nc_server_config_del_tls_server_cert() + * + * - ::nc_server_config_add_tls_client_cert() + * - ::nc_server_config_del_tls_client_cert() + * - ::nc_server_config_add_tls_ca_cert() + * - ::nc_server_config_del_tls_ca_cert() + * - ::nc_server_config_add_tls_endpoint_client_ref() + * - ::nc_server_config_del_tls_endpoint_client_ref() + * - ::nc_server_config_add_tls_ctn() + * - ::nc_server_config_del_tls_ctn() * * FD * == @@ -499,68 +498,39 @@ * * Available in __nc_server.h__. * - * - ::nc_server_config_new_ch_address_port() - * - ::nc_server_config_new_del_ch_client() - * - ::nc_server_config_new_ch_del_endpt() - * - ::nc_server_config_new_ch_persistent() - * - ::nc_server_config_new_ch_period() - * - ::nc_server_config_new_ch_del_period() - * - ::nc_server_config_new_ch_anchor_time() - * - ::nc_server_config_new_ch_del_anchor_time() - * - ::nc_server_config_new_ch_idle_timeout() - * - ::nc_server_config_new_ch_del_idle_timeout() - * - ::nc_server_config_new_ch_reconnect_strategy() - * - ::nc_server_config_new_ch_del_reconnect_strategy() - * - * - ::nc_server_config_new_ch_ssh_hostkey() - * - ::nc_server_config_new_ch_ssh_del_hostkey() - * - ::nc_server_config_new_ch_ssh_keystore_ref() - * - ::nc_server_config_new_ch_ssh_del_keystore_ref() - * - ::nc_server_config_new_ch_ssh_auth_attempts() - * - ::nc_server_config_new_ch_ssh_auth_timeout() - * - ::nc_server_config_new_ch_ssh_user_pubkey() - * - ::nc_server_config_new_ch_ssh_del_user_pubkey() - * - ::nc_server_config_new_ch_ssh_user_password() - * - ::nc_server_config_new_ch_ssh_del_user_password() - * - ::nc_server_config_new_ch_ssh_user_none() - * - ::nc_server_config_new_ch_ssh_del_user_none() - * - ::nc_server_config_new_ch_ssh_user_interactive() - * - ::nc_server_config_new_ch_ssh_del_user_interactive() - * - ::nc_server_config_new_ch_ssh_del_user() - * - ::nc_server_config_new_ch_ssh_truststore_ref() - * - ::nc_server_config_new_ch_ssh_del_truststore_ref() - * - ::nc_server_config_new_ch_ssh_host_key_algs() - * - ::nc_server_config_new_ch_ssh_del_host_key_alg() - * - ::nc_server_config_new_ch_ssh_key_exchange_algs() - * - ::nc_server_config_new_ch_ssh_del_key_exchange_alg() - * - ::nc_server_config_new_ch_ssh_encryption_algs() - * - ::nc_server_config_new_ch_ssh_del_encryption_alg() - * - ::nc_server_config_new_ch_ssh_mac_algs() - * - ::nc_server_config_new_ch_ssh_del_mac_alg() - * - * - ::nc_server_config_new_ch_tls_server_certificate() - * - ::nc_server_config_new_ch_tls_del_server_certificate() - * - ::nc_server_config_new_ch_tls_keystore_ref() - * - ::nc_server_config_new_ch_tls_del_keystore_ref() - * - ::nc_server_config_new_ch_tls_client_certificate() - * - ::nc_server_config_new_ch_tls_del_client_certificate() - * - ::nc_server_config_new_ch_tls_client_cert_truststore_ref() - * - ::nc_server_config_new_ch_tls_del_client_cert_truststore_ref() - * - ::nc_server_config_new_ch_tls_client_ca() - * - ::nc_server_config_new_ch_tls_del_client_ca() - * - ::nc_server_config_new_ch_tls_client_ca_truststore_ref() - * - ::nc_server_config_new_ch_tls_del_client_ca_truststore_ref() - * - ::nc_server_config_new_ch_tls_ctn() - * - ::nc_server_config_new_ch_tls_del_ctn() - * - ::nc_server_config_new_ch_tls_version() - * - ::nc_server_config_new_ch_tls_del_version() - * - ::nc_server_config_new_ch_tls_ciphers() - * - ::nc_server_config_new_ch_tls_del_cipher() - * - ::nc_server_config_new_ch_tls_crl_path() - * - ::nc_server_config_new_ch_tls_crl_url() - * - ::nc_server_config_new_ch_tls_crl_cert_ext() - * - ::nc_server_config_new_ch_tls_del_crl() - * + * - ::nc_server_config_add_ch_address_port() + * - ::nc_server_config_del_ch_client() + * - ::nc_server_config_del_ch_endpt() + * - ::nc_server_config_add_ch_persistent() + * - ::nc_server_config_add_ch_period() + * - ::nc_server_config_del_ch_period() + * - ::nc_server_config_add_ch_anchor_time() + * - ::nc_server_config_del_ch_anchor_time() + * - ::nc_server_config_add_ch_idle_timeout() + * - ::nc_server_config_del_ch_idle_timeout() + * - ::nc_server_config_add_ch_reconnect_strategy() + * - ::nc_server_config_del_ch_reconnect_strategy() + * + * - ::nc_server_config_add_ch_ssh_hostkey() + * - ::nc_server_config_del_ch_ssh_hostkey() + * - ::nc_server_config_add_ch_ssh_auth_attempts() + * - ::nc_server_config_add_ch_ssh_auth_timeout() + * - ::nc_server_config_add_ch_ssh_user_pubkey() + * - ::nc_server_config_del_ch_ssh_user_pubkey() + * - ::nc_server_config_add_ch_ssh_user_password() + * - ::nc_server_config_del_ch_ssh_user_password() + * - ::nc_server_config_add_ch_ssh_user_interactive() + * - ::nc_server_config_del_ch_ssh_user_interactive() + * - ::nc_server_config_del_ch_ssh_user() + * + * - ::nc_server_config_add_ch_tls_server_cert() + * - ::nc_server_config_del_ch_tls_server_cert() + * - ::nc_server_config_add_ch_tls_client_cert() + * - ::nc_server_config_del_ch_tls_client_cert() + * - ::nc_server_config_add_ch_tls_ca_cert() + * - ::nc_server_config_del_ch_tls_ca_cert() + * - ::nc_server_config_add_ch_tls_ctn() + * - ::nc_server_config_del_ch_tls_ctn() * * Connecting And Cleanup * ====================== @@ -684,7 +654,7 @@ * To free up some resources, it is possible to adjust the maximum idle period * of a session before it is disconnected. In _Call Home_, for both a persistent * and periodic connection can this idle timeout be specified separately for each - * client using corresponding functions. Unlike other timeouts, the idle timeout + * client by configuring the server. Unlike other timeouts, the idle timeout * can only be set via applying configuration data. * * Lastly, SSH user authentication timeout can be also modified. It is the time diff --git a/examples/server.c b/examples/server.c index c0ce0a89..88254c88 100644 --- a/examples/server.c +++ b/examples/server.c @@ -238,19 +238,19 @@ init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_T /* this is where the YANG configuration data gets generated, * start by creating hostkey configuration data */ - rc = nc_server_config_new_ssh_hostkey(*context, "endpt", "hostkey", hostkey_path, NULL, &config); + rc = nc_server_config_add_ssh_hostkey(*context, "endpt", "hostkey", hostkey_path, NULL, &config); if (rc) { ERR_MSG_CLEANUP("Error creating new hostkey configuration data.\n"); } /* create address and port configuration data */ - rc = nc_server_config_new_address_port(*context, "endpt", NC_TI_LIBSSH, SSH_ADDRESS, SSH_PORT, &config); + rc = nc_server_config_add_address_port(*context, "endpt", NC_TI_LIBSSH, SSH_ADDRESS, SSH_PORT, &config); if (rc) { ERR_MSG_CLEANUP("Error creating new address and port configuration data.\n"); } /* create client authentication configuration data */ - rc = nc_server_config_new_ssh_user_password(*context, "endpt", SSH_USERNAME, SSH_PASSWORD, &config); + rc = nc_server_config_add_ssh_user_password(*context, "endpt", SSH_USERNAME, SSH_PASSWORD, &config); if (rc) { ERR_MSG_CLEANUP("Error creating client authentication configuration data.\n"); } diff --git a/src/config_new_ssh.c b/src/config_new_ssh.c deleted file mode 100644 index a61dd424..00000000 --- a/src/config_new_ssh.c +++ /dev/null @@ -1,1334 +0,0 @@ -/** - * @file config_new_ssh.c - * @author Roman Janota - * @brief libnetconf2 server new SSH configuration creation functions - * - * @copyright - * Copyright (c) 2023 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 - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - -#include - -#include "compat.h" -#include "config.h" -#include "config_new.h" -#include "log_p.h" -#include "server_config.h" -#include "session_p.h" - -#if !defined (HAVE_CRYPT_R) -extern pthread_mutex_t crypt_lock; -#endif - -static int -_nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *tree_path, - const char *privkey_path, const char *pubkey_path, struct lyd_node **config) -{ - int ret = 0; - char *pubkey = NULL, *privkey = NULL; - NC_PRIVKEY_FORMAT privkey_type; - const char *privkey_format, *pubkey_format = "ietf-crypto-types:ssh-public-key-format"; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, privkey_path, config, 1); - - /* get the keys as a string from the given files */ - ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_SSH, &privkey, &privkey_type, &pubkey); - if (ret) { - ERR(NULL, "Getting keys from file(s) failed."); - goto cleanup; - } - - /* get privkey identityref value */ - privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type); - if (!privkey_format) { - ret = 1; - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/public-key-format", pubkey_format, config); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/public-key", pubkey, config); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/private-key-format", privkey_format, config); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/cleartext-private-key", privkey, config); - if (ret) { - goto cleanup; - } - - /* delete keystore choice nodes if present */ - ret = nc_config_new_check_delete(config, "%s/keystore-reference", tree_path); - if (ret) { - goto cleanup; - } - -cleanup: - free(privkey); - free(pubkey); - return ret; -} - -API int -nc_server_config_new_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 ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, privkey_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "server-identity/host-key[name='%s']/public-key", endpt_name, hostkey_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_ssh_hostkey(ctx, path, privkey_path, pubkey_path, config); - if (ret) { - ERR(NULL, "Creating new hostkey YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_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) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, privkey_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key", client_name, endpt_name, hostkey_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_ssh_hostkey(ctx, path, privkey_path, pubkey_path, config); - if (ret) { - ERR(NULL, "Creating new Call-Home hostkey YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ssh_del_hostkey(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, - struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - if (hostkey_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "server-identity/host-key[name='%s']", endpt_name, hostkey_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "server-identity/host-key", endpt_name); - } -} - -API int -nc_server_config_new_ch_ssh_del_hostkey(const char *client_name, const char *endpt_name, - const char *hostkey_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (hostkey_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']", client_name, endpt_name, hostkey_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key", client_name, endpt_name); - } -} - -API int -nc_server_config_new_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 ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, keystore_reference, config, 1); - - ret = nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" - "keystore-reference", endpt_name, hostkey_name); - if (ret) { - goto cleanup; - } - - /* delete inline definition nodes if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" - "inline-definition", endpt_name, hostkey_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_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) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, keystore_reference, config, 1); - - ret = nc_config_new_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); - if (ret) { - goto cleanup; - } - - /* delete inline definition nodes if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/inline-definition", client_name, endpt_name, hostkey_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_ssh_del_keystore_ref(const char *endpt_name, const char *hostkey_name, - struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" - "keystore-reference", endpt_name, hostkey_name); -} - -API int -nc_server_config_new_ch_ssh_del_keystore_ref(const char *client_name, const char *endpt_name, - const char *hostkey_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, hostkey_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); -} - -API int -nc_server_config_new_ssh_auth_attempts(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_attempts, - struct lyd_node **config) -{ - int ret = 0; - char *attempts_buf = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - /* uint to str */ - if (asprintf(&attempts_buf, "%u", auth_attempts) == -1) { - ERRMEM; - attempts_buf = NULL; - ret = 1; - goto cleanup; - } - - ret = nc_config_new_create(ctx, config, attempts_buf, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/libnetconf2-netconf-server:auth-attempts", endpt_name); - -cleanup: - free(attempts_buf); - return ret; -} - -API int -nc_server_config_new_ssh_auth_timeout(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_timeout, - struct lyd_node **config) -{ - int ret = 0; - char *timeout_buf = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - /* uint to str */ - if (asprintf(&timeout_buf, "%u", auth_timeout) == -1) { - ERRMEM; - timeout_buf = NULL; - ret = 1; - goto cleanup; - } - - ret = nc_config_new_create(ctx, config, timeout_buf, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/libnetconf2-netconf-server:auth-timeout", endpt_name); - -cleanup: - free(timeout_buf); - return ret; -} - -API int -nc_server_config_new_ch_ssh_auth_attempts(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - uint16_t auth_attempts, struct lyd_node **config) -{ - int ret = 0; - char *attempts_buf = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); - - /* uint to str */ - if (asprintf(&attempts_buf, "%u", auth_attempts) == -1) { - ERRMEM; - attempts_buf = NULL; - ret = 1; - goto cleanup; - } - - ret = nc_config_new_create(ctx, config, attempts_buf, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "libnetconf2-netconf-server:auth-attempts", client_name, endpt_name); - -cleanup: - free(attempts_buf); - return ret; -} - -API int -nc_server_config_new_ch_ssh_auth_timeout(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - uint16_t auth_timeout, struct lyd_node **config) -{ - int ret = 0; - char *timeout_buf = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); - - /* uint to str */ - if (asprintf(&timeout_buf, "%u", auth_timeout) == -1) { - ERRMEM; - timeout_buf = NULL; - ret = 1; - goto cleanup; - } - - ret = nc_config_new_create(ctx, config, timeout_buf, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "libnetconf2-netconf-server:auth-timeout", client_name, endpt_name); - -cleanup: - free(timeout_buf); - return ret; -} - -static int -_nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *tree_path, const char *pubkey_path, - struct lyd_node **config) -{ - int ret = 0; - char *pubkey = NULL; - const char *pubkey_format = "ietf-crypto-types:ssh-public-key-format"; - - /* get pubkey data */ - ret = nc_server_config_new_get_ssh_pubkey_file(pubkey_path, &pubkey); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "public-key-format", pubkey_format, config); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "public-key", pubkey, config); - if (ret) { - goto cleanup; - } - -cleanup: - free(pubkey); - return ret; -} - -API int -nc_server_config_new_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) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pubkey_name, pubkey_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" - "public-key[name='%s']", endpt_name, user_name, pubkey_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_ssh_user_pubkey(ctx, path, pubkey_path, config); - if (ret) { - ERR(NULL, "Creating new SSH user's public key failed."); - goto cleanup; - } - - /* delete truststore reference if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/truststore-reference", - endpt_name, user_name); - if (ret) { - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_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) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pubkey_name, pubkey_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, - endpt_name, user_name, pubkey_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_ssh_user_pubkey(ctx, path, pubkey_path, config); - if (ret) { - ERR(NULL, "Creating new CH SSH user's public key failed."); - goto cleanup; - } - - /* delete truststore reference if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" - "public-keys/truststore-reference", client_name, endpt_name, user_name); - if (ret) { - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ssh_del_user_pubkey(const char *endpt_name, const char *user_name, - const char *pubkey_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - - if (pubkey_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" - "public-key[name='%s']", endpt_name, user_name, pubkey_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" - "public-key", endpt_name, user_name); - } -} - -API int -nc_server_config_new_ch_ssh_del_user_pubkey(const char *client_name, const char *endpt_name, - const char *user_name, const char *pubkey_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - - if (pubkey_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, - endpt_name, user_name, pubkey_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/inline-definition/public-key", client_name, - endpt_name, user_name); - } -} - -static int -_nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *tree_path, - const char *password, struct lyd_node **config) -{ - int ret = 0; - char *hashed_pw = NULL; - const char *salt = "$6$idsizuippipk$"; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, password, config, 1); - -#ifdef HAVE_CRYPT_R - struct crypt_data cdata; -#endif - -#ifdef HAVE_CRYPT_R - cdata.initialized = 0; - hashed_pw = crypt_r(password, salt, &data); -#else - pthread_mutex_lock(&crypt_lock); - hashed_pw = crypt(password, salt); - pthread_mutex_unlock(&crypt_lock); -#endif - - if (!hashed_pw) { - ERR(NULL, "Hashing password failed (%s).", strerror(errno)); - ret = 1; - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "password", hashed_pw, config); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, const char *password, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, password, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/users/user[name='%s']", endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_ssh_user_password(ctx, path, password, config); - if (ret) { - ERR(NULL, "Creating new SSH user's password failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_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) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, password, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']", client_name, endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_ssh_user_password(ctx, path, password, config); - if (ret) { - ERR(NULL, "Creating new CH SSH user's password failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ssh_del_user_password(const char *endpt_name, const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/password", endpt_name, user_name); -} - -API int -nc_server_config_new_ch_ssh_del_user_password(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/password", client_name, endpt_name, user_name); -} - -API int -nc_server_config_new_ssh_user_none(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, config, 1); - - return nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/none", endpt_name, user_name); -} - -API int -nc_server_config_new_ch_ssh_user_none(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, config, 1); - - return nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/none", client_name, endpt_name, user_name); -} - -API int -nc_server_config_new_ssh_del_user_none(const char *endpt_name, const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/none", endpt_name, user_name); -} - -API int -nc_server_config_new_ch_ssh_del_user_none(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/none", client_name, endpt_name, user_name); -} - -static int -_nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *tree_path, - const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) -{ - int ret = 0; - - ret = nc_config_new_create_append(ctx, tree_path, "pam-config-file-name", pam_config_name, config); - if (ret) { - goto cleanup; - } - - if (pam_config_dir) { - ret = nc_config_new_create_append(ctx, tree_path, "pam-config-file-dir", pam_config_dir, config); - if (ret) { - goto cleanup; - } - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pam_config_name, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/users/user[name='%s']/" - "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); - if (ret) { - ERR(NULL, "Creating new SSH user's keyboard interactive nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ch_ssh_user_interactive(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pam_config_name, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" - "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); - if (ret) { - ERR(NULL, "Creating new CH SSH user's keyboard interactive nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ssh_del_user_interactive(const char *endpt_name, const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/" - "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name); -} - -API int -nc_server_config_new_ch_ssh_del_user_interactive(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" - "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name); -} - -API int -nc_server_config_new_ssh_del_user(const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (user_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']", endpt_name, user_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user", endpt_name); - } -} - -API int -nc_server_config_new_ch_ssh_del_user(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (user_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']", client_name, - endpt_name, user_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user", client_name, endpt_name); - } -} - -API int -nc_config_new_ssh_endpoint_user_ref(const struct ly_ctx *ctx, const char *endpt_name, - const char *referenced_endpt, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); - - return nc_config_new_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); -} - -API int -nc_config_new_ssh_del_endpoint_user_ref(const char *endpt_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); -} - -API int -nc_server_config_new_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 ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, truststore_reference, config, 1); - - ret = nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" - "truststore-reference", endpt_name, user_name); - if (ret) { - goto cleanup; - } - - /* delete inline definition nodes if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition", - endpt_name, user_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_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) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, truststore_reference, config, 1); - - ret = nc_config_new_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); - if (ret) { - goto cleanup; - } - - /* delete inline definition nodes if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" - "public-keys/inline-definition", client_name, endpt_name, user_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_ssh_del_truststore_ref(const char *endpt_name, const char *user_name, - struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" - "truststore-reference", endpt_name, user_name); -} - -API int -nc_server_config_new_ch_ssh_del_truststore_ref(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); -} - -static int -nc_server_config_new_ssh_transport_params_prep(const struct ly_ctx *ctx, const char *client_name, - const char *endpt_name, struct lyd_node *config, struct lyd_node **new_tree, struct lyd_node **alg_tree) -{ - int ret = 0; - char *tree_path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, new_tree, alg_tree, 1); - - /* prepare path */ - if (client_name) { - /* ch */ - ret = asprintf(&tree_path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/transport-params", client_name, endpt_name); - } else { - /* listen */ - ret = asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params", endpt_name); - } - if (ret == -1) { - ERRMEM; - tree_path = NULL; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path2(config, ctx, tree_path, NULL, 0, 0, LYD_NEW_PATH_UPDATE, new_tree, alg_tree); - if (ret) { - ERR(NULL, "Creating new path to transport-params failed."); - goto cleanup; - } - - if (!*alg_tree) { - /* no new nodes added, set the path correctly for adding child nodes later */ - ret = lyd_find_path(config, tree_path, 0, alg_tree); - if (ret) { - goto cleanup; - } - } - -cleanup: - free(tree_path); - return ret; -} - -static int -nc_server_config_new_ssh_transport_params_create(const struct ly_ctx *ctx, NC_ALG_TYPE alg_type, int alg_count, va_list ap, - struct lyd_node *tree) -{ - int i, ret = 0; - char *alg, *alg_ident; - const char *module, *alg_path, *old_path; - struct lyd_node *old = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, tree, 1); - - /* get the correct module with the indentity base and the path in the ietf-netconf-server module */ - switch (alg_type) { - case NC_ALG_HOSTKEY: - module = "iana-ssh-public-key-algs"; - alg_path = "host-key/host-key-alg"; - old_path = "host-key"; - break; - case NC_ALG_KEY_EXCHANGE: - module = "iana-ssh-key-exchange-algs"; - alg_path = "key-exchange/key-exchange-alg"; - old_path = "key-exchange"; - break; - case NC_ALG_ENCRYPTION: - module = "iana-ssh-encryption-algs"; - alg_path = "encryption/encryption-alg"; - old_path = "encryption"; - break; - case NC_ALG_MAC: - module = "iana-ssh-mac-algs"; - alg_path = "mac/mac-alg"; - old_path = "mac"; - break; - default: - ret = 1; - ERR(NULL, "Unknown algorithm type."); - goto cleanup; - } - - /* delete all older algorithms (if any) se they can be replaced by the new ones */ - lyd_find_path(tree, old_path, 0, &old); - if (old) { - lyd_free_tree(old); - } - - for (i = 0; i < alg_count; i++) { - alg = va_arg(ap, char *); - - if (asprintf(&alg_ident, "%s:%s", module, alg) == -1) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create the leaf list */ - ret = lyd_new_path(tree, ctx, alg_path, alg_ident, 0, NULL); - if (ret) { - ERR(NULL, "Creating new algorithm leaf-list failed."); - free(alg_ident); - goto cleanup; - } - - free(alg_ident); - alg_ident = NULL; - } - -cleanup: - return ret; -} - -static int -nc_server_config_new_ssh_transport_params(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - NC_ALG_TYPE alg_type, int alg_count, va_list ap, struct lyd_node **config) -{ - int ret = 0; - struct lyd_node *new_tree, *alg_tree; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - /* prepare the tree for appending child nodes (the params) */ - ret = nc_server_config_new_ssh_transport_params_prep(ctx, client_name, endpt_name, *config, &new_tree, &alg_tree); - if (ret) { - goto cleanup; - } - - if (!*config) { - *config = new_tree; - } - - /* create the child nodes */ - ret = nc_server_config_new_ssh_transport_params_create(ctx, alg_type, alg_count, ap, alg_tree); - if (ret) { - goto cleanup; - } - - /* add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new hostkey algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_new_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new hostkey algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_new_ssh_del_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/host-key/" - "host-key-alg[.='iana-ssh-public-key-algs:%s']", endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/host-key", endpt_name); - } -} - -API int -nc_server_config_new_ch_ssh_del_host_key_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key/" - "host-key-alg[.='iana-ssh-public-key-algs:%s']", client_name, endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key", client_name, endpt_name); - } -} - -API int -nc_server_config_new_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new key exchange algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_new_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new key exchange algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_new_ssh_del_key_exchange_alg(const char *endpt_name, const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/key-exchange/" - "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/key-exchange", endpt_name); - } -} - -API int -nc_server_config_new_ch_ssh_del_key_exchange_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange/" - "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", client_name, endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange", client_name, endpt_name); - } -} - -API int -nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new encryption algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_new_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new encryption algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_new_ssh_del_encryption_alg(const char *endpt_name, const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/encryption/" - "encryption-alg[.='iana-ssh-encryption-algs:%s']", endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/encryption", endpt_name); - } -} - -API int -nc_server_config_new_ch_ssh_del_encryption_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption/" - "encryption-alg[.='iana-ssh-encryption-algs:%s']", client_name, endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption", client_name, endpt_name); - } -} - -API int -nc_server_config_ssh_new_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_new_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_MAC, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new mac algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_new_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_new_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_MAC, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new mac algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_new_ssh_del_mac_alg(const char *endpt_name, const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/mac/" - "mac-alg[.='iana-ssh-mac-algs:%s']", endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/mac", endpt_name); - } -} - -API int -nc_server_config_new_ch_ssh_del_mac_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (alg) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac/" - "mac-alg[.='iana-ssh-mac-algs:%s']", client_name, endpt_name, alg); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac", client_name, endpt_name); - } -} diff --git a/src/config_new_tls.c b/src/config_new_tls.c deleted file mode 100644 index 2fb7a7bd..00000000 --- a/src/config_new_tls.c +++ /dev/null @@ -1,1385 +0,0 @@ -/** - * @file config_new_tls.c - * @author Roman Janota - * @brief libnetconf2 TLS server new configuration creation functions - * - * @copyright - * Copyright (c) 2023 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 - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include - -#include - -#include "compat.h" -#include "config.h" -#include "config_new.h" -#include "log_p.h" -#include "server_config.h" -#include "session.h" -#include "session_p.h" - -static int -_nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *privkey_path, - const char *pubkey_path, const char *certificate_path, struct lyd_node **config) -{ - int ret = 0; - char *privkey = NULL, *pubkey = NULL, *cert = NULL; - NC_PRIVKEY_FORMAT privkey_type; - const char *privkey_format, *pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, privkey_path, certificate_path, config, 1); - - /* get the keys as a string from the given files */ - ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey, &privkey_type, &pubkey); - if (ret) { - ERR(NULL, "Getting keys from file(s) failed."); - goto cleanup; - } - - /* get cert data from file */ - ret = nc_server_config_new_read_certificate(certificate_path, &cert); - if (ret) { - ERR(NULL, "Getting certificate from file \"%s\" failed.", certificate_path); - goto cleanup; - } - - /* get privkey identityref value */ - privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type); - if (!privkey_format) { - ret = 1; - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/public-key-format", pubkey_format, config); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/public-key", pubkey, config); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/private-key-format", privkey_format, config); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/cleartext-private-key", privkey, config); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "inline-definition/cert-data", cert, config); - if (ret) { - goto cleanup; - } - - /* delete keystore if present */ - ret = nc_config_new_check_delete(config, "%s/keystore-reference", tree_path); - if (ret) { - goto cleanup; - } - -cleanup: - free(privkey); - free(pubkey); - free(cert); - return ret; -} - -API int -nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path, - const char *pubkey_path, const char *certificate_path, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, certificate_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_server_certificate(ctx, path, privkey_path, pubkey_path, - certificate_path, config); - if (ret) { - ERR(NULL, "Creating new TLS server certificate YANG data failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_tls_del_server_certificate(const char *endpt_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/inline-definition", endpt_name); -} - -API int -nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *privkey_path, const char *pubkey_path, const char *certificate_path, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, privkey_path, certificate_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" - "certificate", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_server_certificate(ctx, path, privkey_path, pubkey_path, - certificate_path, config); - if (ret) { - ERR(NULL, "Creating new CH TLS server certificate YANG data failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ch_tls_del_server_certificate(const char *client_name, const char *endpt_name, - struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" - "certificate/inline-definition", client_name, endpt_name); -} - -static int -_nc_server_config_new_tls_keystore_ref(const struct ly_ctx *ctx, const char *tree_path, const char *asym_key_ref, - const char *cert_ref, struct lyd_node **config) -{ - int ret = 0; - - /* create asymmetric key pair reference */ - ret = nc_config_new_create_append(ctx, tree_path, "keystore-reference/asymmetric-key", asym_key_ref, config); - if (ret) { - goto cleanup; - } - - /* create cert reference, this cert has to belong to the asym key */ - ret = nc_config_new_create_append(ctx, tree_path, "keystore-reference/certificate", cert_ref, config); - if (ret) { - goto cleanup; - } - - /* delete inline definition if present */ - ret = nc_config_new_check_delete(config, "%s/inline-definition", tree_path); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_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) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, asym_key_ref, cert_ref, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_keystore_ref(ctx, path, asym_key_ref, cert_ref, config); - if (ret) { - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_tls_del_keystore_ref(const char *endpt_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate/keystore-reference", endpt_name); -} - -API int -nc_server_config_new_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) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, asym_key_ref, cert_ref, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_keystore_ref(ctx, path, asym_key_ref, cert_ref, config); - if (ret) { - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ch_tls_del_keystore_ref(const char *client_name, const char *endpt_name, - struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate/" - "keystore-reference", client_name, endpt_name); -} - -static int -_nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char *tree_path, - const char *cert_path, struct lyd_node **config) -{ - int ret = 0; - char *cert = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, cert_path, config, 1); - - ret = nc_server_config_new_read_certificate(cert_path, &cert); - if (ret) { - ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path); - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "cert-data", cert, config); - if (ret) { - goto cleanup; - } - -cleanup: - free(cert); - return ret; -} - -API int -nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, - const char *cert_path, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ee-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_client_certificate(ctx, path, cert_path, config); - if (ret) { - ERR(NULL, "Creating new TLS client certificate YANG data failed."); - goto cleanup; - } - - /* delete truststore if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ee-certs/truststore-reference", endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_tls_del_client_certificate(const char *endpt_name, const char *cert_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (cert_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/client-authentication/ee-certs/inline-definition/" - "certificate[name='%s']", endpt_name, cert_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/client-authentication/ee-certs/inline-definition/" - "certificate", endpt_name); - } -} - -API int -nc_server_config_new_ch_tls_client_certificate(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) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" - "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_client_certificate(ctx, path, cert_path, config); - if (ret) { - ERR(NULL, "Creating new CH TLS client certificate YANG data failed."); - goto cleanup; - } - - /* delete truststore if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ee-certs/truststore-reference", client_name, endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ch_tls_del_client_certificate(const char *client_name, const char *endpt_name, - const char *cert_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (cert_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" - "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" - "inline-definition/certificate", client_name, endpt_name); - } -} - -API int -nc_server_config_new_tls_client_cert_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, - const char *cert_bag_ref, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1); - - ret = nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/client-authentication/ee-certs/truststore-reference", endpt_name); - if (ret) { - goto cleanup; - } - - /* delete inline definition if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/client-authentication/ee-certs/inline-definition", endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_tls_del_client_cert_truststore_ref(const char *endpt_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/client-authentication/ee-certs/truststore-reference", endpt_name); -} - -API int -nc_server_config_new_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) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_bag_ref, config, 1); - - ret = nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ee-certs/truststore-reference", client_name, endpt_name); - if (ret) { - goto cleanup; - } - - /* delete inline definition if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/" - "tls-server-parameters/client-authentication/ee-certs/inline-definition", client_name, endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_ch_tls_del_client_cert_truststore_ref(const char *client_name, const char *endpt_name, - struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ee-certs/truststore-reference", client_name, endpt_name); -} - -API int -nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, - const char *cert_path, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ca-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_client_certificate(ctx, path, cert_path, config); - if (ret) { - ERR(NULL, "Creating new TLS client certificate authority YANG data failed."); - goto cleanup; - } - - /* delete truststore if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ca-certs/truststore-reference", endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_tls_del_client_ca(const char *endpt_name, const char *cert_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (cert_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/client-authentication/ca-certs/inline-definition/" - "certificate[name='%s']", endpt_name, cert_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/client-authentication/ca-certs/inline-definition/" - "certificate", endpt_name); - } -} - -API int -nc_server_config_new_ch_tls_client_ca(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) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" - "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_client_certificate(ctx, path, cert_path, config); - if (ret) { - ERR(NULL, "Creating new CH TLS client certificate authority YANG data failed."); - goto cleanup; - } - - /* delete truststore if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ca-certs/truststore-reference", client_name, endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ch_tls_del_client_ca(const char *client_name, const char *endpt_name, - const char *cert_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (cert_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" - "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" - "inline-definition/certificate", client_name, endpt_name); - } -} - -API int -nc_server_config_new_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, - const char *cert_bag_ref, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1); - - ret = nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/client-authentication/ca-certs/truststore-reference", endpt_name); - if (ret) { - goto cleanup; - } - - /* delete inline definition if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/client-authentication/ca-certs/inline-definition", endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_tls_del_client_ca_truststore_ref(const char *endpt_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/client-authentication/ca-certs/truststore-reference", endpt_name); -} - -API int -nc_server_config_new_ch_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *client_name, - const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_bag_ref, config, 1); - - ret = nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ca-certs/truststore-reference", client_name, endpt_name); - if (ret) { - goto cleanup; - } - - /* delete inline definition if present */ - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ca-certs/inline-definition", client_name, endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_ch_tls_del_client_ca_truststore_ref(const char *client_name, const char *endpt_name, - struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ca-certs/truststore-reference", client_name, endpt_name); -} - -static const char * -nc_config_new_tls_maptype2str(NC_TLS_CTN_MAPTYPE map_type) -{ - switch (map_type) { - case NC_TLS_CTN_SPECIFIED: - return "ietf-x509-cert-to-name:specified"; - case NC_TLS_CTN_SAN_RFC822_NAME: - return "ietf-x509-cert-to-name:san-rfc822-name"; - case NC_TLS_CTN_SAN_DNS_NAME: - return "ietf-x509-cert-to-name:san-dns-name"; - case NC_TLS_CTN_SAN_IP_ADDRESS: - return "ietf-x509-cert-to-name:san-ip-address"; - case NC_TLS_CTN_SAN_ANY: - return "ietf-x509-cert-to-name:san-any"; - case NC_TLS_CTN_COMMON_NAME: - return "ietf-x509-cert-to-name:common-name"; - case NC_TLS_CTN_UNKNOWN: - default: - ERR(NULL, "Unknown CTN mapping type."); - return NULL; - } -} - -static int -_nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *tree_path, const char *fingerprint, - NC_TLS_CTN_MAPTYPE map_type, const char *name, struct lyd_node **config) -{ - int ret = 0; - const char *map; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, name, config, 1); - - if (fingerprint) { - /* optional */ - ret = nc_config_new_create_append(ctx, tree_path, "fingerprint", fingerprint, config); - if (ret) { - goto cleanup; - } - } - - /* get map str */ - map = nc_config_new_tls_maptype2str(map_type); - if (!map) { - ret = 1; - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "map-type", map, config); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "name", name, config); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_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) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, name, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/netconf-server-parameters/" - "client-identity-mappings/cert-to-name[id='%u']", endpt_name, id) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_ctn(ctx, path, fingerprint, map_type, name, config); - if (ret) { - ERR(NULL, "Creating new TLS cert-to-name YANG data failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_tls_del_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (id) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%u']", endpt_name, id); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "netconf-server-parameters/client-identity-mappings/cert-to-name", endpt_name); - } -} - -API int -nc_server_config_new_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) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, id, name, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" - "cert-to-name[id='%u']", client_name, endpt_name, id) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_ctn(ctx, path, fingerprint, map_type, name, config); - if (ret) { - ERR(NULL, "Creating new CH TLS cert-to-name YANG data failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ch_tls_del_ctn(const char *client_name, const char *endpt_name, - uint32_t id, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (id) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" - "cert-to-name[id='%u']", client_name, endpt_name, id); - } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" - "cert-to-name", client_name, endpt_name); - } -} - -static const char * -nc_config_new_tls_tlsversion2str(NC_TLS_VERSION version) -{ - switch (version) { - case NC_TLS_VERSION_10: - return "ietf-tls-common:tls10"; - case NC_TLS_VERSION_11: - return "ietf-tls-common:tls11"; - case NC_TLS_VERSION_12: - return "ietf-tls-common:tls12"; - case NC_TLS_VERSION_13: - return "ietf-tls-common:tls13"; - default: - ERR(NULL, "Unknown TLS version."); - return NULL; - } -} - -API int -nc_server_config_new_tls_version(const struct ly_ctx *ctx, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config) -{ - int ret = 0; - const char *version; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - /* version to str */ - version = nc_config_new_tls_tlsversion2str(tls_version); - if (!version) { - ret = 1; - goto cleanup; - } - - ret = nc_config_new_create(ctx, config, version, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "hello-params/tls-versions/tls-version", endpt_name); - if (ret) { - ERR(NULL, "Creating new YANG data nodes for TLS version failed."); - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_ch_tls_version(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config) -{ - int ret = 0; - const char *version; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); - - /* version to str */ - version = nc_config_new_tls_tlsversion2str(tls_version); - if (!version) { - ret = 1; - goto cleanup; - } - - ret = nc_config_new_create(ctx, config, version, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "hello-params/tls-versions/tls-version", client_name, endpt_name); - if (ret) { - ERR(NULL, "Creating new YANG data nodes for CH TLS version failed."); - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_tls_del_version(const char *endpt_name, NC_TLS_VERSION tls_version, struct lyd_node **config) -{ - int ret = 0; - const char *version; - - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - /* version to str */ - version = nc_config_new_tls_tlsversion2str(tls_version); - if (!version) { - ret = 1; - goto cleanup; - } - - ret = nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/hello-params/tls-versions/tls-version[.='%s']", endpt_name, version); - -cleanup: - return ret; -} - -API int -nc_server_config_new_ch_tls_del_version(const char *client_name, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config) -{ - int ret = 0; - const char *version; - - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - /* version to str */ - version = nc_config_new_tls_tlsversion2str(tls_version); - if (!version) { - ret = 1; - goto cleanup; - } - - ret = nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/" - "tls-server-parameters/hello-params/tls-versions/tls-version[.='%s']", client_name, endpt_name, version); - -cleanup: - return ret; -} - -static int -_nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *tree_path, - int cipher_count, va_list ap, struct lyd_node **config) -{ - int ret = 0, i; - struct lyd_node *old = NULL; - char *cipher = NULL, *cipher_ident = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, config, 1); - - /* delete all older algorithms (if any) se they can be replaced by the new ones */ - lyd_find_path(*config, tree_path, 0, &old); - if (old) { - lyd_free_tree(old); - } - - for (i = 0; i < cipher_count; i++) { - cipher = va_arg(ap, char *); - - if (asprintf(&cipher_ident, "iana-tls-cipher-suite-algs:%s", cipher) == -1) { - ERRMEM; - ret = 1; - goto cleanup; - } - - ret = nc_config_new_create_append(ctx, tree_path, "cipher-suite", cipher_ident, config); - if (ret) { - free(cipher_ident); - goto cleanup; - } - - free(cipher_ident); - cipher_ident = NULL; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int cipher_count, ...) -{ - int ret = 0; - va_list ap; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cipher_count, config, 1); - - va_start(ap, cipher_count); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/hello-params/cipher-suites", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_ciphers(ctx, path, cipher_count, ap, config); - if (ret) { - ERR(NULL, "Creating new TLS cipher YANG data nodes failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - free(path); - return ret; -} - -API int -nc_server_config_new_ch_tls_ciphers(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int cipher_count, ...) -{ - int ret = 0; - va_list ap; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cipher_count, config, 1); - - va_start(ap, cipher_count); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/tls/tls-server-parameters/hello-params/cipher-suites", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_ciphers(ctx, path, cipher_count, ap, config); - if (ret) { - ERR(NULL, "Creating new Call-Home TLS cipher YANG data nodes failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - free(path); - return ret; -} - -API int -nc_server_config_new_tls_del_cipher(const char *endpt_name, const char *cipher, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, cipher, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/hello-params/cipher-suites/" - "cipher-suite[.='iana-tls-cipher-suite-algs:%s']", endpt_name, cipher); -} - -API int -nc_server_config_new_ch_tls_del_cipher(const char *client_name, const char *endpt_name, - const char *cipher, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, cipher, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/hello-params/cipher-suites/" - "cipher-suite[.='iana-tls-cipher-suite-algs:%s']", client_name, endpt_name, cipher); -} - -static int -_nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *tree_path, - const char *crl_path, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, crl_path, config, 1); - - /* create the crl path node */ - ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-path", crl_path, config); - if (ret) { - goto cleanup; - } - - /* delete other choice nodes if they are present */ - ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-url", tree_path); - if (ret) { - goto cleanup; - } - ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, - const char *crl_path, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, crl_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_crl_path(ctx, path, crl_path, config); - if (ret) { - ERR(NULL, "Creating new CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ch_tls_crl_path(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *crl_path, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, crl_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_crl_path(ctx, path, crl_path, config); - if (ret) { - ERR(NULL, "Creating new CH CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -static int -_nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *tree_path, - const char *crl_url, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, crl_url, config, 1); - - /* create the crl path node */ - ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-url", crl_url, config); - if (ret) { - goto cleanup; - } - - /* delete other choice nodes if they are present */ - ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-path", tree_path); - if (ret) { - goto cleanup; - } - ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *crl_url, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, crl_url, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_crl_url(ctx, path, crl_url, config); - if (ret) { - ERR(NULL, "Creating new CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ch_tls_crl_url(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *crl_url, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, crl_url, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_crl_url(ctx, path, crl_url, config); - if (ret) { - ERR(NULL, "Creating new CH CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -static int -_nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *tree_path, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, config, 1); - - /* create the crl path node */ - ret = nc_config_new_create_append(ctx, tree_path, "libnetconf2-netconf-server:crl-cert-ext", NULL, config); - if (ret) { - goto cleanup; - } - - /* delete other choice nodes if they are present */ - ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-path", tree_path); - if (ret) { - goto cleanup; - } - ret = nc_config_new_check_delete(config, "%s/libnetconf2-netconf-server:crl-url", tree_path); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_crl_cert_ext(ctx, path, config); - if (ret) { - ERR(NULL, "Creating new CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_ch_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_new_tls_crl_cert_ext(ctx, path, config); - if (ret) { - ERR(NULL, "Creating new CH CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_new_tls_del_crl(const char *endpt_name, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-path", endpt_name); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-url", endpt_name); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-cert-ext", endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_new_ch_tls_del_crl(const char *client_name, const char *endpt_name, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-path", client_name, endpt_name); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-url", client_name, endpt_name); - if (ret) { - goto cleanup; - } - - ret = nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-cert-ext", client_name, endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_config_new_tls_endpoint_client_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); - - return nc_config_new_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); -} - -API int -nc_config_new_tls_del_endpoint_client_ref(const char *endpt_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); -} diff --git a/src/server_config.c b/src/server_config.c index 56b03dc3..328367ba 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -4415,15 +4415,14 @@ nc_server_config_load_modules(struct ly_ctx **ctx) * encrypted-passwords, hidden-symmetric-keys, encrypted-symmetric-keys, hidden-private-keys, encrypted-private-keys, * one-symmetric-key-format, one-asymmetric-key-format, symmetrically-encrypted-value-format, * asymmetrically-encrypted-value-format, cms-enveloped-data-format, cms-encrypted-data-format, - * cleartext-symmetric-keys - */ + * cleartext-symmetric-keys */ const char *ietf_crypto_types[] = {"cleartext-passwords", "cleartext-private-keys", NULL}; /* all features */ const char *ietf_tcp_common[] = {"keepalives-supported", NULL}; /* all features */ const char *ietf_tcp_server[] = {"tcp-server-keepalives", NULL}; - /* no proxy-connect, socks5-gss-api, socks5-username-password */ - const char *ietf_tcp_client[] = {"local-binding-supported", "tcp-client-keepalives", NULL}; + /* no proxy-connect, socks5-gss-api, socks5-username-password, local-binding-supported ? */ + const char *ietf_tcp_client[] = {"tcp-client-keepalives", NULL}; /* no ssh-x509-certs, public-key-generation */ const char *ietf_ssh_common[] = {"transport-params", NULL}; /* no ssh-server-keepalives and local-user-auth-hostbased */ diff --git a/src/server_config.h b/src/server_config.h index e3a8544c..e38c086c 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -20,7 +20,6 @@ extern "C" { #endif -#include #include #include @@ -71,7 +70,7 @@ int nc_server_config_load_modules(struct ly_ctx **ctx); * Context must already have implemented the required modules, see ::nc_server_config_load_modules(). * * @param[in] diff YANG diff belonging to either ietf-netconf-server, ietf-keystore or ietf-truststore modules. - * This diff should be validated. The top level node HAS to have an operation (create, replace, delete or none). + * The top level node HAS to have an operation (create, replace, delete or none). * @return 0 on success, 1 on error. */ int nc_server_config_setup_diff(const struct lyd_node *diff); @@ -84,7 +83,7 @@ int nc_server_config_setup_diff(const struct lyd_node *diff); * Context must already have implemented the required modules, see ::nc_server_config_load_modules(). * * @param[in] data YANG data belonging to either ietf-netconf-server, ietf-keystore or ietf-truststore modules. - * This data should be validated. No node can have an operation attribute. + * This data __must be valid__. No node can have an operation attribute. * @return 0 on success, 1 on error. */ int nc_server_config_setup_data(const struct lyd_node *data); @@ -97,6 +96,7 @@ int nc_server_config_setup_data(const struct lyd_node *data); * * @param[in] ctx libyang context. * @param[in] path Path to a file with ietf-netconf-server, ietf-keystore or ietf-truststore YANG data. + * This data __must be valid__. No node can have an operation attribute. * @return 0 on success, 1 on error. */ int nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path); @@ -116,7 +116,7 @@ int nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path); * 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_new_address_port(const struct ly_ctx *ctx, const char *endpt_name, NC_TRANSPORT_IMPL transport, +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 */ @@ -135,7 +135,7 @@ int nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endp * 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_new_unix_socket(const struct ly_ctx *ctx, const char *endpt_name, const char *path, +int nc_server_config_add_unix_socket(const struct ly_ctx *ctx, const char *endpt_name, const char *path, mode_t mode, uid_t uid, gid_t gid, struct lyd_node **config); /** @@ -146,7 +146,7 @@ int nc_server_config_new_unix_socket(const struct ly_ctx *ctx, const char *endpt * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **config); +int nc_server_config_del_endpt(const char *endpt_name, struct lyd_node **config); #ifdef NC_ENABLED_SSH_TLS @@ -164,7 +164,7 @@ int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **con * 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_new_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, const char *asym_key_name, +int nc_server_config_add_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, const char *asym_key_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config); /** @@ -175,7 +175,7 @@ int nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPOR * @param[in,out] config Configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_del_keystore_asym_key(const char *asym_key_name, struct lyd_node **config); +int nc_server_config_del_keystore_asym_key(const char *asym_key_name, struct lyd_node **config); /** * @brief Creates new YANG data nodes for a certificate in the keystore. @@ -193,7 +193,7 @@ int nc_server_config_new_del_keystore_asym_key(const char *asym_key_name, struct * 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_new_keystore_cert(const struct ly_ctx *ctx, const char *asym_key_name, const char *cert_name, +int nc_server_config_add_keystore_cert(const struct ly_ctx *ctx, const char *asym_key_name, const char *cert_name, const char *cert_path, struct lyd_node **config); /** @@ -206,12 +206,13 @@ int nc_server_config_new_keystore_cert(const struct ly_ctx *ctx, const char *asy * 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_new_del_keystore_cert(const char *asym_key_name, const char *cert_name, struct lyd_node **config); +int nc_server_config_del_keystore_cert(const char *asym_key_name, const char *cert_name, struct lyd_node **config); /** * @brief Creates new YANG data nodes for a public key in the truststore. * * @param[in] ctx libyang context. + * @param[in] ti Transport for which this key will be used, to be generated correctly. * @param[in] pub_bag_name Arbitrary identifier of the public key bag. * This name is used to reference the public keys in the bag. * If a public key bag with this name already exists, its contents will be changed. @@ -222,8 +223,8 @@ int nc_server_config_new_del_keystore_cert(const char *asym_key_name, const char * 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_new_truststore_pubkey(const struct ly_ctx *ctx, const char *pub_bag_name, const char *pubkey_name, - const char *pubkey_path, struct lyd_node **config); +int nc_server_config_add_truststore_pubkey(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, + const char *pub_bag_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config); /** * @brief Deletes a truststore's public key from the YANG data. @@ -234,7 +235,7 @@ int nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char * @param[in,out] config Configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_del_truststore_pubkey(const char *pub_bag_name, const char *pubkey_name, struct lyd_node **config); +int nc_server_config_del_truststore_pubkey(const char *pub_bag_name, const char *pubkey_name, struct lyd_node **config); /** * @brief Creates new YANG data nodes for a certificate in the truststore. @@ -250,7 +251,7 @@ int nc_server_config_new_del_truststore_pubkey(const char *pub_bag_name, const c * 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_new_truststore_cert(const struct ly_ctx *ctx, const char *cert_bag_name, const char *cert_name, +int nc_server_config_add_truststore_cert(const struct ly_ctx *ctx, const char *cert_bag_name, const char *cert_name, const char *cert_path, struct lyd_node **config); /** @@ -262,7 +263,7 @@ int nc_server_config_new_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_new_del_truststore_cert(const char *cert_bag_name, +int nc_server_config_del_truststore_cert(const char *cert_bag_name, const char *cert_name, struct lyd_node **config); /** @@ -293,7 +294,7 @@ int nc_server_config_new_del_truststore_cert(const char *cert_bag_name, * 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_new_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, +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); /** @@ -306,38 +307,9 @@ int nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt * @param[in,out] config Configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ssh_del_hostkey(const struct ly_ctx *ctx, const char *endpt_name, +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_new_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_new_ssh_del_keystore_ref(const char *endpt_name, const char *hostkey_name, - struct lyd_node **config); - /** * @brief Creates new YANG configuration data nodes for the maximum amount of failed SSH authentication attempts. * @@ -350,7 +322,7 @@ int nc_server_config_new_ssh_del_keystore_ref(const char *endpt_name, const char * 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_new_ssh_auth_attempts(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_attempts, +int nc_server_config_add_ssh_auth_attempts(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_attempts, struct lyd_node **config); /** @@ -365,7 +337,7 @@ int nc_server_config_new_ssh_auth_attempts(const struct ly_ctx *ctx, const char * 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_new_ssh_auth_timeout(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_timeout, +int nc_server_config_add_ssh_auth_timeout(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_timeout, struct lyd_node **config); /** @@ -383,7 +355,7 @@ int nc_server_config_new_ssh_auth_timeout(const struct ly_ctx *ctx, const char * * 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_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *endpt_name, +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); /** @@ -396,7 +368,7 @@ int nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *e * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ssh_del_user_pubkey(const char *endpt_name, const char *user_name, +int nc_server_config_del_ssh_user_pubkey(const char *endpt_name, const char *user_name, const char *pubkey_name, struct lyd_node **config); /** @@ -412,7 +384,7 @@ int nc_server_config_new_ssh_del_user_pubkey(const char *endpt_name, const char * 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_new_ssh_user_password(const struct ly_ctx *ctx, const char *endpt_name, +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); /** @@ -423,33 +395,7 @@ int nc_server_config_new_ssh_user_password(const struct ly_ctx *ctx, const char * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ssh_del_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 none 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,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_new_ssh_user_none(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config); - -/** - * @brief Deletes an SSH user's none authentication 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_new_ssh_del_user_none(const char *endpt_name, const char *user_name, +int nc_server_config_del_ssh_user_password(const char *endpt_name, const char *user_name, struct lyd_node **config); /** @@ -468,7 +414,7 @@ int nc_server_config_new_ssh_del_user_none(const char *endpt_name, const char *u * 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_new_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, +int nc_server_config_add_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config); /** @@ -479,7 +425,7 @@ int nc_server_config_new_ssh_user_interactive(const struct ly_ctx *ctx, const ch * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ssh_del_user_interactive(const char *endpt_name, const char *user_name, +int nc_server_config_del_ssh_user_interactive(const char *endpt_name, const char *user_name, struct lyd_node **config); /** @@ -491,38 +437,9 @@ int nc_server_config_new_ssh_del_user_interactive(const char *endpt_name, const * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ssh_del_user(const char *endpt_name, +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_new_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_new_ssh_del_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. * @@ -538,7 +455,7 @@ int nc_server_config_new_ssh_del_truststore_ref(const char *endpt_name, const ch * 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_config_new_ssh_endpoint_user_ref(const struct ly_ctx *ctx, const char *endpt_name, +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); /** @@ -548,123 +465,7 @@ int nc_config_new_ssh_endpoint_user_ref(const struct ly_ctx *ctx, const char *en * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_config_new_ssh_del_endpoint_user_ref(const char *endpt_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for host-key algorithms replacing any previous ones. - * - * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, - * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its host-key algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); - -/** - * @brief Deletes a hostkey algorithm from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] alg Optional algorithm to be deleted. - * If NULL, all of the hostkey algorithms 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_new_ssh_del_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for key exchange algorithms replacing any previous ones. - * - * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, - * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, - * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its key exchange algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); - -/** - * @brief Deletes a key exchange algorithm from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] alg Optional algorithm to be deleted. - * If NULL, all of the key exchange algorithms 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_new_ssh_del_key_exchange_alg(const char *endpt_name, const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for encryption algorithms replacing any previous ones. - * - * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc - * triple-des-cbc and none. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its encryption algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); - -/** - * @brief Deletes an encryption algorithm from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] alg Optional algorithm to be deleted. - * If NULL, all of the encryption algorithms 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_new_ssh_del_encryption_alg(const char *endpt_name, const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for mac algorithms replacing any previous ones. - * - * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its mac algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of mac algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_ssh_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); - -/** - * @brief Deletes a mac algorithm from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] alg Optional algorithm to be deleted. - * If NULL, all of the mac algorithms 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_new_ssh_del_mac_alg(const char *endpt_name, const char *alg, struct lyd_node **config); +int nc_server_config_del_ssh_endpoint_client_ref(const char *endpt_name, struct lyd_node **config); /** * @} SSH Server Configuration @@ -692,7 +493,7 @@ int nc_server_config_new_ssh_del_mac_alg(const char *endpt_name, const char *alg * 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_new_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path, +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 *certificate_path, struct lyd_node **config); /** @@ -702,31 +503,7 @@ int nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_tls_del_server_certificate(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_new_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. - */ -int nc_server_config_new_tls_del_keystore_ref(const char *endpt_name, struct lyd_node **config); +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 client's (end-entity) certificate. @@ -741,7 +518,7 @@ int nc_server_config_new_tls_del_keystore_ref(const char *endpt_name, struct lyd * 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_new_tls_client_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, +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); /** @@ -753,30 +530,7 @@ int nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_tls_del_client_certificate(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_new_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. - */ -int nc_server_config_new_tls_del_client_cert_truststore_ref(const char *endpt_name, struct lyd_node **config); +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 client certificate authority (trust-anchor) certificate. @@ -791,7 +545,7 @@ int nc_server_config_new_tls_del_client_cert_truststore_ref(const char *endpt_na * 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_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, +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); /** @@ -803,30 +557,7 @@ int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *end * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_tls_del_client_ca(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_new_tls_client_ca_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. - */ -int nc_server_config_new_tls_del_client_ca_truststore_ref(const char *endpt_name, struct lyd_node **config); +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, which will be a reference to another TLS endpoint's certificates. @@ -843,7 +574,7 @@ int nc_server_config_new_tls_del_client_ca_truststore_ref(const char *endpt_name * 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_config_new_tls_endpoint_client_ref(const struct ly_ctx *ctx, const char *endpt_name, +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); /** @@ -853,7 +584,7 @@ int nc_config_new_tls_endpoint_client_ref(const struct ly_ctx *ctx, const char * * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_config_new_tls_del_endpoint_client_ref(const char *endpt_name, struct lyd_node **config); +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. @@ -870,7 +601,7 @@ int nc_config_new_tls_del_endpoint_client_ref(const char *endpt_name, struct lyd * 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_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, uint32_t id, const char *fingerprint, +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); /** @@ -882,123 +613,7 @@ int nc_server_config_new_tls_ctn(const struct ly_ctx *ctx, const char *endpt_nam * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_tls_del_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a TLS version. - * - * @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] tls_version TLS version to be used. Call this multiple times to set - * the accepted versions of the TLS protocol and let the client and server negotiate - * the given version. - * @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_new_tls_version(const struct ly_ctx *ctx, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config); - -/** - * @brief Deletes a TLS version from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] tls_version TLS version to be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_tls_del_version(const char *endpt_name, NC_TLS_VERSION tls_version, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a TLS cipher. - * - * @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,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[in] cipher_count Number of following ciphers. - * @param[in] ... TLS ciphers. These ciphers MUST be in the format as listed in the - * iana-tls-cipher-suite-algs YANG model (lowercase and separated by dashes). Regardless - * of the TLS protocol version used, all of these ciphers will be tried and some of them - * might not be set (TLS handshake might fail then). For the list of supported ciphers see - * the OpenSSL documentation. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int cipher_count, ...); - -/** - * @brief Deletes a TLS cipher from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] cipher TLS cipher to be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_tls_del_cipher(const char *endpt_name, const char *cipher, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via a local file. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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] crl_path Path to a DER/PEM encoded CRL 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_new_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, - const char *crl_path, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via an URL. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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] crl_url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. - * The allowed protocols are all the protocols supported by CURL. - * @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_new_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *crl_url, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via certificate extensions. - * - * The chain of configured Certificate Authorities will be examined. For each certificate in this chain all the - * CRLs from the URLs specified in their extension fields CRL Distribution Points will be downloaded and used. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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,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_new_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config); - -/** - * @brief Deletes all the CRL nodes 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_new_tls_del_crl(const char *endpt_name, struct lyd_node **config); +int nc_server_config_del_tls_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config); /** * @} TLS Server Configuration @@ -1039,7 +654,7 @@ int nc_server_config_new_tls_del_crl(const char *endpt_name, struct lyd_node **c * 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_new_ch_address_port(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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 */ @@ -1052,7 +667,7 @@ int nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *c * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_del_ch_client(const char *client_name, struct lyd_node **config); +int nc_server_config_del_ch_client(const char *client_name, struct lyd_node **config); /** * @brief Deletes a Call Home endpoint from the YANG data. @@ -1063,7 +678,7 @@ int nc_server_config_new_ch_del_ch_client(const char *client_name, struct lyd_no * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt_name, struct lyd_node **config); +int nc_server_config_del_ch_endpt(const char *client_name, const char *endpt_name, struct lyd_node **config); /** * @brief Creates new YANG configuration data nodes for the Call Home persistent connection type. @@ -1077,7 +692,7 @@ int nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt * 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_new_ch_persistent(const struct ly_ctx *ctx, const char *client_name, struct lyd_node **config); +int nc_server_config_add_ch_persistent(const struct ly_ctx *ctx, const char *client_name, struct lyd_node **config); /** * @brief Creates new YANG configuration data nodes for the period parameter of the Call Home periodic connection type. @@ -1092,7 +707,7 @@ int nc_server_config_new_ch_persistent(const struct ly_ctx *ctx, const char *cli * 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_new_ch_period(const struct ly_ctx *ctx, const char *client_name, uint16_t period, +int nc_server_config_add_ch_period(const struct ly_ctx *ctx, const char *client_name, uint16_t period, struct lyd_node **config); /** @@ -1104,7 +719,7 @@ int nc_server_config_new_ch_period(const struct ly_ctx *ctx, const char *client_ * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_del_period(const char *client_name, struct lyd_node **config); +int nc_server_config_del_ch_period(const char *client_name, struct lyd_node **config); /** * @brief Creates new YANG configuration data nodes for the anchor time parameter of the Call Home periodic connection type. @@ -1119,7 +734,7 @@ int nc_server_config_new_ch_del_period(const char *client_name, struct lyd_node * 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_new_ch_anchor_time(const struct ly_ctx *ctx, const char *client_name, +int nc_server_config_add_ch_anchor_time(const struct ly_ctx *ctx, const char *client_name, const char *anchor_time, struct lyd_node **config); /** @@ -1129,7 +744,7 @@ int nc_server_config_new_ch_anchor_time(const struct ly_ctx *ctx, const char *cl * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_del_anchor_time(const char *client_name, struct lyd_node **config); +int nc_server_config_del_ch_anchor_time(const char *client_name, struct lyd_node **config); /** * @brief Creates new YANG configuration data nodes for the idle timeout parameter of the Call Home periodic connection type. @@ -1144,7 +759,7 @@ int nc_server_config_new_ch_del_anchor_time(const char *client_name, struct lyd_ * 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_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *client_name, +int nc_server_config_add_ch_idle_timeout(const struct ly_ctx *ctx, const char *client_name, uint16_t idle_timeout, struct lyd_node **config); /** @@ -1156,7 +771,7 @@ int nc_server_config_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *c * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_del_idle_timeout(const char *client_name, struct lyd_node **config); +int nc_server_config_del_ch_idle_timeout(const char *client_name, struct lyd_node **config); /** * @brief Creates new YANG configuration data nodes for the Call Home reconnect strategy. @@ -1171,7 +786,7 @@ int nc_server_config_new_ch_del_idle_timeout(const char *client_name, struct lyd * 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_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char *client_name, +int nc_server_config_add_ch_reconnect_strategy(const struct ly_ctx *ctx, const char *client_name, NC_CH_START_WITH start_with, uint16_t max_wait, uint8_t max_attempts, struct lyd_node **config); /** @@ -1183,7 +798,7 @@ int nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const c * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_del_reconnect_strategy(const char *client_name, struct lyd_node **config); +int nc_server_config_del_ch_reconnect_strategy(const char *client_name, struct lyd_node **config); /** * @} Call Home Server Configuration Functions @@ -1217,7 +832,7 @@ int nc_server_config_new_ch_del_reconnect_strategy(const char *client_name, stru * 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_new_ch_ssh_hostkey(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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); /** @@ -1230,43 +845,11 @@ int nc_server_config_new_ch_ssh_hostkey(const struct ly_ctx *ctx, const char *cl * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_ssh_del_hostkey(const char *client_name, const char *endpt_name, +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_new_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_new_ch_ssh_del_keystore_ref(const char *client_name, const char *endpt_name, - const char *hostkey_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for the maximum amount of failed Call Home SSH authentication attempts. + * @brief Creates new YANG configuration data nodes for the maximum amount of failed Call Home SSH authentication attempts. * * @param[in] ctx libyang context. * @param[in] client_name Arbitrary identifier of the Call Home client. @@ -1279,7 +862,7 @@ int nc_server_config_new_ch_ssh_del_keystore_ref(const char *client_name, const * 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_new_ch_ssh_auth_attempts(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +int nc_server_config_add_ch_ssh_auth_attempts(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, uint16_t auth_attempts, struct lyd_node **config); /** @@ -1296,7 +879,7 @@ int nc_server_config_new_ch_ssh_auth_attempts(const struct ly_ctx *ctx, const ch * 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_new_ch_ssh_auth_timeout(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +int nc_server_config_add_ch_ssh_auth_timeout(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, uint16_t auth_timeout, struct lyd_node **config); /** @@ -1316,7 +899,7 @@ int nc_server_config_new_ch_ssh_auth_timeout(const struct ly_ctx *ctx, const cha * 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_new_ch_ssh_user_pubkey(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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); /** @@ -1330,7 +913,7 @@ int nc_server_config_new_ch_ssh_user_pubkey(const struct ly_ctx *ctx, const char * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_ssh_del_user_pubkey(const char *client_name, const char *endpt_name, +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); /** @@ -1348,7 +931,7 @@ int nc_server_config_new_ch_ssh_del_user_pubkey(const char *client_name, const c * 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_new_ch_ssh_user_password(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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); /** @@ -1360,36 +943,7 @@ int nc_server_config_new_ch_ssh_user_password(const struct ly_ctx *ctx, const ch * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_ssh_del_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 none 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,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_new_ch_ssh_user_none(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 none authentication 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 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_new_ch_ssh_del_user_none(const char *client_name, const char *endpt_name, +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); /** @@ -1410,7 +964,7 @@ int nc_server_config_new_ch_ssh_del_user_none(const char *client_name, const cha * 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_new_ch_ssh_user_interactive(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config); /** @@ -1422,7 +976,7 @@ int nc_server_config_new_ch_ssh_user_interactive(const struct ly_ctx *ctx, const * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_ssh_del_user_interactive(const char *client_name, const char *endpt_name, +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); /** @@ -1434,173 +988,9 @@ int nc_server_config_new_ch_ssh_del_user_interactive(const char *client_name, co * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_ssh_del_user(const char *client_name, const char *endpt_name, +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_new_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_new_ch_ssh_del_truststore_ref(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for Call Home host-key algorithms replacing any previous ones. - * - * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, - * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. - * - * @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,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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); - -/** - * @brief Deletes a Call Home hostkey algorithm 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] alg Optional algorithm to be deleted. - * If NULL, all of the hostkey algorithms 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_new_ch_ssh_del_host_key_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for Call Home key exchange algorithms replacing any previous ones. - * - * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, - * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, - * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. - * - * @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,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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); - -/** - * @brief Deletes a Call Home key exchange algorithm 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] alg Optional algorithm to be deleted. - * If NULL, all of the key exchange algorithms 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_new_ch_ssh_del_key_exchange_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for Call Home encryption algorithms replacing any previous ones. - * - * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc - * triple-des-cbc and none. - * - * @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,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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); - -/** - * @brief Deletes a Call Home encryption algorithm 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] alg Optional algorithm to be deleted. - * If NULL, all of the encryption algorithms 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_new_ch_ssh_del_encryption_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for Call Home mac algorithms replacing any previous ones. - * - * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. - * - * @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,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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of mac algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); - -/** - * @brief Deletes a Call Home mac algorithm 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] alg Optional algorithm to be deleted. - * If NULL, all of the mac algorithms 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_new_ch_ssh_del_mac_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config); - /** * @} SSH Call Home Server Configuration */ @@ -1629,7 +1019,7 @@ int nc_server_config_new_ch_ssh_del_mac_alg(const char *client_name, const char * 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_new_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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 *certificate_path, struct lyd_node **config); /** @@ -1640,35 +1030,7 @@ int nc_server_config_new_ch_tls_server_certificate(const struct ly_ctx *ctx, con * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_tls_del_server_certificate(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_new_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. - */ -int nc_server_config_new_ch_tls_del_keystore_ref(const char *client_name, const char *endpt_name, +int nc_server_config_del_ch_tls_server_cert(const char *client_name, const char *endpt_name, struct lyd_node **config); /** @@ -1686,7 +1048,7 @@ int nc_server_config_new_ch_tls_del_keystore_ref(const char *client_name, const * 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_new_ch_tls_client_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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); /** @@ -1699,36 +1061,9 @@ int nc_server_config_new_ch_tls_client_certificate(const struct ly_ctx *ctx, con * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_tls_del_client_certificate(const char *client_name, const char *endpt_name, +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_new_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. - */ -int nc_server_config_new_ch_tls_del_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. * @@ -1744,7 +1079,7 @@ int nc_server_config_new_ch_tls_del_client_cert_truststore_ref(const char *clien * 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_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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); /** @@ -1757,36 +1092,9 @@ int nc_server_config_new_ch_tls_client_ca(const struct ly_ctx *ctx, const char * * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_tls_del_client_ca(const char *client_name, const char *endpt_name, +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_new_ch_tls_client_ca_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. - */ -int nc_server_config_new_ch_tls_del_client_ca_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. * @@ -1804,7 +1112,7 @@ int nc_server_config_new_ch_tls_del_client_ca_truststore_ref(const char *client_ * 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_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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); /** @@ -1817,141 +1125,9 @@ int nc_server_config_new_ch_tls_ctn(const struct ly_ctx *ctx, const char *client * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_ch_tls_del_ctn(const char *client_name, const char *endpt_name, +int nc_server_config_del_ch_tls_ctn(const char *client_name, const char *endpt_name, uint32_t id, struct lyd_node **config); -/** - * @brief Creates new YANG configuration data nodes for a Call Home TLS version. - * - * @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] tls_version TLS version to be used. Call this multiple times to set the accepted versions - * of the TLS protocol and let the client and server negotiate the given version. - * @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_new_ch_tls_version(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config); - -/** - * @brief Deletes a TLS version 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] tls_version TLS version to be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_ch_tls_del_version(const char *client_name, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home TLS cipher. - * - * @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,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[in] cipher_count Number of following ciphers. - * @param[in] ... TLS ciphers. These ciphers MUST be in the format as listed in the - * iana-tls-cipher-suite-algs YANG model (lowercase and separated by dashes). Regardless - * of the TLS protocol version used, all of these ciphers will be tried and some of them - * might not be set (TLS handshake might fail then). For the list of supported ciphers see - * the OpenSSL documentation. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_ch_tls_ciphers(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int cipher_count, ...); - -/** - * @brief Deletes a Call Home TLS cipher 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] cipher TLS cipher to be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_new_ch_tls_del_cipher(const char *client_name, const char *endpt_name, - const char *cipher, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via a local file. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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] crl_path Path to a DER/PEM encoded CRL 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_new_ch_tls_crl_path(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *crl_path, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via an URL. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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] crl_url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. - * The allowed protocols are all the protocols supported by CURL. - * @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_new_ch_tls_crl_url(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *crl_url, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via certificate extensions. - * - * The chain of configured Certificate Authorities will be examined. For each certificate in this chain all the - * CRLs from the URLs specified in their extension fields CRL Distribution Points will be downloaded and used. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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,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_new_ch_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config); - -/** - * @brief Deletes all the CRL nodes 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. - */ -int nc_server_config_new_ch_tls_del_crl(const char *client_name, const char *endpt_name, struct lyd_node **config); - /** * @} TLS Call Home Server Configuration */ diff --git a/src/config_new.c b/src/server_config_util.c similarity index 79% rename from src/config_new.c rename to src/server_config_util.c index 2a957553..cf19e012 100644 --- a/src/config_new.c +++ b/src/server_config_util.c @@ -1,7 +1,7 @@ /** - * @file config_new.c + * @file server_config_util.c * @author Roman Janota - * @brief libnetconf2 server new configuration creation functions + * @brief libnetconf2 server configuration utilities * * @copyright * Copyright (c) 2023 CESNET, z.s.p.o. @@ -15,6 +15,8 @@ #define _GNU_SOURCE +#include "server_config_util.h" + #include #include #include @@ -29,13 +31,13 @@ #endif /* NC_ENABLED_SSH_TLS */ #include "compat.h" -#include "config_new.h" #include "log_p.h" +#include "server_config.h" #include "session.h" #include "session_p.h" int -nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...) +nc_server_config_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...) { int ret = 0; va_list ap; @@ -83,7 +85,7 @@ nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const cha } int -nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name, +nc_server_config_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name, const char *value, struct lyd_node **tree) { int ret = 0; @@ -128,7 +130,7 @@ nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, c } int -nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...) +nc_server_config_delete(struct lyd_node **tree, const char *path_fmt, ...) { int ret = 0; va_list ap; @@ -174,7 +176,7 @@ nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...) } int -nc_config_new_check_delete(struct lyd_node **tree, const char *path_fmt, ...) +nc_server_config_check_delete(struct lyd_node **tree, const char *path_fmt, ...) { int ret = 0; va_list ap; @@ -220,7 +222,7 @@ nc_config_new_check_delete(struct lyd_node **tree, const char *path_fmt, ...) #ifdef NC_ENABLED_SSH_TLS const char * -nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT format) +nc_server_config_util_privkey_format_to_identityref(NC_PRIVKEY_FORMAT format) { switch (format) { case NC_PRIVKEY_FORMAT_RSA: @@ -238,7 +240,7 @@ nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT format) } static int -nc_server_config_new_pubkey_bin_to_b64(const unsigned char *pub_bin, int bin_len, char **pubkey) +nc_server_config_util_pubkey_bin_to_b64(const unsigned char *pub_bin, int bin_len, char **pubkey) { int ret = 0, b64_len; char *pub_b64 = NULL; @@ -273,7 +275,7 @@ nc_server_config_new_pubkey_bin_to_b64(const unsigned char *pub_bin, int bin_len } static int -nc_server_config_new_bn_to_bin(const BIGNUM *bn, unsigned char **bin, int *bin_len) +nc_server_config_util_bn_to_bin(const BIGNUM *bn, unsigned char **bin, int *bin_len) { int ret = 0; unsigned char *bin_tmp = NULL; @@ -322,7 +324,7 @@ nc_server_config_new_bn_to_bin(const BIGNUM *bn, unsigned char **bin, int *bin_l /* ssh pubkey defined in RFC 4253 section 6.6 */ static int -nc_server_config_new_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) +nc_server_config_util_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) { int ret = 0, e_len, n_len, p_len, bin_len; BIGNUM *e = NULL, *n = NULL, *p = NULL; @@ -346,7 +348,7 @@ nc_server_config_new_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) } /* BIGNUM to bin */ - if (nc_server_config_new_bn_to_bin(e, &e_bin, &e_len) || nc_server_config_new_bn_to_bin(n, &n_bin, &n_len)) { + if (nc_server_config_util_bn_to_bin(e, &e_bin, &e_len) || nc_server_config_util_bn_to_bin(n, &n_bin, &n_len)) { ret = 1; goto cleanup; } @@ -480,7 +482,7 @@ nc_server_config_new_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) } /* convert created bin to b64 */ - ret = nc_server_config_new_pubkey_bin_to_b64(bin, bin_len, pubkey); + ret = nc_server_config_util_pubkey_bin_to_b64(bin, bin_len, pubkey); if (ret) { ERR(NULL, "Converting public key from binary to base64 failed."); goto cleanup; @@ -500,7 +502,7 @@ nc_server_config_new_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) /* spki = subject public key info */ static int -nc_server_config_new_evp_pkey_to_spki_pubkey(EVP_PKEY *pkey, char **pubkey) +nc_server_config_util_evp_pkey_to_spki_pubkey(EVP_PKEY *pkey, char **pubkey) { int ret = 0, len; BIO *bio = NULL; @@ -545,7 +547,7 @@ nc_server_config_new_evp_pkey_to_spki_pubkey(EVP_PKEY *pkey, char **pubkey) } int -nc_server_config_new_read_certificate(const char *cert_path, char **cert) +nc_server_config_util_read_certificate(const char *cert_path, char **cert) { int ret = 0, cert_len; X509 *x509 = NULL; @@ -630,7 +632,7 @@ nc_server_config_new_read_certificate(const char *cert_path, char **cert) } static int -nc_server_config_new_read_pubkey_ssh2(FILE *f, char **pubkey) +nc_server_config_util_read_pubkey_ssh2(FILE *f, char **pubkey) { char *buffer = NULL; size_t size = 0, pubkey_len = 0; @@ -683,7 +685,7 @@ nc_server_config_new_read_pubkey_ssh2(FILE *f, char **pubkey) } static int -nc_server_config_new_read_pubkey_openssl(FILE *f, char **pubkey) +nc_server_config_util_read_pubkey_openssl(FILE *f, char **pubkey) { int ret = 0; EVP_PKEY *pub_pkey = NULL; @@ -697,14 +699,14 @@ nc_server_config_new_read_pubkey_openssl(FILE *f, char **pubkey) return 1; } - ret = nc_server_config_new_evp_pkey_to_ssh_pubkey(pub_pkey, pubkey); + ret = nc_server_config_util_evp_pkey_to_ssh_pubkey(pub_pkey, pubkey); EVP_PKEY_free(pub_pkey); return ret; } static int -nc_server_config_new_read_pubkey_libssh(const char *pubkey_path, char **pubkey) +nc_server_config_util_read_pubkey_libssh(const char *pubkey_path, char **pubkey) { int ret = 0; ssh_key pub_sshkey = NULL; @@ -729,7 +731,7 @@ nc_server_config_new_read_pubkey_libssh(const char *pubkey_path, char **pubkey) } int -nc_server_config_new_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey) +nc_server_config_util_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey) { int ret = 0; FILE *f = NULL; @@ -757,13 +759,13 @@ nc_server_config_new_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey) if (!strncmp(header, NC_SUBJECT_PUBKEY_INFO_HEADER, strlen(NC_SUBJECT_PUBKEY_INFO_HEADER))) { /* it's subject public key info public key */ - ret = nc_server_config_new_read_pubkey_openssl(f, pubkey); + ret = nc_server_config_util_read_pubkey_openssl(f, pubkey); } else if (!strncmp(header, NC_SSH2_PUBKEY_HEADER, strlen(NC_SSH2_PUBKEY_HEADER))) { /* it's ssh2 public key */ - ret = nc_server_config_new_read_pubkey_ssh2(f, pubkey); + ret = nc_server_config_util_read_pubkey_ssh2(f, pubkey); } else { /* it's probably OpenSSH public key */ - ret = nc_server_config_new_read_pubkey_libssh(pubkey_path, pubkey); + ret = nc_server_config_util_read_pubkey_libssh(pubkey_path, pubkey); } if (ret) { ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path); @@ -780,7 +782,7 @@ nc_server_config_new_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey) } int -nc_server_config_new_get_spki_pubkey_file(const char *pubkey_path, char **pubkey) +nc_server_config_util_get_spki_pubkey_file(const char *pubkey_path, char **pubkey) { int ret = 0; FILE *f = NULL; @@ -804,7 +806,7 @@ nc_server_config_new_get_spki_pubkey_file(const char *pubkey_path, char **pubkey return 1; } - ret = nc_server_config_new_evp_pkey_to_spki_pubkey(pub_pkey, pubkey); + ret = nc_server_config_util_evp_pkey_to_spki_pubkey(pub_pkey, pubkey); if (ret) { goto cleanup; } @@ -819,7 +821,7 @@ nc_server_config_new_get_spki_pubkey_file(const char *pubkey_path, char **pubkey } static int -nc_server_config_new_privkey_header_to_format(FILE *f_privkey, const char *privkey_path, NC_PRIVKEY_FORMAT *privkey_format) +nc_server_config_util_privkey_header_to_format(FILE *f_privkey, const char *privkey_path, NC_PRIVKEY_FORMAT *privkey_format) { char *privkey_header = NULL; size_t len = 0; @@ -857,7 +859,7 @@ nc_server_config_new_privkey_header_to_format(FILE *f_privkey, const char *privk } static int -nc_server_config_new_get_privkey_openssl(const char *privkey_path, FILE *f_privkey, char **privkey, EVP_PKEY **pkey) +nc_server_config_util_get_privkey_openssl(const char *privkey_path, FILE *f_privkey, char **privkey, EVP_PKEY **pkey) { int ret = 0, len; BIO *bio = NULL; @@ -909,7 +911,7 @@ nc_server_config_new_get_privkey_openssl(const char *privkey_path, FILE *f_privk } static int -nc_server_config_new_get_privkey_libssh(const char *privkey_path, char **privkey, EVP_PKEY **pkey) +nc_server_config_util_get_privkey_libssh(const char *privkey_path, char **privkey, EVP_PKEY **pkey) { int ret = 0; BIO *bio = NULL; @@ -971,7 +973,7 @@ nc_server_config_new_get_privkey_libssh(const char *privkey_path, char **privkey } static int -nc_server_config_new_get_privkey(const char *privkey_path, NC_PRIVKEY_FORMAT *privkey_format, char **privkey, EVP_PKEY **pkey) +nc_server_config_util_get_privkey(const char *privkey_path, NC_PRIVKEY_FORMAT *privkey_format, char **privkey, EVP_PKEY **pkey) { int ret = 0; FILE *f_privkey = NULL; @@ -987,7 +989,7 @@ nc_server_config_new_get_privkey(const char *privkey_path, NC_PRIVKEY_FORMAT *pr } /* read the first line from the privkey to determine it's type */ - ret = nc_server_config_new_privkey_header_to_format(f_privkey, privkey_path, privkey_format); + ret = nc_server_config_util_privkey_header_to_format(f_privkey, privkey_path, privkey_format); if (ret) { ERR(NULL, "Getting private key format from file \"%s\" failed.", privkey_path); goto cleanup; @@ -999,11 +1001,11 @@ nc_server_config_new_get_privkey(const char *privkey_path, NC_PRIVKEY_FORMAT *pr case NC_PRIVKEY_FORMAT_EC: case NC_PRIVKEY_FORMAT_X509: /* OpenSSL solely can do this */ - ret = nc_server_config_new_get_privkey_openssl(privkey_path, f_privkey, &priv, pkey); + ret = nc_server_config_util_get_privkey_openssl(privkey_path, f_privkey, &priv, pkey); break; case NC_PRIVKEY_FORMAT_OPENSSH: /* need the help of libssh */ - ret = nc_server_config_new_get_privkey_libssh(privkey_path, &priv, pkey); + ret = nc_server_config_util_get_privkey_libssh(privkey_path, &priv, pkey); /* if the function returned successfully, the key is no longer OpenSSH, it was converted to x509 */ *privkey_format = NC_PRIVKEY_FORMAT_X509; break; @@ -1035,7 +1037,7 @@ nc_server_config_new_get_privkey(const char *privkey_path, NC_PRIVKEY_FORMAT *pr } int -nc_server_config_new_get_asym_key_pair(const char *privkey_path, const char *pubkey_path, NC_PUBKEY_FORMAT wanted_pubkey_format, +nc_server_config_util_get_asym_key_pair(const char *privkey_path, const char *pubkey_path, NC_PUBKEY_FORMAT wanted_pubkey_format, char **privkey, NC_PRIVKEY_FORMAT *privkey_type, char **pubkey) { int ret = 0; @@ -1047,7 +1049,7 @@ nc_server_config_new_get_asym_key_pair(const char *privkey_path, const char *pub *pubkey = NULL; /* get private key base64 and EVP_PKEY */ - ret = nc_server_config_new_get_privkey(privkey_path, privkey_type, privkey, &priv_pkey); + ret = nc_server_config_util_get_privkey(privkey_path, privkey_type, privkey, &priv_pkey); if (ret) { ERR(NULL, "Getting private key from file \"%s\" failed.", privkey_path); goto cleanup; @@ -1056,15 +1058,15 @@ nc_server_config_new_get_asym_key_pair(const char *privkey_path, const char *pub /* get public key, either from file or generate it from the EVP_PKEY */ if (!pubkey_path) { if (wanted_pubkey_format == NC_PUBKEY_FORMAT_SSH) { - ret = nc_server_config_new_evp_pkey_to_ssh_pubkey(priv_pkey, pubkey); + ret = nc_server_config_util_evp_pkey_to_ssh_pubkey(priv_pkey, pubkey); } else { - ret = nc_server_config_new_evp_pkey_to_spki_pubkey(priv_pkey, pubkey); + ret = nc_server_config_util_evp_pkey_to_spki_pubkey(priv_pkey, pubkey); } } else { if (wanted_pubkey_format == NC_PUBKEY_FORMAT_SSH) { - ret = nc_server_config_new_get_ssh_pubkey_file(pubkey_path, pubkey); + ret = nc_server_config_util_get_ssh_pubkey_file(pubkey_path, pubkey); } else { - ret = nc_server_config_new_get_spki_pubkey_file(pubkey_path, pubkey); + ret = nc_server_config_util_get_spki_pubkey_file(pubkey_path, pubkey); } } if (ret) { @@ -1082,7 +1084,7 @@ nc_server_config_new_get_asym_key_pair(const char *privkey_path, const char *pub } API int -nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_name, NC_TRANSPORT_IMPL transport, +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) { int ret = 0; @@ -1105,13 +1107,13 @@ nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_na goto cleanup; } - ret = nc_config_new_create(ctx, config, address, address_fmt, endpt_name); + ret = nc_server_config_create(ctx, config, address, address_fmt, endpt_name); if (ret) { goto cleanup; } sprintf(port_buf, "%d", port); - ret = nc_config_new_create(ctx, config, port_buf, port_fmt, endpt_name); + ret = nc_server_config_create(ctx, config, port_buf, port_fmt, endpt_name); if (ret) { goto cleanup; } @@ -1121,7 +1123,7 @@ nc_server_config_new_address_port(const struct ly_ctx *ctx, const char *endpt_na } API int -nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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) { int ret = 0; @@ -1143,12 +1145,12 @@ nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *clien goto cleanup; } - ret = nc_config_new_create(ctx, config, address, address_fmt, client_name, endpt_name); + ret = nc_server_config_create(ctx, config, address, address_fmt, client_name, endpt_name); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, port, port_fmt, client_name, endpt_name); + ret = nc_server_config_create(ctx, config, port, port_fmt, client_name, endpt_name); if (ret) { goto cleanup; } @@ -1158,45 +1160,45 @@ nc_server_config_new_ch_address_port(const struct ly_ctx *ctx, const char *clien } API int -nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **config) +nc_server_config_del_endpt(const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, config, 1); if (endpt_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']", endpt_name); + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']", endpt_name); } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint"); + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint"); } } API int -nc_server_config_new_ch_del_ch_client(const char *ch_client_name, struct lyd_node **config) +nc_server_config_del_ch_client(const char *ch_client_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, config, 1); if (ch_client_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']", ch_client_name); + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']", ch_client_name); } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client"); + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client"); } } API int -nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt_name, struct lyd_node **config) +nc_server_config_del_ch_endpt(const char *client_name, const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, config, 1); if (endpt_name) { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']", client_name, endpt_name); } else { - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint", client_name); } } API int -nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, const char *asym_key_name, +nc_server_config_add_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, const char *asym_key_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config) { int ret = 0; @@ -1208,9 +1210,9 @@ nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IM /* get the keys as a string from the given files */ if (ti == NC_TI_LIBSSH) { - ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_SSH, &privkey, &privkey_type, &pubkey); + 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_OPENSSL) { - ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey, &privkey_type, &pubkey); + ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey, &privkey_type, &pubkey); } else { ERR(NULL, "Only SSH and TLS transports can be used to create an asymmetric key pair in the keystore."); ret = 1; @@ -1229,31 +1231,31 @@ nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IM } /* get privkey identityref value */ - privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type); + privkey_format = nc_server_config_util_privkey_format_to_identityref(privkey_type); if (!privkey_format) { ret = 1; goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-keystore:keystore/asymmetric-keys/" + ret = nc_server_config_create(ctx, config, pubkey_format, "/ietf-keystore:keystore/asymmetric-keys/" "asymmetric-key[name='%s']/public-key-format", asym_key_name); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey, "/ietf-keystore:keystore/asymmetric-keys/" + ret = nc_server_config_create(ctx, config, pubkey, "/ietf-keystore:keystore/asymmetric-keys/" "asymmetric-key[name='%s']/public-key", asym_key_name); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-keystore:keystore/asymmetric-keys/" + ret = nc_server_config_create(ctx, config, privkey_format, "/ietf-keystore:keystore/asymmetric-keys/" "asymmetric-key[name='%s']/private-key-format", asym_key_name); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, privkey, "/ietf-keystore:keystore/asymmetric-keys/" + ret = nc_server_config_create(ctx, config, privkey, "/ietf-keystore:keystore/asymmetric-keys/" "asymmetric-key[name='%s']/cleartext-private-key", asym_key_name); if (ret) { goto cleanup; @@ -1266,19 +1268,19 @@ nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IM } API int -nc_server_config_new_del_keystore_asym_key(const char *asym_key_name, struct lyd_node **config) +nc_server_config_del_keystore_asym_key(const char *asym_key_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, config, 1); if (asym_key_name) { - return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']", asym_key_name); + return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']", asym_key_name); } else { - return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key"); + return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key"); } } API int -nc_server_config_new_keystore_cert(const struct ly_ctx *ctx, const char *asym_key_name, const char *cert_name, +nc_server_config_add_keystore_cert(const struct ly_ctx *ctx, const char *asym_key_name, const char *cert_name, const char *cert_path, struct lyd_node **config) { int ret = 0; @@ -1287,12 +1289,12 @@ nc_server_config_new_keystore_cert(const struct ly_ctx *ctx, const char *asym_ke NC_CHECK_ARG_RET(NULL, ctx, asym_key_name, cert_name, cert_path, config, 1); /* get cert data */ - ret = nc_server_config_new_read_certificate(cert_path, &cert); + ret = nc_server_config_util_read_certificate(cert_path, &cert); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, cert, "/ietf-keystore:keystore/asymmetric-keys/" + ret = nc_server_config_create(ctx, config, cert, "/ietf-keystore:keystore/asymmetric-keys/" "asymmetric-key[name='%s']/certificates/certificate[name='%s']/cert-data", asym_key_name, cert_name); cleanup: @@ -1301,22 +1303,22 @@ nc_server_config_new_keystore_cert(const struct ly_ctx *ctx, const char *asym_ke } API int -nc_server_config_new_del_keystore_cert(const char *asym_key_name, const char *cert_name, struct lyd_node **config) +nc_server_config_del_keystore_cert(const char *asym_key_name, const char *cert_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, asym_key_name, config, 1); if (cert_name) { - return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/" + return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/" "certificates/certificate[name='%s']", asym_key_name, cert_name); } else { - return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/" + return nc_server_config_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/" "certificates/certificate", asym_key_name); } } API int -nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *pub_bag_name, const char *pubkey_name, - const char *pubkey_path, struct lyd_node **config) +nc_server_config_add_truststore_pubkey(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, const char *pub_bag_name, + const char *pubkey_name, const char *pubkey_path, struct lyd_node **config) { int ret = 0; char *pubkey = NULL; @@ -1324,18 +1326,26 @@ nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *pub NC_CHECK_ARG_RET(NULL, ctx, pub_bag_name, pubkey_name, pubkey_path, config, 1); - ret = nc_server_config_new_get_ssh_pubkey_file(pubkey_path, &pubkey); + if (ti == NC_TI_LIBSSH) { + ret = nc_server_config_util_get_ssh_pubkey_file(pubkey_path, &pubkey); + } else if (ti == NC_TI_OPENSSL) { + ret = nc_server_config_util_get_spki_pubkey_file(pubkey_path, &pubkey); + } else { + ERR(NULL, "Public key in the truststore can only be created for SSH or TLS transports."); + ret = 1; + goto cleanup; + } if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-truststore:truststore/public-key-bags/" + ret = nc_server_config_create(ctx, config, pubkey_format, "/ietf-truststore:truststore/public-key-bags/" "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", pub_bag_name, pubkey_name); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, pubkey, "/ietf-truststore:truststore/public-key-bags/" + ret = nc_server_config_create(ctx, config, pubkey, "/ietf-truststore:truststore/public-key-bags/" "public-key-bag[name='%s']/public-key[name='%s']/public-key", pub_bag_name, pubkey_name); if (ret) { goto cleanup; @@ -1347,22 +1357,22 @@ nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *pub } API int -nc_server_config_new_del_truststore_pubkey(const char *pub_bag_name, +nc_server_config_del_truststore_pubkey(const char *pub_bag_name, const char *pubkey_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, pub_bag_name, config, 1); if (pubkey_name) { - return nc_config_new_delete(config, "/ietf-truststore:truststore/public-key-bags/" + return nc_server_config_delete(config, "/ietf-truststore:truststore/public-key-bags/" "public-key-bag[name='%s']/public-key[name='%s']", pub_bag_name, pubkey_name); } else { - return nc_config_new_delete(config, "/ietf-truststore:truststore/public-key-bags/" + return nc_server_config_delete(config, "/ietf-truststore:truststore/public-key-bags/" "public-key-bag[name='%s']/public-key", pub_bag_name); } } API int -nc_server_config_new_truststore_cert(const struct ly_ctx *ctx, const char *cert_bag_name, const char *cert_name, +nc_server_config_add_truststore_cert(const struct ly_ctx *ctx, const char *cert_bag_name, const char *cert_name, const char *cert_path, struct lyd_node **config) { int ret = 0; @@ -1370,12 +1380,12 @@ nc_server_config_new_truststore_cert(const struct ly_ctx *ctx, const char *cert_ NC_CHECK_ARG_RET(NULL, ctx, cert_bag_name, cert_name, cert_path, config, 1); - ret = nc_server_config_new_read_certificate(cert_path, &cert); + ret = nc_server_config_util_read_certificate(cert_path, &cert); if (ret) { goto cleanup; } - ret = nc_config_new_create(ctx, config, cert, "/ietf-truststore:truststore/certificate-bags/" + ret = nc_server_config_create(ctx, config, cert, "/ietf-truststore:truststore/certificate-bags/" "certificate-bag[name='%s']/certificate[name='%s']/cert-data", cert_bag_name, cert_name); if (ret) { goto cleanup; @@ -1387,16 +1397,16 @@ nc_server_config_new_truststore_cert(const struct ly_ctx *ctx, const char *cert_ } API int -nc_server_config_new_del_truststore_cert(const char *cert_bag_name, +nc_server_config_del_truststore_cert(const char *cert_bag_name, const char *cert_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, cert_bag_name, config, 1); if (cert_name) { - return nc_config_new_delete(config, "/ietf-truststore:truststore/certificate-bags/" + return nc_server_config_delete(config, "/ietf-truststore:truststore/certificate-bags/" "certificate-bag[name='%s']/certificate[name='%s']", cert_bag_name, cert_name); } else { - return nc_config_new_delete(config, "/ietf-truststore:truststore/certificate-bags/" + return nc_server_config_delete(config, "/ietf-truststore:truststore/certificate-bags/" "certificate-bag[name='%s']/certificate", cert_bag_name); } } @@ -1404,7 +1414,7 @@ nc_server_config_new_del_truststore_cert(const char *cert_bag_name, #endif /* NC_ENABLED_SSH_TLS */ API int -nc_server_config_new_unix_socket(const struct ly_ctx *ctx, const char *endpt_name, const char *path, +nc_server_config_add_unix_socket(const struct ly_ctx *ctx, const char *endpt_name, const char *path, mode_t mode, uid_t uid, gid_t gid, struct lyd_node **config) { int ret = 0; @@ -1421,7 +1431,7 @@ nc_server_config_new_unix_socket(const struct ly_ctx *ctx, const char *endpt_nam } /* path to unix socket */ - ret = nc_config_new_create_append(ctx, tree_path, "path", path, config); + ret = nc_server_config_append(ctx, tree_path, "path", path, config); if (ret) { goto cleanup; } @@ -1435,7 +1445,7 @@ nc_server_config_new_unix_socket(const struct ly_ctx *ctx, const char *endpt_nam } sprintf(buf, "%o", mode); - ret = nc_config_new_create_append(ctx, tree_path, "mode", buf, config); + ret = nc_server_config_append(ctx, tree_path, "mode", buf, config); if (ret) { goto cleanup; } @@ -1445,7 +1455,7 @@ nc_server_config_new_unix_socket(const struct ly_ctx *ctx, const char *endpt_nam if (uid != (uid_t)-1) { memset(buf, 0, 12); sprintf(buf, "%u", uid); - ret = nc_config_new_create_append(ctx, tree_path, "uid", buf, config); + ret = nc_server_config_append(ctx, tree_path, "uid", buf, config); if (ret) { goto cleanup; } @@ -1455,7 +1465,7 @@ nc_server_config_new_unix_socket(const struct ly_ctx *ctx, const char *endpt_nam if (gid != (gid_t)-1) { memset(buf, 0, 12); sprintf(buf, "%u", gid); - ret = nc_config_new_create_append(ctx, tree_path, "gid", buf, config); + ret = nc_server_config_append(ctx, tree_path, "gid", buf, config); if (ret) { goto cleanup; } @@ -1467,22 +1477,22 @@ nc_server_config_new_unix_socket(const struct ly_ctx *ctx, const char *endpt_nam } API int -nc_server_config_new_ch_persistent(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config) +nc_server_config_add_ch_persistent(const struct ly_ctx *ctx, const char *ch_client_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1); /* delete periodic tree if exists */ - if (nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/periodic", ch_client_name)) { return 1; } - return nc_config_new_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/call-home/" + return nc_server_config_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/persistent", ch_client_name); } API int -nc_server_config_new_ch_period(const struct ly_ctx *ctx, const char *ch_client_name, uint16_t period, +nc_server_config_add_ch_period(const struct ly_ctx *ctx, const char *ch_client_name, uint16_t period, struct lyd_node **config) { char buf[6] = {0}; @@ -1490,52 +1500,52 @@ nc_server_config_new_ch_period(const struct ly_ctx *ctx, const char *ch_client_n NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1); /* delete persistent tree if exists */ - if (nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) { return 1; } sprintf(buf, "%u", period); - return nc_config_new_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/" + return nc_server_config_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/periodic/period", ch_client_name); } API int -nc_server_config_new_ch_del_period(const char *ch_client_name, struct lyd_node **config) +nc_server_config_del_ch_period(const char *ch_client_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/periodic/period", ch_client_name); } API int -nc_server_config_new_ch_anchor_time(const struct ly_ctx *ctx, const char *ch_client_name, +nc_server_config_add_ch_anchor_time(const struct ly_ctx *ctx, const char *ch_client_name, const char *anchor_time, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, anchor_time, config, 1); /* delete persistent tree if exists */ - if (nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) { return 1; } - return nc_config_new_create(ctx, config, anchor_time, "/ietf-netconf-server:netconf-server/call-home/" + return nc_server_config_create(ctx, config, anchor_time, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/periodic/anchor-time", ch_client_name); } API int -nc_server_config_new_ch_del_anchor_time(const char *ch_client_name, struct lyd_node **config) +nc_server_config_del_ch_anchor_time(const char *ch_client_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/periodic/anchor-time", ch_client_name); } API int -nc_server_config_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_client_name, +nc_server_config_add_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_client_name, uint16_t idle_timeout, struct lyd_node **config) { char buf[6] = {0}; @@ -1543,27 +1553,27 @@ nc_server_config_new_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_cl NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1); /* delete persistent tree if exists */ - if (nc_config_new_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + if (nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/persistent", ch_client_name)) { return 1; } sprintf(buf, "%u", idle_timeout); - return nc_config_new_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/" + return nc_server_config_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/periodic/idle-timeout", ch_client_name); } API int -nc_server_config_new_ch_del_idle_timeout(const char *ch_client_name, struct lyd_node **config) +nc_server_config_del_ch_idle_timeout(const char *ch_client_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/periodic/idle-timeout", ch_client_name); } API int -nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char *ch_client_name, +nc_server_config_add_ch_reconnect_strategy(const struct ly_ctx *ctx, const char *ch_client_name, NC_CH_START_WITH start_with, uint16_t max_wait, uint8_t max_attempts, struct lyd_node **config) { int ret = 0; @@ -1592,7 +1602,7 @@ nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char start_with_val = "random-selection"; } - ret = nc_config_new_create_append(ctx, path, "start-with", start_with_val, config); + ret = nc_server_config_append(ctx, path, "start-with", start_with_val, config); if (ret) { goto cleanup; } @@ -1600,7 +1610,7 @@ nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char if (max_attempts) { sprintf(buf, "%u", max_attempts); - ret = nc_config_new_create_append(ctx, path, "max-attempts", buf, config); + ret = nc_server_config_append(ctx, path, "max-attempts", buf, config); if (ret) { goto cleanup; } @@ -1609,7 +1619,7 @@ nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char if (max_wait) { sprintf(buf, "%u", max_wait); - ret = nc_config_new_create_append(ctx, path, "max-wait", buf, config); + ret = nc_server_config_append(ctx, path, "max-wait", buf, config); if (ret) { goto cleanup; } @@ -1621,10 +1631,10 @@ nc_server_config_new_ch_reconnect_strategy(const struct ly_ctx *ctx, const char } API int -nc_server_config_new_ch_del_reconnect_strategy(const char *ch_client_name, struct lyd_node **config) +nc_server_config_del_ch_reconnect_strategy(const char *ch_client_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, ch_client_name, config, 1); - return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/reconnect-strategy", ch_client_name); } diff --git a/src/config_new.h b/src/server_config_util.h similarity index 65% rename from src/config_new.h rename to src/server_config_util.h index 3fae017c..6048fc4b 100644 --- a/src/config_new.h +++ b/src/server_config_util.h @@ -1,7 +1,7 @@ /** - * @file config_new.h + * @file server_config_util.h * @author Roman Janota - * @brief libnetconf2 server new configuration creation header + * @brief libnetconf2 server configuration utlities header * * @copyright * Copyright (c) 2023 CESNET, z.s.p.o. @@ -13,18 +13,13 @@ * https://opensource.org/licenses/BSD-3-Clause */ -#ifndef NC_CONFIG_NEW_H_ -#define NC_CONFIG_NEW_H_ +#ifndef NC_SERVER_CONFIG_UTIL_H_ +#define NC_SERVER_CONFIG_UTIL_H_ #include -#include #include "session_p.h" -#ifdef __cplusplus -extern "C" { -#endif - #ifdef NC_ENABLED_SSH_TLS /* private key's pkcs8 header */ @@ -73,14 +68,48 @@ typedef enum { NC_ALG_MAC } NC_ALG_TYPE; -int nc_server_config_new_get_asym_key_pair(const char *privkey_path, const char *pubkey_path, NC_PUBKEY_FORMAT wanted_pubkey_type, +/** + * @brief Gets asymmetric key pair from private key (and optionally public key) file(s). + * + * @param[in] privkey_path Path to private key. + * @param[in] pubkey_path Optional path to public key. If not set, PK will be generated from private key. + * @param[in] wanted_pubkey_type Wanted public key format to be generated (SPKI/SSH) + * @param[out] privkey Base64 encoded private key. + * @param[out] privkey_type Type of the private key. (RSA, EC, etc) + * @param[out] pubkey Base64 encoded public key. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_util_get_asym_key_pair(const char *privkey_path, const char *pubkey_path, NC_PUBKEY_FORMAT wanted_pubkey_type, char **privkey, NC_PRIVKEY_FORMAT *privkey_type, char **pubkey); -int nc_server_config_new_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey); +/** + * @brief Gets public key from a file and converts it to the SSH format if need be. + * + * @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); -int nc_server_config_new_read_certificate(const char *cert_path, char **cert); +/** + * @brief Gets a certificate from a file. + * + * @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); -const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT format); +/** + * @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(NC_PRIVKEY_FORMAT format); #endif /* NC_ENABLED_SSH_TLS */ @@ -95,7 +124,7 @@ const char * nc_config_new_privkey_format_to_identityref(NC_PRIVKEY_FORMAT forma * @param[in] ... Parameters for the path format, essentially representing the lists' keys. * @return 0 on success, 1 otherwise. */ -int nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...); +int nc_server_config_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...); /** * @brief Creates a YANG data node by appending it to a specified parent node. @@ -108,7 +137,7 @@ int nc_config_new_create(const struct ly_ctx *ctx, struct lyd_node **tree, const * this is set to the top level container. * @return 0 on success, 1 otherwise. */ -int nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name, +int nc_server_config_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name, const char *value, struct lyd_node **tree); /** @@ -119,7 +148,7 @@ int nc_config_new_create_append(const struct ly_ctx *ctx, const char *parent_pat * @param[in] ... Parameters for the path format, essentially representing the lists' keys. * @return 0 on success, non-zero otherwise. */ -int nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...); +int nc_server_config_delete(struct lyd_node **tree, const char *path_fmt, ...); /** * @brief Deletes a subtree from the YANG data, but doesn't return an error if the node doesn't exist. @@ -129,10 +158,6 @@ int nc_config_new_delete(struct lyd_node **tree, const char *path_fmt, ...); * @param[in] ... Parameters for the path format, essentially representing the lists' keys. * @return 0 on success, non-zero otherwise. */ -int nc_config_new_check_delete(struct lyd_node **tree, const char *path_fmt, ...); - -#ifdef __cplusplus -} -#endif +int nc_server_config_check_delete(struct lyd_node **tree, const char *path_fmt, ...); #endif /* NC_CONFIG_NEW_H_ */ diff --git a/src/server_config_util_ssh.c b/src/server_config_util_ssh.c new file mode 100644 index 00000000..64b56abc --- /dev/null +++ b/src/server_config_util_ssh.c @@ -0,0 +1,691 @@ +/** + * @file server_config_util_ssh.c + * @author Roman Janota + * @brief libnetconf2 server SSH configuration utilities + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include "server_config_util.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "compat.h" +#include "config.h" +#include "log_p.h" +#include "server_config.h" +#include "session_p.h" + +#if !defined (HAVE_CRYPT_R) +extern pthread_mutex_t crypt_lock; +#endif + +static int +_nc_server_config_add_ssh_hostkey(const struct ly_ctx *ctx, const char *tree_path, + const char *privkey_path, const char *pubkey_path, struct lyd_node **config) +{ + int ret = 0; + char *pubkey = NULL, *privkey = NULL; + NC_PRIVKEY_FORMAT privkey_type; + const char *privkey_format, *pubkey_format = "ietf-crypto-types:ssh-public-key-format"; + + NC_CHECK_ARG_RET(NULL, ctx, tree_path, privkey_path, config, 1); + + /* get the keys as a string from the given files */ + ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_SSH, &privkey, &privkey_type, &pubkey); + if (ret) { + ERR(NULL, "Getting keys from file(s) failed."); + goto cleanup; + } + + /* get privkey identityref value */ + privkey_format = nc_server_config_util_privkey_format_to_identityref(privkey_type); + if (!privkey_format) { + ret = 1; + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "inline-definition/public-key-format", pubkey_format, config); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "inline-definition/public-key", pubkey, config); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "inline-definition/private-key-format", privkey_format, config); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "inline-definition/cleartext-private-key", privkey, config); + if (ret) { + goto cleanup; + } + + /* delete keystore choice nodes if present */ + ret = nc_server_config_check_delete(config, "%s/keystore-reference", tree_path); + if (ret) { + goto cleanup; + } + +cleanup: + free(privkey); + free(pubkey); + return ret; +} + +API 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 ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, privkey_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key[name='%s']/public-key", endpt_name, hostkey_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_ssh_hostkey(ctx, path, privkey_path, pubkey_path, config); + if (ret) { + ERR(NULL, "Creating new hostkey YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, privkey_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key", client_name, endpt_name, hostkey_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_ssh_hostkey(ctx, path, privkey_path, pubkey_path, config); + if (ret) { + ERR(NULL, "Creating new Call-Home hostkey YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + if (hostkey_name) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key[name='%s']", endpt_name, hostkey_name); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key", endpt_name); + } +} + +API int +nc_server_config_del_ch_ssh_hostkey(const char *client_name, const char *endpt_name, + const char *hostkey_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (hostkey_name) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']", client_name, endpt_name, hostkey_name); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key", client_name, endpt_name); + } +} + +API int +nc_server_config_add_ssh_auth_attempts(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_attempts, + struct lyd_node **config) +{ + int ret = 0; + char *attempts_buf = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + /* uint to str */ + if (asprintf(&attempts_buf, "%u", auth_attempts) == -1) { + ERRMEM; + attempts_buf = NULL; + ret = 1; + goto cleanup; + } + + ret = nc_server_config_create(ctx, config, attempts_buf, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/libnetconf2-netconf-server:auth-attempts", endpt_name); + +cleanup: + free(attempts_buf); + return ret; +} + +API int +nc_server_config_add_ssh_auth_timeout(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_timeout, + struct lyd_node **config) +{ + int ret = 0; + char *timeout_buf = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + /* uint to str */ + if (asprintf(&timeout_buf, "%u", auth_timeout) == -1) { + ERRMEM; + timeout_buf = NULL; + ret = 1; + goto cleanup; + } + + ret = nc_server_config_create(ctx, config, timeout_buf, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/libnetconf2-netconf-server:auth-timeout", endpt_name); + +cleanup: + free(timeout_buf); + return ret; +} + +API int +nc_server_config_add_ch_ssh_auth_attempts(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + uint16_t auth_attempts, struct lyd_node **config) +{ + int ret = 0; + char *attempts_buf = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); + + /* uint to str */ + if (asprintf(&attempts_buf, "%u", auth_attempts) == -1) { + ERRMEM; + attempts_buf = NULL; + ret = 1; + goto cleanup; + } + + ret = nc_server_config_create(ctx, config, attempts_buf, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "libnetconf2-netconf-server:auth-attempts", client_name, endpt_name); + +cleanup: + free(attempts_buf); + return ret; +} + +API int +nc_server_config_add_ch_ssh_auth_timeout(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + uint16_t auth_timeout, struct lyd_node **config) +{ + int ret = 0; + char *timeout_buf = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); + + /* uint to str */ + if (asprintf(&timeout_buf, "%u", auth_timeout) == -1) { + ERRMEM; + timeout_buf = NULL; + ret = 1; + goto cleanup; + } + + ret = nc_server_config_create(ctx, config, timeout_buf, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "libnetconf2-netconf-server:auth-timeout", client_name, endpt_name); + +cleanup: + free(timeout_buf); + return ret; +} + +static int +_nc_server_config_add_ssh_user_pubkey(const struct ly_ctx *ctx, const char *tree_path, const char *pubkey_path, + struct lyd_node **config) +{ + int ret = 0; + char *pubkey = NULL; + const char *pubkey_format = "ietf-crypto-types:ssh-public-key-format"; + + /* get pubkey data */ + ret = nc_server_config_util_get_ssh_pubkey_file(pubkey_path, &pubkey); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "public-key-format", pubkey_format, config); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "public-key", pubkey, config); + if (ret) { + goto cleanup; + } + +cleanup: + free(pubkey); + return ret; +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pubkey_name, pubkey_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" + "public-key[name='%s']", endpt_name, user_name, pubkey_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_ssh_user_pubkey(ctx, path, pubkey_path, config); + if (ret) { + ERR(NULL, "Creating new SSH user's public key failed."); + goto cleanup; + } + + /* delete truststore reference if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/truststore-reference", + endpt_name, user_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pubkey_name, pubkey_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, + endpt_name, user_name, pubkey_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_ssh_user_pubkey(ctx, path, pubkey_path, config); + if (ret) { + ERR(NULL, "Creating new CH SSH user's public key failed."); + goto cleanup; + } + + /* delete truststore reference if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" + "public-keys/truststore-reference", client_name, endpt_name, user_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_ssh_user_pubkey(const char *endpt_name, const char *user_name, + const char *pubkey_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + + if (pubkey_name) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" + "public-key[name='%s']", endpt_name, user_name, pubkey_name); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" + "public-key", endpt_name, user_name); + } +} + +API 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) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + + if (pubkey_name) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, + endpt_name, user_name, pubkey_name); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/inline-definition/public-key", client_name, + endpt_name, user_name); + } +} + +static int +_nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char *tree_path, + const char *password, struct lyd_node **config) +{ + int ret = 0; + char *hashed_pw = NULL; + const char *salt = "$6$idsizuippipk$"; + + NC_CHECK_ARG_RET(NULL, ctx, tree_path, password, config, 1); + +#ifdef HAVE_CRYPT_R + struct crypt_data cdata; +#endif + +#ifdef HAVE_CRYPT_R + cdata.initialized = 0; + hashed_pw = crypt_r(password, salt, &data); +#else + pthread_mutex_lock(&crypt_lock); + hashed_pw = crypt(password, salt); + pthread_mutex_unlock(&crypt_lock); +#endif + + if (!hashed_pw) { + ERR(NULL, "Hashing password failed (%s).", strerror(errno)); + ret = 1; + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "password", hashed_pw, config); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API 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 ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, password, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/users/user[name='%s']", endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_ssh_user_password(ctx, path, password, config); + if (ret) { + ERR(NULL, "Creating new SSH user's password failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, password, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']", client_name, endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_ssh_user_password(ctx, path, password, config); + if (ret) { + ERR(NULL, "Creating new CH SSH user's password failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_ssh_user_password(const char *endpt_name, const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/password", endpt_name, user_name); +} + +API 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) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/password", client_name, endpt_name, user_name); +} + +static int +_nc_server_config_add_ssh_user_interactive(const struct ly_ctx *ctx, const char *tree_path, + const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) +{ + int ret = 0; + + ret = nc_server_config_append(ctx, tree_path, "pam-config-file-name", pam_config_name, config); + if (ret) { + goto cleanup; + } + + if (pam_config_dir) { + ret = nc_server_config_append(ctx, tree_path, "pam-config-file-dir", pam_config_dir, config); + if (ret) { + goto cleanup; + } + } + +cleanup: + return ret; +} + +API int +nc_server_config_add_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pam_config_name, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); + if (ret) { + ERR(NULL, "Creating new SSH user's keyboard interactive nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API 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, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pam_config_name, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); + if (ret) { + ERR(NULL, "Creating new CH SSH user's keyboard interactive nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_ssh_user_interactive(const char *endpt_name, const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name); +} + +API 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) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" + "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name); +} + +API int +nc_server_config_del_ssh_user(const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (user_name) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']", endpt_name, user_name); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user", endpt_name); + } +} + +API int +nc_server_config_del_ch_ssh_user(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (user_name) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']", client_name, + endpt_name, user_name); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user", client_name, endpt_name); + } +} + +API 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) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); + + return nc_server_config_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); +} + +API int +nc_server_config_del_ssh_endpoint_client_ref(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); +} diff --git a/src/server_config_util_tls.c b/src/server_config_util_tls.c new file mode 100644 index 00000000..0d628f60 --- /dev/null +++ b/src/server_config_util_tls.c @@ -0,0 +1,584 @@ +/** + * @file server_config_util_tls.c + * @author Roman Janota + * @brief libnetconf2 server TLS configuration utilities + * + * @copyright + * Copyright (c) 2023 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 + */ + +#define _GNU_SOURCE + +#include "server_config_util.h" + +#include +#include +#include +#include +#include + +#include + +#include "compat.h" +#include "config.h" +#include "log_p.h" +#include "server_config.h" +#include "session.h" +#include "session_p.h" + +static int +_nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *tree_path, const char *privkey_path, + const char *pubkey_path, const char *certificate_path, struct lyd_node **config) +{ + int ret = 0; + char *privkey = NULL, *pubkey = NULL, *cert = NULL; + NC_PRIVKEY_FORMAT privkey_type; + const char *privkey_format, *pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; + + NC_CHECK_ARG_RET(NULL, ctx, tree_path, privkey_path, certificate_path, config, 1); + + /* get the keys as a string from the given files */ + ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey, &privkey_type, &pubkey); + if (ret) { + ERR(NULL, "Getting keys from file(s) failed."); + goto cleanup; + } + + /* get cert data from file */ + ret = nc_server_config_util_read_certificate(certificate_path, &cert); + if (ret) { + ERR(NULL, "Getting certificate from file \"%s\" failed.", certificate_path); + goto cleanup; + } + + /* get privkey identityref value */ + privkey_format = nc_server_config_util_privkey_format_to_identityref(privkey_type); + if (!privkey_format) { + ret = 1; + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "inline-definition/public-key-format", pubkey_format, config); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "inline-definition/public-key", pubkey, config); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "inline-definition/private-key-format", privkey_format, config); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "inline-definition/cleartext-private-key", privkey, config); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "inline-definition/cert-data", cert, config); + if (ret) { + goto cleanup; + } + + /* delete keystore if present */ + ret = nc_server_config_check_delete(config, "%s/keystore-reference", tree_path); + if (ret) { + goto cleanup; + } + +cleanup: + free(privkey); + free(pubkey); + free(cert); + return ret; +} + +API 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 *certificate_path, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, certificate_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_server_cert(ctx, path, privkey_path, pubkey_path, + certificate_path, config); + if (ret) { + ERR(NULL, "Creating new TLS server certificate YANG data failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_tls_server_cert(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/inline-definition", endpt_name); +} + +API 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 *certificate_path, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, privkey_path, certificate_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" + "certificate", client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_server_cert(ctx, path, privkey_path, pubkey_path, + certificate_path, config); + if (ret) { + ERR(NULL, "Creating new CH TLS server certificate YANG data failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_ch_tls_server_cert(const char *client_name, const char *endpt_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" + "certificate/inline-definition", client_name, endpt_name); +} + +static int +_nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *tree_path, + const char *cert_path, struct lyd_node **config) +{ + int ret = 0; + char *cert = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, tree_path, cert_path, config, 1); + + ret = nc_server_config_util_read_certificate(cert_path, &cert); + if (ret) { + ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path); + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "cert-data", cert, config); + if (ret) { + goto cleanup; + } + +cleanup: + free(cert); + return ret; +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); + if (ret) { + ERR(NULL, "Creating new TLS client certificate YANG data failed."); + goto cleanup; + } + + /* delete truststore if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/truststore-reference", endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_tls_client_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (cert_name) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/inline-definition/" + "certificate[name='%s']", endpt_name, cert_name); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/inline-definition/" + "certificate", endpt_name); + } +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" + "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); + if (ret) { + ERR(NULL, "Creating new CH TLS client certificate YANG data failed."); + goto cleanup; + } + + /* delete truststore if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/truststore-reference", client_name, endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API 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) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (cert_name) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" + "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" + "inline-definition/certificate", client_name, endpt_name); + } +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); + if (ret) { + ERR(NULL, "Creating new TLS client certificate authority YANG data failed."); + goto cleanup; + } + + /* delete truststore if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/truststore-reference", endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_tls_ca_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (cert_name) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/inline-definition/" + "certificate[name='%s']", endpt_name, cert_name); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/inline-definition/" + "certificate", endpt_name); + } +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" + "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); + if (ret) { + ERR(NULL, "Creating new CH TLS client certificate authority YANG data failed."); + goto cleanup; + } + + /* delete truststore if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/truststore-reference", client_name, endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API 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) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (cert_name) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" + "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" + "inline-definition/certificate", client_name, endpt_name); + } +} + +static const char * +nc_server_config_tls_maptype2str(NC_TLS_CTN_MAPTYPE map_type) +{ + switch (map_type) { + case NC_TLS_CTN_SPECIFIED: + return "ietf-x509-cert-to-name:specified"; + case NC_TLS_CTN_SAN_RFC822_NAME: + return "ietf-x509-cert-to-name:san-rfc822-name"; + case NC_TLS_CTN_SAN_DNS_NAME: + return "ietf-x509-cert-to-name:san-dns-name"; + case NC_TLS_CTN_SAN_IP_ADDRESS: + return "ietf-x509-cert-to-name:san-ip-address"; + case NC_TLS_CTN_SAN_ANY: + return "ietf-x509-cert-to-name:san-any"; + case NC_TLS_CTN_COMMON_NAME: + return "ietf-x509-cert-to-name:common-name"; + case NC_TLS_CTN_UNKNOWN: + default: + ERR(NULL, "Unknown CTN mapping type."); + return NULL; + } +} + +static int +_nc_server_config_add_tls_ctn(const struct ly_ctx *ctx, const char *tree_path, const char *fingerprint, + NC_TLS_CTN_MAPTYPE map_type, const char *name, struct lyd_node **config) +{ + int ret = 0; + const char *map; + + NC_CHECK_ARG_RET(NULL, ctx, tree_path, name, config, 1); + + if (fingerprint) { + /* optional */ + ret = nc_server_config_append(ctx, tree_path, "fingerprint", fingerprint, config); + if (ret) { + goto cleanup; + } + } + + /* get map str */ + map = nc_server_config_tls_maptype2str(map_type); + if (!map) { + ret = 1; + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "map-type", map, config); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "name", name, config); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, name, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/netconf-server-parameters/" + "client-identity-mappings/cert-to-name[id='%u']", endpt_name, id) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_ctn(ctx, path, fingerprint, map_type, name, config); + if (ret) { + ERR(NULL, "Creating new TLS cert-to-name YANG data failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_tls_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (id) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "netconf-server-parameters/client-identity-mappings/cert-to-name[id='%u']", endpt_name, id); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "netconf-server-parameters/client-identity-mappings/cert-to-name", endpt_name); + } +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, id, name, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" + "cert-to-name[id='%u']", client_name, endpt_name, id) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_ctn(ctx, path, fingerprint, map_type, name, config); + if (ret) { + ERR(NULL, "Creating new CH TLS cert-to-name YANG data failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_ch_tls_ctn(const char *client_name, const char *endpt_name, + uint32_t id, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (id) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" + "cert-to-name[id='%u']", client_name, endpt_name, id); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" + "cert-to-name", client_name, endpt_name); + } +} + +API 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) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); + + return nc_server_config_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); +} + +API int +nc_server_config_del_tls_endpoint_client_ref(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index be94cf34..b3e75485 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,7 +8,7 @@ if(${SOURCE_FORMAT_ENABLED}) endif() # list of all the tests that don't require SSH and TLS -set(tests test_unix_socket) +set(tests test_unix_socket test_client_thread test_fd_comm test_init_destroy_client test_init_destroy_server test_io test_thread_messages) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) @@ -37,7 +37,7 @@ endforeach() #append tests depending on SSH/TLS if(ENABLE_SSH_TLS) - list(APPEND tests test_two_channels test_ks_ts test_config_new test_ec + list(APPEND tests test_two_channels test_ks_ts test_ec test_ed25519 test_replace test_endpt_share_clients test_tls test_crl test_ch test_runtime_changes) endif() diff --git a/tests/test_auth.c b/tests/test_auth.c index 87f6e894..631a84a5 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -1,7 +1,7 @@ /** * @file test_auth.c * @author Roman Janota - * @brief libnetconf2 Linux PAM keyboard-interactive authentication test + * @brief libnetconf2 SSH authentication methods test * * @copyright * Copyright (c) 2022 CESNET, z.s.p.o. @@ -315,22 +315,23 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); + ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); + ret = nc_server_config_add_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "test_pk", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt", "test_pk", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_interactive(ctx, "endpt", "test_int", "netconf.conf", BUILD_DIR "/tests", &tree); + ret = nc_server_config_add_ssh_user_interactive(ctx, "endpt", "test_int", "netconf.conf", BUILD_DIR "/tests", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_password(ctx, "endpt", "test_pw", "testpw", &tree); + ret = nc_server_config_add_ssh_user_password(ctx, "endpt", "test_pw", "testpw", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_none(ctx, "endpt", "test_none", &tree); + ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/ssh/ssh-server-parameters/" + "client-authentication/users/user[name='test_none']/none", NULL, 0, NULL); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_ch.c b/tests/test_ch.c index 5e48cbc5..558e29a2 100644 --- a/tests/test_ch.c +++ b/tests/test_ch.c @@ -98,7 +98,7 @@ server_thread_ssh(void *arg) strcpy(expected, "reconnecting in"); /* prepare data for deleting the call-home client */ - ret = nc_server_config_new_ch_del_ch_client("ch_ssh", &state->ssh_tree); + ret = nc_server_config_del_ch_client("ch_ssh", &state->ssh_tree); assert_int_equal(ret, 0); /* new poll session */ @@ -198,23 +198,23 @@ setup_ssh(void **state) assert_int_equal(ret, 0); /* set call-home address and port */ - ret = nc_server_config_new_ch_address_port(ctx, "ch_ssh", "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &test_state->ssh_tree); + ret = nc_server_config_add_ch_address_port(ctx, "ch_ssh", "endpt", NC_TI_LIBSSH, "127.0.0.1", "10009", &test_state->ssh_tree); assert_int_equal(ret, 0); /* set connection type to persistent */ - ret = nc_server_config_new_ch_persistent(ctx, "ch_ssh", &test_state->ssh_tree); + ret = nc_server_config_add_ch_persistent(ctx, "ch_ssh", &test_state->ssh_tree); assert_int_equal(ret, 0); /* set the period of the periodic connection type, this should remove the persistent connection type */ - ret = nc_server_config_new_ch_period(ctx, "ch_ssh", 3, &test_state->ssh_tree); + ret = nc_server_config_add_ch_period(ctx, "ch_ssh", 3, &test_state->ssh_tree); assert_int_equal(ret, 0); /* set call-home server hostkey */ - ret = nc_server_config_new_ch_ssh_hostkey(ctx, "ch_ssh", "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &test_state->ssh_tree); + ret = nc_server_config_add_ch_ssh_hostkey(ctx, "ch_ssh", "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &test_state->ssh_tree); assert_int_equal(ret, 0); /* set call-home client's pubkey */ - ret = nc_server_config_new_ch_ssh_user_pubkey(ctx, "ch_ssh", "endpt", "test_ch_ssh", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->ssh_tree); + ret = nc_server_config_add_ch_ssh_user_pubkey(ctx, "ch_ssh", "endpt", "test_ch_ssh", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->ssh_tree); assert_int_equal(ret, 0); /* configure the server based on the data */ @@ -282,7 +282,7 @@ server_thread_tls(void *arg) struct nc_pollsession *ps; /* prepare data for deleting the call-home client */ - ret = nc_server_config_new_ch_del_ch_client("ch_tls", &state->tls_tree); + ret = nc_server_config_del_ch_client("ch_tls", &state->tls_tree); assert_int_equal(ret, 0); /* new poll session */ @@ -400,23 +400,23 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* set call-home address and port */ - ret = nc_server_config_new_ch_address_port(ctx, "ch_tls", "endpt", NC_TI_OPENSSL, "127.0.0.1", "10010", &test_state->tls_tree); + ret = nc_server_config_add_ch_address_port(ctx, "ch_tls", "endpt", NC_TI_OPENSSL, "127.0.0.1", "10010", &test_state->tls_tree); assert_int_equal(ret, 0); /* set call-home server certificate */ - ret = nc_server_config_new_ch_tls_server_certificate(ctx, "ch_tls", "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tls_tree); + ret = nc_server_config_add_ch_tls_server_cert(ctx, "ch_tls", "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tls_tree); assert_int_equal(ret, 0); /* set call-home client end entity certificate */ - ret = nc_server_config_new_ch_tls_client_certificate(ctx, "ch_tls", "endpt", "ee-cert", TESTS_DIR "/data/client.crt", &test_state->tls_tree); + ret = nc_server_config_add_ch_tls_client_cert(ctx, "ch_tls", "endpt", "ee-cert", TESTS_DIR "/data/client.crt", &test_state->tls_tree); assert_int_equal(ret, 0); /* set call-home client certificate authority certificate */ - ret = nc_server_config_new_ch_tls_client_ca(ctx, "ch_tls", "endpt", "ca-cert", TESTS_DIR "/data/serverca.pem", &test_state->tls_tree); + ret = nc_server_config_add_ch_tls_ca_cert(ctx, "ch_tls", "endpt", "ca-cert", TESTS_DIR "/data/serverca.pem", &test_state->tls_tree); assert_int_equal(ret, 0); /* set call-home CTN */ - ret = nc_server_config_new_ch_tls_ctn(ctx, "ch_tls", "endpt", 1, + ret = nc_server_config_add_ch_tls_ctn(ctx, "ch_tls", "endpt", 1, "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", NC_TLS_CTN_SPECIFIED, "ch_client_tls", &test_state->tls_tree); assert_int_equal(ret, 0); diff --git a/tests/test_config_new.c b/tests/test_config_new.c deleted file mode 100644 index 72dda366..00000000 --- a/tests/test_config_new.c +++ /dev/null @@ -1,213 +0,0 @@ -/** - * @file test_keystore.c - * @author Roman Janota - * @brief libnetconf2 Linux PAM keyboard-interactive authentication test - * - * @copyright - * Copyright (c) 2022 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 - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include - -#include - -#include "tests/config.h" - -#define NC_ACCEPT_TIMEOUT 2000 -#define NC_PS_POLL_TIMEOUT 2000 - -struct ly_ctx *ctx; - -struct test_state { - pthread_barrier_t barrier; -}; - -static void * -server_thread(void *arg) -{ - int ret; - NC_MSG_TYPE msgtype; - struct nc_session *session; - struct nc_pollsession *ps; - struct test_state *state = arg; - - ps = nc_ps_new(); - assert_non_null(ps); - - /* accept a session and add it to the poll session structure */ - pthread_barrier_wait(&state->barrier); - msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); - assert_int_equal(msgtype, NC_MSG_HELLO); - - ret = nc_ps_add_session(ps, session); - assert_int_equal(ret, 0); - - do { - ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); - assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); - } while (!(ret & NC_PSPOLL_SESSION_TERM)); - - nc_ps_clear(ps, 1, NULL); - nc_ps_free(ps); - return NULL; -} - -static char * -auth_password(const char *username, const char *hostname, void *priv) -{ - (void) username; - (void) hostname; - (void) priv; - - /* set the reply to password authentication */ - return strdup("testpassword123"); -} - -static void * -client_thread(void *arg) -{ - int ret; - struct nc_session *session = NULL; - struct test_state *state = arg; - - /* skip all hostkey and known_hosts checks */ - nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); - - ret = nc_client_set_schema_searchpath(MODULES_DIR); - assert_int_equal(ret, 0); - - ret = nc_client_ssh_set_username("client"); - assert_int_equal(ret, 0); - - nc_client_ssh_set_auth_password_clb(auth_password, NULL); - - pthread_barrier_wait(&state->barrier); - session = nc_connect_ssh("127.0.0.1", 10005, NULL); - assert_non_null(session); - - nc_session_free(session, NULL); - return NULL; -} - -static void -test_nc_config_new(void **state) -{ - int ret, i; - pthread_t tids[2]; - - assert_non_null(state); - - ret = pthread_create(&tids[0], NULL, client_thread, *state); - assert_int_equal(ret, 0); - ret = pthread_create(&tids[1], NULL, server_thread, *state); - assert_int_equal(ret, 0); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static int -setup_f(void **state) -{ - int ret; - struct lyd_node *tree = NULL; - struct test_state *test_state; - - nc_verbosity(NC_VERB_VERBOSE); - - /* init barrier */ - test_state = malloc(sizeof *test_state); - assert_non_null(test_state); - - ret = pthread_barrier_init(&test_state->barrier, NULL, 2); - assert_int_equal(ret, 0); - - *state = test_state; - - /* new context */ - ret = ly_ctx_new(MODULES_DIR, 0, &ctx); - assert_int_equal(ret, 0); - - /* initialize the context by loading default modules */ - ret = nc_server_init_ctx(&ctx); - assert_int_equal(ret, 0); - - /* load ietf-netconf-server module and it's imports */ - ret = nc_server_config_load_modules(&ctx); - assert_int_equal(ret, 0); - - /* create new hostkey data */ - ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/server.key", NULL, &tree); - assert_int_equal(ret, 0); - - /* create new address and port data */ - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); - assert_int_equal(ret, 0); - - /* create the host-key algorithms data */ - ret = nc_server_config_new_ssh_host_key_algs(ctx, "endpt", &tree, 1, "rsa-sha2-512"); - assert_int_equal(ret, 0); - - /* create the client authentication data, password only */ - ret = nc_server_config_new_ssh_user_password(ctx, "endpt", "client", "testpassword123", &tree); - assert_int_equal(ret, 0); - - /* configure the server based on the data */ - ret = nc_server_config_setup_data(tree); - assert_int_equal(ret, 0); - - ret = nc_server_init(); - assert_int_equal(ret, 0); - - /* initialize client */ - ret = nc_client_init(); - assert_int_equal(ret, 0); - - lyd_free_all(tree); - - return 0; -} - -static int -teardown_f(void **state) -{ - int ret = 0; - struct test_state *test_state; - - assert_non_null(state); - test_state = *state; - - ret = pthread_barrier_destroy(&test_state->barrier); - assert_int_equal(ret, 0); - - free(*state); - nc_client_destroy(); - nc_server_destroy(); - ly_ctx_destroy(ctx); - - return 0; -} - -int -main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_nc_config_new, setup_f, teardown_f), - }; - - setenv("CMOCKA_TEST_ABORT", "1", 1); - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/tests/test_crl.c b/tests/test_crl.c index 213792b2..6cd6dc77 100644 --- a/tests/test_crl.c +++ b/tests/test_crl.c @@ -144,48 +144,32 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new address and port data */ - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", 10005, &tree); + ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); /* create new server certificate data */ - ret = nc_server_config_new_tls_server_certificate(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_add_tls_server_cert(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); /* create new end entity client cert data */ - ret = nc_server_config_new_tls_client_certificate(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); + ret = nc_server_config_add_tls_client_cert(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); assert_int_equal(ret, 0); /* create new client ca data */ - ret = nc_server_config_new_tls_client_ca(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); + ret = nc_server_config_add_tls_ca_cert(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); assert_int_equal(ret, 0); /* create new cert-to-name */ - ret = nc_server_config_new_tls_ctn(ctx, "endpt", 1, + ret = nc_server_config_add_tls_ctn(ctx, "endpt", 1, "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", NC_TLS_CTN_SPECIFIED, "client", &tree); assert_int_equal(ret, 0); - /* limit TLS version to 1.3 */ - ret = nc_server_config_new_tls_version(ctx, "endpt", NC_TLS_VERSION_13, &tree); - assert_int_equal(ret, 0); - - /* set the TLS cipher */ - ret = nc_server_config_new_tls_ciphers(ctx, "endpt", &tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); - assert_int_equal(ret, 0); - - /* set this node, but it should be deleted by the next call, bcs only one choice node can be present */ - ret = nc_server_config_new_tls_crl_url(ctx, "endpt", "abc", &tree); - assert_int_equal(ret, 0); - /* set path to a CRL file */ - ret = nc_server_config_new_tls_crl_path(ctx, "endpt", TESTS_DIR "/data/crl.pem", &tree); + ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-path", TESTS_DIR "/data/crl.pem", 0, NULL); assert_int_equal(ret, 0); - /* check if the choice node was removed */ - ret = lyd_find_path(tree, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-url", 0, NULL); - assert_int_not_equal(ret, 0); - /* configure the server based on the data */ ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); diff --git a/tests/test_ec.c b/tests/test_ec.c index 43d513f1..415588d7 100644 --- a/tests/test_ec.c +++ b/tests/test_ec.c @@ -213,19 +213,19 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); + ret = nc_server_config_add_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10009, &tree); + ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10009, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "test_ec256", "pubkey", TESTS_DIR "/data/id_ecdsa256.pub", &tree); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt", "test_ec256", "pubkey", TESTS_DIR "/data/id_ecdsa256.pub", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "test_ec384", "pubkey", TESTS_DIR "/data/id_ecdsa384.pub", &tree); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt", "test_ec384", "pubkey", TESTS_DIR "/data/id_ecdsa384.pub", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "test_ec521", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt", "test_ec521", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_ed25519.c b/tests/test_ed25519.c index b381c6ab..714a88a8 100644 --- a/tests/test_ed25519.c +++ b/tests/test_ed25519.c @@ -150,13 +150,13 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/server.key", NULL, &tree); + ret = nc_server_config_add_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/server.key", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10009, &tree); + ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10009, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "test_ed25519", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt", "test_ed25519", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c index f9284fe0..7099d77e 100644 --- a/tests/test_endpt_share_clients.c +++ b/tests/test_endpt_share_clients.c @@ -193,23 +193,23 @@ setup_ssh(void **state) assert_int_equal(ret, 0); /* create the first SSH endpoint with a client reference to the second endpoint */ - ret = nc_server_config_new_ssh_hostkey(ctx, "SSH_endpt_1", "hostkey", TESTS_DIR "/data/key_rsa", NULL, &tree); + ret = nc_server_config_add_ssh_hostkey(ctx, "SSH_endpt_1", "hostkey", TESTS_DIR "/data/key_rsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "SSH_endpt_1", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); + ret = nc_server_config_add_address_port(ctx, "SSH_endpt_1", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); - ret = nc_config_new_ssh_endpoint_user_ref(ctx, "SSH_endpt_1", "SSH_endpt_2", &tree); + ret = nc_server_config_add_ssh_endpoint_client_ref(ctx, "SSH_endpt_1", "SSH_endpt_2", &tree); assert_int_equal(ret, 0); /* create the second SSH endpoint with a single client */ - ret = nc_server_config_new_ssh_hostkey(ctx, "SSH_endpt_2", "hostkey", TESTS_DIR "/data/key_rsa", NULL, &tree); + ret = nc_server_config_add_ssh_hostkey(ctx, "SSH_endpt_2", "hostkey", TESTS_DIR "/data/key_rsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "SSH_endpt_2", NC_TI_LIBSSH, "127.0.0.1", 10006, &tree); + ret = nc_server_config_add_address_port(ctx, "SSH_endpt_2", NC_TI_LIBSSH, "127.0.0.1", 10006, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_pubkey(ctx, "SSH_endpt_2", "client", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "SSH_endpt_2", "client", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the yang data */ @@ -260,32 +260,32 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* create the first TLS endpoint with a single end entity client cert and a CTN entry */ - ret = nc_server_config_new_tls_server_certificate(ctx, "TLS_endpt_1", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_add_tls_server_cert(ctx, "TLS_endpt_1", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "TLS_endpt_1", NC_TI_OPENSSL, "127.0.0.1", 10007, &tree); + ret = nc_server_config_add_address_port(ctx, "TLS_endpt_1", NC_TI_OPENSSL, "127.0.0.1", 10007, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_tls_client_certificate(ctx, "TLS_endpt_1", "cert_client", TESTS_DIR "/data/client.crt", &tree); + ret = nc_server_config_add_tls_client_cert(ctx, "TLS_endpt_1", "cert_client", TESTS_DIR "/data/client.crt", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_tls_client_ca(ctx, "TLS_endpt_1", "cert_ca", TESTS_DIR "/data/serverca.pem", &tree); + ret = nc_server_config_add_tls_ca_cert(ctx, "TLS_endpt_1", "cert_ca", TESTS_DIR "/data/serverca.pem", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_tls_ctn(ctx, "TLS_endpt_1", 1, + ret = nc_server_config_add_tls_ctn(ctx, "TLS_endpt_1", 1, "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", NC_TLS_CTN_SPECIFIED, "client", &tree); assert_int_equal(ret, 0); /* create the second TLS endpoint with a reference to the first endpoint */ - ret = nc_server_config_new_tls_server_certificate(ctx, "TLS_endpt_2", + ret = nc_server_config_add_tls_server_cert(ctx, "TLS_endpt_2", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "TLS_endpt_2", NC_TI_OPENSSL, "127.0.0.1", 10008, &tree); + ret = nc_server_config_add_address_port(ctx, "TLS_endpt_2", NC_TI_OPENSSL, "127.0.0.1", 10008, &tree); assert_int_equal(ret, 0); - ret = nc_config_new_tls_endpoint_client_ref(ctx, "TLS_endpt_2", "TLS_endpt_1", &tree); + ret = nc_server_config_add_tls_endpoint_client_ref(ctx, "TLS_endpt_2", "TLS_endpt_1", &tree); assert_int_equal(ret, 0); /* configure the server based on the yang data */ diff --git a/tests/test_init_destroy_client.c b/tests/test_init_destroy_client.c index 097fa69e..a9ee0dbc 100644 --- a/tests/test_init_destroy_client.c +++ b/tests/test_init_destroy_client.c @@ -39,6 +39,8 @@ setup_client(void **state) { (void)state; + nc_client_init(); + return 0; } diff --git a/tests/test_ks_ts.c b/tests/test_ks_ts.c index 159b6cff..5440b7e6 100644 --- a/tests/test_ks_ts.c +++ b/tests/test_ks_ts.c @@ -138,19 +138,23 @@ setup_ssh(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); + ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_keystore_ref(ctx, "endpt", "hostkey", "test_keystore", &tree); + ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='endpt']/ssh/ssh-server-parameters/server-identity/host-key[name='hostkey']/public-key/" + "keystore-reference", "test_keystore", 0, NULL); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_truststore_ref(ctx, "endpt", "client", "test_truststore", &tree); + ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='endpt']/ssh/ssh-server-parameters/client-authentication/users/user[name='client']/public-keys/" + "truststore-reference", "test_truststore", 0, NULL); assert_int_equal(ret, 0); - ret = nc_server_config_new_keystore_asym_key(ctx, NC_TI_LIBSSH, "test_keystore", TESTS_DIR "/data/key_rsa", NULL, &tree); + ret = nc_server_config_add_keystore_asym_key(ctx, NC_TI_LIBSSH, "test_keystore", TESTS_DIR "/data/key_rsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_truststore_pubkey(ctx, "test_truststore", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); + ret = nc_server_config_add_truststore_pubkey(ctx, NC_TI_LIBSSH, "test_truststore", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ @@ -244,39 +248,45 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* new tls bind */ - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", 10005, &tree); + ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); /* new keystore asym key pair */ - ret = nc_server_config_new_keystore_asym_key(ctx, NC_TI_OPENSSL, "server_key", TESTS_DIR "/data/server.key", NULL, &tree); + ret = nc_server_config_add_keystore_asym_key(ctx, NC_TI_OPENSSL, "server_key", TESTS_DIR "/data/server.key", NULL, &tree); assert_int_equal(ret, 0); /* new keystore cert belonging to the key pair */ - ret = nc_server_config_new_keystore_cert(ctx, "server_key", "server_cert", TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_add_keystore_cert(ctx, "server_key", "server_cert", TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); /* new truststore client cert */ - ret = nc_server_config_new_truststore_cert(ctx, "ee_cert_bag", "ee_cert", TESTS_DIR "/data/client.crt", &tree); + ret = nc_server_config_add_truststore_cert(ctx, "ee_cert_bag", "ee_cert", TESTS_DIR "/data/client.crt", &tree); assert_int_equal(ret, 0); /* new truststore client CA cert */ - ret = nc_server_config_new_truststore_cert(ctx, "ca_cert_bag", "ca_cert", TESTS_DIR "/data/serverca.pem", &tree); + ret = nc_server_config_add_truststore_cert(ctx, "ca_cert_bag", "ca_cert", TESTS_DIR "/data/serverca.pem", &tree); assert_int_equal(ret, 0); /* new keystore ref for the TLS server cert */ - ret = nc_server_config_new_tls_keystore_ref(ctx, "endpt", "server_key", "server_cert", &tree); + ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/" + "tls/tls-server-parameters/server-identity/certificate/keystore-reference/asymmetric-key", "server_key", 0, NULL); + assert_int_equal(ret, 0); + ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/" + "tls/tls-server-parameters/server-identity/certificate/keystore-reference/certificate", "server_cert", 0, NULL); assert_int_equal(ret, 0); /* new truststore ref for the client cert */ - ret = nc_server_config_new_tls_client_cert_truststore_ref(ctx, "endpt", "ee_cert_bag", &tree); + ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/tls/" + "tls-server-parameters/client-authentication/ee-certs/truststore-reference", "ee_cert_bag", 0, NULL); assert_int_equal(ret, 0); /* new truststore ref for the client CA cert */ - ret = nc_server_config_new_tls_client_ca_truststore_ref(ctx, "endpt", "ca_cert_bag", &tree); + ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/tls/" + "tls-server-parameters/client-authentication/ca-certs/truststore-reference", "ca_cert_bag", 0, NULL); assert_int_equal(ret, 0); /* new cert-to-name */ - ret = nc_server_config_new_tls_ctn(ctx, "endpt", 1, + ret = nc_server_config_add_tls_ctn(ctx, "endpt", 1, "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", NC_TLS_CTN_SPECIFIED, "client", &tree); assert_int_equal(ret, 0); diff --git a/tests/test_replace.c b/tests/test_replace.c index 7a61cee7..1fd09371 100644 --- a/tests/test_replace.c +++ b/tests/test_replace.c @@ -233,26 +233,26 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "old", NC_TI_LIBSSH, "127.0.0.1", 10005, &old_tree); + ret = nc_server_config_add_address_port(ctx, "old", NC_TI_LIBSSH, "127.0.0.1", 10005, &old_tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_hostkey(ctx, "old", "old_key", TESTS_DIR "/data/key_rsa", NULL, &old_tree); + ret = nc_server_config_add_ssh_hostkey(ctx, "old", "old_key", TESTS_DIR "/data/key_rsa", NULL, &old_tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_password(ctx, "old", "old_client", "passwd", &old_tree); + ret = nc_server_config_add_ssh_user_password(ctx, "old", "old_client", "passwd", &old_tree); assert_int_equal(ret, 0); /* configure the server based on the yang data, treat them as if every node had replace operation */ ret = nc_server_config_setup_data(old_tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "new", NC_TI_LIBSSH, "127.0.0.1", 10005, &new_tree); + ret = nc_server_config_add_address_port(ctx, "new", NC_TI_LIBSSH, "127.0.0.1", 10005, &new_tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_hostkey(ctx, "new", "new_key", TESTS_DIR "/data/key_rsa", NULL, &new_tree); + ret = nc_server_config_add_ssh_hostkey(ctx, "new", "new_key", TESTS_DIR "/data/key_rsa", NULL, &new_tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_pubkey(ctx, "new", "new_client", "pubkey", TESTS_DIR "/data/key_rsa.pub", &new_tree); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "new", "new_client", "pubkey", TESTS_DIR "/data/key_rsa.pub", &new_tree); assert_int_equal(ret, 0); /* configure the server based on the yang data, meaning diff --git a/tests/test_runtime_changes.c b/tests/test_runtime_changes.c index a7cd45df..284d3606 100644 --- a/tests/test_runtime_changes.c +++ b/tests/test_runtime_changes.c @@ -240,11 +240,11 @@ test_nc_change_tls_srv_crt(void **state) test_state = *state; init_test_create_threads_tls(tids, state); - ret = nc_server_config_new_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/client.key", NULL, TESTS_DIR "/data/client.crt", &test_state->tree); + ret = nc_server_config_add_tls_server_cert(ctx, "endpt_tls", TESTS_DIR "/data/client.key", NULL, TESTS_DIR "/data/client.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - ret = nc_server_config_new_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); + ret = nc_server_config_add_tls_server_cert(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); @@ -264,11 +264,11 @@ test_nc_change_tls_client_crt(void **state) test_state = *state; init_test_create_threads_tls(tids, state); - ret = nc_server_config_new_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/server.crt", &test_state->tree); + ret = nc_server_config_add_tls_client_cert(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/server.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - ret = nc_server_config_new_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); + ret = nc_server_config_add_tls_client_cert(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); @@ -288,13 +288,13 @@ test_nc_change_tls_ctn(void **state) test_state = *state; init_test_create_threads_tls(tids, state); - ret = nc_server_config_new_tls_ctn(ctx, "endpt_tls", 1, + ret = nc_server_config_add_tls_ctn(ctx, "endpt_tls", 1, "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF", NC_TLS_CTN_SPECIFIED, "invalid-fingerprint", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - ret = nc_server_config_new_tls_ctn(ctx, "endpt_tls", 1, + ret = nc_server_config_add_tls_ctn(ctx, "endpt_tls", 1, "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", NC_TLS_CTN_SPECIFIED, "client", &test_state->tree); assert_int_equal(ret, 0); @@ -305,96 +305,34 @@ test_nc_change_tls_ctn(void **state) } } -static void -test_nc_change_tls_version(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct test_state *test_state; - - assert_non_null(state); - test_state = *state; - init_test_create_threads_tls(tids, state); - - ret = nc_server_config_new_tls_version(ctx, "endpt_tls", NC_TLS_VERSION_11, &test_state->tree); - assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - - ret = nc_server_config_new_tls_version(ctx, "endpt_tls", NC_TLS_VERSION_13, &test_state->tree); - assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static void -test_nc_change_tls_ciphers(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct test_state *test_state; - - assert_non_null(state); - test_state = *state; - init_test_create_threads_tls(tids, state); - - ret = nc_server_config_new_tls_ciphers(ctx, "endpt_tls", &test_state->tree, 1, "tls-rsa-with-null-sha"); - assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - - ret = nc_server_config_new_tls_ciphers(ctx, "endpt_tls", &test_state->tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); - assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - static void test_nc_change_ssh_hostkey(void **state) { int ret, i; pthread_t tids[2]; struct test_state *test_state; + struct lyd_node *hostkey = NULL; assert_non_null(state); test_state = *state; init_test_create_threads_ssh(tids, state); - ret = nc_server_config_new_ssh_hostkey(ctx, "endpt_ssh", "hostkey", TESTS_DIR "/data/server.key", NULL, &test_state->tree); + ret = nc_server_config_add_ssh_hostkey(ctx, "endpt_ssh", "hostkey", TESTS_DIR "/data/server.key", NULL, &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_RUN); - ret = nc_server_config_new_keystore_asym_key(ctx, NC_TI_LIBSSH, "keystore_hostkey", TESTS_DIR "/data/key_rsa", TESTS_DIR "/data/key_rsa.pub", &test_state->tree); - assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_keystore_ref(ctx, "endpt_ssh", "hostkey", "keystore_hostkey", &test_state->tree); - assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static void -test_nc_change_ssh_usr_pubkey(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct test_state *test_state; - - assert_non_null(state); - test_state = *state; - init_test_create_threads_ssh(tids, state); + /* delete the locally defined hostkey */ + ret = lyd_find_path(test_state->tree, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='endpt_ssh']/ssh/ssh-server-parameters/server-identity/host-key[name='hostkey']/public-key", 0, &hostkey); + assert_non_null(hostkey); + lyd_free_tree(hostkey); - ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt_ssh", "client", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &test_state->tree); + /* add the keystore entry and set it as hostkey */ + ret = nc_server_config_add_keystore_asym_key(ctx, NC_TI_LIBSSH, "keystore_hostkey", TESTS_DIR "/data/key_rsa", TESTS_DIR "/data/key_rsa.pub", &test_state->tree); assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - - ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt_ssh", "client", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->tree); + ret = lyd_new_path(test_state->tree, ctx, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='endpt_ssh']/ssh/ssh-server-parameters/server-identity/host-key[name='hostkey']/public-key/" + "keystore-reference", "keystore_hostkey", 0, NULL); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); @@ -404,7 +342,7 @@ test_nc_change_ssh_usr_pubkey(void **state) } static void -test_nc_change_ssh_hostkey_algs(void **state) +test_nc_change_ssh_usr_pubkey(void **state) { int ret, i; pthread_t tids[2]; @@ -414,11 +352,11 @@ test_nc_change_ssh_hostkey_algs(void **state) test_state = *state; init_test_create_threads_ssh(tids, state); - ret = nc_server_config_new_ssh_host_key_algs(ctx, "endpt_ssh", &test_state->tree, 1, "ssh-dss"); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt_ssh", "client", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - ret = nc_server_config_new_ssh_host_key_algs(ctx, "endpt_ssh", &test_state->tree, 1, "rsa-sha2-256"); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt_ssh", "client", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); @@ -457,33 +395,33 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new address and port data */ - ret = nc_server_config_new_address_port(ctx, "endpt_tls", NC_TI_OPENSSL, "127.0.0.1", 10005, &test_state->tree); + ret = nc_server_config_add_address_port(ctx, "endpt_tls", NC_TI_OPENSSL, "127.0.0.1", 10005, &test_state->tree); assert_int_equal(ret, 0); /* create new server certificate data */ - ret = nc_server_config_new_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); + ret = nc_server_config_add_tls_server_cert(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); assert_int_equal(ret, 0); /* create new end entity client cert data */ - ret = nc_server_config_new_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); + ret = nc_server_config_add_tls_client_cert(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); assert_int_equal(ret, 0); /* create new cert-to-name */ - ret = nc_server_config_new_tls_ctn(ctx, "endpt_tls", 1, + ret = nc_server_config_add_tls_ctn(ctx, "endpt_tls", 1, "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", NC_TLS_CTN_SPECIFIED, "client", &test_state->tree); assert_int_equal(ret, 0); /* create new address and port data */ - ret = nc_server_config_new_address_port(ctx, "endpt_ssh", NC_TI_LIBSSH, "127.0.0.1", 10006, &test_state->tree); + ret = nc_server_config_add_address_port(ctx, "endpt_ssh", NC_TI_LIBSSH, "127.0.0.1", 10006, &test_state->tree); assert_int_equal(ret, 0); /* create new hostkey data */ - ret = nc_server_config_new_ssh_hostkey(ctx, "endpt_ssh", "hostkey", TESTS_DIR "/data/server.key", NULL, &test_state->tree); + ret = nc_server_config_add_ssh_hostkey(ctx, "endpt_ssh", "hostkey", TESTS_DIR "/data/server.key", NULL, &test_state->tree); assert_int_equal(ret, 0); /* create new ssh user pubkey data */ - ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt_ssh", "client", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->tree); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt_ssh", "client", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &test_state->tree); assert_int_equal(ret, 0); ret = nc_server_init(); @@ -526,11 +464,8 @@ main(void) cmocka_unit_test_setup_teardown(test_nc_change_tls_srv_crt, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_change_tls_client_crt, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_change_tls_ctn, setup_f, teardown_f), - cmocka_unit_test_setup_teardown(test_nc_change_tls_version, setup_f, teardown_f), - cmocka_unit_test_setup_teardown(test_nc_change_tls_ciphers, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_change_ssh_hostkey, setup_f, teardown_f), - cmocka_unit_test_setup_teardown(test_nc_change_ssh_usr_pubkey, setup_f, teardown_f), - cmocka_unit_test_setup_teardown(test_nc_change_ssh_hostkey_algs, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_change_ssh_usr_pubkey, setup_f, teardown_f) }; setenv("CMOCKA_TEST_ABORT", "1", 1); diff --git a/tests/test_tls.c b/tests/test_tls.c index dc5b502b..542f7bdb 100644 --- a/tests/test_tls.c +++ b/tests/test_tls.c @@ -138,35 +138,27 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new address and port data */ - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", 10005, &tree); + ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); /* create new server certificate data */ - ret = nc_server_config_new_tls_server_certificate(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_add_tls_server_cert(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); /* create new end entity client cert data */ - ret = nc_server_config_new_tls_client_certificate(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); + ret = nc_server_config_add_tls_client_cert(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); assert_int_equal(ret, 0); /* create new client ca data */ - ret = nc_server_config_new_tls_client_ca(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); + ret = nc_server_config_add_tls_ca_cert(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); assert_int_equal(ret, 0); /* create new cert-to-name */ - ret = nc_server_config_new_tls_ctn(ctx, "endpt", 1, + ret = nc_server_config_add_tls_ctn(ctx, "endpt", 1, "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", NC_TLS_CTN_SPECIFIED, "client", &tree); assert_int_equal(ret, 0); - /* limit TLS version to 1.3 */ - ret = nc_server_config_new_tls_version(ctx, "endpt", NC_TLS_VERSION_13, &tree); - assert_int_equal(ret, 0); - - /* set the TLS cipher */ - ret = nc_server_config_new_tls_ciphers(ctx, "endpt", &tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); - assert_int_equal(ret, 0); - /* configure the server based on the data */ ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c index 38597c00..24e7353a 100644 --- a/tests/test_two_channels.c +++ b/tests/test_two_channels.c @@ -154,16 +154,16 @@ setup_f(void **state) ret = nc_server_config_load_modules(&ctx); assert_int_equal(ret, 0); - ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); + ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); + ret = nc_server_config_add_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "client_1", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt", "client_1", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_new_ssh_user_pubkey(ctx, "endpt", "client_2", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); + ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt", "client_2", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); assert_int_equal(ret, 0); ret = nc_server_config_setup_data(tree); diff --git a/tests/test_unix_socket.c b/tests/test_unix_socket.c index 5743fd44..351a6e23 100644 --- a/tests/test_unix_socket.c +++ b/tests/test_unix_socket.c @@ -1,7 +1,7 @@ /** - * @file test_keystore.c + * @file test_unix_socket.c * @author Roman Janota - * @brief libnetconf2 Linux PAM keyboard-interactive authentication test + * @brief libnetconf2 UNIX socket test * * @copyright * Copyright (c) 2022 CESNET, z.s.p.o. @@ -132,7 +132,7 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create the UNIX socket */ - ret = nc_server_config_new_unix_socket(ctx, "unix", "/tmp/nc2_test_unix_sock", 0700, -1, -1, &tree); + ret = nc_server_config_add_unix_socket(ctx, "unix", "/tmp/nc2_test_unix_sock", 0700, -1, -1, &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ From abee710f1985169c803058e4c248980a15d4470e Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 13 Oct 2023 14:32:19 +0200 Subject: [PATCH 089/134] config UPDATE rename and doc --- doc/libnetconf.doc | 118 +++-- src/server_config.h | 857 ++++++++++++++++++++++++++++++- src/server_config_util.c | 15 +- src/server_config_util_ssh.c | 644 +++++++++++++++++++++++ src/server_config_util_tls.c | 842 +++++++++++++++++++++++++++++- tests/test_auth.c | 5 +- tests/test_ch.c | 6 +- tests/test_config_new.c | 213 ++++++++ tests/test_crl.c | 26 +- tests/test_endpt_share_clients.c | 8 +- tests/test_ks_ts.c | 22 +- tests/test_runtime_changes.c | 101 +++- tests/test_tls.c | 14 +- 13 files changed, 2741 insertions(+), 130 deletions(-) create mode 100644 tests/test_config_new.c diff --git a/doc/libnetconf.doc b/doc/libnetconf.doc index b58f96fc..20be760f 100644 --- a/doc/libnetconf.doc +++ b/doc/libnetconf.doc @@ -18,7 +18,7 @@ * - Creating, sending, receiving, and replying to RPCs ([RFC 4741](https://tools.ietf.org/html/rfc4741), * [RFC 6241](https://tools.ietf.org/html/rfc6241)). * - Creating, sending and receiving NETCONF Event Notifications ([RFC 5277](https://tools.ietf.org/html/rfc5277)). - * - Configuring the NETCONF server based on the [ietf-netconf-server](https://datatracker.ietf.org/doc/html/draft-ietf-netconf-netconf-client-server-29) YANG module. + * - Configuring the NETCONF server based on the [ietf-netconf-server](https://datatracker.ietf.org/doc/html/draft-ietf-netconf-netconf-client-server-29) YANG module * * @section about-license License * @@ -219,7 +219,7 @@ * If you authenticated the connection using some tunneling software, you * can pass its file descriptors to _libnetconf2_ using ::nc_connect_inout(), * which will continue to establish a full NETCONF session. To connect locally - * on a UNIX socket avoiding all cryptography use ::nc_connect_unix(). + * on a UNIX socket avoiding all cryptography use ::nc_connect_unix(). * * Funtions List * ------------- @@ -327,28 +327,24 @@ * data - *YANG data* and *YANG diff*. * * YANG data - * --------- - * + * == * Configuring the server using YANG data simplifies the management of network services. * With YANG data, you build a structured configuration tree and apply it as a whole. * This approach is user-friendly, allowing you to modify the configuration by adding or deleting nodes, * and then deploying the updated configuration tree in its entirety, providing a way to manage your server's settings. * The *libnetconf2* library exports API functions that can help you with creation or deletion of the *YANG* data. - * Using this approach requires you to have access to the current configuration whenever you want to make any changes. * * YANG diff - * --------- - * + * == * YANG diff, enriched with operation attributes, offers advanced configuration control. * It empowers the user to make precise changes within the configuration tree, * enabling operations like specific node deletions, additions, and modifications. * On the other hand, unlike YANG data, YANG diff represents only a subtree of the * changes expecting the whole configuration to be managed externally. - * For example this approach is used by the tool [sysrepo](https://www.sysrepo.org/). + * For example this is done by the tool [sysrepo](https://www.sysrepo.org/). * * Usage - * ----- - * + * == * To be able to configure the server, the required models first need to be implemented. * To do this, see ::nc_server_config_load_modules(). * Not all of the *ietf-netconf-server* (and all of its associated modules) features are enabled. @@ -378,7 +374,6 @@ * - ::nc_server_config_add_address_port() * - ::nc_server_config_add_unix_socket() * - ::nc_server_config_del_endpt() - * * - ::nc_server_config_add_keystore_asym_key() * - ::nc_server_config_del_keystore_asym_key() * - ::nc_server_config_add_keystore_cert() @@ -399,8 +394,7 @@ * Another option for authorized clients is to reference another endpoint's clients, however be careful not to create a cyclic reference * (see ::nc_server_config_add_ssh_endpoint_client_ref()). An authorized client MUST authenticate to all of it's configured authentication methods. * - * There are also some other optional settings. Like setting the authentication attempts and timeout of an authorized client, or - * setting the encryption/key exchange/mac/public key algorithms, etc. + * There are also some other optional settings. * * Functions List * -------------- @@ -409,6 +403,8 @@ * * - ::nc_server_config_add_ssh_hostkey() * - ::nc_server_config_del_ssh_hostkey() + * - ::nc_server_config_add_ssh_keystore_ref() + * - ::nc_server_config_del_ssh_keystore_ref() * - ::nc_server_config_add_ssh_auth_attempts() * - ::nc_server_config_add_ssh_auth_timeout() * @@ -416,12 +412,26 @@ * - ::nc_server_config_del_ssh_user_pubkey() * - ::nc_server_config_add_ssh_user_password() * - ::nc_server_config_del_ssh_user_password() + * - ::nc_server_config_add_ssh_user_none() + * - ::nc_server_config_del_ssh_user_none() * - ::nc_server_config_add_ssh_user_interactive() * - ::nc_server_config_del_ssh_user_interactive() * - ::nc_server_config_del_ssh_user() + * - ::nc_server_config_add_ssh_truststore_ref() + * - ::nc_server_config_del_ssh_truststore_ref() * - ::nc_server_config_add_ssh_endpoint_client_ref() * - ::nc_server_config_del_ssh_endpoint_client_ref() * + * - ::nc_server_config_add_ssh_host_key_algs() + * - ::nc_server_config_del_ssh_host_key_alg() + * - ::nc_server_config_add_ssh_key_exchange_algs() + * - ::nc_server_config_del_ssh_key_exchange_alg() + * - ::nc_server_config_add_ssh_encryption_algs() + * - ::nc_server_config_del_ssh_encryption_alg() + * - ::nc_server_config_add_ssh_mac_algs() + * - ::nc_server_config_del_ssh_mac_alg() + * + * * TLS * === * @@ -430,7 +440,7 @@ * options that TLS uses to derive usernames from client certificates. * * If you wish to listen on a TLS endpoint, you need to configure the endpoint's - * server certificate (see ::nc_server_config_add_tls_server_cert()). + * server certificate (see ::nc_server_config_add_tls_server_certificate()). * * To accept client certificates, they must first be considered trusted. * For each TLS endpoint you may configure two types of client certificates. @@ -446,25 +456,44 @@ * _cert-to-name_ entry. * * There are some further options. For example you can configure the TLS - * version and ciphers to be used or you can even use a Certificate Revocation List. + * version and ciphers to be used. You may also choose to use a Certificate + * Revoke List. There are three options, ::nc_server_config_add_tls_crl_path() + * attempts to get the list of revoked certificates from a file. ::nc_server_config_add_tls_crl_url() + * attempts to download the list from the given URL. Lastly, ::nc_server_config_add_tls_crl_cert_ext() + * attempts to download the CRLs from URLs specified in the extension fields of the configured certificates. * * Functions List * -------------- * * Available in __nc_server.h__. * - * - ::nc_server_config_add_tls_server_cert() - * - ::nc_server_config_del_tls_server_cert() - * - * - ::nc_server_config_add_tls_client_cert() - * - ::nc_server_config_del_tls_client_cert() - * - ::nc_server_config_add_tls_ca_cert() - * - ::nc_server_config_del_tls_ca_cert() + * - ::nc_server_config_add_tls_server_certificate() + * - ::nc_server_config_del_tls_server_certificate() + * - ::nc_server_config_add_tls_keystore_ref() + * - ::nc_server_config_del_tls_keystore_ref() + * + * - ::nc_server_config_add_tls_client_certificate() + * - ::nc_server_config_del_tls_client_certificate() + * - ::nc_server_config_add_tls_client_cert_truststore_ref() + * - ::nc_server_config_del_tls_client_cert_truststore_ref() + * - ::nc_server_config_add_tls_client_ca() + * - ::nc_server_config_del_tls_client_ca() + * - ::nc_server_config_add_tls_client_ca_truststore_ref() + * - ::nc_server_config_del_tls_client_ca_truststore_ref() * - ::nc_server_config_add_tls_endpoint_client_ref() * - ::nc_server_config_del_tls_endpoint_client_ref() * - ::nc_server_config_add_tls_ctn() * - ::nc_server_config_del_tls_ctn() * + * - ::nc_server_config_add_tls_version() + * - ::nc_server_config_del_tls_version() + * - ::nc_server_config_add_tls_ciphers() + * - ::nc_server_config_del_tls_cipher() + * - ::nc_server_config_add_tls_crl_path() + * - ::nc_server_config_add_tls_crl_url() + * - ::nc_server_config_add_tls_crl_cert_ext() + * - ::nc_server_config_del_tls_crl() + * * FD * == * @@ -513,24 +542,53 @@ * * - ::nc_server_config_add_ch_ssh_hostkey() * - ::nc_server_config_del_ch_ssh_hostkey() + * - ::nc_server_config_add_ch_ssh_keystore_ref() + * - ::nc_server_config_del_ch_ssh_keystore_ref() * - ::nc_server_config_add_ch_ssh_auth_attempts() * - ::nc_server_config_add_ch_ssh_auth_timeout() * - ::nc_server_config_add_ch_ssh_user_pubkey() * - ::nc_server_config_del_ch_ssh_user_pubkey() * - ::nc_server_config_add_ch_ssh_user_password() * - ::nc_server_config_del_ch_ssh_user_password() + * - ::nc_server_config_add_ch_ssh_user_none() + * - ::nc_server_config_del_ch_ssh_user_none() * - ::nc_server_config_add_ch_ssh_user_interactive() * - ::nc_server_config_del_ch_ssh_user_interactive() * - ::nc_server_config_del_ch_ssh_user() - * - * - ::nc_server_config_add_ch_tls_server_cert() - * - ::nc_server_config_del_ch_tls_server_cert() - * - ::nc_server_config_add_ch_tls_client_cert() - * - ::nc_server_config_del_ch_tls_client_cert() - * - ::nc_server_config_add_ch_tls_ca_cert() - * - ::nc_server_config_del_ch_tls_ca_cert() + * - ::nc_server_config_add_ch_ssh_truststore_ref() + * - ::nc_server_config_del_ch_ssh_truststore_ref() + * - ::nc_server_config_add_ch_ssh_host_key_algs() + * - ::nc_server_config_del_ch_ssh_host_key_alg() + * - ::nc_server_config_add_ch_ssh_key_exchange_algs() + * - ::nc_server_config_del_ch_ssh_key_exchange_alg() + * - ::nc_server_config_add_ch_ssh_encryption_algs() + * - ::nc_server_config_del_ch_ssh_encryption_alg() + * - ::nc_server_config_add_ch_ssh_mac_algs() + * - ::nc_server_config_del_ch_ssh_mac_alg() + * + * - ::nc_server_config_add_ch_tls_server_certificate() + * - ::nc_server_config_del_ch_tls_server_certificate() + * - ::nc_server_config_add_ch_tls_keystore_ref() + * - ::nc_server_config_del_ch_tls_keystore_ref() + * - ::nc_server_config_add_ch_tls_client_certificate() + * - ::nc_server_config_del_ch_tls_client_certificate() + * - ::nc_server_config_add_ch_tls_client_cert_truststore_ref() + * - ::nc_server_config_del_ch_tls_client_cert_truststore_ref() + * - ::nc_server_config_add_ch_tls_client_ca() + * - ::nc_server_config_del_ch_tls_client_ca() + * - ::nc_server_config_add_ch_tls_client_ca_truststore_ref() + * - ::nc_server_config_del_ch_tls_client_ca_truststore_ref() * - ::nc_server_config_add_ch_tls_ctn() * - ::nc_server_config_del_ch_tls_ctn() + * - ::nc_server_config_add_ch_tls_version() + * - ::nc_server_config_del_ch_tls_version() + * - ::nc_server_config_add_ch_tls_ciphers() + * - ::nc_server_config_del_ch_tls_cipher() + * - ::nc_server_config_add_ch_tls_crl_path() + * - ::nc_server_config_add_ch_tls_crl_url() + * - ::nc_server_config_add_ch_tls_crl_cert_ext() + * - ::nc_server_config_del_ch_tls_crl() + * * * Connecting And Cleanup * ====================== @@ -654,7 +712,7 @@ * To free up some resources, it is possible to adjust the maximum idle period * of a session before it is disconnected. In _Call Home_, for both a persistent * and periodic connection can this idle timeout be specified separately for each - * client by configuring the server. Unlike other timeouts, the idle timeout + * client using corresponding functions. Unlike other timeouts, the idle timeout * can only be set via applying configuration data. * * Lastly, SSH user authentication timeout can be also modified. It is the time diff --git a/src/server_config.h b/src/server_config.h index e38c086c..d1480760 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -20,6 +20,7 @@ extern "C" { #endif +#include #include #include @@ -212,7 +213,6 @@ int nc_server_config_del_keystore_cert(const char *asym_key_name, const char *ce * @brief Creates new YANG data nodes for a public key in the truststore. * * @param[in] ctx libyang context. - * @param[in] ti Transport for which this key will be used, to be generated correctly. * @param[in] pub_bag_name Arbitrary identifier of the public key bag. * This name is used to reference the public keys in the bag. * If a public key bag with this name already exists, its contents will be changed. @@ -223,8 +223,8 @@ int nc_server_config_del_keystore_cert(const char *asym_key_name, const char *ce * 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_truststore_pubkey(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, - const char *pub_bag_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config); +int nc_server_config_add_truststore_pubkey(const struct ly_ctx *ctx, const char *pub_bag_name, const char *pubkey_name, + const char *pubkey_path, struct lyd_node **config); /** * @brief Deletes a truststore's public key from the YANG data. @@ -310,6 +310,35 @@ int nc_server_config_add_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt 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 the maximum amount of failed SSH authentication attempts. * @@ -398,6 +427,32 @@ int nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char 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 none 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,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_none(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config); + +/** + * @brief Deletes an SSH user's none authentication 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_none(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. * @@ -440,6 +495,35 @@ int nc_server_config_del_ssh_user_interactive(const char *endpt_name, const char 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. * @@ -467,6 +551,122 @@ int nc_server_config_add_ssh_endpoint_client_ref(const struct ly_ctx *ctx, const */ int nc_server_config_del_ssh_endpoint_client_ref(const char *endpt_name, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes for host-key algorithms replacing any previous ones. + * + * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, + * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its host-key algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); + +/** + * @brief Deletes a hostkey algorithm from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] alg Optional algorithm to be deleted. + * If NULL, all of the hostkey algorithms 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_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for key exchange algorithms replacing any previous ones. + * + * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, + * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, + * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its key exchange algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +/** + * @brief Deletes a key exchange algorithm from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] alg Optional algorithm to be deleted. + * If NULL, all of the key exchange algorithms 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_key_exchange_alg(const char *endpt_name, const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for encryption algorithms replacing any previous ones. + * + * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc + * triple-des-cbc and none. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its encryption algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +/** + * @brief Deletes an encryption algorithm from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] alg Optional algorithm to be deleted. + * If NULL, all of the encryption algorithms 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_encryption_alg(const char *endpt_name, const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for mac algorithms replacing any previous ones. + * + * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. + * + * @param[in] ctx libyang context + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its mac algorithms will be replaced. + * @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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of mac algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ssh_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...); + +/** + * @brief Deletes a mac algorithm from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] alg Optional algorithm to be deleted. + * If NULL, all of the mac algorithms 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_mac_alg(const char *endpt_name, const char *alg, struct lyd_node **config); + /** * @} SSH Server Configuration */ @@ -493,7 +693,7 @@ int nc_server_config_del_ssh_endpoint_client_ref(const char *endpt_name, struct * 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, +int nc_server_config_add_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path, const char *pubkey_path, const char *certificate_path, struct lyd_node **config); /** @@ -503,7 +703,31 @@ int nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *e * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_tls_server_cert(const char *endpt_name, struct lyd_node **config); +int nc_server_config_del_tls_server_certificate(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. + */ +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. @@ -518,7 +742,7 @@ int nc_server_config_del_tls_server_cert(const char *endpt_name, struct lyd_node * 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, +int nc_server_config_add_tls_client_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, const char *cert_path, struct lyd_node **config); /** @@ -530,7 +754,30 @@ int nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *e * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_tls_client_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config); +int nc_server_config_del_tls_client_certificate(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. + */ +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. @@ -545,7 +792,7 @@ int nc_server_config_del_tls_client_cert(const char *endpt_name, const char *cer * 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, +int nc_server_config_add_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, const char *cert_path, struct lyd_node **config); /** @@ -557,7 +804,30 @@ int nc_server_config_add_tls_ca_cert(const struct ly_ctx *ctx, const char *endpt * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_tls_ca_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config); +int nc_server_config_del_tls_client_ca(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_client_ca_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. + */ +int nc_server_config_del_tls_client_ca_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. @@ -615,6 +885,122 @@ int nc_server_config_add_tls_ctn(const struct ly_ctx *ctx, const char *endpt_nam */ int nc_server_config_del_tls_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes for a TLS version. + * + * @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] tls_version TLS version to be used. Call this multiple times to set + * the accepted versions of the TLS protocol and let the client and server negotiate + * the given version. + * @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_version(const struct ly_ctx *ctx, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config); + +/** + * @brief Deletes a TLS version from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] tls_version TLS version to be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_tls_version(const char *endpt_name, NC_TLS_VERSION tls_version, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a TLS cipher. + * + * @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,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[in] cipher_count Number of following ciphers. + * @param[in] ... TLS ciphers. These ciphers MUST be in the format as listed in the + * iana-tls-cipher-suite-algs YANG model (lowercase and separated by dashes). Regardless + * of the TLS protocol version used, all of these ciphers will be tried and some of them + * might not be set (TLS handshake might fail then). For the list of supported ciphers see + * the OpenSSL documentation. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int cipher_count, ...); + +/** + * @brief Deletes a TLS cipher from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in] cipher TLS cipher to be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_tls_cipher(const char *endpt_name, const char *cipher, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via a local file. + * + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @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] crl_path Path to a DER/PEM encoded CRL 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_crl_path(const struct ly_ctx *ctx, const char *endpt_name, + const char *crl_path, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via an URL. + * + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @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] crl_url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. + * The allowed protocols are all the protocols supported by CURL. + * @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_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *crl_url, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via certificate extensions. + * + * The chain of configured Certificate Authorities will be examined. For each certificate in this chain all the + * CRLs from the URLs specified in their extension fields CRL Distribution Points will be downloaded and used. + * + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @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,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_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config); + +/** + * @brief Deletes all the CRL nodes 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_crl(const char *endpt_name, struct lyd_node **config); + /** * @} TLS Server Configuration */ @@ -849,7 +1235,39 @@ int nc_server_config_del_ch_ssh_hostkey(const char *client_name, const char *end const char *hostkey_name, struct lyd_node **config); /** - * @brief Creates new YANG configuration data nodes for the maximum amount of failed Call Home SSH authentication attempts. + * @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 configuration data nodes for the maximum amount of failed Call Home SSH authentication attempts. * * @param[in] ctx libyang context. * @param[in] client_name Arbitrary identifier of the Call Home client. @@ -946,6 +1364,35 @@ int nc_server_config_add_ch_ssh_user_password(const struct ly_ctx *ctx, const ch 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 none 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,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_none(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 none authentication 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 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_none(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. * @@ -991,6 +1438,170 @@ int nc_server_config_del_ch_ssh_user_interactive(const char *client_name, const 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); + +/** + * @brief Creates new YANG configuration data nodes for Call Home host-key algorithms replacing any previous ones. + * + * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, + * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. + * + * @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,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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); + +/** + * @brief Deletes a Call Home hostkey algorithm 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] alg Optional algorithm to be deleted. + * If NULL, all of the hostkey algorithms 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_ch_ssh_host_key_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for Call Home key exchange algorithms replacing any previous ones. + * + * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, + * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, + * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. + * + * @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,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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); + +/** + * @brief Deletes a Call Home key exchange algorithm 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] alg Optional algorithm to be deleted. + * If NULL, all of the key exchange algorithms 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_ch_ssh_key_exchange_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for Call Home encryption algorithms replacing any previous ones. + * + * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc + * triple-des-cbc and none. + * + * @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,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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); + +/** + * @brief Deletes a Call Home encryption algorithm 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] alg Optional algorithm to be deleted. + * If NULL, all of the encryption algorithms 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_ch_ssh_encryption_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for Call Home mac algorithms replacing any previous ones. + * + * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. + * + * @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,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[in] alg_count Number of following algorithms. + * @param[in] ... String literals of mac algorithms in a decreasing order of preference. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...); + +/** + * @brief Deletes a Call Home mac algorithm 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] alg Optional algorithm to be deleted. + * If NULL, all of the mac algorithms 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_ch_ssh_mac_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config); + /** * @} SSH Call Home Server Configuration */ @@ -1019,7 +1630,7 @@ int nc_server_config_del_ch_ssh_user(const char *client_name, const char *endpt_ * 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, +int nc_server_config_add_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, const char *privkey_path, const char *pubkey_path, const char *certificate_path, struct lyd_node **config); /** @@ -1030,7 +1641,35 @@ int nc_server_config_add_ch_tls_server_cert(const struct ly_ctx *ctx, const char * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_ch_tls_server_cert(const char *client_name, const char *endpt_name, +int nc_server_config_del_ch_tls_server_certificate(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. + */ +int nc_server_config_del_ch_tls_keystore_ref(const char *client_name, const char *endpt_name, struct lyd_node **config); /** @@ -1048,7 +1687,7 @@ int nc_server_config_del_ch_tls_server_cert(const char *client_name, const char * 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, +int nc_server_config_add_ch_tls_client_certificate(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); /** @@ -1061,9 +1700,36 @@ int nc_server_config_add_ch_tls_client_cert(const struct ly_ctx *ctx, const char * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_ch_tls_client_cert(const char *client_name, const char *endpt_name, +int nc_server_config_del_ch_tls_client_certificate(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. + */ +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. * @@ -1079,7 +1745,7 @@ int nc_server_config_del_ch_tls_client_cert(const char *client_name, const char * 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, +int nc_server_config_add_ch_tls_client_ca(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); /** @@ -1092,9 +1758,36 @@ int nc_server_config_add_ch_tls_ca_cert(const struct ly_ctx *ctx, const char *cl * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_ch_tls_ca_cert(const char *client_name, const char *endpt_name, +int nc_server_config_del_ch_tls_client_ca(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_client_ca_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. + */ +int nc_server_config_del_ch_tls_client_ca_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. * @@ -1128,6 +1821,138 @@ int nc_server_config_add_ch_tls_ctn(const struct ly_ctx *ctx, const char *client int nc_server_config_del_ch_tls_ctn(const char *client_name, const char *endpt_name, uint32_t id, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes for a Call Home TLS version. + * + * @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] tls_version TLS version to be used. Call this multiple times to set the accepted versions + * of the TLS protocol and let the client and server negotiate the given version. + * @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_version(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config); + +/** + * @brief Deletes a TLS version 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] tls_version TLS version to be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ch_tls_version(const char *client_name, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call Home TLS cipher. + * + * @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,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[in] cipher_count Number of following ciphers. + * @param[in] ... TLS ciphers. These ciphers MUST be in the format as listed in the + * iana-tls-cipher-suite-algs YANG model (lowercase and separated by dashes). Regardless + * of the TLS protocol version used, all of these ciphers will be tried and some of them + * might not be set (TLS handshake might fail then). For the list of supported ciphers see + * the OpenSSL documentation. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_add_ch_tls_ciphers(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int cipher_count, ...); + +/** + * @brief Deletes a Call Home TLS cipher 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] cipher TLS cipher to be deleted. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_del_ch_tls_cipher(const char *client_name, const char *endpt_name, + const char *cipher, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via a local file. + * + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @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] crl_path Path to a DER/PEM encoded CRL 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_crl_path(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *crl_path, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via an URL. + * + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @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] crl_url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. + * The allowed protocols are all the protocols supported by CURL. + * @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_crl_url(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *crl_url, struct lyd_node **config); + +/** + * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via certificate extensions. + * + * The chain of configured Certificate Authorities will be examined. For each certificate in this chain all the + * CRLs from the URLs specified in their extension fields CRL Distribution Points will be downloaded and used. + * + * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling + * this function will remove any CRL YANG nodes created by the other two functions. + * + * @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,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_crl_cert_ext(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config); + +/** + * @brief Deletes all the CRL nodes 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. + */ +int nc_server_config_del_ch_tls_crl(const char *client_name, const char *endpt_name, struct lyd_node **config); + /** * @} TLS Call Home Server Configuration */ diff --git a/src/server_config_util.c b/src/server_config_util.c index cf19e012..2e8aed14 100644 --- a/src/server_config_util.c +++ b/src/server_config_util.c @@ -32,7 +32,6 @@ #include "compat.h" #include "log_p.h" -#include "server_config.h" #include "session.h" #include "session_p.h" @@ -1317,8 +1316,8 @@ nc_server_config_del_keystore_cert(const char *asym_key_name, const char *cert_n } API int -nc_server_config_add_truststore_pubkey(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, const char *pub_bag_name, - const char *pubkey_name, const char *pubkey_path, struct lyd_node **config) +nc_server_config_add_truststore_pubkey(const struct ly_ctx *ctx, const char *pub_bag_name, const char *pubkey_name, + const char *pubkey_path, struct lyd_node **config) { int ret = 0; char *pubkey = NULL; @@ -1326,15 +1325,7 @@ nc_server_config_add_truststore_pubkey(const struct ly_ctx *ctx, NC_TRANSPORT_IM NC_CHECK_ARG_RET(NULL, ctx, pub_bag_name, pubkey_name, pubkey_path, config, 1); - if (ti == NC_TI_LIBSSH) { - ret = nc_server_config_util_get_ssh_pubkey_file(pubkey_path, &pubkey); - } else if (ti == NC_TI_OPENSSL) { - ret = nc_server_config_util_get_spki_pubkey_file(pubkey_path, &pubkey); - } else { - ERR(NULL, "Public key in the truststore can only be created for SSH or TLS transports."); - ret = 1; - goto cleanup; - } + ret = nc_server_config_util_get_ssh_pubkey_file(pubkey_path, &pubkey); if (ret) { goto cleanup; } diff --git a/src/server_config_util_ssh.c b/src/server_config_util_ssh.c index 64b56abc..bcd9bd6d 100644 --- a/src/server_config_util_ssh.c +++ b/src/server_config_util_ssh.c @@ -182,6 +182,82 @@ nc_server_config_del_ch_ssh_hostkey(const char *client_name, const char *endpt_n } } +API 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 ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, keystore_reference, config, 1); + + ret = nc_server_config_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" + "keystore-reference", endpt_name, hostkey_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition nodes if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" + "inline-definition", endpt_name, hostkey_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API 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) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, keystore_reference, config, 1); + + ret = nc_server_config_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition nodes if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/inline-definition", client_name, endpt_name, hostkey_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_del_ssh_keystore_ref(const char *endpt_name, const char *hostkey_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/" + "keystore-reference", endpt_name, hostkey_name); +} + +API 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) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, hostkey_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" + "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); +} + API int nc_server_config_add_ssh_auth_attempts(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_attempts, struct lyd_node **config) @@ -539,6 +615,47 @@ nc_server_config_del_ch_ssh_user_password(const char *client_name, const char *e "users/user[name='%s']/password", client_name, endpt_name, user_name); } +API int +nc_server_config_add_ssh_user_none(const struct ly_ctx *ctx, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, config, 1); + + return nc_server_config_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/none", endpt_name, user_name); +} + +API int +nc_server_config_add_ch_ssh_user_none(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, config, 1); + + return nc_server_config_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/none", client_name, endpt_name, user_name); +} + +API int +nc_server_config_del_ssh_user_none(const char *endpt_name, const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/none", endpt_name, user_name); +} + +API int +nc_server_config_del_ch_ssh_user_none(const char *client_name, const char *endpt_name, + const char *user_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/none", client_name, endpt_name, user_name); +} + static int _nc_server_config_add_ssh_user_interactive(const struct ly_ctx *ctx, const char *tree_path, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) @@ -689,3 +806,530 @@ nc_server_config_del_ssh_endpoint_client_ref(const char *endpt_name, struct lyd_ return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); } + +API 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 ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, truststore_reference, config, 1); + + ret = nc_server_config_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" + "truststore-reference", endpt_name, user_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition nodes if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition", + endpt_name, user_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API 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) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, truststore_reference, config, 1); + + ret = nc_server_config_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition nodes if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" + "public-keys/inline-definition", client_name, endpt_name, user_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_del_ssh_truststore_ref(const char *endpt_name, const char *user_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/" + "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/" + "truststore-reference", endpt_name, user_name); +} + +API 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) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" + "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); +} + +static int +nc_server_config_ssh_transport_params_prep(const struct ly_ctx *ctx, const char *client_name, + const char *endpt_name, struct lyd_node *config, struct lyd_node **new_tree, struct lyd_node **alg_tree) +{ + int ret = 0; + char *tree_path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, new_tree, alg_tree, 1); + + /* prepare path */ + if (client_name) { + /* ch */ + ret = asprintf(&tree_path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/ssh/ssh-server-parameters/transport-params", client_name, endpt_name); + } else { + /* listen */ + ret = asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params", endpt_name); + } + if (ret == -1) { + ERRMEM; + tree_path = NULL; + ret = 1; + goto cleanup; + } + + /* create all the nodes in the path */ + ret = lyd_new_path2(config, ctx, tree_path, NULL, 0, 0, LYD_NEW_PATH_UPDATE, new_tree, alg_tree); + if (ret) { + ERR(NULL, "Creating new path to transport-params failed."); + goto cleanup; + } + + if (!*alg_tree) { + /* no new nodes added, set the path correctly for adding child nodes later */ + ret = lyd_find_path(config, tree_path, 0, alg_tree); + if (ret) { + goto cleanup; + } + } + +cleanup: + free(tree_path); + return ret; +} + +static int +nc_server_config_ssh_transport_params_create(const struct ly_ctx *ctx, NC_ALG_TYPE alg_type, int alg_count, va_list ap, + struct lyd_node *tree) +{ + int i, ret = 0; + char *alg, *alg_ident; + const char *module, *alg_path, *old_path; + struct lyd_node *old = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, tree, 1); + + /* get the correct module with the indentity base and the path in the ietf-netconf-server module */ + switch (alg_type) { + case NC_ALG_HOSTKEY: + module = "iana-ssh-public-key-algs"; + alg_path = "host-key/host-key-alg"; + old_path = "host-key"; + break; + case NC_ALG_KEY_EXCHANGE: + module = "iana-ssh-key-exchange-algs"; + alg_path = "key-exchange/key-exchange-alg"; + old_path = "key-exchange"; + break; + case NC_ALG_ENCRYPTION: + module = "iana-ssh-encryption-algs"; + alg_path = "encryption/encryption-alg"; + old_path = "encryption"; + break; + case NC_ALG_MAC: + module = "iana-ssh-mac-algs"; + alg_path = "mac/mac-alg"; + old_path = "mac"; + break; + default: + ret = 1; + ERR(NULL, "Unknown algorithm type."); + goto cleanup; + } + + /* delete all older algorithms (if any) se they can be replaced by the new ones */ + lyd_find_path(tree, old_path, 0, &old); + if (old) { + lyd_free_tree(old); + } + + for (i = 0; i < alg_count; i++) { + alg = va_arg(ap, char *); + + if (asprintf(&alg_ident, "%s:%s", module, alg) == -1) { + ERRMEM; + ret = 1; + goto cleanup; + } + + /* create the leaf list */ + ret = lyd_new_path(tree, ctx, alg_path, alg_ident, 0, NULL); + if (ret) { + ERR(NULL, "Creating new algorithm leaf-list failed."); + free(alg_ident); + goto cleanup; + } + + free(alg_ident); + alg_ident = NULL; + } + +cleanup: + return ret; +} + +static int +nc_server_config_ssh_transport_params(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + NC_ALG_TYPE alg_type, int alg_count, va_list ap, struct lyd_node **config) +{ + int ret = 0; + struct lyd_node *new_tree, *alg_tree; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + /* prepare the tree for appending child nodes (the params) */ + ret = nc_server_config_ssh_transport_params_prep(ctx, client_name, endpt_name, *config, &new_tree, &alg_tree); + if (ret) { + goto cleanup; + } + + if (!*config) { + *config = new_tree; + } + + /* create the child nodes */ + ret = nc_server_config_ssh_transport_params_create(ctx, alg_type, alg_count, ap, alg_tree); + if (ret) { + goto cleanup; + } + + /* add all default nodes */ + ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_add_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new hostkey algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_add_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new hostkey algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_del_ssh_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (alg) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/host-key/" + "host-key-alg[.='iana-ssh-public-key-algs:%s']", endpt_name, alg); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/host-key", endpt_name); + } +} + +API int +nc_server_config_del_ch_ssh_host_key_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (alg) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key/" + "host-key-alg[.='iana-ssh-public-key-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key", client_name, endpt_name); + } +} + +API int +nc_server_config_add_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new key exchange algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_add_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new key exchange algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_del_ssh_key_exchange_alg(const char *endpt_name, const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (alg) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/key-exchange/" + "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", endpt_name, alg); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/key-exchange", endpt_name); + } +} + +API int +nc_server_config_del_ch_ssh_key_exchange_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (alg) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange/" + "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange", client_name, endpt_name); + } +} + +API int +nc_server_config_add_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new encryption algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_add_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new encryption algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_del_ssh_encryption_alg(const char *endpt_name, const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (alg) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/encryption/" + "encryption-alg[.='iana-ssh-encryption-algs:%s']", endpt_name, alg); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/encryption", endpt_name); + } +} + +API int +nc_server_config_del_ch_ssh_encryption_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (alg) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption/" + "encryption-alg[.='iana-ssh-encryption-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption", client_name, endpt_name); + } +} + +API int +nc_server_config_add_ssh_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_MAC, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new mac algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_add_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int alg_count, ...) +{ + int ret = 0; + va_list ap; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); + + va_start(ap, alg_count); + + ret = nc_server_config_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_MAC, alg_count, ap, config); + if (ret) { + ERR(NULL, "Creating new mac algorithms failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + return ret; +} + +API int +nc_server_config_del_ssh_mac_alg(const char *endpt_name, const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + if (alg) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/mac/" + "mac-alg[.='iana-ssh-mac-algs:%s']", endpt_name, alg); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "ssh/ssh-server-parameters/transport-params/mac", endpt_name); + } +} + +API int +nc_server_config_del_ch_ssh_mac_alg(const char *client_name, const char *endpt_name, + const char *alg, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + if (alg) { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac/" + "mac-alg[.='iana-ssh-mac-algs:%s']", client_name, endpt_name, alg); + } else { + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac", client_name, endpt_name); + } +} diff --git a/src/server_config_util_tls.c b/src/server_config_util_tls.c index 0d628f60..20837c24 100644 --- a/src/server_config_util_tls.c +++ b/src/server_config_util_tls.c @@ -33,7 +33,7 @@ #include "session_p.h" static int -_nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *tree_path, const char *privkey_path, +_nc_server_config_add_tls_server_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *privkey_path, const char *pubkey_path, const char *certificate_path, struct lyd_node **config) { int ret = 0; @@ -103,7 +103,7 @@ _nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *tree } API int -nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path, +nc_server_config_add_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path, const char *pubkey_path, const char *certificate_path, struct lyd_node **config) { int ret = 0; @@ -119,7 +119,7 @@ nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *endpt goto cleanup; } - ret = _nc_server_config_add_tls_server_cert(ctx, path, privkey_path, pubkey_path, + ret = _nc_server_config_add_tls_server_certificate(ctx, path, privkey_path, pubkey_path, certificate_path, config); if (ret) { ERR(NULL, "Creating new TLS server certificate YANG data failed."); @@ -132,7 +132,7 @@ nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *endpt } API int -nc_server_config_del_tls_server_cert(const char *endpt_name, struct lyd_node **config) +nc_server_config_del_tls_server_certificate(const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); @@ -141,7 +141,7 @@ nc_server_config_del_tls_server_cert(const char *endpt_name, struct lyd_node **c } API int -nc_server_config_add_ch_tls_server_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +nc_server_config_add_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, const char *privkey_path, const char *pubkey_path, const char *certificate_path, struct lyd_node **config) { int ret = 0; @@ -158,7 +158,7 @@ nc_server_config_add_ch_tls_server_cert(const struct ly_ctx *ctx, const char *cl goto cleanup; } - ret = _nc_server_config_add_tls_server_cert(ctx, path, privkey_path, pubkey_path, + ret = _nc_server_config_add_tls_server_certificate(ctx, path, privkey_path, pubkey_path, certificate_path, config); if (ret) { ERR(NULL, "Creating new CH TLS server certificate YANG data failed."); @@ -171,7 +171,7 @@ nc_server_config_add_ch_tls_server_cert(const struct ly_ctx *ctx, const char *cl } API int -nc_server_config_del_ch_tls_server_cert(const char *client_name, const char *endpt_name, +nc_server_config_del_ch_tls_server_certificate(const char *client_name, const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); @@ -182,7 +182,109 @@ nc_server_config_del_ch_tls_server_cert(const char *client_name, const char *end } static int -_nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *tree_path, +_nc_server_config_add_tls_keystore_ref(const struct ly_ctx *ctx, const char *tree_path, const char *asym_key_ref, + const char *cert_ref, struct lyd_node **config) +{ + int ret = 0; + + /* create asymmetric key pair reference */ + ret = nc_server_config_append(ctx, tree_path, "keystore-reference/asymmetric-key", asym_key_ref, config); + if (ret) { + goto cleanup; + } + + /* create cert reference, this cert has to belong to the asym key */ + ret = nc_server_config_append(ctx, tree_path, "keystore-reference/certificate", cert_ref, config); + if (ret) { + goto cleanup; + } + + /* delete inline definition if present */ + ret = nc_server_config_check_delete(config, "%s/inline-definition", tree_path); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, asym_key_ref, cert_ref, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_keystore_ref(ctx, path, asym_key_ref, cert_ref, config); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_tls_keystore_ref(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/keystore-reference", endpt_name); +} + +API 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) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, asym_key_ref, cert_ref, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate", client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_keystore_ref(ctx, path, asym_key_ref, cert_ref, config); + if (ret) { + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_ch_tls_keystore_ref(const char *client_name, const char *endpt_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate/" + "keystore-reference", client_name, endpt_name); +} + +static int +_nc_server_config_add_tls_client_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *cert_path, struct lyd_node **config) { int ret = 0; @@ -207,7 +309,7 @@ _nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *tree } API int -nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, +nc_server_config_add_tls_client_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, const char *cert_path, struct lyd_node **config) { int ret = 0; @@ -223,7 +325,7 @@ nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *endpt goto cleanup; } - ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); + ret = _nc_server_config_add_tls_client_certificate(ctx, path, cert_path, config); if (ret) { ERR(NULL, "Creating new TLS client certificate YANG data failed."); goto cleanup; @@ -242,7 +344,7 @@ nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *endpt } API int -nc_server_config_del_tls_client_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config) +nc_server_config_del_tls_client_certificate(const char *endpt_name, const char *cert_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); @@ -258,7 +360,7 @@ nc_server_config_del_tls_client_cert(const char *endpt_name, const char *cert_na } API int -nc_server_config_add_ch_tls_client_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +nc_server_config_add_ch_tls_client_certificate(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) { int ret = 0; @@ -275,7 +377,7 @@ nc_server_config_add_ch_tls_client_cert(const struct ly_ctx *ctx, const char *cl goto cleanup; } - ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); + ret = _nc_server_config_add_tls_client_certificate(ctx, path, cert_path, config); if (ret) { ERR(NULL, "Creating new CH TLS client certificate YANG data failed."); goto cleanup; @@ -295,7 +397,7 @@ nc_server_config_add_ch_tls_client_cert(const struct ly_ctx *ctx, const char *cl } API int -nc_server_config_del_ch_tls_client_cert(const char *client_name, const char *endpt_name, +nc_server_config_del_ch_tls_client_certificate(const char *client_name, const char *endpt_name, const char *cert_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); @@ -312,7 +414,79 @@ nc_server_config_del_ch_tls_client_cert(const char *client_name, const char *end } API int -nc_server_config_add_tls_ca_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, +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) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1); + + ret = nc_server_config_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/truststore-reference", endpt_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/inline-definition", endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_del_tls_client_cert_truststore_ref(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/truststore-reference", endpt_name); +} + +API 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) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_bag_ref, config, 1); + + ret = nc_server_config_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/truststore-reference", client_name, endpt_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/inline-definition", client_name, endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_del_ch_tls_client_cert_truststore_ref(const char *client_name, const char *endpt_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/truststore-reference", client_name, endpt_name); +} + +API int +nc_server_config_add_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, const char *cert_path, struct lyd_node **config) { int ret = 0; @@ -328,7 +502,7 @@ nc_server_config_add_tls_ca_cert(const struct ly_ctx *ctx, const char *endpt_nam goto cleanup; } - ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); + ret = _nc_server_config_add_tls_client_certificate(ctx, path, cert_path, config); if (ret) { ERR(NULL, "Creating new TLS client certificate authority YANG data failed."); goto cleanup; @@ -347,7 +521,7 @@ nc_server_config_add_tls_ca_cert(const struct ly_ctx *ctx, const char *endpt_nam } API int -nc_server_config_del_tls_ca_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config) +nc_server_config_del_tls_client_ca(const char *endpt_name, const char *cert_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); @@ -363,7 +537,7 @@ nc_server_config_del_tls_ca_cert(const char *endpt_name, const char *cert_name, } API int -nc_server_config_add_ch_tls_ca_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +nc_server_config_add_ch_tls_client_ca(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) { int ret = 0; @@ -380,7 +554,7 @@ nc_server_config_add_ch_tls_ca_cert(const struct ly_ctx *ctx, const char *client goto cleanup; } - ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); + ret = _nc_server_config_add_tls_client_certificate(ctx, path, cert_path, config); if (ret) { ERR(NULL, "Creating new CH TLS client certificate authority YANG data failed."); goto cleanup; @@ -400,7 +574,7 @@ nc_server_config_add_ch_tls_ca_cert(const struct ly_ctx *ctx, const char *client } API int -nc_server_config_del_ch_tls_ca_cert(const char *client_name, const char *endpt_name, +nc_server_config_del_ch_tls_client_ca(const char *client_name, const char *endpt_name, const char *cert_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); @@ -416,6 +590,78 @@ nc_server_config_del_ch_tls_ca_cert(const char *client_name, const char *endpt_n } } +API int +nc_server_config_add_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, + const char *cert_bag_ref, struct lyd_node **config) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1); + + ret = nc_server_config_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/truststore-reference", endpt_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/inline-definition", endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_del_tls_client_ca_truststore_ref(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/truststore-reference", endpt_name); +} + +API int +nc_server_config_add_ch_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *client_name, + const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_bag_ref, config, 1); + + ret = nc_server_config_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/truststore-reference", client_name, endpt_name); + if (ret) { + goto cleanup; + } + + /* delete inline definition if present */ + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/inline-definition", client_name, endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_del_ch_tls_client_ca_truststore_ref(const char *client_name, const char *endpt_name, + struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/truststore-reference", client_name, endpt_name); +} + static const char * nc_server_config_tls_maptype2str(NC_TLS_CTN_MAPTYPE map_type) { @@ -565,6 +811,562 @@ nc_server_config_del_ch_tls_ctn(const char *client_name, const char *endpt_name, } } +static const char * +nc_server_config_tlsversion2str(NC_TLS_VERSION version) +{ + switch (version) { + case NC_TLS_VERSION_10: + return "ietf-tls-common:tls10"; + case NC_TLS_VERSION_11: + return "ietf-tls-common:tls11"; + case NC_TLS_VERSION_12: + return "ietf-tls-common:tls12"; + case NC_TLS_VERSION_13: + return "ietf-tls-common:tls13"; + default: + ERR(NULL, "Unknown TLS version."); + return NULL; + } +} + +API int +nc_server_config_add_tls_version(const struct ly_ctx *ctx, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config) +{ + int ret = 0; + const char *version; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + /* version to str */ + version = nc_server_config_tlsversion2str(tls_version); + if (!version) { + ret = 1; + goto cleanup; + } + + ret = nc_server_config_create(ctx, config, version, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "hello-params/tls-versions/tls-version", endpt_name); + if (ret) { + ERR(NULL, "Creating new YANG data nodes for TLS version failed."); + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_add_ch_tls_version(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config) +{ + int ret = 0; + const char *version; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); + + /* version to str */ + version = nc_server_config_tlsversion2str(tls_version); + if (!version) { + ret = 1; + goto cleanup; + } + + ret = nc_server_config_create(ctx, config, version, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "hello-params/tls-versions/tls-version", client_name, endpt_name); + if (ret) { + ERR(NULL, "Creating new YANG data nodes for CH TLS version failed."); + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_del_tls_version(const char *endpt_name, NC_TLS_VERSION tls_version, struct lyd_node **config) +{ + int ret = 0; + const char *version; + + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + /* version to str */ + version = nc_server_config_tlsversion2str(tls_version); + if (!version) { + ret = 1; + goto cleanup; + } + + ret = nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/hello-params/tls-versions/tls-version[.='%s']", endpt_name, version); + +cleanup: + return ret; +} + +API int +nc_server_config_del_ch_tls_version(const char *client_name, const char *endpt_name, + NC_TLS_VERSION tls_version, struct lyd_node **config) +{ + int ret = 0; + const char *version; + + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + /* version to str */ + version = nc_server_config_tlsversion2str(tls_version); + if (!version) { + ret = 1; + goto cleanup; + } + + ret = nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" + "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/" + "tls-server-parameters/hello-params/tls-versions/tls-version[.='%s']", client_name, endpt_name, version); + +cleanup: + return ret; +} + +static int +_nc_server_config_add_tls_ciphers(const struct ly_ctx *ctx, const char *tree_path, + int cipher_count, va_list ap, struct lyd_node **config) +{ + int ret = 0, i; + struct lyd_node *old = NULL; + char *cipher = NULL, *cipher_ident = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, tree_path, config, 1); + + /* delete all older algorithms (if any) se they can be replaced by the new ones */ + lyd_find_path(*config, tree_path, 0, &old); + if (old) { + lyd_free_tree(old); + } + + for (i = 0; i < cipher_count; i++) { + cipher = va_arg(ap, char *); + + if (asprintf(&cipher_ident, "iana-tls-cipher-suite-algs:%s", cipher) == -1) { + ERRMEM; + ret = 1; + goto cleanup; + } + + ret = nc_server_config_append(ctx, tree_path, "cipher-suite", cipher_ident, config); + if (ret) { + free(cipher_ident); + goto cleanup; + } + + free(cipher_ident); + cipher_ident = NULL; + } + +cleanup: + return ret; +} + +API int +nc_server_config_add_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, + int cipher_count, ...) +{ + int ret = 0; + va_list ap; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cipher_count, config, 1); + + va_start(ap, cipher_count); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/hello-params/cipher-suites", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_ciphers(ctx, path, cipher_count, ap, config); + if (ret) { + ERR(NULL, "Creating new TLS cipher YANG data nodes failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + free(path); + return ret; +} + +API int +nc_server_config_add_ch_tls_ciphers(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config, int cipher_count, ...) +{ + int ret = 0; + va_list ap; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cipher_count, config, 1); + + va_start(ap, cipher_count); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/tls/tls-server-parameters/hello-params/cipher-suites", client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_ciphers(ctx, path, cipher_count, ap, config); + if (ret) { + ERR(NULL, "Creating new Call-Home TLS cipher YANG data nodes failed."); + goto cleanup; + } + +cleanup: + va_end(ap); + free(path); + return ret; +} + +API int +nc_server_config_del_tls_cipher(const char *endpt_name, const char *cipher, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, cipher, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/hello-params/cipher-suites/" + "cipher-suite[.='iana-tls-cipher-suite-algs:%s']", endpt_name, cipher); +} + +API int +nc_server_config_del_ch_tls_cipher(const char *client_name, const char *endpt_name, + const char *cipher, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, cipher, config, 1); + + return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/hello-params/cipher-suites/" + "cipher-suite[.='iana-tls-cipher-suite-algs:%s']", client_name, endpt_name, cipher); +} + +static int +_nc_server_config_add_tls_crl_path(const struct ly_ctx *ctx, const char *tree_path, + const char *crl_path, struct lyd_node **config) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, tree_path, crl_path, config, 1); + + /* create the crl path node */ + ret = nc_server_config_append(ctx, tree_path, "libnetconf2-netconf-server:crl-path", crl_path, config); + if (ret) { + goto cleanup; + } + + /* delete other choice nodes if they are present */ + ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-url", tree_path); + if (ret) { + goto cleanup; + } + ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_add_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, + const char *crl_path, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, crl_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_crl_path(ctx, path, crl_path, config); + if (ret) { + ERR(NULL, "Creating new CRL YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_add_ch_tls_crl_path(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *crl_path, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, crl_path, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_crl_path(ctx, path, crl_path, config); + if (ret) { + ERR(NULL, "Creating new CH CRL YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +static int +_nc_server_config_add_tls_crl_url(const struct ly_ctx *ctx, const char *tree_path, + const char *crl_url, struct lyd_node **config) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, tree_path, crl_url, config, 1); + + /* create the crl path node */ + ret = nc_server_config_append(ctx, tree_path, "libnetconf2-netconf-server:crl-url", crl_url, config); + if (ret) { + goto cleanup; + } + + /* delete other choice nodes if they are present */ + ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-path", tree_path); + if (ret) { + goto cleanup; + } + ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_add_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *crl_url, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, crl_url, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_crl_url(ctx, path, crl_url, config); + if (ret) { + ERR(NULL, "Creating new CRL YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_add_ch_tls_crl_url(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + const char *crl_url, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, crl_url, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_crl_url(ctx, path, crl_url, config); + if (ret) { + ERR(NULL, "Creating new CH CRL YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +static int +_nc_server_config_add_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *tree_path, struct lyd_node **config) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, tree_path, config, 1); + + /* create the crl path node */ + ret = nc_server_config_append(ctx, tree_path, "libnetconf2-netconf-server:crl-cert-ext", NULL, config); + if (ret) { + goto cleanup; + } + + /* delete other choice nodes if they are present */ + ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-path", tree_path); + if (ret) { + goto cleanup; + } + ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-url", tree_path); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_add_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_crl_cert_ext(ctx, path, config); + if (ret) { + ERR(NULL, "Creating new CRL YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_add_ch_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, + struct lyd_node **config) +{ + int ret = 0; + char *path = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); + + if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication", client_name, endpt_name) == -1) { + ERRMEM; + path = NULL; + ret = 1; + goto cleanup; + } + + ret = _nc_server_config_add_tls_crl_cert_ext(ctx, path, config); + if (ret) { + ERR(NULL, "Creating new CH CRL YANG data nodes failed."); + goto cleanup; + } + +cleanup: + free(path); + return ret; +} + +API int +nc_server_config_del_tls_crl(const char *endpt_name, struct lyd_node **config) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-path", endpt_name); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-url", endpt_name); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-cert-ext", endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + +API int +nc_server_config_del_ch_tls_crl(const char *client_name, const char *endpt_name, struct lyd_node **config) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); + + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-path", client_name, endpt_name); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-url", client_name, endpt_name); + if (ret) { + goto cleanup; + } + + ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-cert-ext", client_name, endpt_name); + if (ret) { + goto cleanup; + } + +cleanup: + return ret; +} + API 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) { diff --git a/tests/test_auth.c b/tests/test_auth.c index 631a84a5..a7021800 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -1,7 +1,7 @@ /** * @file test_auth.c * @author Roman Janota - * @brief libnetconf2 SSH authentication methods test + * @brief libnetconf2 Linux PAM keyboard-interactive authentication test * * @copyright * Copyright (c) 2022 CESNET, z.s.p.o. @@ -330,8 +330,7 @@ setup_f(void **state) ret = nc_server_config_add_ssh_user_password(ctx, "endpt", "test_pw", "testpw", &tree); assert_int_equal(ret, 0); - ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/ssh/ssh-server-parameters/" - "client-authentication/users/user[name='test_none']/none", NULL, 0, NULL); + ret = nc_server_config_add_ssh_user_none(ctx, "endpt", "test_none", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_ch.c b/tests/test_ch.c index 558e29a2..a4d5f14d 100644 --- a/tests/test_ch.c +++ b/tests/test_ch.c @@ -404,15 +404,15 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* set call-home server certificate */ - ret = nc_server_config_add_ch_tls_server_cert(ctx, "ch_tls", "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tls_tree); + ret = nc_server_config_add_ch_tls_server_certificate(ctx, "ch_tls", "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tls_tree); assert_int_equal(ret, 0); /* set call-home client end entity certificate */ - ret = nc_server_config_add_ch_tls_client_cert(ctx, "ch_tls", "endpt", "ee-cert", TESTS_DIR "/data/client.crt", &test_state->tls_tree); + ret = nc_server_config_add_ch_tls_client_certificate(ctx, "ch_tls", "endpt", "ee-cert", TESTS_DIR "/data/client.crt", &test_state->tls_tree); assert_int_equal(ret, 0); /* set call-home client certificate authority certificate */ - ret = nc_server_config_add_ch_tls_ca_cert(ctx, "ch_tls", "endpt", "ca-cert", TESTS_DIR "/data/serverca.pem", &test_state->tls_tree); + ret = nc_server_config_add_ch_tls_client_ca(ctx, "ch_tls", "endpt", "ca-cert", TESTS_DIR "/data/serverca.pem", &test_state->tls_tree); assert_int_equal(ret, 0); /* set call-home CTN */ diff --git a/tests/test_config_new.c b/tests/test_config_new.c new file mode 100644 index 00000000..03ebb0bd --- /dev/null +++ b/tests/test_config_new.c @@ -0,0 +1,213 @@ +/** + * @file test_keystore.c + * @author Roman Janota + * @brief libnetconf2 Linux PAM keyboard-interactive authentication test + * + * @copyright + * Copyright (c) 2022 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include + +#include "tests/config.h" + +#define NC_ACCEPT_TIMEOUT 2000 +#define NC_PS_POLL_TIMEOUT 2000 + +struct ly_ctx *ctx; + +struct test_state { + pthread_barrier_t barrier; +}; + +static void * +server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session; + struct nc_pollsession *ps; + struct test_state *state = arg; + + ps = nc_ps_new(); + assert_non_null(ps); + + /* accept a session and add it to the poll session structure */ + pthread_barrier_wait(&state->barrier); + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC); + } while (!(ret & NC_PSPOLL_SESSION_TERM)); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + return NULL; +} + +static char * +auth_password(const char *username, const char *hostname, void *priv) +{ + (void) username; + (void) hostname; + (void) priv; + + /* set the reply to password authentication */ + return strdup("testpassword123"); +} + +static void * +client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + ret = nc_client_ssh_set_username("client"); + assert_int_equal(ret, 0); + + nc_client_ssh_set_auth_password_clb(auth_password, NULL); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_ssh("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + return NULL; +} + +static void +test_nc_config_new(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + /* new context */ + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* initialize the context by loading default modules */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf-netconf-server module and it's imports */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* create new hostkey data */ + ret = nc_server_config_add_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/server.key", NULL, &tree); + assert_int_equal(ret, 0); + + /* create new address and port data */ + ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); + assert_int_equal(ret, 0); + + /* create the host-key algorithms data */ + ret = nc_server_config_add_ssh_host_key_algs(ctx, "endpt", &tree, 1, "rsa-sha2-512"); + assert_int_equal(ret, 0); + + /* create the client authentication data, password only */ + ret = nc_server_config_add_ssh_user_password(ctx, "endpt", "client", "testpassword123", &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup_data(tree); + assert_int_equal(ret, 0); + + ret = nc_server_init(); + assert_int_equal(ret, 0); + + /* initialize client */ + ret = nc_client_init(); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + +static int +teardown_f(void **state) +{ + int ret = 0; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + + ret = pthread_barrier_destroy(&test_state->barrier); + assert_int_equal(ret, 0); + + free(*state); + nc_client_destroy(); + nc_server_destroy(); + ly_ctx_destroy(ctx); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_nc_config_new, setup_f, teardown_f), + }; + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/test_crl.c b/tests/test_crl.c index 6cd6dc77..9b951edd 100644 --- a/tests/test_crl.c +++ b/tests/test_crl.c @@ -148,15 +148,15 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new server certificate data */ - ret = nc_server_config_add_tls_server_cert(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_add_tls_server_certificate(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); /* create new end entity client cert data */ - ret = nc_server_config_add_tls_client_cert(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); + ret = nc_server_config_add_tls_client_certificate(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); assert_int_equal(ret, 0); /* create new client ca data */ - ret = nc_server_config_add_tls_ca_cert(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); + ret = nc_server_config_add_tls_client_ca(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); assert_int_equal(ret, 0); /* create new cert-to-name */ @@ -165,11 +165,27 @@ setup_f(void **state) NC_TLS_CTN_SPECIFIED, "client", &tree); assert_int_equal(ret, 0); + /* limit TLS version to 1.3 */ + ret = nc_server_config_add_tls_version(ctx, "endpt", NC_TLS_VERSION_13, &tree); + assert_int_equal(ret, 0); + + /* set the TLS cipher */ + ret = nc_server_config_add_tls_ciphers(ctx, "endpt", &tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); + assert_int_equal(ret, 0); + + /* set this node, but it should be deleted by the next call, bcs only one choice node can be present */ + ret = nc_server_config_add_tls_crl_url(ctx, "endpt", "abc", &tree); + assert_int_equal(ret, 0); + /* set path to a CRL file */ - ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-path", TESTS_DIR "/data/crl.pem", 0, NULL); + ret = nc_server_config_add_tls_crl_path(ctx, "endpt", TESTS_DIR "/data/crl.pem", &tree); assert_int_equal(ret, 0); + /* check if the choice node was removed */ + ret = lyd_find_path(tree, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-url", 0, NULL); + assert_int_not_equal(ret, 0); + /* configure the server based on the data */ ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c index 7099d77e..7966de1a 100644 --- a/tests/test_endpt_share_clients.c +++ b/tests/test_endpt_share_clients.c @@ -260,16 +260,16 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* create the first TLS endpoint with a single end entity client cert and a CTN entry */ - ret = nc_server_config_add_tls_server_cert(ctx, "TLS_endpt_1", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_add_tls_server_certificate(ctx, "TLS_endpt_1", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); ret = nc_server_config_add_address_port(ctx, "TLS_endpt_1", NC_TI_OPENSSL, "127.0.0.1", 10007, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_add_tls_client_cert(ctx, "TLS_endpt_1", "cert_client", TESTS_DIR "/data/client.crt", &tree); + ret = nc_server_config_add_tls_client_certificate(ctx, "TLS_endpt_1", "cert_client", TESTS_DIR "/data/client.crt", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_add_tls_ca_cert(ctx, "TLS_endpt_1", "cert_ca", TESTS_DIR "/data/serverca.pem", &tree); + ret = nc_server_config_add_tls_client_ca(ctx, "TLS_endpt_1", "cert_ca", TESTS_DIR "/data/serverca.pem", &tree); assert_int_equal(ret, 0); ret = nc_server_config_add_tls_ctn(ctx, "TLS_endpt_1", 1, @@ -278,7 +278,7 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* create the second TLS endpoint with a reference to the first endpoint */ - ret = nc_server_config_add_tls_server_cert(ctx, "TLS_endpt_2", + ret = nc_server_config_add_tls_server_certificate(ctx, "TLS_endpt_2", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); diff --git a/tests/test_ks_ts.c b/tests/test_ks_ts.c index 5440b7e6..1e08a7ce 100644 --- a/tests/test_ks_ts.c +++ b/tests/test_ks_ts.c @@ -141,20 +141,16 @@ setup_ssh(void **state) ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10005, &tree); assert_int_equal(ret, 0); - ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='endpt']/ssh/ssh-server-parameters/server-identity/host-key[name='hostkey']/public-key/" - "keystore-reference", "test_keystore", 0, NULL); + ret = nc_server_config_add_ssh_keystore_ref(ctx, "endpt", "hostkey", "test_keystore", &tree); assert_int_equal(ret, 0); - ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='endpt']/ssh/ssh-server-parameters/client-authentication/users/user[name='client']/public-keys/" - "truststore-reference", "test_truststore", 0, NULL); + ret = nc_server_config_add_ssh_truststore_ref(ctx, "endpt", "client", "test_truststore", &tree); assert_int_equal(ret, 0); ret = nc_server_config_add_keystore_asym_key(ctx, NC_TI_LIBSSH, "test_keystore", TESTS_DIR "/data/key_rsa", NULL, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_add_truststore_pubkey(ctx, NC_TI_LIBSSH, "test_truststore", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); + ret = nc_server_config_add_truststore_pubkey(ctx, "test_truststore", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); assert_int_equal(ret, 0); /* configure the server based on the data */ @@ -268,21 +264,15 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* new keystore ref for the TLS server cert */ - ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/" - "tls/tls-server-parameters/server-identity/certificate/keystore-reference/asymmetric-key", "server_key", 0, NULL); - assert_int_equal(ret, 0); - ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/" - "tls/tls-server-parameters/server-identity/certificate/keystore-reference/certificate", "server_cert", 0, NULL); + ret = nc_server_config_add_tls_keystore_ref(ctx, "endpt", "server_key", "server_cert", &tree); assert_int_equal(ret, 0); /* new truststore ref for the client cert */ - ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/tls/" - "tls-server-parameters/client-authentication/ee-certs/truststore-reference", "ee_cert_bag", 0, NULL); + ret = nc_server_config_add_tls_client_cert_truststore_ref(ctx, "endpt", "ee_cert_bag", &tree); assert_int_equal(ret, 0); /* new truststore ref for the client CA cert */ - ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/tls/" - "tls-server-parameters/client-authentication/ca-certs/truststore-reference", "ca_cert_bag", 0, NULL); + ret = nc_server_config_add_tls_client_ca_truststore_ref(ctx, "endpt", "ca_cert_bag", &tree); assert_int_equal(ret, 0); /* new cert-to-name */ diff --git a/tests/test_runtime_changes.c b/tests/test_runtime_changes.c index 284d3606..7c389ee4 100644 --- a/tests/test_runtime_changes.c +++ b/tests/test_runtime_changes.c @@ -240,11 +240,11 @@ test_nc_change_tls_srv_crt(void **state) test_state = *state; init_test_create_threads_tls(tids, state); - ret = nc_server_config_add_tls_server_cert(ctx, "endpt_tls", TESTS_DIR "/data/client.key", NULL, TESTS_DIR "/data/client.crt", &test_state->tree); + ret = nc_server_config_add_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/client.key", NULL, TESTS_DIR "/data/client.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - ret = nc_server_config_add_tls_server_cert(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); + ret = nc_server_config_add_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); @@ -264,11 +264,11 @@ test_nc_change_tls_client_crt(void **state) test_state = *state; init_test_create_threads_tls(tids, state); - ret = nc_server_config_add_tls_client_cert(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/server.crt", &test_state->tree); + ret = nc_server_config_add_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/server.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - ret = nc_server_config_add_tls_client_cert(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); + ret = nc_server_config_add_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); @@ -305,13 +305,60 @@ test_nc_change_tls_ctn(void **state) } } +static void +test_nc_change_tls_version(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + init_test_create_threads_tls(tids, state); + + ret = nc_server_config_add_tls_version(ctx, "endpt_tls", NC_TLS_VERSION_11, &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); + + ret = nc_server_config_add_tls_version(ctx, "endpt_tls", NC_TLS_VERSION_13, &test_state->tree); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_nc_change_tls_ciphers(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + init_test_create_threads_tls(tids, state); + + ret = nc_server_config_add_tls_ciphers(ctx, "endpt_tls", &test_state->tree, 1, "tls-rsa-with-null-sha"); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); + + ret = nc_server_config_add_tls_ciphers(ctx, "endpt_tls", &test_state->tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + static void test_nc_change_ssh_hostkey(void **state) { int ret, i; pthread_t tids[2]; struct test_state *test_state; - struct lyd_node *hostkey = NULL; assert_non_null(state); test_state = *state; @@ -321,18 +368,9 @@ test_nc_change_ssh_hostkey(void **state) assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_RUN); - /* delete the locally defined hostkey */ - ret = lyd_find_path(test_state->tree, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='endpt_ssh']/ssh/ssh-server-parameters/server-identity/host-key[name='hostkey']/public-key", 0, &hostkey); - assert_non_null(hostkey); - lyd_free_tree(hostkey); - - /* add the keystore entry and set it as hostkey */ ret = nc_server_config_add_keystore_asym_key(ctx, NC_TI_LIBSSH, "keystore_hostkey", TESTS_DIR "/data/key_rsa", TESTS_DIR "/data/key_rsa.pub", &test_state->tree); assert_int_equal(ret, 0); - ret = lyd_new_path(test_state->tree, ctx, "/ietf-netconf-server:netconf-server/listen/" - "endpoint[name='endpt_ssh']/ssh/ssh-server-parameters/server-identity/host-key[name='hostkey']/public-key/" - "keystore-reference", "keystore_hostkey", 0, NULL); + ret = nc_server_config_add_ssh_keystore_ref(ctx, "endpt_ssh", "hostkey", "keystore_hostkey", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); @@ -365,6 +403,30 @@ test_nc_change_ssh_usr_pubkey(void **state) } } +static void +test_nc_change_ssh_hostkey_algs(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct test_state *test_state; + + assert_non_null(state); + test_state = *state; + init_test_create_threads_ssh(tids, state); + + ret = nc_server_config_add_ssh_host_key_algs(ctx, "endpt_ssh", &test_state->tree, 1, "ssh-dss"); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); + + ret = nc_server_config_add_ssh_host_key_algs(ctx, "endpt_ssh", &test_state->tree, 1, "rsa-sha2-256"); + assert_int_equal(ret, 0); + configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + static int setup_f(void **state) { @@ -399,11 +461,11 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new server certificate data */ - ret = nc_server_config_add_tls_server_cert(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); + ret = nc_server_config_add_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); assert_int_equal(ret, 0); /* create new end entity client cert data */ - ret = nc_server_config_add_tls_client_cert(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); + ret = nc_server_config_add_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); assert_int_equal(ret, 0); /* create new cert-to-name */ @@ -464,8 +526,11 @@ main(void) cmocka_unit_test_setup_teardown(test_nc_change_tls_srv_crt, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_change_tls_client_crt, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_change_tls_ctn, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_change_tls_version, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_change_tls_ciphers, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_change_ssh_hostkey, setup_f, teardown_f), - cmocka_unit_test_setup_teardown(test_nc_change_ssh_usr_pubkey, setup_f, teardown_f) + cmocka_unit_test_setup_teardown(test_nc_change_ssh_usr_pubkey, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_change_ssh_hostkey_algs, setup_f, teardown_f), }; setenv("CMOCKA_TEST_ABORT", "1", 1); diff --git a/tests/test_tls.c b/tests/test_tls.c index 542f7bdb..7d84184d 100644 --- a/tests/test_tls.c +++ b/tests/test_tls.c @@ -142,15 +142,15 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new server certificate data */ - ret = nc_server_config_add_tls_server_cert(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_add_tls_server_certificate(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); /* create new end entity client cert data */ - ret = nc_server_config_add_tls_client_cert(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); + ret = nc_server_config_add_tls_client_certificate(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); assert_int_equal(ret, 0); /* create new client ca data */ - ret = nc_server_config_add_tls_ca_cert(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); + ret = nc_server_config_add_tls_client_ca(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); assert_int_equal(ret, 0); /* create new cert-to-name */ @@ -159,6 +159,14 @@ setup_f(void **state) NC_TLS_CTN_SPECIFIED, "client", &tree); assert_int_equal(ret, 0); + /* limit TLS version to 1.3 */ + ret = nc_server_config_add_tls_version(ctx, "endpt", NC_TLS_VERSION_13, &tree); + assert_int_equal(ret, 0); + + /* set the TLS cipher */ + ret = nc_server_config_add_tls_ciphers(ctx, "endpt", &tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); + assert_int_equal(ret, 0); + /* configure the server based on the data */ ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); From 2b22565a35ecbb786304d76543575d7a4c20fd4c Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 19 Oct 2023 09:47:40 +0200 Subject: [PATCH 090/134] session server ssh UPDATE add ssh_sess param to cb --- src/session_p.h | 6 +- src/session_server.c | 2001 ++++++++++---------------------------- src/session_server.h | 431 +------- src/session_server_ssh.c | 1450 ++++++++------------------- 4 files changed, 982 insertions(+), 2906 deletions(-) diff --git a/src/session_p.h b/src/session_p.h index 02658ad2..86bbace6 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -437,11 +437,7 @@ struct nc_server_opts { void *pubkey_auth_data; void (*pubkey_auth_data_free)(void *data); - int (*interactive_auth_sess_clb)(const struct nc_session *session, ssh_session ssh_sess, ssh_message msg, void *user_data); - void *interactive_auth_sess_data; - void (*interactive_auth_sess_data_free)(void *data); - - int (*interactive_auth_clb)(const struct nc_session *session, ssh_message msg, void *user_data); + int (*interactive_auth_clb)(const struct nc_session *session, ssh_session ssh_sess, ssh_message msg, void *user_data); void *interactive_auth_data; void (*interactive_auth_data_free)(void *data); diff --git a/src/session_server.c b/src/session_server.c index 03938ee7..7e37cb07 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -29,24 +29,30 @@ #include #include #include +#include #include #include #include #include +#ifdef NC_ENABLED_SSH_TLS +#include +#endif + #include "compat.h" -#include "config_new_ssh.h" -#include "libnetconf.h" +#include "config.h" +#include "log_p.h" +#include "messages_p.h" +#include "messages_server.h" +#include "server_config_p.h" +#include "session.h" +#include "session_p.h" #include "session_server.h" #include "session_server_ch.h" struct nc_server_opts server_opts = { -#ifdef NC_ENABLED_SSH - .authkey_lock = PTHREAD_MUTEX_INITIALIZER, -#endif - .bind_lock = PTHREAD_MUTEX_INITIALIZER, - .endpt_lock = PTHREAD_RWLOCK_INITIALIZER, - .ch_client_lock = PTHREAD_RWLOCK_INITIALIZER + .config_lock = PTHREAD_RWLOCK_INITIALIZER, + .ch_client_lock = PTHREAD_RWLOCK_INITIALIZER, }; static nc_rpc_clb global_rpc_clb = NULL; @@ -57,13 +63,10 @@ nc_server_endpt_lock_get(const char *name, NC_TRANSPORT_IMPL ti, uint16_t *idx) uint16_t i; struct nc_endpt *endpt = NULL; - if (!name) { - ERRARG("endpt_name"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, name, NULL); - /* WRITE LOCK */ - pthread_rwlock_wrlock(&server_opts.endpt_lock); + /* READ LOCK */ + pthread_rwlock_rdlock(&server_opts.config_lock); for (i = 0; i < server_opts.endpt_count; ++i) { if (!strcmp(server_opts.endpts[i].name, name) && (!ti || (server_opts.endpts[i].ti == ti))) { @@ -75,7 +78,7 @@ nc_server_endpt_lock_get(const char *name, NC_TRANSPORT_IMPL ti, uint16_t *idx) if (!endpt) { ERR(NULL, "Endpoint \"%s\" was not found.", name); /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); + pthread_rwlock_unlock(&server_opts.config_lock); return NULL; } @@ -95,16 +98,13 @@ nc_server_ch_client_lock(const char *name, const char *endpt_name, NC_TRANSPORT_ *client_p = NULL; - if (!name) { - ERRARG("client_name"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, name, NULL); /* READ LOCK */ pthread_rwlock_rdlock(&server_opts.ch_client_lock); for (i = 0; i < server_opts.ch_client_count; ++i) { - if (!strcmp(server_opts.ch_clients[i].name, name)) { + if (server_opts.ch_clients[i].name && !strcmp(server_opts.ch_clients[i].name, name)) { client = &server_opts.ch_clients[i]; if (!endpt_name && !ti) { /* return only client */ @@ -122,7 +122,7 @@ nc_server_ch_client_lock(const char *name, const char *endpt_name, NC_TRANSPORT_ } if (!client) { - ERR(NULL, "Call Home client \"%s\" was not found.", name); + VRB(NULL, "Call Home client \"%s\" was not found.", name); /* READ UNLOCK */ pthread_rwlock_unlock(&server_opts.ch_client_lock); @@ -155,10 +155,10 @@ API void nc_session_set_term_reason(struct nc_session *session, NC_SESSION_TERM_REASON reason) { if (!session) { - ERRARG("session"); + ERRARG(session, "session"); return; } else if (!reason) { - ERRARG("reason"); + ERRARG(session, "reason"); return; } @@ -172,10 +172,10 @@ API void nc_session_set_killed_by(struct nc_session *session, uint32_t sid) { if (!session || (session->term_reason != NC_SESSION_TERM_KILLED)) { - ERRARG("session"); + ERRARG(session, "session"); return; } else if (!sid) { - ERRARG("sid"); + ERRARG(session, "sid"); return; } @@ -186,16 +186,97 @@ API void nc_session_set_status(struct nc_session *session, NC_STATUS status) { if (!session) { - ERRARG("session"); + ERRARG(session, "session"); return; } else if (!status) { - ERRARG("status"); + ERRARG(session, "status"); return; } session->status = status; } +API int +nc_server_init_ctx(struct ly_ctx **ctx) +{ + int new_ctx = 0, i, ret = 0; + struct lys_module *module; + /* all features */ + const char *ietf_netconf_features[] = {"writable-running", "candidate", "rollback-on-error", "validate", "startup", "url", "xpath", "confirmed-commit", NULL}; + /* all features (module has no features) */ + const char *ietf_netconf_monitoring_features[] = {NULL}; + + NC_CHECK_ARG_RET(NULL, ctx, 1); + + if (!*ctx) { + /* context not given, create a new one */ + if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) { + ERR(NULL, "Couldn't create new libyang context.\n"); + ret = 1; + goto cleanup; + } + new_ctx = 1; + } + + if (new_ctx) { + /* new context created, implement both modules */ + if (!ly_ctx_load_module(*ctx, "ietf-netconf", NULL, ietf_netconf_features)) { + ERR(NULL, "Loading module \"ietf-netconf\" failed.\n"); + ret = 1; + goto cleanup; + } + + if (!ly_ctx_load_module(*ctx, "ietf-netconf-monitoring", NULL, ietf_netconf_monitoring_features)) { + ERR(NULL, "Loading module \"ietf-netconf-monitoring\" failed.\n"); + ret = 1; + goto cleanup; + } + + goto cleanup; + } + + module = ly_ctx_get_module_implemented(*ctx, "ietf-netconf"); + if (module) { + /* ietf-netconf module is present, check features */ + for (i = 0; ietf_netconf_features[i]; i++) { + if (lys_feature_value(module, ietf_netconf_features[i])) { + /* feature not found, enable all of them */ + if (!ly_ctx_load_module(*ctx, "ietf-netconf", NULL, ietf_netconf_features)) { + ERR(NULL, "Loading module \"ietf-netconf\" failed.\n"); + ret = 1; + goto cleanup; + } + + break; + } + } + } else { + /* ietf-netconf module not found, add it */ + if (!ly_ctx_load_module(*ctx, "ietf-netconf", NULL, ietf_netconf_features)) { + ERR(NULL, "Loading module \"ietf-netconf\" failed.\n"); + ret = 1; + goto cleanup; + } + } + + module = ly_ctx_get_module_implemented(*ctx, "ietf-netconf-monitoring"); + if (!module) { + /* ietf-netconf-monitoring module not found, add it */ + if (!ly_ctx_load_module(*ctx, "ietf-netconf-monitoring", NULL, ietf_netconf_monitoring_features)) { + ERR(NULL, "Loading module \"ietf-netconf-monitoring\" failed.\n"); + ret = 1; + goto cleanup; + } + } + +cleanup: + if (new_ctx && ret) { + ly_ctx_destroy(*ctx); + *ctx = NULL; + } + return ret; +} + int nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepalives *ka) { @@ -229,7 +310,7 @@ nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepalives *ka goto fail; } - if (nc_sock_enable_keepalive(sock, ka)) { + if (nc_sock_configure_keepalive(sock, ka)) { goto fail; } @@ -271,7 +352,6 @@ nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepalives *ka ERR(NULL, "Unable to start listening on \"%s\" port %d (%s).", address, port, strerror(errno)); goto fail; } - return sock; fail: @@ -434,7 +514,7 @@ sock_host_inet6(const struct sockaddr_in6 *addr, char **host, uint16_t *port) } int -nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, char **host, uint16_t *port, uint16_t *idx) +nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, pthread_mutex_t *bind_lock, int timeout, char **host, uint16_t *port, uint16_t *idx) { sigset_t sigmask, origmask; uint16_t i, j, pfd_count, client_port; @@ -450,6 +530,9 @@ nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, ch return -1; } + /* LOCK */ + pthread_mutex_lock(bind_lock); + for (i = 0, pfd_count = 0; i < bind_count; ++i) { if (binds[i].sock < 0) { /* invalid socket */ @@ -478,10 +561,14 @@ nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, ch if (!ret) { /* we timeouted */ free(pfd); + /* UNLOCK */ + pthread_mutex_unlock(bind_lock); return 0; } else if (ret == -1) { ERR(NULL, "Poll failed (%s).", strerror(errno)); free(pfd); + /* UNLOCK */ + pthread_mutex_unlock(bind_lock); return -1; } @@ -506,9 +593,10 @@ nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, ch } } free(pfd); - if (sock == -1) { ERRINT; + /* UNLOCK */ + pthread_mutex_unlock(bind_lock); return -1; } @@ -516,6 +604,8 @@ nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, ch client_sock = accept(sock, (struct sockaddr *)&saddr, &saddr_len); if (client_sock < 0) { ERR(NULL, "Accept failed (%s).", strerror(errno)); + /* UNLOCK */ + pthread_mutex_unlock(bind_lock); return -1; } @@ -561,10 +651,14 @@ nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, ch if (idx) { *idx = i; } + /* UNLOCK */ + pthread_mutex_unlock(bind_lock); return client_sock; fail: close(client_sock); + /* UNLOCK */ + pthread_mutex_unlock(bind_lock); return -1; } @@ -676,7 +770,7 @@ nc_clb_default_close_session(struct lyd_node *UNUSED(rpc), struct nc_session *se * @param[in] ctx Context to initialize. */ static void -nc_server_init_ctx(const struct ly_ctx *ctx) +nc_server_init_cb_ctx(const struct ly_ctx *ctx) { struct lysc_node *rpc; @@ -707,8 +801,6 @@ nc_server_init(void) pthread_rwlockattr_t attr, *attr_p = NULL; int r; - nc_init(); - server_opts.new_session_id = 1; server_opts.new_client_id = 1; @@ -724,7 +816,7 @@ nc_server_init(void) } #endif - if ((r = pthread_rwlock_init(&server_opts.endpt_lock, attr_p))) { + if ((r = pthread_rwlock_init(&server_opts.config_lock, attr_p))) { ERR(NULL, "%s: failed to init rwlock(%s).", __func__, strerror(r)); goto error; } @@ -736,6 +828,19 @@ nc_server_init(void) if (attr_p) { pthread_rwlockattr_destroy(attr_p); } + +#ifdef NC_ENABLED_SSH_TLS + if (curl_global_init(CURL_GLOBAL_SSL | CURL_GLOBAL_ACK_EINTR)) { + ERR(NULL, "%s: failed to init CURL.", __func__); + goto error; + } +#endif + + if ((r = pthread_mutex_init(&server_opts.bind_lock, NULL))) { + ERR(NULL, "%s: failed to init bind lock(%s).", __func__, strerror(r)); + goto error; + } + return 0; error: @@ -760,11 +865,12 @@ nc_server_destroy(void) server_opts.content_id_data_free(server_opts.content_id_data); } -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) - nc_server_del_endpt(NULL, 0); - nc_server_ch_del_client(NULL); -#endif -#ifdef NC_ENABLED_SSH + nc_server_config_listen(NULL, NC_OP_DELETE); + nc_server_config_ch(NULL, NC_OP_DELETE); + + pthread_mutex_destroy(&server_opts.bind_lock); + +#ifdef NC_ENABLED_SSH_TLS if (server_opts.passwd_auth_data && server_opts.passwd_auth_data_free) { server_opts.passwd_auth_data_free(server_opts.passwd_auth_data); } @@ -777,60 +883,31 @@ nc_server_destroy(void) server_opts.pubkey_auth_data = NULL; server_opts.pubkey_auth_data_free = NULL; - if (server_opts.interactive_auth_sess_data && server_opts.interactive_auth_sess_data_free) { - server_opts.interactive_auth_sess_data_free(server_opts.interactive_auth_sess_data); - } - server_opts.interactive_auth_sess_data = NULL; - server_opts.interactive_auth_sess_data_free = NULL; - if (server_opts.interactive_auth_data && server_opts.interactive_auth_data_free) { server_opts.interactive_auth_data_free(server_opts.interactive_auth_data); } server_opts.interactive_auth_data = NULL; server_opts.interactive_auth_data_free = NULL; - nc_server_ssh_del_authkey(NULL, NULL, 0, NULL); - - if (server_opts.hostkey_data && server_opts.hostkey_data_free) { - server_opts.hostkey_data_free(server_opts.hostkey_data); - } - server_opts.hostkey_data = NULL; - server_opts.hostkey_data_free = NULL; - - /* PAM */ - free(server_opts.conf_name); - free(server_opts.conf_dir); - server_opts.conf_name = NULL; - server_opts.conf_dir = NULL; -#endif -#ifdef NC_ENABLED_TLS - if (server_opts.server_cert_data && server_opts.server_cert_data_free) { - server_opts.server_cert_data_free(server_opts.server_cert_data); - } - server_opts.server_cert_data = NULL; - server_opts.server_cert_data_free = NULL; - if (server_opts.trusted_cert_list_data && server_opts.trusted_cert_list_data_free) { - server_opts.trusted_cert_list_data_free(server_opts.trusted_cert_list_data); - } - server_opts.trusted_cert_list_data = NULL; - server_opts.trusted_cert_list_data_free = NULL; -#endif - nc_destroy(); + nc_server_config_ks_keystore(NULL, NC_OP_DELETE); + nc_server_config_ts_truststore(NULL, NC_OP_DELETE); + curl_global_cleanup(); +#endif /* NC_ENABLED_SSH_TLS */ } API int nc_server_set_capab_withdefaults(NC_WD_MODE basic_mode, int also_supported) { if (!basic_mode || (basic_mode == NC_WD_ALL_TAG)) { - ERRARG("basic_mode"); + ERRARG(NULL, "basic_mode"); return -1; } else if (also_supported && !(also_supported & (NC_WD_ALL | NC_WD_ALL_TAG | NC_WD_TRIM | NC_WD_EXPLICIT))) { - ERRARG("also_supported"); + ERRARG(NULL, "also_supported"); return -1; } - server_opts.wd_basic_mode = basic_mode; - server_opts.wd_also_supported = also_supported; + ATOMIC_STORE_RELAXED(server_opts.wd_basic_mode, basic_mode); + ATOMIC_STORE_RELAXED(server_opts.wd_also_supported, also_supported); return 0; } @@ -838,15 +915,15 @@ API void nc_server_get_capab_withdefaults(NC_WD_MODE *basic_mode, int *also_supported) { if (!basic_mode && !also_supported) { - ERRARG("basic_mode and also_supported"); + ERRARG(NULL, "basic_mode and also_supported"); return; } if (basic_mode) { - *basic_mode = server_opts.wd_basic_mode; + *basic_mode = ATOMIC_LOAD_RELAXED(server_opts.wd_basic_mode); } if (also_supported) { - *also_supported = server_opts.wd_also_supported; + *also_supported = ATOMIC_LOAD_RELAXED(server_opts.wd_also_supported); } } @@ -856,7 +933,7 @@ nc_server_set_capability(const char *value) void *mem; if (!value || !value[0]) { - ERRARG("value must not be empty"); + ERRARG(NULL, "value must not be empty"); return EXIT_FAILURE; } @@ -894,12 +971,6 @@ nc_server_get_hello_timeout(void) return server_opts.hello_timeout; } -API void -nc_server_set_idle_timeout(uint16_t idle_timeout) -{ - server_opts.idle_timeout = idle_timeout; -} - API uint16_t nc_server_get_idle_timeout(void) { @@ -912,25 +983,18 @@ nc_accept_inout(int fdin, int fdout, const char *username, const struct ly_ctx * NC_MSG_TYPE msgtype; struct timespec ts_cur; - if (!ctx) { - ERRARG("ctx"); - return NC_MSG_ERROR; - } else if (fdin < 0) { - ERRARG("fdin"); + NC_CHECK_ARG_RET(NULL, ctx, username, session, NC_MSG_ERROR); + + if (fdin < 0) { + ERRARG(NULL, "fdin"); return NC_MSG_ERROR; } else if (fdout < 0) { - ERRARG("fdout"); - return NC_MSG_ERROR; - } else if (!username) { - ERRARG("username"); - return NC_MSG_ERROR; - } else if (!session) { - ERRARG("session"); + ERRARG(NULL, "fdout"); return NC_MSG_ERROR; } /* init ctx as needed */ - nc_server_init_ctx(ctx); + nc_server_init_cb_ctx(ctx); /* prepare session structure */ *session = nc_new_session(NC_SERVER, 0); @@ -1171,13 +1235,7 @@ nc_ps_add_session(struct nc_pollsession *ps, struct nc_session *session) { uint8_t q_id; - if (!ps) { - ERRARG("ps"); - return -1; - } else if (!session) { - ERRARG("session"); - return -1; - } + NC_CHECK_ARG_RET(session, ps, session, -1); /* LOCK */ if (nc_ps_lock(ps, &q_id, __func__)) { @@ -1242,13 +1300,7 @@ nc_ps_del_session(struct nc_pollsession *ps, struct nc_session *session) uint8_t q_id; int ret, ret2; - if (!ps) { - ERRARG("ps"); - return -1; - } else if (!session) { - ERRARG("session"); - return -1; - } + NC_CHECK_ARG_RET(session, ps, session, -1); /* LOCK */ if (nc_ps_lock(ps, &q_id, __func__)) { @@ -1269,10 +1321,7 @@ nc_ps_get_session(const struct nc_pollsession *ps, uint16_t idx) uint8_t q_id; struct nc_session *ret = NULL; - if (!ps) { - ERRARG("ps"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, ps, NULL); /* LOCK */ if (nc_ps_lock((struct nc_pollsession *)ps, &q_id, __func__)) { @@ -1296,10 +1345,7 @@ nc_ps_find_session(const struct nc_pollsession *ps, nc_ps_session_match_cb match uint16_t i; struct nc_session *ret = NULL; - if (!ps) { - ERRARG("ps"); - return NULL; - } + NC_CHECK_ARG_RET(NULL, ps, NULL); /* LOCK */ if (nc_ps_lock((struct nc_pollsession *)ps, &q_id, __func__)) { @@ -1325,10 +1371,7 @@ nc_ps_session_count(struct nc_pollsession *ps) uint8_t q_id; uint16_t session_count; - if (!ps) { - ERRARG("ps"); - return 0; - } + NC_CHECK_ARG_RET(NULL, ps, 0); /* LOCK (just for memory barrier so that we read the current value) */ if (nc_ps_lock((struct nc_pollsession *)ps, &q_id, __func__)) { @@ -1379,13 +1422,9 @@ nc_server_recv_rpc_io(struct nc_session *session, int io_timeout, struct nc_serv struct lyd_node *e; int r, ret = 0; - if (!session) { - ERRARG("session"); - return NC_PSPOLL_ERROR; - } else if (!rpc) { - ERRARG("rpc"); - return NC_PSPOLL_ERROR; - } else if ((session->status != NC_STATUS_RUNNING) || (session->side != NC_SERVER)) { + NC_CHECK_ARG_RET(session, session, rpc, NC_PSPOLL_ERROR); + + if ((session->status != NC_STATUS_RUNNING) || (session->side != NC_SERVER)) { ERR(session, "Invalid session to receive RPCs."); return NC_PSPOLL_ERROR; } @@ -1477,10 +1516,10 @@ nc_server_notif_send(struct nc_session *session, struct nc_server_notif *notif, /* check parameters */ if (!session || (session->side != NC_SERVER) || !nc_session_get_notif_status(session)) { - ERRARG("session"); + ERRARG(NULL, "session"); return NC_MSG_ERROR; } else if (!notif || !notif->ntf || !notif->eventtime) { - ERRARG("notif"); + ERRARG(NULL, "notif"); return NC_MSG_ERROR; } @@ -1592,14 +1631,14 @@ nc_ps_poll_session_io(struct nc_session *session, int io_timeout, time_t now_mon struct pollfd pfd; int r, ret = 0; -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS ssh_message ssh_msg; struct nc_session *new; -#endif +#endif /* NC_ENABLED_SSH_TLS */ /* check timeout first */ if (!(session->flags & NC_SESSION_CALLHOME) && !nc_session_get_notif_status(session) && server_opts.idle_timeout && - (now_mono >= session->opts.server.last_rpc + server_opts.idle_timeout)) { + (now_mono >= session->opts.server.last_rpc + (unsigned) server_opts.idle_timeout)) { sprintf(msg, "session idle timeout elapsed"); session->status = NC_STATUS_INVALID; session->term_reason = NC_SESSION_TERM_TIMEOUT; @@ -1615,8 +1654,37 @@ nc_ps_poll_session_io(struct nc_session *session, int io_timeout, time_t now_mon } switch (session->ti_type) { -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS case NC_TI_LIBSSH: + ssh_msg = ssh_message_get(session->ti.libssh.session); + if (ssh_msg) { + nc_session_ssh_msg(session, NULL, ssh_msg, NULL); + if (session->ti.libssh.next) { + for (new = session->ti.libssh.next; new != session; new = new->ti.libssh.next) { + if ((new->status == NC_STATUS_STARTING) && new->ti.libssh.channel && + (new->flags & NC_SESSION_SSH_SUBSYS_NETCONF)) { + /* new NETCONF SSH channel */ + ret = NC_PSPOLL_SSH_CHANNEL; + break; + } + } + if (new != session) { + ssh_message_free(ssh_msg); + break; + } + } + if (!ret) { + /* just some SSH message */ + ret = NC_PSPOLL_SSH_MSG; + } + ssh_message_free(ssh_msg); + + /* break because 1) we don't want to return anything here ORred with NC_PSPOLL_RPC + * and 2) we don't want to delay openning a new channel by waiting for a RPC to get processed + */ + break; + } + r = ssh_channel_poll_timeout(session->ti.libssh.channel, 0, 0); if (r == SSH_EOF) { sprintf(msg, "SSH channel unexpected EOF"); @@ -1629,35 +1697,13 @@ nc_ps_poll_session_io(struct nc_session *session, int io_timeout, time_t now_mon session->term_reason = NC_SESSION_TERM_OTHER; ret = NC_PSPOLL_SESSION_TERM | NC_PSPOLL_SESSION_ERROR; } else if (!r) { - if (session->flags & NC_SESSION_SSH_NEW_MSG) { - /* new SSH message */ - session->flags &= ~NC_SESSION_SSH_NEW_MSG; - if (session->ti.libssh.next) { - for (new = session->ti.libssh.next; new != session; new = new->ti.libssh.next) { - if ((new->status == NC_STATUS_STARTING) && new->ti.libssh.channel && - (new->flags & NC_SESSION_SSH_SUBSYS_NETCONF)) { - /* new NETCONF SSH channel */ - ret = NC_PSPOLL_SSH_CHANNEL; - break; - } - } - if (new != session) { - break; - } - } - - /* just some SSH message */ - ret = NC_PSPOLL_SSH_MSG; - } else { - ret = NC_PSPOLL_TIMEOUT; - } + /* no application data received */ + ret = NC_PSPOLL_TIMEOUT; } else { /* we have some application data */ ret = NC_PSPOLL_RPC; } break; -#endif -#ifdef NC_ENABLED_TLS case NC_TI_OPENSSL: r = SSL_pending(session->ti.tls); if (!r) { @@ -1697,7 +1743,7 @@ nc_ps_poll_session_io(struct nc_session *session, int io_timeout, time_t now_mon ret = NC_PSPOLL_RPC; } break; -#endif +#endif /* NC_ENABLED_SSH_TLS */ case NC_TI_FD: case NC_TI_UNIX: pfd.fd = (session->ti_type == NC_TI_FD) ? session->ti.fd.in : session->ti.unixsock.sock; @@ -1749,10 +1795,7 @@ nc_ps_poll(struct nc_pollsession *ps, int timeout, struct nc_session **session) struct nc_ps_session *cur_ps_session; struct nc_server_rpc *rpc = NULL; - if (!ps) { - ERRARG("ps"); - return NC_PSPOLL_ERROR; - } + NC_CHECK_ARG_RET(NULL, ps, NC_PSPOLL_ERROR); /* PS LOCK */ if (nc_ps_lock(ps, &q_id, __func__)) { @@ -1805,10 +1848,10 @@ nc_ps_poll(struct nc_pollsession *ps, int timeout, struct nc_session **session) cur_ps_session->state = NC_PS_STATE_NONE; break; case NC_PSPOLL_TIMEOUT: -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS case NC_PSPOLL_SSH_CHANNEL: case NC_PSPOLL_SSH_MSG: -#endif +#endif /* NC_ENABLED_SSH_TLS */ cur_ps_session->state = NC_PS_STATE_NONE; break; case NC_PSPOLL_RPC: @@ -1873,10 +1916,10 @@ nc_ps_poll(struct nc_pollsession *ps, int timeout, struct nc_session **session) case NC_PSPOLL_RPC: case NC_PSPOLL_SESSION_TERM: case NC_PSPOLL_SESSION_TERM | NC_PSPOLL_SESSION_ERROR: -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS case NC_PSPOLL_SSH_CHANNEL: case NC_PSPOLL_SSH_MSG: -#endif +#endif /* NC_ENABLED_SSH_TLS */ if (session) { *session = cur_session; } @@ -1931,7 +1974,7 @@ nc_ps_clear(struct nc_pollsession *ps, int all, void (*data_free)(void *)) struct nc_session *session; if (!ps) { - ERRARG("ps"); + ERRARG(NULL, "ps"); return; } @@ -2033,1297 +2076,224 @@ nc_accept_unix(struct nc_session *session, int sock) } API int -nc_server_add_endpt(const char *name, NC_TRANSPORT_IMPL ti) +nc_server_endpt_count(void) +{ + return server_opts.endpt_count; +} + +API int +nc_server_is_endpt(const char *name) { uint16_t i; - int ret = 0; + int found = 0; if (!name) { - ERRARG("name"); - return -1; + return found; } - /* BIND LOCK */ - pthread_mutex_lock(&server_opts.bind_lock); - - /* ENDPT WRITE LOCK */ - pthread_rwlock_wrlock(&server_opts.endpt_lock); + /* CONFIG READ LOCK */ + pthread_rwlock_rdlock(&server_opts.config_lock); /* check name uniqueness */ for (i = 0; i < server_opts.endpt_count; ++i) { if (!strcmp(server_opts.endpts[i].name, name)) { - ERR(NULL, "Endpoint \"%s\" already exists.", name); - ret = -1; - goto cleanup; + found = 1; + break; } } - server_opts.endpts = nc_realloc(server_opts.endpts, (server_opts.endpt_count + 1) * sizeof *server_opts.endpts); - if (!server_opts.endpts) { - ERRMEM; - ret = -1; - goto cleanup; + /* CONFIG UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); + + return found; +} + +API NC_MSG_TYPE +nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session) +{ + NC_MSG_TYPE msgtype; + int sock, ret; + char *host = NULL; + uint16_t port, bind_idx; + struct timespec ts_cur; + + NC_CHECK_ARG_RET(NULL, ctx, session, NC_MSG_ERROR); + + /* init ctx as needed */ + nc_server_init_cb_ctx(ctx); + + /* CONFIG LOCK */ + pthread_rwlock_rdlock(&server_opts.config_lock); + + if (!server_opts.endpt_count) { + ERR(NULL, "No endpoints to accept sessions on."); + /* CONFIG UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); + return NC_MSG_ERROR; + } + + ret = nc_sock_accept_binds(server_opts.binds, server_opts.endpt_count, &server_opts.bind_lock, timeout, &host, &port, &bind_idx); + if (ret < 1) { + free(host); + /* CONFIG UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); + if (!ret) { + return NC_MSG_WOULDBLOCK; + } + return NC_MSG_ERROR; } - memset(&server_opts.endpts[server_opts.endpt_count], 0, sizeof *server_opts.endpts); - ++server_opts.endpt_count; - server_opts.endpts[server_opts.endpt_count - 1].name = strdup(name); - server_opts.endpts[server_opts.endpt_count - 1].ti = ti; - server_opts.endpts[server_opts.endpt_count - 1].ka.idle_time = 1; - server_opts.endpts[server_opts.endpt_count - 1].ka.max_probes = 10; - server_opts.endpts[server_opts.endpt_count - 1].ka.probe_interval = 5; + sock = ret; - server_opts.binds = nc_realloc(server_opts.binds, server_opts.endpt_count * sizeof *server_opts.binds); - if (!server_opts.binds) { + *session = nc_new_session(NC_SERVER, 0); + if (!(*session)) { ERRMEM; - ret = -1; + close(sock); + free(host); + msgtype = NC_MSG_ERROR; goto cleanup; } + (*session)->status = NC_STATUS_STARTING; + (*session)->ctx = (struct ly_ctx *)ctx; + (*session)->flags = NC_SESSION_SHAREDCTX; + (*session)->host = host; + (*session)->port = port; - memset(&server_opts.binds[server_opts.endpt_count - 1], 0, sizeof *server_opts.binds); - server_opts.binds[server_opts.endpt_count - 1].sock = -1; - - switch (ti) { -#ifdef NC_ENABLED_SSH - case NC_TI_LIBSSH: - server_opts.endpts[server_opts.endpt_count - 1].opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts)); - if (!server_opts.endpts[server_opts.endpt_count - 1].opts.ssh) { - ERRMEM; - ret = -1; + /* sock gets assigned to session or closed */ +#ifdef NC_ENABLED_SSH_TLS + if (server_opts.endpts[bind_idx].ti == NC_TI_LIBSSH) { + ret = nc_accept_ssh_session(*session, server_opts.endpts[bind_idx].opts.ssh, sock, NC_TRANSPORT_TIMEOUT); + if (ret < 0) { + msgtype = NC_MSG_ERROR; + goto cleanup; + } else if (!ret) { + msgtype = NC_MSG_WOULDBLOCK; goto cleanup; } - server_opts.endpts[server_opts.endpt_count - 1].opts.ssh->auth_methods = - NC_SSH_AUTH_PUBLICKEY | NC_SSH_AUTH_PASSWORD; - server_opts.endpts[server_opts.endpt_count - 1].opts.ssh->auth_attempts = 3; - server_opts.endpts[server_opts.endpt_count - 1].opts.ssh->auth_timeout = 30; - break; -#endif -#ifdef NC_ENABLED_TLS - case NC_TI_OPENSSL: - server_opts.endpts[server_opts.endpt_count - 1].opts.tls = calloc(1, sizeof(struct nc_server_tls_opts)); - if (!server_opts.endpts[server_opts.endpt_count - 1].opts.tls) { - ERRMEM; - ret = -1; + } else if (server_opts.endpts[bind_idx].ti == NC_TI_OPENSSL) { + (*session)->data = server_opts.endpts[bind_idx].opts.tls; + ret = nc_accept_tls_session(*session, server_opts.endpts[bind_idx].opts.tls, sock, NC_TRANSPORT_TIMEOUT); + if (ret < 0) { + msgtype = NC_MSG_ERROR; + goto cleanup; + } else if (!ret) { + msgtype = NC_MSG_WOULDBLOCK; goto cleanup; } - break; -#endif - case NC_TI_UNIX: - server_opts.endpts[server_opts.endpt_count - 1].opts.unixsock = calloc(1, sizeof(struct nc_server_unix_opts)); - if (!server_opts.endpts[server_opts.endpt_count - 1].opts.unixsock) { - ERRMEM; - ret = -1; + } else +#endif /* NC_ENABLED_SSH_TLS */ + if (server_opts.endpts[bind_idx].ti == NC_TI_UNIX) { + (*session)->data = server_opts.endpts[bind_idx].opts.unixsock; + ret = nc_accept_unix(*session, sock); + if (ret < 0) { + msgtype = NC_MSG_ERROR; goto cleanup; } - server_opts.endpts[server_opts.endpt_count - 1].opts.unixsock->mode = (mode_t)-1; - server_opts.endpts[server_opts.endpt_count - 1].opts.unixsock->uid = (uid_t)-1; - server_opts.endpts[server_opts.endpt_count - 1].opts.unixsock->gid = (gid_t)-1; - break; - default: + } else { ERRINT; - ret = -1; + close(sock); + msgtype = NC_MSG_ERROR; goto cleanup; } -cleanup: - /* ENDPT UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - /* BIND UNLOCK */ - pthread_mutex_unlock(&server_opts.bind_lock); + (*session)->data = NULL; - return ret; -} + /* CONFIG UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); -API int -nc_server_del_endpt(const char *name, NC_TRANSPORT_IMPL ti) -{ - uint32_t i; - int ret = -1; + /* assign new SID atomically */ + (*session)->id = ATOMIC_INC_RELAXED(server_opts.new_session_id); - /* BIND LOCK */ - pthread_mutex_lock(&server_opts.bind_lock); - - /* ENDPT WRITE LOCK */ - pthread_rwlock_wrlock(&server_opts.endpt_lock); - - if (!name && !ti) { - /* remove all endpoints */ - for (i = 0; i < server_opts.endpt_count; ++i) { - free(server_opts.endpts[i].name); - switch (server_opts.endpts[i].ti) { -#ifdef NC_ENABLED_SSH - case NC_TI_LIBSSH: - nc_server_ssh_clear_opts(server_opts.endpts[i].opts.ssh); - free(server_opts.endpts[i].opts.ssh); - break; -#endif -#ifdef NC_ENABLED_TLS - case NC_TI_OPENSSL: - nc_server_tls_clear_opts(server_opts.endpts[i].opts.tls); - free(server_opts.endpts[i].opts.tls); - break; -#endif - case NC_TI_UNIX: - free(server_opts.endpts[i].opts.unixsock); - break; - default: - ERRINT; - /* won't get here ...*/ - break; - } - ret = 0; - } - free(server_opts.endpts); - server_opts.endpts = NULL; - - /* remove all binds */ - for (i = 0; i < server_opts.endpt_count; ++i) { - free(server_opts.binds[i].address); - if (server_opts.binds[i].sock > -1) { - close(server_opts.binds[i].sock); - } - } - free(server_opts.binds); - server_opts.binds = NULL; - - server_opts.endpt_count = 0; - - } else { - /* remove one endpoint with bind(s) or all endpoints using one transport protocol */ - for (i = 0; i < server_opts.endpt_count; ++i) { - if ((name && !strcmp(server_opts.endpts[i].name, name)) || (!name && (server_opts.endpts[i].ti == ti))) { - /* remove endpt */ - free(server_opts.endpts[i].name); - switch (server_opts.endpts[i].ti) { -#ifdef NC_ENABLED_SSH - case NC_TI_LIBSSH: - nc_server_ssh_clear_opts(server_opts.endpts[i].opts.ssh); - free(server_opts.endpts[i].opts.ssh); - break; -#endif -#ifdef NC_ENABLED_TLS - case NC_TI_OPENSSL: - nc_server_tls_clear_opts(server_opts.endpts[i].opts.tls); - free(server_opts.endpts[i].opts.tls); - break; -#endif - case NC_TI_UNIX: - free(server_opts.endpts[i].opts.unixsock); - break; - default: - ERRINT; - break; - } - - /* remove bind(s) */ - free(server_opts.binds[i].address); - if (server_opts.binds[i].sock > -1) { - close(server_opts.binds[i].sock); - } - - /* move last endpt and bind(s) to the empty space */ - --server_opts.endpt_count; - if (!server_opts.endpt_count) { - free(server_opts.binds); - server_opts.binds = NULL; - free(server_opts.endpts); - server_opts.endpts = NULL; - } else if (i < server_opts.endpt_count) { - memcpy(&server_opts.binds[i], &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds); - memcpy(&server_opts.endpts[i], &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts); - } - - ret = 0; - if (name) { - break; - } - } - } - } - - /* ENDPT UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - /* BIND UNLOCK */ - pthread_mutex_unlock(&server_opts.bind_lock); - - return ret; -} - -API int -nc_server_endpt_count(void) -{ - return server_opts.endpt_count; -} - -API int -nc_server_is_endpt(const char *name) -{ - uint16_t i; - int found = 0; - - if (!name) { - return found; - } - - /* ENDPT READ LOCK */ - pthread_rwlock_rdlock(&server_opts.endpt_lock); - - /* check name uniqueness */ - for (i = 0; i < server_opts.endpt_count; ++i) { - if (!strcmp(server_opts.endpts[i].name, name)) { - found = 1; - break; - } - } - - /* ENDPT UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - return found; -} - -int -nc_server_endpt_set_address_port(const char *endpt_name, const char *address, uint16_t port) -{ - struct nc_endpt *endpt; - struct nc_bind *bind = NULL; - uint16_t i; - int sock = -1, set_addr, ret = 0; - - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } else if ((!address && !port) || (address && port)) { - ERRARG("address and port"); - return -1; - } - - if (address) { - set_addr = 1; - } else { - set_addr = 0; - } - - /* BIND LOCK */ - pthread_mutex_lock(&server_opts.bind_lock); - - /* ENDPT LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, 0, &i); - if (!endpt) { - /* BIND UNLOCK */ - pthread_mutex_unlock(&server_opts.bind_lock); - return -1; - } - - bind = &server_opts.binds[i]; - - if (set_addr) { - port = bind->port; - } else { - address = bind->address; - } - - if (!set_addr && (endpt->ti == NC_TI_UNIX)) { - ret = -1; - goto cleanup; - } - - /* we have all the information we need to create a listening socket */ - if (address && (port || (endpt->ti == NC_TI_UNIX))) { - /* create new socket, close the old one */ - if (endpt->ti == NC_TI_UNIX) { - sock = nc_sock_listen_unix(address, endpt->opts.unixsock); - } else { - sock = nc_sock_listen_inet(address, port, &endpt->ka); - } - if (sock == -1) { - ret = -1; - goto cleanup; - } - - if (bind->sock > -1) { - close(bind->sock); - } - bind->sock = sock; - } /* else we are just setting address or port */ - - if (set_addr) { - free(bind->address); - bind->address = strdup(address); - } else { - bind->port = port; - } - - if (sock > -1) { - switch (endpt->ti) { - case NC_TI_UNIX: - VRB(NULL, "Listening on %s for UNIX connections.", address); - break; -#ifdef NC_ENABLED_SSH - case NC_TI_LIBSSH: - VRB(NULL, "Listening on %s:%u for SSH connections.", address, port); - break; -#endif -#ifdef NC_ENABLED_TLS - case NC_TI_OPENSSL: - VRB(NULL, "Listening on %s:%u for TLS connections.", address, port); - break; -#endif - default: - ERRINT; - break; - } - } - -cleanup: - /* ENDPT UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - /* BIND UNLOCK */ - pthread_mutex_unlock(&server_opts.bind_lock); - - return ret; -} - -API int -nc_server_endpt_set_address(const char *endpt_name, const char *address) -{ - return nc_server_endpt_set_address_port(endpt_name, address, 0); -} - -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) - -API int -nc_server_endpt_set_port(const char *endpt_name, uint16_t port) -{ - return nc_server_endpt_set_address_port(endpt_name, NULL, port); -} - -#endif - -API int -nc_server_endpt_set_perms(const char *endpt_name, mode_t mode, uid_t uid, gid_t gid) -{ - struct nc_endpt *endpt; - uint16_t i; - int ret = 0; - - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } else if (mode == 0) { - ERRARG("mode"); - return -1; - } - - /* ENDPT LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, 0, &i); - if (!endpt) { - return -1; - } - - if (endpt->ti != NC_TI_UNIX) { - ret = -1; - goto cleanup; - } - - endpt->opts.unixsock->mode = mode; - endpt->opts.unixsock->uid = uid; - endpt->opts.unixsock->gid = gid; - -cleanup: - /* ENDPT UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - return ret; -} - -API int -nc_server_endpt_enable_keepalives(const char *endpt_name, int enable) -{ - struct nc_endpt *endpt; - int ret = 0; - - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } - - /* ENDPT LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, 0, NULL); - if (!endpt) { - return -1; - } - - endpt->ka.enabled = (enable ? 1 : 0); - - /* ENDPT UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - return ret; -} - -API int -nc_server_endpt_set_keepalives(const char *endpt_name, int idle_time, int max_probes, int probe_interval) -{ - struct nc_endpt *endpt; - int ret = 0; - - if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } - - /* ENDPT LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, 0, NULL); - if (!endpt) { - return -1; - } - - if (idle_time > -1) { - endpt->ka.idle_time = idle_time; - } - if (max_probes > -1) { - endpt->ka.max_probes = max_probes; - } - if (probe_interval > -1) { - endpt->ka.probe_interval = probe_interval; - } - - /* ENDPT UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - return ret; -} - -API NC_MSG_TYPE -nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session) -{ - NC_MSG_TYPE msgtype; - int sock, ret; - char *host = NULL; - uint16_t port, bind_idx; - struct timespec ts_cur; - - if (!ctx) { - ERRARG("ctx"); - return NC_MSG_ERROR; - } else if (!session) { - ERRARG("session"); - return NC_MSG_ERROR; - } - - /* init ctx as needed */ - nc_server_init_ctx(ctx); - - /* BIND LOCK */ - pthread_mutex_lock(&server_opts.bind_lock); - - if (!server_opts.endpt_count) { - ERR(NULL, "No endpoints to accept sessions on."); - /* BIND UNLOCK */ - pthread_mutex_unlock(&server_opts.bind_lock); - return NC_MSG_ERROR; - } - - ret = nc_sock_accept_binds(server_opts.binds, server_opts.endpt_count, timeout, &host, &port, &bind_idx); - if (ret < 1) { - /* BIND UNLOCK */ - pthread_mutex_unlock(&server_opts.bind_lock); - free(host); - if (!ret) { - return NC_MSG_WOULDBLOCK; - } - return NC_MSG_ERROR; - } - - /* switch bind_lock for endpt_lock, so that another thread can accept another session */ - /* ENDPT READ LOCK */ - pthread_rwlock_rdlock(&server_opts.endpt_lock); - - /* BIND UNLOCK */ - pthread_mutex_unlock(&server_opts.bind_lock); - - sock = ret; - - *session = nc_new_session(NC_SERVER, 0); - if (!(*session)) { - ERRMEM; - close(sock); - free(host); - msgtype = NC_MSG_ERROR; - goto cleanup; - } - (*session)->status = NC_STATUS_STARTING; - (*session)->ctx = (struct ly_ctx *)ctx; - (*session)->flags = NC_SESSION_SHAREDCTX; - (*session)->host = host; - (*session)->port = port; - - /* sock gets assigned to session or closed */ -#ifdef NC_ENABLED_SSH - if (server_opts.endpts[bind_idx].ti == NC_TI_LIBSSH) { - (*session)->data = server_opts.endpts[bind_idx].opts.ssh; - ret = nc_accept_ssh_session(*session, sock, NC_TRANSPORT_TIMEOUT); - if (ret < 0) { - msgtype = NC_MSG_ERROR; - goto cleanup; - } else if (!ret) { - msgtype = NC_MSG_WOULDBLOCK; - goto cleanup; - } - } else -#endif -#ifdef NC_ENABLED_TLS - if (server_opts.endpts[bind_idx].ti == NC_TI_OPENSSL) { - (*session)->data = server_opts.endpts[bind_idx].opts.tls; - ret = nc_accept_tls_session(*session, sock, NC_TRANSPORT_TIMEOUT); - if (ret < 0) { - msgtype = NC_MSG_ERROR; - goto cleanup; - } else if (!ret) { - msgtype = NC_MSG_WOULDBLOCK; - goto cleanup; - } - } else -#endif - if (server_opts.endpts[bind_idx].ti == NC_TI_UNIX) { - (*session)->data = server_opts.endpts[bind_idx].opts.unixsock; - ret = nc_accept_unix(*session, sock); - if (ret < 0) { - msgtype = NC_MSG_ERROR; - goto cleanup; - } - } else { - ERRINT; - close(sock); - msgtype = NC_MSG_ERROR; - goto cleanup; - } - - (*session)->data = NULL; - - /* ENDPT UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - /* assign new SID atomically */ - (*session)->id = ATOMIC_INC_RELAXED(server_opts.new_session_id); - - /* NETCONF handshake */ - msgtype = nc_handshake_io(*session); - if (msgtype != NC_MSG_HELLO) { - nc_session_free(*session, NULL); - *session = NULL; - return msgtype; - } - - nc_timeouttime_get(&ts_cur, 0); - (*session)->opts.server.last_rpc = ts_cur.tv_sec; - nc_realtime_get(&ts_cur); - (*session)->opts.server.session_start = ts_cur.tv_sec; - (*session)->status = NC_STATUS_RUNNING; - - return msgtype; - -cleanup: - /* ENDPT UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - nc_session_free(*session, NULL); - *session = NULL; - return msgtype; -} - -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) - -/* client is expected to be locked */ -static int -_nc_server_ch_client_del_endpt(struct nc_ch_client *client, const char *endpt_name, NC_TRANSPORT_IMPL ti) -{ - uint16_t i; - int ret = -1; - - if (!endpt_name) { - /* remove all endpoints */ - for (i = 0; i < client->ch_endpt_count; ++i) { - free(client->ch_endpts[i].name); - free(client->ch_endpts[i].address); - if (client->ch_endpts[i].sock_pending != -1) { - close(client->ch_endpts[i].sock_pending); - } - switch (client->ch_endpts[i].ti) { -#ifdef NC_ENABLED_SSH - case NC_TI_LIBSSH: - nc_server_ssh_clear_opts(client->ch_endpts[i].opts.ssh); - free(client->ch_endpts[i].opts.ssh); - break; -#endif -#ifdef NC_ENABLED_TLS - case NC_TI_OPENSSL: - nc_server_tls_clear_opts(client->ch_endpts[i].opts.tls); - free(client->ch_endpts[i].opts.tls); - break; -#endif - default: - ERRINT; - /* won't get here ...*/ - break; - } - } - free(client->ch_endpts); - client->ch_endpts = NULL; - client->ch_endpt_count = 0; - - ret = 0; - } else { - for (i = 0; i < client->ch_endpt_count; ++i) { - if (!strcmp(client->ch_endpts[i].name, endpt_name) && (!ti || (ti == client->ch_endpts[i].ti))) { - free(client->ch_endpts[i].name); - free(client->ch_endpts[i].address); - if (client->ch_endpts[i].sock_pending != -1) { - close(client->ch_endpts[i].sock_pending); - } - switch (client->ch_endpts[i].ti) { -#ifdef NC_ENABLED_SSH - case NC_TI_LIBSSH: - nc_server_ssh_clear_opts(client->ch_endpts[i].opts.ssh); - free(client->ch_endpts[i].opts.ssh); - break; -#endif -#ifdef NC_ENABLED_TLS - case NC_TI_OPENSSL: - nc_server_tls_clear_opts(client->ch_endpts[i].opts.tls); - free(client->ch_endpts[i].opts.tls); - break; -#endif - default: - ERRINT; - /* won't get here ...*/ - break; - } - - /* move last endpoint to the empty space */ - --client->ch_endpt_count; - if (i < client->ch_endpt_count) { - memcpy(&client->ch_endpts[i], &client->ch_endpts[client->ch_endpt_count], sizeof *client->ch_endpts); - } else if (!server_opts.ch_client_count) { - free(server_opts.ch_clients); - server_opts.ch_clients = NULL; - } - - ret = 0; - break; - } - } - } - - return ret; -} - -API int -nc_server_ch_add_client(const char *name) -{ - uint16_t i; - struct nc_ch_client *client; - - if (!name) { - ERRARG("name"); - return -1; - } - - /* WRITE LOCK */ - pthread_rwlock_wrlock(&server_opts.ch_client_lock); - - /* check name uniqueness */ - for (i = 0; i < server_opts.ch_client_count; ++i) { - if (!strcmp(server_opts.ch_clients[i].name, name)) { - ERR(NULL, "Call Home client \"%s\" already exists.", name); - /* WRITE UNLOCK */ - pthread_rwlock_unlock(&server_opts.ch_client_lock); - return -1; - } - } - - ++server_opts.ch_client_count; - server_opts.ch_clients = nc_realloc(server_opts.ch_clients, server_opts.ch_client_count * sizeof *server_opts.ch_clients); - if (!server_opts.ch_clients) { - ERRMEM; - /* WRITE UNLOCK */ - pthread_rwlock_unlock(&server_opts.ch_client_lock); - return -1; - } - client = &server_opts.ch_clients[server_opts.ch_client_count - 1]; - - client->name = strdup(name); - client->id = ATOMIC_INC_RELAXED(server_opts.new_client_id); - client->ch_endpts = NULL; - client->ch_endpt_count = 0; - client->conn_type = 0; - - /* set CH default options */ - client->start_with = NC_CH_FIRST_LISTED; - client->max_attempts = 3; - - pthread_mutex_init(&client->lock, NULL); - - /* WRITE UNLOCK */ - pthread_rwlock_unlock(&server_opts.ch_client_lock); - - return 0; -} - -API int -nc_server_ch_del_client(const char *name) -{ - uint16_t i; - int ret = -1; - - /* WRITE LOCK */ - pthread_rwlock_wrlock(&server_opts.ch_client_lock); - - if (!name) { - /* remove all CH clients with endpoints */ - for (i = 0; i < server_opts.ch_client_count; ++i) { - free(server_opts.ch_clients[i].name); - - /* remove all endpoints */ - _nc_server_ch_client_del_endpt(&server_opts.ch_clients[i], NULL, 0); - - pthread_mutex_destroy(&server_opts.ch_clients[i].lock); - ret = 0; - } - free(server_opts.ch_clients); - server_opts.ch_clients = NULL; - - server_opts.ch_client_count = 0; - - } else { - /* remove one client with endpoints */ - for (i = 0; i < server_opts.ch_client_count; ++i) { - if (!strcmp(server_opts.ch_clients[i].name, name)) { - free(server_opts.ch_clients[i].name); - - /* remove all endpoints */ - _nc_server_ch_client_del_endpt(&server_opts.ch_clients[i], NULL, 0); - - pthread_mutex_destroy(&server_opts.ch_clients[i].lock); - - /* move last client and endpoint(s) to the empty space */ - --server_opts.ch_client_count; - if (i < server_opts.ch_client_count) { - memcpy(&server_opts.ch_clients[i], &server_opts.ch_clients[server_opts.ch_client_count], - sizeof *server_opts.ch_clients); - } else if (!server_opts.ch_client_count) { - free(server_opts.ch_clients); - server_opts.ch_clients = NULL; - } - - ret = 0; - break; - } - } - } - - /* WRITE UNLOCK */ - pthread_rwlock_unlock(&server_opts.ch_client_lock); - - return ret; -} - -API int -nc_server_ch_is_client(const char *name) -{ - uint16_t i; - int found = 0; - - if (!name) { - return found; - } - - /* READ LOCK */ - pthread_rwlock_rdlock(&server_opts.ch_client_lock); - - /* check name uniqueness */ - for (i = 0; i < server_opts.ch_client_count; ++i) { - if (!strcmp(server_opts.ch_clients[i].name, name)) { - found = 1; - break; - } - } - - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.ch_client_lock); - - return found; -} - -API int -nc_server_ch_client_add_endpt(const char *client_name, const char *endpt_name, NC_TRANSPORT_IMPL ti) -{ - uint16_t i; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - int ret = -1; - - if (!client_name) { - ERRARG("client_name"); - return -1; - } else if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } else if (!ti) { - ERRARG("ti"); - return -1; - } - - /* LOCK */ - nc_server_ch_client_lock(client_name, NULL, 0, &client); - if (!client) { - return -1; - } - - for (i = 0; i < client->ch_endpt_count; ++i) { - if (!strcmp(client->ch_endpts[i].name, endpt_name)) { - ERR(NULL, "Call Home client \"%s\" endpoint \"%s\" already exists.", client_name, endpt_name); - goto cleanup; - } - } - - ++client->ch_endpt_count; - client->ch_endpts = realloc(client->ch_endpts, client->ch_endpt_count * sizeof *client->ch_endpts); - if (!client->ch_endpts) { - ERRMEM; - goto cleanup; - } - endpt = &client->ch_endpts[client->ch_endpt_count - 1]; - - memset(endpt, 0, sizeof *client->ch_endpts); - endpt->name = strdup(endpt_name); - endpt->ti = ti; - endpt->sock_pending = -1; - endpt->ka.idle_time = 1; - endpt->ka.max_probes = 10; - endpt->ka.probe_interval = 5; - - switch (ti) { -#ifdef NC_ENABLED_SSH - case NC_TI_LIBSSH: - endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts)); - if (!endpt->opts.ssh) { - ERRMEM; - goto cleanup; - } - endpt->opts.ssh->auth_methods = NC_SSH_AUTH_PUBLICKEY | NC_SSH_AUTH_PASSWORD; - endpt->opts.ssh->auth_attempts = 3; - endpt->opts.ssh->auth_timeout = 30; - break; -#endif -#ifdef NC_ENABLED_TLS - case NC_TI_OPENSSL: - endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts)); - if (!endpt->opts.tls) { - ERRMEM; - goto cleanup; - } - break; -#endif - default: - ERRINT; - goto cleanup; - } - - /* success */ - ret = 0; - -cleanup: - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -API int -nc_server_ch_client_del_endpt(const char *client_name, const char *endpt_name, NC_TRANSPORT_IMPL ti) -{ - int ret; - struct nc_ch_client *client; - - if (!client_name) { - ERRARG("client_name"); - return -1; - } - - /* LOCK */ - nc_server_ch_client_lock(client_name, NULL, 0, &client); - if (!client) { - return -1; - } - - ret = _nc_server_ch_client_del_endpt(client, endpt_name, ti); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -API int -nc_server_ch_client_is_endpt(const char *client_name, const char *endpt_name) -{ - uint16_t i; - struct nc_ch_client *client = NULL; - int found = 0; - - if (!client_name || !endpt_name) { - return found; - } - - /* READ LOCK */ - pthread_rwlock_rdlock(&server_opts.ch_client_lock); - - for (i = 0; i < server_opts.ch_client_count; ++i) { - if (!strcmp(server_opts.ch_clients[i].name, client_name)) { - client = &server_opts.ch_clients[i]; - break; - } - } - - if (!client) { - goto cleanup; - } - - for (i = 0; i < client->ch_endpt_count; ++i) { - if (!strcmp(client->ch_endpts[i].name, endpt_name)) { - found = 1; - break; - } - } - -cleanup: - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.ch_client_lock); - return found; -} - -API int -nc_server_ch_client_endpt_set_address(const char *client_name, const char *endpt_name, const char *address) -{ - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - if (!client_name) { - ERRARG("client_name"); - return -1; - } else if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } else if (!address) { - ERRARG("address"); - return -1; - } - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, 0, &client); - if (!endpt) { - return -1; - } - - free(endpt->address); - endpt->address = strdup(address); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return 0; -} - -API int -nc_server_ch_client_endpt_set_port(const char *client_name, const char *endpt_name, uint16_t port) -{ - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - if (!client_name) { - ERRARG("client_name"); - return -1; - } else if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } else if (!port) { - ERRARG("port"); - return -1; - } - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, 0, &client); - if (!endpt) { - return -1; - } - - endpt->port = port; - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return 0; -} - -API int -nc_server_ch_client_endpt_enable_keepalives(const char *client_name, const char *endpt_name, int enable) -{ - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - if (!client_name) { - ERRARG("client_name"); - return -1; - } else if (!endpt_name) { - ERRARG("endpt_name"); - return -1; - } - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, 0, &client); - if (!endpt) { - return -1; - } - - endpt->ka.enabled = (enable ? 1 : 0); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return 0; -} - -API int -nc_server_ch_client_endpt_set_keepalives(const char *client_name, const char *endpt_name, int idle_time, int max_probes, - int probe_interval) -{ - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - if (!client_name) { - ERRARG("client_name"); - return -1; - } else if (!endpt_name) { - ERRARG("endpt_name"); - return -1; + /* NETCONF handshake */ + msgtype = nc_handshake_io(*session); + if (msgtype != NC_MSG_HELLO) { + nc_session_free(*session, NULL); + *session = NULL; + return msgtype; } - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, 0, &client); - if (!endpt) { - return -1; - } + nc_timeouttime_get(&ts_cur, 0); + (*session)->opts.server.last_rpc = ts_cur.tv_sec; + nc_realtime_get(&ts_cur); + (*session)->opts.server.session_start = ts_cur.tv_sec; + (*session)->status = NC_STATUS_RUNNING; - if (idle_time > -1) { - endpt->ka.idle_time = idle_time; - } - if (max_probes > -1) { - endpt->ka.max_probes = max_probes; - } - if (probe_interval > -1) { - endpt->ka.probe_interval = probe_interval; - } + return msgtype; - /* UNLOCK */ - nc_server_ch_client_unlock(client); +cleanup: + /* CONFIG UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); - return 0; + nc_session_free(*session, NULL); + *session = NULL; + return msgtype; } +#ifdef NC_ENABLED_SSH_TLS + API int -nc_server_ch_client_set_conn_type(const char *client_name, NC_CH_CONN_TYPE conn_type) +nc_server_ch_is_client(const char *name) { - struct nc_ch_client *client; - - if (!client_name) { - ERRARG("client_name"); - return -1; - } else if (!conn_type) { - ERRARG("conn_type"); - return -1; - } + uint16_t i; + int found = 0; - /* LOCK */ - nc_server_ch_client_lock(client_name, NULL, 0, &client); - if (!client) { - return -1; + if (!name) { + return found; } - if (client->conn_type != conn_type) { - client->conn_type = conn_type; + /* READ LOCK */ + pthread_rwlock_rdlock(&server_opts.ch_client_lock); - /* set default options */ - switch (conn_type) { - case NC_CH_PERSIST: - /* no options */ - break; - case NC_CH_PERIOD: - client->conn.period.period = 60; - client->conn.period.anchor_time = 0; - client->conn.period.idle_timeout = 120; - break; - default: - ERRINT; + /* check name uniqueness */ + for (i = 0; i < server_opts.ch_client_count; ++i) { + if (!strcmp(server_opts.ch_clients[i].name, name)) { + found = 1; break; } } /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return 0; -} - -API int -nc_server_ch_client_periodic_set_period(const char *client_name, uint16_t period) -{ - struct nc_ch_client *client; - - if (!client_name) { - ERRARG("client_name"); - return -1; - } else if (!period) { - ERRARG("period"); - return -1; - } - - /* LOCK */ - nc_server_ch_client_lock(client_name, NULL, 0, &client); - if (!client) { - return -1; - } - - if (client->conn_type != NC_CH_PERIOD) { - ERR(NULL, "Call Home client \"%s\" is not of periodic connection type.", client_name); - /* UNLOCK */ - nc_server_ch_client_unlock(client); - return -1; - } - - client->conn.period.period = period; - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return 0; -} - -API int -nc_server_ch_client_periodic_set_anchor_time(const char *client_name, time_t anchor_time) -{ - struct nc_ch_client *client; - - if (!client_name) { - ERRARG("client_name"); - return -1; - } - - /* LOCK */ - nc_server_ch_client_lock(client_name, NULL, 0, &client); - if (!client) { - return -1; - } - - if (client->conn_type != NC_CH_PERIOD) { - ERR(NULL, "Call Home client \"%s\" is not of periodic connection type.", client_name); - /* UNLOCK */ - nc_server_ch_client_unlock(client); - return -1; - } - - client->conn.period.anchor_time = anchor_time; - - /* UNLOCK */ - nc_server_ch_client_unlock(client); + pthread_rwlock_unlock(&server_opts.ch_client_lock); - return 0; + return found; } API int -nc_server_ch_client_periodic_set_idle_timeout(const char *client_name, uint16_t idle_timeout) +nc_server_ch_client_is_endpt(const char *client_name, const char *endpt_name) { - struct nc_ch_client *client; - - if (!client_name) { - ERRARG("client_name"); - return -1; - } - - /* LOCK */ - nc_server_ch_client_lock(client_name, NULL, 0, &client); - if (!client) { - return -1; - } + uint16_t i; + struct nc_ch_client *client = NULL; + int found = 0; - if (client->conn_type != NC_CH_PERIOD) { - ERR(NULL, "Call Home client \"%s\" is not of periodic connection type.", client_name); - /* UNLOCK */ - nc_server_ch_client_unlock(client); - return -1; + if (!client_name || !endpt_name) { + return found; } - client->conn.period.idle_timeout = idle_timeout; - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return 0; -} - -API int -nc_server_ch_client_set_start_with(const char *client_name, NC_CH_START_WITH start_with) -{ - struct nc_ch_client *client; + /* READ LOCK */ + pthread_rwlock_rdlock(&server_opts.ch_client_lock); - if (!client_name) { - ERRARG("client_name"); - return -1; + for (i = 0; i < server_opts.ch_client_count; ++i) { + if (!strcmp(server_opts.ch_clients[i].name, client_name)) { + client = &server_opts.ch_clients[i]; + break; + } } - /* LOCK */ - nc_server_ch_client_lock(client_name, NULL, 0, &client); if (!client) { - return -1; - } - - client->start_with = start_with; - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return 0; -} - -API int -nc_server_ch_client_set_max_attempts(const char *client_name, uint8_t max_attempts) -{ - struct nc_ch_client *client; - - if (!client_name) { - ERRARG("client_name"); - return -1; - } else if (!max_attempts) { - ERRARG("max_attempts"); - return -1; + goto cleanup; } - /* LOCK */ - nc_server_ch_client_lock(client_name, NULL, 0, &client); - if (!client) { - return -1; + for (i = 0; i < client->ch_endpt_count; ++i) { + if (!strcmp(client->ch_endpts[i].name, endpt_name)) { + found = 1; + break; + } } - client->max_attempts = max_attempts; - +cleanup: /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return 0; + pthread_rwlock_unlock(&server_opts.ch_client_lock); + return found; } /** @@ -3362,6 +2332,9 @@ nc_connect_ch_endpt(struct nc_ch_endpt *endpt, nc_server_ch_session_acquire_ctx_ return NC_MSG_ERROR; } + /* init ctx as needed */ + nc_server_init_cb_ctx(ctx); + /* create session */ *session = nc_new_session(NC_SERVER, 0); if (!(*session)) { @@ -3378,10 +2351,9 @@ nc_connect_ch_endpt(struct nc_ch_endpt *endpt, nc_server_ch_session_acquire_ctx_ (*session)->port = endpt->port; /* sock gets assigned to session or closed */ -#ifdef NC_ENABLED_SSH +#ifdef NC_ENABLED_SSH_TLS if (endpt->ti == NC_TI_LIBSSH) { - (*session)->data = endpt->opts.ssh; - ret = nc_accept_ssh_session(*session, sock, NC_TRANSPORT_TIMEOUT); + ret = nc_accept_ssh_session(*session, endpt->opts.ssh, sock, NC_TRANSPORT_TIMEOUT); (*session)->data = NULL; if (ret < 0) { @@ -3391,12 +2363,9 @@ nc_connect_ch_endpt(struct nc_ch_endpt *endpt, nc_server_ch_session_acquire_ctx_ msgtype = NC_MSG_WOULDBLOCK; goto fail; } - } else -#endif -#ifdef NC_ENABLED_TLS - if (endpt->ti == NC_TI_OPENSSL) { + } else if (endpt->ti == NC_TI_OPENSSL) { (*session)->data = endpt->opts.tls; - ret = nc_accept_tls_session(*session, sock, NC_TRANSPORT_TIMEOUT); + ret = nc_accept_tls_session(*session, endpt->opts.tls, sock, NC_TRANSPORT_TIMEOUT); (*session)->data = NULL; if (ret < 0) { @@ -3407,7 +2376,7 @@ nc_connect_ch_endpt(struct nc_ch_endpt *endpt, nc_server_ch_session_acquire_ctx_ goto fail; } } else -#endif +#endif /* NC_ENABLED_SSH_TLS */ { ERRINT; close(sock); @@ -3441,14 +2410,6 @@ nc_connect_ch_endpt(struct nc_ch_endpt *endpt, nc_server_ch_session_acquire_ctx_ return msgtype; } -struct nc_ch_client_thread_arg { - char *client_name; - nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb; - nc_server_ch_session_release_ctx_cb release_ctx_cb; - void *ctx_cb_data; - nc_server_ch_new_session_cb new_session_cb; -}; - static struct nc_ch_client * nc_server_ch_client_with_endpt_lock(const char *name) { @@ -3488,7 +2449,7 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_session *session, struct session->flags |= NC_SESSION_CH_THREAD; /* give the session to the user */ - if (data->new_session_cb(data->client_name, session)) { + if (data->new_session_cb(data->client_name, session, data->new_session_cb_data)) { /* something is wrong, free the session */ session->flags &= ~NC_SESSION_CH_THREAD; @@ -3502,8 +2463,7 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_session *session, struct } do { - nc_timeouttime_get(&ts, NC_CH_NO_ENDPT_WAIT); - + nc_timeouttime_get(&ts, NC_CH_THREAD_IDLE_TIMEOUT_SLEEP); /* CH COND WAIT */ r = pthread_cond_clockwait(&session->opts.server.ch_cond, &session->opts.server.ch_lock, COMPAT_CLOCK_ID, &ts); if (!r) { @@ -3529,7 +2489,7 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_session *session, struct } if (client->conn_type == NC_CH_PERIOD) { - idle_timeout = client->conn.period.idle_timeout; + idle_timeout = client->idle_timeout; } else { idle_timeout = 0; } @@ -3556,30 +2516,102 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_session *session, struct return ret; } +/** + * @brief Waits for some amount of time while reacting to signals about terminating a Call Home thread. + * + * @param[in] session An established session. + * @param[in] data Call Home thread's data. + * @param[in] cond_wait_time Time in seconds to sleep for, after which a reconnect is attempted. + * + * @return 0 if the thread should stop running, 1 if it should continue. + */ +static int +nc_server_ch_client_thread_is_running_wait(struct nc_session *session, struct nc_ch_client_thread_arg *data, uint64_t cond_wait_time) +{ + struct timespec ts; + int ret = 0, thread_running; + + /* COND LOCK */ + pthread_mutex_lock(&data->cond_lock); + /* get reconnect timeout in ms */ + nc_timeouttime_get(&ts, cond_wait_time * 1000); + while (!ret && data->thread_running) { + ret = pthread_cond_clockwait(&data->cond, &data->cond_lock, COMPAT_CLOCK_ID, &ts); + } + + thread_running = data->thread_running; + /* COND UNLOCK */ + pthread_mutex_unlock(&data->cond_lock); + + if (!thread_running) { + /* thread is terminating */ + VRB(session, "Call Home thread signaled to exit, client \"%s\" probably removed.", data->client_name); + ret = 0; + } else if (ret == ETIMEDOUT) { + /* time to reconnect */ + VRB(session, "Call Home client \"%s\" timeout of %" PRIu64 " seconds expired, reconnecting.", data->client_name, cond_wait_time); + ret = 1; + } else if (ret) { + ERR(session, "Pthread condition timedwait failed (%s).", strerror(ret)); + ret = 0; + } + + return ret; +} + +/** + * @brief Checks if a Call Home thread should terminate. + * + * Checks the shared boolean variable thread_running. This should be done everytime + * before entering a critical section. + * + * @param[in] data Call Home thread's data. + * + * @return 0 if the thread should stop running, -1 if it can continue. + */ +static int +nc_server_ch_client_thread_is_running(struct nc_ch_client_thread_arg *data) +{ + int ret = -1; + + /* COND LOCK */ + pthread_mutex_lock(&data->cond_lock); + if (!data->thread_running) { + /* thread should stop running */ + ret = 0; + } + /* COND UNLOCK */ + pthread_mutex_unlock(&data->cond_lock); + + return ret; +} + static void * nc_ch_client_thread(void *arg) { struct nc_ch_client_thread_arg *data = (struct nc_ch_client_thread_arg *)arg; NC_MSG_TYPE msgtype; uint8_t cur_attempts = 0; - uint16_t next_endpt_index; + uint16_t next_endpt_index, max_wait; char *cur_endpt_name = NULL; struct nc_ch_endpt *cur_endpt; - struct nc_session *session; + struct nc_session *session = NULL; struct nc_ch_client *client; - uint32_t client_id, reconnect_in; + uint32_t reconnect_in; /* LOCK */ client = nc_server_ch_client_with_endpt_lock(data->client_name); - if (!client) { - goto cleanup; - } - client_id = client->id; + assert(client); cur_endpt = &client->ch_endpts[0]; cur_endpt_name = strdup(cur_endpt->name); while (1) { + if (!nc_server_ch_client_thread_is_running(data)) { + /* thread should stop running */ + break; + } + if (!cur_attempts) { VRB(NULL, "Call Home client \"%s\" endpoint \"%s\" connecting...", data->client_name, cur_endpt_name); } @@ -3589,49 +2621,50 @@ nc_ch_client_thread(void *arg) /* UNLOCK */ nc_server_ch_client_unlock(client); - VRB(NULL, "Call Home client \"%s\" session %u established.", data->client_name, session->id); - if (nc_server_ch_client_thread_session_cond_wait(session, data)) { + if (!nc_server_ch_client_thread_is_running(data)) { + /* thread should stop running */ goto cleanup; } - VRB(NULL, "Call Home client \"%s\" session terminated.", data->client_name); - /* LOCK */ - client = nc_server_ch_client_with_endpt_lock(data->client_name); - if (!client) { + /* run while the session is established */ + VRB(session, "Call Home client \"%s\" session %u established.", data->client_name, session->id); + if (nc_server_ch_client_thread_session_cond_wait(session, data)) { goto cleanup; } - if (client->id != client_id) { - nc_server_ch_client_unlock(client); + + VRB(session, "Call Home client \"%s\" session terminated.", data->client_name); + if (!nc_server_ch_client_thread_is_running(data)) { + /* thread should stop running */ goto cleanup; } + /* LOCK */ + client = nc_server_ch_client_with_endpt_lock(data->client_name); + assert(client); + /* session changed status -> it was disconnected for whatever reason, * persistent connection immediately tries to reconnect, periodic connects at specific times */ if (client->conn_type == NC_CH_PERIOD) { - if (client->conn.period.anchor_time) { + if (client->anchor_time) { /* anchored */ - reconnect_in = (time(NULL) - client->conn.period.anchor_time) % (client->conn.period.period * 60); + reconnect_in = (time(NULL) - client->anchor_time) % (client->period * 60); } else { /* fixed timeout */ - reconnect_in = client->conn.period.period * 60; + reconnect_in = client->period * 60; } /* UNLOCK */ nc_server_ch_client_unlock(client); - /* sleep until we should reconnect TODO wake up sometimes to check for new notifications */ - VRB(NULL, "Call Home client \"%s\" reconnecting in %" PRIu32 " seconds.", data->client_name, reconnect_in); - sleep(reconnect_in); + /* wait for the timeout to elapse, so we can try to reconnect */ + VRB(session, "Call Home client \"%s\" reconnecting in %" PRIu32 " seconds.", data->client_name, reconnect_in); + if (!nc_server_ch_client_thread_is_running_wait(session, data, reconnect_in)) { + goto cleanup; + } /* LOCK */ client = nc_server_ch_client_with_endpt_lock(data->client_name); - if (!client) { - goto cleanup; - } - if (client->id != client_id) { - nc_server_ch_client_unlock(client); - goto cleanup; - } + assert(client); } /* set next endpoint to try */ @@ -3654,21 +2687,21 @@ nc_ch_client_thread(void *arg) } } else { + /* session was not created, wait a little bit and try again */ + max_wait = client->max_wait; + /* UNLOCK */ nc_server_ch_client_unlock(client); - /* session was not created */ - sleep(NC_CH_ENDPT_BACKOFF_WAIT); + /* wait for max_wait seconds */ + if (!nc_server_ch_client_thread_is_running_wait(session, data, max_wait)) { + /* thread should stop running */ + goto cleanup; + } /* LOCK */ client = nc_server_ch_client_with_endpt_lock(data->client_name); - if (!client) { - goto cleanup; - } - if (client->id != client_id) { - nc_server_ch_client_unlock(client); - goto cleanup; - } + assert(client); ++cur_attempts; @@ -3681,12 +2714,12 @@ nc_ch_client_thread(void *arg) if (next_endpt_index >= client->ch_endpt_count) { /* endpoint was removed, start with the first one */ - VRB(NULL, "Call Home client \"%s\" endpoint \"%s\" removed.", data->client_name, cur_endpt_name); + VRB(session, "Call Home client \"%s\" endpoint \"%s\" removed.", data->client_name, cur_endpt_name); next_endpt_index = 0; cur_attempts = 0; } else if (cur_attempts == client->max_attempts) { /* we have tried to connect to this endpoint enough times */ - VRB(NULL, "Call Home client \"%s\" endpoint \"%s\" failed connection attempt limit %" PRIu8 " reached.", + VRB(session, "Call Home client \"%s\" endpoint \"%s\" failed connection attempt limit %" PRIu8 " reached.", data->client_name, cur_endpt_name, client->max_attempts); /* clear a pending socket, if any */ @@ -3711,9 +2744,11 @@ nc_ch_client_thread(void *arg) free(cur_endpt_name); cur_endpt_name = strdup(cur_endpt->name); } + /* UNLOCK if we break out of the loop */ + nc_server_ch_client_unlock(client); cleanup: - VRB(NULL, "Call Home client \"%s\" thread exit.", data->client_name); + VRB(session, "Call Home client \"%s\" thread exit.", data->client_name); free(cur_endpt_name); free(data->client_name); free(data); @@ -3722,23 +2757,26 @@ nc_ch_client_thread(void *arg) API int nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb, - nc_server_ch_session_release_ctx_cb release_ctx_cb, void *ctx_cb_data, nc_server_ch_new_session_cb new_session_cb) + nc_server_ch_session_release_ctx_cb release_ctx_cb, void *ctx_cb_data, nc_server_ch_new_session_cb new_session_cb, + void *new_session_cb_data) { int ret; pthread_t tid; struct nc_ch_client_thread_arg *arg; + uint16_t i; + struct nc_ch_client *ch_client; - if (!client_name) { - ERRARG("client_name"); - return -1; - } else if (!acquire_ctx_cb) { - ERRARG("acquire_ctx_cb"); - return -1; - } else if (!release_ctx_cb) { - ERRARG("release_ctx_cb"); - return -1; - } else if (!new_session_cb) { - ERRARG("new_session_cb"); + NC_CHECK_ARG_RET(NULL, client_name, acquire_ctx_cb, release_ctx_cb, new_session_cb, -1); + + for (i = 0; i < server_opts.ch_client_count; i++) { + if (!strcmp(server_opts.ch_clients[i].name, client_name)) { + ch_client = &server_opts.ch_clients[i]; + break; + } + } + + if (i == server_opts.ch_client_count) { + ERR(NULL, "Client \"%s\" not found.", client_name); return -1; } @@ -3757,6 +2795,13 @@ nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_acqu arg->release_ctx_cb = release_ctx_cb; arg->ctx_cb_data = ctx_cb_data; arg->new_session_cb = new_session_cb; + arg->new_session_cb_data = new_session_cb_data; + /* thread is now running */ + arg->thread_running = 1; + /* initialize the condition */ + pthread_cond_init(&arg->cond, NULL); + /* initialize the mutex */ + pthread_mutex_init(&arg->cond_lock, NULL); ret = pthread_create(&tid, NULL, nc_ch_client_thread, arg); if (ret) { @@ -3766,19 +2811,21 @@ nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_acqu return -1; } /* the thread now manages arg */ - - pthread_detach(tid); + ch_client->tid = tid; + ch_client->thread_data = arg; return 0; } -#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */ +#endif /* NC_ENABLED_SSH_TLS */ API time_t nc_session_get_start_time(const struct nc_session *session) { - if (!session || (session->side != NC_SERVER)) { - ERRARG("session"); + NC_CHECK_ARG_RET(session, session, 0); + + if (session->side != NC_SERVER) { + ERRARG(session, "session"); return 0; } @@ -3789,7 +2836,7 @@ API void nc_session_inc_notif_status(struct nc_session *session) { if (!session || (session->side != NC_SERVER)) { - ERRARG("session"); + ERRARG(session, "session"); return; } @@ -3806,7 +2853,7 @@ API void nc_session_dec_notif_status(struct nc_session *session) { if (!session || (session->side != NC_SERVER)) { - ERRARG("session"); + ERRARG(session, "session"); return; } @@ -3827,7 +2874,7 @@ nc_session_get_notif_status(const struct nc_session *session) uint32_t ntf_status; if (!session || (session->side != NC_SERVER)) { - ERRARG("session"); + ERRARG(session, "session"); return 0; } diff --git a/src/session_server.h b/src/session_server.h index 612bb929..660badab 100644 --- a/src/session_server.h +++ b/src/session_server.h @@ -114,7 +114,8 @@ struct nc_server_reply *nc_clb_default_close_session(struct lyd_node *rpc, struc /** @} Server Session */ /** - * @addtogroup server + * @defgroup server_functions Server Functions + * @ingroup server * @{ */ @@ -133,6 +134,23 @@ int nc_server_init(void); */ void nc_server_destroy(void); +/** + * @brief Initialize a context which can serve as a default server context. + * + * Loads the default modules ietf-netconf and ietf-netconf-monitoring and their enabled features - ietf-netconf + * enabled features are : writable-running, candidate, rollback-on-error, validate, startup, url, xpath, confirmed-commit and + * ietf-netconf-monitoring has no features. + * + * If ctx is : + * - NULL: a new context will be created and if the call is successful you have to free it, + * - non NULL: context will be searched for the two modules and their features + * and if anything is missing, it will be implemented. + * + * @param[in,out] ctx Optional context in which the modules will be loaded. Created if ctx is null. + * @return 0 on success, -1 on error. + */ +int nc_server_init_ctx(struct ly_ctx **ctx); + /** * @brief Set the with-defaults capability extra parameters. * @@ -154,8 +172,8 @@ int nc_server_set_capab_withdefaults(NC_WD_MODE basic_mode, int also_supported); * * At least one argument must be non-NULL. * - * @param[in,out] basic_mode basic-mode parameter. - * @param[in,out] also_supported also-supported parameter. + * @param[out] basic_mode basic-mode parameter. + * @param[out] also_supported also-supported parameter. */ void nc_server_get_capab_withdefaults(NC_WD_MODE *basic_mode, int *also_supported); @@ -195,22 +213,6 @@ void nc_server_set_hello_timeout(uint16_t hello_timeout); */ uint16_t nc_server_get_hello_timeout(void); -/** - * @brief Set server timeout for dropping an idle session. - * - * @param[in] idle_timeout Idle session timeout. 0 to never drop a session - * because of inactivity. - */ -void nc_server_set_idle_timeout(uint16_t idle_timeout); - -/** - * @brief Get server timeout for dropping an idle session. - * - * @return Idle session timeout, 0 for for never dropping - * a session because of inactivity. - */ -uint16_t nc_server_get_idle_timeout(void); - /** * @brief Get all the server capabilities including all the schemas. * @@ -235,7 +237,7 @@ char **nc_server_get_cpblts(const struct ly_ctx *ctx); */ char **nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version); -/** @} Server */ +/** @} Server Functions */ /** * @addtogroup server_session @@ -377,33 +379,10 @@ void nc_ps_clear(struct nc_pollsession *ps, int all, void (*data_free)(void *)); /** @} Server Session */ /** - * @addtogroup server + * @addtogroup server_functions * @{ */ -/** - * @brief Add a new endpoint. - * - * Before the endpoint can accept any connections, its address and port must - * be set via nc_server_endpt_set_address() and nc_server_endpt_set_port(). - * - * @param[in] name Arbitrary unique endpoint name. - * @param[in] ti Transport protocol to use. - * @return 0 on success, -1 on error. - */ -int nc_server_add_endpt(const char *name, NC_TRANSPORT_IMPL ti); - -/** - * @brief Stop listening on and remove an endpoint. - * - * @param[in] name Endpoint name. NULL matches all endpoints. - * @param[in] ti Endpoint transport protocol. NULL matches any protocol. - * Redundant to set if @p name is set, endpoint names are - * unique disregarding their protocol. - * @return 0 on success, -1 on not finding any match. - */ -int nc_server_del_endpt(const char *name, NC_TRANSPORT_IMPL ti); - /** * @brief Get the number of currently configured listening endpoints. * Note that an ednpoint without address and/or port will be included @@ -421,68 +400,7 @@ int nc_server_endpt_count(void); */ int nc_server_is_endpt(const char *name); -/** - * @brief Change endpoint listening address. - * - * On error the previous listening socket (if any) is left untouched. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] address New listening address. - * @return 0 on success, -1 on error. - */ -int nc_server_endpt_set_address(const char *endpt_name, const char *address); - -#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS) - -/** - * @brief Change endpoint listening port. - * - * This is only valid on SSH/TLS transport endpoint. - * On error the previous listening socket (if any) is left untouched. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] port New listening port. - * @return 0 on success, -1 on error. - */ -int nc_server_endpt_set_port(const char *endpt_name, uint16_t port); - -#endif - -/** - * @brief Change endpoint permissions. - * - * This is only valid on UNIX transport endpoint. - * On error the previous listening socket (if any) is left untouched. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] mode New mode, -1 to use default. - * @param[in] uid New uid, -1 to use default. - * @param[in] gid New gid, -1 to use default. - * @return 0 on success, -1 on error. - */ -int nc_server_endpt_set_perms(const char *endpt_name, mode_t mode, uid_t uid, gid_t gid); - -/** - * @brief Change endpoint keepalives state. Affects only new connections. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] enable Whether to enable or disable keepalives. - * @return 0 on success, -1 on error. - */ -int nc_server_endpt_enable_keepalives(const char *endpt_name, int enable); - -/** - * @brief Change endpoint keepalives parameters. Affects only new connections. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] idle_time Keepalive idle time in seconds, 1 by default, -1 to keep previous value. - * @param[in] max_probes Keepalive max probes sent, 10 by default, -1 to keep previous value. - * @param[in] probe_interval Keepalive probe interval in seconds, 5 by default, -1 to keep previous value. - * @return 0 on success, -1 on error. - */ -int nc_server_endpt_set_keepalives(const char *endpt_name, int idle_time, int max_probes, int probe_interval); - -/** @} Server */ +/** @} */ /** * @addtogroup server_session @@ -497,7 +415,8 @@ int nc_server_endpt_set_keepalives(const char *endpt_name, int idle_time, int ma * for much longer that @p timeout, but only with slow/faulty/malicious clients. * * Server capabilities are generated based on the content of @p ctx. The context must - * not be destroyed before the accepted NETCONF session is freed. + * not be destroyed before the accepted NETCONF session is freed. Basic usable context may + * be created by calling ::nc_server_init_ctx(). * * Supported RPCs of models in the context are expected to have their callback * in the corresponding RPC schema node set to a nc_rpc_clb function callback using ::nc_set_rpc_callback(). @@ -549,39 +468,6 @@ NC_MSG_TYPE nc_ps_accept_ssh_channel(struct nc_pollsession *ps, struct nc_sessio * @{ */ -/** - * @brief Add an authorized client SSH public key. This public key can be used for - * publickey authentication (for any SSH connection, even Call Home) afterwards. - * - * @param[in] pubkey_base64 Authorized public key binary content encoded in base64. - * @param[in] type Authorized public key SSH type. - * @param[in] username Username that the client with the public key must use. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_add_authkey(const char *pubkey_base64, NC_SSH_KEY_TYPE type, const char *username); - -/** - * @brief Add an authorized client SSH public key. This public key can be used for - * publickey authentication (for any SSH connection, even Call Home) afterwards. - * - * @param[in] pubkey_path Path to the public key. - * @param[in] username Username that the client with the public key must use. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_add_authkey_path(const char *pubkey_path, const char *username); - -/** - * @brief Remove an authorized client SSH public key. - * - * @param[in] pubkey_path Path to an authorized public key. NULL matches all the keys. - * @param[in] pubkey_base64 Authorized public key content. NULL matches any key. - * @param[in] type Authorized public key type. 0 matches all types. - * @param[in] username Username for an authorized public key. NULL matches all the usernames. - * @return 0 on success, -1 on not finding any match. - */ -int nc_server_ssh_del_authkey(const char *pubkey_path, const char *pubkey_base64, NC_SSH_KEY_TYPE type, - const char *username); - /** * @brief Set the callback for SSH password authentication. If none is set, local system users are used. * @@ -594,35 +480,15 @@ void nc_server_ssh_set_passwd_auth_clb(int (*passwd_auth_clb)(const struct nc_se void *user_data), void *user_data, void (*free_user_data)(void *user_data)); /** - * @brief Set the callback for SSH interactive authentication. If none is set, local PAM-based authentication is used. + * @brief Set the callback for SSH interactive authentication. If not set, local PAM-based authentication is used. * - * @param[in] interactive_auth_sess_clb Callback that should authenticate the user. + * @param[in] interactive_auth_clb Callback that should authenticate the user. * Zero return indicates success, non-zero an error. - * @param[in] user_data Optional arbitrary user data that will be passed to @p interactive_auth_sess_clb. + * @param[in] user_data Optional arbitrary user data that will be passed to @p interactive_auth_clb. * @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data. */ -void nc_server_ssh_set_interactive_auth_sess_clb(int (*interactive_auth_sess_clb)(const struct nc_session *session, - ssh_session ssh_sess, ssh_message msg, void *user_data), void *user_data, void (*free_user_data)(void *user_data)); - -/** - * @brief Deprecated, use ::nc_server_ssh_set_interactive_auth_sess_clb() instead. - */ void nc_server_ssh_set_interactive_auth_clb(int (*interactive_auth_clb)(const struct nc_session *session, - const ssh_message msg, void *user_data), void *user_data, void (*free_user_data)(void *user_data)); - -/** - * @brief Set the name and a path to a PAM configuration file. - * - * @p conf_name has to be set via this function prior to using PAM keyboard-interactive authentication method. - * - * @param[in] conf_name Name of the configuration file. - * @param[in] conf_dir Optional. The absolute path to the directory in which the configuration file - * with the name @p conf_name is located. A newer version (>= 1.4) of PAM library is required to be - * able to specify the path. If NULL is passed, - * then the PAM's system directories will be searched (usually /etc/pam.d/). - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_set_pam_conf_path(const char *conf_name, const char *conf_dir); + ssh_session ssh_sess, ssh_message msg, void *user_data), void *user_data, void (*free_user_data)(void *user_data)); /** * @brief Set the callback for SSH public key authentication. If none is set, local system users are used. @@ -635,101 +501,6 @@ int nc_server_ssh_set_pam_conf_path(const char *conf_name, const char *conf_dir) void nc_server_ssh_set_pubkey_auth_clb(int (*pubkey_auth_clb)(const struct nc_session *session, ssh_key key, void *user_data), void *user_data, void (*free_user_data)(void *user_data)); -/** - * @brief Set the callback for retrieving host keys. Any RSA, DSA, and ECDSA keys can be added. However, - * a maximum of one key of each type will be used during SSH authentication, later keys replacing - * the earlier ones. - * - * @param[in] hostkey_clb Callback that should return the key itself. Zero return indicates success, non-zero - * an error. On success exactly ONE of @p privkey_path or @p privkey_data is expected - * to be set. The one set will be freed. - * - @p privkey_path expects a PEM file, - * - @p privkey_data expects a base-64 encoded ANS.1 DER data, - * - @p privkey_type type of the key in @p privkey_data. Use ::NC_SSH_KEY_UNKNOWN for - * PKCS#8 key that includes the information about the key in its data. - * @param[in] user_data Optional arbitrary user data that will be passed to @p hostkey_clb. - * @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data. - */ -void nc_server_ssh_set_hostkey_clb(int (*hostkey_clb)(const char *name, void *user_data, char **privkey_path, - char **privkey_data, NC_SSH_KEY_TYPE *privkey_type), void *user_data, void (*free_user_data)(void *user_data)); - -/** - * @brief Add endpoint SSH host keys the server will identify itself with. Only the name is set, the key itself - * wil be retrieved using a callback. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] name Arbitrary name of the host key. - * @param[in] idx Optional index where to add the key. -1 adds at the end. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_endpt_add_hostkey(const char *endpt_name, const char *name, int16_t idx); - -/** - * @brief Delete endpoint SSH host key. Their order is preserved. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] name Name of the host key. NULL matches all the keys, but if @p idx != -1 then this must be NULL. - * @param[in] idx Index of the hostkey. -1 matches all indices, but if @p name != NULL then this must be -1. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_endpt_del_hostkey(const char *endpt_name, const char *name, int16_t idx); - -/** - * @brief Move endpoint SSH host key. - * - * @param[in] endpt_name Exisitng endpoint name. - * @param[in] key_mov Name of the host key that will be moved. - * @param[in] key_after Name of the key that will preceed @p key_mov. NULL if @p key_mov is to be moved at the beginning. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_endpt_mov_hostkey(const char *endpt_name, const char *key_mov, const char *key_after); - -/** - * @brief Modify endpoint SSH host key. - * - * @param[in] endpt_name Exisitng endpoint name. - * @param[in] name Name of an existing host key. - * @param[in] new_name New name of the host key @p name. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_endpt_mod_hostkey(const char *endpt_name, const char *name, const char *new_name); - -/** - * @brief Set endpoint accepted SSH authentication methods. All (publickey, password, interactive) - * are supported by default. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] auth_methods Accepted authentication methods bit field of NC_SSH_AUTH_TYPE. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_endpt_set_auth_methods(const char *endpt_name, int auth_methods); - -/** - * @brief Get endpoint accepted SSH authentication methods. - * - * @param[in] endpt_name Existing endpoint name. - * @return Accepted authentication methods bit field of NC_SSH_AUTH_TYPE. - */ -int nc_server_ssh_endpt_get_auth_methods(const char *endpt_name); - -/** - * @brief Set endpoint SSH authentication attempts of every client. 3 by default. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] auth_attempts Failed authentication attempts before a client is dropped. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_endpt_set_auth_attempts(const char *endpt_name, uint16_t auth_attempts); - -/** - * @brief Set endpoint SSH authentication timeout. 30 seconds by default. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] auth_timeout Number of seconds before an unauthenticated client is dropped. - * @return 0 on success, -1 on error. - */ -int nc_server_ssh_endpt_set_auth_timeout(const char *endpt_name, uint16_t auth_timeout); - /** @} Server SSH */ /** @@ -740,148 +511,6 @@ int nc_server_ssh_endpt_set_auth_timeout(const char *endpt_name, uint16_t auth_t * @{ */ -/** - * @brief Set the server TLS certificate. Only the name is set, the certificate itself - * wil be retrieved using a callback. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] name Arbitrary certificate name. - * @return 0 on success, -1 on error. - */ -int nc_server_tls_endpt_set_server_cert(const char *endpt_name, const char *name); - -/** - * @brief Set the callback for retrieving server certificate and matching private key. - * - * @param[in] cert_clb Callback that should return the certificate and the key itself. Zero return indicates success, - * non-zero an error. On success exactly ONE of @p cert_path or @p cert_data and ONE of - * @p privkey_path and @p privkey_data is expected to be set. Those set will be freed. - * - @p cert_path expects a PEM file, - * - @p cert_data expects a base-64 encoded ASN.1 DER data, - * - @p privkey_path expects a PEM file, - * - @p privkey_data expects a base-64 encoded ANS.1 DER data, - * - @p privkey_type type of the key in @p privkey_data. - * @param[in] user_data Optional arbitrary user data that will be passed to @p cert_clb. - * @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data. - */ -void nc_server_tls_set_server_cert_clb(int (*cert_clb)(const char *name, void *user_data, char **cert_path, char **cert_data, - char **privkey_path, char **privkey_data, NC_SSH_KEY_TYPE *privkey_type), void *user_data, - void (*free_user_data)(void *user_data)); - -/** - * @brief Set the callback for retrieving server certificate chain - * - * @param[in] cert_chain_clb Callback that should return all the certificates of the chain. Zero return indicates success, - * non-zero an error. On success, @p cert_paths and @p cert_data are expected to be set or left - * NULL. Both will be (deeply) freed. - * - @p cert_paths expect an array of PEM files, - * - @p cert_path_count number of @p cert_paths array members, - * - @p cert_data expect an array of base-64 encoded ASN.1 DER cert data, - * - @p cert_data_count number of @p cert_data array members. - * @param[in] user_data Optional arbitrary user data that will be passed to @p cert_clb. - * @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data. - */ -void nc_server_tls_set_server_cert_chain_clb(int (*cert_chain_clb)(const char *name, void *user_data, char ***cert_paths, - int *cert_path_count, char ***cert_data, int *cert_data_count), void *user_data, void (*free_user_data)(void *user_data)); - -/** - * @brief Add a trusted certificate list. Can be both a CA or a client one. Can be - * safely used together with nc_server_tls_endpt_set_trusted_ca_paths(). - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] name Arbitary name identifying this certificate list. - * @return 0 on success, -1 on error. - */ -int nc_server_tls_endpt_add_trusted_cert_list(const char *endpt_name, const char *name); - -/** - * @brief Set the callback for retrieving trusted certificates. - * - * @param[in] cert_list_clb Callback that should return all the certificates of a list. Zero return indicates success, - * non-zero an error. On success, @p cert_paths and @p cert_data are expected to be set or left - * NULL. Both will be (deeply) freed. - * - @p cert_paths expect an array of PEM files, - * - @p cert_path_count number of @p cert_paths array members, - * - @p cert_data expect an array of base-64 encoded ASN.1 DER cert data, - * - @p cert_data_count number of @p cert_data array members. - * @param[in] user_data Optional arbitrary user data that will be passed to @p cert_clb. - * @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data. - */ -void nc_server_tls_set_trusted_cert_list_clb(int (*cert_list_clb)(const char *name, void *user_data, char ***cert_paths, - int *cert_path_count, char ***cert_data, int *cert_data_count), void *user_data, void (*free_user_data)(void *user_data)); - -/** - * @brief Remove a trusted certificate. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] name Name of the certificate list to delete. NULL deletes all the lists. - * @return 0 on success, -1 on not found. - */ -int nc_server_tls_endpt_del_trusted_cert_list(const char *endpt_name, const char *name); - -/** - * @brief Set trusted Certificate Authority certificate locations. There can only be - * one file and one directory, they are replaced if already set. Can be safely - * used with nc_server_tls_endpt_add_trusted_cert() or its _path variant. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] ca_file Path to a trusted CA cert store file in PEM format. Can be NULL. - * @param[in] ca_dir Path to a trusted CA cert store hashed directory (c_rehash utility - * can be used to create hashes) with PEM files. Can be NULL. - * @return 0 on success, -1 on error. - */ -int nc_server_tls_endpt_set_trusted_ca_paths(const char *endpt_name, const char *ca_file, const char *ca_dir); - -/** - * @brief Set Certificate Revocation List locations. There can only be one file - * and one directory, they are replaced if already set. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] crl_file Path to a CRL store file in PEM format. Can be NULL. - * @param[in] crl_dir Path to a CRL store hashed directory (c_rehash utility - * can be used to create hashes) with PEM files. Can be NULL. - * @return 0 on success, -1 on error. - */ -int nc_server_tls_endpt_set_crl_paths(const char *endpt_name, const char *crl_file, const char *crl_dir); - -/** - * @brief Destroy and clean CRLs. Certificates, private keys, and CTN entries are - * not affected. - * - * @param[in] endpt_name Existing endpoint name. - */ -void nc_server_tls_endpt_clear_crls(const char *endpt_name); - -/** - * @brief Add a cert-to-name entry. - * - * It is possible to add an entry step-by-step, specifying first only @p ip and in later calls - * @p fingerprint, @p map_type, and optionally @p name spearately. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] id Priority of the entry. It must be unique. If already exists, the entry with this id - * is modified. - * @param[in] fingerprint Matching certificate fingerprint. If NULL, kept temporarily unset. - * @param[in] map_type Type of username-certificate mapping. If 0, kept temporarily unset. - * @param[in] name Specific username used only if @p map_type == NC_TLS_CTN_SPECIFED. - * @return 0 on success, -1 on error. - */ -int nc_server_tls_endpt_add_ctn(const char *endpt_name, uint32_t id, const char *fingerprint, - NC_TLS_CTN_MAPTYPE map_type, const char *name); - -/** - * @brief Remove a cert-to-name entry. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in] id Priority of the entry. -1 matches all the priorities. - * @param[in] fingerprint Fingerprint fo the entry. NULL matches all the fingerprints. - * @param[in] map_type Mapping type of the entry. 0 matches all the mapping types. - * @param[in] name Specific username for the entry. NULL matches all the usernames. - * @return 0 on success, -1 on not finding any match. - */ -int nc_server_tls_endpt_del_ctn(const char *endpt_name, int64_t id, const char *fingerprint, - NC_TLS_CTN_MAPTYPE map_type, const char *name); - /** * @brief Get a cert-to-name entry. * diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index 0b7aad85..a65e77dc 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -15,7 +15,7 @@ #define _GNU_SOURCE -#include "config.h" /* Expose HAVE_SHADOW and HAVE_CRYPT */ +#include "config.h" /* Expose HAVE_SHADOW, HAVE_CRYPT and HAVE_LIBPAM */ #ifdef HAVE_SHADOW #include @@ -27,9 +27,17 @@ #include #endif +#include +#include #include -#include +#include +#include +#include +#include +#include +#include #include +#include #include #include #include @@ -38,9 +46,9 @@ #include #include "compat.h" -#include "libnetconf.h" -#include "session_server.h" -#include "session_server_ch.h" +#include "log_p.h" +#include "session.h" +#include "session_p.h" #if !defined (HAVE_CRYPT_R) pthread_mutex_t crypt_lock = PTHREAD_MUTEX_INITIALIZER; @@ -49,16 +57,15 @@ pthread_mutex_t crypt_lock = PTHREAD_MUTEX_INITIALIZER; extern struct nc_server_opts server_opts; static char * -base64der_key_to_tmp_file(const char *in, const char *key_str) +base64der_privkey_to_tmp_file(const char *in, const char *privkey_format) { char path[12] = "/tmp/XXXXXX"; int fd, written; + unsigned len; mode_t umode; FILE *file; - if (in == NULL) { - return NULL; - } + NC_CHECK_ARG_RET(NULL, in, NULL); umode = umask(0177); fd = mkstemp(path); @@ -73,858 +80,137 @@ base64der_key_to_tmp_file(const char *in, const char *key_str) return NULL; } - /* write the key into the file */ - if (key_str) { - written = fwrite("-----BEGIN ", 1, 11, file); - written += fwrite(key_str, 1, strlen(key_str), file); + /* write header */ + written = fwrite("-----BEGIN ", 1, 11, file); + if (privkey_format) { + written += fwrite(privkey_format, 1, strlen(privkey_format), file); written += fwrite(" PRIVATE KEY-----\n", 1, 18, file); - written += fwrite(in, 1, strlen(in), file); - written += fwrite("\n-----END ", 1, 10, file); - written += fwrite(key_str, 1, strlen(key_str), file); - written += fwrite(" PRIVATE KEY-----", 1, 17, file); - - fclose(file); - if ((unsigned)written != 11 + strlen(key_str) + 18 + strlen(in) + 10 + strlen(key_str) + 17) { - unlink(path); - return NULL; - } } else { - written = fwrite("-----BEGIN PRIVATE KEY-----\n", 1, 28, file); - written += fwrite(in, 1, strlen(in), file); - written += fwrite("\n-----END PRIVATE KEY-----", 1, 26, file); - - fclose(file); - if ((unsigned)written != 28 + strlen(in) + 26) { - unlink(path); - return NULL; - } - } - - return strdup(path); -} - -static int -nc_server_ssh_add_hostkey(const char *name, int16_t idx, struct nc_server_ssh_opts *opts) -{ - uint8_t i; - - if (!name) { - ERRARG("name"); - return -1; - } else if (idx > opts->hostkey_count) { - ERRARG("idx"); - return -1; - } - - for (i = 0; i < opts->hostkey_count; ++i) { - if (!strcmp(opts->hostkeys[i], name)) { - ERRARG("name"); - return -1; - } - } - - ++opts->hostkey_count; - opts->hostkeys = nc_realloc(opts->hostkeys, opts->hostkey_count * sizeof *opts->hostkeys); - if (!opts->hostkeys) { - ERRMEM; - return -1; - } - - if (idx < 0) { - idx = opts->hostkey_count - 1; - } - if (idx != opts->hostkey_count - 1) { - memmove(opts->hostkeys + idx + 1, opts->hostkeys + idx, opts->hostkey_count - idx); - } - opts->hostkeys[idx] = strdup(name); - - return 0; -} - -API int -nc_server_ssh_endpt_add_hostkey(const char *endpt_name, const char *name, int16_t idx) -{ - int ret; - struct nc_endpt *endpt; - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_LIBSSH, NULL); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_add_hostkey(name, idx, endpt->opts.ssh); - - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - return ret; -} - -API void -nc_server_ssh_set_passwd_auth_clb(int (*passwd_auth_clb)(const struct nc_session *session, const char *password, void *user_data), - void *user_data, void (*free_user_data)(void *user_data)) -{ - server_opts.passwd_auth_clb = passwd_auth_clb; - server_opts.passwd_auth_data = user_data; - server_opts.passwd_auth_data_free = free_user_data; -} - -API void -nc_server_ssh_set_interactive_auth_sess_clb(int (*interactive_auth_sess_clb)(const struct nc_session *session, - ssh_session ssh_sess, ssh_message msg, void *user_data), void *user_data, void (*free_user_data)(void *user_data)) -{ - server_opts.interactive_auth_sess_clb = interactive_auth_sess_clb; - server_opts.interactive_auth_sess_data = user_data; - server_opts.interactive_auth_sess_data_free = free_user_data; -} - -API void -nc_server_ssh_set_interactive_auth_clb(int (*interactive_auth_clb)(const struct nc_session *session, ssh_message msg, void *user_data), - void *user_data, void (*free_user_data)(void *user_data)) -{ - server_opts.interactive_auth_clb = interactive_auth_clb; - server_opts.interactive_auth_data = user_data; - server_opts.interactive_auth_data_free = free_user_data; -} - -API int -nc_server_ssh_set_pam_conf_path(const char *conf_name, const char *conf_dir) -{ -#ifdef HAVE_LIBPAM - free(server_opts.conf_name); - free(server_opts.conf_dir); - server_opts.conf_name = NULL; - server_opts.conf_dir = NULL; - - if (conf_dir) { -# ifdef LIBPAM_HAVE_CONFDIR - server_opts.conf_dir = strdup(conf_dir); - if (!(server_opts.conf_dir)) { - ERRMEM; - return -1; - } -# else - ERR(NULL, "Failed to set PAM config directory because of old version of PAM. " - "Put the config file in the system directory (usually /etc/pam.d/)."); - return -1; -# endif - } - - if (conf_name) { - server_opts.conf_name = strdup(conf_name); - if (!(server_opts.conf_name)) { - ERRMEM; - return -1; - } - } - - return 0; -#else - (void)conf_name; - (void)conf_dir; - - ERR(NULL, "PAM-based SSH authentication is not supported."); - return -1; -#endif -} - -API void -nc_server_ssh_set_pubkey_auth_clb(int (*pubkey_auth_clb)(const struct nc_session *session, ssh_key key, void *user_data), - void *user_data, void (*free_user_data)(void *user_data)) -{ - server_opts.pubkey_auth_clb = pubkey_auth_clb; - server_opts.pubkey_auth_data = user_data; - server_opts.pubkey_auth_data_free = free_user_data; -} - -API int -nc_server_ssh_ch_client_endpt_add_hostkey(const char *client_name, const char *endpt_name, const char *name, int16_t idx) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_LIBSSH, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_add_hostkey(name, idx, endpt->opts.ssh); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -API void -nc_server_ssh_set_hostkey_clb(int (*hostkey_clb)(const char *name, void *user_data, char **privkey_path, - char **privkey_data, NC_SSH_KEY_TYPE *privkey_type), void *user_data, void (*free_user_data)(void *user_data)) -{ - if (!hostkey_clb) { - ERRARG("hostkey_clb"); - return; - } - - server_opts.hostkey_clb = hostkey_clb; - server_opts.hostkey_data = user_data; - server_opts.hostkey_data_free = free_user_data; -} - -static int -nc_server_ssh_del_hostkey(const char *name, int16_t idx, struct nc_server_ssh_opts *opts) -{ - uint8_t i; - - if (name && (idx > -1)) { - ERRARG("name and idx"); - return -1; - } else if (idx >= opts->hostkey_count) { - ERRARG("idx"); + written += fwrite("PRIVATE KEY-----\n", 1, 17, file); } - if (!name && (idx < 0)) { - for (i = 0; i < opts->hostkey_count; ++i) { - free(opts->hostkeys[i]); - } - free(opts->hostkeys); - opts->hostkeys = NULL; - opts->hostkey_count = 0; - } else if (name) { - for (i = 0; i < opts->hostkey_count; ++i) { - if (!strcmp(opts->hostkeys[i], name)) { - idx = i; - goto remove_idx; - } - } + /* write data */ + written += fwrite(in, 1, strlen(in), file); - ERRARG("name"); - return -1; + /* write footer */ + written += fwrite("\n-----END ", 1, 10, file); + if (privkey_format) { + written += fwrite(privkey_format, 1, strlen(privkey_format), file); + written += fwrite(" PRIVATE KEY-----", 1, 17, file); } else { -remove_idx: - --opts->hostkey_count; - free(opts->hostkeys[idx]); - if (idx < opts->hostkey_count - 1) { - memmove(opts->hostkeys + idx, opts->hostkeys + idx + 1, (opts->hostkey_count - idx) * sizeof *opts->hostkeys); - } - if (!opts->hostkey_count) { - free(opts->hostkeys); - opts->hostkeys = NULL; - } - } - - return 0; -} - -API int -nc_server_ssh_endpt_del_hostkey(const char *endpt_name, const char *name, int16_t idx) -{ - int ret; - struct nc_endpt *endpt; - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_LIBSSH, NULL); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_del_hostkey(name, idx, endpt->opts.ssh); - - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - return ret; -} - -API int -nc_server_ssh_ch_client_endpt_del_hostkey(const char *client_name, const char *endpt_name, const char *name, int16_t idx) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_LIBSSH, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_del_hostkey(name, idx, endpt->opts.ssh); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -static int -nc_server_ssh_mov_hostkey(const char *key_mov, const char *key_after, struct nc_server_ssh_opts *opts) -{ - uint8_t i; - int16_t mov_idx = -1, after_idx = -1; - char *bckup; - - if (!key_mov) { - ERRARG("key_mov"); - return -1; - } - - for (i = 0; i < opts->hostkey_count; ++i) { - if (key_after && (after_idx == -1) && !strcmp(opts->hostkeys[i], key_after)) { - after_idx = i; - } - if ((mov_idx == -1) && !strcmp(opts->hostkeys[i], key_mov)) { - mov_idx = i; - } - - if ((!key_after || (after_idx > -1)) && (mov_idx > -1)) { - break; - } + written += fwrite("PRIVATE KEY-----", 1, 16, file); } - if (key_after && (after_idx == -1)) { - ERRARG("key_after"); - return -1; - } - if (mov_idx == -1) { - ERRARG("key_mov"); - return -1; - } - if ((mov_idx == after_idx) || (mov_idx == after_idx + 1)) { - /* nothing to do */ - return 0; - } + fclose(file); - /* finally move the key */ - bckup = opts->hostkeys[mov_idx]; - if (mov_idx > after_idx) { - memmove(opts->hostkeys + after_idx + 2, opts->hostkeys + after_idx + 1, - ((mov_idx - after_idx) - 1) * sizeof *opts->hostkeys); - opts->hostkeys[after_idx + 1] = bckup; + /* checksum */ + if (privkey_format) { + len = 11 + strlen(privkey_format) + 18 + strlen(in) + 10 + strlen(privkey_format) + 17; } else { - memmove(opts->hostkeys + mov_idx, opts->hostkeys + mov_idx + 1, (after_idx - mov_idx) * sizeof *opts->hostkeys); - opts->hostkeys[after_idx] = bckup; - } - - return 0; -} - -API int -nc_server_ssh_endpt_mov_hostkey(const char *endpt_name, const char *key_mov, const char *key_after) -{ - int ret; - struct nc_endpt *endpt; - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_LIBSSH, NULL); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_mov_hostkey(key_mov, key_after, endpt->opts.ssh); - - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - return ret; -} - -API int -nc_server_ssh_ch_client_endpt_mov_hostkey(const char *client_name, const char *endpt_name, const char *key_mov, - const char *key_after) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_LIBSSH, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_mov_hostkey(key_mov, key_after, endpt->opts.ssh); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -static int -nc_server_ssh_set_auth_methods(int auth_methods, struct nc_server_ssh_opts *opts) -{ - if ((auth_methods & NC_SSH_AUTH_INTERACTIVE) && !server_opts.conf_name && !server_opts.interactive_auth_clb && - !server_opts.interactive_auth_sess_clb) { - /* path to a configuration file not set */ - ERR(NULL, "To use Keyboard-Interactive authentication method, set the PAM configuration file or a callback."); - return 1; - } - opts->auth_methods = auth_methods; - return 0; -} - -API int -nc_server_ssh_endpt_set_auth_methods(const char *endpt_name, int auth_methods) -{ - int ret; - struct nc_endpt *endpt; - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_LIBSSH, NULL); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_set_auth_methods(auth_methods, endpt->opts.ssh); - - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - return ret; -} - -API int -nc_server_ssh_ch_client_endpt_set_auth_methods(const char *client_name, const char *endpt_name, int auth_methods) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_LIBSSH, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_set_auth_methods(auth_methods, endpt->opts.ssh); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -API int -nc_server_ssh_endpt_get_auth_methods(const char *endpt_name) -{ - int ret; - struct nc_endpt *endpt; - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_LIBSSH, NULL); - if (!endpt) { - return -1; - } - - ret = endpt->opts.ssh->auth_methods; - - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - return ret; -} - -API int -nc_server_ssh_ch_client_endpt_get_auth_methods(const char *client_name, const char *endpt_name) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_LIBSSH, &client); - if (!endpt) { - return -1; - } - - ret = endpt->opts.ssh->auth_methods; - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -static int -nc_server_ssh_set_auth_attempts(uint16_t auth_attempts, struct nc_server_ssh_opts *opts) -{ - NC_CHECK_ARG_RET(NULL, auth_attempts, -1); - - opts->auth_attempts = auth_attempts; - return 0; -} - -API int -nc_server_ssh_endpt_set_auth_attempts(const char *endpt_name, uint16_t auth_attempts) -{ - int ret; - struct nc_endpt *endpt; - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_LIBSSH, NULL); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_set_auth_attempts(auth_attempts, endpt->opts.ssh); - - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - return ret; -} - -API int -nc_server_ssh_ch_client_endpt_set_auth_attempts(const char *client_name, const char *endpt_name, uint16_t auth_attempts) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_LIBSSH, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_set_auth_attempts(auth_attempts, endpt->opts.ssh); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -static int -nc_server_ssh_set_auth_timeout(uint16_t auth_timeout, struct nc_server_ssh_opts *opts) -{ - NC_CHECK_ARG_RET(NULL, auth_timeout, -1); - - opts->auth_timeout = auth_timeout; - return 0; -} - -API int -nc_server_ssh_endpt_set_auth_timeout(const char *endpt_name, uint16_t auth_timeout) -{ - int ret; - struct nc_endpt *endpt; - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_LIBSSH, NULL); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_set_auth_timeout(auth_timeout, endpt->opts.ssh); - - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.endpt_lock); - - return ret; -} - -API int -nc_server_ssh_ch_client_endpt_set_auth_timeout(const char *client_name, const char *endpt_name, uint16_t auth_timeout) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_LIBSSH, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_ssh_set_auth_timeout(auth_timeout, endpt->opts.ssh); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - -static int -_nc_server_ssh_add_authkey(const char *pubkey_path, const char *pubkey_base64, NC_SSH_KEY_TYPE type, const char *username) -{ - int ret = 0; - - /* LOCK */ - pthread_mutex_lock(&server_opts.authkey_lock); - - ++server_opts.authkey_count; - server_opts.authkeys = nc_realloc(server_opts.authkeys, server_opts.authkey_count * sizeof *server_opts.authkeys); - if (!server_opts.authkeys) { - ERRMEM; - ret = -1; - goto cleanup; - } - server_opts.authkeys[server_opts.authkey_count - 1].path = pubkey_path ? strdup(pubkey_path) : NULL; - server_opts.authkeys[server_opts.authkey_count - 1].base64 = pubkey_base64 ? strdup(pubkey_base64) : NULL; - server_opts.authkeys[server_opts.authkey_count - 1].type = type; - server_opts.authkeys[server_opts.authkey_count - 1].username = strdup(username); - -cleanup: - /* UNLOCK */ - pthread_mutex_unlock(&server_opts.authkey_lock); - return ret; -} - -API int -nc_server_ssh_add_authkey_path(const char *pubkey_path, const char *username) -{ - if (!pubkey_path) { - ERRARG("pubkey_path"); - return -1; - } else if (!username) { - ERRARG("username"); - return -1; - } - - return _nc_server_ssh_add_authkey(pubkey_path, NULL, 0, username); -} - -API int -nc_server_ssh_add_authkey(const char *pubkey_base64, NC_SSH_KEY_TYPE type, const char *username) -{ - if (!pubkey_base64) { - ERRARG("pubkey_base64"); - return -1; - } else if (!type) { - ERRARG("type"); - return -1; - } else if (!username) { - ERRARG("username"); - return -1; - } - - return _nc_server_ssh_add_authkey(NULL, pubkey_base64, type, username); -} - -API int -nc_server_ssh_del_authkey(const char *pubkey_path, const char *pubkey_base64, NC_SSH_KEY_TYPE type, - const char *username) -{ - uint32_t i; - int ret = -1; - - /* LOCK */ - pthread_mutex_lock(&server_opts.authkey_lock); - - if (!pubkey_path && !pubkey_base64 && !type && !username) { - for (i = 0; i < server_opts.authkey_count; ++i) { - free(server_opts.authkeys[i].path); - free(server_opts.authkeys[i].base64); - free(server_opts.authkeys[i].username); - - ret = 0; - } - free(server_opts.authkeys); - server_opts.authkeys = NULL; - server_opts.authkey_count = 0; - } else { - for (i = 0; i < server_opts.authkey_count; ++i) { - if ((!pubkey_path || !strcmp(server_opts.authkeys[i].path, pubkey_path)) && - (!pubkey_base64 || !strcmp(server_opts.authkeys[i].base64, pubkey_base64)) && - (!type || (server_opts.authkeys[i].type == type)) && - (!username || !strcmp(server_opts.authkeys[i].username, username))) { - free(server_opts.authkeys[i].path); - free(server_opts.authkeys[i].base64); - free(server_opts.authkeys[i].username); - - --server_opts.authkey_count; - if (i < server_opts.authkey_count) { - memcpy(&server_opts.authkeys[i], &server_opts.authkeys[server_opts.authkey_count], - sizeof *server_opts.authkeys); - } else if (!server_opts.authkey_count) { - free(server_opts.authkeys); - server_opts.authkeys = NULL; - } - - ret = 0; - } - } - } - - /* UNLOCK */ - pthread_mutex_unlock(&server_opts.authkey_lock); - - return ret; -} - -void -nc_server_ssh_clear_opts(struct nc_server_ssh_opts *opts) -{ - nc_server_ssh_del_hostkey(NULL, -1, opts); -} - -#ifdef HAVE_SHADOW - -/** - * @brief Get passwd entry for a user. - * - * @param[in] username Name of the user. - * @param[in] pwd_buf Passwd entry buffer. - * @param[in,out] buf Passwd entry string buffer. - * @param[in,out] buf_size Current @p buf size. - * @return Found passwd entry for the user, NULL if none found. - */ -static struct passwd * -auth_password_getpwnam(const char *username, struct passwd *pwd_buf, char **buf, size_t *buf_size) -{ - struct passwd *pwd = NULL; - char *mem; - int r = 0; - - do { - r = getpwnam_r(username, pwd_buf, *buf, *buf_size, &pwd); - if (pwd) { - /* entry found */ - break; - } - - if (r == ERANGE) { - /* small buffer, enlarge */ - *buf_size <<= 2; - mem = realloc(*buf, *buf_size); - if (!mem) { - ERRMEM; - return NULL; - } - *buf = mem; - } - } while (r == ERANGE); - - return pwd; -} - -/** - * @brief Get shadow entry for a user. - * - * @param[in] username Name of the user. - * @param[in] spwd_buf Shadow entry buffer. - * @param[in,out] buf Shadow entry string buffer. - * @param[in,out] buf_size Current @p buf size. - * @return Found shadow entry for the user, NULL if none found. - */ -static struct spwd * -auth_password_getspnam(const char *username, struct spwd *spwd_buf, char **buf, size_t *buf_size) -{ - struct spwd *spwd = NULL; - char *mem; - int r = 0; - - do { -# ifndef __QNXNTO__ - r = getspnam_r(username, spwd_buf, *buf, *buf_size, &spwd); -# else - spwd = getspnam_r(username, spwd_buf, *buf, *buf_size); -# endif - if (spwd) { - /* entry found */ - break; - } + len = 11 + 17 + strlen(in) + 10 + 16; + } - if (r == ERANGE) { - /* small buffer, enlarge */ - *buf_size <<= 2; - mem = realloc(*buf, *buf_size); - if (!mem) { - ERRMEM; - return NULL; - } - *buf = mem; - } - } while (r == ERANGE); + if ((unsigned)written != len) { + unlink(path); + return NULL; + } - return spwd; + return strdup(path); } -/** - * @brief Get hashed system apssword for a user. - * - * @param[in] username Name of the user. - * @return Hashed password of @p username. - */ -static char * -auth_password_get_pwd_hash(const char *username) +static int +nc_server_ssh_ks_ref_get_key(const char *referenced_name, struct nc_asymmetric_key **askey) { - struct passwd *pwd, pwd_buf; - struct spwd *spwd, spwd_buf; - char *pass_hash = NULL, *buf = NULL; - size_t buf_size = 256; + uint16_t i; + struct nc_keystore *ks = &server_opts.keystore; - buf = malloc(buf_size); - if (!buf) { - ERRMEM; - goto error; + *askey = NULL; + + /* lookup name */ + for (i = 0; i < ks->asym_key_count; i++) { + if (!strcmp(referenced_name, ks->asym_keys[i].name)) { + break; + } } - pwd = auth_password_getpwnam(username, &pwd_buf, &buf, &buf_size); - if (!pwd) { - VRB(NULL, "User \"%s\" not found locally.", username); - goto error; + if (i == ks->asym_key_count) { + ERR(NULL, "Keystore entry \"%s\" not found.", referenced_name); + return 1; } - if (!strcmp(pwd->pw_passwd, "x")) { - spwd = auth_password_getspnam(username, &spwd_buf, &buf, &buf_size); - if (!spwd) { - VRB(NULL, "Failed to retrieve the shadow entry for \"%s\".", username); - goto error; - } else if ((spwd->sp_expire > -1) && (spwd->sp_expire <= (time(NULL) / (60 * 60 * 24)))) { - WRN(NULL, "User \"%s\" account has expired.", username); - goto error; - } + *askey = &ks->asym_keys[i]; - pass_hash = spwd->sp_pwdp; - } else { - pass_hash = pwd->pw_passwd; + /* check if the referenced public key is SubjectPublicKeyInfo */ + if ((*askey)->pubkey_data && nc_is_pk_subject_public_key_info((*askey)->pubkey_data)) { + ERR(NULL, "The public key of the referenced hostkey \"%s\" is in the SubjectPublicKeyInfo format, " + "which is not allowed in the SSH!", referenced_name); + return 1; } - if (!pass_hash) { - ERR(NULL, "No password could be retrieved for \"%s\".", username); - goto error; - } + return 0; +} + +static int +nc_server_ssh_ts_ref_get_keys(const char *referenced_name, struct nc_public_key **pubkeys, uint16_t *pubkey_count) +{ + uint16_t i, j; + struct nc_truststore *ts = &server_opts.truststore; - /* check the hash structure for special meaning */ - if (!strcmp(pass_hash, "*") || !strcmp(pass_hash, "!")) { - VRB(NULL, "User \"%s\" is not allowed to authenticate using a password.", username); - goto error; + *pubkeys = NULL; + *pubkey_count = 0; + + /* lookup name */ + for (i = 0; i < ts->pub_bag_count; i++) { + if (!strcmp(referenced_name, ts->pub_bags[i].name)) { + break; + } } - if (!strcmp(pass_hash, "*NP*")) { - VRB(NULL, "Retrieving password for \"%s\" from a NIS+ server not supported.", username); - goto error; + + if (i == ts->pub_bag_count) { + ERR(NULL, "Truststore entry \"%s\" not found.", referenced_name); + return 1; } - pass_hash = strdup(pass_hash); - free(buf); - return pass_hash; + /* check if any of the referenced public keys is SubjectPublicKeyInfo */ + for (j = 0; j < ts->pub_bags[i].pubkey_count; j++) { + if (nc_is_pk_subject_public_key_info(ts->pub_bags[i].pubkeys[j].data)) { + ERR(NULL, "A public key of the referenced public key bag \"%s\" is in the SubjectPublicKeyInfo format, " + "which is not allowed in the SSH!", referenced_name); + return 1; + } + } -error: - free(buf); - return NULL; + *pubkeys = ts->pub_bags[i].pubkeys; + *pubkey_count = ts->pub_bags[i].pubkey_count; + return 0; } -#else +API void +nc_server_ssh_set_passwd_auth_clb(int (*passwd_auth_clb)(const struct nc_session *session, const char *password, void *user_data), + void *user_data, void (*free_user_data)(void *user_data)) +{ + server_opts.passwd_auth_clb = passwd_auth_clb; + server_opts.passwd_auth_data = user_data; + server_opts.passwd_auth_data_free = free_user_data; +} -/** - * @brief Get hashed system password for a user. - * - * @param[in] username Name of the user. - * @return Hashed password of @p username. - */ -static char * -auth_password_get_pwd_hash(const char *username) +API void +nc_server_ssh_set_interactive_auth_clb(int (*interactive_auth_clb)(const struct nc_session *session, ssh_session ssh_sess, + ssh_message msg, void *user_data), void *user_data, void (*free_user_data)(void *user_data)) { - (void)username; - return strdup(""); + server_opts.interactive_auth_clb = interactive_auth_clb; + server_opts.interactive_auth_data = user_data; + server_opts.interactive_auth_data_free = free_user_data; } -#endif +API void +nc_server_ssh_set_pubkey_auth_clb(int (*pubkey_auth_clb)(const struct nc_session *session, ssh_key key, void *user_data), + void *user_data, void (*free_user_data)(void *user_data)) +{ + server_opts.pubkey_auth_clb = pubkey_auth_clb; + server_opts.pubkey_auth_data = user_data; + server_opts.pubkey_auth_data_free = free_user_data; +} /** * @brief Compare hashed password with a cleartext password for a match. @@ -970,32 +256,25 @@ auth_password_compare_pwd(const char *pass_hash, const char *pass_clear) return strcmp(new_pass_hash, pass_hash); } -static void -nc_sshcb_auth_password(struct nc_session *session, ssh_message msg) +static int +nc_sshcb_auth_password(struct nc_session *session, struct nc_auth_client *auth_client, ssh_message msg) { - char *pass_hash; int auth_ret = 1; if (server_opts.passwd_auth_clb) { auth_ret = server_opts.passwd_auth_clb(session, ssh_message_auth_password(msg), server_opts.passwd_auth_data); } else { - pass_hash = auth_password_get_pwd_hash(session->username); - if (pass_hash) { - auth_ret = auth_password_compare_pwd(pass_hash, ssh_message_auth_password(msg)); - free(pass_hash); - } + auth_ret = auth_password_compare_pwd(auth_client->password, ssh_message_auth_password(msg)); } - if (!auth_ret) { - session->flags |= NC_SESSION_SSH_AUTHENTICATED; - VRB(session, "User \"%s\" authenticated.", session->username); - ssh_message_auth_reply_success(msg, 0); - } else { + if (auth_ret) { ++session->opts.server.ssh_auth_attempts; VRB(session, "Failed user \"%s\" authentication attempt (#%d).", session->username, session->opts.server.ssh_auth_attempts); ssh_message_reply_default(msg); } + + return auth_ret; } #ifdef HAVE_LIBPAM @@ -1026,7 +305,7 @@ nc_pam_conv_clb(int n_messages, const struct pam_message **msg, struct pam_respo struct nc_server_ssh_opts *opts; libssh_session = clb_data->session->ti.libssh.session; - opts = clb_data->session->data; + opts = clb_data->opts; /* PAM_MAX_NUM_MSG == 32 by default */ if ((n_messages <= 0) || (n_messages >= PAM_MAX_NUM_MSG)) { @@ -1168,28 +447,49 @@ nc_pam_conv_clb(int n_messages, const struct pam_message **msg, struct pam_respo * @return PAM error otherwise. */ static int -nc_pam_auth(struct nc_session *session, ssh_message ssh_msg) +nc_pam_auth(struct nc_session *session, struct nc_server_ssh_opts *opts, ssh_message ssh_msg) { pam_handle_t *pam_h = NULL; int ret; struct nc_pam_thread_arg clb_data; struct pam_conv conv; + uint16_t i; /* structure holding callback's data */ clb_data.msg = ssh_msg; clb_data.session = session; + clb_data.opts = opts; /* PAM conversation structure holding the callback and it's data */ conv.conv = nc_pam_conv_clb; conv.appdata_ptr = &clb_data; + /* get the current client's configuration file */ + for (i = 0; i < opts->client_count; i++) { + if (!strcmp(opts->auth_clients[i].username, session->username)) { + break; + } + } + + if (i == opts->client_count) { + ERR(NULL, "User \"%s\" not found.", session->username); + ret = 1; + goto cleanup; + } + + if (!opts->auth_clients[i].pam_config_name) { + ERR(NULL, "User's \"%s\" PAM configuration filename not set."); + ret = 1; + goto cleanup; + } + /* initialize PAM and see if the given configuration file exists */ # ifdef LIBPAM_HAVE_CONFDIR /* PAM version >= 1.4 */ - ret = pam_start_confdir(server_opts.conf_name, session->username, &conv, server_opts.conf_dir, &pam_h); + ret = pam_start_confdir(opts->auth_clients[i].pam_config_name, session->username, &conv, opts->auth_clients[i].pam_config_dir, &pam_h); # else /* PAM version < 1.4 */ - ret = pam_start(server_opts.conf_name, session->username, &conv, &pam_h); + ret = pam_start(opts->auth_clients[i].pam_config_name, session->username, &conv, &pam_h); # endif if (ret != PAM_SUCCESS) { ERR(NULL, "PAM error occurred (%s).\n", pam_strerror(pam_h, ret)); @@ -1237,19 +537,16 @@ nc_pam_auth(struct nc_session *session, ssh_message ssh_msg) #endif -static void -nc_sshcb_auth_kbdint(struct nc_session *session, ssh_message msg) +static int +nc_sshcb_auth_kbdint(struct nc_session *session, struct nc_server_ssh_opts *opts, ssh_message msg) { int auth_ret = 1; - if (server_opts.interactive_auth_sess_clb) { - auth_ret = server_opts.interactive_auth_sess_clb(session, session->ti.libssh.session, msg, - server_opts.interactive_auth_data); - } else if (server_opts.interactive_auth_clb) { - auth_ret = server_opts.interactive_auth_clb(session, msg, server_opts.interactive_auth_data); + if (server_opts.interactive_auth_clb) { + auth_ret = server_opts.interactive_auth_clb(session, session->ti.libssh.session, msg, server_opts.interactive_auth_data); } else { #ifdef HAVE_LIBPAM - if (nc_pam_auth(session, msg) == PAM_SUCCESS) { + if (nc_pam_auth(session, opts, msg) == PAM_SUCCESS) { auth_ret = 0; } #else @@ -1257,22 +554,99 @@ nc_sshcb_auth_kbdint(struct nc_session *session, ssh_message msg) #endif } - /* We have already sent a reply */ - if (auth_ret == -1) { - return; - } - /* Authenticate message based on outcome */ - if (!auth_ret) { - session->flags |= NC_SESSION_SSH_AUTHENTICATED; - VRB(session, "User \"%s\" authenticated.", session->username); - ssh_message_auth_reply_success(msg, 0); - } else { + if (auth_ret) { ++session->opts.server.ssh_auth_attempts; VRB(session, "Failed user \"%s\" authentication attempt (#%d).", session->username, session->opts.server.ssh_auth_attempts); ssh_message_reply_default(msg); } + + return auth_ret; +} + +/* + * Get the public key type from binary data stored in buffer. + * The data is in the form of: 4 bytes = data length, then data of data length + * and the data is in network byte order. The key has to be in the SSH2 format. + */ +static const char * +nc_server_ssh_get_pubkey_type(const char *buffer, uint32_t *len) +{ + uint32_t type_len; + + /* copy the 4 bytes */ + memcpy(&type_len, buffer, sizeof type_len); + /* type_len now stores the length of the key type */ + type_len = ntohl(type_len); + *len = type_len; + + /* move 4 bytes in the buffer, this is where the type should be */ + buffer += sizeof type_len; + return buffer; +} + +/** + * @brief Create ssh key from base64 pubkey data. + * + * @param[in] base64 base64 encoded public key. + * @param[out] key created ssh key. + * @return 0 on success, 1 otherwise. + */ +static int +nc_server_ssh_create_ssh_pubkey(const char *base64, ssh_key *key) +{ + int ret = 0; + char *bin = NULL; + const char *pub_type = NULL; + uint32_t pub_type_len = 0; + + if (!key && !base64) { + ERRINT; + ret = 1; + goto cleanup; + } + + *key = NULL; + + /* convert base64 to binary */ + if (nc_base64_to_bin(base64, &bin) == -1) { + ERR(NULL, "Unable to decode base64."); + ret = 1; + goto cleanup; + } + + /* get the key type and try to import it if possible */ + pub_type = nc_server_ssh_get_pubkey_type(bin, &pub_type_len); + if (!pub_type) { + ret = 1; + goto cleanup; + } else if (!strncmp(pub_type, "ssh-dss", pub_type_len)) { + ERR(NULL, "DSA keys are not supported."); + ret = 1; + goto cleanup; + } else if (!strncmp(pub_type, "ssh-rsa", pub_type_len)) { + ret = ssh_pki_import_pubkey_base64(base64, SSH_KEYTYPE_RSA, key); + } else if (!strncmp(pub_type, "ecdsa-sha2-nistp256", pub_type_len)) { + ret = ssh_pki_import_pubkey_base64(base64, SSH_KEYTYPE_ECDSA_P256, key); + } else if (!strncmp(pub_type, "ecdsa-sha2-nistp384", pub_type_len)) { + ret = ssh_pki_import_pubkey_base64(base64, SSH_KEYTYPE_ECDSA_P384, key); + } else if (!strncmp(pub_type, "ecdsa-sha2-nistp521", pub_type_len)) { + ret = ssh_pki_import_pubkey_base64(base64, SSH_KEYTYPE_ECDSA_P521, key); + } else if (!strncmp(pub_type, "ssh-ed25519", pub_type_len)) { + ret = ssh_pki_import_pubkey_base64(base64, SSH_KEYTYPE_ED25519, key); + } else { + ERR(NULL, "Public key type not recognised."); + ret = 1; + goto cleanup; + } + +cleanup: + if (ret != SSH_OK) { + ERR(NULL, "Error importing public key."); + } + free(bin); + return ret; } /** @@ -1281,96 +655,103 @@ nc_sshcb_auth_kbdint(struct nc_session *session, ssh_message msg) * @param[in] key Presented SSH key to compare. * @return Authorized key username, NULL if no match was found. */ -static const char * -auth_pubkey_compare_key(ssh_key key) +static int +auth_pubkey_compare_key(ssh_key key, struct nc_auth_client *auth_client) { - uint32_t i; - ssh_key pub_key; - const char *username = NULL; + uint16_t i, pubkey_count; int ret = 0; + ssh_key new_key = NULL; + struct nc_public_key *pubkeys; - /* LOCK */ - pthread_mutex_lock(&server_opts.authkey_lock); - - for (i = 0; i < server_opts.authkey_count; ++i) { - switch (server_opts.authkeys[i].type) { - case NC_SSH_KEY_UNKNOWN: - ret = ssh_pki_import_pubkey_file(server_opts.authkeys[i].path, &pub_key); - break; - case NC_SSH_KEY_DSA: - ret = ssh_pki_import_pubkey_base64(server_opts.authkeys[i].base64, SSH_KEYTYPE_DSS, &pub_key); - break; - case NC_SSH_KEY_RSA: - ret = ssh_pki_import_pubkey_base64(server_opts.authkeys[i].base64, SSH_KEYTYPE_RSA, &pub_key); - break; - case NC_SSH_KEY_ECDSA: - ret = ssh_pki_import_pubkey_base64(server_opts.authkeys[i].base64, SSH_KEYTYPE_ECDSA, &pub_key); - break; + /* get the correct public key storage */ + if (auth_client->store == NC_STORE_LOCAL) { + pubkeys = auth_client->pubkeys; + pubkey_count = auth_client->pubkey_count; + } else { + ret = nc_server_ssh_ts_ref_get_keys(auth_client->ts_ref, &pubkeys, &pubkey_count); + if (ret) { + ERR(NULL, "Error getting \"%s\"'s public keys from the truststore.", auth_client->username); + return ret; } + } - if (ret == SSH_EOF) { - WRN(NULL, "Failed to import a public key of \"%s\" (File access problem).", server_opts.authkeys[i].username); - continue; - } else if (ret == SSH_ERROR) { - WRN(NULL, "Failed to import a public key of \"%s\" (SSH error).", server_opts.authkeys[i].username); + /* try to compare all of the client's keys with the key received in the SSH message */ + for (i = 0; i < pubkey_count; i++) { + /* create the SSH key from the data */ + if (nc_server_ssh_create_ssh_pubkey(pubkeys[i].data, &new_key)) { + ssh_key_free(new_key); continue; } - if (!ssh_key_cmp(key, pub_key, SSH_KEY_CMP_PUBLIC)) { - ssh_key_free(pub_key); + /* compare the keys */ + ret = ssh_key_cmp(key, new_key, SSH_KEY_CMP_PUBLIC); + if (!ret) { break; + } else { + WRN(NULL, "User's \"%s\" public key doesn't match, trying another.", auth_client->username); + ssh_key_free(new_key); } - - ssh_key_free(pub_key); } - if (i < server_opts.authkey_count) { - username = server_opts.authkeys[i].username; + if (i == pubkey_count) { + ret = 1; } - /* UNLOCK */ - pthread_mutex_unlock(&server_opts.authkey_lock); + if (!ret) { + /* only free a key if everything was ok, it would have already been freed otherwise */ + ssh_key_free(new_key); + } - return username; + return ret; } static void -nc_sshcb_auth_pubkey(struct nc_session *session, ssh_message msg) +nc_sshcb_auth_none(struct nc_session *session, struct nc_auth_client *auth_client, ssh_message msg) +{ + if (auth_client->supports_none && !auth_client->password && !auth_client->pubkey_count && !auth_client->pam_config_name) { + /* only authenticate the client if he supports none and no other method */ + session->flags |= NC_SESSION_SSH_AUTHENTICATED; + VRB(session, "User \"%s\" authenticated.", session->username); + ssh_message_auth_reply_success(msg, 0); + } + + ssh_message_reply_default(msg); +} + +static int +nc_sshcb_auth_pubkey(struct nc_session *session, struct nc_auth_client *auth_client, ssh_message msg) { - const char *username; - int signature_state; + int signature_state, ret = 0; if (server_opts.pubkey_auth_clb) { if (server_opts.pubkey_auth_clb(session, ssh_message_auth_pubkey(msg), server_opts.pubkey_auth_data)) { + ret = 1; goto fail; } } else { - if ((username = auth_pubkey_compare_key(ssh_message_auth_pubkey(msg))) == NULL) { + if (auth_pubkey_compare_key(ssh_message_auth_pubkey(msg), auth_client)) { VRB(session, "User \"%s\" tried to use an unknown (unauthorized) public key.", session->username); - goto fail; - } else if (strcmp(session->username, username)) { - VRB(session, "User \"%s\" is not the username identified with the presented public key.", session->username); + ret = 1; goto fail; } } signature_state = ssh_message_auth_publickey_state(msg); - if (signature_state == SSH_PUBLICKEY_STATE_VALID) { - VRB(session, "User \"%s\" authenticated.", session->username); - session->flags |= NC_SESSION_SSH_AUTHENTICATED; - ssh_message_auth_reply_success(msg, 0); - } else if (signature_state == SSH_PUBLICKEY_STATE_NONE) { + if (signature_state == SSH_PUBLICKEY_STATE_NONE) { /* accepting only the use of a public key */ ssh_message_auth_reply_pk_ok_simple(msg); + ret = 1; } - return; + return ret; fail: ++session->opts.server.ssh_auth_attempts; VRB(session, "Failed user \"%s\" authentication attempt (#%d).", session->username, session->opts.server.ssh_auth_attempts); ssh_message_reply_default(msg); + + return ret; } static int @@ -1458,11 +839,12 @@ nc_sshcb_channel_subsystem(struct nc_session *session, ssh_channel channel, cons } int -nc_sshcb_msg(ssh_session UNUSED(sshsession), ssh_message msg, void *data) +nc_session_ssh_msg(struct nc_session *session, struct nc_server_ssh_opts *opts, ssh_message msg, struct nc_auth_state *state) { const char *str_type, *str_subtype = NULL, *username; - int subtype, type; - struct nc_session *session = (struct nc_session *)data; + int subtype, type, libssh_auth_methods = 0, ret = 0; + uint16_t i; + struct nc_auth_client *auth_client = NULL; type = ssh_message_type(msg); subtype = ssh_message_subtype(msg); @@ -1584,7 +966,6 @@ nc_sshcb_msg(ssh_session UNUSED(sshsession), ssh_message msg, void *data) ssh_message_reply_default(msg); return 0; } - session->flags |= NC_SESSION_SSH_NEW_MSG; /* * process known messages @@ -1594,19 +975,67 @@ nc_sshcb_msg(ssh_session UNUSED(sshsession), ssh_message msg, void *data) ERR(session, "User \"%s\" authenticated, but requested another authentication.", session->username); ssh_message_reply_default(msg); return 0; + } else if (!state || !opts) { + /* these two parameters should always be set during an authentication, + * however do a check just in case something goes really wrong, since they + * are not needed for other types of messages + */ + ERRINT; + return 1; } /* save the username, do not let the client change it */ username = ssh_message_auth_user(msg); - if (!session->username) { - if (!username) { - ERR(session, "Denying an auth request without a username."); - return 1; + assert(username); + + for (i = 0; i < opts->client_count; i++) { + if (!strcmp(opts->auth_clients[i].username, username)) { + auth_client = &opts->auth_clients[i]; + break; + } + } + + if (!auth_client) { + if (opts->endpt_client_ref) { + return nc_session_ssh_msg(session, opts->endpt_client_ref->opts.ssh, msg, state); } + ERR(NULL, "User \"%s\" not known by the server.", username); + ssh_message_reply_default(msg); + return 0; + } + + if (!session->username) { session->username = strdup(username); - } else if (username) { + + /* configure and count accepted auth methods */ + if (auth_client->store == NC_STORE_LOCAL) { + if (auth_client->pubkey_count) { + libssh_auth_methods |= SSH_AUTH_METHOD_PUBLICKEY; + } + } else if (auth_client->ts_ref) { + libssh_auth_methods |= SSH_AUTH_METHOD_PUBLICKEY; + } + if (auth_client->password) { + state->auth_method_count++; + libssh_auth_methods |= SSH_AUTH_METHOD_PASSWORD; + } + if (auth_client->pam_config_name) { + state->auth_method_count++; + libssh_auth_methods |= SSH_AUTH_METHOD_INTERACTIVE; + } + if (auth_client->supports_none) { + libssh_auth_methods |= SSH_AUTH_METHOD_NONE; + } + + if (libssh_auth_methods & SSH_AUTH_METHOD_PUBLICKEY) { + state->auth_method_count++; + } + + ssh_set_auth_methods(session->ti.libssh.session, libssh_auth_methods); + } else { if (strcmp(username, session->username)) { + /* changing username not allowed */ ERR(session, "User \"%s\" changed its username to \"%s\".", session->username, username); session->status = NC_STATUS_INVALID; session->term_reason = NC_SESSION_TERM_OTHER; @@ -1614,19 +1043,34 @@ nc_sshcb_msg(ssh_session UNUSED(sshsession), ssh_message msg, void *data) } } + /* try authenticating, the user must authenticate via all of his configured auth methods */ if (subtype == SSH_AUTH_METHOD_NONE) { - /* libssh will return the supported auth methods */ - return 1; + nc_sshcb_auth_none(session, auth_client, msg); + ret = 1; } else if (subtype == SSH_AUTH_METHOD_PASSWORD) { - nc_sshcb_auth_password(session, msg); - return 0; + ret = nc_sshcb_auth_password(session, auth_client, msg); } else if (subtype == SSH_AUTH_METHOD_PUBLICKEY) { - nc_sshcb_auth_pubkey(session, msg); - return 0; + ret = nc_sshcb_auth_pubkey(session, auth_client, msg); } else if (subtype == SSH_AUTH_METHOD_INTERACTIVE) { - nc_sshcb_auth_kbdint(session, msg); - return 0; + ret = nc_sshcb_auth_kbdint(session, opts, msg); + } + + if (!ret) { + state->auth_success_count++; + } + + if (!ret && (state->auth_success_count < state->auth_method_count)) { + /* success, but he needs to do another method */ + VRB(session, "User \"%s\" partially authenticated, but still needs to authenticate via the rest of his configured methods.", username); + ssh_message_auth_reply_success(msg, 1); + } else if (!ret && (state->auth_success_count == state->auth_method_count)) { + /* authenticated */ + ssh_message_auth_reply_success(msg, 0); + session->flags |= NC_SESSION_SSH_AUTHENTICATED; + VRB(session, "User \"%s\" authenticated.", username); } + + return 0; } else if (session->flags & NC_SESSION_SSH_AUTHENTICATED) { if ((type == SSH_REQUEST_CHANNEL_OPEN) && ((enum ssh_channel_type_e)subtype == SSH_CHANNEL_SESSION)) { if (nc_sshcb_channel_open(session, msg)) { @@ -1651,67 +1095,34 @@ nc_sshcb_msg(ssh_session UNUSED(sshsession), ssh_message msg, void *data) /* ret 1 on success, 0 on timeout, -1 on error */ static int -nc_accept_ssh_session_open_netconf_channel(struct nc_session *session, int timeout) +nc_accept_ssh_session_open_netconf_channel(struct nc_session *session, struct nc_server_ssh_opts *opts, int timeout) { - int ret; struct timespec ts_timeout; + ssh_message msg; - /* message callback is executed twice to give chance for the channel to be - * created if timeout == 0 (it takes 2 messages, channel-open, subsystem-request) */ - if (!timeout) { - if (!nc_session_is_connected(session)) { - ERR(session, "Communication socket unexpectedly closed (libssh)."); - return -1; - } - - ret = ssh_execute_message_callbacks(session->ti.libssh.session); - if (ret != SSH_OK) { - ERR(session, "Failed to receive SSH messages on a session (%s).", - ssh_get_error(session->ti.libssh.session)); - return -1; - } - - if (!session->ti.libssh.channel) { - return 0; - } - - ret = ssh_execute_message_callbacks(session->ti.libssh.session); - if (ret != SSH_OK) { - ERR(session, "Failed to receive SSH messages on a session (%s).", - ssh_get_error(session->ti.libssh.session)); - return -1; - } - - if (!(session->flags & NC_SESSION_SSH_SUBSYS_NETCONF)) { - /* we did not receive subsystem-request, timeout */ - return 0; - } - - return 1; - } - - if (timeout > -1) { - nc_timeouttime_get(&ts_timeout, timeout); + if (timeout) { + nc_timeouttime_get(&ts_timeout, timeout * 1000); } while (1) { if (!nc_session_is_connected(session)) { - ERR(session, "Communication socket unexpectedly closed (libssh)."); + ERR(session, "Communication SSH socket unexpectedly closed."); return -1; } - ret = ssh_execute_message_callbacks(session->ti.libssh.session); - if (ret != SSH_OK) { - ERR(session, "Failed to receive SSH messages on a session (%s).", - ssh_get_error(session->ti.libssh.session)); - return -1; + msg = ssh_message_get(session->ti.libssh.session); + if (msg) { + if (nc_session_ssh_msg(session, opts, msg, NULL)) { + ssh_message_reply_default(msg); + } + ssh_message_free(msg); } - if (session->ti.libssh.channel && (session->flags & NC_SESSION_SSH_SUBSYS_NETCONF)) { + if (session->ti.libssh.channel && session->flags & NC_SESSION_SSH_SUBSYS_NETCONF) { return 1; } usleep(NC_TIMEOUT_STEP); - if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) { + if ((opts->auth_timeout) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) { /* timeout */ ERR(session, "Failed to start \"netconf\" SSH subsystem for too long, disconnecting."); break; @@ -1731,44 +1142,42 @@ nc_accept_ssh_session_open_netconf_channel(struct nc_session *session, int timeo * @return -1 on error. */ static int -nc_ssh_bind_add_hostkeys(ssh_bind sbind, char **hostkeys, uint8_t hostkey_count) +nc_ssh_bind_add_hostkeys(ssh_bind sbind, struct nc_server_ssh_opts *opts, uint16_t hostkey_count) { - uint8_t i; + uint16_t i; char *privkey_path, *privkey_data; int ret; - NC_SSH_KEY_TYPE privkey_type; - - if (!server_opts.hostkey_clb) { - ERR(NULL, "Callback for retrieving SSH host keys not set."); - return -1; - } + struct nc_asymmetric_key *key = NULL; for (i = 0; i < hostkey_count; ++i) { privkey_path = privkey_data = NULL; - if (server_opts.hostkey_clb(hostkeys[i], server_opts.hostkey_data, &privkey_path, &privkey_data, &privkey_type)) { - ERR(NULL, "Host key callback failed."); - return -1; - } - if (privkey_data) { - privkey_path = base64der_key_to_tmp_file(privkey_data, nc_keytype2str(privkey_type)); - if (!privkey_path) { - ERR(NULL, "Temporarily storing a host key into a file failed (%s).", strerror(errno)); - free(privkey_data); + /* get the asymmetric key */ + if (opts->hostkeys[i].store == NC_STORE_LOCAL) { + /* stored locally */ + key = &opts->hostkeys[i].key; + } else { + /* keystore reference, need to get it */ + if (nc_server_ssh_ks_ref_get_key(opts->hostkeys[i].ks_ref, &key)) { return -1; } } + privkey_path = base64der_privkey_to_tmp_file(key->privkey_data, nc_privkey_format_to_str(key->privkey_type)); + if (!privkey_path) { + ERR(NULL, "Temporarily storing a host key into a file failed (%s).", strerror(errno)); + return -1; + } + ret = ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_HOSTKEY, privkey_path); /* cleanup */ if (privkey_data && unlink(privkey_path)) { WRN(NULL, "Removing a temporary host key file \"%s\" failed (%s).", privkey_path, strerror(errno)); } - free(privkey_data); if (ret != SSH_OK) { - ERR(NULL, "Failed to set hostkey \"%s\" (%s).", hostkeys[i], privkey_path); + ERR(NULL, "Failed to set hostkey \"%s\" (%s).", opts->hostkeys[i].name, privkey_path); } free(privkey_path); @@ -1781,23 +1190,11 @@ nc_ssh_bind_add_hostkeys(ssh_bind sbind, char **hostkeys, uint8_t hostkey_count) } static int -nc_accept_ssh_session_auth(struct nc_session *session, const struct nc_server_ssh_opts *opts) +nc_accept_ssh_session_auth(struct nc_session *session, struct nc_server_ssh_opts *opts) { struct timespec ts_timeout; ssh_message msg; - int libssh_auth_methods = 0; - - /* configure accepted auth methods */ - if (opts->auth_methods & NC_SSH_AUTH_PUBLICKEY) { - libssh_auth_methods |= SSH_AUTH_METHOD_PUBLICKEY; - } - if (opts->auth_methods & NC_SSH_AUTH_PASSWORD) { - libssh_auth_methods |= SSH_AUTH_METHOD_PASSWORD; - } - if (opts->auth_methods & NC_SSH_AUTH_INTERACTIVE) { - libssh_auth_methods |= SSH_AUTH_METHOD_INTERACTIVE; - } - ssh_set_auth_methods(session->ti.libssh.session, libssh_auth_methods); + struct nc_auth_state state = {0}; /* authenticate */ if (opts->auth_timeout) { @@ -1811,7 +1208,7 @@ nc_accept_ssh_session_auth(struct nc_session *session, const struct nc_server_ss msg = ssh_message_get(session->ti.libssh.session); if (msg) { - if (nc_sshcb_msg(session->ti.libssh.session, msg, (void *) session)) { + if (nc_session_ssh_msg(session, opts, msg, &state)) { ssh_message_reply_default(msg); } ssh_message_free(msg); @@ -1847,16 +1244,13 @@ nc_accept_ssh_session_auth(struct nc_session *session, const struct nc_server_ss } int -nc_accept_ssh_session(struct nc_session *session, int sock, int timeout) +nc_accept_ssh_session(struct nc_session *session, struct nc_server_ssh_opts *opts, int sock, int timeout) { ssh_bind sbind = NULL; - struct nc_server_ssh_opts *opts; int rc = 1, r; struct timespec ts_timeout; const char *err_msg; - opts = session->data; - /* other transport-specific data */ session->ti_type = NC_TI_LIBSSH; session->ti.libssh.session = ssh_new(); @@ -1874,7 +1268,25 @@ nc_accept_ssh_session(struct nc_session *session, int sock, int timeout) } /* configure host keys */ - if (nc_ssh_bind_add_hostkeys(sbind, opts->hostkeys, opts->hostkey_count)) { + if (nc_ssh_bind_add_hostkeys(sbind, opts, opts->hostkey_count)) { + rc = -1; + goto cleanup; + } + + /* configure supported algorithms */ + if (opts->hostkey_algs && ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, opts->hostkey_algs)) { + rc = -1; + goto cleanup; + } + if (opts->encryption_algs && ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_CIPHERS_S_C, opts->encryption_algs)) { + rc = -1; + goto cleanup; + } + if (opts->kex_algs && ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_KEY_EXCHANGE, opts->kex_algs)) { + rc = -1; + goto cleanup; + } + if (opts->mac_algs && ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_HMAC_S_C, opts->mac_algs)) { rc = -1; goto cleanup; } @@ -1887,6 +1299,7 @@ nc_accept_ssh_session(struct nc_session *session, int sock, int timeout) } sock = -1; + /* set to non-blocking */ ssh_set_blocking(session->ti.libssh.session, 0); if (timeout > -1) { @@ -1918,20 +1331,11 @@ nc_accept_ssh_session(struct nc_session *session, int sock, int timeout) goto cleanup; } - /* set the message callback after a successful authentication */ - ssh_set_message_callback(session->ti.libssh.session, nc_sshcb_msg, session); - - /* remember that this session was just set as nc_sshcb_msg() parameter */ - session->flags |= NC_SESSION_SSH_MSG_CB; - /* open channel and request 'netconf' subsystem */ - if ((rc = nc_accept_ssh_session_open_netconf_channel(session, timeout)) != 1) { + if ((rc = nc_accept_ssh_session_open_netconf_channel(session, opts, timeout)) != 1) { goto cleanup; } - /* all SSH messages were processed */ - session->flags &= ~NC_SESSION_SSH_NEW_MSG; - cleanup: if (sock > -1) { close(sock); From af56da564d32d08faa744ed8214413729521dfc7 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 19 Oct 2023 09:48:23 +0200 Subject: [PATCH 091/134] readme UPDATE update readme --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e9e321ae..36e677b5 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,8 @@ NETCONF 1.0 ([RFC 4741](https://tools.ietf.org/html/rfc4741)) as well as NETCONF * NETCONF over pre-established transport sessions (using this mechanism the communication can be tunneled through sshd(8), for instance). * NETCONF Call Home ([RFC 8071](https://tools.ietf.org/html/rfc8071)). -* NETCONF Event Notifications ([RFC 5277](https://tools.ietf.org/html/rfc5277)), +* NETCONF Event Notifications ([RFC 5277](https://tools.ietf.org/html/rfc5277)). +* Compatibility with the [ietf-netconf-server](https://datatracker.ietf.org/doc/html/draft-ietf-netconf-netconf-client-server-29#name-the-ietf-netconf-server-mod) YANG module. **libnetconf2** is maintained and further developed by the [Tools for Monitoring and Configuration](https://www.liberouter.org/) department of @@ -64,6 +65,7 @@ the `distro` directory. * libssh >= 0.7.1 (for SSH support) * recommended >= 0.9.0 * OpenSSL (for TLS support) +* curl #### Optional @@ -122,7 +124,7 @@ and enabling both 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_TLS=ON -DENABLE_SSH=ON .. +$ cmake -DENABLE_SSH_TLS=ON .. ``` ### DNSSEC SSHFP Retrieval From c6676967ab17e16d0a5b25a68537e25500f220b4 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 19 Oct 2023 09:55:00 +0200 Subject: [PATCH 092/134] SOVERSION bump to version 4.0.0 --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78ddc7aa..80cf9f87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,9 +65,9 @@ set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION # Version of the library # Major version is changed with every backward non-compatible API/ABI change in libyang, minor version changes # with backward compatible change and micro version is connected with any internal change of the library. -set(LIBNETCONF2_MAJOR_SOVERSION 3) -set(LIBNETCONF2_MINOR_SOVERSION 7) -set(LIBNETCONF2_MICRO_SOVERSION 1) +set(LIBNETCONF2_MAJOR_SOVERSION 4) +set(LIBNETCONF2_MINOR_SOVERSION 0) +set(LIBNETCONF2_MICRO_SOVERSION 0) set(LIBNETCONF2_SOVERSION_FULL ${LIBNETCONF2_MAJOR_SOVERSION}.${LIBNETCONF2_MINOR_SOVERSION}.${LIBNETCONF2_MICRO_SOVERSION}) set(LIBNETCONF2_SOVERSION ${LIBNETCONF2_MAJOR_SOVERSION}) From ebc29d6cf4e16304015112a3107f6b6109abac65 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 19 Oct 2023 09:55:30 +0200 Subject: [PATCH 093/134] VERSION bump to version 3.0.0 --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 80cf9f87..3b194e61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,9 +57,9 @@ endif() # Generic version of not only the library. Major version is reserved for really big changes of the project, # minor version changes with added functionality (new tool, functionality of the tool or library, ...) and # micro version is changed with a set of small changes or bugfixes anywhere in the project. -set(LIBNETCONF2_MAJOR_VERSION 2) -set(LIBNETCONF2_MINOR_VERSION 1) -set(LIBNETCONF2_MICRO_VERSION 40) +set(LIBNETCONF2_MAJOR_VERSION 3) +set(LIBNETCONF2_MINOR_VERSION 0) +set(LIBNETCONF2_MICRO_VERSION 0) set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION}.${LIBNETCONF2_MICRO_VERSION}) # Version of the library From a97f7fb05e14cff97ca6f23c0351688b1781ed99 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 19 Oct 2023 10:04:23 +0200 Subject: [PATCH 094/134] workflow UPDATE delete libnetconf3 yml --- .github/workflows/libnetconf3-ci.yml | 161 --------------------------- 1 file changed, 161 deletions(-) delete mode 100644 .github/workflows/libnetconf3-ci.yml diff --git a/.github/workflows/libnetconf3-ci.yml b/.github/workflows/libnetconf3-ci.yml deleted file mode 100644 index 1d41a045..00000000 --- a/.github/workflows/libnetconf3-ci.yml +++ /dev/null @@ -1,161 +0,0 @@ -name: libnetconf2 CI -on: - push: - branches: - - libnetconf3 - pull_request: - branches: - - libnetconf3 - -env: - DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev libcurl4-openssl-dev - -jobs: - build: - name: ${{ matrix.config.name }} - runs-on: ${{ matrix.config.os }} - strategy: - fail-fast: false - matrix: - config: - - { - name: "Release, gcc", - os: "ubuntu-22.04", - build-type: "Release", - dep-build-type: "Release", - cc: "gcc", - options: "-DENABLE_TESTS=ON -DENABLE_DNSSEC=ON", - packages: "", - snaps: "", - make-prepend: "", - make-target: "" - } - - { - name: "Release, clang", - os: "ubuntu-22.04", - build-type: "Release", - dep-build-type: "Release", - cc: "clang", - options: "-DENABLE_TESTS=ON -DENABLE_DNSSEC=ON", - packages: "", - snaps: "", - make-prepend: "", - make-target: "" - } - - { - name: "Debug, gcc", - os: "ubuntu-22.04", - build-type: "Debug", - dep-build-type: "Release", - cc: "gcc", - options: "-DENABLE_DNSSEC=ON", - packages: "valgrind", - snaps: "", - make-prepend: "", - make-target: "" - } - - { - name: "Debug, clang", - os: "ubuntu-22.04", - build-type: "Debug", - dep-build-type: "Release", - cc: "clang", - options: "-DENABLE_DNSSEC=ON", - # no valgrind because it does not support DWARF5 yet generated by clang 14 - packages: "", - snaps: "", - make-prepend: "", - make-target: "" - } - - { - name: "No SSH nor TLS", - os: "ubuntu-22.04", - build-type: "Debug", - dep-build-type: "Release", - cc: "gcc", - options: "-DENABLE_TESTS=ON -DENABLE_SSH_TLS=OFF", - packages: "valgrind", - snaps: "", - make-prepend: "", - make-target: "" - } - - { - name: "ASAN and UBSAN", - os: "ubuntu-22.04", - build-type: "Debug", - dep-build-type: "Release", - cc: "clang", - options: "-DCMAKE_C_FLAGS=-fsanitize=address,undefined -DENABLE_VALGRIND_TESTS=OFF", - packages: "", - snaps: "", - make-prepend: "", - make-target: "" - } - - steps: - - uses: actions/checkout@v3 - - - name: Deps-packages - shell: bash - run: | - sudo apt-get update - sudo apt-get install $DEFAULT_PACKAGES ${{ matrix.config.packages }} - if ${{ matrix.config.snaps != '' }} - then sudo snap refresh; sudo snap install ${{ matrix.config.snaps }} - fi - - - name: Deps-uncrustify - shell: bash - working-directory: ${{ github.workspace }} - run: | - git clone --branch uncrustify-0.75.1 https://github.com/uncrustify/uncrustify - cd uncrustify - mkdir build - cd build - CC=${{ matrix.config.cc }} cmake .. - make - sudo make install - if: ${{ matrix.config.name == 'Debug, gcc' }} - - - name: Deps-libyang - shell: bash - run: | - git clone -b devel https://github.com/CESNET/libyang.git - cd libyang - mkdir build - cd build - CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.dep-build-type }} -DENABLE_TESTS=OFF .. - make -j2 - sudo make install - - - name: Deps-libval - shell: bash - run: | - git clone https://github.com/DNSSEC-Tools/DNSSEC-Tools.git dnssec-tools - cd dnssec-tools/dnssec-tools/validator - ./configure - make -j2 - sudo make install - - - name: Configure - shell: bash - working-directory: ${{ github.workspace }} - run: | - mkdir build - cd build - CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.build-type }} ${{ matrix.config.options }} .. - - - name: Build - shell: bash - working-directory: ${{ github.workspace }}/build - run: | - export LC_ALL=C.UTF-8 - export PATH=/snap/bin:${{ github.workspace }}/coverity-tools/bin:$PATH - ${{ matrix.config.make-prepend }} make ${{ matrix.config.make-target }} - - - name: Test - shell: bash - working-directory: ${{ github.workspace }}/build - run: | - export LSAN_OPTIONS=suppressions=${{ github.workspace }}/tests/library_lsan.supp - ctest --output-on-failure From e4c69f69971fc2cf8f7c4640c0f9da2741c1820e Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 19 Oct 2023 14:37:14 +0200 Subject: [PATCH 095/134] readme UPDATE add/update versions --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 36e677b5..567b5e31 100644 --- a/README.md +++ b/README.md @@ -60,12 +60,11 @@ the `distro` directory. ## Requirements * C compiler (gcc >= 4.8.4, clang >= 3.0, ...) -* cmake >= 2.8.12 +* cmake >= 3.5.0 * [libyang](https://github.com/CESNET/libyang) -* libssh >= 0.7.1 (for SSH support) - * recommended >= 0.9.0 -* OpenSSL (for TLS support) -* curl +* libssh >= 0.9.5 (for SSH support) +* OpenSSL >= 3.0.0 (for TLS support) +* curl >= 7.30.0 #### Optional From 3cda245150b7b769c5c05c109adb96aa283f793d Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 19 Oct 2023 14:38:05 +0200 Subject: [PATCH 096/134] config UPDATE add hello/idle timeouts leaves --- doc/libnetconf.doc | 20 ++-------- ...libnetconf2-netconf-server@2023-09-07.yang | 18 +++++++++ src/server_config.c | 39 ++++++++++++++----- src/session_server.c | 18 --------- src/session_server.h | 14 ------- 5 files changed, 51 insertions(+), 58 deletions(-) diff --git a/doc/libnetconf.doc b/doc/libnetconf.doc index 20be760f..c4d7353a 100644 --- a/doc/libnetconf.doc +++ b/doc/libnetconf.doc @@ -289,8 +289,6 @@ * determined by the context used when accepting new NETCONF sessions. Few capabilities that * cannot be learnt from the context are set with separate functions * ::nc_server_set_capab_withdefaults() and generally ::nc_server_set_capability(). - * Timeout for receiving the _hello_ message on a new session can be set - * by ::nc_server_set_hello_timeout(). * * Context does not only determine server modules, but its overall * functionality as well. For every RPC the server should support, @@ -310,7 +308,6 @@ * * - ::nc_server_set_capab_withdefaults() * - ::nc_server_set_capability() - * - ::nc_server_set_hello_timeout() * * Server Configuration * === @@ -701,8 +698,8 @@ * You can adjust active and inactive read timeout using `cmake` variables. * For details look into `README.md`. * - * API Functions - * ------------- + * Configurable timeouts + * --------------------- * * Once a new connection is established including transport protocol negotiations, * _hello_ message is exchanged. You can set how long will the server wait for @@ -712,19 +709,10 @@ * To free up some resources, it is possible to adjust the maximum idle period * of a session before it is disconnected. In _Call Home_, for both a persistent * and periodic connection can this idle timeout be specified separately for each - * client using corresponding functions. Unlike other timeouts, the idle timeout - * can only be set via applying configuration data. - * - * Lastly, SSH user authentication timeout can be also modified. It is the time + * client. Lastly, SSH user authentication timeout can be also modified. It is the time * a client has to successfully authenticate after connecting before it is disconnected. * - * Functions List - * -------------- - * - * Available in __nc_server.h__. - * - * - ::nc_server_set_hello_timeout() - * - ::nc_server_get_hello_timeout() + * These timeouts can be toggled by applying corresponding configuration data. */ /** diff --git a/modules/libnetconf2-netconf-server@2023-09-07.yang b/modules/libnetconf2-netconf-server@2023-09-07.yang index 2f9d26fa..9708c547 100644 --- a/modules/libnetconf2-netconf-server@2023-09-07.yang +++ b/modules/libnetconf2-netconf-server@2023-09-07.yang @@ -240,6 +240,24 @@ module libnetconf2-netconf-server { https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD"; } + augment "/ncs:netconf-server" { + leaf hello-timeout { + type uint16; + default 60; + description + "Represents the maximum number of seconds the server will wait for receiving a hello message."; + } + } + + augment "/ncs:netconf-server" { + leaf idle-timeout { + type uint16; + default 0; + description + "Represents the maximum number of seconds a NETCONF session may remain idle. The value of 0 represents indefinitely."; + } + } + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { leaf auth-attempts { type uint16; diff --git a/src/server_config.c b/src/server_config.c index 328367ba..63bf0c10 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -1155,6 +1155,22 @@ nc_server_config_ch(const struct lyd_node *node, NC_OPERATION op) return 0; } +/* default leaf */ +static int +nc_server_config_hello_timeout(const struct lyd_node *node, NC_OPERATION op) +{ + assert(!strcmp(LYD_NAME(node), "hello-timeout")); + + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + server_opts.hello_timeout = strtoul(lyd_get_value(node), NULL, 10); + } else { + /* default value */ + server_opts.hello_timeout = 60; + } + + return 0; +} + /* default leaf */ static int nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op) @@ -1163,14 +1179,7 @@ nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "idle-timeout")); - if (is_listen(node)) { - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10); - } else { - /* default value */ - server_opts.idle_timeout = 180; - } - } else { + if (is_ch(node)) { /* call-home idle timeout */ if (nc_server_config_get_ch_client_with_lock(node, &ch_client)) { /* to avoid unlock on fail */ @@ -1184,6 +1193,14 @@ nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op) } nc_ch_client_unlock(ch_client); + } else { + /* whole server idle timeout */ + if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10); + } else { + /* default value */ + server_opts.idle_timeout = 0; + } } return 0; @@ -4207,8 +4224,8 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION ret = nc_server_config_listen(node, op); } else if (!strcmp(name, "call-home")) { ret = nc_server_config_ch(node, op); - } else if (!strcmp(name, "idle-timeout")) { - ret = nc_server_config_idle_timeout(node, op); + } else if (!strcmp(name, "hello-timeout")) { + ret = nc_server_config_hello_timeout(node, op); } else if (!strcmp(name, "endpoint")) { ret = nc_server_config_endpoint(node, op); } else if (!strcmp(name, "unix-socket")) { @@ -4309,6 +4326,8 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION ret = nc_server_config_period(node, op); } else if (!strcmp(name, "anchor-time")) { ret = nc_server_config_anchor_time(node, op); + } else if (!strcmp(name, "idle-timeout")) { + ret = nc_server_config_idle_timeout(node, op); } else if (!strcmp(name, "reconnect-strategy")) { ret = nc_server_config_reconnect_strategy(node, op); } else if (!strcmp(name, "start-with")) { diff --git a/src/session_server.c b/src/session_server.c index 7e37cb07..be53450f 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -959,24 +959,6 @@ nc_server_set_content_id_clb(char *(*content_id_clb)(void *user_data), void *use server_opts.content_id_data_free = free_user_data; } -API void -nc_server_set_hello_timeout(uint16_t hello_timeout) -{ - server_opts.hello_timeout = hello_timeout; -} - -API uint16_t -nc_server_get_hello_timeout(void) -{ - return server_opts.hello_timeout; -} - -API uint16_t -nc_server_get_idle_timeout(void) -{ - return server_opts.idle_timeout; -} - API NC_MSG_TYPE nc_accept_inout(int fdin, int fdout, const char *username, const struct ly_ctx *ctx, struct nc_session **session) { diff --git a/src/session_server.h b/src/session_server.h index 660badab..d9486f08 100644 --- a/src/session_server.h +++ b/src/session_server.h @@ -199,20 +199,6 @@ int nc_server_set_capability(const char *value); void nc_server_set_content_id_clb(char *(*content_id_clb)(void *user_data), void *user_data, void (*free_user_data)(void *user_data)); -/** - * @brief Set server timeout for receiving a hello message. - * - * @param[in] hello_timeout Hello message timeout. 0 for infinite waiting. - */ -void nc_server_set_hello_timeout(uint16_t hello_timeout); - -/** - * @brief get server timeout for receiving a hello message. - * - * @return Hello message timeout, 0 is infinite. - */ -uint16_t nc_server_get_hello_timeout(void); - /** * @brief Get all the server capabilities including all the schemas. * From 27b81b07beb7e8ffcf16f5db8abfaa0eea49b867 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 19 Oct 2023 15:21:52 +0200 Subject: [PATCH 097/134] config UPDATE remove nonessential api functions --- doc/libnetconf.doc | 85 +--- src/server_config.h | 655 +------------------------------ src/server_config_util_ssh.c | 594 ---------------------------- src/server_config_util_tls.c | 624 ++--------------------------- tests/test_auth.c | 3 +- tests/test_ch.c | 6 +- tests/test_crl.c | 26 +- tests/test_endpt_share_clients.c | 8 +- tests/test_ks_ts.c | 2 +- tests/test_runtime_changes.c | 87 +--- tests/test_tls.c | 14 +- 11 files changed, 97 insertions(+), 2007 deletions(-) diff --git a/doc/libnetconf.doc b/doc/libnetconf.doc index c4d7353a..9a788a4d 100644 --- a/doc/libnetconf.doc +++ b/doc/libnetconf.doc @@ -402,15 +402,11 @@ * - ::nc_server_config_del_ssh_hostkey() * - ::nc_server_config_add_ssh_keystore_ref() * - ::nc_server_config_del_ssh_keystore_ref() - * - ::nc_server_config_add_ssh_auth_attempts() - * - ::nc_server_config_add_ssh_auth_timeout() * * - ::nc_server_config_add_ssh_user_pubkey() * - ::nc_server_config_del_ssh_user_pubkey() * - ::nc_server_config_add_ssh_user_password() * - ::nc_server_config_del_ssh_user_password() - * - ::nc_server_config_add_ssh_user_none() - * - ::nc_server_config_del_ssh_user_none() * - ::nc_server_config_add_ssh_user_interactive() * - ::nc_server_config_del_ssh_user_interactive() * - ::nc_server_config_del_ssh_user() @@ -419,16 +415,6 @@ * - ::nc_server_config_add_ssh_endpoint_client_ref() * - ::nc_server_config_del_ssh_endpoint_client_ref() * - * - ::nc_server_config_add_ssh_host_key_algs() - * - ::nc_server_config_del_ssh_host_key_alg() - * - ::nc_server_config_add_ssh_key_exchange_algs() - * - ::nc_server_config_del_ssh_key_exchange_alg() - * - ::nc_server_config_add_ssh_encryption_algs() - * - ::nc_server_config_del_ssh_encryption_alg() - * - ::nc_server_config_add_ssh_mac_algs() - * - ::nc_server_config_del_ssh_mac_alg() - * - * * TLS * === * @@ -437,7 +423,7 @@ * options that TLS uses to derive usernames from client certificates. * * If you wish to listen on a TLS endpoint, you need to configure the endpoint's - * server certificate (see ::nc_server_config_add_tls_server_certificate()). + * server certificate (see ::nc_server_config_add_tls_server_cert()). * * To accept client certificates, they must first be considered trusted. * For each TLS endpoint you may configure two types of client certificates. @@ -454,43 +440,31 @@ * * There are some further options. For example you can configure the TLS * version and ciphers to be used. You may also choose to use a Certificate - * Revoke List. There are three options, ::nc_server_config_add_tls_crl_path() - * attempts to get the list of revoked certificates from a file. ::nc_server_config_add_tls_crl_url() - * attempts to download the list from the given URL. Lastly, ::nc_server_config_add_tls_crl_cert_ext() - * attempts to download the CRLs from URLs specified in the extension fields of the configured certificates. + * Revocation List. * * Functions List * -------------- * * Available in __nc_server.h__. * - * - ::nc_server_config_add_tls_server_certificate() - * - ::nc_server_config_del_tls_server_certificate() + * - ::nc_server_config_add_tls_server_cert() + * - ::nc_server_config_del_tls_server_cert() * - ::nc_server_config_add_tls_keystore_ref() * - ::nc_server_config_del_tls_keystore_ref() * - * - ::nc_server_config_add_tls_client_certificate() - * - ::nc_server_config_del_tls_client_certificate() + * - ::nc_server_config_add_tls_client_cert() + * - ::nc_server_config_del_tls_client_cert() * - ::nc_server_config_add_tls_client_cert_truststore_ref() * - ::nc_server_config_del_tls_client_cert_truststore_ref() - * - ::nc_server_config_add_tls_client_ca() - * - ::nc_server_config_del_tls_client_ca() - * - ::nc_server_config_add_tls_client_ca_truststore_ref() - * - ::nc_server_config_del_tls_client_ca_truststore_ref() + * - ::nc_server_config_add_tls_ca_cert() + * - ::nc_server_config_del_tls_ca_cert() + * - ::nc_server_config_add_tls_ca_cert_truststore_ref() + * - ::nc_server_config_del_tls_ca_cert_truststore_ref() * - ::nc_server_config_add_tls_endpoint_client_ref() * - ::nc_server_config_del_tls_endpoint_client_ref() * - ::nc_server_config_add_tls_ctn() * - ::nc_server_config_del_tls_ctn() * - * - ::nc_server_config_add_tls_version() - * - ::nc_server_config_del_tls_version() - * - ::nc_server_config_add_tls_ciphers() - * - ::nc_server_config_del_tls_cipher() - * - ::nc_server_config_add_tls_crl_path() - * - ::nc_server_config_add_tls_crl_url() - * - ::nc_server_config_add_tls_crl_cert_ext() - * - ::nc_server_config_del_tls_crl() - * * FD * == * @@ -541,51 +515,30 @@ * - ::nc_server_config_del_ch_ssh_hostkey() * - ::nc_server_config_add_ch_ssh_keystore_ref() * - ::nc_server_config_del_ch_ssh_keystore_ref() - * - ::nc_server_config_add_ch_ssh_auth_attempts() - * - ::nc_server_config_add_ch_ssh_auth_timeout() * - ::nc_server_config_add_ch_ssh_user_pubkey() * - ::nc_server_config_del_ch_ssh_user_pubkey() * - ::nc_server_config_add_ch_ssh_user_password() * - ::nc_server_config_del_ch_ssh_user_password() - * - ::nc_server_config_add_ch_ssh_user_none() - * - ::nc_server_config_del_ch_ssh_user_none() * - ::nc_server_config_add_ch_ssh_user_interactive() * - ::nc_server_config_del_ch_ssh_user_interactive() * - ::nc_server_config_del_ch_ssh_user() * - ::nc_server_config_add_ch_ssh_truststore_ref() * - ::nc_server_config_del_ch_ssh_truststore_ref() - * - ::nc_server_config_add_ch_ssh_host_key_algs() - * - ::nc_server_config_del_ch_ssh_host_key_alg() - * - ::nc_server_config_add_ch_ssh_key_exchange_algs() - * - ::nc_server_config_del_ch_ssh_key_exchange_alg() - * - ::nc_server_config_add_ch_ssh_encryption_algs() - * - ::nc_server_config_del_ch_ssh_encryption_alg() - * - ::nc_server_config_add_ch_ssh_mac_algs() - * - ::nc_server_config_del_ch_ssh_mac_alg() - * - * - ::nc_server_config_add_ch_tls_server_certificate() - * - ::nc_server_config_del_ch_tls_server_certificate() + * + * - ::nc_server_config_add_ch_tls_server_cert() + * - ::nc_server_config_del_ch_tls_server_cert() * - ::nc_server_config_add_ch_tls_keystore_ref() * - ::nc_server_config_del_ch_tls_keystore_ref() - * - ::nc_server_config_add_ch_tls_client_certificate() - * - ::nc_server_config_del_ch_tls_client_certificate() + * - ::nc_server_config_add_ch_tls_client_cert() + * - ::nc_server_config_del_ch_tls_client_cert() * - ::nc_server_config_add_ch_tls_client_cert_truststore_ref() * - ::nc_server_config_del_ch_tls_client_cert_truststore_ref() - * - ::nc_server_config_add_ch_tls_client_ca() - * - ::nc_server_config_del_ch_tls_client_ca() - * - ::nc_server_config_add_ch_tls_client_ca_truststore_ref() - * - ::nc_server_config_del_ch_tls_client_ca_truststore_ref() + * - ::nc_server_config_add_ch_tls_ca_cert() + * - ::nc_server_config_del_ch_tls_ca_cert() + * - ::nc_server_config_add_ch_tls_ca_cert_truststore_ref() + * - ::nc_server_config_del_ch_tls_ca_cert_truststore_ref() * - ::nc_server_config_add_ch_tls_ctn() * - ::nc_server_config_del_ch_tls_ctn() - * - ::nc_server_config_add_ch_tls_version() - * - ::nc_server_config_del_ch_tls_version() - * - ::nc_server_config_add_ch_tls_ciphers() - * - ::nc_server_config_del_ch_tls_cipher() - * - ::nc_server_config_add_ch_tls_crl_path() - * - ::nc_server_config_add_ch_tls_crl_url() - * - ::nc_server_config_add_ch_tls_crl_cert_ext() - * - ::nc_server_config_del_ch_tls_crl() - * * * Connecting And Cleanup * ====================== diff --git a/src/server_config.h b/src/server_config.h index d1480760..f0bc71cd 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -339,36 +339,6 @@ int nc_server_config_add_ssh_keystore_ref(const struct ly_ctx *ctx, const char * 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 the maximum amount of failed SSH authentication attempts. - * - * @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] auth_attempts Maximum amount of failed SSH authentication attempts after which a - * client is disconnected. The default value is 3. - * @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_auth_attempts(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_attempts, - struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for an SSH authentication timeout. - * - * @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] auth_timeout Maximum amount of time in seconds after which the authentication is deemed - * unsuccessful. The default value is 10. - * @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_auth_timeout(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_timeout, - struct lyd_node **config); - /** * @brief Creates new YANG configuration data nodes for an SSH user's public key authentication method. * @@ -427,32 +397,6 @@ int nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char 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 none 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,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_none(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config); - -/** - * @brief Deletes an SSH user's none authentication 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_none(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. * @@ -551,122 +495,6 @@ int nc_server_config_add_ssh_endpoint_client_ref(const struct ly_ctx *ctx, const */ int nc_server_config_del_ssh_endpoint_client_ref(const char *endpt_name, struct lyd_node **config); -/** - * @brief Creates new YANG configuration data nodes for host-key algorithms replacing any previous ones. - * - * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, - * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its host-key algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); - -/** - * @brief Deletes a hostkey algorithm from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] alg Optional algorithm to be deleted. - * If NULL, all of the hostkey algorithms 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_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for key exchange algorithms replacing any previous ones. - * - * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, - * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, - * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its key exchange algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); - -/** - * @brief Deletes a key exchange algorithm from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] alg Optional algorithm to be deleted. - * If NULL, all of the key exchange algorithms 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_key_exchange_alg(const char *endpt_name, const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for encryption algorithms replacing any previous ones. - * - * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc - * triple-des-cbc and none. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its encryption algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); - -/** - * @brief Deletes an encryption algorithm from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] alg Optional algorithm to be deleted. - * If NULL, all of the encryption algorithms 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_encryption_alg(const char *endpt_name, const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for mac algorithms replacing any previous ones. - * - * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. - * - * @param[in] ctx libyang context - * @param[in] endpt_name Arbitrary identifier of the endpoint. - * If an endpoint with this identifier already exists, its mac algorithms will be replaced. - * @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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of mac algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ssh_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...); - -/** - * @brief Deletes a mac algorithm from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] alg Optional algorithm to be deleted. - * If NULL, all of the mac algorithms 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_mac_alg(const char *endpt_name, const char *alg, struct lyd_node **config); - /** * @} SSH Server Configuration */ @@ -688,13 +516,13 @@ int nc_server_config_del_ssh_mac_alg(const char *endpt_name, const char *alg, st * @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] certificate_path Path to the server's certificate file. + * @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_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path, - const char *pubkey_path, const char *certificate_path, struct lyd_node **config); +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. @@ -703,7 +531,7 @@ int nc_server_config_add_tls_server_certificate(const struct ly_ctx *ctx, const * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_tls_server_certificate(const char *endpt_name, struct lyd_node **config); +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. @@ -742,7 +570,7 @@ int nc_server_config_del_tls_keystore_ref(const char *endpt_name, struct lyd_nod * 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_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, +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); /** @@ -754,7 +582,7 @@ int nc_server_config_add_tls_client_certificate(const struct ly_ctx *ctx, const * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_tls_client_certificate(const char *endpt_name, const char *cert_name, struct lyd_node **config); +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. @@ -792,7 +620,7 @@ int nc_server_config_del_tls_client_cert_truststore_ref(const char *endpt_name, * 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_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, +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); /** @@ -804,7 +632,7 @@ int nc_server_config_add_tls_client_ca(const struct ly_ctx *ctx, const char *end * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_tls_client_ca(const char *endpt_name, const char *cert_name, struct lyd_node **config); +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. @@ -817,7 +645,7 @@ int nc_server_config_del_tls_client_ca(const char *endpt_name, const char *cert_ * 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_ca_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, +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); /** @@ -827,7 +655,7 @@ int nc_server_config_add_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_tls_client_ca_truststore_ref(const char *endpt_name, struct lyd_node **config); +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. @@ -885,122 +713,6 @@ int nc_server_config_add_tls_ctn(const struct ly_ctx *ctx, const char *endpt_nam */ int nc_server_config_del_tls_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config); -/** - * @brief Creates new YANG configuration data nodes for a TLS version. - * - * @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] tls_version TLS version to be used. Call this multiple times to set - * the accepted versions of the TLS protocol and let the client and server negotiate - * the given version. - * @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_version(const struct ly_ctx *ctx, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config); - -/** - * @brief Deletes a TLS version from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] tls_version TLS version to be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_tls_version(const char *endpt_name, NC_TLS_VERSION tls_version, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a TLS cipher. - * - * @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,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[in] cipher_count Number of following ciphers. - * @param[in] ... TLS ciphers. These ciphers MUST be in the format as listed in the - * iana-tls-cipher-suite-algs YANG model (lowercase and separated by dashes). Regardless - * of the TLS protocol version used, all of these ciphers will be tried and some of them - * might not be set (TLS handshake might fail then). For the list of supported ciphers see - * the OpenSSL documentation. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int cipher_count, ...); - -/** - * @brief Deletes a TLS cipher from the YANG data. - * - * @param[in] endpt_name Identifier of an existing endpoint. - * @param[in] cipher TLS cipher to be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_tls_cipher(const char *endpt_name, const char *cipher, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via a local file. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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] crl_path Path to a DER/PEM encoded CRL 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_crl_path(const struct ly_ctx *ctx, const char *endpt_name, - const char *crl_path, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via an URL. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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] crl_url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. - * The allowed protocols are all the protocols supported by CURL. - * @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_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *crl_url, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Certificate Revocation List via certificate extensions. - * - * The chain of configured Certificate Authorities will be examined. For each certificate in this chain all the - * CRLs from the URLs specified in their extension fields CRL Distribution Points will be downloaded and used. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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,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_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config); - -/** - * @brief Deletes all the CRL nodes 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_crl(const char *endpt_name, struct lyd_node **config); - /** * @} TLS Server Configuration */ @@ -1266,40 +978,6 @@ int nc_server_config_add_ch_ssh_keystore_ref(const struct ly_ctx *ctx, const cha 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 configuration data nodes for the maximum amount of failed Call Home SSH authentication attempts. - * - * @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] auth_attempts Maximum amount of failed SSH authentication attempts after which a - * client is disconnected. The default value is 3. - * @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_auth_attempts(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - uint16_t auth_attempts, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home SSH authentication timeout. - * - * @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] auth_timeout Maximum amount of time in seconds after which the authentication is deemed - * unsuccessful. The default value is 10. - * @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_auth_timeout(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - uint16_t auth_timeout, struct lyd_node **config); - /** * @brief Creates new YANG data nodes for a Call Home SSH user's public key authentication method. * @@ -1364,35 +1042,6 @@ int nc_server_config_add_ch_ssh_user_password(const struct ly_ctx *ctx, const ch 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 none 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,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_none(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 none authentication 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 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_none(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. * @@ -1470,138 +1119,6 @@ int nc_server_config_add_ch_ssh_truststore_ref(const struct ly_ctx *ctx, const c 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); -/** - * @brief Creates new YANG configuration data nodes for Call Home host-key algorithms replacing any previous ones. - * - * Supported algorithms are: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, - * rsa-sha2-512, rsa-sha2-256, ssh-rsa and ssh-dss. - * - * @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,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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of host-key algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); - -/** - * @brief Deletes a Call Home hostkey algorithm 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] alg Optional algorithm to be deleted. - * If NULL, all of the hostkey algorithms 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_ch_ssh_host_key_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for Call Home key exchange algorithms replacing any previous ones. - * - * Supported algorithms are: diffie-hellman-group-exchange-sha1, curve25519-sha256, ecdh-sha2-nistp256, - * ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group18-sha512, diffie-hellman-group16-sha512, - * diffie-hellman-group-exchange-sha256 and diffie-hellman-group14-sha256. - * - * @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,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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of key exchange algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); - -/** - * @brief Deletes a Call Home key exchange algorithm 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] alg Optional algorithm to be deleted. - * If NULL, all of the key exchange algorithms 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_ch_ssh_key_exchange_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for Call Home encryption algorithms replacing any previous ones. - * - * Supported algorithms are: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, blowfish-cbc - * triple-des-cbc and none. - * - * @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,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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of encryption algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); - -/** - * @brief Deletes a Call Home encryption algorithm 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] alg Optional algorithm to be deleted. - * If NULL, all of the encryption algorithms 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_ch_ssh_encryption_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for Call Home mac algorithms replacing any previous ones. - * - * Supported algorithms are: hmac-sha2-256, hmac-sha2-512 and hmac-sha1. - * - * @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,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[in] alg_count Number of following algorithms. - * @param[in] ... String literals of mac algorithms in a decreasing order of preference. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...); - -/** - * @brief Deletes a Call Home mac algorithm 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] alg Optional algorithm to be deleted. - * If NULL, all of the mac algorithms 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_ch_ssh_mac_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config); - /** * @} SSH Call Home Server Configuration */ @@ -1625,13 +1142,13 @@ int nc_server_config_del_ch_ssh_mac_alg(const char *client_name, const char *end * @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] certificate_path Path to the server's certificate file. + * @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_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *privkey_path, const char *pubkey_path, const char *certificate_path, struct lyd_node **config); +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. @@ -1641,7 +1158,7 @@ int nc_server_config_add_ch_tls_server_certificate(const struct ly_ctx *ctx, con * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_ch_tls_server_certificate(const char *client_name, const char *endpt_name, +int nc_server_config_del_ch_tls_server_cert(const char *client_name, const char *endpt_name, struct lyd_node **config); /** @@ -1687,7 +1204,7 @@ int nc_server_config_del_ch_tls_keystore_ref(const char *client_name, const char * 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_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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); /** @@ -1700,7 +1217,7 @@ int nc_server_config_add_ch_tls_client_certificate(const struct ly_ctx *ctx, con * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_ch_tls_client_certificate(const char *client_name, const char *endpt_name, +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); /** @@ -1745,7 +1262,7 @@ int nc_server_config_del_ch_tls_client_cert_truststore_ref(const char *client_na * 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_ca(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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); /** @@ -1758,7 +1275,7 @@ int nc_server_config_add_ch_tls_client_ca(const struct ly_ctx *ctx, const char * * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_ch_tls_client_ca(const char *client_name, const char *endpt_name, +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); /** @@ -1774,7 +1291,7 @@ int nc_server_config_del_ch_tls_client_ca(const char *client_name, const char *e * 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_ca_truststore_ref(const struct ly_ctx *ctx, const char *client_name, +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); /** @@ -1785,7 +1302,7 @@ int nc_server_config_add_ch_tls_client_ca_truststore_ref(const struct ly_ctx *ct * @param[in,out] config Modified configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_del_ch_tls_client_ca_truststore_ref(const char *client_name, const char *endpt_name, +int nc_server_config_del_ch_tls_ca_cert_truststore_ref(const char *client_name, const char *endpt_name, struct lyd_node **config); /** @@ -1821,138 +1338,6 @@ int nc_server_config_add_ch_tls_ctn(const struct ly_ctx *ctx, const char *client int nc_server_config_del_ch_tls_ctn(const char *client_name, const char *endpt_name, uint32_t id, struct lyd_node **config); -/** - * @brief Creates new YANG configuration data nodes for a Call Home TLS version. - * - * @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] tls_version TLS version to be used. Call this multiple times to set the accepted versions - * of the TLS protocol and let the client and server negotiate the given version. - * @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_version(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config); - -/** - * @brief Deletes a TLS version 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] tls_version TLS version to be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_ch_tls_version(const char *client_name, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home TLS cipher. - * - * @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,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[in] cipher_count Number of following ciphers. - * @param[in] ... TLS ciphers. These ciphers MUST be in the format as listed in the - * iana-tls-cipher-suite-algs YANG model (lowercase and separated by dashes). Regardless - * of the TLS protocol version used, all of these ciphers will be tried and some of them - * might not be set (TLS handshake might fail then). For the list of supported ciphers see - * the OpenSSL documentation. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_add_ch_tls_ciphers(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int cipher_count, ...); - -/** - * @brief Deletes a Call Home TLS cipher 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] cipher TLS cipher to be deleted. - * @param[in,out] config Modified configuration YANG data tree. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_del_ch_tls_cipher(const char *client_name, const char *endpt_name, - const char *cipher, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via a local file. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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] crl_path Path to a DER/PEM encoded CRL 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_crl_path(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *crl_path, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via an URL. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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] crl_url URL from which the CRL file will be downloaded. The file has to be in the DER or PEM format. - * The allowed protocols are all the protocols supported by CURL. - * @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_crl_url(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *crl_url, struct lyd_node **config); - -/** - * @brief Creates new YANG configuration data nodes for a Call Home Certificate Revocation List via certificate extensions. - * - * The chain of configured Certificate Authorities will be examined. For each certificate in this chain all the - * CRLs from the URLs specified in their extension fields CRL Distribution Points will be downloaded and used. - * - * Beware that you can choose up to one function between the three CRL alternatives on a given endpoint and calling - * this function will remove any CRL YANG nodes created by the other two functions. - * - * @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,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_crl_cert_ext(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config); - -/** - * @brief Deletes all the CRL nodes 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. - */ -int nc_server_config_del_ch_tls_crl(const char *client_name, const char *endpt_name, struct lyd_node **config); - /** * @} TLS Call Home Server Configuration */ diff --git a/src/server_config_util_ssh.c b/src/server_config_util_ssh.c index bcd9bd6d..d19dc771 100644 --- a/src/server_config_util_ssh.c +++ b/src/server_config_util_ssh.c @@ -258,108 +258,6 @@ nc_server_config_del_ch_ssh_keystore_ref(const char *client_name, const char *en "host-key[name='%s']/public-key/keystore-reference", client_name, endpt_name, hostkey_name); } -API int -nc_server_config_add_ssh_auth_attempts(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_attempts, - struct lyd_node **config) -{ - int ret = 0; - char *attempts_buf = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - /* uint to str */ - if (asprintf(&attempts_buf, "%u", auth_attempts) == -1) { - ERRMEM; - attempts_buf = NULL; - ret = 1; - goto cleanup; - } - - ret = nc_server_config_create(ctx, config, attempts_buf, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/libnetconf2-netconf-server:auth-attempts", endpt_name); - -cleanup: - free(attempts_buf); - return ret; -} - -API int -nc_server_config_add_ssh_auth_timeout(const struct ly_ctx *ctx, const char *endpt_name, uint16_t auth_timeout, - struct lyd_node **config) -{ - int ret = 0; - char *timeout_buf = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - /* uint to str */ - if (asprintf(&timeout_buf, "%u", auth_timeout) == -1) { - ERRMEM; - timeout_buf = NULL; - ret = 1; - goto cleanup; - } - - ret = nc_server_config_create(ctx, config, timeout_buf, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/libnetconf2-netconf-server:auth-timeout", endpt_name); - -cleanup: - free(timeout_buf); - return ret; -} - -API int -nc_server_config_add_ch_ssh_auth_attempts(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - uint16_t auth_attempts, struct lyd_node **config) -{ - int ret = 0; - char *attempts_buf = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); - - /* uint to str */ - if (asprintf(&attempts_buf, "%u", auth_attempts) == -1) { - ERRMEM; - attempts_buf = NULL; - ret = 1; - goto cleanup; - } - - ret = nc_server_config_create(ctx, config, attempts_buf, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "libnetconf2-netconf-server:auth-attempts", client_name, endpt_name); - -cleanup: - free(attempts_buf); - return ret; -} - -API int -nc_server_config_add_ch_ssh_auth_timeout(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - uint16_t auth_timeout, struct lyd_node **config) -{ - int ret = 0; - char *timeout_buf = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); - - /* uint to str */ - if (asprintf(&timeout_buf, "%u", auth_timeout) == -1) { - ERRMEM; - timeout_buf = NULL; - ret = 1; - goto cleanup; - } - - ret = nc_server_config_create(ctx, config, timeout_buf, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "libnetconf2-netconf-server:auth-timeout", client_name, endpt_name); - -cleanup: - free(timeout_buf); - return ret; -} - static int _nc_server_config_add_ssh_user_pubkey(const struct ly_ctx *ctx, const char *tree_path, const char *pubkey_path, struct lyd_node **config) @@ -615,47 +513,6 @@ nc_server_config_del_ch_ssh_user_password(const char *client_name, const char *e "users/user[name='%s']/password", client_name, endpt_name, user_name); } -API int -nc_server_config_add_ssh_user_none(const struct ly_ctx *ctx, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, config, 1); - - return nc_server_config_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/none", endpt_name, user_name); -} - -API int -nc_server_config_add_ch_ssh_user_none(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, config, 1); - - return nc_server_config_create(ctx, config, NULL, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/none", client_name, endpt_name, user_name); -} - -API int -nc_server_config_del_ssh_user_none(const char *endpt_name, const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1); - - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" - "ssh-server-parameters/client-authentication/users/user[name='%s']/none", endpt_name, user_name); -} - -API int -nc_server_config_del_ch_ssh_user_none(const char *client_name, const char *endpt_name, - const char *user_name, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1); - - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']/none", client_name, endpt_name, user_name); -} - static int _nc_server_config_add_ssh_user_interactive(const struct ly_ctx *ctx, const char *tree_path, const char *pam_config_name, const char *pam_config_dir, struct lyd_node **config) @@ -882,454 +739,3 @@ nc_server_config_del_ch_ssh_truststore_ref(const char *client_name, const char * "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/public-keys/truststore-reference", client_name, endpt_name, user_name); } - -static int -nc_server_config_ssh_transport_params_prep(const struct ly_ctx *ctx, const char *client_name, - const char *endpt_name, struct lyd_node *config, struct lyd_node **new_tree, struct lyd_node **alg_tree) -{ - int ret = 0; - char *tree_path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, new_tree, alg_tree, 1); - - /* prepare path */ - if (client_name) { - /* ch */ - ret = asprintf(&tree_path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/ssh/ssh-server-parameters/transport-params", client_name, endpt_name); - } else { - /* listen */ - ret = asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params", endpt_name); - } - if (ret == -1) { - ERRMEM; - tree_path = NULL; - ret = 1; - goto cleanup; - } - - /* create all the nodes in the path */ - ret = lyd_new_path2(config, ctx, tree_path, NULL, 0, 0, LYD_NEW_PATH_UPDATE, new_tree, alg_tree); - if (ret) { - ERR(NULL, "Creating new path to transport-params failed."); - goto cleanup; - } - - if (!*alg_tree) { - /* no new nodes added, set the path correctly for adding child nodes later */ - ret = lyd_find_path(config, tree_path, 0, alg_tree); - if (ret) { - goto cleanup; - } - } - -cleanup: - free(tree_path); - return ret; -} - -static int -nc_server_config_ssh_transport_params_create(const struct ly_ctx *ctx, NC_ALG_TYPE alg_type, int alg_count, va_list ap, - struct lyd_node *tree) -{ - int i, ret = 0; - char *alg, *alg_ident; - const char *module, *alg_path, *old_path; - struct lyd_node *old = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, tree, 1); - - /* get the correct module with the indentity base and the path in the ietf-netconf-server module */ - switch (alg_type) { - case NC_ALG_HOSTKEY: - module = "iana-ssh-public-key-algs"; - alg_path = "host-key/host-key-alg"; - old_path = "host-key"; - break; - case NC_ALG_KEY_EXCHANGE: - module = "iana-ssh-key-exchange-algs"; - alg_path = "key-exchange/key-exchange-alg"; - old_path = "key-exchange"; - break; - case NC_ALG_ENCRYPTION: - module = "iana-ssh-encryption-algs"; - alg_path = "encryption/encryption-alg"; - old_path = "encryption"; - break; - case NC_ALG_MAC: - module = "iana-ssh-mac-algs"; - alg_path = "mac/mac-alg"; - old_path = "mac"; - break; - default: - ret = 1; - ERR(NULL, "Unknown algorithm type."); - goto cleanup; - } - - /* delete all older algorithms (if any) se they can be replaced by the new ones */ - lyd_find_path(tree, old_path, 0, &old); - if (old) { - lyd_free_tree(old); - } - - for (i = 0; i < alg_count; i++) { - alg = va_arg(ap, char *); - - if (asprintf(&alg_ident, "%s:%s", module, alg) == -1) { - ERRMEM; - ret = 1; - goto cleanup; - } - - /* create the leaf list */ - ret = lyd_new_path(tree, ctx, alg_path, alg_ident, 0, NULL); - if (ret) { - ERR(NULL, "Creating new algorithm leaf-list failed."); - free(alg_ident); - goto cleanup; - } - - free(alg_ident); - alg_ident = NULL; - } - -cleanup: - return ret; -} - -static int -nc_server_config_ssh_transport_params(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - NC_ALG_TYPE alg_type, int alg_count, va_list ap, struct lyd_node **config) -{ - int ret = 0; - struct lyd_node *new_tree, *alg_tree; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - /* prepare the tree for appending child nodes (the params) */ - ret = nc_server_config_ssh_transport_params_prep(ctx, client_name, endpt_name, *config, &new_tree, &alg_tree); - if (ret) { - goto cleanup; - } - - if (!*config) { - *config = new_tree; - } - - /* create the child nodes */ - ret = nc_server_config_ssh_transport_params_create(ctx, alg_type, alg_count, ap, alg_tree); - if (ret) { - goto cleanup; - } - - /* add all default nodes */ - ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_add_ssh_host_key_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new hostkey algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_add_ch_ssh_host_key_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_HOSTKEY, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new hostkey algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_del_ssh_host_key_alg(const char *endpt_name, const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (alg) { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/host-key/" - "host-key-alg[.='iana-ssh-public-key-algs:%s']", endpt_name, alg); - } else { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/host-key", endpt_name); - } -} - -API int -nc_server_config_del_ch_ssh_host_key_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (alg) { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key/" - "host-key-alg[.='iana-ssh-public-key-algs:%s']", client_name, endpt_name, alg); - } else { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/host-key", client_name, endpt_name); - } -} - -API int -nc_server_config_add_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new key exchange algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_add_ch_ssh_key_exchange_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_KEY_EXCHANGE, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new key exchange algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_del_ssh_key_exchange_alg(const char *endpt_name, const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (alg) { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/key-exchange/" - "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", endpt_name, alg); - } else { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/key-exchange", endpt_name); - } -} - -API int -nc_server_config_del_ch_ssh_key_exchange_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (alg) { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange/" - "key-exchange-alg[.='iana-ssh-key-exchange-algs:%s']", client_name, endpt_name, alg); - } else { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/key-exchange", client_name, endpt_name); - } -} - -API int -nc_server_config_add_ssh_encryption_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new encryption algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_add_ch_ssh_encryption_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_ENCRYPTION, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new encryption algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_del_ssh_encryption_alg(const char *endpt_name, const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (alg) { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/encryption/" - "encryption-alg[.='iana-ssh-encryption-algs:%s']", endpt_name, alg); - } else { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/encryption", endpt_name); - } -} - -API int -nc_server_config_del_ch_ssh_encryption_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (alg) { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption/" - "encryption-alg[.='iana-ssh-encryption-algs:%s']", client_name, endpt_name, alg); - } else { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/encryption", client_name, endpt_name); - } -} - -API int -nc_server_config_add_ssh_mac_algs(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_ssh_transport_params(ctx, NULL, endpt_name, NC_ALG_MAC, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new mac algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_add_ch_ssh_mac_algs(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int alg_count, ...) -{ - int ret = 0; - va_list ap; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, alg_count, 1); - - va_start(ap, alg_count); - - ret = nc_server_config_ssh_transport_params(ctx, client_name, endpt_name, NC_ALG_MAC, alg_count, ap, config); - if (ret) { - ERR(NULL, "Creating new mac algorithms failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - return ret; -} - -API int -nc_server_config_del_ssh_mac_alg(const char *endpt_name, const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - if (alg) { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/mac/" - "mac-alg[.='iana-ssh-mac-algs:%s']", endpt_name, alg); - } else { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "ssh/ssh-server-parameters/transport-params/mac", endpt_name); - } -} - -API int -nc_server_config_del_ch_ssh_mac_alg(const char *client_name, const char *endpt_name, - const char *alg, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - if (alg) { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac/" - "mac-alg[.='iana-ssh-mac-algs:%s']", client_name, endpt_name, alg); - } else { - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/transport-params/mac", client_name, endpt_name); - } -} diff --git a/src/server_config_util_tls.c b/src/server_config_util_tls.c index 20837c24..0ee6b068 100644 --- a/src/server_config_util_tls.c +++ b/src/server_config_util_tls.c @@ -33,15 +33,15 @@ #include "session_p.h" static int -_nc_server_config_add_tls_server_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *privkey_path, - const char *pubkey_path, const char *certificate_path, struct lyd_node **config) +_nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *tree_path, const char *privkey_path, + const char *pubkey_path, const char *cert_path, struct lyd_node **config) { int ret = 0; char *privkey = NULL, *pubkey = NULL, *cert = NULL; NC_PRIVKEY_FORMAT privkey_type; const char *privkey_format, *pubkey_format = "ietf-crypto-types:subject-public-key-info-format"; - NC_CHECK_ARG_RET(NULL, ctx, tree_path, privkey_path, certificate_path, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, tree_path, privkey_path, cert_path, config, 1); /* get the keys as a string from the given files */ ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey, &privkey_type, &pubkey); @@ -51,9 +51,9 @@ _nc_server_config_add_tls_server_certificate(const struct ly_ctx *ctx, const cha } /* get cert data from file */ - ret = nc_server_config_util_read_certificate(certificate_path, &cert); + ret = nc_server_config_util_read_certificate(cert_path, &cert); if (ret) { - ERR(NULL, "Getting certificate from file \"%s\" failed.", certificate_path); + ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path); goto cleanup; } @@ -103,13 +103,13 @@ _nc_server_config_add_tls_server_certificate(const struct ly_ctx *ctx, const cha } API int -nc_server_config_add_tls_server_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path, - const char *pubkey_path, const char *certificate_path, struct lyd_node **config) +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) { int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, certificate_path, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, cert_path, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" "tls/tls-server-parameters/server-identity/certificate", endpt_name) == -1) { @@ -119,8 +119,8 @@ nc_server_config_add_tls_server_certificate(const struct ly_ctx *ctx, const char goto cleanup; } - ret = _nc_server_config_add_tls_server_certificate(ctx, path, privkey_path, pubkey_path, - certificate_path, config); + ret = _nc_server_config_add_tls_server_cert(ctx, path, privkey_path, pubkey_path, + cert_path, config); if (ret) { ERR(NULL, "Creating new TLS server certificate YANG data failed."); goto cleanup; @@ -132,7 +132,7 @@ nc_server_config_add_tls_server_certificate(const struct ly_ctx *ctx, const char } API int -nc_server_config_del_tls_server_certificate(const char *endpt_name, struct lyd_node **config) +nc_server_config_del_tls_server_cert(const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); @@ -141,13 +141,13 @@ nc_server_config_del_tls_server_certificate(const char *endpt_name, struct lyd_n } API int -nc_server_config_add_ch_tls_server_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *privkey_path, const char *pubkey_path, const char *certificate_path, struct lyd_node **config) +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) { int ret = 0; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, privkey_path, certificate_path, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, privkey_path, cert_path, config, 1); if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" @@ -158,8 +158,8 @@ nc_server_config_add_ch_tls_server_certificate(const struct ly_ctx *ctx, const c goto cleanup; } - ret = _nc_server_config_add_tls_server_certificate(ctx, path, privkey_path, pubkey_path, - certificate_path, config); + ret = _nc_server_config_add_tls_server_cert(ctx, path, privkey_path, pubkey_path, + cert_path, config); if (ret) { ERR(NULL, "Creating new CH TLS server certificate YANG data failed."); goto cleanup; @@ -171,7 +171,7 @@ nc_server_config_add_ch_tls_server_certificate(const struct ly_ctx *ctx, const c } API int -nc_server_config_del_ch_tls_server_certificate(const char *client_name, const char *endpt_name, +nc_server_config_del_ch_tls_server_cert(const char *client_name, const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); @@ -284,7 +284,7 @@ nc_server_config_del_ch_tls_keystore_ref(const char *client_name, const char *en } static int -_nc_server_config_add_tls_client_certificate(const struct ly_ctx *ctx, const char *tree_path, +_nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *tree_path, const char *cert_path, struct lyd_node **config) { int ret = 0; @@ -309,7 +309,7 @@ _nc_server_config_add_tls_client_certificate(const struct ly_ctx *ctx, const cha } API int -nc_server_config_add_tls_client_certificate(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, +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) { int ret = 0; @@ -325,7 +325,7 @@ nc_server_config_add_tls_client_certificate(const struct ly_ctx *ctx, const char goto cleanup; } - ret = _nc_server_config_add_tls_client_certificate(ctx, path, cert_path, config); + ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); if (ret) { ERR(NULL, "Creating new TLS client certificate YANG data failed."); goto cleanup; @@ -344,7 +344,7 @@ nc_server_config_add_tls_client_certificate(const struct ly_ctx *ctx, const char } API int -nc_server_config_del_tls_client_certificate(const char *endpt_name, const char *cert_name, struct lyd_node **config) +nc_server_config_del_tls_client_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); @@ -360,7 +360,7 @@ nc_server_config_del_tls_client_certificate(const char *endpt_name, const char * } API int -nc_server_config_add_ch_tls_client_certificate(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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) { int ret = 0; @@ -377,7 +377,7 @@ nc_server_config_add_ch_tls_client_certificate(const struct ly_ctx *ctx, const c goto cleanup; } - ret = _nc_server_config_add_tls_client_certificate(ctx, path, cert_path, config); + ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); if (ret) { ERR(NULL, "Creating new CH TLS client certificate YANG data failed."); goto cleanup; @@ -397,7 +397,7 @@ nc_server_config_add_ch_tls_client_certificate(const struct ly_ctx *ctx, const c } API int -nc_server_config_del_ch_tls_client_certificate(const char *client_name, const char *endpt_name, +nc_server_config_del_ch_tls_client_cert(const char *client_name, const char *endpt_name, const char *cert_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); @@ -486,7 +486,7 @@ nc_server_config_del_ch_tls_client_cert_truststore_ref(const char *client_name, } API int -nc_server_config_add_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, +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) { int ret = 0; @@ -502,7 +502,7 @@ nc_server_config_add_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_n goto cleanup; } - ret = _nc_server_config_add_tls_client_certificate(ctx, path, cert_path, config); + ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); if (ret) { ERR(NULL, "Creating new TLS client certificate authority YANG data failed."); goto cleanup; @@ -521,7 +521,7 @@ nc_server_config_add_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_n } API int -nc_server_config_del_tls_client_ca(const char *endpt_name, const char *cert_name, struct lyd_node **config) +nc_server_config_del_tls_ca_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); @@ -537,7 +537,7 @@ nc_server_config_del_tls_client_ca(const char *endpt_name, const char *cert_name } API int -nc_server_config_add_ch_tls_client_ca(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, +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) { int ret = 0; @@ -554,7 +554,7 @@ nc_server_config_add_ch_tls_client_ca(const struct ly_ctx *ctx, const char *clie goto cleanup; } - ret = _nc_server_config_add_tls_client_certificate(ctx, path, cert_path, config); + ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); if (ret) { ERR(NULL, "Creating new CH TLS client certificate authority YANG data failed."); goto cleanup; @@ -574,7 +574,7 @@ nc_server_config_add_ch_tls_client_ca(const struct ly_ctx *ctx, const char *clie } API int -nc_server_config_del_ch_tls_client_ca(const char *client_name, const char *endpt_name, +nc_server_config_del_ch_tls_ca_cert(const char *client_name, const char *endpt_name, const char *cert_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); @@ -591,7 +591,7 @@ nc_server_config_del_ch_tls_client_ca(const char *client_name, const char *endpt } API int -nc_server_config_add_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, +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) { int ret = 0; @@ -616,7 +616,7 @@ nc_server_config_add_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, cons } API int -nc_server_config_del_tls_client_ca_truststore_ref(const char *endpt_name, struct lyd_node **config) +nc_server_config_del_tls_ca_cert_truststore_ref(const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); @@ -625,7 +625,7 @@ nc_server_config_del_tls_client_ca_truststore_ref(const char *endpt_name, struct } API int -nc_server_config_add_ch_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *client_name, +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) { int ret = 0; @@ -652,7 +652,7 @@ nc_server_config_add_ch_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, c } API int -nc_server_config_del_ch_tls_client_ca_truststore_ref(const char *client_name, const char *endpt_name, +nc_server_config_del_ch_tls_ca_cert_truststore_ref(const char *client_name, const char *endpt_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); @@ -811,562 +811,6 @@ nc_server_config_del_ch_tls_ctn(const char *client_name, const char *endpt_name, } } -static const char * -nc_server_config_tlsversion2str(NC_TLS_VERSION version) -{ - switch (version) { - case NC_TLS_VERSION_10: - return "ietf-tls-common:tls10"; - case NC_TLS_VERSION_11: - return "ietf-tls-common:tls11"; - case NC_TLS_VERSION_12: - return "ietf-tls-common:tls12"; - case NC_TLS_VERSION_13: - return "ietf-tls-common:tls13"; - default: - ERR(NULL, "Unknown TLS version."); - return NULL; - } -} - -API int -nc_server_config_add_tls_version(const struct ly_ctx *ctx, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config) -{ - int ret = 0; - const char *version; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - /* version to str */ - version = nc_server_config_tlsversion2str(tls_version); - if (!version) { - ret = 1; - goto cleanup; - } - - ret = nc_server_config_create(ctx, config, version, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "hello-params/tls-versions/tls-version", endpt_name); - if (ret) { - ERR(NULL, "Creating new YANG data nodes for TLS version failed."); - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_add_ch_tls_version(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config) -{ - int ret = 0; - const char *version; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); - - /* version to str */ - version = nc_server_config_tlsversion2str(tls_version); - if (!version) { - ret = 1; - goto cleanup; - } - - ret = nc_server_config_create(ctx, config, version, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "hello-params/tls-versions/tls-version", client_name, endpt_name); - if (ret) { - ERR(NULL, "Creating new YANG data nodes for CH TLS version failed."); - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_del_tls_version(const char *endpt_name, NC_TLS_VERSION tls_version, struct lyd_node **config) -{ - int ret = 0; - const char *version; - - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - /* version to str */ - version = nc_server_config_tlsversion2str(tls_version); - if (!version) { - ret = 1; - goto cleanup; - } - - ret = nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/hello-params/tls-versions/tls-version[.='%s']", endpt_name, version); - -cleanup: - return ret; -} - -API int -nc_server_config_del_ch_tls_version(const char *client_name, const char *endpt_name, - NC_TLS_VERSION tls_version, struct lyd_node **config) -{ - int ret = 0; - const char *version; - - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - /* version to str */ - version = nc_server_config_tlsversion2str(tls_version); - if (!version) { - ret = 1; - goto cleanup; - } - - ret = nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/" - "tls-server-parameters/hello-params/tls-versions/tls-version[.='%s']", client_name, endpt_name, version); - -cleanup: - return ret; -} - -static int -_nc_server_config_add_tls_ciphers(const struct ly_ctx *ctx, const char *tree_path, - int cipher_count, va_list ap, struct lyd_node **config) -{ - int ret = 0, i; - struct lyd_node *old = NULL; - char *cipher = NULL, *cipher_ident = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, config, 1); - - /* delete all older algorithms (if any) se they can be replaced by the new ones */ - lyd_find_path(*config, tree_path, 0, &old); - if (old) { - lyd_free_tree(old); - } - - for (i = 0; i < cipher_count; i++) { - cipher = va_arg(ap, char *); - - if (asprintf(&cipher_ident, "iana-tls-cipher-suite-algs:%s", cipher) == -1) { - ERRMEM; - ret = 1; - goto cleanup; - } - - ret = nc_server_config_append(ctx, tree_path, "cipher-suite", cipher_ident, config); - if (ret) { - free(cipher_ident); - goto cleanup; - } - - free(cipher_ident); - cipher_ident = NULL; - } - -cleanup: - return ret; -} - -API int -nc_server_config_add_tls_ciphers(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config, - int cipher_count, ...) -{ - int ret = 0; - va_list ap; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cipher_count, config, 1); - - va_start(ap, cipher_count); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" - "tls-server-parameters/hello-params/cipher-suites", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_add_tls_ciphers(ctx, path, cipher_count, ap, config); - if (ret) { - ERR(NULL, "Creating new TLS cipher YANG data nodes failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - free(path); - return ret; -} - -API int -nc_server_config_add_ch_tls_ciphers(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config, int cipher_count, ...) -{ - int ret = 0; - va_list ap; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cipher_count, config, 1); - - va_start(ap, cipher_count); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/tls/tls-server-parameters/hello-params/cipher-suites", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_add_tls_ciphers(ctx, path, cipher_count, ap, config); - if (ret) { - ERR(NULL, "Creating new Call-Home TLS cipher YANG data nodes failed."); - goto cleanup; - } - -cleanup: - va_end(ap); - free(path); - return ret; -} - -API int -nc_server_config_del_tls_cipher(const char *endpt_name, const char *cipher, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, endpt_name, cipher, config, 1); - - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/hello-params/cipher-suites/" - "cipher-suite[.='iana-tls-cipher-suite-algs:%s']", endpt_name, cipher); -} - -API int -nc_server_config_del_ch_tls_cipher(const char *client_name, const char *endpt_name, - const char *cipher, struct lyd_node **config) -{ - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, cipher, config, 1); - - return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/hello-params/cipher-suites/" - "cipher-suite[.='iana-tls-cipher-suite-algs:%s']", client_name, endpt_name, cipher); -} - -static int -_nc_server_config_add_tls_crl_path(const struct ly_ctx *ctx, const char *tree_path, - const char *crl_path, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, crl_path, config, 1); - - /* create the crl path node */ - ret = nc_server_config_append(ctx, tree_path, "libnetconf2-netconf-server:crl-path", crl_path, config); - if (ret) { - goto cleanup; - } - - /* delete other choice nodes if they are present */ - ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-url", tree_path); - if (ret) { - goto cleanup; - } - ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_add_tls_crl_path(const struct ly_ctx *ctx, const char *endpt_name, - const char *crl_path, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, crl_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_add_tls_crl_path(ctx, path, crl_path, config); - if (ret) { - ERR(NULL, "Creating new CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_add_ch_tls_crl_path(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *crl_path, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, crl_path, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_add_tls_crl_path(ctx, path, crl_path, config); - if (ret) { - ERR(NULL, "Creating new CH CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -static int -_nc_server_config_add_tls_crl_url(const struct ly_ctx *ctx, const char *tree_path, - const char *crl_url, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, crl_url, config, 1); - - /* create the crl path node */ - ret = nc_server_config_append(ctx, tree_path, "libnetconf2-netconf-server:crl-url", crl_url, config); - if (ret) { - goto cleanup; - } - - /* delete other choice nodes if they are present */ - ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-path", tree_path); - if (ret) { - goto cleanup; - } - ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-cert-ext", tree_path); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_add_tls_crl_url(const struct ly_ctx *ctx, const char *endpt_name, const char *crl_url, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, crl_url, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_add_tls_crl_url(ctx, path, crl_url, config); - if (ret) { - ERR(NULL, "Creating new CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_add_ch_tls_crl_url(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - const char *crl_url, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, crl_url, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_add_tls_crl_url(ctx, path, crl_url, config); - if (ret) { - ERR(NULL, "Creating new CH CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -static int -_nc_server_config_add_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *tree_path, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, ctx, tree_path, config, 1); - - /* create the crl path node */ - ret = nc_server_config_append(ctx, tree_path, "libnetconf2-netconf-server:crl-cert-ext", NULL, config); - if (ret) { - goto cleanup; - } - - /* delete other choice nodes if they are present */ - ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-path", tree_path); - if (ret) { - goto cleanup; - } - ret = nc_server_config_check_delete(config, "%s/libnetconf2-netconf-server:crl-url", tree_path); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_add_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *endpt_name, struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_add_tls_crl_cert_ext(ctx, path, config); - if (ret) { - ERR(NULL, "Creating new CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_add_ch_tls_crl_cert_ext(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name, - struct lyd_node **config) -{ - int ret = 0; - char *path = NULL; - - NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, config, 1); - - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } - - ret = _nc_server_config_add_tls_crl_cert_ext(ctx, path, config); - if (ret) { - ERR(NULL, "Creating new CH CRL YANG data nodes failed."); - goto cleanup; - } - -cleanup: - free(path); - return ret; -} - -API int -nc_server_config_del_tls_crl(const char *endpt_name, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); - - ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-path", endpt_name); - if (ret) { - goto cleanup; - } - - ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-url", endpt_name); - if (ret) { - goto cleanup; - } - - ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-cert-ext", endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - -API int -nc_server_config_del_ch_tls_crl(const char *client_name, const char *endpt_name, struct lyd_node **config) -{ - int ret = 0; - - NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1); - - ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-path", client_name, endpt_name); - if (ret) { - goto cleanup; - } - - ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-url", client_name, endpt_name); - if (ret) { - goto cleanup; - } - - ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" - "endpoints/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-cert-ext", client_name, endpt_name); - if (ret) { - goto cleanup; - } - -cleanup: - return ret; -} - API 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) { diff --git a/tests/test_auth.c b/tests/test_auth.c index a7021800..70f5ba30 100644 --- a/tests/test_auth.c +++ b/tests/test_auth.c @@ -330,7 +330,8 @@ setup_f(void **state) ret = nc_server_config_add_ssh_user_password(ctx, "endpt", "test_pw", "testpw", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_add_ssh_user_none(ctx, "endpt", "test_none", &tree); + ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/ssh/ssh-server-parameters/" + "client-authentication/users/user[name='test_none']/none", NULL, 0, NULL); assert_int_equal(ret, 0); /* configure the server based on the data */ diff --git a/tests/test_ch.c b/tests/test_ch.c index a4d5f14d..558e29a2 100644 --- a/tests/test_ch.c +++ b/tests/test_ch.c @@ -404,15 +404,15 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* set call-home server certificate */ - ret = nc_server_config_add_ch_tls_server_certificate(ctx, "ch_tls", "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tls_tree); + ret = nc_server_config_add_ch_tls_server_cert(ctx, "ch_tls", "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tls_tree); assert_int_equal(ret, 0); /* set call-home client end entity certificate */ - ret = nc_server_config_add_ch_tls_client_certificate(ctx, "ch_tls", "endpt", "ee-cert", TESTS_DIR "/data/client.crt", &test_state->tls_tree); + ret = nc_server_config_add_ch_tls_client_cert(ctx, "ch_tls", "endpt", "ee-cert", TESTS_DIR "/data/client.crt", &test_state->tls_tree); assert_int_equal(ret, 0); /* set call-home client certificate authority certificate */ - ret = nc_server_config_add_ch_tls_client_ca(ctx, "ch_tls", "endpt", "ca-cert", TESTS_DIR "/data/serverca.pem", &test_state->tls_tree); + ret = nc_server_config_add_ch_tls_ca_cert(ctx, "ch_tls", "endpt", "ca-cert", TESTS_DIR "/data/serverca.pem", &test_state->tls_tree); assert_int_equal(ret, 0); /* set call-home CTN */ diff --git a/tests/test_crl.c b/tests/test_crl.c index 9b951edd..6cd6dc77 100644 --- a/tests/test_crl.c +++ b/tests/test_crl.c @@ -148,15 +148,15 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new server certificate data */ - ret = nc_server_config_add_tls_server_certificate(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_add_tls_server_cert(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); /* create new end entity client cert data */ - ret = nc_server_config_add_tls_client_certificate(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); + ret = nc_server_config_add_tls_client_cert(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); assert_int_equal(ret, 0); /* create new client ca data */ - ret = nc_server_config_add_tls_client_ca(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); + ret = nc_server_config_add_tls_ca_cert(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); assert_int_equal(ret, 0); /* create new cert-to-name */ @@ -165,27 +165,11 @@ setup_f(void **state) NC_TLS_CTN_SPECIFIED, "client", &tree); assert_int_equal(ret, 0); - /* limit TLS version to 1.3 */ - ret = nc_server_config_add_tls_version(ctx, "endpt", NC_TLS_VERSION_13, &tree); - assert_int_equal(ret, 0); - - /* set the TLS cipher */ - ret = nc_server_config_add_tls_ciphers(ctx, "endpt", &tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); - assert_int_equal(ret, 0); - - /* set this node, but it should be deleted by the next call, bcs only one choice node can be present */ - ret = nc_server_config_add_tls_crl_url(ctx, "endpt", "abc", &tree); - assert_int_equal(ret, 0); - /* set path to a CRL file */ - ret = nc_server_config_add_tls_crl_path(ctx, "endpt", TESTS_DIR "/data/crl.pem", &tree); + ret = lyd_new_path(tree, ctx, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/tls/tls-server-parameters/" + "client-authentication/libnetconf2-netconf-server:crl-path", TESTS_DIR "/data/crl.pem", 0, NULL); assert_int_equal(ret, 0); - /* check if the choice node was removed */ - ret = lyd_find_path(tree, "/ietf-netconf-server:netconf-server/listen/endpoint[name='endpt']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:crl-url", 0, NULL); - assert_int_not_equal(ret, 0); - /* configure the server based on the data */ ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); diff --git a/tests/test_endpt_share_clients.c b/tests/test_endpt_share_clients.c index 7966de1a..7099d77e 100644 --- a/tests/test_endpt_share_clients.c +++ b/tests/test_endpt_share_clients.c @@ -260,16 +260,16 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* create the first TLS endpoint with a single end entity client cert and a CTN entry */ - ret = nc_server_config_add_tls_server_certificate(ctx, "TLS_endpt_1", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_add_tls_server_cert(ctx, "TLS_endpt_1", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); ret = nc_server_config_add_address_port(ctx, "TLS_endpt_1", NC_TI_OPENSSL, "127.0.0.1", 10007, &tree); assert_int_equal(ret, 0); - ret = nc_server_config_add_tls_client_certificate(ctx, "TLS_endpt_1", "cert_client", TESTS_DIR "/data/client.crt", &tree); + ret = nc_server_config_add_tls_client_cert(ctx, "TLS_endpt_1", "cert_client", TESTS_DIR "/data/client.crt", &tree); assert_int_equal(ret, 0); - ret = nc_server_config_add_tls_client_ca(ctx, "TLS_endpt_1", "cert_ca", TESTS_DIR "/data/serverca.pem", &tree); + ret = nc_server_config_add_tls_ca_cert(ctx, "TLS_endpt_1", "cert_ca", TESTS_DIR "/data/serverca.pem", &tree); assert_int_equal(ret, 0); ret = nc_server_config_add_tls_ctn(ctx, "TLS_endpt_1", 1, @@ -278,7 +278,7 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* create the second TLS endpoint with a reference to the first endpoint */ - ret = nc_server_config_add_tls_server_certificate(ctx, "TLS_endpt_2", + ret = nc_server_config_add_tls_server_cert(ctx, "TLS_endpt_2", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); diff --git a/tests/test_ks_ts.c b/tests/test_ks_ts.c index 1e08a7ce..940f357c 100644 --- a/tests/test_ks_ts.c +++ b/tests/test_ks_ts.c @@ -272,7 +272,7 @@ setup_tls(void **state) assert_int_equal(ret, 0); /* new truststore ref for the client CA cert */ - ret = nc_server_config_add_tls_client_ca_truststore_ref(ctx, "endpt", "ca_cert_bag", &tree); + ret = nc_server_config_add_tls_ca_cert_truststore_ref(ctx, "endpt", "ca_cert_bag", &tree); assert_int_equal(ret, 0); /* new cert-to-name */ diff --git a/tests/test_runtime_changes.c b/tests/test_runtime_changes.c index 7c389ee4..53360c6d 100644 --- a/tests/test_runtime_changes.c +++ b/tests/test_runtime_changes.c @@ -240,11 +240,11 @@ test_nc_change_tls_srv_crt(void **state) test_state = *state; init_test_create_threads_tls(tids, state); - ret = nc_server_config_add_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/client.key", NULL, TESTS_DIR "/data/client.crt", &test_state->tree); + ret = nc_server_config_add_tls_server_cert(ctx, "endpt_tls", TESTS_DIR "/data/client.key", NULL, TESTS_DIR "/data/client.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - ret = nc_server_config_add_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); + ret = nc_server_config_add_tls_server_cert(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); @@ -264,11 +264,11 @@ test_nc_change_tls_client_crt(void **state) test_state = *state; init_test_create_threads_tls(tids, state); - ret = nc_server_config_add_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/server.crt", &test_state->tree); + ret = nc_server_config_add_tls_client_cert(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/server.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - ret = nc_server_config_add_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); + ret = nc_server_config_add_tls_client_cert(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); assert_int_equal(ret, 0); configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); @@ -305,54 +305,6 @@ test_nc_change_tls_ctn(void **state) } } -static void -test_nc_change_tls_version(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct test_state *test_state; - - assert_non_null(state); - test_state = *state; - init_test_create_threads_tls(tids, state); - - ret = nc_server_config_add_tls_version(ctx, "endpt_tls", NC_TLS_VERSION_11, &test_state->tree); - assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - - ret = nc_server_config_add_tls_version(ctx, "endpt_tls", NC_TLS_VERSION_13, &test_state->tree); - assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static void -test_nc_change_tls_ciphers(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct test_state *test_state; - - assert_non_null(state); - test_state = *state; - init_test_create_threads_tls(tids, state); - - ret = nc_server_config_add_tls_ciphers(ctx, "endpt_tls", &test_state->tree, 1, "tls-rsa-with-null-sha"); - assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - - ret = nc_server_config_add_tls_ciphers(ctx, "endpt_tls", &test_state->tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); - assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - static void test_nc_change_ssh_hostkey(void **state) { @@ -403,30 +355,6 @@ test_nc_change_ssh_usr_pubkey(void **state) } } -static void -test_nc_change_ssh_hostkey_algs(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct test_state *test_state; - - assert_non_null(state); - test_state = *state; - init_test_create_threads_ssh(tids, state); - - ret = nc_server_config_add_ssh_host_key_algs(ctx, "endpt_ssh", &test_state->tree, 1, "ssh-dss"); - assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_FAIL, NC_TEST_STATE_RUN); - - ret = nc_server_config_add_ssh_host_key_algs(ctx, "endpt_ssh", &test_state->tree, 1, "rsa-sha2-256"); - assert_int_equal(ret, 0); - configure(test_state, NC_TEST_EXPECT_OK, NC_TEST_STATE_END); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - static int setup_f(void **state) { @@ -461,11 +389,11 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new server certificate data */ - ret = nc_server_config_add_tls_server_certificate(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); + ret = nc_server_config_add_tls_server_cert(ctx, "endpt_tls", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &test_state->tree); assert_int_equal(ret, 0); /* create new end entity client cert data */ - ret = nc_server_config_add_tls_client_certificate(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); + ret = nc_server_config_add_tls_client_cert(ctx, "endpt_tls", "client_cert", TESTS_DIR "/data/client.crt", &test_state->tree); assert_int_equal(ret, 0); /* create new cert-to-name */ @@ -526,11 +454,8 @@ main(void) cmocka_unit_test_setup_teardown(test_nc_change_tls_srv_crt, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_change_tls_client_crt, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_change_tls_ctn, setup_f, teardown_f), - cmocka_unit_test_setup_teardown(test_nc_change_tls_version, setup_f, teardown_f), - cmocka_unit_test_setup_teardown(test_nc_change_tls_ciphers, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_change_ssh_hostkey, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_change_ssh_usr_pubkey, setup_f, teardown_f), - cmocka_unit_test_setup_teardown(test_nc_change_ssh_hostkey_algs, setup_f, teardown_f), }; setenv("CMOCKA_TEST_ABORT", "1", 1); diff --git a/tests/test_tls.c b/tests/test_tls.c index 7d84184d..542f7bdb 100644 --- a/tests/test_tls.c +++ b/tests/test_tls.c @@ -142,15 +142,15 @@ setup_f(void **state) assert_int_equal(ret, 0); /* create new server certificate data */ - ret = nc_server_config_add_tls_server_certificate(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); + ret = nc_server_config_add_tls_server_cert(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree); assert_int_equal(ret, 0); /* create new end entity client cert data */ - ret = nc_server_config_add_tls_client_certificate(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); + ret = nc_server_config_add_tls_client_cert(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree); assert_int_equal(ret, 0); /* create new client ca data */ - ret = nc_server_config_add_tls_client_ca(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); + ret = nc_server_config_add_tls_ca_cert(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree); assert_int_equal(ret, 0); /* create new cert-to-name */ @@ -159,14 +159,6 @@ setup_f(void **state) NC_TLS_CTN_SPECIFIED, "client", &tree); assert_int_equal(ret, 0); - /* limit TLS version to 1.3 */ - ret = nc_server_config_add_tls_version(ctx, "endpt", NC_TLS_VERSION_13, &tree); - assert_int_equal(ret, 0); - - /* set the TLS cipher */ - ret = nc_server_config_add_tls_ciphers(ctx, "endpt", &tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256"); - assert_int_equal(ret, 0); - /* configure the server based on the data */ ret = nc_server_config_setup_data(tree); assert_int_equal(ret, 0); From b0cc4210970f849beb714b924186178563753cf6 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 19 Oct 2023 15:51:16 +0200 Subject: [PATCH 098/134] session server ssh UPDATE support cleartext pw --- src/session_server_ssh.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index a65e77dc..d4bb528f 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -221,16 +221,16 @@ nc_server_ssh_set_pubkey_auth_clb(int (*pubkey_auth_clb)(const struct nc_session * @return non-zero if not a match. */ static int -auth_password_compare_pwd(const char *pass_hash, const char *pass_clear) +auth_password_compare_pwd(const char *stored_pw, const char *received_pw) { - char *new_pass_hash; + char *received_pw_hash = NULL; #ifdef HAVE_CRYPT_R struct crypt_data cdata; #endif - if (!pass_hash[0]) { - if (!pass_clear[0]) { + if (!stored_pw[0]) { + if (!received_pw[0]) { WRN(NULL, "User authentication successful with an empty password!"); return 0; } else { @@ -240,20 +240,24 @@ auth_password_compare_pwd(const char *pass_hash, const char *pass_clear) } } + if (!strncmp(stored_pw, "$0$", 3)) { + /* cleartext password, simply compare the values */ + return strcmp(stored_pw + 3, received_pw); + } + #ifdef HAVE_CRYPT_R cdata.initialized = 0; - new_pass_hash = crypt_r(pass_clear, pass_hash, &cdata); + received_pw_hash = crypt_r(received_pw, stored_pw, &cdata); #else pthread_mutex_lock(&crypt_lock); - new_pass_hash = crypt(pass_clear, pass_hash); + received_pw_hash = crypt(received_pw, stored_pw); pthread_mutex_unlock(&crypt_lock); #endif - - if (!new_pass_hash) { + if (!received_pw_hash) { return 1; } - return strcmp(new_pass_hash, pass_hash); + return strcmp(received_pw_hash, stored_pw); } static int From 5b209effa17858539a7b58de45549005d74563a1 Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 25 Oct 2023 11:10:58 +0200 Subject: [PATCH 099/134] messages_server UPDATE unify err arg print --- examples/README.md | 64 +++++++++++++---------- examples/client.c | 78 ++++++++++++++++++--------- examples/config.json | 97 ++++++++++++++++++++++++++++++++++ examples/config.xml | 119 ------------------------------------------ examples/example.h.in | 14 ----- examples/server.c | 82 +++++------------------------ src/messages_server.c | 4 +- 7 files changed, 200 insertions(+), 258 deletions(-) create mode 100644 examples/config.json delete mode 100644 examples/config.xml diff --git a/examples/README.md b/examples/README.md index 46d8e9a2..78565329 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,28 +1,36 @@ # libnetconf2 - examples -There are two examples `server` and `client` demonstrating a simple NETCONF server and client using libnetconf2 C library. This is an extensively documented example, which is trying to showcase the key parts of the libnetconf2 library in as simple way as possible. The library configuration is kept to the minimum just to achieve basic functionality. Two types of transport are supported in this example: _UNIX Socket_ and _SSH_ (password authentication only). In the `example.h` header there are the SSH listening IP address and port, username and password that can be edited. Both examples have the `-h` option that displays their usage. +There are two examples `server` and `client` demonstrating a simple NETCONF server and client using libnetconf2 C library. This is an extensively documented example, which is trying to showcase the key parts of the libnetconf2 library in a simple way. The library configuration is kept to the minimum just to achieve basic functionality. Two types of transport are supported in this example: _UNIX Socket_ and _SSH_. Both examples have the `-h` option that displays their usage. ## Server The example server provides `ietf-yang-library` state data that are returned as a reply to `get` RPC. In case an XPath filter is used it is properly applied on these data. If some unsupported parameters are specified, the server replies with a NETCONF error. +### Server Configuration +The server's default configuration can be found in the `config.json` file. The YANG data stored in this file define three endpoints - two for SSH and one for UNIX socket. +You can modify this configuration in any way you like, but you need to make sure that it is valid. + ## Example usage -### UNIX socket -#### Server +### Server First start the server: ``` -$ server -u ./example_socket +$ server ``` -Where `-u` means UNIX socket transport will be used and `./example_socket` is the path to the socket, where the socket will be listening. +The server will be started and configured per YANG data stored in the file `config.json`. A UNIX socket with the default address `/tmp/.ln2-unix-socket` will be created. +In addition to that two SSH endpoints with the addresses `127.0.0.1:10000` and `127.0.0.1:10001` will be listening. +This first endpoint has a single user that can authenticate with a password (which is set to `admin` by default). +The second endpoint has a single user that can authenticate with a publickey (the asymmetric key pair used is stored in `admin_key` and `admin_key.pub`). -#### Client -After the server has been run, in another terminal instance: +### Client +#### UNIX socket +After the server has been run, in another terminal instance, with the default configuration: ``` -$ client -u ./example_socket get "/ietf-yang-library:yang-library/module-set/module[name='ietf-netconf']" +$ client -u /tmp/.ln2-unix-socket get "/ietf-yang-library:yang-library/module-set/module[name='ietf-netconf']" ``` -In this case, `-u` means that a connection to an UNIX socket will be attemped, `./example_socket` is the path to the UNIX socket, `get` is the name of the RPC and `/ietf-yang-library:yang-library/module-set/module[name='ietf-netconf']` is the RPC's optional XPath filter. +In this case, `-u` means that a connection to an UNIX socket will be attemped and a path to the socket needs to be specified, that is `/tmp/ln2-unix-socket` by default. +The `get` parameter is the name of the RPC and `/ietf-yang-library:yang-library/module-set/module[name='ietf-netconf']` is the RPC's optional XPath filter. -#### Server output +##### Server output ``` -Using UNIX socket! <-- server created +Listening for new connections! <-- server created Connection established <-- client joined Received RPC: get-schema <-- name of the RPC @@ -47,7 +55,7 @@ Received RPC: ``` The server received five supported RPCs. First, the client attempts to obtain basic YANG modules using `get-schema`. Then, it retrieves all the `ietf-yang-library` data to be used for creating its context, which should ideally be the same as that of the server. Next the example `get` RPC is received and lastly `close-session` RPC terminates the connection. -#### Client output +##### Client output ``` @@ -76,22 +84,15 @@ The server received five supported RPCs. First, the client attempts to obtain ba ``` The client received a single `ietf-yang-library` module based on the used filter. -### _SSH_ -#### Server -``` -# server -s /home/user/.ssh/id_rsa -``` -Where `-s` means SSH transport will be used and the next argument `/home/user/.ssh/id_rsa` is the path to an SSH hostkey, which will be used for authentication. The SSH server has to be run as `root`, because the default listening port is 830, which cannot be bound otherwise. This port can be changed in the header file. -To generate an SSH key, you can use: -``` -$ ssh-keygen -``` -#### Client +#### SSH +After the server has been run, in another terminal instance, with the default configuration: ``` -$ client -s get-config candidate +$ client -p 10000 get-config candidate ``` -In this case, `-s` means that a connection via SSH will be attemped, `get-config` is the name of the RPC and `candidate` is the source datastore for the retrieved data of the get-config RPC. -#### Server output +In this case, `-p 10000` is the port to connect to. By default the endpoint with this port has a single authorized client that needs to authenticate with a password. +The parameter `get-config` is the name of the RPC and `candidate` is the source datastore for the retrieved data of the get-config RPC. + +##### Server output ``` Using SSH! Connection established @@ -114,11 +115,18 @@ Received RPC: Received RPC: close-session ``` -#### Client output + +##### Client output ``` admin@127.0.0.1 password: <-- prompts for password, type in 'admin' ``` -The _username_ and _password_ can be found and modified in the `example.h` header file. +The _username_ in the `example.h` header file. The _password_ is located in `config.json`. + +If you wish to connect to the SSH public key endpoint, you need to specify its port and the asymmetric key pair to use. +By default the command to connect would look like so: +``` +$ ./examples/client -p 10001 -P /home/roman/libnetconf2/examples/admin_key.pub -i /home/roman/libnetconf2/examples/admin_key get +``` diff --git a/examples/client.c b/examples/client.c index 7612239f..8295fb77 100644 --- a/examples/client.c +++ b/examples/client.c @@ -34,12 +34,14 @@ static void help_print() { printf("Example usage:\n" - " client -u ./unix_socket get\n" + " client get\n" "\n" " Available options:\n" " -h, --help\t \tPrint usage help.\n" - " -u, --unix\t\tConnect to a UNIX socket at the place specified by .\n" - " -s, --ssh\t\tConnect to a SSH server.\n\n" + " -p, --port\t\t\tSpecify the port to connect to.\n" + " -u, --unix-path\t\tConnect to a UNIX socket located at .\n" + " -P, --ssh-pubkey\t\tSet the path to an SSH Public key.\n" + " -i, --ssh-privkey\t\tSet the path to an SSH Private key.\n\n" " Available RPCs:\n" " get [xpath-filter]\t\t\t\t\t send a RPC with optional XPath filter\n" " get-config [datastore] [xpath-filter]\t\t send a RPC with optional XPath filter and datastore, the default datastore is \"running\" \n\n"); @@ -132,16 +134,19 @@ send_rpc(struct nc_session *session, NC_RPC_TYPE rpc_type, const char *param1, c int main(int argc, char **argv) { - int rc = 0, opt, connection_type = NONE; + int rc = 0, opt, port = 0; struct nc_session *session = NULL; const char *unix_socket_path = NULL, *rpc_parameter_1 = NULL, *rpc_parameter_2 = NULL; + const char *ssh_pubkey_path = NULL, *ssh_privkey_path = NULL; struct option options[] = { - {"help", no_argument, NULL, 'h'}, - {"unix", required_argument, NULL, 'u'}, - {"ssh", no_argument, NULL, 's'}, - {"debug", no_argument, NULL, 'd'}, - {NULL, 0, NULL, 0} + {"help", no_argument, NULL, 'h'}, + {"port", required_argument, NULL, 'p'}, + {"unix-path", required_argument, NULL, 'u'}, + {"ssh-pubkey", required_argument, NULL, 'P'}, + {"ssh-privkey", required_argument, NULL, 'i'}, + {"debug", no_argument, NULL, 'd'}, + {NULL, 0, NULL, 0} }; if (argc == 1) { @@ -154,23 +159,26 @@ main(int argc, char **argv) opterr = 0; - while ((opt = getopt_long(argc, argv, "hu:sd", options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "hp:u:P:i:d", options, NULL)) != -1) { switch (opt) { case 'h': help_print(); goto cleanup; + case 'p': + port = strtoul(optarg, NULL, 10); + break; + case 'u': unix_socket_path = optarg; - connection_type = UNIX; break; - case 's': - connection_type = SSH; - /* set the client SSH username to always be used when connecting to the server */ - if (nc_client_ssh_set_username(SSH_USERNAME)) { - ERR_MSG_CLEANUP("Couldn't set the SSH username\n"); - } + case 'P': + ssh_pubkey_path = optarg; + break; + + case 'i': + ssh_privkey_path = optarg; break; case 'd': @@ -187,18 +195,38 @@ main(int argc, char **argv) ERR_MSG_CLEANUP("Expected the name of RPC after options\n"); } + /* check invalid args combinations */ + if (unix_socket_path && port) { + ERR_MSG_CLEANUP("Both UNIX socket path and port specified. Please choose either SSH or UNIX.\n"); + } else if (unix_socket_path && (ssh_pubkey_path || ssh_privkey_path)) { + ERR_MSG_CLEANUP("Both UNIX socket path and a path to key(s) specified. Please choose either SSH or UNIX.\n"); + } else if ((port == 10001) && (!ssh_pubkey_path || !ssh_privkey_path)) { + ERR_MSG_CLEANUP("You need to specify both paths to private and public keys, if you want to connect to a publickey endpoint.\n"); + } else if ((port == 10000) && (ssh_pubkey_path || ssh_privkey_path)) { + ERR_MSG_CLEANUP("Public or private key specified, when connecting to the password endpoint.\n"); + } else if (!unix_socket_path && !port) { + ERR_MSG_CLEANUP("Neither UNIX socket or SSH specified.\n"); + } + /* connect to the server using the specified transport protocol */ - switch (connection_type) { - case UNIX: + if (unix_socket_path) { + /* it's UNIX socket */ session = nc_connect_unix(unix_socket_path, NULL); - break; + } else { + /* it must be SSH, so set the client SSH username to always be used when connecting to the server */ + if (nc_client_ssh_set_username(SSH_USERNAME)) { + ERR_MSG_CLEANUP("Couldn't set the SSH username\n"); + } - case SSH: - session = nc_connect_ssh(SSH_ADDRESS, SSH_PORT, NULL); - break; + if (ssh_pubkey_path && ssh_privkey_path) { + /* set the client's SSH keypair to be used for authentication if necessary */ + if (nc_client_ssh_add_keypair(ssh_pubkey_path, ssh_privkey_path)) { + ERR_MSG_CLEANUP("Couldn't set client's SSH keypair.\n"); + } + } - case NONE: - ERR_MSG_CLEANUP("Expected connection type (either SSH or UNIX)!\n"); + /* try to connect via SSH */ + session = nc_connect_ssh(SSH_ADDRESS, port, NULL); } if (!session) { ERR_MSG_CLEANUP("Couldn't connect to the server\n"); diff --git a/examples/config.json b/examples/config.json new file mode 100644 index 00000000..4eb80162 --- /dev/null +++ b/examples/config.json @@ -0,0 +1,97 @@ +{ + "ietf-netconf-server:netconf-server": { + "listen": { + "idle-timeout": 10, + "endpoint": [ + { + "name": "ssh-password-auth-endpt", + "ssh": { + "tcp-server-parameters": { + "local-address": "127.0.0.1", + "local-port": 10000 + }, + "ssh-server-parameters": { + "server-identity": { + "host-key": [ + { + "name": "key", + "public-key": { + "inline-definition": { + "public-key-format": "ietf-crypto-types:ssh-public-key-format", + "public-key": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDRIB2eNSRWU+HNWRUGKr76ghCLg8RaMlUCps9lBjnc6ggaJl2Q+TOLn8se2wAdK3lYBMz3dcqR+SlU7eB8wJAc=", + "private-key-format": "ietf-crypto-types:ec-private-key-format", + "cleartext-private-key": "MHcCAQEEICQ2fr9Jt2xluom0YQQ7HseE8YTo5reZRVcQENKUWOrooAoGCCqGSM49AwEHoUQDQgAENEgHZ41JFZT4c1ZFQYqvvqCEIuDxFoyVQKmz2UGOdzqCBomXZD5M4ufyx7bAB0reVgEzPd1ypH5KVTt4HzAkBw==" + } + } + } + ] + }, + "client-authentication": { + "users": { + "user": [ + { + "name": "admin", + "password": "$0$admin" + } + ] + } + } + } + } + }, + { + "name": "ssh-pubkey-auth-endpt", + "ssh": { + "tcp-server-parameters": { + "local-address": "127.0.0.1", + "local-port": 10001 + }, + "ssh-server-parameters": { + "server-identity": { + "host-key": [ + { + "name": "key", + "public-key": { + "inline-definition": { + "public-key-format": "ietf-crypto-types:ssh-public-key-format", + "public-key": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDRIB2eNSRWU+HNWRUGKr76ghCLg8RaMlUCps9lBjnc6ggaJl2Q+TOLn8se2wAdK3lYBMz3dcqR+SlU7eB8wJAc=", + "private-key-format": "ietf-crypto-types:ec-private-key-format", + "cleartext-private-key": "MHcCAQEEICQ2fr9Jt2xluom0YQQ7HseE8YTo5reZRVcQENKUWOrooAoGCCqGSM49AwEHoUQDQgAENEgHZ41JFZT4c1ZFQYqvvqCEIuDxFoyVQKmz2UGOdzqCBomXZD5M4ufyx7bAB0reVgEzPd1ypH5KVTt4HzAkBw==" + } + } + } + ] + }, + "client-authentication": { + "users": { + "user": [ + { + "name": "admin", + "public-keys": { + "inline-definition": { + "public-key": [ + { + "name": "admin_key.pub", + "public-key-format": "ietf-crypto-types:ssh-public-key-format", + "public-key": "AAAAC3NzaC1lZDI1NTE5AAAAIOr46rptg6BsWhO1JMomuh3cuCYmeuO6JfOUPs/YO35w" + } + ] + } + } + } + ] + } + } + } + } + }, + { + "name": "unix-socket-endpt", + "libnetconf2-netconf-server:unix-socket": { + "path": "/tmp/.ln2-unix-socket" + } + } + ] + } + } +} \ No newline at end of file diff --git a/examples/config.xml b/examples/config.xml deleted file mode 100644 index 2bf7598c..00000000 --- a/examples/config.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - 10 - - default-ssh - - - 127.0.0.1 - 830 - - - - - key - - - ct:ssh-public-key-format - MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr -97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeV -n6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FT -irzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6w -NmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCU -UGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrz -ARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rf -WZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKv -Ya1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3 -u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMa -OQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMh -jufl2qE2Q7fQIaav/1NqBVkCAwEAAQ== - ct:rsa-private-key-format - MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1V -ArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6al -wf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4g -fNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+Zc -zSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+d -KYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FK -tGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo -4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/f -t1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBT -oE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yV -ONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEA -AQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj -1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAH -X8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXB -RgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMk -cjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk -2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rED -MlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5 -R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuar -AhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNt -xZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2Rn -LkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH -/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+U -XA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmG -vWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+ -31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3 -ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRL -ZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7 -YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7v -IQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bf -JAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhg -W4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y -8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFy -fSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+ -N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/b -BY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu -8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SR -q7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu -3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJv -nwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcai -rBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM -3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4S -SBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinb -Tsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW -8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPo -Swr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JB -dOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/K -qDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8T -bstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o= - - - - - - - - admin - $6$xyz$WwFC0nTow5jwJwMYeOZItipYgZidye/O7Z2kxRP3cPttku.GHre0y/51bO2uJlRjQwLNRddSA5fuJG5X1F8Dd1 - - - - client - ct:ssh-public-key-format - AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl - - - - - - - - - sshpka:rsa-sha2-512 - - - sshkea:curve25519-sha256 - - - sshea:aes256-ctr - - - sshma:hmac-sha2-512 - - - - - - - \ No newline at end of file diff --git a/examples/example.h.in b/examples/example.h.in index e195dda6..1a97f170 100644 --- a/examples/example.h.in +++ b/examples/example.h.in @@ -24,18 +24,11 @@ /* directory with examples source code and this header */ #define EXAMPLES_DIR "@CMAKE_SOURCE_DIR@/examples" -/* directory with tests and more importantly test key pairs */ -#define TESTS_DIR "@CMAKE_SOURCE_DIR@/tests" - /* SSH listening IP address */ #define SSH_ADDRESS "127.0.0.1" -/* SSH listening port */ -#define SSH_PORT 830 - /* SSH 'password' authentication exptected username and password */ #define SSH_USERNAME "admin" -#define SSH_PASSWORD "admin" /* time in microseconds to sleep for if there are no new RPCs and no new sessions */ #define BACKOFF_TIMEOUT_USECS 100 @@ -45,11 +38,4 @@ fprintf(stderr, "%s", msg); \ goto cleanup -/* supported server transport protocol */ -enum server_transport { - NONE = 0, - UNIX, - SSH -}; - #endif diff --git a/examples/server.c b/examples/server.c index 88254c88..713aecb7 100644 --- a/examples/server.c +++ b/examples/server.c @@ -203,21 +203,11 @@ help_print() } static int -init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_TRANSPORT_IMPL server_type) +init(struct ly_ctx **context, struct nc_pollsession **ps) { int rc = 0; - const char *hostkey_path = TESTS_DIR "/data/server.key"; struct lyd_node *config = NULL; - if (path) { - /* if a path is supplied, then use it */ - hostkey_path = path; - } - - if (server_type == NC_TI_UNIX) { - ERR_MSG_CLEANUP("Only support SSH for now.\n"); - } - /* create a libyang context that will determine which YANG modules will be supported by the server */ rc = ly_ctx_new(MODULES_DIR, 0, context); if (rc) { @@ -236,27 +226,8 @@ init(struct ly_ctx **context, struct nc_pollsession **ps, const char *path, NC_T ERR_MSG_CLEANUP("Error loading modules required for configuration of the server.\n"); } - /* this is where the YANG configuration data gets generated, - * start by creating hostkey configuration data */ - rc = nc_server_config_add_ssh_hostkey(*context, "endpt", "hostkey", hostkey_path, NULL, &config); - if (rc) { - ERR_MSG_CLEANUP("Error creating new hostkey configuration data.\n"); - } - - /* create address and port configuration data */ - rc = nc_server_config_add_address_port(*context, "endpt", NC_TI_LIBSSH, SSH_ADDRESS, SSH_PORT, &config); - if (rc) { - ERR_MSG_CLEANUP("Error creating new address and port configuration data.\n"); - } - - /* create client authentication configuration data */ - rc = nc_server_config_add_ssh_user_password(*context, "endpt", SSH_USERNAME, SSH_PASSWORD, &config); - if (rc) { - ERR_MSG_CLEANUP("Error creating client authentication configuration data.\n"); - } - - /* apply the created configuration data */ - rc = nc_server_config_setup_data(config); + /* apply the YANG data stored in config.json */ + rc = nc_server_config_setup_path(*context, EXAMPLES_DIR "/config.json"); if (rc) { ERR_MSG_CLEANUP("Application of configuration data failed.\n"); } @@ -290,67 +261,38 @@ main(int argc, char **argv) struct ly_ctx *context = NULL; struct nc_session *session, *new_session; struct nc_pollsession *ps = NULL; - const char *unix_socket_path = NULL, *hostkey_path = NULL; struct option options[] = { {"help", no_argument, NULL, 'h'}, - {"unix", required_argument, NULL, 'u'}, - {"ssh", required_argument, NULL, 's'}, {"debug", no_argument, NULL, 'd'}, {NULL, 0, NULL, 0} }; - if (argc == 1) { - help_print(); - goto cleanup; - } - opterr = 0; - while ((opt = getopt_long(argc, argv, ":s:hu:d", options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "hd", options, NULL)) != -1) { switch (opt) { case 'h': help_print(); goto cleanup; - case 'u': - unix_socket_path = optarg; - if (init(&context, &ps, unix_socket_path, NC_TI_UNIX)) { - ERR_MSG_CLEANUP("Failed to initialize a UNIX socket\n"); - } - printf("Using UNIX socket!\n"); - break; - - case 's': - hostkey_path = optarg; - if (init(&context, &ps, hostkey_path, NC_TI_LIBSSH)) { - ERR_MSG_CLEANUP("Failed to initialize a SSH server\n"); - goto cleanup; - } - printf("Using SSH!\n"); - break; - case 'd': nc_verbosity(NC_VERB_DEBUG); break; - case ':': - if (optopt == 's') { - if (init(&context, &ps, NULL, NC_TI_LIBSSH)) { - ERR_MSG_CLEANUP("Failed to initialize a SSH server\n"); - goto cleanup; - } - printf("Using SSH!\n"); - break; - } else { - ERR_MSG_CLEANUP("Invalid option or missing argument\n"); - } - default: ERR_MSG_CLEANUP("Invalid option or missing argument\n"); } } + /* initialize the server */ + r = init(&context, &ps); + if (r) { + ERR_MSG_CLEANUP("Initializing the server failed."); + } + + printf("Listening for new connections!\n"); + while (!exit_application) { no_new_sessions = 0; diff --git a/src/messages_server.c b/src/messages_server.c index 2cc193ab..2a984836 100644 --- a/src/messages_server.c +++ b/src/messages_server.c @@ -109,7 +109,7 @@ nc_server_reply_add_err(struct nc_server_reply *reply, struct lyd_node *err) NC_CHECK_ARG_RET(NULL, reply, err, -1); if (reply->type != NC_RPL_ERROR) { - ERR(NULL, "nc_server_reply_add_err: bad reply type"); + ERR(NULL, "nc_server_reply_add_err() bad reply type"); return -1; } @@ -126,7 +126,7 @@ nc_server_reply_get_last_err(const struct nc_server_reply *reply) NC_CHECK_ARG_RET(NULL, reply, NULL); if (reply->type != NC_RPL_ERROR) { - ERR(NULL, "nc_server_reply_get_last_err: bad reply type"); + ERR(NULL, "nc_server_reply_get_last_err() bad reply type"); return NULL; } From 4830ea76460147a33e2d26df40b5ffe70dc0e6cc Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 25 Oct 2023 11:28:32 +0200 Subject: [PATCH 100/134] server_config UPDATE minor fixes --- src/server_config.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 63bf0c10..724c634b 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -885,13 +885,11 @@ nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn) return; } - iter = opts->ctn; - while (iter) { + for (iter = opts->ctn; iter; iter = iter->next) { if (iter->next == ctn) { /* found the ctn */ break; } - iter = iter->next; } iter->next = ctn->next; @@ -903,14 +901,13 @@ nc_server_config_del_ctns(struct nc_server_tls_opts *opts) { struct nc_ctn *cur, *next; - cur = opts->ctn; - while (cur) { + for (cur = opts->ctn; cur; cur = next) { next = cur->next; free(cur->name); free(cur->fingerprint); free(cur); - cur = next; } + opts->ctn = NULL; } @@ -1113,6 +1110,8 @@ nc_server_config_ch_del_client(struct nc_ch_client *ch_client) /* RD LOCK */ pthread_rwlock_rdlock(&server_opts.ch_client_lock); + /* MUTEX LOCK */ + pthread_mutex_lock(&client.lock); if (client.thread_data->thread_running) { /* CH COND LOCK */ @@ -1122,6 +1121,8 @@ nc_server_config_ch_del_client(struct nc_ch_client *ch_client) /* CH COND UNLOCK */ pthread_mutex_unlock(&client.thread_data->cond_lock); + /* MUTEX UNLOCK */ + pthread_mutex_unlock(&client.lock); /* RD UNLOCK */ pthread_rwlock_unlock(&server_opts.ch_client_lock); @@ -2971,7 +2972,7 @@ static int nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - uint32_t prev_lo; + uint32_t log_options = 0; struct nc_endpt *endpt; struct nc_bind *bind; struct nc_server_unix_opts *opts; @@ -3004,7 +3005,7 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) } /* silently search for non-mandatory parameters */ - prev_lo = ly_log_options(0); + ly_temp_log_options(&log_options); ret = lyd_find_path(node, "mode", 0, &data); if (!ret) { opts->mode = strtol(lyd_get_value(data), NULL, 8); @@ -3021,7 +3022,7 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) } /* reset the logging options */ - ly_log_options(prev_lo); + ly_temp_log_options(NULL); ret = nc_server_config_set_address_port(endpt, bind, NULL, 0); if (ret) { @@ -3601,7 +3602,7 @@ nc_server_config_tls_version(const struct lyd_node *node, NC_OPERATION op) opts->tls_versions |= tls_version; } else if ((op == NC_OP_DELETE) && (opts->tls_versions & tls_version)) { /* delete the version if it is there */ - opts->tls_versions -= tls_version; + opts->tls_versions &= ~tls_version; } cleanup: @@ -4507,11 +4508,11 @@ static int nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION op) { int ret = 0; - uint32_t prev_lo; + uint32_t log_options = 0; struct lyd_node *tree; /* silently search for ietf-netconf-server, it may not be present */ - prev_lo = ly_log_options(0); + ly_temp_log_options(&log_options); ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree); if (ret || (tree->flags & LYD_DEFAULT)) { @@ -4535,7 +4536,7 @@ nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION o cleanup: /* reset the logging options back to what they were */ - ly_log_options(prev_lo); + ly_temp_log_options(NULL); return ret; } From f0f1aa350ac02804991ed35f096747aefe599241 Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 25 Oct 2023 13:32:03 +0200 Subject: [PATCH 101/134] server_config UPDATE access numbers directly --- src/server_config.c | 36 ++++++++++++++++++------------------ src/session_p.h | 5 ++--- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 724c634b..16656c6b 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -541,7 +541,7 @@ nc_server_config_get_ctn(const struct lyd_node *node, struct nc_ctn **ctn) node = lyd_child(node); assert(!strcmp(LYD_NAME(node), "id")); - id = strtoul(lyd_get_value(node), NULL, 10); + id = ((struct lyd_node_term *)node)->value.uint32; if (nc_server_config_get_tls_opts(node, &opts)) { return 1; @@ -1163,7 +1163,7 @@ nc_server_config_hello_timeout(const struct lyd_node *node, NC_OPERATION op) assert(!strcmp(LYD_NAME(node), "hello-timeout")); if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - server_opts.hello_timeout = strtoul(lyd_get_value(node), NULL, 10); + server_opts.hello_timeout = ((struct lyd_node_term *)node)->value.uint16; } else { /* default value */ server_opts.hello_timeout = 60; @@ -1188,7 +1188,7 @@ nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_client->idle_timeout = strtoul(lyd_get_value(node), NULL, 10); + ch_client->idle_timeout = ((struct lyd_node_term *)node)->value.uint16; } else if (op == NC_OP_DELETE) { ch_client->idle_timeout = 180; } @@ -1197,7 +1197,7 @@ nc_server_config_idle_timeout(const struct lyd_node *node, NC_OPERATION op) } else { /* whole server idle timeout */ if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - server_opts.idle_timeout = strtoul(lyd_get_value(node), NULL, 10); + server_opts.idle_timeout = ((struct lyd_node_term *)node)->value.uint16; } else { /* default value */ server_opts.idle_timeout = 0; @@ -1613,7 +1613,7 @@ nc_server_config_local_port(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - bind->port = strtoul(lyd_get_value(node), NULL, 10); + bind->port = ((struct lyd_node_term *)node)->value.uint16; } else { /* delete -> set to default */ bind->port = 0; @@ -1702,7 +1702,7 @@ nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10); + endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16; } else { endpt->ka.idle_time = 0; } @@ -1723,7 +1723,7 @@ nc_server_config_idle_time(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_endpt->ka.idle_time = strtoul(lyd_get_value(node), NULL, 10); + ch_endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16; } else { ch_endpt->ka.idle_time = 0; } @@ -1756,7 +1756,7 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10); + endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16; } else { endpt->ka.max_probes = 0; } @@ -1777,7 +1777,7 @@ nc_server_config_max_probes(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_endpt->ka.max_probes = strtoul(lyd_get_value(node), NULL, 10); + ch_endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16; } else { ch_endpt->ka.max_probes = 0; } @@ -1810,7 +1810,7 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10); + endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16; } else { endpt->ka.probe_interval = 0; } @@ -1831,7 +1831,7 @@ nc_server_config_probe_interval(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_endpt->ka.probe_interval = strtoul(lyd_get_value(node), NULL, 10); + ch_endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16; } else { ch_endpt->ka.max_probes = 0; } @@ -2385,7 +2385,7 @@ nc_server_config_auth_attempts(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - opts->auth_attempts = strtoul(lyd_get_value(node), NULL, 10); + opts->auth_attempts = ((struct lyd_node_term *)node)->value.uint16; } cleanup: @@ -2417,7 +2417,7 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - opts->auth_timeout = strtoul(lyd_get_value(node), NULL, 10); + opts->auth_timeout = ((struct lyd_node_term *)node)->value.uint16; } cleanup: @@ -3403,7 +3403,7 @@ nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_serv /* find the list's key */ lyd_find_path(node, "id", 0, &n); assert(n); - id = strtoul(lyd_get_value(n), NULL, 10); + id = ((struct lyd_node_term *)node)->value.uint32; /* find the ctn's name */ lyd_find_path(node, "name", 0, &n); @@ -3974,7 +3974,7 @@ nc_server_config_remote_port(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_endpt->port = strtoul(lyd_get_value(node), NULL, 10); + ch_endpt->port = ((struct lyd_node_term *)node)->value.uint16; } else { ch_endpt->port = 0; } @@ -4054,7 +4054,7 @@ nc_server_config_period(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_client->period = strtoul(lyd_get_value(node), NULL, 10); + ch_client->period = ((struct lyd_node_term *)node)->value.uint16; } else if (op == NC_OP_DELETE) { ch_client->period = 60; } @@ -4178,7 +4178,7 @@ nc_server_config_max_wait(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_client->max_wait = strtoul(lyd_get_value(node), NULL, 10); + ch_client->max_wait = ((struct lyd_node_term *)node)->value.uint16; } else { ch_client->max_wait = 5; } @@ -4204,7 +4204,7 @@ nc_server_config_max_attempts(const struct lyd_node *node, NC_OPERATION op) } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_client->max_attempts = strtoul(lyd_get_value(node), NULL, 10); + ch_client->max_attempts = ((struct lyd_node_term *)node)->value.uint8; } else { ch_client->max_attempts = 3; } diff --git a/src/session_p.h b/src/session_p.h index 86bbace6..2f06a5c2 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -424,9 +424,8 @@ struct nc_server_opts { void (*content_id_data_free)(void *data); - /* ACCESS unlocked */ - ATOMIC_T hello_timeout; - ATOMIC_T idle_timeout; + uint16_t hello_timeout; + uint16_t idle_timeout; #ifdef NC_ENABLED_SSH_TLS int (*passwd_auth_clb)(const struct nc_session *session, const char *password, void *user_data); From 92b6d6d29d148d6c8ca2d7571b4abc817a6cfa10 Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 25 Oct 2023 13:32:30 +0200 Subject: [PATCH 102/134] server_config UPDATE add delete substring func --- src/server_config.c | 86 ++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 16656c6b..6e6e2766 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -2664,12 +2664,41 @@ nc_server_config_none(const struct lyd_node *node, NC_OPERATION op) return ret; } +static int +nc_server_config_delete_substring(const char *haystack, const char *needle, const char delim) +{ + size_t needle_len = strlen(needle); + char *substr; + int substr_found = 0, ret = 0; + + while ((substr = strstr(haystack, needle))) { + /* iterate over all the substrings */ + if (((substr == haystack) && (*(substr + needle_len) == delim)) || + ((substr != haystack) && (*(substr - 1) == delim) && (*(substr + needle_len) == delim))) { + /* either the first element of the string or somewhere in the middle */ + memmove(substr, substr + needle_len + 1, strlen(substr + needle_len + 1)); + substr_found = 1; + break; + } else if ((*(substr - 1) == delim) && (*(substr + needle_len) == '\0')) { + /* the last element of the string */ + *(substr - 1) = '\0'; + substr_found = 1; + break; + } + haystack = substr + 1; + } + if (!substr_found) { + ret = 1; + } + + return ret; +} + static int nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OPERATION op) { - int ret = 0, alg_found = 0; - char *substr, *haystack, *alg = NULL; - size_t alg_len; + int ret = 0; + char *alg = NULL; if (!strncmp(algorithm, "openssh-", 8)) { /* if the name starts with openssh, convert it to it's original libssh accepted form */ @@ -2696,8 +2725,6 @@ nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OP } } - alg_len = strlen(alg); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { if (!*alg_store) { /* first call */ @@ -2709,7 +2736,7 @@ nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OP } } else { /* +1 because of ',' between algorithms */ - *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + alg_len + 1 + 1); + *alg_store = nc_realloc(*alg_store, strlen(*alg_store) +strlen(alg) + 1 + 1); if (!*alg_store) { ERRMEM; ret = 1; @@ -2720,26 +2747,10 @@ nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OP } } else { /* delete */ - haystack = *alg_store; - while ((substr = strstr(haystack, alg))) { - /* iterate over all the substrings */ - if (((substr == haystack) && (*(substr + alg_len) == ',')) || - ((substr != haystack) && (*(substr - 1) == ',') && (*(substr + alg_len) == ','))) { - /* either the first element of the string or somewhere in the middle */ - memmove(substr, substr + alg_len + 1, strlen(substr + alg_len + 1)); - alg_found = 1; - break; - } else if ((*(substr - 1) == ',') && (*(substr + alg_len) == '\0')) { - /* the last element of the string */ - *(substr - 1) = '\0'; - alg_found = 1; - break; - } - haystack = substr + 1; - } - if (!alg_found) { + ret = nc_server_config_delete_substring(*alg_store, alg, ','); + if (ret) { ERR(NULL, "Unable to delete an algorithm (%s), which was not previously added.", alg); - ret = 1; + goto cleanup; } } @@ -3668,29 +3679,10 @@ nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char static int nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher) { - int cipher_found = 0; - char *haystack, *substr; - size_t cipher_len = strlen(cipher); - - /* iterate over all the substrings */ - haystack = opts->ciphers; - while ((substr = strstr(haystack, cipher))) { - if (((substr == haystack) && (*(substr + cipher_len) == ':')) || - ((substr != haystack) && (*(substr - 1) == ':') && (*(substr + cipher_len) == ':'))) { - /* either the first element of the string or somewhere in the middle */ - memmove(substr, substr + cipher_len + 1, strlen(substr + cipher_len + 1)); - cipher_found = 1; - break; - } else if ((*(substr - 1) == ':') && (*(substr + cipher_len) == '\0')) { - /* the last element of the string */ - *(substr - 1) = '\0'; - cipher_found = 1; - break; - } - haystack = substr + 1; - } + int ret = 0; - if (!cipher_found) { + ret = nc_server_config_delete_substring(opts->ciphers, cipher, ':'); + if (ret) { ERR(NULL, "Unable to delete a cipher (%s), which was not previously added.", cipher); return 1; } From ec3eab85edde769576a89a9a3f3f3006911a1614 Mon Sep 17 00:00:00 2001 From: roman Date: Wed, 25 Oct 2023 13:59:55 +0200 Subject: [PATCH 103/134] server_config BUGFIX use correct node for ctn id --- src/server_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server_config.c b/src/server_config.c index 6e6e2766..dfed7960 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -3414,7 +3414,7 @@ nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_serv /* find the list's key */ lyd_find_path(node, "id", 0, &n); assert(n); - id = ((struct lyd_node_term *)node)->value.uint32; + id = ((struct lyd_node_term *)n)->value.uint32; /* find the ctn's name */ lyd_find_path(node, "name", 0, &n); From c39a9228deae39839ba1f662755c761498166fac Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 11:07:17 +0200 Subject: [PATCH 104/134] log UPDATE add ERRMEM check macros --- src/io.c | 54 ++------ src/log_p.h | 3 + src/messages_client.c | 145 +++++---------------- src/messages_server.c | 20 +-- src/server_config.c | 239 +++++++---------------------------- src/server_config_ks.c | 15 +-- src/server_config_ts.c | 11 +- src/server_config_util.c | 138 ++++---------------- src/server_config_util_ssh.c | 80 ++++-------- src/server_config_util_tls.c | 100 +++++---------- src/session.c | 35 +---- src/session_client.c | 87 ++++--------- src/session_client_ssh.c | 94 +++----------- src/session_client_tls.c | 40 ++---- src/session_server.c | 62 ++------- src/session_server_ssh.c | 11 +- src/session_server_tls.c | 45 ++----- 17 files changed, 255 insertions(+), 924 deletions(-) diff --git a/src/io.c b/src/io.c index 47894d41..d51278f0 100644 --- a/src/io.c +++ b/src/io.c @@ -74,18 +74,12 @@ nc_ssl_error_get_reasons(void) /* add "; " */ reason_size += 2; reasons = nc_realloc(reasons, reason_size); - if (!reasons) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!reasons, NULL); reason_len += sprintf(reasons + reason_len, "; "); } reason_size += strlen(ERR_reason_error_string(e)); reasons = nc_realloc(reasons, reason_size); - if (!reasons) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!reasons, NULL); reason_len += sprintf(reasons + reason_len, "%s", ERR_reason_error_string(e)); } @@ -253,10 +247,7 @@ nc_read_chunk(struct nc_session *session, size_t len, uint32_t inact_timeout, st } *chunk = malloc((len + 1) * sizeof **chunk); - if (!*chunk) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!*chunk, -1); r = nc_read(session, *chunk, len, inact_timeout, ts_act_timeout); if (r <= 0) { @@ -286,10 +277,7 @@ nc_read_until(struct nc_session *session, const char *endtag, size_t limit, uint size = BUFFERSIZE; } chunk = malloc((size + 1) * sizeof *chunk); - if (!chunk) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!chunk, -1); len = strlen(endtag); while (1) { @@ -305,10 +293,7 @@ nc_read_until(struct nc_session *session, const char *endtag, size_t limit, uint /* get more memory */ size = size + BUFFERSIZE; chunk = nc_realloc(chunk, (size + 1) * sizeof *chunk); - if (!chunk) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!chunk, -1); } /* get another character */ @@ -431,11 +416,7 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i /* realloc message buffer, remember to count terminating null byte */ data = nc_realloc(data, len + chunk_len + 1); - if (!data) { - ERRMEM; - ret = -1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!data, ret = -1, cleanup); memcpy(data + len, chunk, chunk_len); len += chunk_len; data[len] = '\0'; @@ -951,11 +932,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...) /* open */ count = asprintf(&buf, "", NC_NS_BASE, session->opts.client.msgid + 1, attrs ? attrs : ""); - if (count == -1) { - ERRMEM; - ret = NC_MSG_ERROR; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(count == -1, ret = NC_MSG_ERROR, cleanup); nc_write_clb((void *)&arg, buf, count, 0); free(buf); @@ -1114,11 +1091,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...) sid = va_arg(ap, uint32_t *); count = asprintf(&buf, "", NC_NS_BASE); - if (count == -1) { - ERRMEM; - ret = NC_MSG_ERROR; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(count == -1, ret = NC_MSG_ERROR, cleanup); nc_write_clb((void *)&arg, buf, count, 0); free(buf); for (i = 0; capabilities[i]; i++) { @@ -1128,11 +1101,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...) } if (sid) { count = asprintf(&buf, "%u", *sid); - if (count == -1) { - ERRMEM; - ret = NC_MSG_ERROR; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(count == -1, ret = NC_MSG_ERROR, cleanup); nc_write_clb((void *)&arg, buf, count, 0); free(buf); } else { @@ -1194,10 +1163,7 @@ nc_getpw(uid_t uid, const char *username, struct passwd *pwd_buf, char **buf, si /* allocate some buffer */ *buf = nc_realloc(*buf, *buf_size); - if (!*buf) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!*buf, NULL); if (username) { ret = getpwnam_r(username, pwd_buf, *buf, *buf_size, &pwd); diff --git a/src/log_p.h b/src/log_p.h index 5f3e1d01..c4f6c9e3 100644 --- a/src/log_p.h +++ b/src/log_p.h @@ -53,6 +53,9 @@ extern ATOMIC_T verbose_level; #define ERRINT ERR(NULL, "%s: internal error (%s:%d).", __func__, __FILE__, __LINE__) #define ERRARG(session, ARG) ERR(session, "Invalid argument %s (%s()).", #ARG, __func__) +#define NC_CHECK_ERRMEM_RET(COND, RET) if ((COND)) {ERRMEM; return (RET);} +#define NC_CHECK_ERRMEM_GOTO(COND, RET, GOTO) if ((COND)) {ERRMEM; RET; goto GOTO;} + #define GETMACRO1(_1, NAME, ...) NAME #define GETMACRO2(_1, _2, NAME, ...) NAME #define GETMACRO3(_1, _2, _3, NAME, ...) NAME diff --git a/src/messages_client.c b/src/messages_client.c index 5cd1165c..5008865b 100644 --- a/src/messages_client.c +++ b/src/messages_client.c @@ -53,10 +53,7 @@ nc_rpc_act_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype) } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_ACT_GENERIC; rpc->has_data = 1; @@ -81,10 +78,7 @@ nc_rpc_act_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype) NC_CHECK_ARG_RET(NULL, xml_str, NULL); rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_ACT_GENERIC; rpc->has_data = 0; @@ -111,10 +105,7 @@ nc_rpc_getconfig(NC_DATASTORE source, const char *filter, NC_WD_MODE wd_mode, NC } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_GETCONFIG; rpc->source = source; @@ -143,10 +134,7 @@ nc_rpc_edit(NC_DATASTORE target, NC_RPC_EDIT_DFLTOP default_op, NC_RPC_EDIT_TEST } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_EDIT; rpc->target = target; @@ -177,10 +165,7 @@ nc_rpc_copy(NC_DATASTORE target, const char *url_trg, NC_DATASTORE source, const } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_COPY; rpc->target = target; @@ -209,10 +194,7 @@ nc_rpc_delete(NC_DATASTORE target, const char *url, NC_PARAMTYPE paramtype) NC_CHECK_ARG_RET(NULL, target, NULL); rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_DELETE; rpc->target = target; @@ -234,10 +216,7 @@ nc_rpc_lock(NC_DATASTORE target) NC_CHECK_ARG_RET(NULL, target, NULL); rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_LOCK; rpc->target = target; @@ -253,10 +232,7 @@ nc_rpc_unlock(NC_DATASTORE target) NC_CHECK_ARG_RET(NULL, target, NULL); rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_UNLOCK; rpc->target = target; @@ -275,10 +251,7 @@ nc_rpc_get(const char *filter, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype) } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_GET; if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) { @@ -300,10 +273,7 @@ nc_rpc_kill(uint32_t session_id) NC_CHECK_ARG_RET(NULL, session_id, NULL); rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_KILL; rpc->sid = session_id; @@ -318,10 +288,7 @@ nc_rpc_commit(int confirmed, uint32_t confirm_timeout, const char *persist, cons struct nc_rpc_commit *rpc; rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_COMMIT; rpc->confirmed = confirmed; @@ -347,10 +314,7 @@ nc_rpc_discard(void) struct nc_rpc *rpc; rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_DISCARD; @@ -363,10 +327,7 @@ nc_rpc_cancel(const char *persist_id, NC_PARAMTYPE paramtype) struct nc_rpc_cancel *rpc; rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_CANCEL; if (persist_id && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) { @@ -392,10 +353,7 @@ nc_rpc_validate(NC_DATASTORE source, const char *url_or_config, NC_PARAMTYPE par } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_VALIDATE; rpc->source = source; @@ -417,10 +375,7 @@ nc_rpc_getschema(const char *identifier, const char *version, const char *format NC_CHECK_ARG_RET(NULL, identifier, NULL); rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_GETSCHEMA; if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) { @@ -455,10 +410,7 @@ nc_rpc_subscribe(const char *stream_name, const char *filter, const char *start_ } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_SUBSCRIBE; if (stream_name && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) { @@ -502,10 +454,7 @@ nc_rpc_getdata(const char *datastore, const char *filter, const char *config_fil } rpc = calloc(1, sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1); rpc->type = NC_RPC_GETDATA; @@ -526,16 +475,10 @@ nc_rpc_getdata(const char *datastore, const char *filter, const char *config_fil } if (origin_filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) { rpc->origin_filter = malloc(origin_filter_count * sizeof *rpc->origin_filter); - if (!rpc->origin_filter) { - ERRMEM; - goto error; - } + NC_CHECK_ERRMEM_GOTO(!rpc->origin_filter,; , error); for (i = 0; i < origin_filter_count; ++i) { rpc->origin_filter[i] = strdup(origin_filter[i]); - if (!rpc->origin_filter[i]) { - ERRMEM; - goto error; - } + NC_CHECK_ERRMEM_GOTO(!rpc->origin_filter[i],; , error); ++rpc->origin_filter_count; } } else { @@ -567,10 +510,7 @@ nc_rpc_editdata(const char *datastore, NC_RPC_EDIT_DFLTOP default_op, const char } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_EDITDATA; if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) { @@ -604,10 +544,7 @@ nc_rpc_establishsub(const char *filter, const char *stream_name, const char *sta } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_ESTABLISHSUB; if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) { @@ -654,10 +591,7 @@ nc_rpc_modifysub(uint32_t id, const char *filter, const char *stop_time, NC_PARA } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_MODIFYSUB; rpc->id = id; @@ -684,10 +618,7 @@ nc_rpc_deletesub(uint32_t id) NC_CHECK_ARG_RET(NULL, id, NULL); rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_DELETESUB; rpc->id = id; @@ -703,10 +634,7 @@ nc_rpc_killsub(uint32_t id) NC_CHECK_ARG_RET(NULL, id, NULL); rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_KILLSUB; rpc->id = id; @@ -729,10 +657,7 @@ nc_rpc_establishpush_periodic(const char *datastore, const char *filter, const c } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_ESTABLISHPUSH; if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) { @@ -783,10 +708,7 @@ nc_rpc_establishpush_onchange(const char *datastore, const char *filter, const c } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_ESTABLISHPUSH; if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) { @@ -842,10 +764,7 @@ nc_rpc_modifypush_periodic(uint32_t id, const char *datastore, const char *filte } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_MODIFYPUSH; rpc->id = id; @@ -891,10 +810,7 @@ nc_rpc_modifypush_onchange(uint32_t id, const char *datastore, const char *filte } rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_MODIFYPUSH; rpc->id = id; @@ -928,10 +844,7 @@ nc_rpc_resyncsub(uint32_t id) NC_CHECK_ARG_RET(NULL, id, NULL); rpc = malloc(sizeof *rpc); - if (!rpc) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!rpc, NULL); rpc->type = NC_RPC_RESYNCSUB; rpc->id = id; diff --git a/src/messages_server.c b/src/messages_server.c index 2a984836..b02f5a1e 100644 --- a/src/messages_server.c +++ b/src/messages_server.c @@ -38,10 +38,7 @@ nc_server_reply_ok(void) struct nc_server_reply *ret; ret = malloc(sizeof *ret); - if (!ret) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!ret, NULL); ret->type = NC_RPL_OK; return ret; @@ -60,10 +57,7 @@ nc_server_reply_data(struct lyd_node *data, NC_WD_MODE wd, NC_PARAMTYPE paramtyp } ret = malloc(sizeof *ret); - if (!ret) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!ret, NULL); ret->type = NC_RPL_DATA; ret->wd = wd; @@ -91,10 +85,7 @@ nc_server_reply_err(struct lyd_node *err) NC_CHECK_ARG_RET(NULL, err, NULL); ret = malloc(sizeof *ret); - if (!ret) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!ret, NULL); ret->type = NC_RPL_ERROR; ret->err = err; @@ -797,10 +788,7 @@ nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramt } ntf = malloc(sizeof *ntf); - if (!ntf) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!ntf, NULL); if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) { ntf->eventtime = strdup(eventtime); diff --git a/src/server_config.c b/src/server_config.c index dfed7960..82c90ba6 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -659,11 +659,7 @@ nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_ char **name; tmp = realloc(*ptr, (*count + 1) * size); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup); *ptr = tmp; /* set the newly allocated memory to 0 */ @@ -675,11 +671,7 @@ nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_ /* and set it's value */ *name = strdup(key_value); - if (!*name) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!*name, ret = 1, cleanup); cleanup: return ret; @@ -907,7 +899,7 @@ nc_server_config_del_ctns(struct nc_server_tls_opts *opts) free(cur->fingerprint); free(cur); } - + opts->ctn = NULL; } @@ -1214,11 +1206,7 @@ nc_server_config_create_bind(void) void *tmp; tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup); server_opts.binds = tmp; memset(&server_opts.binds[server_opts.endpt_count], 0, sizeof *server_opts.binds); @@ -1335,10 +1323,7 @@ nc_server_config_create_ssh(struct nc_endpt *endpt) { endpt->ti = NC_TI_LIBSSH; endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts)); - if (!endpt->opts.ssh) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1); return 0; } @@ -1348,10 +1333,7 @@ nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt) { ch_endpt->ti = NC_TI_LIBSSH; ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts)); - if (!ch_endpt->opts.ssh) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!ch_endpt->opts.ssh, 1); return 0; } @@ -1417,10 +1399,7 @@ nc_server_config_create_tls(struct nc_endpt *endpt) { endpt->ti = NC_TI_OPENSSL; endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls); - if (!endpt->opts.tls) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1); return 0; } @@ -1430,10 +1409,7 @@ nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt) { ch_endpt->ti = NC_TI_OPENSSL; ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts)); - if (!ch_endpt->opts.tls) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!ch_endpt->opts.tls, 1); return 0; } @@ -1580,11 +1556,7 @@ nc_server_config_local_address(const struct lyd_node *node, NC_OPERATION op) free(bind->address); bind->address = strdup(lyd_get_value(node)); - if (!bind->address) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!bind->address, ret = 1, cleanup); ret = nc_server_config_set_address_port(endpt, bind, lyd_get_value(node), 0); if (ret) { @@ -1986,10 +1958,7 @@ nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, s { free(pubkey->data); pubkey->data = strdup(lyd_get_value(node)); - if (!pubkey->data) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!pubkey->data, 1); return 0; } @@ -1999,10 +1968,7 @@ nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct { free(hostkey->key.pubkey_data); hostkey->key.pubkey_data = strdup(lyd_get_value(node)); - if (!hostkey->key.pubkey_data) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!hostkey->key.pubkey_data, 1); return 0; } @@ -2012,10 +1978,7 @@ nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, stru { free(opts->pubkey_data); opts->pubkey_data = strdup(lyd_get_value(node)); - if (!opts->pubkey_data) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!opts->pubkey_data, 1); return 0; } @@ -2226,11 +2189,7 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { free(hostkey->key.privkey_data); hostkey->key.privkey_data = strdup(lyd_get_value(node)); - if (!hostkey->key.privkey_data) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!hostkey->key.privkey_data, ret = 1, cleanup); } else { free(hostkey->key.privkey_data); hostkey->key.privkey_data = NULL; @@ -2245,11 +2204,7 @@ nc_server_config_cleartext_private_key(const struct lyd_node *node, NC_OPERATION if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { free(opts->privkey_data); opts->privkey_data = strdup(lyd_get_value(node)); - if (!opts->privkey_data) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!opts->privkey_data, ret = 1, cleanup); } else { free(opts->privkey_data); opts->privkey_data = NULL; @@ -2292,11 +2247,7 @@ nc_server_config_keystore_reference(const struct lyd_node *node, NC_OPERATION op free(hostkey->ks_ref); hostkey->ks_ref = strdup(lyd_get_value(node)); - if (!hostkey->ks_ref) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!hostkey->ks_ref, ret = 1, cleanup); } else if (op == NC_OP_DELETE) { free(hostkey->ks_ref); hostkey->ks_ref = NULL; @@ -2458,11 +2409,7 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION free(auth_client->ts_ref); auth_client->ts_ref = strdup(lyd_get_value(node)); - if (!auth_client->ts_ref) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!auth_client->ts_ref, ret = 1, cleanup); } else if (op == NC_OP_DELETE) { free(auth_client->ts_ref); auth_client->ts_ref = NULL; @@ -2486,11 +2433,7 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION free(certs_grp->ts_ref); certs_grp->ts_ref = strdup(lyd_get_value(node)); - if (!certs_grp->ts_ref) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!certs_grp->ts_ref, ret = 1, cleanup); } else if (op == NC_OP_DELETE) { free(certs_grp->ts_ref); certs_grp->ts_ref = NULL; @@ -2529,11 +2472,7 @@ nc_server_config_password(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { free(auth_client->password); auth_client->password = strdup(lyd_get_value(node)); - if (!auth_client->password) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!auth_client->password, ret = 1, cleanup); } else { free(auth_client->password); auth_client->password = NULL; @@ -2570,11 +2509,7 @@ nc_server_config_pam_name(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { free(auth_client->pam_config_name); auth_client->pam_config_name = strdup(lyd_get_value(node)); - if (!auth_client->pam_config_name) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!auth_client->pam_config_name, ret = 1, cleanup); } else { free(auth_client->pam_config_name); auth_client->pam_config_name = NULL; @@ -2611,11 +2546,7 @@ nc_server_config_pam_dir(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { free(auth_client->pam_config_dir); auth_client->pam_config_dir = strdup(lyd_get_value(node)); - if (!auth_client->pam_config_dir) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!auth_client->pam_config_dir, ret = 1, cleanup); } else { free(auth_client->pam_config_dir); auth_client->pam_config_dir = NULL; @@ -2702,46 +2633,26 @@ nc_server_config_transport_params(const char *algorithm, char **alg_store, NC_OP if (!strncmp(algorithm, "openssh-", 8)) { /* if the name starts with openssh, convert it to it's original libssh accepted form */ - if (asprintf(&alg, "%s@openssh.com", algorithm + 8) == -1) { - ERRMEM; - alg = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&alg, "%s@openssh.com", algorithm + 8); + NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup); } else if (!strncmp(algorithm, "libssh-", 7)) { /* if the name starts with libssh, convert it to it's original libssh accepted form */ - if (asprintf(&alg, "%s@libssh.org", algorithm + 7) == -1) { - ERRMEM; - alg = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&alg, "%s@libssh.org", algorithm + 7); + NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; alg = NULL, cleanup); } else { alg = strdup(algorithm); - if (!alg) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!alg, ret = 1, cleanup); } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { if (!*alg_store) { /* first call */ *alg_store = strdup(alg); - if (!*alg_store) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup); } else { /* +1 because of ',' between algorithms */ - *alg_store = nc_realloc(*alg_store, strlen(*alg_store) +strlen(alg) + 1 + 1); - if (!*alg_store) { - ERRMEM; - ret = 1; - goto cleanup; - } + *alg_store = nc_realloc(*alg_store, strlen(*alg_store) + strlen(alg) + 1 + 1); + NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup); strcat(*alg_store, ","); strcat(*alg_store, alg); } @@ -2966,10 +2877,7 @@ nc_server_config_create_unix_socket(struct nc_endpt *endpt) { endpt->ti = NC_TI_UNIX; endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock); - if (!endpt->opts.unixsock) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!endpt->opts.unixsock, 1); /* set default values */ endpt->opts.unixsock->mode = -1; @@ -3009,11 +2917,7 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) opts->address = strdup(lyd_get_value(data)); bind->address = strdup(lyd_get_value(data)); - if (!opts->address || !bind->address) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!opts->address || !bind->address, ret = 1, cleanup); /* silently search for non-mandatory parameters */ ly_temp_log_options(&log_options); @@ -3165,10 +3069,7 @@ nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION /* endpt not found, save the name and try to look it up later */ free(endpt->referenced_endpt_name); endpt->referenced_endpt_name = strdup(endpt_name); - if (!endpt->referenced_endpt_name) { - ERRMEM; - ret = 1; - } + NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup); goto cleanup; } @@ -3222,11 +3123,7 @@ nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { free(opts->cert_data); opts->cert_data = strdup(lyd_get_value(node)); - if (!opts->cert_data) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!opts->cert_data, ret = 1, cleanup); } } else if (equal_parent_name(node, 3, "ca-certs") || equal_parent_name(node, 3, "ee-certs")) { if (nc_server_config_get_cert(node, &cert)) { @@ -3237,11 +3134,7 @@ nc_server_config_cert_data(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { free(cert->data); cert->data = strdup(lyd_get_value(node)); - if (!cert->data) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!cert->data, ret = 1, cleanup); } else { free(cert->data); cert->data = NULL; @@ -3282,11 +3175,7 @@ nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) free(endpt->opts.tls->key_ref); endpt->opts.tls->key_ref = strdup(lyd_get_value(node)); - if (!endpt->opts.tls->key_ref) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!endpt->opts.tls->key_ref, ret = 1, cleanup); } else { free(endpt->opts.tls->key_ref); endpt->opts.tls->key_ref = NULL; @@ -3351,11 +3240,7 @@ nc_server_config_certificate(const struct lyd_node *node, NC_OPERATION op) free(opts->cert_ref); opts->cert_ref = strdup(lyd_get_value(node)); - if (!opts->cert_ref) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!opts->cert_ref, ret = 1, cleanup); } else { free(opts->cert_ref); opts->cert_ref = NULL; @@ -3445,11 +3330,7 @@ nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_serv /* create new ctn */ new = calloc(1, sizeof *new); - if (!new) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!new, ret = 1, cleanup); /* find the right place for insertion */ if (!opts->ctn) { @@ -3475,11 +3356,7 @@ nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_serv new->id = id; free(new->name); new->name = strdup(name); - if (!new->name) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!new->name, ret = 1, cleanup); new->map_type = m_type; cleanup: @@ -3552,11 +3429,7 @@ nc_server_config_fingerprint(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { free(ctn->fingerprint); ctn->fingerprint = strdup(lyd_get_value(node)); - if (!ctn->fingerprint) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!ctn->fingerprint, ret = 1, cleanup); } else { free(ctn->fingerprint); ctn->fingerprint = NULL; @@ -3633,11 +3506,7 @@ nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char void *tmp; ssl_cipher = malloc(strlen(cipher) + 1); - if (!ssl_cipher) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!ssl_cipher, ret = 1, cleanup); for (i = 0; cipher[i]; i++) { if (cipher[i] == '-') { @@ -3653,19 +3522,11 @@ nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char if (!opts->ciphers) { /* first entry */ opts->ciphers = strdup(ssl_cipher); - if (!opts->ciphers) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!opts->ciphers, ret = 1, cleanup); } else { /* + 1 because of : between entries */ tmp = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(ssl_cipher) + 1 + 1); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup); opts->ciphers = tmp; strcat(opts->ciphers, ":"); strcat(opts->ciphers, ssl_cipher); @@ -3755,11 +3616,7 @@ nc_server_config_crl_url(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { free(opts->crl_url); opts->crl_url = strdup(lyd_get_value(node)); - if (!opts->crl_url) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!opts->crl_url, ret = 1, cleanup); } else if (op == NC_OP_DELETE) { free(opts->crl_url); opts->crl_url = NULL; @@ -3796,11 +3653,7 @@ nc_server_config_crl_path(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { free(opts->crl_path); opts->crl_path = strdup(lyd_get_value(node)); - if (!opts->crl_path) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!opts->crl_path, ret = 1, cleanup); } else if (op == NC_OP_DELETE) { free(opts->crl_path); opts->crl_path = NULL; @@ -3929,11 +3782,7 @@ nc_server_config_remote_address(const struct lyd_node *node, NC_OPERATION op) if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { free(ch_endpt->address); ch_endpt->address = strdup(lyd_get_value(node)); - if (!ch_endpt->address) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!ch_endpt->address, ret = 1, cleanup); } else { free(ch_endpt->address); ch_endpt->address = NULL; diff --git a/src/server_config_ks.c b/src/server_config_ks.c index 75003ff4..9540f3d5 100644 --- a/src/server_config_ks.c +++ b/src/server_config_ks.c @@ -267,10 +267,7 @@ nc_server_config_ks_public_key(const struct lyd_node *node, NC_OPERATION op) /* replace the pubkey */ free(key->pubkey_data); key->pubkey_data = strdup(lyd_get_value(node)); - if (!key->pubkey_data) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!key->pubkey_data, 1); return 0; } @@ -319,10 +316,7 @@ nc_server_config_ks_cleartext_private_key(const struct lyd_node *node, NC_OPERAT /* replace the privkey */ free(key->privkey_data); key->privkey_data = strdup(lyd_get_value(node)); - if (!key->privkey_data) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!key->privkey_data, 1); } else if (op == NC_OP_DELETE) { free(key->privkey_data); key->privkey_data = NULL; @@ -384,10 +378,7 @@ nc_server_config_ks_cert_data(const struct lyd_node *node, NC_OPERATION op) /* replace the cert data */ free(cert->data); cert->data = strdup(lyd_get_value(node)); - if (!cert->data) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!cert->data, 1); } return 0; diff --git a/src/server_config_ts.c b/src/server_config_ts.c index d4004ddb..14f684c3 100644 --- a/src/server_config_ts.c +++ b/src/server_config_ts.c @@ -423,10 +423,7 @@ nc_server_config_ts_cert_data(const struct lyd_node *node, NC_OPERATION op) free(cert->data); cert->data = strdup(lyd_get_value(node)); - if (!cert->data) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!cert->data, 1); } return 0; @@ -511,11 +508,7 @@ nc_server_config_ts_public_key(const struct lyd_node *node, NC_OPERATION op) /* replace the public key */ free(pkey->data); pkey->data = strdup(lyd_get_value(node)); - if (!pkey->data) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!pkey->data, ret = 1, cleanup); } cleanup: diff --git a/src/server_config_util.c b/src/server_config_util.c index 2e8aed14..e02b98f9 100644 --- a/src/server_config_util.c +++ b/src/server_config_util.c @@ -48,11 +48,7 @@ nc_server_config_create(const struct ly_ctx *ctx, struct lyd_node **tree, const /* create the path from the format */ ret = vasprintf(&path, path_fmt, ap); - if (ret == -1) { - ERRMEM; - path = NULL; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; path = NULL, cleanup); /* create the nodes in the path */ if (!*tree) { @@ -94,11 +90,7 @@ nc_server_config_append(const struct ly_ctx *ctx, const char *parent_path, const /* create the path by appending child to the parent path */ ret = asprintf(&path, "%s/%s", parent_path, child_name); - if (ret == -1) { - ERRMEM; - path = NULL; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; path = NULL, cleanup); /* create the nodes in the path */ if (!*tree) { @@ -142,11 +134,7 @@ nc_server_config_delete(struct lyd_node **tree, const char *path_fmt, ...) /* create the path from the format */ ret = vasprintf(&path, path_fmt, ap); - if (ret == -1) { - ERRMEM; - path = NULL; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; path = NULL, cleanup); /* find the node we want to delete */ ret = lyd_find_path(*tree, path, 0, &sub); @@ -188,11 +176,7 @@ nc_server_config_check_delete(struct lyd_node **tree, const char *path_fmt, ...) /* create the path from the format */ ret = vasprintf(&path, path_fmt, ap); - if (ret == -1) { - ERRMEM; - path = NULL; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(ret == -1, ret = 1; path = NULL, cleanup); /* find the node we want to delete */ ret = lyd_find_path(*tree, path, 0, &sub); @@ -253,20 +237,12 @@ nc_server_config_util_pubkey_bin_to_b64(const unsigned char *pub_bin, int bin_le /* bin len not divisible by 3, need to add 4 bytes for some padding so that the len is divisible by 4 */ pub_b64 = malloc((bin_len / 3) * 4 + 4 + 1); } - if (!pub_b64) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!pub_b64, ret = 1, cleanup); /* bin to b64 */ b64_len = EVP_EncodeBlock((unsigned char *)pub_b64, pub_bin, bin_len); *pubkey = strndup(pub_b64, b64_len); - if (!*pubkey) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!*pubkey, ret = 1, cleanup); cleanup: free(pub_b64); @@ -285,10 +261,7 @@ nc_server_config_util_bn_to_bin(const BIGNUM *bn, unsigned char **bin, int *bin_ /* prepare buffer for converting BN to binary */ bin_tmp = calloc(BN_num_bytes(bn), sizeof *bin_tmp); - if (!bin_tmp) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!bin_tmp, 1); /* convert to binary */ *bin_len = BN_bn2bin(bn, bin_tmp); @@ -296,23 +269,13 @@ nc_server_config_util_bn_to_bin(const BIGNUM *bn, unsigned char **bin, int *bin_ /* if the highest bit in the MSB is set a byte with the value 0 has to be prepended */ if (bin_tmp[0] & 0x80) { *bin = malloc(*bin_len + 1); - if (!*bin) { - ERRMEM; - ret = 1; - goto cleanup; - } - + NC_CHECK_ERRMEM_GOTO(!*bin, ret = 1, cleanup); (*bin)[0] = 0; memcpy(*bin + 1, bin_tmp, *bin_len); (*bin_len)++; } else { *bin = malloc(*bin_len); - if (!*bin) { - ERRMEM; - ret = 1; - goto cleanup; - } - + NC_CHECK_ERRMEM_GOTO(!*bin, ret = 1, cleanup); memcpy(*bin, bin_tmp, *bin_len); } @@ -358,11 +321,7 @@ nc_server_config_util_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) */ bin_len = 4 + alg_name_len + 4 + e_len + 4 + n_len; bin = malloc(bin_len); - if (!bin) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!bin, ret = 1, cleanup); /* to network byte order (big endian) */ alg_name_len_be = htonl(alg_name_len); @@ -392,11 +351,7 @@ nc_server_config_util_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) } /* alloc mem for group + 1 for \0 */ ec_group = malloc(ec_group_len + 1); - if (!ec_group) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!ec_group, ret = 1, cleanup); /* get the group */ ret = EVP_PKEY_get_utf8_string_param(pkey, "group", ec_group, ec_group_len + 1, NULL); if (!ret) { @@ -431,11 +386,7 @@ nc_server_config_util_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) /* prepare buffer for converting p to binary */ p_bin = malloc(BN_num_bytes(p)); - if (!p_bin) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!p_bin, ret = 1, cleanup); /* convert to binary */ p_len = BN_bn2bin(p, p_bin); @@ -446,11 +397,7 @@ nc_server_config_util_evp_pkey_to_ssh_pubkey(EVP_PKEY *pkey, char **pubkey) */ bin_len = 4 + alg_name_len + 4 + curve_name_len + 4 + p_len; bin = malloc(bin_len); - if (!bin) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!bin, ret = 1, cleanup); /* to network byte order (big endian) */ alg_name_len_be = htonl(alg_name_len); @@ -534,11 +481,7 @@ nc_server_config_util_evp_pkey_to_spki_pubkey(EVP_PKEY *pkey, char **pubkey) /* copy the public key without the header and footer */ *pubkey = strndup(pub_b64 + strlen(NC_SUBJECT_PUBKEY_INFO_HEADER), len - strlen(NC_SUBJECT_PUBKEY_INFO_HEADER) - strlen(NC_SUBJECT_PUBKEY_INFO_FOOTER)); - if (!*pubkey) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!*pubkey, ret = 1, cleanup); cleanup: BIO_free(bio); @@ -589,11 +532,7 @@ nc_server_config_util_read_certificate(const char *cert_path, char **cert) } c = malloc(cert_len + 1); - if (!c) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!c, ret = 1, cleanup); /* read the cert from bio */ ret = BIO_read(bio, c, cert_len); @@ -605,11 +544,7 @@ nc_server_config_util_read_certificate(const char *cert_path, char **cert) /* strip the cert of the header and footer */ *cert = strdup(c + strlen(NC_PEM_CERTIFICATE_HEADER)); - if (!*cert) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!*cert, ret = 1, cleanup); (*cert)[strlen(*cert) - strlen(NC_PEM_CERTIFICATE_FOOTER)] = '\0'; @@ -659,11 +594,7 @@ nc_server_config_util_read_pubkey_ssh2(FILE *f, char **pubkey) } tmp = realloc(*pubkey, pubkey_len + read + 1); - if (!tmp) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup); *pubkey = tmp; memcpy(*pubkey + pubkey_len, buffer, read); @@ -897,11 +828,7 @@ nc_server_config_util_get_privkey_openssl(const char *privkey_path, FILE *f_priv } *privkey = strndup(priv_b64, len); - if (!*privkey) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!*privkey, ret = 1, cleanup); cleanup: /* priv_b64 is freed with BIO */ @@ -955,11 +882,7 @@ nc_server_config_util_get_privkey_libssh(const char *privkey_path, char **privke } *privkey = strndup(priv_b64, ret); - if (!*privkey) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!*privkey, ret = 1, cleanup); /* ok */ ret = 0; @@ -1019,11 +942,7 @@ nc_server_config_util_get_privkey(const char *privkey_path, NC_PRIVKEY_FORMAT *p /* strip private key's header and footer */ *privkey = strdup(priv + strlen(NC_PKCS8_PRIVKEY_HEADER)); - if (!*privkey) { - ERRMEM; - ret = 1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!*privkey, ret = 1, cleanup); (*privkey)[strlen(*privkey) - strlen(NC_PKCS8_PRIVKEY_FOOTER)] = '\0'; cleanup: @@ -1414,12 +1333,8 @@ nc_server_config_add_unix_socket(const struct ly_ctx *ctx, const char *endpt_nam NC_CHECK_ARG_RET(NULL, ctx, endpt_name, path, config, 1); - if (asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/libnetconf2-netconf-server:unix-socket", endpt_name) == -1) { - ERRMEM; - tree_path = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/libnetconf2-netconf-server:unix-socket", endpt_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, tree_path = NULL; ret = 1, cleanup); /* path to unix socket */ ret = nc_server_config_append(ctx, tree_path, "path", path, config); @@ -1575,13 +1490,8 @@ nc_server_config_add_ch_reconnect_strategy(const struct ly_ctx *ctx, const char NC_CHECK_ARG_RET(NULL, ctx, ch_client_name, config, 1); /* prepared the path */ - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" - "netconf-client[name='%s']/reconnect-strategy", ch_client_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/reconnect-strategy", ch_client_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); if (start_with) { /* get string value from enum */ diff --git a/src/server_config_util_ssh.c b/src/server_config_util_ssh.c index d19dc771..00cfe744 100644 --- a/src/server_config_util_ssh.c +++ b/src/server_config_util_ssh.c @@ -102,13 +102,9 @@ nc_server_config_add_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_nam NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, privkey_path, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "server-identity/host-key[name='%s']/public-key", endpt_name, hostkey_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "server-identity/host-key[name='%s']/public-key", endpt_name, hostkey_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_ssh_hostkey(ctx, path, privkey_path, pubkey_path, config); if (ret) { @@ -130,14 +126,10 @@ nc_server_config_add_ch_ssh_hostkey(const struct ly_ctx *ctx, const char *client NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, privkey_path, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/" - "host-key[name='%s']/public-key", client_name, endpt_name, hostkey_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + "host-key[name='%s']/public-key", client_name, endpt_name, hostkey_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_ssh_hostkey(ctx, path, privkey_path, pubkey_path, config); if (ret) { @@ -296,14 +288,10 @@ nc_server_config_add_ssh_user_pubkey(const struct ly_ctx *ctx, const char *endpt NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pubkey_name, pubkey_path, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/" "ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/" - "public-key[name='%s']", endpt_name, user_name, pubkey_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + "public-key[name='%s']", endpt_name, user_name, pubkey_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_ssh_user_pubkey(ctx, path, pubkey_path, config); if (ret) { @@ -333,15 +321,11 @@ nc_server_config_add_ch_ssh_user_pubkey(const struct ly_ctx *ctx, const char *cl NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pubkey_name, pubkey_path, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" "users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name, - endpt_name, user_name, pubkey_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + endpt_name, user_name, pubkey_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_ssh_user_pubkey(ctx, path, pubkey_path, config); if (ret) { @@ -445,13 +429,9 @@ nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char *end NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, password, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/users/user[name='%s']", endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + "client-authentication/users/user[name='%s']", endpt_name, user_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_ssh_user_password(ctx, path, password, config); if (ret) { @@ -473,14 +453,10 @@ nc_server_config_add_ch_ssh_user_password(const struct ly_ctx *ctx, const char * NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, password, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/" - "users/user[name='%s']", client_name, endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + "users/user[name='%s']", client_name, endpt_name, user_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_ssh_user_password(ctx, path, password, config); if (ret) { @@ -544,14 +520,10 @@ nc_server_config_add_ssh_user_interactive(const struct ly_ctx *ctx, const char * NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pam_config_name, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" "client-authentication/users/user[name='%s']/" - "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + "libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); if (ret) { @@ -573,14 +545,10 @@ nc_server_config_add_ch_ssh_user_interactive(const struct ly_ctx *ctx, const cha NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pam_config_name, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" "endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/" - "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + "libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_ssh_user_interactive(ctx, path, pam_config_name, pam_config_dir, config); if (ret) { diff --git a/src/server_config_util_tls.c b/src/server_config_util_tls.c index 0ee6b068..66b25593 100644 --- a/src/server_config_util_tls.c +++ b/src/server_config_util_tls.c @@ -111,13 +111,9 @@ nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *endpt NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, cert_path, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate", endpt_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_tls_server_cert(ctx, path, privkey_path, pubkey_path, cert_path, config); @@ -149,14 +145,10 @@ nc_server_config_add_ch_tls_server_cert(const struct ly_ctx *ctx, const char *cl NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, privkey_path, cert_path, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/" - "certificate", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + "certificate", client_name, endpt_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_tls_server_cert(ctx, path, privkey_path, pubkey_path, cert_path, config); @@ -218,13 +210,9 @@ nc_server_config_add_tls_keystore_ref(const struct ly_ctx *ctx, const char *endp NC_CHECK_ARG_RET(NULL, ctx, endpt_name, asym_key_ref, cert_ref, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" - "tls/tls-server-parameters/server-identity/certificate", endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate", endpt_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_tls_keystore_ref(ctx, path, asym_key_ref, cert_ref, config); if (ret) { @@ -254,13 +242,9 @@ nc_server_config_add_ch_tls_keystore_ref(const struct ly_ctx *ctx, const char *c NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, asym_key_ref, cert_ref, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" - "endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate", client_name, endpt_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/" + "endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate", client_name, endpt_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_tls_keystore_ref(ctx, path, asym_key_ref, cert_ref, config); if (ret) { @@ -317,13 +301,9 @@ nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *endpt NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ee-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ee-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); if (ret) { @@ -368,14 +348,10 @@ nc_server_config_add_ch_tls_client_cert(const struct ly_ctx *ctx, const char *cl NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/" - "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name) == -1; + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); if (ret) { @@ -494,13 +470,9 @@ nc_server_config_add_tls_ca_cert(const struct ly_ctx *ctx, const char *endpt_nam NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/ca-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" + "client-authentication/ca-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); if (ret) { @@ -545,14 +517,10 @@ nc_server_config_add_ch_tls_ca_cert(const struct ly_ctx *ctx, const char *client NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/" - "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + "inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config); if (ret) { @@ -732,13 +700,9 @@ nc_server_config_add_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, u NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, name, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/netconf-server-parameters/" - "client-identity-mappings/cert-to-name[id='%u']", endpt_name, id) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/netconf-server-parameters/" + "client-identity-mappings/cert-to-name[id='%u']", endpt_name, id); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_tls_ctn(ctx, path, fingerprint, map_type, name, config); if (ret) { @@ -774,14 +738,10 @@ nc_server_config_add_ch_tls_ctn(const struct ly_ctx *ctx, const char *client_nam NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, id, name, config, 1); - if (asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" + ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/" "endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/" - "cert-to-name[id='%u']", client_name, endpt_name, id) == -1) { - ERRMEM; - path = NULL; - ret = 1; - goto cleanup; - } + "cert-to-name[id='%u']", client_name, endpt_name, id); + NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup); ret = _nc_server_config_add_tls_ctn(ctx, path, fingerprint, map_type, name, config); if (ret) { diff --git a/src/session.c b/src/session.c index 78cec176..2aed66e4 100644 --- a/src/session.c +++ b/src/session.c @@ -136,10 +136,7 @@ nc_base64_to_bin(const char *base64, char **bin) nl_count = strlen(base64) / 64; remainder = strlen(base64) - 64 * nl_count; b64 = calloc(strlen(base64) + nl_count + 1, 1); - if (!b64) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!b64, -1); for (i = 0; i < nl_count; i++) { /* copy 64 bytes and add a NL */ @@ -1080,10 +1077,7 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version) NC_CHECK_ARG_RET(NULL, ctx, NULL); cpblts = malloc(size * sizeof *cpblts); - if (!cpblts) { - ERRMEM; - goto error; - } + NC_CHECK_ERRMEM_GOTO(!cpblts,; , error); cpblts[0] = strdup("urn:ietf:params:netconf:base:1.0"); cpblts[1] = strdup("urn:ietf:params:netconf:base:1.1"); count = 2; @@ -1185,16 +1179,10 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version) /* get content-id */ if (server_opts.content_id_clb) { yl_content_id = server_opts.content_id_clb(server_opts.content_id_data); - if (!yl_content_id) { - ERRMEM; - goto error; - } + NC_CHECK_ERRMEM_GOTO(!yl_content_id,; , error); } else { yl_content_id = malloc(11); - if (!yl_content_id) { - ERRMEM; - goto error; - } + NC_CHECK_ERRMEM_GOTO(!yl_content_id,; , error); sprintf(yl_content_id, "%u", ly_ctx_get_change_count(ctx)); } @@ -1301,10 +1289,7 @@ parse_cpblts(struct lyd_node *capabilities, char ***list) } /* last item remains NULL */ *list = calloc(i + 1, sizeof **list); - if (!*list) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!*list, -1); i = 0; } @@ -1334,10 +1319,7 @@ parse_cpblts(struct lyd_node *capabilities, char ***list) /* store capabilities */ if (list) { (*list)[i] = strndup(cpb_start, cpb_end - cpb_start); - if (!(*list)[i]) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!(*list)[i], -1); i++; } } @@ -1360,10 +1342,7 @@ nc_send_hello_io(struct nc_session *session) if (session->side == NC_CLIENT) { /* client side hello - send only NETCONF base capabilities */ cpblts = malloc(3 * sizeof *cpblts); - if (!cpblts) { - ERRMEM; - return NC_MSG_ERROR; - } + NC_CHECK_ERRMEM_RET(!cpblts, NC_MSG_ERROR); cpblts[0] = strdup("urn:ietf:params:netconf:base:1.0"); cpblts[1] = strdup("urn:ietf:params:netconf:base:1.1"); cpblts[2] = NULL; diff --git a/src/session_client.c b/src/session_client.c index 047d6ed4..c45d7647 100644 --- a/src/session_client.c +++ b/src/session_client.c @@ -279,10 +279,7 @@ nc_client_set_schema_searchpath(const char *path) if (path) { client_opts.schema_searchpath = strdup(path); - if (!client_opts.schema_searchpath) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!client_opts.schema_searchpath, 1); } else { client_opts.schema_searchpath = NULL; } @@ -920,11 +917,7 @@ build_module_info_yl(struct nc_session *session, int get_data_sup, int xpath_sup } (*result) = calloc(modules->count + 1, sizeof **result); - if (!(*result)) { - ERRMEM; - ret = -1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!(*result), ret = -1, cleanup); for (u = 0; u < modules->count; ++u) { submodules_count = 0; @@ -947,13 +940,7 @@ build_module_info_yl(struct nc_session *session, int get_data_sup, int xpath_sup (*result)[u].implemented = !strcmp(lyd_get_value(iter), "implement"); } else if (!strcmp(iter->schema->name, "feature")) { (*result)[u].features = nc_realloc((*result)[u].features, (feature_count + 2) * sizeof *(*result)[u].features); - if (!(*result)[u].features) { - ERRMEM; - free_module_info(*result); - *result = NULL; - ret = -1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!(*result)[u].features, free_module_info(*result); *result = NULL; ret = -1, cleanup); (*result)[u].features[feature_count] = strdup(lyd_get_value(iter)); (*result)[u].features[feature_count + 1] = NULL; ++feature_count; @@ -964,25 +951,18 @@ build_module_info_yl(struct nc_session *session, int get_data_sup, int xpath_sup if (submodules_count) { (*result)[u].submodules = calloc(submodules_count + 1, sizeof *(*result)[u].submodules); - if (!(*result)[u].submodules) { - ERRMEM; - free_module_info(*result); - *result = NULL; - ret = -1; - goto cleanup; - } else { - v = 0; - LY_LIST_FOR(lyd_child(modules->dnodes[u]), iter) { - mod = modules->dnodes[u]->schema->module; - if ((mod == iter->schema->module) && !strcmp(iter->schema->name, "submodule")) { - LY_LIST_FOR(lyd_child(iter), child) { - if (mod != child->schema->module) { - continue; - } else if (!strcmp(child->schema->name, "name")) { - (*result)[u].submodules[v].name = strdup(lyd_get_value(child)); - } else if (!strcmp(child->schema->name, "revision")) { - (*result)[u].submodules[v].revision = strdup(lyd_get_value(child)); - } + NC_CHECK_ERRMEM_GOTO(!(*result)[u].submodules, free_module_info(*result); *result = NULL; ret = -1, cleanup); + v = 0; + LY_LIST_FOR(lyd_child(modules->dnodes[u]), iter) { + mod = modules->dnodes[u]->schema->module; + if ((mod == iter->schema->module) && !strcmp(iter->schema->name, "submodule")) { + LY_LIST_FOR(lyd_child(iter), child) { + if (mod != child->schema->module) { + continue; + } else if (!strcmp(child->schema->name, "name")) { + (*result)[u].submodules[v].name = strdup(lyd_get_value(child)); + } else if (!strcmp(child->schema->name, "revision")) { + (*result)[u].submodules[v].revision = strdup(lyd_get_value(child)); } } } @@ -1012,10 +992,7 @@ build_module_info_cpblts(char **cpblts, struct module_info **result) for (u = 0; cpblts[u]; ++u) {} (*result) = calloc(u + 1, sizeof **result); - if (!(*result)) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!(*result), -1); for (u = v = 0; cpblts[u]; ++u) { module_cpblt = strstr(cpblts[u], "module="); @@ -1394,10 +1371,7 @@ nc_connect_inout(int fdin, int fdout, struct ly_ctx *ctx) /* prepare session structure */ session = nc_new_session(NC_CLIENT, 0); - if (!session) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!session, NULL); session->status = NC_STATUS_STARTING; /* transport specific data */ @@ -1462,10 +1436,7 @@ nc_connect_unix(const char *address, struct ly_ctx *ctx) /* prepare session structure */ session = nc_new_session(NC_CLIENT, 0); - if (!session) { - ERRMEM; - goto fail; - } + NC_CHECK_ERRMEM_GOTO(!session,; , fail); session->status = NC_STATUS_STARTING; /* transport specific data */ @@ -1487,10 +1458,7 @@ nc_connect_unix(const char *address, struct ly_ctx *ctx) } username = strdup(pw->pw_name); free(buf); - if (!username) { - ERRMEM; - goto fail; - } + NC_CHECK_ERRMEM_GOTO(!username,; , fail); session->username = username; /* NETCONF handshake */ @@ -1532,10 +1500,7 @@ nc_saddr2str(const struct sockaddr *saddr, char **str_ip, uint16_t *port) str_len = (saddr->sa_family == AF_INET) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; *str_ip = malloc(str_len); - if (!*str_ip) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!(*str_ip), -1); if (saddr->sa_family == AF_INET) { addr = &((struct sockaddr_in *)saddr)->sin_addr; @@ -2110,11 +2075,7 @@ recv_msg(struct nc_session *session, int timeout, NC_MSG_TYPE expected, struct l cont_ptr = &((*cont_ptr)->next); } *cont_ptr = malloc(sizeof **cont_ptr); - if (!*cont_ptr) { - ERRMEM; - ret = NC_MSG_ERROR; - goto cleanup_unlock; - } + NC_CHECK_ERRMEM_GOTO(!*cont_ptr, ret = NC_MSG_ERROR, cleanup_unlock); (*cont_ptr)->msg = msg; msg = NULL; (*cont_ptr)->type = ret; @@ -2479,10 +2440,8 @@ nc_recv_notif_dispatch_data(struct nc_session *session, nc_notif_dispatch_clb no } ntarg = malloc(sizeof *ntarg); - if (!ntarg) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!ntarg, -1); + ntarg->session = session; ntarg->notif_clb = notif_clb; ntarg->user_data = user_data; diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c index 50eb1d2c..02a8c7a5 100644 --- a/src/session_client_ssh.c +++ b/src/session_client_ssh.c @@ -333,12 +333,14 @@ nc_client_ssh_do_dnssec_sshfp_check(ssh_session session, enum ssh_keytypes_e srv if ((srv_pubkey_type != SSH_KEYTYPE_UNKNOWN) && (srv_pubkey_type != SSH_KEYTYPE_RSA1)) { if (srv_pubkey_type == SSH_KEYTYPE_DSS) { - /* TODO else branch? */ ret = sshauth_hostkey_hash_dnssec_check(hostname, hash_sha1, 2, 1); } else if (srv_pubkey_type == SSH_KEYTYPE_RSA) { ret = sshauth_hostkey_hash_dnssec_check(hostname, hash_sha1, 1, 1); } else if (srv_pubkey_type == SSH_KEYTYPE_ECDSA) { ret = sshauth_hostkey_hash_dnssec_check(hostname, hash_sha1, 3, 1); + } else { + /* other key types not supported */ + ret = 1; } /* DNSSEC SSHFP check successful, that's enough */ @@ -515,10 +517,7 @@ sshauth_password(const char *username, const char *hostname, void *UNUSED(priv)) FILE *in = NULL, *out = NULL; buf = malloc(buflen * sizeof *buf); - if (!buf) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!buf, NULL); if (!(in = nc_open_in(0, &oldterm))) { goto error; @@ -538,10 +537,7 @@ sshauth_password(const char *username, const char *hostname, void *UNUSED(priv)) if (len >= buflen - 1) { buflen *= 2; buf = nc_realloc(buf, buflen * sizeof *buf); - if (!buf) { - ERRMEM; - goto error; - } + NC_CHECK_ERRMEM_GOTO(!buf,; , error); } buf[len++] = (char)c; } @@ -570,10 +566,7 @@ sshauth_interactive(const char *auth_name, const char *instruction, const char * FILE *in = NULL, *out = NULL; buf = malloc(buflen * sizeof *buf); - if (!buf) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!buf, NULL); if (!(in = nc_open_in(echo, &oldterm))) { goto error; @@ -601,10 +594,7 @@ sshauth_interactive(const char *auth_name, const char *instruction, const char * if (cur_len >= buflen - 1) { buflen *= 2; buf = nc_realloc(buf, buflen * sizeof *buf); - if (!buf) { - ERRMEM; - goto error; - } + NC_CHECK_ERRMEM_GOTO(!buf,; , error); } buf[cur_len++] = (char)c; } @@ -633,10 +623,7 @@ sshauth_privkey_passphrase(const char *privkey_path, void *UNUSED(priv)) FILE *in = NULL, *out = NULL; buf = malloc(buflen * sizeof *buf); - if (!buf) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!buf, NULL); if (!(in = nc_open_in(0, &oldterm))) { goto error; @@ -656,10 +643,7 @@ sshauth_privkey_passphrase(const char *privkey_path, void *UNUSED(priv)) if (len >= buflen - 1) { buflen *= 2; buf = nc_realloc(buf, buflen * sizeof *buf); - if (!buf) { - ERRMEM; - goto error; - } + NC_CHECK_ERRMEM_GOTO(!buf,; , error); } buf[len++] = (char)c; } @@ -689,10 +673,7 @@ nc_client_ssh_set_knownhosts_path(const char *path) } ssh_opts.knownhosts_path = strdup(path); - if (!ssh_opts.knownhosts_path) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!ssh_opts.knownhosts_path, 1); return 0; } @@ -897,18 +878,12 @@ _nc_client_ssh_add_keypair(const char *pub_key, const char *priv_key, struct nc_ /* add the keys */ ++opts->key_count; opts->keys = nc_realloc(opts->keys, opts->key_count * sizeof *opts->keys); - if (!opts->keys) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!opts->keys, -1); opts->keys[opts->key_count - 1].pubkey_path = strdup(pub_key); opts->keys[opts->key_count - 1].privkey_path = strdup(priv_key); opts->keys[opts->key_count - 1].privkey_crypt = 0; - if (!opts->keys[opts->key_count - 1].pubkey_path || !opts->keys[opts->key_count - 1].privkey_path) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!opts->keys[opts->key_count - 1].pubkey_path || !opts->keys[opts->key_count - 1].privkey_path, -1); /* check encryption */ if ((key = fopen(priv_key, "r"))) { @@ -962,10 +937,7 @@ _nc_client_ssh_del_keypair(int idx, struct nc_client_ssh_opts *opts) } if (opts->key_count) { opts->keys = nc_realloc(opts->keys, opts->key_count * sizeof *opts->keys); - if (!opts->keys) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!opts->keys, -1); } else { free(opts->keys); opts->keys = NULL; @@ -1101,10 +1073,7 @@ _nc_client_ssh_set_username(const char *username, struct nc_client_ssh_opts *opt } if (username) { opts->username = strdup(username); - if (!opts->username) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!opts->username, -1); } else { opts->username = NULL; } @@ -1519,10 +1488,7 @@ _nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx, struct nc_keepal /* prepare session structure */ session = nc_new_session(NC_CLIENT, 0); - if (!session) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!session, NULL); session->status = NC_STATUS_STARTING; session->ti_type = NC_TI_LIBSSH; session->ti.libssh.session = ssh_session; @@ -1538,10 +1504,7 @@ _nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx, struct nc_keepal /* remember host */ host = strdup("localhost"); - if (!host) { - ERRMEM; - goto fail; - } + NC_CHECK_ERRMEM_GOTO(!host,; , fail); ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_HOST, host); /* create and connect socket */ @@ -1578,10 +1541,7 @@ _nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx, struct nc_keepal } else { username = strdup(opts->username); } - if (!username) { - ERRMEM; - goto fail; - } + NC_CHECK_ERRMEM_GOTO(!username,; , fail); ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_USER, username); } @@ -1671,24 +1631,15 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx) if (ssh_opts.knownhosts_path) { /* known_hosts file path was set so use it */ known_hosts_path = strdup(ssh_opts.knownhosts_path); - if (!known_hosts_path) { - ERRMEM; - goto fail; - } + NC_CHECK_ERRMEM_GOTO(!known_hosts_path,; , fail); } else if (pw) { /* path not set explicitly, but current user's username found in /etc/passwd, so create the path */ - if (asprintf(&known_hosts_path, "%s/.ssh/known_hosts", pw->pw_dir) == -1) { - ERRMEM; - goto fail; - } + NC_CHECK_ERRMEM_GOTO(asprintf(&known_hosts_path, "%s/.ssh/known_hosts", pw->pw_dir) == -1,; , fail); } /* prepare session structure */ session = nc_new_session(NC_CLIENT, 0); - if (!session) { - ERRMEM; - goto fail; - } + NC_CHECK_ERRMEM_GOTO(!session,; , fail); session->status = NC_STATUS_STARTING; /* transport-specific data */ @@ -1773,10 +1724,7 @@ nc_connect_ssh_channel(struct nc_session *session, struct ly_ctx *ctx) /* prepare session structure */ new_session = nc_new_session(NC_CLIENT, 1); - if (!new_session) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!new_session, NULL); new_session->status = NC_STATUS_STARTING; /* share some parameters including the IO lock (we are using one socket for both sessions) */ diff --git a/src/session_client_tls.c b/src/session_client_tls.c index 1d4aa120..bf5dcdb7 100644 --- a/src/session_client_tls.c +++ b/src/session_client_tls.c @@ -168,17 +168,11 @@ _nc_client_tls_set_cert_key_paths(const char *client_cert, const char *client_ke free(opts->key_path); opts->cert_path = strdup(client_cert); - if (!opts->cert_path) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!opts->cert_path, -1); if (client_key) { opts->key_path = strdup(client_key); - if (!opts->key_path) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!opts->key_path, -1); } else { opts->key_path = NULL; } @@ -241,20 +235,14 @@ _nc_client_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir, str if (ca_file) { opts->ca_file = strdup(ca_file); - if (!opts->ca_file) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!opts->ca_file, -1); } else { opts->ca_file = NULL; } if (ca_dir) { opts->ca_dir = strdup(ca_dir); - if (!opts->ca_dir) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!opts->ca_dir, -1); } else { opts->ca_dir = NULL; } @@ -317,20 +305,14 @@ _nc_client_tls_set_crl_paths(const char *crl_file, const char *crl_dir, struct n if (crl_file) { opts->crl_file = strdup(crl_file); - if (!opts->crl_file) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!opts->crl_file, -1); } else { opts->crl_file = NULL; } if (crl_dir) { opts->crl_dir = strdup(crl_dir); - if (!opts->crl_dir) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!opts->crl_dir, -1); } else { opts->crl_dir = NULL; } @@ -567,10 +549,7 @@ nc_connect_tls(const char *host, unsigned short port, struct ly_ctx *ctx) /* prepare session structure */ session = nc_new_session(NC_CLIENT, 0); - if (!session) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!session, NULL); session->status = NC_STATUS_STARTING; /* fill the session */ @@ -649,10 +628,7 @@ nc_connect_libssl(SSL *tls, struct ly_ctx *ctx) /* prepare session structure */ session = nc_new_session(NC_CLIENT, 0); - if (!session) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!session, NULL); session->status = NC_STATUS_STARTING; session->ti_type = NC_TI_OPENSSL; session->ti.tls = tls; diff --git a/src/session_server.c b/src/session_server.c index be53450f..30db0403 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -447,10 +447,7 @@ sock_host_unix(int acc_sock_fd, char **host) return 0; } - if (!(*host = strdup(sun_path))) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!(*host = strdup(sun_path)), -1); return 0; } @@ -467,10 +464,7 @@ static int sock_host_inet(const struct sockaddr_in *addr, char **host, uint16_t *port) { *host = malloc(INET_ADDRSTRLEN); - if (!(*host)) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!(*host), -1); if (!inet_ntop(AF_INET, &addr->sin_addr, *host, INET_ADDRSTRLEN)) { ERR(NULL, "inet_ntop failed (%s).", strerror(errno)); @@ -496,10 +490,7 @@ static int sock_host_inet6(const struct sockaddr_in6 *addr, char **host, uint16_t *port) { *host = malloc(INET6_ADDRSTRLEN); - if (!(*host)) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!(*host), -1); if (!inet_ntop(AF_INET6, &addr->sin6_addr, *host, INET6_ADDRSTRLEN)) { ERR(NULL, "inet_ntop failed (%s).", strerror(errno)); @@ -525,10 +516,7 @@ nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, pthread_mutex_t int ret, client_sock, sock = -1, flags; pfd = malloc(bind_count * sizeof *pfd); - if (!pfd) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!pfd, -1); /* LOCK */ pthread_mutex_lock(bind_lock); @@ -938,10 +926,7 @@ nc_server_set_capability(const char *value) } mem = realloc(server_opts.capabilities, (server_opts.capabilities_count + 1) * sizeof *server_opts.capabilities); - if (!mem) { - ERRMEM; - return EXIT_FAILURE; - } + NC_CHECK_ERRMEM_RET(!mem, EXIT_FAILURE); server_opts.capabilities = mem; server_opts.capabilities[server_opts.capabilities_count] = strdup(value); @@ -980,10 +965,7 @@ nc_accept_inout(int fdin, int fdout, const char *username, const struct ly_ctx * /* prepare session structure */ *session = nc_new_session(NC_SERVER, 0); - if (!(*session)) { - ERRMEM; - return NC_MSG_ERROR; - } + NC_CHECK_ERRMEM_RET(!(*session), NC_MSG_ERROR); (*session)->status = NC_STATUS_STARTING; /* transport specific data */ @@ -1178,10 +1160,7 @@ nc_ps_new(void) struct nc_pollsession *ps; ps = calloc(1, sizeof(struct nc_pollsession)); - if (!ps) { - ERRMEM; - return NULL; - } + NC_CHECK_ERRMEM_RET(!ps, NULL); pthread_cond_init(&ps->cond, NULL); pthread_mutex_init(&ps->lock, NULL); @@ -1427,11 +1406,7 @@ nc_server_recv_rpc_io(struct nc_session *session, int io_timeout, struct nc_serv } *rpc = calloc(1, sizeof **rpc); - if (!*rpc) { - ERRMEM; - ret = NC_PSPOLL_ERROR; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!*rpc, ret = NC_PSPOLL_ERROR, cleanup); /* parse the RPC */ if (!lyd_parse_op(session->ctx, NULL, msg, LYD_XML, LYD_TYPE_RPC_NETCONF, &(*rpc)->envp, &(*rpc)->rpc)) { @@ -2128,13 +2103,7 @@ nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session) sock = ret; *session = nc_new_session(NC_SERVER, 0); - if (!(*session)) { - ERRMEM; - close(sock); - free(host); - msgtype = NC_MSG_ERROR; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!(*session), close(sock); free(host); msgtype = NC_MSG_ERROR, cleanup); (*session)->status = NC_STATUS_STARTING; (*session)->ctx = (struct ly_ctx *)ctx; (*session)->flags = NC_SESSION_SHAREDCTX; @@ -2319,13 +2288,7 @@ nc_connect_ch_endpt(struct nc_ch_endpt *endpt, nc_server_ch_session_acquire_ctx_ /* create session */ *session = nc_new_session(NC_SERVER, 0); - if (!(*session)) { - ERRMEM; - close(sock); - free(ip_host); - msgtype = NC_MSG_ERROR; - goto fail; - } + NC_CHECK_ERRMEM_GOTO(!(*session), close(sock); free(ip_host); msgtype = NC_MSG_ERROR, fail); (*session)->status = NC_STATUS_STARTING; (*session)->ctx = (struct ly_ctx *)ctx; (*session)->flags = NC_SESSION_SHAREDCTX | NC_SESSION_CALLHOME; @@ -2763,10 +2726,7 @@ nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_acqu } arg = malloc(sizeof *arg); - if (!arg) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!arg, -1); arg->client_name = strdup(client_name); if (!arg->client_name) { ERRMEM; diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index d4bb528f..402c91a0 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -351,11 +351,7 @@ nc_pam_conv_clb(int n_messages, const struct pam_message **msg, struct pam_respo *resp = calloc(n_requests, sizeof **resp); prompts = calloc(n_requests, sizeof *prompts); echo = calloc(n_requests, sizeof *echo); - if (!(*resp) || !prompts || !echo) { - ERRMEM; - r = PAM_BUF_ERR; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!(*resp) || !prompts || !echo, r = PAM_BUF_ERR, cleanup); /* set the prompts for the user */ j = 0; @@ -814,10 +810,7 @@ nc_sshcb_channel_subsystem(struct nc_session *session, ssh_channel channel, cons } else { /* additional channel subsystem request, new session is ready as far as SSH is concerned */ new_session = nc_new_session(NC_SERVER, 1); - if (!new_session) { - ERRMEM; - return -1; - } + NC_CHECK_ERRMEM_RET(!new_session, -1); /* insert the new session */ if (!session->ti.libssh.next) { diff --git a/src/session_server_tls.c b/src/session_server_tls.c index a48ae452..2dc68dfc 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -203,10 +203,7 @@ nc_tls_ctn_get_username_from_cert(X509 *client_cert, NC_TLS_CTN_MAPTYPE map_type *strchr(common_name, '/') = '\0'; } *username = strdup(common_name); - if (!*username) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!*username, 1); free(subject); } else { /* retrieve subjectAltName's rfc822Name (email), dNSName and iPAddress values */ @@ -224,10 +221,7 @@ nc_tls_ctn_get_username_from_cert(X509 *client_cert, NC_TLS_CTN_MAPTYPE map_type if (((map_type == NC_TLS_CTN_SAN_ANY) || (map_type == NC_TLS_CTN_SAN_RFC822_NAME)) && (san_name->type == GEN_EMAIL)) { *username = strdup((char *)ASN1_STRING_get0_data(san_name->d.rfc822Name)); - if (!*username) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!*username, 1); break; } @@ -235,10 +229,7 @@ nc_tls_ctn_get_username_from_cert(X509 *client_cert, NC_TLS_CTN_MAPTYPE map_type if (((map_type == NC_TLS_CTN_SAN_ANY) || (map_type == NC_TLS_CTN_SAN_DNS_NAME)) && (san_name->type == GEN_DNS)) { *username = strdup((char *)ASN1_STRING_get0_data(san_name->d.dNSName)); - if (!*username) { - ERRMEM; - return 1; - } + NC_CHECK_ERRMEM_RET(!*username, 1); break; } @@ -300,17 +291,15 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * { char *digest_md5 = NULL, *digest_sha1 = NULL, *digest_sha224 = NULL; char *digest_sha256 = NULL, *digest_sha384 = NULL, *digest_sha512 = NULL; - unsigned char *buf = malloc(64); + unsigned char *buf; unsigned int buf_len = 64; int ret = 0; struct nc_ctn *ctn; NC_TLS_CTN_MAPTYPE map_type; char *username = NULL; - if (!buf) { - ERRMEM; - return -1; - } + buf = malloc(buf_len); + NC_CHECK_ERRMEM_RET(!buf, -1); if (!session || !cert) { free(buf); @@ -456,11 +445,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * if (map_type == NC_TLS_CTN_SPECIFIED) { /* specified -> get username from the ctn entry */ session->username = strdup(ctn->name); - if (!session->username) { - ERRMEM; - ret = -1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!session->username, ret = -1, cleanup); } else { /* try to get the username from the cert with this ctn's map type */ ret = nc_tls_ctn_get_username_from_cert(session->opts.server.client_cert, map_type, &username); @@ -512,11 +497,7 @@ nc_server_tls_check_crl(X509_STORE *crl_store, X509_STORE_CTX *x509_ctx, X509 *c char *cp; store_ctx = X509_STORE_CTX_new(); - if (!store_ctx) { - ERRMEM; - ret = -1; - goto cleanup; - } + NC_CHECK_ERRMEM_GOTO(!store_ctx, ret = -1, cleanup); /* init store context */ ret = X509_STORE_CTX_init(store_ctx, crl_store, NULL, NULL); @@ -1126,10 +1107,7 @@ nc_server_tls_curl_cb(char *ptr, size_t size, size_t nmemb, void *userdata) data = (struct nc_curl_data *)userdata; data->data = nc_realloc(data->data, data->size + size); - if (!data->data) { - ERRMEM; - return 0; - } + NC_CHECK_ERRMEM_RET(!data->data, 0); memcpy(&data->data[data->size], ptr, size); data->size += size; @@ -1361,10 +1339,7 @@ nc_tls_store_set_crl(struct nc_session *session, struct nc_server_tls_opts *opts if (!opts->crl_store) { /* first call on this endpoint */ opts->crl_store = X509_STORE_new(); - if (!opts->crl_store) { - ERRMEM; - goto fail; - } + NC_CHECK_ERRMEM_GOTO(!opts->crl_store,; , fail); } if (opts->crl_path) { From 01d5edebd79342023148f7236447176c74002e74 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 11:15:53 +0200 Subject: [PATCH 105/134] server_config UPDATE access time value directly --- src/server_config.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 82c90ba6..9672aec7 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -24,6 +24,7 @@ #include #include +#include #ifdef NC_ENABLED_SSH_TLS #include @@ -3911,7 +3912,7 @@ nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; struct nc_ch_client *ch_client; - time_t anchor_time = {0}; + struct lyd_value_date_and_time *anchor_time; assert(!strcmp(LYD_NAME(node), "anchor-time")); @@ -3921,13 +3922,11 @@ nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op) return 1; } - ret = ly_time_str2time(lyd_get_value(node), &anchor_time, NULL); - if (ret) { - goto cleanup; - } + /* get the value of time from the node directly */ + LYD_VALUE_GET(&((struct lyd_node_term *)node)->value, anchor_time); if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_client->anchor_time = anchor_time; + ch_client->anchor_time = anchor_time->time; } else if (op == NC_OP_DELETE) { ch_client->anchor_time = 0; } From db012492a9a278b31ab93dd73f00c7c90fb5dab6 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 11:16:14 +0200 Subject: [PATCH 106/134] server_config_p UPDATE remove cpp from priv header --- src/server_config_p.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/server_config_p.h b/src/server_config_p.h index a17f2f3d..15584257 100644 --- a/src/server_config_p.h +++ b/src/server_config_p.h @@ -16,10 +16,6 @@ #ifndef NC_CONFIG_SERVER_P_H_ #define NC_CONFIG_SERVER_P_H_ -#ifdef __cplusplus -extern "C" { -#endif - #include #include #include @@ -158,8 +154,4 @@ int nc_server_config_ts_truststore(const struct lyd_node *node, NC_OPERATION op) #endif /* NC_ENABLED_SSH_TLS */ -#ifdef __cplusplus -} -#endif - #endif /* NC_CONFIG_SERVER_P_H_ */ From 86ffb2d9f85d974156dd001e0c61524567a919e5 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 11:26:57 +0200 Subject: [PATCH 107/134] server_config_util UPDATE print uint correctly --- src/server_config.c | 1 - src/server_config_util.c | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 9672aec7..ce67f576 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -3931,7 +3931,6 @@ nc_server_config_anchor_time(const struct lyd_node *node, NC_OPERATION op) ch_client->anchor_time = 0; } -cleanup: /* UNLOCK */ nc_ch_client_unlock(ch_client); return ret; diff --git a/src/server_config_util.c b/src/server_config_util.c index e02b98f9..914004d0 100644 --- a/src/server_config_util.c +++ b/src/server_config_util.c @@ -18,6 +18,8 @@ #include "server_config_util.h" #include + +#include #include #include #include @@ -1411,7 +1413,7 @@ nc_server_config_add_ch_period(const struct ly_ctx *ctx, const char *ch_client_n return 1; } - sprintf(buf, "%u", period); + sprintf(buf, "%" PRIu16, period); return nc_server_config_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/periodic/period", ch_client_name); } @@ -1464,7 +1466,7 @@ nc_server_config_add_ch_idle_timeout(const struct ly_ctx *ctx, const char *ch_cl return 1; } - sprintf(buf, "%u", idle_timeout); + sprintf(buf, "%" PRIu16, idle_timeout); return nc_server_config_create(ctx, config, buf, "/ietf-netconf-server:netconf-server/call-home/" "netconf-client[name='%s']/connection-type/periodic/idle-timeout", ch_client_name); } @@ -1510,7 +1512,7 @@ nc_server_config_add_ch_reconnect_strategy(const struct ly_ctx *ctx, const char } if (max_attempts) { - sprintf(buf, "%u", max_attempts); + sprintf(buf, "%" PRIu8, max_attempts); ret = nc_server_config_append(ctx, path, "max-attempts", buf, config); if (ret) { goto cleanup; @@ -1519,7 +1521,7 @@ nc_server_config_add_ch_reconnect_strategy(const struct ly_ctx *ctx, const char } if (max_wait) { - sprintf(buf, "%u", max_wait); + sprintf(buf, "%" PRIu16, max_wait); ret = nc_server_config_append(ctx, path, "max-wait", buf, config); if (ret) { goto cleanup; From 5bf8d55b532c639a349c55298f3fe9b241c9493b Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 12:14:12 +0200 Subject: [PATCH 108/134] session_client_ssh REFACTOR shorten knownhosts err --- src/session_client_ssh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c index 02a8c7a5..95f9a0c8 100644 --- a/src/session_client_ssh.c +++ b/src/session_client_ssh.c @@ -388,7 +388,7 @@ nc_client_ssh_auth_hostkey_check(const char *hostname, uint16_t port, ssh_sessio case SSH_KNOWN_HOSTS_CHANGED: if (knownhosts_mode == NC_SSH_KNOWNHOSTS_ACCEPT) { /* is the mode is set to accept, then accept any connection even if the remote key changed */ - WRN(NULL, "Remote host key changed, but you have requested accept mode so the connection will not be terminated."); + WRN(NULL, "Remote host key changed!"); break; } else { ERR(NULL, "Remote host key changed, the connection will be terminated!"); @@ -423,7 +423,7 @@ nc_client_ssh_auth_hostkey_check(const char *hostname, uint16_t port, ssh_sessio if (knownhosts_mode == NC_SSH_KNOWNHOSTS_STRICT) { /* do not connect if the hostkey is not present in known_hosts file in this mode */ - ERR(NULL, "No %s host key is known for [%s]:%hu and you have requested strict checking.\n", ssh_key_type_to_char(srv_pubkey_type), hostname, port); + ERR(NULL, "No %s host key is known for [%s]:%hu.\n", ssh_key_type_to_char(srv_pubkey_type), hostname, port); goto error; } else if ((knownhosts_mode == NC_SSH_KNOWNHOSTS_ACCEPT_NEW) || (knownhosts_mode == NC_SSH_KNOWNHOSTS_ACCEPT)) { /* add a new entry to the known_hosts file without prompting */ From 6c9d7fc5363025515985f60e783a098f820d681e Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 12:16:25 +0200 Subject: [PATCH 109/134] session_server_ssh REFACTOR remove redundant () --- src/session_server_ssh.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index 402c91a0..fa0dad3b 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -399,7 +399,7 @@ nc_pam_conv_clb(int n_messages, const struct pam_message **msg, struct pam_respo } usleep(NC_TIMEOUT_STEP); - } while ((opts->auth_timeout) && (nc_timeouttime_cur_diff(&ts_timeout) >= 1)); + } while (opts->auth_timeout && (nc_timeouttime_cur_diff(&ts_timeout) >= 1)); if (!reply) { ERR(NULL, "Authentication timeout."); @@ -1119,7 +1119,7 @@ nc_accept_ssh_session_open_netconf_channel(struct nc_session *session, struct nc } usleep(NC_TIMEOUT_STEP); - if ((opts->auth_timeout) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) { + if (opts->auth_timeout && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) { /* timeout */ ERR(session, "Failed to start \"netconf\" SSH subsystem for too long, disconnecting."); break; @@ -1221,7 +1221,7 @@ nc_accept_ssh_session_auth(struct nc_session *session, struct nc_server_ssh_opts } usleep(NC_TIMEOUT_STEP); - if ((opts->auth_timeout) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) { + if (opts->auth_timeout && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) { /* timeout */ break; } From c8629ea9a5f0dbd3d0bf5bd6009d2cf398480955 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 13:35:22 +0200 Subject: [PATCH 110/134] compat UPDATE define crypt_r --- CMakeModules/UseCompat.cmake | 8 ++++++++ compat/compat.c | 19 +++++++++++++++++++ compat/compat.h.in | 6 ++++++ src/server_config_util_ssh.c | 19 ++----------------- src/session_server_ssh.c | 17 ++--------------- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/CMakeModules/UseCompat.cmake b/CMakeModules/UseCompat.cmake index 144a6368..f9dc007b 100644 --- a/CMakeModules/UseCompat.cmake +++ b/CMakeModules/UseCompat.cmake @@ -62,6 +62,14 @@ macro(USE_COMPAT) check_symbol_exists(get_current_dir_name "unistd.h" HAVE_GET_CURRENT_DIR_NAME) + # crypt + if(${CMAKE_SYSTEM_NAME} MATCHES "QNX") + list(APPEND CMAKE_REQUIRED_LIBRARIES -llogin) + elseif(NOT APPLE) + list(APPEND CMAKE_REQUIRED_LIBRARIES -lcrypt) + endif() + check_symbol_exists(crypt_r "crypt.h" HAVE_CRYPT_R) + TEST_BIG_ENDIAN(IS_BIG_ENDIAN) check_include_file("stdatomic.h" HAVE_STDATOMIC) diff --git a/compat/compat.c b/compat/compat.c index d0495b28..88a3b698 100644 --- a/compat/compat.c +++ b/compat/compat.c @@ -16,6 +16,7 @@ #include "compat.h" +#include #include #include #include @@ -372,3 +373,21 @@ get_current_dir_name(void) } #endif + +#ifndef HAVE_CRYPT_R +char * +crypt_r(const char *phrase, const char *setting, struct crypt_data *data) +{ + static pthread_mutex_t crypt_lock = PTHREAD_MUTEX_INITIALIZER; + char *hash; + + (void) data; + + pthread_mutex_lock(&crypt_lock); + hash = crypt(phrase, setting); + pthread_mutex_unlock(&crypt_lock); + + return hash; +} + +#endif diff --git a/compat/compat.h.in b/compat/compat.h.in index 2c6495d6..f1161523 100644 --- a/compat/compat.h.in +++ b/compat/compat.h.in @@ -18,6 +18,7 @@ #define _GNU_SOURCE /* pthread_rwlock_t */ #include +#include #include #include #include @@ -69,6 +70,7 @@ #cmakedefine HAVE_STRDUPA #cmakedefine HAVE_STRCHRNUL #cmakedefine HAVE_GET_CURRENT_DIR_NAME +#cmakedefine HAVE_CRYPT_R #ifndef bswap64 #define bswap64(val) \ @@ -204,4 +206,8 @@ char *strchrnul(const char *s, int c); char *get_current_dir_name(void); #endif +#ifndef HAVE_CRYPT_R +char *crypt_r(const char *phrase, const char *setting, struct crypt_data *data); +#endif + #endif /* _COMPAT_H_ */ diff --git a/src/server_config_util_ssh.c b/src/server_config_util_ssh.c index 00cfe744..f3ca8c03 100644 --- a/src/server_config_util_ssh.c +++ b/src/server_config_util_ssh.c @@ -32,10 +32,6 @@ #include "server_config.h" #include "session_p.h" -#if !defined (HAVE_CRYPT_R) -extern pthread_mutex_t crypt_lock; -#endif - static int _nc_server_config_add_ssh_hostkey(const struct ly_ctx *ctx, const char *tree_path, const char *privkey_path, const char *pubkey_path, struct lyd_node **config) @@ -389,22 +385,11 @@ _nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char *tr int ret = 0; char *hashed_pw = NULL; const char *salt = "$6$idsizuippipk$"; + struct crypt_data cdata = {0}; NC_CHECK_ARG_RET(NULL, ctx, tree_path, password, config, 1); -#ifdef HAVE_CRYPT_R - struct crypt_data cdata; -#endif - -#ifdef HAVE_CRYPT_R - cdata.initialized = 0; - hashed_pw = crypt_r(password, salt, &data); -#else - pthread_mutex_lock(&crypt_lock); - hashed_pw = crypt(password, salt); - pthread_mutex_unlock(&crypt_lock); -#endif - + hashed_pw = crypt_r(password, salt, &cdata); if (!hashed_pw) { ERR(NULL, "Hashing password failed (%s).", strerror(errno)); ret = 1; diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index fa0dad3b..c4c3085f 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -50,10 +50,6 @@ #include "session.h" #include "session_p.h" -#if !defined (HAVE_CRYPT_R) -pthread_mutex_t crypt_lock = PTHREAD_MUTEX_INITIALIZER; -#endif - extern struct nc_server_opts server_opts; static char * @@ -224,10 +220,7 @@ static int auth_password_compare_pwd(const char *stored_pw, const char *received_pw) { char *received_pw_hash = NULL; - -#ifdef HAVE_CRYPT_R - struct crypt_data cdata; -#endif + struct crypt_data cdata = {0}; if (!stored_pw[0]) { if (!received_pw[0]) { @@ -245,15 +238,9 @@ auth_password_compare_pwd(const char *stored_pw, const char *received_pw) return strcmp(stored_pw + 3, received_pw); } -#ifdef HAVE_CRYPT_R - cdata.initialized = 0; received_pw_hash = crypt_r(received_pw, stored_pw, &cdata); -#else - pthread_mutex_lock(&crypt_lock); - received_pw_hash = crypt(received_pw, stored_pw); - pthread_mutex_unlock(&crypt_lock); -#endif if (!received_pw_hash) { + ERR(NULL, "Hashing the password failed (%s).", strerror(errno)); return 1; } From 08298404af816c812c9cf8ca74b8afa32e72c605 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 14:51:44 +0200 Subject: [PATCH 111/134] tests UPDATE add back client tests --- tests/CMakeLists.txt | 19 +-- tests/client/test_client.c | 141 ------------------ tests/{client => }/test_client_messages.c | 0 tests/{client => }/test_client_ssh.c | 168 ++-------------------- tests/{client => }/test_client_tls.c | 0 5 files changed, 12 insertions(+), 316 deletions(-) delete mode 100644 tests/client/test_client.c rename tests/{client => }/test_client_messages.c (100%) rename tests/{client => }/test_client_ssh.c (65%) rename tests/{client => }/test_client_tls.c (100%) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b3e75485..3b3a4088 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,15 +8,14 @@ if(${SOURCE_FORMAT_ENABLED}) endif() # list of all the tests that don't require SSH and TLS -set(tests test_unix_socket test_client_thread test_fd_comm test_init_destroy_client test_init_destroy_server test_io test_thread_messages) +set(tests test_unix_socket test_client_thread test_fd_comm test_init_destroy_client test_init_destroy_server + test_io test_thread_messages test_client_messages test_client_ssh test_client_tls) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) list(APPEND tests test_auth) endif() -# set(client_tests test_client test_client_messages) - # add -Wl,--wrap flags set(test test_client_ssh) set(${test}_mock_funcs connect ssh_connect ssh_userauth_none ssh_userauth_kbdint ssh_is_connected @@ -55,31 +54,17 @@ foreach(test_name IN LISTS tests) add_test(NAME ${test_name} COMMAND $) endforeach() -# foreach(test_name IN LISTS client_tests) -# add_executable(${test_name} $ ./client/${test_name}.c) -# target_link_libraries(${test_name} ${CMOCKA_LIBRARIES} ${LIBYANG_LIBRARIES} netconf2) -# target_include_directories(${test_name} PRIVATE ${CMOCKA_INCLUDE_DIR}) -# set_target_properties(${test_name} PROPERTIES LINK_FLAGS "${${test_name}_wrap_link_flags}") -# add_test(NAME ${test_name} COMMAND $) -# endforeach() - if(ENABLE_VALGRIND_TESTS) foreach(test_name IN LISTS tests) add_test(${test_name}_valgrind valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 --suppressions=${PROJECT_SOURCE_DIR}/tests/library_valgrind.supp ${CMAKE_BINARY_DIR}/tests/${test_name}) endforeach() - - # foreach(test_name IN LISTS client_tests) - # add_test(${test_name}_valgrind valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 - # --suppressions=${PROJECT_SOURCE_DIR}/tests/library_valgrind.supp ${CMAKE_BINARY_DIR}/tests/${test_name}) - # endforeach() endif() include_directories(${CMAKE_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}) configure_file("${PROJECT_SOURCE_DIR}/tests/config.h.in" "${PROJECT_BINARY_DIR}/tests/config.h" ESCAPE_QUOTES @ONLY) if(LIBPAM_HAVE_CONFDIR) - #compile PAM test module add_library(pam_netconf SHARED ${CMAKE_SOURCE_DIR}/tests/pam/pam_netconf.c) set_target_properties(pam_netconf PROPERTIES PREFIX "") diff --git a/tests/client/test_client.c b/tests/client/test_client.c deleted file mode 100644 index 722d0bf1..00000000 --- a/tests/client/test_client.c +++ /dev/null @@ -1,141 +0,0 @@ -/** - * @file test_client.c - * @author David Sedlák - * @brief client test - * - * Copyright (c) 2018 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 - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "tests/config.h" - -static int -setup_f(void **state) -{ - (void)state; - - nc_verbosity(NC_VERB_VERBOSE); - - return 0; -} - -static int -teardown_f(void **state) -{ - (void)state; - - return 0; -} - -static void -test_nc_client_setting_schema_searchpath(void **state) -{ - (void)state; - const char *path; - int ret; - - /* initiate client */ - nc_client_init(); - - path = nc_client_get_schema_searchpath(); - assert_null(path); - - ret = nc_client_set_schema_searchpath("path"); - assert_int_equal(ret, 0); - path = nc_client_get_schema_searchpath(); - assert_string_equal(path, "path"); - - ret = nc_client_set_schema_searchpath("path1"); - assert_int_equal(ret, 0); - path = nc_client_get_schema_searchpath(); - assert_string_equal(path, "path1"); -} - -LY_ERR -test_clb(const char *mod_name, const char *mod_rev, const char *submod_name, const char *sub_rev, void *user_data, - LYS_INFORMAT *format, const char **model_data, void (**free_module_data)(void *model_data, void *user_data)) -{ - (void)mod_name; - (void)mod_rev; - (void)submod_name; - (void)sub_rev; - (void)user_data; - (void)format; - (void)model_data; - (void)free_module_data; - - return LY_SUCCESS; -} - -LY_ERR -test_clb1(const char *mod_name, const char *mod_rev, const char *submod_name, const char *sub_rev, void *user_data, - LYS_INFORMAT *format, const char **model_data, void (**free_module_data)(void *model_data, void *user_data)) -{ - (void)mod_name; - (void)mod_rev; - (void)submod_name; - (void)sub_rev; - (void)user_data; - (void)format; - (void)model_data; - (void)free_module_data; - - return LY_SUCCESS; -} - -static void -test_nc_client_setting_schema_callback(void **state) -{ - (void)state; - ly_module_imp_clb ret_f; - char *data_ret; - int ret; - - ret_f = nc_client_get_schema_callback((void **)&data_ret); - assert_null(ret_f); - assert_null(data_ret); - - ret = nc_client_set_schema_callback(test_clb, "DATA"); - assert_int_equal(ret, 0); - ret_f = nc_client_get_schema_callback((void **)&data_ret); - assert_ptr_equal(test_clb, ret_f); - assert_string_equal("DATA", data_ret); - - ret = nc_client_set_schema_callback(test_clb1, "DATA1"); - assert_int_equal(ret, 0); - ret_f = nc_client_get_schema_callback((void **)&data_ret); - assert_ptr_equal(test_clb1, ret_f); - assert_string_equal("DATA1", data_ret); - - /* destroy client */ - nc_client_destroy(); -} - -int -main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_nc_client_setting_schema_searchpath, setup_f, teardown_f), - cmocka_unit_test_setup_teardown(test_nc_client_setting_schema_callback, setup_f, teardown_f), - }; - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/tests/client/test_client_messages.c b/tests/test_client_messages.c similarity index 100% rename from tests/client/test_client_messages.c rename to tests/test_client_messages.c diff --git a/tests/client/test_client_ssh.c b/tests/test_client_ssh.c similarity index 65% rename from tests/client/test_client_ssh.c rename to tests/test_client_ssh.c index 0a66e597..b8fa940f 100644 --- a/tests/client/test_client_ssh.c +++ b/tests/test_client_ssh.c @@ -25,78 +25,15 @@ #include #include #include -#include #include #include #include -#include #include "tests/config.h" #include #include #include -const char *data = - "\n" - " \n" - " 10\n" - " \n" - " default-ssh\n" - " \n" - " \n" - " 127.0.0.1\n" - " 10005\n" - " \n" - " \n" - " \n" - " \n" - " key\n" - " \n" - " \n" - " ct:ssh-public-key-format\n" - " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" - " ct:rsa-private-key-format\n" - " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " test\n" - " \n" - " \n" - " \n" - " client\n" - " ct:ssh-public-key-format\n" - " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " sshpka:rsa-sha2-512\n" - " \n" - " \n" - " sshkea:curve25519-sha256\n" - " \n" - " \n" - " sshea:aes256-ctr\n" - " \n" - " \n" - " sshma:hmac-sha2-512\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n"; - static int setup_f(void **state) { @@ -105,10 +42,15 @@ setup_f(void **state) nc_verbosity(NC_VERB_VERBOSE); + /* init client */ + nc_client_init(); + ret = nc_client_ssh_set_username("username"); assert_int_equal(ret, 0); ret = nc_client_ssh_ch_set_username("ch_username"); assert_int_equal(ret, 0); + /* skip all hostkey and known_hosts checks */ + nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP); return 0; } @@ -117,6 +59,7 @@ static int teardown_f(void **state) { (void)state; + /* destroy client */ nc_client_destroy(); return 0; } @@ -269,10 +212,11 @@ __wrap_nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepali } MOCK int -__wrap_nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, char **host, uint16_t *port, uint16_t *idx) +__wrap_nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, pthread_mutex_t *bind_lock, int timeout, char **host, uint16_t *port, uint16_t *idx) { (void)binds; (void)bind_count; + (void)bind_lock; (void)timeout; (void)host; (void)port; @@ -293,25 +237,6 @@ __wrap_nc_accept_callhome_ssh_sock(int sock, const char *host, uint16_t port, st return mock_ptr_type(struct nc_session *); } -static void -test_nc_client_ssh_setting_auth_hostkey_check_clb(void **state) -{ - (void)state; - // int (*ret_f)(const char *hostname, ssh_session session, void *priv); - // char *priv_data_ret; - - /// * ssh_hostkey_check_clb is set in setup_f */ - // nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret); - // assert_ptr_equal(ret_f, ssh_hostkey_check_clb); - // assert_null(priv_data_ret); - - /// * set different callback and private data */ - // nc_client_ssh_set_auth_hostkey_check_clb(test_hostkey_clb, "DATA"); - // nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret); - // assert_ptr_equal(ret_f, test_hostkey_clb); - // assert_string_equal(priv_data_ret, "DATA"); -} - char * test_pwd_clb1(const char *username, const char *hostname, void *priv) { @@ -501,9 +426,6 @@ test_nc_client_ssh_setting_auth_pref(void **state) (void)state; int ret; - /* initiate client, must be called in first test */ - nc_client_init(); - /* check default prefference settings according to documentation */ ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_INTERACTIVE); assert_int_equal(ret, 1); @@ -638,57 +560,11 @@ test_nc_connect_ssh_password_succesfull(void **state) nc_session_free(session, NULL); } -static void -test_nc_connect_ssh_pubkey_ecdsa_succesfull(void **state) -{ - (void)state; - struct nc_session *session; - int ret = 0; - - /* set authentication method to use password authentication */ - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); - nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); - - /* add keypair for authentication */ - ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_ecdsa.pub", TESTS_DIR "/data/key_ecdsa"); - assert_int_equal(ret, 0); - - /* fake succesfull connection */ - will_return(__wrap_connect, 0); - will_return(__wrap_ssh_connect, 0); - /* do not authenticate using no authentication method */ - will_return(__wrap_ssh_userauth_none, 1); - will_return(__wrap_ssh_userauth_try_publickey, 0); - will_return(__wrap_ssh_userauth_publickey, 0); - will_return(__wrap_ssh_is_connected, 1); - will_return(__wrap_ssh_channel_open_session, 0); - will_return(__wrap_ssh_channel_request_subsystem, 0); - - /* fake ssh function for recieving hello message */ - will_return(__wrap_ssh_is_connected, 1); - - will_return(__wrap_nc_handshake_io, 3); - will_return(__wrap_nc_ctx_check_and_fill, 0); - session = nc_connect_ssh("127.0.0.1", 8080, NULL); - assert_non_null(session); - - /* disconnect */ - will_return(__wrap_ssh_channel_poll_timeout, 0); - nc_session_free(session, NULL); - - /* delete the keypair */ - ret = nc_client_ssh_del_keypair(0); - assert_int_equal(ret, 0); -} - static void test_nc_connect_ssh_pubkey_succesfull(void **state) { (void)state; struct nc_session *session; - struct ly_ctx *ctx; - struct lyd_node *tree; int ret = 0; /* set authentication method to use password authentication */ @@ -697,13 +573,12 @@ test_nc_connect_ssh_pubkey_succesfull(void **state) nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); /* add keypair for authentication */ - ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa"); + ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_ecdsa.pub", TESTS_DIR "/data/key_ecdsa"); assert_int_equal(ret, 0); /* fake succesfull connection */ will_return(__wrap_connect, 0); will_return(__wrap_ssh_connect, 0); - will_return(__wrap_nc_sock_listen_inet, 0); /* do not authenticate using no authentication method */ will_return(__wrap_ssh_userauth_none, 1); will_return(__wrap_ssh_userauth_try_publickey, 0); @@ -717,30 +592,12 @@ test_nc_connect_ssh_pubkey_succesfull(void **state) will_return(__wrap_nc_handshake_io, 3); will_return(__wrap_nc_ctx_check_and_fill, 0); - - ret = ly_ctx_new(MODULES_DIR, 0, &ctx); - assert_int_equal(ret, 0); - - ret = nc_server_config_load_modules(&ctx); - assert_int_equal(ret, 0); - - ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree); - assert_int_equal(ret, 0); - - ret = nc_server_config_setup(tree); - assert_int_equal(ret, 0); - session = nc_connect_ssh("127.0.0.1", 8080, NULL); assert_non_null(session); /* disconnect */ will_return(__wrap_ssh_channel_poll_timeout, 0); - - /* free everything used */ nc_session_free(session, NULL); - lyd_free_all(tree); - nc_server_destroy(); - ly_ctx_destroy(ctx); } static void @@ -784,9 +641,6 @@ test_nc_connect_ssh_bad_hello(void **state) session = nc_connect_ssh("127.0.0.1", 8080, NULL); assert_null(session); - - /* destroy client, must be called in last test */ - nc_client_destroy(); } static void @@ -824,7 +678,7 @@ test_nc_client_ssh_ch_add_bind_listen(void **state) assert_int_equal(ret, -1); /* fake a successful CH ssh listening socket */ - will_return(__wrap_nc_sock_listen_inet, 1); + will_return(__wrap_nc_sock_listen_inet, 5); ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334); assert_int_equal(ret, 0); @@ -916,7 +770,6 @@ main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_pref, setup_f, teardown_f), - cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_hostkey_check_clb, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_password_clb, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_interactive_clb, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_privkey_passphrase_clb, setup_f, teardown_f), @@ -924,7 +777,6 @@ main(void) cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_username, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_connect_ssh_interactive_succesfull, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_connect_ssh_password_succesfull, setup_f, teardown_f), - cmocka_unit_test_setup_teardown(test_nc_connect_ssh_pubkey_ecdsa_succesfull, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_connect_ssh_pubkey_succesfull, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_connect_connection_failed, setup_f, teardown_f), cmocka_unit_test_setup_teardown(test_nc_connect_ssh_bad_hello, setup_f, teardown_f), diff --git a/tests/client/test_client_tls.c b/tests/test_client_tls.c similarity index 100% rename from tests/client/test_client_tls.c rename to tests/test_client_tls.c From 252ea5453157be428816f1a2a8c07b23762d73f9 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 14:55:17 +0200 Subject: [PATCH 112/134] client REFACTOR move param check & delete func def --- src/messages_client.c | 4 ++-- src/session_client_ch.h | 24 ------------------------ 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/messages_client.c b/src/messages_client.c index 5008865b..17ee70da 100644 --- a/src/messages_client.c +++ b/src/messages_client.c @@ -46,8 +46,8 @@ nc_rpc_act_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype) { struct nc_rpc_act_generic *rpc; - NC_CHECK_ARG_RET(NULL, data, data->next, NULL); - if (data->prev != data) { + NC_CHECK_ARG_RET(NULL, data, NULL); + if (data->next || data->prev != data) { ERR(NULL, "nc_rpc_act_generic missing data"); return NULL; } diff --git a/src/session_client_ch.h b/src/session_client_ch.h index a19b5268..916188c8 100644 --- a/src/session_client_ch.h +++ b/src/session_client_ch.h @@ -63,30 +63,6 @@ int nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **sess * @{ */ -/** - * @brief Set SSH Call Home authentication hostkey check (knownhosts) callback. - * - * Repetitive calling causes replacing of the previous callback and its private data. Caller is responsible for - * freeing the private data when necessary (the private data can be obtained by - * nc_client_ssh_ch_get_auth_hostkey_check_clb()). - * - * @param[in] auth_hostkey_check Function to call, returns 0 on success, non-zero in error. - * If NULL, the default callback is set. - * @param[in] priv Optional private data to be passed to the callback function. - */ -void nc_client_ssh_ch_set_auth_hostkey_check_clb(int (*auth_hostkey_check)(const char *hostname, ssh_session session, void *priv), - void *priv); - -/** - * @brief Get currently set SSH Call Home authentication hostkey check (knownhosts) callback and its private data - * previously set by nc_client_ssh_ch_set_auth_hostkey_check_clb(). - * - * @param[out] auth_hostkey_check Currently set callback, NULL in case of the default callback. - * @param[out] priv Currently set (optional) private data to be passed to the callback function. - */ -void nc_client_ssh_ch_get_auth_hostkey_check_clb(int (**auth_hostkey_check)(const char *hostname, ssh_session session, void *priv), - void **priv); - /** * @brief Set SSH Call Home password authentication callback. * From 038bb963e49537a985cfd5e3f786acdb26caf086 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 15:07:41 +0200 Subject: [PATCH 113/134] ln2 yang module UPDATE create groupings --- ...libnetconf2-netconf-server@2023-09-07.yang | 241 +++++++----------- 1 file changed, 99 insertions(+), 142 deletions(-) diff --git a/modules/libnetconf2-netconf-server@2023-09-07.yang b/modules/libnetconf2-netconf-server@2023-09-07.yang index 9708c547..6fb4b0f9 100644 --- a/modules/libnetconf2-netconf-server@2023-09-07.yang +++ b/modules/libnetconf2-netconf-server@2023-09-07.yang @@ -240,25 +240,10 @@ module libnetconf2-netconf-server { https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD"; } - augment "/ncs:netconf-server" { - leaf hello-timeout { - type uint16; - default 60; - description - "Represents the maximum number of seconds the server will wait for receiving a hello message."; - } - } - - augment "/ncs:netconf-server" { - leaf idle-timeout { - type uint16; - default 0; - description - "Represents the maximum number of seconds a NETCONF session may remain idle. The value of 0 represents indefinitely."; - } - } + grouping ssh-authentication-params-grouping { + description + "Grouping for SSH authentication parameters."; - augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { leaf auth-attempts { type uint16; default 3; @@ -268,53 +253,24 @@ module libnetconf2-netconf-server { leaf auth-timeout { type uint16; - default 10; + default 30; units "seconds"; description "Represents the maximum amount of seconds an authentication can go on for."; } } - // CH auth-attempts and auth-timeout - augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ - ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { - leaf auth-attempts { - type uint16; - default 3; - description - "Represents the number of failed attempts before an authentication is deemed unsuccessful."; - } - - leaf auth-timeout { - type uint16; - default 10; - units "seconds"; - description - "Represents the maximum amount of seconds an authentication can go on for."; - } - } + grouping keyboard-interactive-grouping { + description + "Grouping for the SSH Keyboard interactive authentication method."; - augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ - ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" { container keyboard-interactive { - presence ""; - leaf pam-config-file-name { - type string; - mandatory true; - } - leaf pam-config-file-dir { - type string; - } + presence "Indicates that PAM configuration file name has been configured. + This statement is present so the mandatory descendant + nodes do not imply that this node must be + configured."; description "Keyboard interactive SSH authentication method."; - } - } - - // CH KB int - augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ - ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" { - container keyboard-interactive { - presence ""; leaf pam-config-file-name { type string; mandatory true; @@ -322,70 +278,33 @@ module libnetconf2-netconf-server { leaf pam-config-file-dir { type string; } - description - "Keyboard interactive SSH authentication method."; } } - augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport" { + grouping endpoint-auth-reference-grouping { description - "Defines a new transport called UNIX socket."; - case unix-socket { - container unix-socket { - leaf path { - type string; - mandatory true; - } - leaf mode { - type string { - pattern '[0124567]{3}'; - } - } - leaf uid { - type uint16; - } - leaf gid { - type uint16; - } - } - } - } - - augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { - description - "Reference to another SSH endpoint's client-authentication container. - All the users set in the referencing endpoint will be tried first and if and only if - there is no match, the referenced endpoint's users will be tried. The references can be + "Reference to another endpoint. The purpose is to use the referenced endpoint's authentication mechanisms. + If a connection occurs on an endpoint, the connecting user will be tried to be authenticated + using the given endpoint's defined methods. If the user wasn't authenticated and the endpoint + references another endpoint, the authentication will be tried again. However, this time + using the referenced endpoint's mechanisms. The references can be multiple, however there must not be a cycle."; leaf endpoint-client-auth { - type leafref { - path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name"; - } - - must "deref(.)/../*[local-name() = 'ssh']"; - } - } - - augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { - description - "Reference to another TLS endpoint's client-authentication container. - All the users set in the referencing endpoint will be tried first and if and only if - there is no match, the referenced endpoint's users will be tried. The references can be - multiple, however there must not be a cycle."; - - leaf endpoint-client-auth { - type leafref { - path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name"; + type union { + type leafref { + path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name"; + } + type leafref { + path "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:name"; + } } - - must "deref(.)/../*[local-name() = 'tls']"; } } - augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { + grouping certificate-revocation-list-grouping { description - "Indicates that the TLS server is using a Certificate Revocation List + "A grouping for the Certificate Revocation List, which is used to authenticate clients or to deny access for certain certificates. The given Certificate Revocation List must be PEM or DER encoded."; @@ -425,47 +344,85 @@ module libnetconf2-netconf-server { } } - // CH CRL - augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ - ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { - description - "Indicates that the Call Home TLS server is using a Certificate Revocation List - to authenticate clients or to deny access for certain certificates. - The given Certificate Revocation List must be PEM or DER encoded."; + augment "/ncs:netconf-server" { + leaf hello-timeout { + type uint16; + default 60; + description + "Represents the maximum number of seconds the server will wait for receiving a hello message."; + } + } - reference - "RFC 5280: - Internet X.509 Public Key Infrastructure Certificate - and Certificate Revocation List (CRL) Profile"; + augment "/ncs:netconf-server" { + leaf idle-timeout { + type uint16; + default 0; + description + "Represents the maximum number of seconds a NETCONF session may remain idle. The value of 0 represents indefinitely."; + } + } - choice certificate-revocation-list { - leaf crl-url { - type string; - description - "An URL from which the Certificate Revocation List will be - downloaded and used. The HTTP protocol works, but other - protocols, such as FTP, may work as well."; - } + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { + uses ssh-authentication-params-grouping; + } - leaf crl-path { - type string; - description - "A path to a Certificate Revocation List file."; - } + augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { + uses ssh-authentication-params-grouping; + } - leaf crl-cert-ext { - type empty; - description - "Indicates that the Certificate Revocation List - Distribution Points extension will be used to fetch - Certificate Revocation Lists from. This will be done - for all the configured Certificate Authority certificates."; + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" { + uses keyboard-interactive-grouping; + } - reference - "RFC 5280: - Internet X.509 Public Key Infrastructure Certificate - and Certificate Revocation List (CRL) Profile, Section 4.2.1.13"; + augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" { + uses keyboard-interactive-grouping; + } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport" { + case unix-socket { + container unix-socket { + description + "Defines a new transport called UNIX socket."; + leaf path { + type string; + mandatory true; + } + leaf mode { + type string { + pattern '[0124567]{3}'; + } + } + leaf uid { + type uint16; + } + leaf gid { + type uint16; + } } } } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { + uses endpoint-auth-reference-grouping; + } + + augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { + uses endpoint-auth-reference-grouping; + } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { + uses endpoint-auth-reference-grouping; + } + + augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { + uses endpoint-auth-reference-grouping; + } + + augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { + uses certificate-revocation-list-grouping; + } + + augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { + uses certificate-revocation-list-grouping; + } } From 502fe0e0fc69f7e34eb6c630b8c5d8c5a2a9d938 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 15:34:37 +0200 Subject: [PATCH 114/134] examples UPDATE fix readme, add new line to config --- examples/README.md | 4 ++-- examples/config.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/README.md b/examples/README.md index 78565329..6cda2d79 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,7 +6,7 @@ The example server provides `ietf-yang-library` state data that are returned as ### Server Configuration The server's default configuration can be found in the `config.json` file. The YANG data stored in this file define three endpoints - two for SSH and one for UNIX socket. -You can modify this configuration in any way you like, but you need to make sure that it is valid. +You can modify this configuration in any way you want, however, configuring the server may fail if the configuration is not valid. ## Example usage ### Server @@ -25,7 +25,7 @@ After the server has been run, in another terminal instance, with the default co ``` $ client -u /tmp/.ln2-unix-socket get "/ietf-yang-library:yang-library/module-set/module[name='ietf-netconf']" ``` -In this case, `-u` means that a connection to an UNIX socket will be attemped and a path to the socket needs to be specified, that is `/tmp/ln2-unix-socket` by default. +In this case, `-u` means that a connection to an UNIX socket will be attempted and a path to the socket needs to be specified, that is `/tmp/ln2-unix-socket` by default. The `get` parameter is the name of the RPC and `/ietf-yang-library:yang-library/module-set/module[name='ietf-netconf']` is the RPC's optional XPath filter. ##### Server output diff --git a/examples/config.json b/examples/config.json index 4eb80162..510b1238 100644 --- a/examples/config.json +++ b/examples/config.json @@ -94,4 +94,4 @@ ] } } -} \ No newline at end of file +} From 7ae0ffeb8435cca3bb13aa0c63b7cc92758da446 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 15:36:22 +0200 Subject: [PATCH 115/134] log UPDATE replace ; with whitespace in new macro --- src/messages_client.c | 4 ++-- src/session.c | 6 +++--- src/session_client.c | 4 ++-- src/session_client_ssh.c | 16 ++++++++-------- src/session_server_tls.c | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/messages_client.c b/src/messages_client.c index 17ee70da..b210d7c5 100644 --- a/src/messages_client.c +++ b/src/messages_client.c @@ -475,10 +475,10 @@ nc_rpc_getdata(const char *datastore, const char *filter, const char *config_fil } if (origin_filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) { rpc->origin_filter = malloc(origin_filter_count * sizeof *rpc->origin_filter); - NC_CHECK_ERRMEM_GOTO(!rpc->origin_filter,; , error); + NC_CHECK_ERRMEM_GOTO(!rpc->origin_filter, , error); for (i = 0; i < origin_filter_count; ++i) { rpc->origin_filter[i] = strdup(origin_filter[i]); - NC_CHECK_ERRMEM_GOTO(!rpc->origin_filter[i],; , error); + NC_CHECK_ERRMEM_GOTO(!rpc->origin_filter[i], , error); ++rpc->origin_filter_count; } } else { diff --git a/src/session.c b/src/session.c index 2aed66e4..ddf10ab5 100644 --- a/src/session.c +++ b/src/session.c @@ -1077,7 +1077,7 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version) NC_CHECK_ARG_RET(NULL, ctx, NULL); cpblts = malloc(size * sizeof *cpblts); - NC_CHECK_ERRMEM_GOTO(!cpblts,; , error); + NC_CHECK_ERRMEM_GOTO(!cpblts, , error); cpblts[0] = strdup("urn:ietf:params:netconf:base:1.0"); cpblts[1] = strdup("urn:ietf:params:netconf:base:1.1"); count = 2; @@ -1179,10 +1179,10 @@ nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version) /* get content-id */ if (server_opts.content_id_clb) { yl_content_id = server_opts.content_id_clb(server_opts.content_id_data); - NC_CHECK_ERRMEM_GOTO(!yl_content_id,; , error); + NC_CHECK_ERRMEM_GOTO(!yl_content_id, , error); } else { yl_content_id = malloc(11); - NC_CHECK_ERRMEM_GOTO(!yl_content_id,; , error); + NC_CHECK_ERRMEM_GOTO(!yl_content_id, , error); sprintf(yl_content_id, "%u", ly_ctx_get_change_count(ctx)); } diff --git a/src/session_client.c b/src/session_client.c index c45d7647..0b4571ad 100644 --- a/src/session_client.c +++ b/src/session_client.c @@ -1436,7 +1436,7 @@ nc_connect_unix(const char *address, struct ly_ctx *ctx) /* prepare session structure */ session = nc_new_session(NC_CLIENT, 0); - NC_CHECK_ERRMEM_GOTO(!session,; , fail); + NC_CHECK_ERRMEM_GOTO(!session, , fail); session->status = NC_STATUS_STARTING; /* transport specific data */ @@ -1458,7 +1458,7 @@ nc_connect_unix(const char *address, struct ly_ctx *ctx) } username = strdup(pw->pw_name); free(buf); - NC_CHECK_ERRMEM_GOTO(!username,; , fail); + NC_CHECK_ERRMEM_GOTO(!username, , fail); session->username = username; /* NETCONF handshake */ diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c index 95f9a0c8..ff3c6255 100644 --- a/src/session_client_ssh.c +++ b/src/session_client_ssh.c @@ -537,7 +537,7 @@ sshauth_password(const char *username, const char *hostname, void *UNUSED(priv)) if (len >= buflen - 1) { buflen *= 2; buf = nc_realloc(buf, buflen * sizeof *buf); - NC_CHECK_ERRMEM_GOTO(!buf,; , error); + NC_CHECK_ERRMEM_GOTO(!buf, , error); } buf[len++] = (char)c; } @@ -594,7 +594,7 @@ sshauth_interactive(const char *auth_name, const char *instruction, const char * if (cur_len >= buflen - 1) { buflen *= 2; buf = nc_realloc(buf, buflen * sizeof *buf); - NC_CHECK_ERRMEM_GOTO(!buf,; , error); + NC_CHECK_ERRMEM_GOTO(!buf, , error); } buf[cur_len++] = (char)c; } @@ -643,7 +643,7 @@ sshauth_privkey_passphrase(const char *privkey_path, void *UNUSED(priv)) if (len >= buflen - 1) { buflen *= 2; buf = nc_realloc(buf, buflen * sizeof *buf); - NC_CHECK_ERRMEM_GOTO(!buf,; , error); + NC_CHECK_ERRMEM_GOTO(!buf, , error); } buf[len++] = (char)c; } @@ -1504,7 +1504,7 @@ _nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx, struct nc_keepal /* remember host */ host = strdup("localhost"); - NC_CHECK_ERRMEM_GOTO(!host,; , fail); + NC_CHECK_ERRMEM_GOTO(!host, , fail); ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_HOST, host); /* create and connect socket */ @@ -1541,7 +1541,7 @@ _nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx, struct nc_keepal } else { username = strdup(opts->username); } - NC_CHECK_ERRMEM_GOTO(!username,; , fail); + NC_CHECK_ERRMEM_GOTO(!username, , fail); ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_USER, username); } @@ -1631,15 +1631,15 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx) if (ssh_opts.knownhosts_path) { /* known_hosts file path was set so use it */ known_hosts_path = strdup(ssh_opts.knownhosts_path); - NC_CHECK_ERRMEM_GOTO(!known_hosts_path,; , fail); + NC_CHECK_ERRMEM_GOTO(!known_hosts_path, , fail); } else if (pw) { /* path not set explicitly, but current user's username found in /etc/passwd, so create the path */ - NC_CHECK_ERRMEM_GOTO(asprintf(&known_hosts_path, "%s/.ssh/known_hosts", pw->pw_dir) == -1,; , fail); + NC_CHECK_ERRMEM_GOTO(asprintf(&known_hosts_path, "%s/.ssh/known_hosts", pw->pw_dir) == -1, , fail); } /* prepare session structure */ session = nc_new_session(NC_CLIENT, 0); - NC_CHECK_ERRMEM_GOTO(!session,; , fail); + NC_CHECK_ERRMEM_GOTO(!session, , fail); session->status = NC_STATUS_STARTING; /* transport-specific data */ diff --git a/src/session_server_tls.c b/src/session_server_tls.c index 2dc68dfc..de898c84 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -1339,7 +1339,7 @@ nc_tls_store_set_crl(struct nc_session *session, struct nc_server_tls_opts *opts if (!opts->crl_store) { /* first call on this endpoint */ opts->crl_store = X509_STORE_new(); - NC_CHECK_ERRMEM_GOTO(!opts->crl_store,; , fail); + NC_CHECK_ERRMEM_GOTO(!opts->crl_store, , fail); } if (opts->crl_path) { From 16b8fcfb60b5a71ec4c6c2e55bbfd93c339d02f3 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 15:45:31 +0200 Subject: [PATCH 116/134] messages_client REFACTOR add missing parentheses --- src/messages_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/messages_client.c b/src/messages_client.c index b210d7c5..bc58b861 100644 --- a/src/messages_client.c +++ b/src/messages_client.c @@ -47,7 +47,7 @@ nc_rpc_act_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype) struct nc_rpc_act_generic *rpc; NC_CHECK_ARG_RET(NULL, data, NULL); - if (data->next || data->prev != data) { + if (data->next || (data->prev != data)) { ERR(NULL, "nc_rpc_act_generic missing data"); return NULL; } From 97d1a86a99f026cc1f7a4cf0602777e4bd30d49a Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 15:46:01 +0200 Subject: [PATCH 117/134] ci UPDATE add missing curl dependency --- .github/workflows/ci.yml | 28 ++-------------------------- .github/workflows/codeql.yml | 2 +- .github/workflows/devel-push.yml | 2 +- 3 files changed, 4 insertions(+), 28 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 77ec83e8..adac04dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ on: - devel env: - DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev + DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev libcurl4-openssl-dev jobs: git-branch: @@ -85,37 +85,13 @@ jobs: make-prepend: "", make-target: "" } - - { - name: "SSH Only", - os: "ubuntu-22.04", - build-type: "Debug", - dep-build-type: "Release", - cc: "gcc", - options: "-DENABLE_TLS=OFF -DENABLE_SSH=ON", - packages: "valgrind", - snaps: "", - make-prepend: "", - make-target: "" - } - - { - name: "TLS Only", - os: "ubuntu-22.04", - build-type: "Debug", - dep-build-type: "Release", - cc: "gcc", - options: "-DENABLE_TLS=ON -DENABLE_SSH=OFF", - packages: "valgrind", - snaps: "", - make-prepend: "", - make-target: "" - } - { name: "No SSH nor TLS", os: "ubuntu-22.04", build-type: "Debug", dep-build-type: "Release", cc: "gcc", - options: "-DENABLE_TLS=OFF -DENABLE_SSH=OFF", + options: "-DENABLE_SSH_TLS=OFF, packages: "valgrind", snaps: "", make-prepend: "", diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ff6b931b..d65fdba6 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -7,7 +7,7 @@ on: branches: [ "devel" ] env: - DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev + DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev libcurl4-openssl-dev jobs: git-branch: diff --git a/.github/workflows/devel-push.yml b/.github/workflows/devel-push.yml index 6289f6c1..cb694721 100644 --- a/.github/workflows/devel-push.yml +++ b/.github/workflows/devel-push.yml @@ -5,7 +5,7 @@ on: - devel env: - DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev + DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev libcurl4-openssl-dev COVERITY_PROJECT: CESNET%2Flibnetconf2 jobs: From 638ed0667ffca9e6acd05026a8d064f8d79ef1f2 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 15:47:50 +0200 Subject: [PATCH 118/134] cmake UPDATE remove client test folder from format --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b194e61..79fde55f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,7 +161,6 @@ set(format_sources src/*.c src/*.h tests/*.c - tests/client/*.c tests/pam/*.c) # From 0dbeb43ce481d96518bbb2eef6812583591c23cd Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 16:11:12 +0200 Subject: [PATCH 119/134] ci UPDATE fix ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adac04dd..660a6fbd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: build-type: "Debug", dep-build-type: "Release", cc: "gcc", - options: "-DENABLE_SSH_TLS=OFF, + options: "-DENABLE_SSH_TLS=OFF", packages: "valgrind", snaps: "", make-prepend: "", From ff4bf850a540dcb6d926889acf31b39eff8680e9 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 26 Oct 2023 16:18:22 +0200 Subject: [PATCH 120/134] cmake BUGFIX move compiling ssh/tls client tests --- tests/CMakeLists.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3b3a4088..01c7db53 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,13 +9,25 @@ endif() # list of all the tests that don't require SSH and TLS set(tests test_unix_socket test_client_thread test_fd_comm test_init_destroy_client test_init_destroy_server - test_io test_thread_messages test_client_messages test_client_ssh test_client_tls) + test_io test_thread_messages test_client_messages) # only enable PAM tests if the version of PAM is greater than 1.4 if(LIBPAM_HAVE_CONFDIR) list(APPEND tests test_auth) endif() +#append tests depending on SSH/TLS +if(ENABLE_SSH_TLS) + list(APPEND tests test_two_channels test_ks_ts test_ec + test_ed25519 test_replace test_endpt_share_clients test_tls test_crl test_ch + test_runtime_changes test_client_ssh test_client_tls) +endif() + +foreach(src IN LISTS libsrc) + list(APPEND test_srcs "../${src}") +endforeach() +add_library(testobj OBJECT ${test_srcs} ${compatsrc}) + # add -Wl,--wrap flags set(test test_client_ssh) set(${test}_mock_funcs connect ssh_connect ssh_userauth_none ssh_userauth_kbdint ssh_is_connected @@ -34,18 +46,6 @@ foreach(mock_func IN LISTS ${test}_mock_funcs) set(${test}_wrap_link_flags "${${test}_wrap_link_flags},--wrap=${mock_func}") endforeach() -#append tests depending on SSH/TLS -if(ENABLE_SSH_TLS) - list(APPEND tests test_two_channels test_ks_ts test_ec - test_ed25519 test_replace test_endpt_share_clients test_tls test_crl test_ch - test_runtime_changes) -endif() - -foreach(src IN LISTS libsrc) - list(APPEND test_srcs "../${src}") -endforeach() -add_library(testobj OBJECT ${test_srcs} ${compatsrc}) - foreach(test_name IN LISTS tests) add_executable(${test_name} $ ${test_name}.c) target_link_libraries(${test_name} ${CMOCKA_LIBRARIES} ${LIBYANG_LIBRARIES} netconf2) From 7c50ab6e29624a4631e69aacf450436a33da6367 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 2 Nov 2023 10:31:45 +0100 Subject: [PATCH 121/134] session server ch UPDATE ch threads creation --- doc/libnetconf.doc | 15 ++++++++++----- src/server_config.c | 12 ++++++++++++ src/session_p.h | 9 +++++++++ src/session_server.c | 14 ++++++++++++++ src/session_server_ch.h | 17 +++++++++++++++++ 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/doc/libnetconf.doc b/doc/libnetconf.doc index 9a788a4d..83ebe78e 100644 --- a/doc/libnetconf.doc +++ b/doc/libnetconf.doc @@ -245,7 +245,6 @@ * * Available in __nc_client.h__. * - * - ::nc_client_ssh_ch_set_auth_hostkey_check_clb() * - ::nc_client_ssh_ch_set_auth_password_clb() * - ::nc_client_ssh_ch_set_auth_interactive_clb() * - ::nc_client_ssh_ch_set_auth_privkey_passphrase_clb() @@ -485,10 +484,16 @@ * * _Call Home_ works with endpoints just like standard sessions, but * the options are organized a bit differently and endpoints are added - * for CH clients. However, one important difference is that - * once all the mandatory options are set, _libnetconf2_ __will not__ - * immediately start connecting to a client. It will do so only after - * calling ::nc_connect_ch_client_dispatch() in a separate thread. + * for CH clients. + * You may choose one of two approaches for creating a new Call Home + * session (or in other words making a server connect to a client). + * The first is to set all the required callbacks + * by calling ::nc_server_ch_set_dispatch_data(). By setting the callbacks, + * the server will automatically start connecting to a client, whenever + * a new Call Home client is created. + * The second approach is to create the Call Home thread manually. + * To do this, you need to call ::nc_connect_ch_client_dispatch(), + * which then creates a new thread and the server will start to connect. * Unix socket _Call Home_ sessions are not supported. * * Lastly, monitoring of these sessions is up to the application. diff --git a/src/server_config.c b/src/server_config.c index ce67f576..d31c1914 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -3745,6 +3745,18 @@ nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op) if (ret) { goto cleanup; } + + if (server_opts.ch_dispatch_data.acquire_ctx_cb && server_opts.ch_dispatch_data.release_ctx_cb && + server_opts.ch_dispatch_data.new_session_cb) { + /* we have all we need for dispatching a new call home thread */ + ret = nc_connect_ch_client_dispatch(lyd_get_value(lyd_child(node)), server_opts.ch_dispatch_data.acquire_ctx_cb, + server_opts.ch_dispatch_data.release_ctx_cb, server_opts.ch_dispatch_data.ctx_cb_data, + server_opts.ch_dispatch_data.new_session_cb, server_opts.ch_dispatch_data.new_session_cb_data); + if (ret) { + ERR(NULL, "Dispatching a new Call Home thread failed for Call Home client \"%s\".", lyd_get_value(lyd_child(node))); + goto cleanup; + } + } } else if (op == NC_OP_DELETE) { if (nc_server_config_get_ch_client(node, &ch_client)) { ret = 1; diff --git a/src/session_p.h b/src/session_p.h index 2f06a5c2..5d2ccb17 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -27,6 +27,7 @@ #include "compat.h" #include "config.h" #include "session_client.h" +#include "session_server_ch.h" /** * Enumeration of diff operation types. @@ -513,6 +514,14 @@ struct nc_server_opts { uint16_t ch_client_count; pthread_rwlock_t ch_client_lock; + struct nc_ch_dispatch_data { + nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb; + nc_server_ch_session_release_ctx_cb release_ctx_cb; + void *ctx_cb_data; + nc_server_ch_new_session_cb new_session_cb; + void *new_session_cb_data; + } ch_dispatch_data; + /* Atomic IDs */ ATOMIC_T new_session_id; ATOMIC_T new_client_id; diff --git a/src/session_server.c b/src/session_server.c index 30db0403..1fd84fbc 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -277,6 +277,20 @@ nc_server_init_ctx(struct ly_ctx **ctx) return ret; } +API void +nc_server_ch_set_dispatch_data(nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb, + nc_server_ch_session_release_ctx_cb release_ctx_cb, void *ctx_cb_data, nc_server_ch_new_session_cb new_session_cb, + void *new_session_cb_data) +{ + NC_CHECK_ARG_RET(NULL, acquire_ctx_cb, release_ctx_cb, new_session_cb, ); + + server_opts.ch_dispatch_data.acquire_ctx_cb = acquire_ctx_cb; + server_opts.ch_dispatch_data.release_ctx_cb = release_ctx_cb; + server_opts.ch_dispatch_data.ctx_cb_data = ctx_cb_data; + server_opts.ch_dispatch_data.new_session_cb = new_session_cb; + server_opts.ch_dispatch_data.new_session_cb_data = new_session_cb_data; +} + int nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepalives *ka) { diff --git a/src/session_server_ch.h b/src/session_server_ch.h index a465c094..6b5ff197 100644 --- a/src/session_server_ch.h +++ b/src/session_server_ch.h @@ -85,6 +85,7 @@ typedef void (*nc_server_ch_session_release_ctx_cb)(void *cb_data); * * @param[in] client_name Name of the CH client which established the session. * @param[in] new_session New established CH session, the pointer is internally discarded afterwards. + * @param[in] user_data Arbitrary new session callback data. * @return 0 on success; * @return non-zero on error and @p new_session is freed. */ @@ -105,6 +106,22 @@ int nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_ nc_server_ch_session_release_ctx_cb release_ctx_cb, void *ctx_cb_data, nc_server_ch_new_session_cb new_session_cb, void *new_session_cb_data); +/** + * @brief Set callbacks and their data for Call Home threads. + * + * If set, Call Home threads will be dispatched automatically upon creation of a new Call Home clients. + * Calling this will replace all the previously set callbacks and their data. + * + * @param[in] acquire_ctx_cb Callback for acquiring new session context. + * @param[in] release_ctx_cb Callback for releasing session context. + * @param[in] ctx_cb_data Arbitrary user data passed to @p acquire_ctx_cb and @p release_ctx_cb. + * @param[in] new_session_cb Callback called for every established session on the client. + * @param[in] new_session_cb_data Arbitrary user data passed to @p new_session_cb. + */ +void nc_server_ch_set_dispatch_data(nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb, + nc_server_ch_session_release_ctx_cb release_ctx_cb, void *ctx_cb_data, nc_server_ch_new_session_cb new_session_cb, + void *new_session_cb_data); + /** @} Server-side Call Home Functions */ #endif /* NC_ENABLED_SSH_TLS */ From b1fc1535697c7f2fe1990ae68937d9a1fbaef728 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 2 Nov 2023 10:33:57 +0100 Subject: [PATCH 122/134] server config UPDATE dynamic endpt references Get endpoint references dynamically based on referenced endpt name. Also some tls fixes. --- ...libnetconf2-netconf-server@2023-09-07.yang | 21 +- src/server_config.c | 330 ++++++++++++------ src/server_config_util_ssh.c | 4 +- src/server_config_util_tls.c | 4 +- src/session_p.h | 17 +- src/session_server.c | 16 + src/session_server_ssh.c | 11 +- src/session_server_tls.c | 94 ++--- 8 files changed, 329 insertions(+), 168 deletions(-) diff --git a/modules/libnetconf2-netconf-server@2023-09-07.yang b/modules/libnetconf2-netconf-server@2023-09-07.yang index 6fb4b0f9..0ef941f0 100644 --- a/modules/libnetconf2-netconf-server@2023-09-07.yang +++ b/modules/libnetconf2-netconf-server@2023-09-07.yang @@ -281,7 +281,7 @@ module libnetconf2-netconf-server { } } - grouping endpoint-auth-reference-grouping { + grouping endpoint-reference-grouping { description "Reference to another endpoint. The purpose is to use the referenced endpoint's authentication mechanisms. If a connection occurs on an endpoint, the connecting user will be tried to be authenticated @@ -290,14 +290,9 @@ module libnetconf2-netconf-server { using the referenced endpoint's mechanisms. The references can be multiple, however there must not be a cycle."; - leaf endpoint-client-auth { - type union { - type leafref { - path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name"; - } - type leafref { - path "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:name"; - } + leaf endpoint-reference { + type leafref { + path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name"; } } } @@ -403,19 +398,19 @@ module libnetconf2-netconf-server { } augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { - uses endpoint-auth-reference-grouping; + uses endpoint-reference-grouping; } augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" { - uses endpoint-auth-reference-grouping; + uses endpoint-reference-grouping; } augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { - uses endpoint-auth-reference-grouping; + uses endpoint-reference-grouping; } augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { - uses endpoint-auth-reference-grouping; + uses endpoint-reference-grouping; } augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" { diff --git a/src/server_config.c b/src/server_config.c index d31c1914..47bda15d 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -776,10 +776,60 @@ nc_server_config_del_ssh_opts(struct nc_bind *bind, struct nc_server_ssh_opts *o free(opts); } +static void +nc_server_config_del_endpt_references(const char *referenced_endpt_name) +{ + uint16_t i, j; + + for (i = 0; i < server_opts.endpt_count; i++) { + if (server_opts.endpts[i].referenced_endpt_name) { + if (!strcmp(server_opts.endpts[i].referenced_endpt_name, referenced_endpt_name)) { + free(server_opts.endpts[i].referenced_endpt_name); + server_opts.endpts[i].referenced_endpt_name = NULL; + + if (server_opts.endpts[i].ti == NC_TI_LIBSSH) { + server_opts.endpts[i].opts.ssh->referenced_endpt_name = NULL; + } else { + server_opts.endpts[i].opts.tls->referenced_endpt_name = NULL; + } + } + } + } + + /* LOCK */ + pthread_rwlock_rdlock(&server_opts.ch_client_lock); + for (i = 0; i < server_opts.ch_client_count; i++) { + /* LOCK */ + pthread_mutex_lock(&server_opts.ch_clients[i].lock); + for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) { + if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) { + if (!strcmp(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, referenced_endpt_name)) { + free(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name); + server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name = NULL; + + if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) { + server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = NULL; + } else { + server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = NULL; + } + } + } + } + /* UNLOCK */ + pthread_mutex_unlock(&server_opts.ch_clients[i].lock); + } + + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_client_lock); +} + void nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) { + /* delete any references to this endpoint */ + nc_server_config_del_endpt_references(endpt->name); free(endpt->name); + free(endpt->referenced_endpt_name); nc_server_config_del_ssh_opts(bind, endpt->opts.ssh); @@ -936,7 +986,10 @@ nc_server_config_del_tls_opts(struct nc_bind *bind, struct nc_server_tls_opts *o static void nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind) { + /* delete any references to this endpoint */ + nc_server_config_del_endpt_references(endpt->name); free(endpt->name); + free(endpt->referenced_endpt_name); nc_server_config_del_tls_opts(bind, endpt->opts.tls); @@ -2954,148 +3007,213 @@ nc_server_config_unix_socket(const struct lyd_node *node, NC_OPERATION op) #ifdef NC_ENABLED_SSH_TLS +static int +nc_server_config_check_endpt_reference_cycle(struct nc_endpt *original, struct nc_endpt *next) +{ + if (!next->referenced_endpt_name) { + /* no further reference -> no cycle */ + return 0; + } + + if (!strcmp(original->name, next->referenced_endpt_name)) { + /* found cycle */ + return 1; + } else { + if (nc_server_get_referenced_endpt(next->referenced_endpt_name, &next)) { + /* referenced endpoint does not exist */ + return 1; + } + + /* continue further */ + return nc_server_config_check_endpt_reference_cycle(original, next); + } +} + /** - * @brief Set all endpoint client auth references, which couldn't be set while parsing data. + * @brief Set all endpoint references. * * @return 0 on success, 1 on error. */ static int -nc_server_config_fill_endpt_client_auth(void) +nc_server_config_check_endpt_references(void) { uint16_t i, j; + struct nc_endpt *referenced_endpt = NULL; + /* first do listen endpoints */ for (i = 0; i < server_opts.endpt_count; i++) { /* go through all the endpoints */ if (server_opts.endpts[i].referenced_endpt_name) { - /* endpt has a reference, that hasn't been set yet */ - for (j = 0; j < server_opts.endpt_count; j++) { - /* go through all the endpts */ - if (!strcmp(server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[j].name)) { - /* found the endpoint we were looking for, - * assign the server opts from the referenced endpt */ - if (server_opts.endpts[i].ti == NC_TI_LIBSSH) { - server_opts.endpts[i].opts.ssh->endpt_client_ref = &server_opts.endpts[j]; - break; - } else if (server_opts.endpts[i].ti == NC_TI_OPENSSL) { - server_opts.endpts[i].opts.tls->endpt_client_ref = &server_opts.endpts[j]; - break; - } else { - ERRINT; - return 1; - } - } + /* get referenced endpt */ + if (nc_server_get_referenced_endpt(server_opts.endpts[i].referenced_endpt_name, &referenced_endpt)) { + ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" does not exist.", + server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name); + return 1; + } + + /* check if the endpoint references itself */ + if (&server_opts.endpts[i] == referenced_endpt) { + ERR(NULL, "Endpoint \"%s\" references itself.", server_opts.endpts[i].name); + return 1; + } + + /* check transport */ + if ((server_opts.endpts[i].ti != referenced_endpt->ti)) { + ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has different transport type.", + server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name); + return 1; + } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) { + ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has unsupported transport type.", + server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name); + return 1; } - /* didn't find the endpoint */ - if (j == server_opts.endpt_count) { - ERR(NULL, "Endpoint \"%s\" referenced by \"%s\" not found.", + /* check cyclic reference */ + if (nc_server_config_check_endpt_reference_cycle(&server_opts.endpts[i], referenced_endpt)) { + ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" creates a cycle.", server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name); return 1; } + + /* all went well, assign the name to the opts, so we can access it for auth */ + if (server_opts.endpts[i].ti == NC_TI_LIBSSH) { + server_opts.endpts[i].opts.ssh->referenced_endpt_name = referenced_endpt->name; + } else { + server_opts.endpts[i].opts.tls->referenced_endpt_name = referenced_endpt->name; + } } } - return 0; -} + /* now check all the call home endpoints */ + /* LOCK */ + pthread_rwlock_rdlock(&server_opts.ch_client_lock); + for (i = 0; i < server_opts.ch_client_count; i++) { + /* LOCK */ + pthread_mutex_lock(&server_opts.ch_clients[i].lock); + for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) { + if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) { + /* get referenced endpt */ + if (nc_server_get_referenced_endpt(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, &referenced_endpt)) { + ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" does not exist.", + server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name); + goto ch_fail; + } -static int -nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next) -{ - if (original->ti == NC_TI_LIBSSH) { - if (!next->opts.ssh->endpt_client_ref) { - /* no further reference -> no cycle */ - return 0; - } + /* check transport */ + if (server_opts.ch_clients[i].ch_endpts[j].ti != referenced_endpt->ti) { + ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has different transport type.", + server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name); + goto ch_fail; + } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) { + ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has unsupported transport type.", + server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name); + goto ch_fail; + } - if (next->opts.ssh->endpt_client_ref == original) { - /* found cycle */ - return 1; - } else { - /* continue further */ - return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref); - } - } else if (original->ti == NC_TI_OPENSSL) { - if (!next->opts.tls->endpt_client_ref) { - /* no further reference -> no cycle */ - return 0; - } + /* check cyclic reference */ + if (nc_server_config_check_endpt_reference_cycle(referenced_endpt, referenced_endpt)) { + ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" creates a cycle.", + server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name); + goto ch_fail; + } - if (next->opts.tls->endpt_client_ref == original) { - /* found cycle */ - return 1; - } else { - /* continue further */ - return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.tls->endpt_client_ref); + /* all went well, assign the name to the opts, so we can access it for auth */ + if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) { + server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = referenced_endpt->name; + } else { + server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = referenced_endpt->name; + } + } } - } else { - ERRINT; - return 1; + /* UNLOCK */ + pthread_mutex_unlock(&server_opts.ch_clients[i].lock); } + + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_client_lock); + return 0; + +ch_fail: + /* UNLOCK */ + pthread_mutex_unlock(&server_opts.ch_clients[i].lock); + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_client_lock); + return 1; } static int -nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION op) +nc_server_config_endpoint_reference(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - uint16_t i; - const char *endpt_name; - struct nc_endpt *endpt; + struct nc_endpt *endpt = NULL; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt = NULL; + struct nc_server_ssh_opts *ssh = NULL; + struct nc_server_tls_opts *tls = NULL; - assert(!strcmp(LYD_NAME(node), "endpoint-client-auth")); + assert(!strcmp(LYD_NAME(node), "endpoint-reference")); - /* get current endpoint */ - ret = nc_server_config_get_endpt(node, &endpt, NULL); + if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) { + /* to avoid unlock on fail */ + return 1; + } + + /* get endpt */ + if (is_listen(node)) { + ret = nc_server_config_get_endpt(node, &endpt, NULL); + } else { + ret = nc_server_config_get_ch_endpt(node, &ch_endpt); + } if (ret) { goto cleanup; } if (op == NC_OP_DELETE) { - if (is_ssh(node)) { - endpt->opts.ssh->endpt_client_ref = NULL; + if (endpt) { + free(endpt->referenced_endpt_name); + endpt->referenced_endpt_name = NULL; } else { - endpt->opts.tls->endpt_client_ref = NULL; + free(ch_endpt->referenced_endpt_name); + ch_endpt->referenced_endpt_name = NULL; } - goto cleanup; - } + if (is_ssh(node)) { + if (nc_server_config_get_ssh_opts(node, &ssh)) { + ret = 1; + goto cleanup; + } + + ssh->referenced_endpt_name = NULL; + } else { + if (nc_server_config_get_tls_opts(node, &tls)) { + ret = 1; + goto cleanup; + } - /* find the endpoint leafref is referring to */ - endpt_name = lyd_get_value(node); - for (i = 0; i < server_opts.endpt_count; i++) { - if (!strcmp(endpt_name, server_opts.endpts[i].name)) { - break; + tls->referenced_endpt_name = NULL; } - } - if (i == server_opts.endpt_count) { - /* endpt not found, save the name and try to look it up later */ - free(endpt->referenced_endpt_name); - endpt->referenced_endpt_name = strdup(endpt_name); - NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup); - goto cleanup; - } - - /* check for self reference */ - if (endpt == &server_opts.endpts[i]) { - ERR(NULL, "Self endpoint reference detected for endpoint \"%s\".", endpt->name); - ret = 1; goto cleanup; - } + } else { + /* just set the name, check it once configuring of all nodes is done */ + if (endpt) { + free(endpt->referenced_endpt_name); + endpt->referenced_endpt_name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup); + } else { + free(ch_endpt->referenced_endpt_name); + ch_endpt->referenced_endpt_name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_GOTO(!ch_endpt->referenced_endpt_name, ret = 1, cleanup); + } - /* check for cyclic references */ - ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i]); - if (ret) { - ERR(NULL, "Cyclic endpoint reference detected for endpoint \"%s\".", endpt->name); goto cleanup; } - /* assign the current endpt the referrenced endpt */ - if (is_ssh(node)) { - endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i]; - } else { - endpt->opts.tls->endpt_client_ref = &server_opts.endpts[i]; +cleanup: + if (is_ch(node)) { + /* UNLOCK */ + nc_ch_client_unlock(ch_client); } -cleanup: return ret; } @@ -3154,7 +3272,7 @@ static int nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) { int ret = 0; - struct nc_endpt *endpt; + struct nc_server_tls_opts *opts; struct nc_ch_client *ch_client; assert(!strcmp(LYD_NAME(node), "asymmetric-key")); @@ -3165,21 +3283,21 @@ nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op) return 1; } - if (nc_server_config_get_endpt(node, &endpt, NULL)) { + if (nc_server_config_get_tls_opts(node, &opts)) { ret = 1; goto cleanup; } if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { /* set to keystore */ - endpt->opts.tls->store = NC_STORE_KEYSTORE; + opts->store = NC_STORE_KEYSTORE; - free(endpt->opts.tls->key_ref); - endpt->opts.tls->key_ref = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!endpt->opts.tls->key_ref, ret = 1, cleanup); + free(opts->key_ref); + opts->key_ref = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_GOTO(!opts->key_ref, ret = 1, cleanup); } else { - free(endpt->opts.tls->key_ref); - endpt->opts.tls->key_ref = NULL; + free(opts->key_ref); + opts->key_ref = NULL; } cleanup: @@ -4134,8 +4252,8 @@ nc_server_config_parse_netconf_server(const struct lyd_node *node, NC_OPERATION ret = nc_server_config_encryption_alg(node, op); } else if (!strcmp(name, "mac-alg")) { ret = nc_server_config_mac_alg(node, op); - } else if (!strcmp(name, "endpoint-client-auth")) { - ret = nc_server_config_endpoint_client_auth(node, op); + } else if (!strcmp(name, "endpoint-reference")) { + ret = nc_server_config_endpoint_reference(node, op); } else if (!strcmp(name, "tls")) { ret = nc_server_config_tls(node, op); } else if (!strcmp(name, "cert-data")) { @@ -4378,8 +4496,8 @@ nc_server_config_fill_nectonf_server(const struct lyd_node *data, NC_OPERATION o } #ifdef NC_ENABLED_SSH_TLS - /* backward check of client auth reference */ - if (nc_server_config_fill_endpt_client_auth()) { + /* check and set all endpoint references */ + if (nc_server_config_check_endpt_references()) { ret = 1; goto cleanup; } diff --git a/src/server_config_util_ssh.c b/src/server_config_util_ssh.c index f3ca8c03..8b162ee6 100644 --- a/src/server_config_util_ssh.c +++ b/src/server_config_util_ssh.c @@ -605,7 +605,7 @@ nc_server_config_add_ssh_endpoint_client_ref(const struct ly_ctx *ctx, const cha NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); return nc_server_config_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); + "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name); } API int @@ -614,7 +614,7 @@ nc_server_config_del_ssh_endpoint_client_ref(const char *endpt_name, struct lyd_ NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); + "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name); } API int diff --git a/src/server_config_util_tls.c b/src/server_config_util_tls.c index 66b25593..047a6d5e 100644 --- a/src/server_config_util_tls.c +++ b/src/server_config_util_tls.c @@ -777,7 +777,7 @@ nc_server_config_add_tls_endpoint_client_ref(const struct ly_ctx *ctx, const cha NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1); return nc_server_config_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); + "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name); } API int @@ -786,5 +786,5 @@ nc_server_config_del_tls_endpoint_client_ref(const char *endpt_name, struct lyd_ NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/" - "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name); + "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name); } diff --git a/src/session_p.h b/src/session_p.h index 5d2ccb17..2b3524d1 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -202,7 +202,7 @@ struct nc_server_ssh_opts { struct nc_auth_client *auth_clients; /**< Server's authorized clients. */ uint16_t client_count; /**< Number of server's authorized clients. */ - struct nc_endpt *endpt_client_ref; /**< Reference to another endpoint (used for client authentication). */ + char *referenced_endpt_name; /**< Reference to another endpoint (used for client authentication). */ char *hostkey_algs; /**< Hostkey algorithms supported by the server. */ char *encryption_algs; /**< Encryption algorithms supported by the server. */ @@ -275,7 +275,7 @@ struct nc_server_tls_opts { int crl_cert_ext; /**< Indicates to use CA's distribution points to obtain CRLs */ X509_STORE *crl_store; /**< Stores all the CRLs */ - struct nc_endpt *endpt_client_ref; /**< Reference to another endpoint (used for client authentication). */ + char *referenced_endpt_name; /**< Reference to another endpoint (used for client authentication). */ unsigned int tls_versions; /**< TLS versions */ char *ciphers; /**< TLS ciphers */ @@ -476,12 +476,14 @@ struct nc_server_opts { * modify CH clients - READ lock ch_client_lock + ch_client_lock */ struct nc_ch_client { char *name; - pthread_t tid; /**< Call Home client's thread ID */ struct nc_ch_client_thread_arg *thread_data; /**< Data of the Call Home client's thread */ struct nc_ch_endpt { char *name; +#ifdef NC_ENABLED_SSH_TLS + char *referenced_endpt_name; +#endif /* NC_ENABLED_SSH_TLS */ NC_TRANSPORT_IMPL ti; char *address; uint16_t port; @@ -964,6 +966,15 @@ struct nc_ch_endpt *nc_server_ch_client_lock(const char *name, const char *endpt */ void nc_server_ch_client_unlock(struct nc_ch_client *client); +/** + * @brief Gets an endpoint structure based on its name. + * + * @param[in] name The name of the endpoint. + * @param[out] endpt Pointer to the endpoint structure. + * @return 0 on success, 1 on failure. + */ +int nc_server_get_referenced_endpt(const char *name, struct nc_endpt **endpt); + /** * @brief Add a client Call Home bind, listen on it. * diff --git a/src/session_server.c b/src/session_server.c index 1fd84fbc..90e02ff0 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -151,6 +151,22 @@ nc_server_ch_client_unlock(struct nc_ch_client *client) pthread_rwlock_unlock(&server_opts.ch_client_lock); } +int +nc_server_get_referenced_endpt(const char *name, struct nc_endpt **endpt) +{ + uint16_t i; + + for (i = 0; i < server_opts.endpt_count; i++) { + if (!strcmp(name, server_opts.endpts[i].name)) { + *endpt = &server_opts.endpts[i]; + return 0; + } + } + + ERR(NULL, "Referenced endpoint \"%s\" was not found.", name); + return 1; +} + API void nc_session_set_term_reason(struct nc_session *session, NC_SESSION_TERM_REASON reason) { diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index c4c3085f..cc1f3de7 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -829,6 +829,7 @@ nc_session_ssh_msg(struct nc_session *session, struct nc_server_ssh_opts *opts, int subtype, type, libssh_auth_methods = 0, ret = 0; uint16_t i; struct nc_auth_client *auth_client = NULL; + struct nc_endpt *referenced_endpt; type = ssh_message_type(msg); subtype = ssh_message_subtype(msg); @@ -980,8 +981,14 @@ nc_session_ssh_msg(struct nc_session *session, struct nc_server_ssh_opts *opts, } if (!auth_client) { - if (opts->endpt_client_ref) { - return nc_session_ssh_msg(session, opts->endpt_client_ref->opts.ssh, msg, state); + if (opts->referenced_endpt_name) { + /* client not known by the endpt, but it references another one so try it */ + if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) { + ERRINT; + return 1; + } + + return nc_session_ssh_msg(session, referenced_endpt->opts.ssh, msg, state); } ERR(NULL, "User \"%s\" not known by the server.", username); diff --git a/src/session_server_tls.c b/src/session_server_tls.c index de898c84..a11c11b3 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -38,12 +38,8 @@ #include "session_p.h" struct nc_server_tls_opts tls_ch_opts; -pthread_mutex_t tls_ch_opts_lock = PTHREAD_MUTEX_INITIALIZER; extern struct nc_server_opts server_opts; -static pthread_key_t verify_key; -static pthread_once_t verify_once = PTHREAD_ONCE_INIT; - static char * asn1time_to_str(const ASN1_TIME *t) { @@ -312,7 +308,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * /* first make sure the entry is valid */ if (!ctn->map_type || ((ctn->map_type == NC_TLS_CTN_SPECIFIED) && !ctn->name)) { - VRB(NULL, "Cert verify CTN: entry with id %u not valid, skipping.", ctn->id); + VRB(session, "Cert verify CTN: entry with id %u not valid, skipping.", ctn->id); continue; } @@ -324,7 +320,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * } else if (!strncmp(ctn->fingerprint, "01", 2)) { if (!digest_md5) { if (X509_digest(cert, EVP_md5(), buf, &buf_len) != 1) { - ERR(NULL, "Calculating MD5 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); + ERR(session, "Calculating MD5 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); ret = -1; goto cleanup; } @@ -333,7 +329,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * if (!strcasecmp(ctn->fingerprint + 3, digest_md5)) { /* we got ourselves a potential winner! */ - VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); + VRB(session, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } free(digest_md5); @@ -343,7 +339,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * } else if (!strncmp(ctn->fingerprint, "02", 2)) { if (!digest_sha1) { if (X509_digest(cert, EVP_sha1(), buf, &buf_len) != 1) { - ERR(NULL, "Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); + ERR(session, "Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); ret = -1; goto cleanup; } @@ -352,7 +348,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * if (!strcasecmp(ctn->fingerprint + 3, digest_sha1)) { /* we got ourselves a potential winner! */ - VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); + VRB(session, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } free(digest_sha1); @@ -362,7 +358,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * } else if (!strncmp(ctn->fingerprint, "03", 2)) { if (!digest_sha224) { if (X509_digest(cert, EVP_sha224(), buf, &buf_len) != 1) { - ERR(NULL, "Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); + ERR(session, "Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); ret = -1; goto cleanup; } @@ -371,7 +367,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * if (!strcasecmp(ctn->fingerprint + 3, digest_sha224)) { /* we got ourselves a potential winner! */ - VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); + VRB(session, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } free(digest_sha224); @@ -381,7 +377,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * } else if (!strncmp(ctn->fingerprint, "04", 2)) { if (!digest_sha256) { if (X509_digest(cert, EVP_sha256(), buf, &buf_len) != 1) { - ERR(NULL, "Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); + ERR(session, "Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); ret = -1; goto cleanup; } @@ -390,7 +386,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * if (!strcasecmp(ctn->fingerprint + 3, digest_sha256)) { /* we got ourselves a potential winner! */ - VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); + VRB(session, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } free(digest_sha256); @@ -400,7 +396,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * } else if (!strncmp(ctn->fingerprint, "05", 2)) { if (!digest_sha384) { if (X509_digest(cert, EVP_sha384(), buf, &buf_len) != 1) { - ERR(NULL, "Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); + ERR(session, "Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); ret = -1; goto cleanup; } @@ -409,7 +405,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * if (!strcasecmp(ctn->fingerprint + 3, digest_sha384)) { /* we got ourselves a potential winner! */ - VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); + VRB(session, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } free(digest_sha384); @@ -419,7 +415,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * } else if (!strncmp(ctn->fingerprint, "06", 2)) { if (!digest_sha512) { if (X509_digest(cert, EVP_sha512(), buf, &buf_len) != 1) { - ERR(NULL, "Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); + ERR(session, "Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error())); ret = -1; goto cleanup; } @@ -428,7 +424,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * if (!strcasecmp(ctn->fingerprint + 3, digest_sha512)) { /* we got ourselves a potential winner! */ - VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found."); + VRB(session, "Cert verify CTN: entry with a matching fingerprint found."); map_type = ctn->map_type; } free(digest_sha512); @@ -436,7 +432,7 @@ nc_tls_cert_to_name(struct nc_session *session, struct nc_ctn *ctn_first, X509 * /* unknown */ } else { - WRN(NULL, "Unknown fingerprint algorithm used (%s), skipping.", ctn->fingerprint); + WRN(session, "Unknown fingerprint algorithm used (%s), skipping.", ctn->fingerprint); continue; } @@ -668,16 +664,24 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) X509_NAME *issuer; X509 *cert; char *cp; + X509_STORE *store; STACK_OF(X509) * cert_stack; struct nc_session *session; struct nc_server_tls_opts *opts; + struct nc_endpt *referenced_endpt; int rc, depth; - /* get the thread session */ - session = pthread_getspecific(verify_key); + store = X509_STORE_CTX_get0_store(x509_ctx); + if (!store) { + ERR(NULL, "Error getting store from context (%s).", ERR_reason_error_string(ERR_get_error())); + return 0; + } + + /* get session from the store */ + session = X509_STORE_get_ex_data(store, 0); if (!session) { - ERRINT; + ERR(session, "Error getting session from store (%s).", ERR_reason_error_string(ERR_get_error())); return 0; } @@ -702,7 +706,7 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) } /* no match, continue */ - if (opts->endpt_client_ref) { + if (opts->referenced_endpt_name) { /* check referenced endpoint's end-entity certs */ rc = nc_server_tls_do_preverify(session, x509_ctx, 2); if (rc == -1) { @@ -751,12 +755,19 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) /* fatal error */ depth = 0; goto fail; - } else if ((rc == 1) && !opts->endpt_client_ref) { + } else if ((rc == 1) && !opts->referenced_endpt_name) { /* no match found and no referenced endpoint */ goto fail; - } else if ((rc == 1) && opts->endpt_client_ref) { + } else if ((rc == 1) && opts->referenced_endpt_name) { /* no match found, but has a referenced endpoint so try it */ - rc = nc_tls_cert_to_name(session, opts->endpt_client_ref->opts.tls->ctn, cert); + if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) { + /* fatal error */ + ERRINT; + depth = 0; + goto fail; + } + + rc = nc_tls_cert_to_name(session, referenced_endpt->opts.tls->ctn, cert); if (rc) { if (rc == -1) { /* fatal error */ @@ -890,12 +901,6 @@ nc_server_tls_set_verify_clb(int (*verify_clb)(const struct nc_session *session) server_opts.user_verify_clb = verify_clb; } -static void -nc_tls_make_verify_key(void) -{ - pthread_key_create(&verify_key, NULL); -} - static int nc_server_tls_ks_ref_get_cert_key(const char *referenced_key_name, const char *referenced_cert_name, char **privkey_data, NC_PRIVKEY_FORMAT *privkey_type, char **cert_data) @@ -918,7 +923,7 @@ nc_server_tls_ks_ref_get_cert_key(const char *referenced_key_name, const char *r } for (j = 0; j < ks->asym_keys[i].cert_count; j++) { - if (!strcmp(referenced_cert_name, ks->asym_keys[i].certs[i].name)) { + if (!strcmp(referenced_cert_name, ks->asym_keys[i].certs[j].name)) { break; } } @@ -1403,6 +1408,7 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt SSL_CTX *tls_ctx; int ret; struct timespec ts_timeout; + struct nc_endpt *referenced_endpt; /* SSL_CTX */ tls_ctx = SSL_CTX_new(TLS_server_method()); @@ -1424,6 +1430,13 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt goto error; } + /* store the session, retrieve it when needed */ + ret = X509_STORE_set_ex_data(cert_store, 0, session); + if (!ret) { + ERR(session, "Setting certificate store data failed (%s).", ERR_reason_error_string(ERR_get_error())); + goto error; + } + /* set end-entity certs as cert store data, retrieve them if verification fails later */ ret = X509_STORE_set_ex_data(cert_store, 1, &opts->ee_certs); if (!ret) { @@ -1432,8 +1445,13 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt } /* do the same for referenced endpoint's end entity certs */ - if (opts->endpt_client_ref) { - ret = X509_STORE_set_ex_data(cert_store, 2, &opts->endpt_client_ref->opts.tls->ee_certs); + if (opts->referenced_endpt_name) { + if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) { + ERRINT; + goto error; + } + + ret = X509_STORE_set_ex_data(cert_store, 2, &referenced_endpt->opts.tls->ee_certs); if (!ret) { ERR(session, "Setting certificate store data failed (%s).", ERR_reason_error_string(ERR_get_error())); goto error; @@ -1449,8 +1467,8 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt } /* set referenced endpoint's CA certs if set */ - if (opts->endpt_client_ref) { - if (nc_tls_store_set_trusted_certs(cert_store, &opts->endpt_client_ref->opts.tls->ca_certs)) { + if (opts->referenced_endpt_name) { + if (nc_tls_store_set_trusted_certs(cert_store, &referenced_endpt->opts.tls->ca_certs)) { goto error; } } @@ -1502,10 +1520,6 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt sock = -1; SSL_set_mode(session->ti.tls, SSL_MODE_AUTO_RETRY); - /* store session on per-thread basis */ - pthread_once(&verify_once, nc_tls_make_verify_key); - pthread_setspecific(verify_key, session); - if (timeout > -1) { nc_timeouttime_get(&ts_timeout, timeout); } From 663588edf5edcd19f087248aea33acd3e9a7beef Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 2 Nov 2023 11:09:46 +0100 Subject: [PATCH 123/134] session server ch BUGFIX add ssh_tls macros --- src/server_config.c | 12 +++++++----- src/session_p.h | 4 +++- src/session_server.c | 4 ++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 47bda15d..455a4143 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -3138,7 +3138,7 @@ nc_server_config_check_endpt_references(void) pthread_mutex_unlock(&server_opts.ch_clients[i].lock); /* UNLOCK */ pthread_rwlock_unlock(&server_opts.ch_client_lock); - return 1; + return 1; } static int @@ -3181,7 +3181,7 @@ nc_server_config_endpoint_reference(const struct lyd_node *node, NC_OPERATION op ret = 1; goto cleanup; } - + ssh->referenced_endpt_name = NULL; } else { if (nc_server_config_get_tls_opts(node, &tls)) { @@ -3864,17 +3864,19 @@ nc_server_config_netconf_client(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } +#ifdef NC_ENABLED_SSH_TLS if (server_opts.ch_dispatch_data.acquire_ctx_cb && server_opts.ch_dispatch_data.release_ctx_cb && - server_opts.ch_dispatch_data.new_session_cb) { + server_opts.ch_dispatch_data.new_session_cb) { /* we have all we need for dispatching a new call home thread */ ret = nc_connect_ch_client_dispatch(lyd_get_value(lyd_child(node)), server_opts.ch_dispatch_data.acquire_ctx_cb, - server_opts.ch_dispatch_data.release_ctx_cb, server_opts.ch_dispatch_data.ctx_cb_data, - server_opts.ch_dispatch_data.new_session_cb, server_opts.ch_dispatch_data.new_session_cb_data); + server_opts.ch_dispatch_data.release_ctx_cb, server_opts.ch_dispatch_data.ctx_cb_data, + server_opts.ch_dispatch_data.new_session_cb, server_opts.ch_dispatch_data.new_session_cb_data); if (ret) { ERR(NULL, "Dispatching a new Call Home thread failed for Call Home client \"%s\".", lyd_get_value(lyd_child(node))); goto cleanup; } } +#endif /* NC_ENABLED_SSH_TLS */ } else if (op == NC_OP_DELETE) { if (nc_server_config_get_ch_client(node, &ch_client)) { ret = 1; diff --git a/src/session_p.h b/src/session_p.h index 2b3524d1..cebf3a72 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -516,6 +516,7 @@ struct nc_server_opts { uint16_t ch_client_count; pthread_rwlock_t ch_client_lock; +#ifdef NC_ENABLED_SSH_TLS struct nc_ch_dispatch_data { nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb; nc_server_ch_session_release_ctx_cb release_ctx_cb; @@ -523,6 +524,7 @@ struct nc_server_opts { nc_server_ch_new_session_cb new_session_cb; void *new_session_cb_data; } ch_dispatch_data; +#endif /* NC_ENABLED_SSH_TLS */ /* Atomic IDs */ ATOMIC_T new_session_id; @@ -968,7 +970,7 @@ void nc_server_ch_client_unlock(struct nc_ch_client *client); /** * @brief Gets an endpoint structure based on its name. - * + * * @param[in] name The name of the endpoint. * @param[out] endpt Pointer to the endpoint structure. * @return 0 on success, 1 on failure. diff --git a/src/session_server.c b/src/session_server.c index 90e02ff0..564cb63d 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -293,6 +293,8 @@ nc_server_init_ctx(struct ly_ctx **ctx) return ret; } +#ifdef NC_ENABLED_SSH_TLS + API void nc_server_ch_set_dispatch_data(nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb, nc_server_ch_session_release_ctx_cb release_ctx_cb, void *ctx_cb_data, nc_server_ch_new_session_cb new_session_cb, @@ -307,6 +309,8 @@ nc_server_ch_set_dispatch_data(nc_server_ch_session_acquire_ctx_cb acquire_ctx_c server_opts.ch_dispatch_data.new_session_cb_data = new_session_cb_data; } +#endif + int nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepalives *ka) { From a9a1f8caf8fa2e270f14da74233565c8a9dc3547 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 2 Nov 2023 13:34:34 +0100 Subject: [PATCH 124/134] server config BUGFIX fix memory leaks --- src/server_config.c | 74 +++++++++------------------------------------ 1 file changed, 15 insertions(+), 59 deletions(-) diff --git a/src/server_config.c b/src/server_config.c index 455a4143..d41ea211 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -752,9 +752,11 @@ nc_server_config_del_ssh_opts(struct nc_bind *bind, struct nc_server_ssh_opts *o { uint16_t i, hostkey_count, client_count; - free(bind->address); - if (bind->sock > -1) { - close(bind->sock); + if (bind) { + free(bind->address); + if (bind->sock > -1) { + close(bind->sock); + } } /* store in variable because it gets decremented in the function call */ @@ -957,9 +959,11 @@ nc_server_config_del_ctns(struct nc_server_tls_opts *opts) static void nc_server_config_del_tls_opts(struct nc_bind *bind, struct nc_server_tls_opts *opts) { - free(bind->address); - if (bind->sock > -1) { - close(bind->sock); + if (bind) { + free(bind->address); + if (bind->sock > -1) { + close(bind->sock); + } } if (opts->store == NC_STORE_LOCAL) { @@ -1044,55 +1048,6 @@ nc_server_config_listen(const struct lyd_node *node, NC_OPERATION op) return 0; } -#ifdef NC_ENABLED_SSH_TLS - -static void -nc_server_config_ch_del_ssh_opts(struct nc_server_ssh_opts *opts) -{ - uint16_t i, hostkey_count, client_count; - - /* store in variable because it gets decremented in the function call */ - hostkey_count = opts->hostkey_count; - for (i = 0; i < hostkey_count; i++) { - nc_server_config_del_hostkey(opts, &opts->hostkeys[i]); - } - - client_count = opts->client_count; - for (i = 0; i < client_count; i++) { - nc_server_config_del_auth_client(opts, &opts->auth_clients[i]); - } - - free(opts->hostkey_algs); - free(opts->kex_algs); - free(opts->encryption_algs); - free(opts->mac_algs); - - free(opts); -} - -static void -nc_server_config_ch_del_tls_opts(struct nc_server_tls_opts *opts) -{ - if (opts->store == NC_STORE_LOCAL) { - free(opts->pubkey_data); - free(opts->privkey_data); - free(opts->cert_data); - } - - nc_server_config_del_certs(&opts->ca_certs); - nc_server_config_del_certs(&opts->ee_certs); - - free(opts->crl_path); - free(opts->crl_url); - X509_STORE_free(opts->crl_store); - nc_server_config_del_ctns(opts); - free(opts->ciphers); - - free(opts); -} - -#endif /* NC_ENABLED_SSH_TLS */ - static void nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt) { @@ -1104,15 +1059,16 @@ nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt close(ch_endpt->sock_pending); ch_endpt->sock_pending = -1; } + free(ch_endpt->referenced_endpt_name); #endif /* NC_ENABLED_SSH_TLS */ switch (ch_endpt->ti) { #ifdef NC_ENABLED_SSH_TLS case NC_TI_LIBSSH: - nc_server_config_ch_del_ssh_opts(ch_endpt->opts.ssh); + nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh); break; case NC_TI_OPENSSL: - nc_server_config_ch_del_tls_opts(ch_endpt->opts.tls); + nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls); break; #endif /* NC_ENABLED_SSH_TLS */ default: @@ -1436,7 +1392,7 @@ nc_server_config_ssh(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_config_ch_del_ssh_opts(ch_endpt->opts.ssh); + nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh); } } @@ -1511,7 +1467,7 @@ nc_server_config_tls(const struct lyd_node *node, NC_OPERATION op) goto cleanup; } } else if (op == NC_OP_DELETE) { - nc_server_config_ch_del_tls_opts(ch_endpt->opts.tls); + nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls); } } From 8dce938b51ee29b75e3305766d4aaac2275d58b7 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 2 Nov 2023 15:00:09 +0100 Subject: [PATCH 125/134] doc UPDATE update docs --- doc/libnetconf.doc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/libnetconf.doc b/doc/libnetconf.doc index 83ebe78e..46a133b5 100644 --- a/doc/libnetconf.doc +++ b/doc/libnetconf.doc @@ -55,9 +55,9 @@ * @page howtoinit Init and Thread-safety Information * * Before working with the library, it must be initialized using ::nc_client_init() - * or ::nc_server_init(), based on how the library was compiled. To prevent - * any reachable memory at the end of your application, there are complementary - * destroy functions (::nc_server_destroy() and ::nc_client_destroy() available. If your + * and/or ::nc_server_init(). To prevent any reachable memory at the end of your + * application, there are complementary destroy functions + * (::nc_server_destroy() and ::nc_client_destroy() available). If your * application is multi-threaded, call the destroy functions in the main thread, * after all the other threads have ended. * @@ -323,7 +323,7 @@ * data - *YANG data* and *YANG diff*. * * YANG data - * == + * --- * Configuring the server using YANG data simplifies the management of network services. * With YANG data, you build a structured configuration tree and apply it as a whole. * This approach is user-friendly, allowing you to modify the configuration by adding or deleting nodes, @@ -331,7 +331,7 @@ * The *libnetconf2* library exports API functions that can help you with creation or deletion of the *YANG* data. * * YANG diff - * == + * --- * YANG diff, enriched with operation attributes, offers advanced configuration control. * It empowers the user to make precise changes within the configuration tree, * enabling operations like specific node deletions, additions, and modifications. @@ -340,7 +340,7 @@ * For example this is done by the tool [sysrepo](https://www.sysrepo.org/). * * Usage - * == + * --- * To be able to configure the server, the required models first need to be implemented. * To do this, see ::nc_server_config_load_modules(). * Not all of the *ietf-netconf-server* (and all of its associated modules) features are enabled. From 62c098ace002b6533f0c2d230f2b6d94c497f04d Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 2 Nov 2023 15:27:04 +0100 Subject: [PATCH 126/134] compat UPDATE move crypt to compat also delete obsolete shadow dependency --- CMakeLists.txt | 4 ---- CMakeModules/UseCompat.cmake | 2 ++ compat/compat.h.in | 8 +++++++- src/session_server_ssh.c | 10 ++-------- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79fde55f..59181655 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -286,10 +286,6 @@ find_package(LibYANG ${LIBYANG_DEP_SOVERSION} REQUIRED) target_link_libraries(netconf2 ${LIBYANG_LIBRARIES}) include_directories(${LIBYANG_INCLUDE_DIRS}) -# header file compatibility - shadow.h and crypt.h -check_include_file("shadow.h" HAVE_SHADOW) -check_include_file("crypt.h" HAVE_CRYPT) - # function compatibility - getpeereid on QNX if(${CMAKE_SYSTEM_NAME} MATCHES "QNX") target_link_libraries(netconf2 -lsocket) diff --git a/CMakeModules/UseCompat.cmake b/CMakeModules/UseCompat.cmake index f9dc007b..bc132b4b 100644 --- a/CMakeModules/UseCompat.cmake +++ b/CMakeModules/UseCompat.cmake @@ -63,6 +63,8 @@ macro(USE_COMPAT) check_symbol_exists(get_current_dir_name "unistd.h" HAVE_GET_CURRENT_DIR_NAME) # crypt + check_include_file("crypt.h" HAVE_CRYPT_H) + if(${CMAKE_SYSTEM_NAME} MATCHES "QNX") list(APPEND CMAKE_REQUIRED_LIBRARIES -llogin) elseif(NOT APPLE) diff --git a/compat/compat.h.in b/compat/compat.h.in index f1161523..c6209c82 100644 --- a/compat/compat.h.in +++ b/compat/compat.h.in @@ -17,14 +17,20 @@ #define _GNU_SOURCE /* pthread_rwlock_t */ +#cmakedefine HAVE_CRYPT_H + +#ifdef HAVE_CRYPT_H +# include +#endif + #include -#include #include #include #include #include #include #include +#include #ifndef __WORDSIZE # if defined __x86_64__ && !defined __ILP32__ diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index cc1f3de7..f46d968b 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -15,16 +15,10 @@ #define _GNU_SOURCE -#include "config.h" /* Expose HAVE_SHADOW, HAVE_CRYPT and HAVE_LIBPAM */ +#include "config.h" /* Expose HAVE_LIBPAM */ -#ifdef HAVE_SHADOW - #include -#endif -#ifdef HAVE_CRYPT - #include -#endif #ifdef HAVE_LIBPAM - #include +# include #endif #include From 1f4144f3703d04e9ee7db4c3322b1b4d07e38557 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 3 Nov 2023 13:53:47 +0100 Subject: [PATCH 127/134] pkg UPDATE create updated package --- distro/README.md | 17 +++++++++++++++++ distro/pkg/deb/control | 12 ++++++------ ...ibnetconf2-3.install => libnetconf2.install} | 0 distro/pkg/rpm/libnetconf2.spec | 1 + 4 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 distro/README.md rename distro/pkg/deb/{libnetconf2-3.install => libnetconf2.install} (100%) diff --git a/distro/README.md b/distro/README.md new file mode 100644 index 00000000..70dba2d5 --- /dev/null +++ b/distro/README.md @@ -0,0 +1,17 @@ +# upstream packaging + +This directory contains upstream packaging sources in apkg format. + +apkg tool can be used to build packages directly from this source repo. + +See apkg docs: https://pkg.labs.nic.cz/pages/apkg/ + + +## RPM-based system (Fedora, CentOS, SUSE, ...) quickstart + +``` +sudo dnf install -y git rpm-build python3-pip +pip3 install apkg + +apkg build -b +``` diff --git a/distro/pkg/deb/control b/distro/pkg/deb/control index 9e15c613..65e25e21 100644 --- a/distro/pkg/deb/control +++ b/distro/pkg/deb/control @@ -7,14 +7,15 @@ Standards-Version: 4.5.0 Build-Depends: cmake, debhelper (>= 10), libyang2-dev, - libssl-dev, - libssh-dev (>= 0.7.1), + libssl-dev (>= 3.0.0), + libssh-dev (>= 0.9.5), libpam0g-dev, - pkg-config + pkg-config, + libcurl4-openssl-dev (>= 7.30.0) Vcs-Browser: https://github.com/CESNET/libnetconf2/tree/master Vcs-Git: https://github.com/CESNET/libnetconf2.git -Package: libnetconf2-3 +Package: libnetconf2 Depends: ${misc:Depends}, ${shlibs:Depends} Architecture: any @@ -29,7 +30,7 @@ Description: library implementing NETCONF protocol - runtime Package: libnetconf2-dev Depends: libyang2-dev, - libnetconf2-3 (= ${binary:Version}), + libnetconf2 (= ${binary:Version}), ${misc:Depends} Section: libdevel Architecture: any @@ -42,4 +43,3 @@ Description: library implementing NETCONF protocol - development files . This package contains the C headers, a pkgconfig file, and .so entry point for libnetconf2. - diff --git a/distro/pkg/deb/libnetconf2-3.install b/distro/pkg/deb/libnetconf2.install similarity index 100% rename from distro/pkg/deb/libnetconf2-3.install rename to distro/pkg/deb/libnetconf2.install diff --git a/distro/pkg/rpm/libnetconf2.spec b/distro/pkg/rpm/libnetconf2.spec index 979a5161..cfb66e48 100644 --- a/distro/pkg/rpm/libnetconf2.spec +++ b/distro/pkg/rpm/libnetconf2.spec @@ -12,6 +12,7 @@ BuildRequires: libssh-devel BuildRequires: openssl-devel BuildRequires: pam-devel BuildRequires: pkgconfig(libyang) >= 2 +BuildRequires: libcurl-devel %package devel Summary: Headers of libnetconf2 library From 0b5b51aa8a28ad0446e20634b1462460b1d4f869 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 3 Nov 2023 13:54:29 +0100 Subject: [PATCH 128/134] log UPDATE remove deprecated nc_set_print_clb --- src/log.c | 8 -------- src/log.h | 7 ------- 2 files changed, 15 deletions(-) diff --git a/src/log.c b/src/log.c index 682293f7..84634821 100644 --- a/src/log.c +++ b/src/log.c @@ -136,14 +136,6 @@ nc_ly_log_clb(LY_LOG_LEVEL lvl, const char *msg, const char *UNUSED(path)) } } -API void -nc_set_print_clb(void (*clb)(NC_VERB_LEVEL, const char *)) -{ - print_clb = NULL; - depr_print_clb = clb; - ly_set_log_clb(nc_ly_log_clb, 1); -} - API void nc_set_print_clb_session(void (*clb)(const struct nc_session *, NC_VERB_LEVEL, const char *)) { diff --git a/src/log.h b/src/log.h index 4bf69cea..8564db13 100644 --- a/src/log.h +++ b/src/log.h @@ -71,13 +71,6 @@ void nc_libssh_thread_verbosity(int level); #endif /* NC_ENABLED_SSH_TLS */ -/** - * @brief Deprecated, use ::nc_set_print_clb_session() instead. - * - * @param[in] clb Callback that is called for every message. - */ -void nc_set_print_clb(void (*clb)(NC_VERB_LEVEL, const char *)); - /** * @brief Set libnetconf print callback. * From f60c87e9e496d445550970de9d2694268b79a507 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 3 Nov 2023 13:56:23 +0100 Subject: [PATCH 129/134] session server UPDATE remove pubkey and pw cbs --- src/session_p.h | 8 ------- src/session_server.c | 12 ---------- src/session_server.h | 22 ------------------ src/session_server_ssh.c | 48 +++++----------------------------------- 4 files changed, 5 insertions(+), 85 deletions(-) diff --git a/src/session_p.h b/src/session_p.h index cebf3a72..d96acc3d 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -429,14 +429,6 @@ struct nc_server_opts { uint16_t idle_timeout; #ifdef NC_ENABLED_SSH_TLS - int (*passwd_auth_clb)(const struct nc_session *session, const char *password, void *user_data); - void *passwd_auth_data; - void (*passwd_auth_data_free)(void *data); - - int (*pubkey_auth_clb)(const struct nc_session *session, ssh_key key, void *user_data); - void *pubkey_auth_data; - void (*pubkey_auth_data_free)(void *data); - int (*interactive_auth_clb)(const struct nc_session *session, ssh_session ssh_sess, ssh_message msg, void *user_data); void *interactive_auth_data; void (*interactive_auth_data_free)(void *data); diff --git a/src/session_server.c b/src/session_server.c index 564cb63d..1ded506f 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -893,18 +893,6 @@ nc_server_destroy(void) pthread_mutex_destroy(&server_opts.bind_lock); #ifdef NC_ENABLED_SSH_TLS - if (server_opts.passwd_auth_data && server_opts.passwd_auth_data_free) { - server_opts.passwd_auth_data_free(server_opts.passwd_auth_data); - } - server_opts.passwd_auth_data = NULL; - server_opts.passwd_auth_data_free = NULL; - - if (server_opts.pubkey_auth_data && server_opts.pubkey_auth_data_free) { - server_opts.pubkey_auth_data_free(server_opts.pubkey_auth_data); - } - server_opts.pubkey_auth_data = NULL; - server_opts.pubkey_auth_data_free = NULL; - if (server_opts.interactive_auth_data && server_opts.interactive_auth_data_free) { server_opts.interactive_auth_data_free(server_opts.interactive_auth_data); } diff --git a/src/session_server.h b/src/session_server.h index d9486f08..a0115300 100644 --- a/src/session_server.h +++ b/src/session_server.h @@ -454,17 +454,6 @@ NC_MSG_TYPE nc_ps_accept_ssh_channel(struct nc_pollsession *ps, struct nc_sessio * @{ */ -/** - * @brief Set the callback for SSH password authentication. If none is set, local system users are used. - * - * @param[in] passwd_auth_clb Callback that should authenticate the user. Username can be directly obtained from @p session. - * Zero return indicates success, non-zero an error. - * @param[in] user_data Optional arbitrary user data that will be passed to @p passwd_auth_clb. - * @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data. - */ -void nc_server_ssh_set_passwd_auth_clb(int (*passwd_auth_clb)(const struct nc_session *session, const char *password, - void *user_data), void *user_data, void (*free_user_data)(void *user_data)); - /** * @brief Set the callback for SSH interactive authentication. If not set, local PAM-based authentication is used. * @@ -476,17 +465,6 @@ void nc_server_ssh_set_passwd_auth_clb(int (*passwd_auth_clb)(const struct nc_se void nc_server_ssh_set_interactive_auth_clb(int (*interactive_auth_clb)(const struct nc_session *session, ssh_session ssh_sess, ssh_message msg, void *user_data), void *user_data, void (*free_user_data)(void *user_data)); -/** - * @brief Set the callback for SSH public key authentication. If none is set, local system users are used. - * - * @param[in] pubkey_auth_clb Callback that should authenticate the user. - * Zero return indicates success, non-zero an error. - * @param[in] user_data Optional arbitrary user data that will be passed to @p pubkey_auth_clb. - * @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data. - */ -void nc_server_ssh_set_pubkey_auth_clb(int (*pubkey_auth_clb)(const struct nc_session *session, ssh_key key, - void *user_data), void *user_data, void (*free_user_data)(void *user_data)); - /** @} Server SSH */ /** diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index f46d968b..f8b2f101 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -175,33 +175,6 @@ nc_server_ssh_ts_ref_get_keys(const char *referenced_name, struct nc_public_key return 0; } -API void -nc_server_ssh_set_passwd_auth_clb(int (*passwd_auth_clb)(const struct nc_session *session, const char *password, void *user_data), - void *user_data, void (*free_user_data)(void *user_data)) -{ - server_opts.passwd_auth_clb = passwd_auth_clb; - server_opts.passwd_auth_data = user_data; - server_opts.passwd_auth_data_free = free_user_data; -} - -API void -nc_server_ssh_set_interactive_auth_clb(int (*interactive_auth_clb)(const struct nc_session *session, ssh_session ssh_sess, - ssh_message msg, void *user_data), void *user_data, void (*free_user_data)(void *user_data)) -{ - server_opts.interactive_auth_clb = interactive_auth_clb; - server_opts.interactive_auth_data = user_data; - server_opts.interactive_auth_data_free = free_user_data; -} - -API void -nc_server_ssh_set_pubkey_auth_clb(int (*pubkey_auth_clb)(const struct nc_session *session, ssh_key key, void *user_data), - void *user_data, void (*free_user_data)(void *user_data)) -{ - server_opts.pubkey_auth_clb = pubkey_auth_clb; - server_opts.pubkey_auth_data = user_data; - server_opts.pubkey_auth_data_free = free_user_data; -} - /** * @brief Compare hashed password with a cleartext password for a match. * @@ -246,11 +219,7 @@ nc_sshcb_auth_password(struct nc_session *session, struct nc_auth_client *auth_c { int auth_ret = 1; - if (server_opts.passwd_auth_clb) { - auth_ret = server_opts.passwd_auth_clb(session, ssh_message_auth_password(msg), server_opts.passwd_auth_data); - } else { - auth_ret = auth_password_compare_pwd(auth_client->password, ssh_message_auth_password(msg)); - } + auth_ret = auth_password_compare_pwd(auth_client->password, ssh_message_auth_password(msg)); if (auth_ret) { ++session->opts.server.ssh_auth_attempts; @@ -704,17 +673,10 @@ nc_sshcb_auth_pubkey(struct nc_session *session, struct nc_auth_client *auth_cli { int signature_state, ret = 0; - if (server_opts.pubkey_auth_clb) { - if (server_opts.pubkey_auth_clb(session, ssh_message_auth_pubkey(msg), server_opts.pubkey_auth_data)) { - ret = 1; - goto fail; - } - } else { - if (auth_pubkey_compare_key(ssh_message_auth_pubkey(msg), auth_client)) { - VRB(session, "User \"%s\" tried to use an unknown (unauthorized) public key.", session->username); - ret = 1; - goto fail; - } + if (auth_pubkey_compare_key(ssh_message_auth_pubkey(msg), auth_client)) { + VRB(session, "User \"%s\" tried to use an unknown (unauthorized) public key.", session->username); + ret = 1; + goto fail; } signature_state = ssh_message_auth_publickey_state(msg); From ca3c9dd133c94debf641da37989a6200a66b21a2 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 3 Nov 2023 13:57:25 +0100 Subject: [PATCH 130/134] session server UPDATE set start time to timespec --- src/session_p.h | 4 ++-- src/session_server.c | 14 ++++++++------ src/session_server.h | 2 +- src/session_server_ssh.c | 4 ++-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/session_p.h b/src/session_p.h index d96acc3d..7e740432 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -666,8 +666,8 @@ struct nc_session { } client; struct { /* server side only data */ - time_t session_start; /**< real time the session was created */ - time_t last_rpc; /**< monotonic time (seconds) the last RPC was received on this session */ + struct timespec session_start; /**< real time the session was created */ + time_t last_rpc; /**< monotonic time (seconds) the last RPC was received on this session */ pthread_mutex_t ntf_status_lock; /**< lock for ntf_status */ uint32_t ntf_status; /**< flag (count) whether the session is subscribed to notifications */ diff --git a/src/session_server.c b/src/session_server.c index 1ded506f..6952cc48 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -1013,7 +1013,7 @@ nc_accept_inout(int fdin, int fdout, const char *username, const struct ly_ctx * nc_timeouttime_get(&ts_cur, 0); (*session)->opts.server.last_rpc = ts_cur.tv_sec; nc_realtime_get(&ts_cur); - (*session)->opts.server.session_start = ts_cur.tv_sec; + (*session)->opts.server.session_start = ts_cur; (*session)->status = NC_STATUS_RUNNING; @@ -2188,7 +2188,7 @@ nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session) nc_timeouttime_get(&ts_cur, 0); (*session)->opts.server.last_rpc = ts_cur.tv_sec; nc_realtime_get(&ts_cur); - (*session)->opts.server.session_start = ts_cur.tv_sec; + (*session)->opts.server.session_start = ts_cur; (*session)->status = NC_STATUS_RUNNING; return msgtype; @@ -2363,7 +2363,7 @@ nc_connect_ch_endpt(struct nc_ch_endpt *endpt, nc_server_ch_session_acquire_ctx_ nc_timeouttime_get(&ts_cur, 0); (*session)->opts.server.last_rpc = ts_cur.tv_sec; nc_realtime_get(&ts_cur); - (*session)->opts.server.session_start = ts_cur.tv_sec; + (*session)->opts.server.session_start = ts_cur; (*session)->status = NC_STATUS_RUNNING; return msgtype; @@ -2783,14 +2783,16 @@ nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_acqu #endif /* NC_ENABLED_SSH_TLS */ -API time_t +API struct timespec nc_session_get_start_time(const struct nc_session *session) { - NC_CHECK_ARG_RET(session, session, 0); + struct timespec fail = {0}; + + NC_CHECK_ARG_RET(session, session, fail); if (session->side != NC_SERVER) { ERRARG(session, "session"); - return 0; + return fail; } return session->opts.server.session_start; diff --git a/src/session_server.h b/src/session_server.h index a0115300..65a9d8d0 100644 --- a/src/session_server.h +++ b/src/session_server.h @@ -526,7 +526,7 @@ void nc_server_tls_set_verify_clb(int (*verify_clb)(const struct nc_session *ses * @param[in] session Session to get the information from. * @return Session start time. */ -time_t nc_session_get_start_time(const struct nc_session *session); +struct timespec nc_session_get_start_time(const struct nc_session *session); /** * @brief Increase session notification subscription flag count. diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index f8b2f101..77953c61 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -1331,7 +1331,7 @@ nc_session_accept_ssh_channel(struct nc_session *orig_session, struct nc_session } nc_realtime_get(&ts_cur); - new_session->opts.server.session_start = ts_cur.tv_sec; + new_session->opts.server.session_start = ts_cur; nc_timeouttime_get(&ts_cur, 0); new_session->opts.server.last_rpc = ts_cur.tv_sec; new_session->status = NC_STATUS_RUNNING; @@ -1396,7 +1396,7 @@ nc_ps_accept_ssh_channel(struct nc_pollsession *ps, struct nc_session **session) } nc_realtime_get(&ts_cur); - new_session->opts.server.session_start = ts_cur.tv_sec; + new_session->opts.server.session_start = ts_cur; nc_timeouttime_get(&ts_cur, 0); new_session->opts.server.last_rpc = ts_cur.tv_sec; new_session->status = NC_STATUS_RUNNING; From f790ea19b5cac55d39d72efcfafc23619faba1c2 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 3 Nov 2023 13:58:17 +0100 Subject: [PATCH 131/134] session server UPDATE remove obsolete funcions --- src/session_server.c | 27 ------------- src/session_server.h | 25 ------------ src/session_server_tls.c | 85 ---------------------------------------- 3 files changed, 137 deletions(-) diff --git a/src/session_server.c b/src/session_server.c index 6952cc48..581bb88f 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -2060,33 +2060,6 @@ nc_server_endpt_count(void) return server_opts.endpt_count; } -API int -nc_server_is_endpt(const char *name) -{ - uint16_t i; - int found = 0; - - if (!name) { - return found; - } - - /* CONFIG READ LOCK */ - pthread_rwlock_rdlock(&server_opts.config_lock); - - /* check name uniqueness */ - for (i = 0; i < server_opts.endpt_count; ++i) { - if (!strcmp(server_opts.endpts[i].name, name)) { - found = 1; - break; - } - } - - /* CONFIG UNLOCK */ - pthread_rwlock_unlock(&server_opts.config_lock); - - return found; -} - API NC_MSG_TYPE nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session) { diff --git a/src/session_server.h b/src/session_server.h index 65a9d8d0..b7bab618 100644 --- a/src/session_server.h +++ b/src/session_server.h @@ -378,14 +378,6 @@ void nc_ps_clear(struct nc_pollsession *ps, int all, void (*data_free)(void *)); */ int nc_server_endpt_count(void); -/** - * @brief Check if an endpoint exists. - * - * @param[in] name Endpoint name. - * @return 0 if does not exists, non-zero otherwise. - */ -int nc_server_is_endpt(const char *name); - /** @} */ /** @@ -475,23 +467,6 @@ void nc_server_ssh_set_interactive_auth_clb(int (*interactive_auth_clb)(const st * @{ */ -/** - * @brief Get a cert-to-name entry. - * - * If a parameter is NULL, it is ignored. If its dereferenced value is NULL, - * it is filled and returned. If the value is set, it is used as a filter. - * Returns first matching entry. - * - * @param[in] endpt_name Existing endpoint name. - * @param[in,out] id Priority of the entry. - * @param[in,out] fingerprint Fingerprint fo the entry. - * @param[in,out] map_type Mapping type of the entry. - * @param[in,out] name Specific username for the entry. - * @return 0 on success, -1 on not finding any match. - */ -int nc_server_tls_endpt_get_ctn(const char *endpt_name, uint32_t *id, char **fingerprint, NC_TLS_CTN_MAPTYPE *map_type, - char **name); - /** * @brief Get client certificate. * diff --git a/src/session_server_tls.c b/src/session_server_tls.c index a11c11b3..b0aa2b6b 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -799,91 +799,6 @@ nc_tlsclb_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) return 0; } -static int -nc_server_tls_get_ctn(uint32_t *id, char **fingerprint, NC_TLS_CTN_MAPTYPE *map_type, char **name, - struct nc_server_tls_opts *opts) -{ - struct nc_ctn *ctn; - int ret = -1; - - for (ctn = opts->ctn; ctn; ctn = ctn->next) { - if (id && *id && (*id != ctn->id)) { - continue; - } - if (fingerprint && *fingerprint && (!ctn->fingerprint || strcmp(*fingerprint, ctn->fingerprint))) { - continue; - } - if (map_type && *map_type && (!ctn->map_type || (*map_type != ctn->map_type))) { - continue; - } - if (name && *name && (!ctn->name || strcmp(*name, ctn->name))) { - continue; - } - - /* first match, good enough */ - if (id && !(*id)) { - *id = ctn->id; - } - if (fingerprint && !(*fingerprint) && ctn->fingerprint) { - *fingerprint = strdup(ctn->fingerprint); - } - if (map_type && !(*map_type) && ctn->map_type) { - *map_type = ctn->map_type; - } - if (name && !(*name) && ctn->name) { - *name = strdup(ctn->name); - } - - ret = 0; - break; - } - - return ret; -} - -API int -nc_server_tls_endpt_get_ctn(const char *endpt_name, uint32_t *id, char **fingerprint, NC_TLS_CTN_MAPTYPE *map_type, - char **name) -{ - int ret; - struct nc_endpt *endpt; - - NC_CHECK_ARG_RET(NULL, endpt_name, -1); - - /* LOCK */ - endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_OPENSSL, NULL); - if (!endpt) { - return -1; - } - ret = nc_server_tls_get_ctn(id, fingerprint, map_type, name, endpt->opts.tls); - /* UNLOCK */ - pthread_rwlock_unlock(&server_opts.config_lock); - - return ret; -} - -API int -nc_server_tls_ch_client_endpt_get_ctn(const char *client_name, const char *endpt_name, uint32_t *id, char **fingerprint, - NC_TLS_CTN_MAPTYPE *map_type, char **name) -{ - int ret; - struct nc_ch_client *client; - struct nc_ch_endpt *endpt; - - /* LOCK */ - endpt = nc_server_ch_client_lock(client_name, endpt_name, NC_TI_OPENSSL, &client); - if (!endpt) { - return -1; - } - - ret = nc_server_tls_get_ctn(id, fingerprint, map_type, name, endpt->opts.tls); - - /* UNLOCK */ - nc_server_ch_client_unlock(client); - - return ret; -} - API const X509 * nc_session_get_client_cert(const struct nc_session *session) { From 4842c08a0f74b90b1b55bc1aad5a6595c3704e5d Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 3 Nov 2023 13:58:45 +0100 Subject: [PATCH 132/134] doc UPDATE ch --- doc/libnetconf.doc | 2 -- src/session_server_ch.h | 5 ++--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/doc/libnetconf.doc b/doc/libnetconf.doc index 46a133b5..c91b46fe 100644 --- a/doc/libnetconf.doc +++ b/doc/libnetconf.doc @@ -496,8 +496,6 @@ * which then creates a new thread and the server will start to connect. * Unix socket _Call Home_ sessions are not supported. * - * Lastly, monitoring of these sessions is up to the application. - * * Functions List * -------------- * diff --git a/src/session_server_ch.h b/src/session_server_ch.h index 6b5ff197..72191697 100644 --- a/src/session_server_ch.h +++ b/src/session_server_ch.h @@ -109,13 +109,12 @@ int nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_ /** * @brief Set callbacks and their data for Call Home threads. * - * If set, Call Home threads will be dispatched automatically upon creation of a new Call Home clients. - * Calling this will replace all the previously set callbacks and their data. + * If set, Call Home threads will be dispatched automatically upon creation of new Call Home clients. * * @param[in] acquire_ctx_cb Callback for acquiring new session context. * @param[in] release_ctx_cb Callback for releasing session context. * @param[in] ctx_cb_data Arbitrary user data passed to @p acquire_ctx_cb and @p release_ctx_cb. - * @param[in] new_session_cb Callback called for every established session on the client. + * @param[in] new_session_cb Callback called for every established Call Home session. * @param[in] new_session_cb_data Arbitrary user data passed to @p new_session_cb. */ void nc_server_ch_set_dispatch_data(nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb, From d88e811f918bf192b97ac9ae9a359a51b6a4a139 Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 3 Nov 2023 14:55:17 +0100 Subject: [PATCH 133/134] examples UPDATE add keys to examples --- examples/admin_key | 7 +++++++ examples/admin_key.pub | 1 + 2 files changed, 8 insertions(+) create mode 100644 examples/admin_key create mode 100644 examples/admin_key.pub diff --git a/examples/admin_key b/examples/admin_key new file mode 100644 index 00000000..df71976d --- /dev/null +++ b/examples/admin_key @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACDq+Oq6bYOgbFoTtSTKJrod3LgmJnrjuiXzlD7P2Dt+cAAAAJC1rL1gtay9 +YAAAAAtzc2gtZWQyNTUxOQAAACDq+Oq6bYOgbFoTtSTKJrod3LgmJnrjuiXzlD7P2Dt+cA +AAAEAQm84SEphEUZEbuCRmXrMcYyv70wNEVziE/SbBC6+trOr46rptg6BsWhO1JMomuh3c +uCYmeuO6JfOUPs/YO35wAAAADXJvbWFuQHBjdmFza28= +-----END OPENSSH PRIVATE KEY----- diff --git a/examples/admin_key.pub b/examples/admin_key.pub new file mode 100644 index 00000000..533f33f7 --- /dev/null +++ b/examples/admin_key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOr46rptg6BsWhO1JMomuh3cuCYmeuO6JfOUPs/YO35w test@libnetconf2 From 29870fef10948f9ba95bb1846fc24edfb17c0adb Mon Sep 17 00:00:00 2001 From: roman Date: Fri, 3 Nov 2023 14:55:31 +0100 Subject: [PATCH 134/134] gitignore UPDATE --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index fc5bd908..117119fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /pkg +/build +/doc/html