diff --git a/CMakeLists.txt b/CMakeLists.txt index 75c43d84..01d790fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ set(CMAKE_MACOSX_RPATH TRUE) # micro version is changed with a set of small changes or bugfixes anywhere in the project. set(LIBNETCONF2_MAJOR_VERSION 4) set(LIBNETCONF2_MINOR_VERSION 0) -set(LIBNETCONF2_MICRO_VERSION 4) +set(LIBNETCONF2_MICRO_VERSION 5) set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION}.${LIBNETCONF2_MICRO_VERSION}) # Version of the library @@ -66,7 +66,7 @@ set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION # with backward compatible change and micro version is connected with any internal change of the library. set(LIBNETCONF2_MAJOR_SOVERSION 5) set(LIBNETCONF2_MINOR_SOVERSION 0) -set(LIBNETCONF2_MICRO_SOVERSION 4) +set(LIBNETCONF2_MICRO_SOVERSION 5) set(LIBNETCONF2_SOVERSION_FULL ${LIBNETCONF2_MAJOR_SOVERSION}.${LIBNETCONF2_MINOR_SOVERSION}.${LIBNETCONF2_MICRO_SOVERSION}) set(LIBNETCONF2_SOVERSION ${LIBNETCONF2_MAJOR_SOVERSION}) @@ -123,9 +123,7 @@ if(ENABLE_SSH_TLS) src/server_config_util_ssh.c src/session_client_tls.c src/session_server_tls.c - src/server_config_util_tls.c - src/server_config_ks.c - src/server_config_ts.c) + src/server_config_util_tls.c) set(SSH_TLS_MACRO "#ifndef NC_ENABLED_SSH_TLS\n#define NC_ENABLED_SSH_TLS\n#endif") endif() diff --git a/examples/config.json b/examples/config.json index 165579ba..1a5d3fc2 100644 --- a/examples/config.json +++ b/examples/config.json @@ -8,8 +8,12 @@ "name": "ssh-password-auth-endpt", "ssh": { "tcp-server-parameters": { - "local-address": "127.0.0.1", - "local-port": 10000 + "local-bind": [ + { + "local-address": "127.0.0.1", + "local-port": 10000 + } + ] }, "ssh-server-parameters": { "server-identity": { @@ -32,7 +36,9 @@ "user": [ { "name": "admin", - "password": "$0$admin" + "password": { + "hashed-password": "$0$admin" + } } ] } @@ -44,8 +50,12 @@ "name": "ssh-pubkey-auth-endpt", "ssh": { "tcp-server-parameters": { - "local-address": "127.0.0.1", - "local-port": 10001 + "local-bind": [ + { + "local-address": "127.0.0.1", + "local-port": 10001 + } + ] }, "ssh-server-parameters": { "server-identity": { diff --git a/examples/server.c b/examples/server.c index 59dd3e3e..0aab342d 100644 --- a/examples/server.c +++ b/examples/server.c @@ -244,6 +244,13 @@ init(const char *unix_socket_path, struct ly_ctx **context, struct nc_pollsessio } } + /* since nc_server_config_setup_data() requires all implicit nodes to be present and the example + * configuration data does not contain all of them, we need to add them */ + rc = lyd_new_implicit_tree(config, LYD_IMPLICIT_NO_STATE, NULL); + if (rc) { + ERR_MSG_CLEANUP("Adding implicit nodes to the example configuration data failed.\n"); + } + /* apply the example configuration data to the server */ rc = nc_server_config_setup_data(config); if (rc) { diff --git a/modules/iana-ssh-encryption-algs@2024-10-16.yang b/modules/iana-ssh-encryption-algs@2024-10-16.yang new file mode 100755 index 00000000..b2adce05 --- /dev/null +++ b/modules/iana-ssh-encryption-algs@2024-10-16.yang @@ -0,0 +1,365 @@ +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 enumerations for the encryption algorithms + defined in the 'Encryption Algorithm Names' registry of the + 'Secure Shell (SSH) Protocol Parameters' registry group + maintained by IANA. + + Copyright (c) 2024 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 9644 + (https://www.rfc-editor.org/info/rfc9644); see the RFC + itself for full legal notices. + + All versions of this module are published by IANA at + https://www.iana.org/assignments/yang-parameters."; + + revision 2024-10-16 { + description + "This initial version of the module was created using + the script defined in RFC 9644 to reflect the contents + of the encryption algorithms registry maintained by IANA."; + reference + "RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + typedef ssh-encryption-algorithm { + type enumeration { + + enum 3des-cbc { + description + "Enumeration for the '3des-cbc' algorithm. Section 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum blowfish-cbc { + description + "Enumeration for the 'blowfish-cbc' algorithm. Section + 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum twofish256-cbc { + description + "Enumeration for the 'twofish256-cbc' algorithm. Section + 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum twofish-cbc { + description + "Enumeration for the 'twofish-cbc' algorithm. Section 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum twofish192-cbc { + description + "Enumeration for the 'twofish192-cbc' algorithm. Section + 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum twofish128-cbc { + description + "Enumeration for the 'twofish128-cbc' algorithm. Section + 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum aes256-cbc { + description + "Enumeration for the 'aes256-cbc' algorithm. Section 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum aes192-cbc { + description + "Enumeration for the 'aes192-cbc' algorithm. Section 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum aes128-cbc { + description + "Enumeration for the 'aes128-cbc' algorithm. Section 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum serpent256-cbc { + description + "Enumeration for the 'serpent256-cbc' algorithm. Section + 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum serpent192-cbc { + description + "Enumeration for the 'serpent192-cbc' algorithm. Section + 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum serpent128-cbc { + description + "Enumeration for the 'serpent128-cbc' algorithm. Section + 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum arcfour { + status obsolete; + description + "Enumeration for the 'arcfour' algorithm."; + reference + "RFC 8758: + Deprecating RC4 in Secure Shell (SSH)"; + } + + enum idea-cbc { + description + "Enumeration for the 'idea-cbc' algorithm. Section 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum cast128-cbc { + description + "Enumeration for the 'cast128-cbc' algorithm. Section 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum none { + description + "Enumeration for the 'none' algorithm. Section 6.3"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum des-cbc { + status obsolete; + description + "Enumeration for the 'des-cbc' algorithm."; + reference + "FIPS-46-3: + Data Encryption Standard (DES)"; + } + + enum arcfour128 { + status obsolete; + description + "Enumeration for the 'arcfour128' algorithm."; + reference + "RFC 8758: + Deprecating RC4 in Secure Shell (SSH)"; + } + + enum arcfour256 { + status obsolete; + description + "Enumeration for the 'arcfour256' algorithm."; + reference + "RFC 8758: + Deprecating RC4 in Secure Shell (SSH)"; + } + + enum aes128-ctr { + description + "Enumeration for the 'aes128-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum aes192-ctr { + description + "Enumeration for the 'aes192-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum aes256-ctr { + description + "Enumeration for the 'aes256-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum 3des-ctr { + description + "Enumeration for the '3des-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum blowfish-ctr { + description + "Enumeration for the 'blowfish-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum twofish128-ctr { + description + "Enumeration for the 'twofish128-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum twofish192-ctr { + description + "Enumeration for the 'twofish192-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum twofish256-ctr { + description + "Enumeration for the 'twofish256-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum serpent128-ctr { + description + "Enumeration for the 'serpent128-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum serpent192-ctr { + description + "Enumeration for the 'serpent192-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum serpent256-ctr { + description + "Enumeration for the 'serpent256-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum idea-ctr { + description + "Enumeration for the 'idea-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum cast128-ctr { + description + "Enumeration for the 'cast128-ctr' algorithm."; + reference + "RFC 4344: + The Secure Shell (SSH) Transport Layer Encryption + Modes"; + } + + enum AEAD_AES_128_GCM { + description + "Enumeration for the 'AEAD_AES_128_GCM' algorithm. Section + 6.1"; + reference + "RFC 5647: + AES Galois Counter Mode for the Secure Shell Transport + Layer Protocol"; + } + + enum AEAD_AES_256_GCM { + description + "Enumeration for the 'AEAD_AES_256_GCM' algorithm. Section + 6.2"; + reference + "RFC 5647: + AES Galois Counter Mode for the Secure Shell Transport + Layer Protocol"; + } + + enum chacha20-poly1305 { + description + "Enumeration for the 'chacha20-poly1305' algorithm."; + reference + "draft-josefsson-ssh-chacha20-poly1305-openssh-01: + Secure Shell (SSH) authenticated encryption cipher: + chacha20-poly1305"; + } + } + description + "An enumeration for SSH encryption algorithms."; + } + +} diff --git a/modules/iana-ssh-key-exchange-algs@2024-10-16.yang b/modules/iana-ssh-key-exchange-algs@2024-10-16.yang new file mode 100755 index 00000000..3a28078a --- /dev/null +++ b/modules/iana-ssh-key-exchange-algs@2024-10-16.yang @@ -0,0 +1,2107 @@ +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 enumerations for the key exchange algorithms + defined in the 'Key Exchange Method Names' registry of the + 'Secure Shell (SSH) Protocol Parameters' registry group + maintained by IANA. + + Copyright (c) 2024 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 9644 + (https://www.rfc-editor.org/info/rfc9644); see the RFC + itself for full legal notices. + + All versions of this module are published by IANA at + https://www.iana.org/assignments/yang-parameters."; + + revision 2024-10-16 { + description + "This initial version of the module was created using + the script defined in RFC 9644 to reflect the contents + of the key exchange algorithms registry maintained by IANA."; + reference + "RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + typedef ssh-key-exchange-algorithm { + type enumeration { + + enum diffie-hellman-group-exchange-sha1 { + status deprecated; + description + "Enumeration for the 'diffie-hellman-group-exchange-sha1' + algorithm. Section 4.1"; + reference + "RFC 4419: + Diffie-Hellman Group Exchange for the Secure Shell + (SSH) Transport Layer Protocol + RFC 8270: + Increase the Secure Shell Minimum Recommended Diffie- + Hellman Modulus Size to 2048 Bits"; + } + + enum diffie-hellman-group-exchange-sha256 { + description + "Enumeration for the 'diffie-hellman-group-exchange-sha256' + algorithm. Section 4.2"; + reference + "RFC 4419: + Diffie-Hellman Group Exchange for the Secure Shell + (SSH) Transport Layer Protocol + RFC 8270: + Increase the Secure Shell Minimum Recommended Diffie- + Hellman Modulus Size to 2048 Bits"; + } + + enum diffie-hellman-group1-sha1 { + status deprecated; + description + "Enumeration for the 'diffie-hellman-group1-sha1' + algorithm. Section 8.1"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum diffie-hellman-group14-sha1 { + description + "Enumeration for the 'diffie-hellman-group14-sha1' + algorithm. Section 8.2"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum diffie-hellman-group14-sha256 { + description + "Enumeration for the 'diffie-hellman-group14-sha256' + algorithm."; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + enum diffie-hellman-group15-sha512 { + description + "Enumeration for the 'diffie-hellman-group15-sha512' + algorithm."; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + enum diffie-hellman-group16-sha512 { + description + "Enumeration for the 'diffie-hellman-group16-sha512' + algorithm."; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + enum diffie-hellman-group17-sha512 { + description + "Enumeration for the 'diffie-hellman-group17-sha512' + algorithm."; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + enum diffie-hellman-group18-sha512 { + description + "Enumeration for the 'diffie-hellman-group18-sha512' + algorithm."; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + enum ecdh-sha2-nistp256 { + description + "Enumeration for the 'ecdh-sha2-nistp256' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdh-sha2-nistp384 { + description + "Enumeration for the 'ecdh-sha2-nistp384' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdh-sha2-nistp521 { + description + "Enumeration for the 'ecdh-sha2-nistp521' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdh-sha2-1.3.132.0.1 { + description + "Enumeration for the 'ecdh-sha2-1.3.132.0.1' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdh-sha2-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'ecdh-sha2-1.2.840.10045.3.1.1' + algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdh-sha2-1.3.132.0.33 { + description + "Enumeration for the 'ecdh-sha2-1.3.132.0.33' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdh-sha2-1.3.132.0.26 { + description + "Enumeration for the 'ecdh-sha2-1.3.132.0.26' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdh-sha2-1.3.132.0.27 { + description + "Enumeration for the 'ecdh-sha2-1.3.132.0.27' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdh-sha2-1.3.132.0.16 { + description + "Enumeration for the 'ecdh-sha2-1.3.132.0.16' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdh-sha2-1.3.132.0.36 { + description + "Enumeration for the 'ecdh-sha2-1.3.132.0.36' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdh-sha2-1.3.132.0.37 { + description + "Enumeration for the 'ecdh-sha2-1.3.132.0.37' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdh-sha2-1.3.132.0.38 { + description + "Enumeration for the 'ecdh-sha2-1.3.132.0.38' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecmqv-sha2 { + description + "Enumeration for the 'ecmqv-sha2' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum gss-group1-sha1-nistp256 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-nistp256' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group1-sha1-nistp384 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-nistp384' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group1-sha1-nistp521 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-nistp521' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group1-sha1-1.3.132.0.1 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-1.3.132.0.1' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group1-sha1-1.2.840.10045.3.1.1 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-1.2.840.10045.3.1.1' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group1-sha1-1.3.132.0.33 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-1.3.132.0.33' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group1-sha1-1.3.132.0.26 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-1.3.132.0.26' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group1-sha1-1.3.132.0.27 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-1.3.132.0.27' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group1-sha1-1.3.132.0.16 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-1.3.132.0.16' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group1-sha1-1.3.132.0.36 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-1.3.132.0.36' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group1-sha1-1.3.132.0.37 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-1.3.132.0.37' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group1-sha1-1.3.132.0.38 { + status deprecated; + description + "Enumeration for the 'gss-group1-sha1-1.3.132.0.38' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-nistp256 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-nistp256' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-nistp384 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-nistp384' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-nistp521 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-nistp521' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-1.3.132.0.1 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-1.3.132.0.1' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-1.2.840.10045.3.1.1 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-1.2.840.10045.3.1.1' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-1.3.132.0.33 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-1.3.132.0.33' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-1.3.132.0.26 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-1.3.132.0.26' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-1.3.132.0.27 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-1.3.132.0.27' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-1.3.132.0.16 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-1.3.132.0.16' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-1.3.132.0.36 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-1.3.132.0.36' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-1.3.132.0.37 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-1.3.132.0.37' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha1-1.3.132.0.38 { + status deprecated; + description + "Enumeration for the 'gss-group14-sha1-1.3.132.0.38' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-nistp256 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-nistp256' algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-nistp384 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-nistp384' algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-nistp521 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-nistp521' algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-1.3.132.0.1 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-1.3.132.0.1' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-1.2.840.10045.3.1.1 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-1.2.840.10045.3.1.1' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-1.3.132.0.33 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-1.3.132.0.33' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-1.3.132.0.26 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-1.3.132.0.26' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-1.3.132.0.27 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-1.3.132.0.27' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-1.3.132.0.16 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-1.3.132.0.16' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-1.3.132.0.36 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-1.3.132.0.36' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-1.3.132.0.37 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-1.3.132.0.37' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-gex-sha1-1.3.132.0.38 { + status deprecated; + description + "Enumeration for the 'gss-gex-sha1-1.3.132.0.38' + algorithm."; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol + RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss- { + description + "Enumeration for the 'gss-' algorithm. Section 2.6"; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol"; + } + + enum rsa1024-sha1 { + status obsolete; + description + "Enumeration for the 'rsa1024-sha1' algorithm."; + reference + "RFC 4432: + RSA Key Exchange for the Secure Shell (SSH) Transport + Layer Protocol"; + } + + enum rsa2048-sha256 { + description + "Enumeration for the 'rsa2048-sha256' algorithm."; + reference + "RFC 4432: + RSA Key Exchange for the Secure Shell (SSH) Transport + Layer Protocol"; + } + + enum ext-info-s { + description + "Enumeration for the 'ext-info-s' algorithm. Section 2"; + reference + "RFC 8308: + Extension Negotiation in the Secure Shell (SSH) + Protocol"; + } + + enum ext-info-c { + description + "Enumeration for the 'ext-info-c' algorithm. Section 2"; + reference + "RFC 8308: + Extension Negotiation in the Secure Shell (SSH) + Protocol"; + } + + enum gss-group14-sha256-nistp256 { + description + "Enumeration for the 'gss-group14-sha256-nistp256' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha256-nistp384 { + description + "Enumeration for the 'gss-group14-sha256-nistp384' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha256-nistp521 { + description + "Enumeration for the 'gss-group14-sha256-nistp521' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha256-1.3.132.0.1 { + description + "Enumeration for the 'gss-group14-sha256-1.3.132.0.1' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha256-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'gss- + group14-sha256-1.2.840.10045.3.1.1' algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha256-1.3.132.0.33 { + description + "Enumeration for the 'gss-group14-sha256-1.3.132.0.33' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha256-1.3.132.0.26 { + description + "Enumeration for the 'gss-group14-sha256-1.3.132.0.26' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha256-1.3.132.0.27 { + description + "Enumeration for the 'gss-group14-sha256-1.3.132.0.27' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha256-1.3.132.0.16 { + description + "Enumeration for the 'gss-group14-sha256-1.3.132.0.16' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha256-1.3.132.0.36 { + description + "Enumeration for the 'gss-group14-sha256-1.3.132.0.36' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha256-1.3.132.0.37 { + description + "Enumeration for the 'gss-group14-sha256-1.3.132.0.37' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group14-sha256-1.3.132.0.38 { + description + "Enumeration for the 'gss-group14-sha256-1.3.132.0.38' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-nistp256 { + description + "Enumeration for the 'gss-group15-sha512-nistp256' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-nistp384 { + description + "Enumeration for the 'gss-group15-sha512-nistp384' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-nistp521 { + description + "Enumeration for the 'gss-group15-sha512-nistp521' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-1.3.132.0.1 { + description + "Enumeration for the 'gss-group15-sha512-1.3.132.0.1' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'gss- + group15-sha512-1.2.840.10045.3.1.1' algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-1.3.132.0.33 { + description + "Enumeration for the 'gss-group15-sha512-1.3.132.0.33' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-1.3.132.0.26 { + description + "Enumeration for the 'gss-group15-sha512-1.3.132.0.26' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-1.3.132.0.27 { + description + "Enumeration for the 'gss-group15-sha512-1.3.132.0.27' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-1.3.132.0.16 { + description + "Enumeration for the 'gss-group15-sha512-1.3.132.0.16' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-1.3.132.0.36 { + description + "Enumeration for the 'gss-group15-sha512-1.3.132.0.36' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-1.3.132.0.37 { + description + "Enumeration for the 'gss-group15-sha512-1.3.132.0.37' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group15-sha512-1.3.132.0.38 { + description + "Enumeration for the 'gss-group15-sha512-1.3.132.0.38' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-nistp256 { + description + "Enumeration for the 'gss-group16-sha512-nistp256' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-nistp384 { + description + "Enumeration for the 'gss-group16-sha512-nistp384' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-nistp521 { + description + "Enumeration for the 'gss-group16-sha512-nistp521' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-1.3.132.0.1 { + description + "Enumeration for the 'gss-group16-sha512-1.3.132.0.1' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'gss- + group16-sha512-1.2.840.10045.3.1.1' algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-1.3.132.0.33 { + description + "Enumeration for the 'gss-group16-sha512-1.3.132.0.33' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-1.3.132.0.26 { + description + "Enumeration for the 'gss-group16-sha512-1.3.132.0.26' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-1.3.132.0.27 { + description + "Enumeration for the 'gss-group16-sha512-1.3.132.0.27' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-1.3.132.0.16 { + description + "Enumeration for the 'gss-group16-sha512-1.3.132.0.16' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-1.3.132.0.36 { + description + "Enumeration for the 'gss-group16-sha512-1.3.132.0.36' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-1.3.132.0.37 { + description + "Enumeration for the 'gss-group16-sha512-1.3.132.0.37' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group16-sha512-1.3.132.0.38 { + description + "Enumeration for the 'gss-group16-sha512-1.3.132.0.38' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-nistp256 { + description + "Enumeration for the 'gss-group17-sha512-nistp256' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-nistp384 { + description + "Enumeration for the 'gss-group17-sha512-nistp384' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-nistp521 { + description + "Enumeration for the 'gss-group17-sha512-nistp521' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-1.3.132.0.1 { + description + "Enumeration for the 'gss-group17-sha512-1.3.132.0.1' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'gss- + group17-sha512-1.2.840.10045.3.1.1' algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-1.3.132.0.33 { + description + "Enumeration for the 'gss-group17-sha512-1.3.132.0.33' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-1.3.132.0.26 { + description + "Enumeration for the 'gss-group17-sha512-1.3.132.0.26' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-1.3.132.0.27 { + description + "Enumeration for the 'gss-group17-sha512-1.3.132.0.27' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-1.3.132.0.16 { + description + "Enumeration for the 'gss-group17-sha512-1.3.132.0.16' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-1.3.132.0.36 { + description + "Enumeration for the 'gss-group17-sha512-1.3.132.0.36' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-1.3.132.0.37 { + description + "Enumeration for the 'gss-group17-sha512-1.3.132.0.37' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group17-sha512-1.3.132.0.38 { + description + "Enumeration for the 'gss-group17-sha512-1.3.132.0.38' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-nistp256 { + description + "Enumeration for the 'gss-group18-sha512-nistp256' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-nistp384 { + description + "Enumeration for the 'gss-group18-sha512-nistp384' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-nistp521 { + description + "Enumeration for the 'gss-group18-sha512-nistp521' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-1.3.132.0.1 { + description + "Enumeration for the 'gss-group18-sha512-1.3.132.0.1' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'gss- + group18-sha512-1.2.840.10045.3.1.1' algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-1.3.132.0.33 { + description + "Enumeration for the 'gss-group18-sha512-1.3.132.0.33' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-1.3.132.0.26 { + description + "Enumeration for the 'gss-group18-sha512-1.3.132.0.26' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-1.3.132.0.27 { + description + "Enumeration for the 'gss-group18-sha512-1.3.132.0.27' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-1.3.132.0.16 { + description + "Enumeration for the 'gss-group18-sha512-1.3.132.0.16' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-1.3.132.0.36 { + description + "Enumeration for the 'gss-group18-sha512-1.3.132.0.36' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-1.3.132.0.37 { + description + "Enumeration for the 'gss-group18-sha512-1.3.132.0.37' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-group18-sha512-1.3.132.0.38 { + description + "Enumeration for the 'gss-group18-sha512-1.3.132.0.38' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-nistp256 { + description + "Enumeration for the 'gss-nistp256-sha256-nistp256' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-nistp384 { + description + "Enumeration for the 'gss-nistp256-sha256-nistp384' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-nistp521 { + description + "Enumeration for the 'gss-nistp256-sha256-nistp521' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-1.3.132.0.1 { + description + "Enumeration for the 'gss-nistp256-sha256-1.3.132.0.1' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'gss- + nistp256-sha256-1.2.840.10045.3.1.1' algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-1.3.132.0.33 { + description + "Enumeration for the 'gss-nistp256-sha256-1.3.132.0.33' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-1.3.132.0.26 { + description + "Enumeration for the 'gss-nistp256-sha256-1.3.132.0.26' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-1.3.132.0.27 { + description + "Enumeration for the 'gss-nistp256-sha256-1.3.132.0.27' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-1.3.132.0.16 { + description + "Enumeration for the 'gss-nistp256-sha256-1.3.132.0.16' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-1.3.132.0.36 { + description + "Enumeration for the 'gss-nistp256-sha256-1.3.132.0.36' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-1.3.132.0.37 { + description + "Enumeration for the 'gss-nistp256-sha256-1.3.132.0.37' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp256-sha256-1.3.132.0.38 { + description + "Enumeration for the 'gss-nistp256-sha256-1.3.132.0.38' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-nistp256 { + description + "Enumeration for the 'gss-nistp384-sha384-nistp256' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-nistp384 { + description + "Enumeration for the 'gss-nistp384-sha384-nistp384' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-nistp521 { + description + "Enumeration for the 'gss-nistp384-sha384-nistp521' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-1.3.132.0.1 { + description + "Enumeration for the 'gss-nistp384-sha384-1.3.132.0.1' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'gss- + nistp384-sha384-1.2.840.10045.3.1.1' algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-1.3.132.0.33 { + description + "Enumeration for the 'gss-nistp384-sha384-1.3.132.0.33' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-1.3.132.0.26 { + description + "Enumeration for the 'gss-nistp384-sha384-1.3.132.0.26' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-1.3.132.0.27 { + description + "Enumeration for the 'gss-nistp384-sha384-1.3.132.0.27' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-1.3.132.0.16 { + description + "Enumeration for the 'gss-nistp384-sha384-1.3.132.0.16' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-1.3.132.0.36 { + description + "Enumeration for the 'gss-nistp384-sha384-1.3.132.0.36' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-1.3.132.0.37 { + description + "Enumeration for the 'gss-nistp384-sha384-1.3.132.0.37' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp384-sha384-1.3.132.0.38 { + description + "Enumeration for the 'gss-nistp384-sha384-1.3.132.0.38' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-nistp256 { + description + "Enumeration for the 'gss-nistp521-sha512-nistp256' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-nistp384 { + description + "Enumeration for the 'gss-nistp521-sha512-nistp384' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-nistp521 { + description + "Enumeration for the 'gss-nistp521-sha512-nistp521' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-1.3.132.0.1 { + description + "Enumeration for the 'gss-nistp521-sha512-1.3.132.0.1' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'gss- + nistp521-sha512-1.2.840.10045.3.1.1' algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-1.3.132.0.33 { + description + "Enumeration for the 'gss-nistp521-sha512-1.3.132.0.33' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-1.3.132.0.26 { + description + "Enumeration for the 'gss-nistp521-sha512-1.3.132.0.26' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-1.3.132.0.27 { + description + "Enumeration for the 'gss-nistp521-sha512-1.3.132.0.27' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-1.3.132.0.16 { + description + "Enumeration for the 'gss-nistp521-sha512-1.3.132.0.16' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-1.3.132.0.36 { + description + "Enumeration for the 'gss-nistp521-sha512-1.3.132.0.36' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-1.3.132.0.37 { + description + "Enumeration for the 'gss-nistp521-sha512-1.3.132.0.37' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-nistp521-sha512-1.3.132.0.38 { + description + "Enumeration for the 'gss-nistp521-sha512-1.3.132.0.38' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-nistp256 { + description + "Enumeration for the 'gss-curve25519-sha256-nistp256' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-nistp384 { + description + "Enumeration for the 'gss-curve25519-sha256-nistp384' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-nistp521 { + description + "Enumeration for the 'gss-curve25519-sha256-nistp521' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-1.3.132.0.1 { + description + "Enumeration for the 'gss-curve25519-sha256-1.3.132.0.1' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'gss- + curve25519-sha256-1.2.840.10045.3.1.1' algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-1.3.132.0.33 { + description + "Enumeration for the 'gss-curve25519-sha256-1.3.132.0.33' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-1.3.132.0.26 { + description + "Enumeration for the 'gss-curve25519-sha256-1.3.132.0.26' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-1.3.132.0.27 { + description + "Enumeration for the 'gss-curve25519-sha256-1.3.132.0.27' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-1.3.132.0.16 { + description + "Enumeration for the 'gss-curve25519-sha256-1.3.132.0.16' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-1.3.132.0.36 { + description + "Enumeration for the 'gss-curve25519-sha256-1.3.132.0.36' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-1.3.132.0.37 { + description + "Enumeration for the 'gss-curve25519-sha256-1.3.132.0.37' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve25519-sha256-1.3.132.0.38 { + description + "Enumeration for the 'gss-curve25519-sha256-1.3.132.0.38' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-nistp256 { + description + "Enumeration for the 'gss-curve448-sha512-nistp256' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-nistp384 { + description + "Enumeration for the 'gss-curve448-sha512-nistp384' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-nistp521 { + description + "Enumeration for the 'gss-curve448-sha512-nistp521' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-1.3.132.0.1 { + description + "Enumeration for the 'gss-curve448-sha512-1.3.132.0.1' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'gss- + curve448-sha512-1.2.840.10045.3.1.1' algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-1.3.132.0.33 { + description + "Enumeration for the 'gss-curve448-sha512-1.3.132.0.33' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-1.3.132.0.26 { + description + "Enumeration for the 'gss-curve448-sha512-1.3.132.0.26' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-1.3.132.0.27 { + description + "Enumeration for the 'gss-curve448-sha512-1.3.132.0.27' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-1.3.132.0.16 { + description + "Enumeration for the 'gss-curve448-sha512-1.3.132.0.16' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-1.3.132.0.36 { + description + "Enumeration for the 'gss-curve448-sha512-1.3.132.0.36' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-1.3.132.0.37 { + description + "Enumeration for the 'gss-curve448-sha512-1.3.132.0.37' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum gss-curve448-sha512-1.3.132.0.38 { + description + "Enumeration for the 'gss-curve448-sha512-1.3.132.0.38' + algorithm."; + reference + "RFC 8732: + Generic Security Service Application Program Interface + (GSS-API) Key Exchange with SHA-2"; + } + + enum curve25519-sha256 { + description + "Enumeration for the 'curve25519-sha256' algorithm."; + reference + "RFC 8731: + Secure Shell (SSH) Key Exchange Method Using + Curve25519 and Curve448"; + } + + enum curve448-sha512 { + description + "Enumeration for the 'curve448-sha512' algorithm."; + reference + "RFC 8731: + Secure Shell (SSH) Key Exchange Method Using + Curve25519 and Curve448"; + } + + enum sntrup761x25519-sha512 { + description + "Enumeration for the 'sntrup761x25519-sha512' algorithm."; + reference + "draft-josefsson-ntruprime-ssh-02: + Secure Shell (SSH) Key Exchange Method Using Hybrid + Streamlined NTRU Prime sntrup761 and X25519 with + SHA-512: sntrup761x25519-sha512"; + } + + enum mlkem768nistp256-sha256 { + description + "Enumeration for the 'mlkem768nistp256-sha256' algorithm."; + reference + "draft-kampanakis-curdle-ssh-pq-ke-04: + PQ/T Hybrid Key Exchange in SSH"; + } + + enum mlkem1024nistp384-sha384 { + description + "Enumeration for the 'mlkem1024nistp384-sha384' + algorithm."; + reference + "draft-kampanakis-curdle-ssh-pq-ke-04: + PQ/T Hybrid Key Exchange in SSH"; + } + + enum mlkem768x25519-sha256 { + description + "Enumeration for the 'mlkem768x25519-sha256' algorithm."; + reference + "draft-kampanakis-curdle-ssh-pq-ke-04: + PQ/T Hybrid Key Exchange in SSH"; + } + } + description + "An enumeration for SSH key exchange algorithms."; + } + +} diff --git a/modules/iana-ssh-mac-algs@2024-10-16.yang b/modules/iana-ssh-mac-algs@2024-10-16.yang new file mode 100755 index 00000000..0cc6bbdd --- /dev/null +++ b/modules/iana-ssh-mac-algs@2024-10-16.yang @@ -0,0 +1,135 @@ +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 enumerations for the MAC algorithms + defined in the 'MAC Algorithm Names' registry of the + 'Secure Shell (SSH) Protocol Parameters' registry group + maintained by IANA. + + Copyright (c) 2024 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 9644 + (https://www.rfc-editor.org/info/rfc9644); see the RFC + itself for full legal notices. + + All versions of this module are published by IANA at + https://www.iana.org/assignments/yang-parameters."; + + revision 2024-10-16 { + description + "This initial version of the module was created using + the script defined in RFC 9644 to reflect the contents + of the mac algorithms registry maintained by IANA."; + reference + "RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + typedef ssh-mac-algorithm { + type enumeration { + + enum hmac-sha1 { + description + "Enumeration for the 'hmac-sha1' algorithm. Section 6.4"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum hmac-sha1-96 { + description + "Enumeration for the 'hmac-sha1-96' algorithm. Section + 6.4"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum hmac-md5 { + description + "Enumeration for the 'hmac-md5' algorithm. Section 6.4"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum hmac-md5-96 { + description + "Enumeration for the 'hmac-md5-96' algorithm. Section 6.4"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum none { + description + "Enumeration for the 'none' algorithm. Section 6.4"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum AEAD_AES_128_GCM { + description + "Enumeration for the 'AEAD_AES_128_GCM' algorithm. Section + 6.1"; + reference + "RFC 5647: + AES Galois Counter Mode for the Secure Shell Transport + Layer Protocol"; + } + + enum AEAD_AES_256_GCM { + description + "Enumeration for the 'AEAD_AES_256_GCM' algorithm. Section + 6.2"; + reference + "RFC 5647: + AES Galois Counter Mode for the Secure Shell Transport + Layer Protocol"; + } + + enum hmac-sha2-256 { + description + "Enumeration for the 'hmac-sha2-256' algorithm. Section 2"; + reference + "RFC 6668: + SHA-2 Data Integrity Verification for the Secure Shell + (SSH) Transport Layer Protocol"; + } + + enum hmac-sha2-512 { + description + "Enumeration for the 'hmac-sha2-512' algorithm. Section 2"; + reference + "RFC 6668: + SHA-2 Data Integrity Verification for the Secure Shell + (SSH) Transport Layer Protocol"; + } + } + description + "An enumeration for SSH mac algorithms."; + } + +} diff --git a/modules/iana-ssh-public-key-algs@2024-10-16.yang b/modules/iana-ssh-public-key-algs@2024-10-16.yang new file mode 100755 index 00000000..30d885aa --- /dev/null +++ b/modules/iana-ssh-public-key-algs@2024-10-16.yang @@ -0,0 +1,395 @@ +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 enumerations for the public key algorithms + defined in the 'Public Key Algorithm Names' registry of the + 'Secure Shell (SSH) Protocol Parameters' registry group + maintained by IANA. + + Copyright (c) 2024 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 9644 + (https://www.rfc-editor.org/info/rfc9644); see the RFC + itself for full legal notices. + + All versions of this module are published by IANA at + https://www.iana.org/assignments/yang-parameters."; + + revision 2024-10-16 { + description + "This initial version of the module was created using + the script defined in RFC 9644 to reflect the contents + of the public key algorithms registry maintained by IANA."; + reference + "RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + typedef ssh-public-key-algorithm { + type enumeration { + + enum ssh-dss { + description + "Enumeration for the 'ssh-dss' algorithm. Section 6.6"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum ssh-rsa { + description + "Enumeration for the 'ssh-rsa' algorithm. Section 6.6"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum rsa-sha2-256 { + description + "Enumeration for the 'rsa-sha2-256' algorithm. Section 3"; + reference + "RFC 8332: + Use of RSA Keys with SHA-256 and SHA-512 in the Secure + Shell (SSH) Protocol"; + } + + enum rsa-sha2-512 { + description + "Enumeration for the 'rsa-sha2-512' algorithm. Section 3"; + reference + "RFC 8332: + Use of RSA Keys with SHA-256 and SHA-512 in the Secure + Shell (SSH) Protocol"; + } + + enum spki-sign-rsa { + description + "Enumeration for the 'spki-sign-rsa' algorithm. Section + 6.6"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum spki-sign-dss { + description + "Enumeration for the 'spki-sign-dss' algorithm. Section + 6.6"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum pgp-sign-rsa { + description + "Enumeration for the 'pgp-sign-rsa' algorithm. Section + 6.6"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum pgp-sign-dss { + description + "Enumeration for the 'pgp-sign-dss' algorithm. Section + 6.6"; + reference + "RFC 4253: + The Secure Shell (SSH) Transport Layer Protocol"; + } + + enum null { + description + "Enumeration for the 'null' algorithm. Section 5"; + reference + "RFC 4462: + Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the + Secure Shell (SSH) Protocol"; + } + + enum ecdsa-sha2-nistp256 { + description + "Enumeration for the 'ecdsa-sha2-nistp256' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdsa-sha2-nistp384 { + description + "Enumeration for the 'ecdsa-sha2-nistp384' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdsa-sha2-nistp521 { + description + "Enumeration for the 'ecdsa-sha2-nistp521' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdsa-sha2-1.3.132.0.1 { + description + "Enumeration for the 'ecdsa-sha2-1.3.132.0.1' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdsa-sha2-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'ecdsa-sha2-1.2.840.10045.3.1.1' + algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdsa-sha2-1.3.132.0.33 { + description + "Enumeration for the 'ecdsa-sha2-1.3.132.0.33' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdsa-sha2-1.3.132.0.26 { + description + "Enumeration for the 'ecdsa-sha2-1.3.132.0.26' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdsa-sha2-1.3.132.0.27 { + description + "Enumeration for the 'ecdsa-sha2-1.3.132.0.27' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdsa-sha2-1.3.132.0.16 { + description + "Enumeration for the 'ecdsa-sha2-1.3.132.0.16' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdsa-sha2-1.3.132.0.36 { + description + "Enumeration for the 'ecdsa-sha2-1.3.132.0.36' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdsa-sha2-1.3.132.0.37 { + description + "Enumeration for the 'ecdsa-sha2-1.3.132.0.37' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum ecdsa-sha2-1.3.132.0.38 { + description + "Enumeration for the 'ecdsa-sha2-1.3.132.0.38' algorithm."; + reference + "RFC 5656: + Elliptic Curve Algorithm Integration in the Secure + Shell Transport Layer"; + } + + enum x509v3-ssh-dss { + description + "Enumeration for the 'x509v3-ssh-dss' algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ssh-rsa { + description + "Enumeration for the 'x509v3-ssh-rsa' algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-rsa2048-sha256 { + description + "Enumeration for the 'x509v3-rsa2048-sha256' algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-nistp256 { + description + "Enumeration for the 'x509v3-ecdsa-sha2-nistp256' + algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-nistp384 { + description + "Enumeration for the 'x509v3-ecdsa-sha2-nistp384' + algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-nistp521 { + description + "Enumeration for the 'x509v3-ecdsa-sha2-nistp521' + algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-1.3.132.0.1 { + description + "Enumeration for the 'x509v3-ecdsa-sha2-1.3.132.0.1' + algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-1.2.840.10045.3.1.1 { + description + "Enumeration for the 'x509v3-ecdsa- + sha2-1.2.840.10045.3.1.1' algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-1.3.132.0.33 { + description + "Enumeration for the 'x509v3-ecdsa-sha2-1.3.132.0.33' + algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-1.3.132.0.26 { + description + "Enumeration for the 'x509v3-ecdsa-sha2-1.3.132.0.26' + algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-1.3.132.0.27 { + description + "Enumeration for the 'x509v3-ecdsa-sha2-1.3.132.0.27' + algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-1.3.132.0.16 { + description + "Enumeration for the 'x509v3-ecdsa-sha2-1.3.132.0.16' + algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-1.3.132.0.36 { + description + "Enumeration for the 'x509v3-ecdsa-sha2-1.3.132.0.36' + algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-1.3.132.0.37 { + description + "Enumeration for the 'x509v3-ecdsa-sha2-1.3.132.0.37' + algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum x509v3-ecdsa-sha2-1.3.132.0.38 { + description + "Enumeration for the 'x509v3-ecdsa-sha2-1.3.132.0.38' + algorithm."; + reference + "RFC 6187: + X.509v3 Certificates for Secure Shell Authentication"; + } + + enum ssh-ed25519 { + description + "Enumeration for the 'ssh-ed25519' algorithm."; + reference + "RFC 8709: + Ed25519 and Ed448 Public Key Algorithms for the Secure + Shell (SSH) Protocol"; + } + + enum ssh-ed448 { + description + "Enumeration for the 'ssh-ed448' algorithm."; + reference + "RFC 8709: + Ed25519 and Ed448 Public Key Algorithms for the Secure + Shell (SSH) Protocol"; + } + } + description + "An enumeration for SSH public key algorithms."; + } + +} diff --git a/modules/iana-tls-cipher-suite-algs@2024-10-16.yang b/modules/iana-tls-cipher-suite-algs@2024-10-16.yang new file mode 100755 index 00000000..31145128 --- /dev/null +++ b/modules/iana-tls-cipher-suite-algs@2024-10-16.yang @@ -0,0 +1,3551 @@ +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: "; + + description + "This module defines enumerations for the cipher suite + algorithms defined in the 'TLS Cipher Suites' registry + under the 'Transport Layer Security (TLS) Parameters' + registry group maintained by IANA. + + Copyright (c) 2024 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 9645 + (https://www.rfc-editor.org/info/rfc9645); see the RFC + itself for full legal notices. + + All versions of this module are published by IANA + (https://www.iana.org/assignments/yang-parameters)."; + + revision 2024-10-16 { + description + "This initial version of the module was created using + the script defined in RFC 9645 to reflect the contents + of the cipher-suite algorithms registry maintained by IANA."; + reference + "RFC 9645: YANG Groupings for TLS Clients and TLS Servers"; + } + + typedef tls-cipher-suite-algorithm { + type enumeration { + enum TLS_NULL_WITH_NULL_NULL { + status deprecated; + description + "Enumeration for the 'TLS_NULL_WITH_NULL_NULL' algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_RSA_WITH_NULL_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_NULL_MD5' algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_RSA_WITH_NULL_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_NULL_SHA' algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_RSA_EXPORT_WITH_RC4_40_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_EXPORT_WITH_RC4_40_MD5' + algorithm."; + reference + "RFC 4346: + The Transport Layer Security (TLS) Protocol Version 1.1 + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_RSA_WITH_RC4_128_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_RC4_128_MD5' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2 + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_RSA_WITH_RC4_128_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_RC4_128_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2 + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5' + algorithm."; + reference + "RFC 4346: + The Transport Layer Security (TLS) Protocol Version + 1.1"; + } + enum TLS_RSA_WITH_IDEA_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_IDEA_CBC_SHA' + algorithm."; + reference + "RFC 8996: + Deprecating TLS 1.0 and TLS 1.1"; + } + enum TLS_RSA_EXPORT_WITH_DES40_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_EXPORT_WITH_DES40_CBC_SHA' + algorithm."; + reference + "RFC 4346: + The Transport Layer Security (TLS) Protocol Version + 1.1"; + } + enum TLS_RSA_WITH_DES_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_DES_CBC_SHA' + algorithm."; + reference + "RFC 8996: + Deprecating TLS 1.0 and TLS 1.1"; + } + enum TLS_RSA_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA' + algorithm."; + reference + "RFC 4346: + The Transport Layer Security (TLS) Protocol Version + 1.1"; + } + enum TLS_DH_DSS_WITH_DES_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_DES_CBC_SHA' + algorithm."; + reference + "RFC 8996: + Deprecating TLS 1.0 and TLS 1.1"; + } + enum TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA' + algorithm."; + reference + "RFC 4346: + The Transport Layer Security (TLS) Protocol Version + 1.1"; + } + enum TLS_DH_RSA_WITH_DES_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_DES_CBC_SHA' + algorithm."; + reference + "RFC 8996: + Deprecating TLS 1.0 and TLS 1.1"; + } + enum TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA' algorithm."; + reference + "RFC 4346: + The Transport Layer Security (TLS) Protocol Version + 1.1"; + } + enum TLS_DHE_DSS_WITH_DES_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_DES_CBC_SHA' + algorithm."; + reference + "RFC 8996: + Deprecating TLS 1.0 and TLS 1.1"; + } + enum TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA' algorithm."; + reference + "RFC 4346: + The Transport Layer Security (TLS) Protocol Version + 1.1"; + } + enum TLS_DHE_RSA_WITH_DES_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_DES_CBC_SHA' + algorithm."; + reference + "RFC 8996: + Deprecating TLS 1.0 and TLS 1.1"; + } + enum TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_EXPORT_WITH_RC4_40_MD5' + algorithm."; + reference + "RFC 4346: + The Transport Layer Security (TLS) Protocol Version 1.1 + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_DH_anon_WITH_RC4_128_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_RC4_128_MD5' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version 1.2 + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA' algorithm."; + reference + "RFC 4346: + The Transport Layer Security (TLS) Protocol Version + 1.1"; + } + enum TLS_DH_anon_WITH_DES_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_DES_CBC_SHA' + algorithm."; + reference + "RFC 8996: + Deprecating TLS 1.0 and TLS 1.1"; + } + enum TLS_DH_anon_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_KRB5_WITH_DES_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_WITH_DES_CBC_SHA' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_KRB5_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_KRB5_WITH_RC4_128_SHA { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_WITH_RC4_128_SHA' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS) + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_KRB5_WITH_IDEA_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_WITH_IDEA_CBC_SHA' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_KRB5_WITH_DES_CBC_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_WITH_DES_CBC_MD5' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_KRB5_WITH_3DES_EDE_CBC_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_WITH_3DES_EDE_CBC_MD5' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_KRB5_WITH_RC4_128_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_WITH_RC4_128_MD5' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS) + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_KRB5_WITH_IDEA_CBC_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_WITH_IDEA_CBC_MD5' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_KRB5_EXPORT_WITH_RC4_40_SHA { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_EXPORT_WITH_RC4_40_SHA' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS) + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_KRB5_EXPORT_WITH_RC4_40_MD5 { + status deprecated; + description + "Enumeration for the 'TLS_KRB5_EXPORT_WITH_RC4_40_MD5' + algorithm."; + reference + "RFC 2712: + Addition of Kerberos Cipher Suites to Transport Layer + Security (TLS) + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_PSK_WITH_NULL_SHA { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_NULL_SHA' algorithm."; + reference + "RFC 4785: + Pre-Shared Key (PSK) Ciphersuites with NULL Encryption + for Transport Layer Security (TLS)"; + } + enum TLS_DHE_PSK_WITH_NULL_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_NULL_SHA' + algorithm."; + reference + "RFC 4785: + Pre-Shared Key (PSK) Ciphersuites with NULL Encryption + for Transport Layer Security (TLS)"; + } + enum TLS_RSA_PSK_WITH_NULL_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_NULL_SHA' + algorithm."; + reference + "RFC 4785: + Pre-Shared Key (PSK) Ciphersuites with NULL Encryption + for Transport Layer Security (TLS)"; + } + enum TLS_RSA_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_DSS_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_RSA_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DHE_DSS_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DHE_RSA_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_anon_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_RSA_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_DSS_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_RSA_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DHE_DSS_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DHE_RSA_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_anon_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_RSA_WITH_NULL_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_NULL_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_RSA_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_AES_128_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_RSA_WITH_AES_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_AES_256_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_DSS_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_AES_128_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_RSA_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_AES_128_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_RSA_WITH_CAMELLIA_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_CAMELLIA_128_CBC_SHA' + algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA' + algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA' + algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_AES_128_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_DSS_WITH_AES_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_AES_256_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_RSA_WITH_AES_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_AES_256_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_AES_256_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_anon_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_AES_128_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_DH_anon_WITH_AES_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_AES_256_CBC_SHA256' + algorithm."; + reference + "RFC 5246: + The Transport Layer Security (TLS) Protocol Version + 1.2"; + } + enum TLS_RSA_WITH_CAMELLIA_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_CAMELLIA_256_CBC_SHA' + algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA' + algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA' + algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_PSK_WITH_RC4_128_SHA { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_RC4_128_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS) + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_PSK_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS)"; + } + enum TLS_PSK_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS)"; + } + enum TLS_PSK_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS)"; + } + enum TLS_DHE_PSK_WITH_RC4_128_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_RC4_128_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS) + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS)"; + } + enum TLS_DHE_PSK_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS)"; + } + enum TLS_DHE_PSK_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS)"; + } + enum TLS_RSA_PSK_WITH_RC4_128_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_RC4_128_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS) + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS)"; + } + enum TLS_RSA_PSK_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS)"; + } + enum TLS_RSA_PSK_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 4279: + Pre-Shared Key Ciphersuites for Transport Layer Security + (TLS)"; + } + enum TLS_RSA_WITH_SEED_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_SEED_CBC_SHA' + algorithm."; + reference + "RFC 4162: + Addition of SEED Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_DSS_WITH_SEED_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_SEED_CBC_SHA' + algorithm."; + reference + "RFC 4162: + Addition of SEED Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_RSA_WITH_SEED_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_SEED_CBC_SHA' + algorithm."; + reference + "RFC 4162: + Addition of SEED Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_DSS_WITH_SEED_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_SEED_CBC_SHA' + algorithm."; + reference + "RFC 4162: + Addition of SEED Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_RSA_WITH_SEED_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_SEED_CBC_SHA' + algorithm."; + reference + "RFC 4162: + Addition of SEED Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_anon_WITH_SEED_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_SEED_CBC_SHA' + algorithm."; + reference + "RFC 4162: + Addition of SEED Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_RSA_WITH_AES_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_AES_128_GCM_SHA256' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_RSA_WITH_AES_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_AES_256_GCM_SHA384' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 { + description + "Enumeration for the 'TLS_DHE_RSA_WITH_AES_128_GCM_SHA256' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 { + description + "Enumeration for the 'TLS_DHE_RSA_WITH_AES_256_GCM_SHA384' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_DH_RSA_WITH_AES_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_AES_128_GCM_SHA256' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_DH_RSA_WITH_AES_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_AES_256_GCM_SHA384' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_AES_128_GCM_SHA256' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_AES_256_GCM_SHA384' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_DH_DSS_WITH_AES_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_AES_128_GCM_SHA256' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_DH_DSS_WITH_AES_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_AES_256_GCM_SHA384' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_DH_anon_WITH_AES_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_AES_128_GCM_SHA256' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_DH_anon_WITH_AES_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_AES_256_GCM_SHA384' + algorithm."; + reference + "RFC 5288: + AES Galois Counter Mode (GCM) Cipher Suites for TLS"; + } + enum TLS_PSK_WITH_AES_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_AES_128_GCM_SHA256' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_PSK_WITH_AES_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_AES_256_GCM_SHA384' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 { + description + "Enumeration for the 'TLS_DHE_PSK_WITH_AES_128_GCM_SHA256' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 { + description + "Enumeration for the 'TLS_DHE_PSK_WITH_AES_256_GCM_SHA384' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_AES_128_GCM_SHA256' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_AES_256_GCM_SHA384' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_PSK_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_AES_128_CBC_SHA256' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_PSK_WITH_AES_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_AES_256_CBC_SHA384' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_PSK_WITH_NULL_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_NULL_SHA256' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_PSK_WITH_NULL_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_NULL_SHA384' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_AES_128_CBC_SHA256' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_AES_256_CBC_SHA384' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_DHE_PSK_WITH_NULL_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_NULL_SHA256' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_DHE_PSK_WITH_NULL_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_NULL_SHA384' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_AES_128_CBC_SHA256' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_AES_256_CBC_SHA384' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_RSA_PSK_WITH_NULL_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_NULL_SHA256' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_RSA_PSK_WITH_NULL_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_NULL_SHA384' + algorithm."; + reference + "RFC 5487: + Pre-Shared Key Cipher Suites for TLS with SHA-256/384 + and AES Galois Counter Mode"; + } + enum TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256' + algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256' algorithm."; + reference + "RFC 5932: + Camellia Cipher Suites for TLS"; + } + enum TLS_SM4_GCM_SM3 { + status deprecated; + description + "Enumeration for the 'TLS_SM4_GCM_SM3' algorithm."; + reference + "RFC 8998: + ShangMi (SM) Cipher Suites for TLS 1.3"; + } + enum TLS_SM4_CCM_SM3 { + status deprecated; + description + "Enumeration for the 'TLS_SM4_CCM_SM3' algorithm."; + reference + "RFC 8998: + ShangMi (SM) Cipher Suites for TLS 1.3"; + } + enum TLS_EMPTY_RENEGOTIATION_INFO_SCSV { + status deprecated; + description + "Enumeration for the 'TLS_EMPTY_RENEGOTIATION_INFO_SCSV' + algorithm."; + reference + "RFC 5746: + Transport Layer Security (TLS) Renegotiation Indication + Extension"; + } + enum TLS_AES_128_GCM_SHA256 { + description + "Enumeration for the 'TLS_AES_128_GCM_SHA256' algorithm."; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version + 1.3"; + } + enum TLS_AES_256_GCM_SHA384 { + description + "Enumeration for the 'TLS_AES_256_GCM_SHA384' algorithm."; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version + 1.3"; + } + enum TLS_CHACHA20_POLY1305_SHA256 { + description + "Enumeration for the 'TLS_CHACHA20_POLY1305_SHA256' + algorithm."; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version + 1.3"; + } + enum TLS_AES_128_CCM_SHA256 { + description + "Enumeration for the 'TLS_AES_128_CCM_SHA256' algorithm."; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version + 1.3"; + } + enum TLS_AES_128_CCM_8_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_AES_128_CCM_8_SHA256' + algorithm."; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3 + IESG Action: + IESG Action 2018-08-16"; + } + enum TLS_AEGIS_256_SHA512 { + status deprecated; + description + "Enumeration for the 'TLS_AEGIS_256_SHA512' algorithm."; + reference + "draft-irtf-cfrg-aegis-aead-08: + The AEGIS Family of Authenticated Encryption + Algorithms"; + } + enum TLS_AEGIS_128L_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_AEGIS_128L_SHA256' algorithm."; + reference + "draft-irtf-cfrg-aegis-aead-08: + The AEGIS Family of Authenticated Encryption + Algorithms"; + } + enum TLS_FALLBACK_SCSV { + status deprecated; + description + "Enumeration for the 'TLS_FALLBACK_SCSV' algorithm."; + reference + "RFC 7507: + TLS Fallback Signaling Cipher Suite Value (SCSV) for + Preventing Protocol Downgrade Attacks"; + } + enum TLS_ECDH_ECDSA_WITH_NULL_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_ECDSA_WITH_NULL_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDH_ECDSA_WITH_RC4_128_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_ECDSA_WITH_RC4_128_SHA' + algorithm."; + 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"; + } + enum TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDHE_ECDSA_WITH_NULL_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_ECDSA_WITH_NULL_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDHE_ECDSA_WITH_RC4_128_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_ECDSA_WITH_RC4_128_SHA' + algorithm."; + 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"; + } + enum TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA' algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDH_RSA_WITH_NULL_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_RSA_WITH_NULL_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDH_RSA_WITH_RC4_128_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_RSA_WITH_RC4_128_SHA' + algorithm."; + 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"; + } + enum TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDH_RSA_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_RSA_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDH_RSA_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_RSA_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDHE_RSA_WITH_NULL_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_RSA_WITH_NULL_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDHE_RSA_WITH_RC4_128_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_RSA_WITH_RC4_128_SHA' + algorithm."; + 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"; + } + enum TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDH_anon_WITH_NULL_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_anon_WITH_NULL_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDH_anon_WITH_RC4_128_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_anon_WITH_RC4_128_SHA' + algorithm."; + 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"; + } + enum TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDH_anon_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_anon_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_ECDH_anon_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_anon_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and + Earlier"; + } + enum TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 5054: + Using the Secure Remote Password (SRP) Protocol for TLS + Authentication"; + } + enum TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA' algorithm."; + reference + "RFC 5054: + Using the Secure Remote Password (SRP) Protocol for TLS + Authentication"; + } + enum TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the + 'TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA' algorithm."; + reference + "RFC 5054: + Using the Secure Remote Password (SRP) Protocol for TLS + Authentication"; + } + enum TLS_SRP_SHA_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_SRP_SHA_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 5054: + Using the Secure Remote Password (SRP) Protocol for TLS + Authentication"; + } + enum TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 5054: + Using the Secure Remote Password (SRP) Protocol for TLS + Authentication"; + } + enum TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 5054: + Using the Secure Remote Password (SRP) Protocol for TLS + Authentication"; + } + enum TLS_SRP_SHA_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_SRP_SHA_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 5054: + Using the Secure Remote Password (SRP) Protocol for TLS + Authentication"; + } + enum TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 5054: + Using the Secure Remote Password (SRP) Protocol for TLS + Authentication"; + } + enum TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 5054: + Using the Secure Remote Password (SRP) Protocol for TLS + Authentication"; + } + enum TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256' + algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384' + algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 { + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 { + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 { + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 { + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384' algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256' + algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384' + algorithm."; + reference + "RFC 5289: + TLS Elliptic Curve Cipher Suites with SHA-256/384 and + AES Galois Counter Mode (GCM)"; + } + enum TLS_ECDHE_PSK_WITH_RC4_128_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_PSK_WITH_RC4_128_SHA' + algorithm."; + reference + "RFC 5489: + ECDHE_PSK Cipher Suites for Transport Layer Security + (TLS) + RFC 6347: + Datagram Transport Layer Security Version 1.2"; + } + enum TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA' + algorithm."; + reference + "RFC 5489: + ECDHE_PSK Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA' + algorithm."; + reference + "RFC 5489: + ECDHE_PSK Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA' + algorithm."; + reference + "RFC 5489: + ECDHE_PSK Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256' algorithm."; + reference + "RFC 5489: + ECDHE_PSK Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384' algorithm."; + reference + "RFC 5489: + ECDHE_PSK Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_NULL_SHA { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_PSK_WITH_NULL_SHA' + algorithm."; + reference + "RFC 5489: + ECDHE_PSK Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_NULL_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_PSK_WITH_NULL_SHA256' + algorithm."; + reference + "RFC 5489: + ECDHE_PSK Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_NULL_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_PSK_WITH_NULL_SHA384' + algorithm."; + reference + "RFC 5489: + ECDHE_PSK Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_RSA_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_ARIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_RSA_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_ARIA_256_CBC_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_ARIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_ARIA_256_CBC_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_RSA_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_ARIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_RSA_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_ARIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_ARIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DH_anon_WITH_ARIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_PSK_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_ARIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_PSK_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_ARIA_256_CBC_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_PSK_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_ARIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_PSK_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_ARIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384' algorithm."; + reference + "RFC 6209: + Addition of the ARIA Cipher Suites to Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384' + algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256' + algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384' + algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256' + algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384' + algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384' algorithm."; + reference + "RFC 6367: + Addition of the Camellia Cipher Suites to Transport + Layer Security (TLS)"; + } + enum TLS_RSA_WITH_AES_128_CCM { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_AES_128_CCM' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_RSA_WITH_AES_256_CCM { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_AES_256_CCM' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_DHE_RSA_WITH_AES_128_CCM { + description + "Enumeration for the 'TLS_DHE_RSA_WITH_AES_128_CCM' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_DHE_RSA_WITH_AES_256_CCM { + description + "Enumeration for the 'TLS_DHE_RSA_WITH_AES_256_CCM' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_RSA_WITH_AES_128_CCM_8 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_AES_128_CCM_8' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_RSA_WITH_AES_256_CCM_8 { + status deprecated; + description + "Enumeration for the 'TLS_RSA_WITH_AES_256_CCM_8' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_DHE_RSA_WITH_AES_128_CCM_8 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_AES_128_CCM_8' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_DHE_RSA_WITH_AES_256_CCM_8 { + status deprecated; + description + "Enumeration for the 'TLS_DHE_RSA_WITH_AES_256_CCM_8' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_PSK_WITH_AES_128_CCM { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_AES_128_CCM' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_PSK_WITH_AES_256_CCM { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_AES_256_CCM' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_DHE_PSK_WITH_AES_128_CCM { + description + "Enumeration for the 'TLS_DHE_PSK_WITH_AES_128_CCM' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_DHE_PSK_WITH_AES_256_CCM { + description + "Enumeration for the 'TLS_DHE_PSK_WITH_AES_256_CCM' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_PSK_WITH_AES_128_CCM_8 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_AES_128_CCM_8' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_PSK_WITH_AES_256_CCM_8 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_WITH_AES_256_CCM_8' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_PSK_DHE_WITH_AES_128_CCM_8 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_DHE_WITH_AES_128_CCM_8' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_PSK_DHE_WITH_AES_256_CCM_8 { + status deprecated; + description + "Enumeration for the 'TLS_PSK_DHE_WITH_AES_256_CCM_8' + algorithm."; + reference + "RFC 6655: + AES-CCM Cipher Suites for Transport Layer Security + (TLS)"; + } + enum TLS_ECDHE_ECDSA_WITH_AES_128_CCM { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_ECDSA_WITH_AES_128_CCM' + algorithm."; + reference + "RFC 7251: + AES-CCM Elliptic Curve Cryptography (ECC) Cipher Suites + for TLS"; + } + enum TLS_ECDHE_ECDSA_WITH_AES_256_CCM { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_ECDSA_WITH_AES_256_CCM' + algorithm."; + reference + "RFC 7251: + AES-CCM Elliptic Curve Cryptography (ECC) Cipher Suites + for TLS"; + } + enum TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8' + algorithm."; + reference + "RFC 7251: + AES-CCM Elliptic Curve Cryptography (ECC) Cipher Suites + for TLS"; + } + enum TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 { + status deprecated; + description + "Enumeration for the 'TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8' + algorithm."; + reference + "RFC 7251: + AES-CCM Elliptic Curve Cryptography (ECC) Cipher Suites + for TLS"; + } + enum TLS_ECCPWD_WITH_AES_128_GCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_ECCPWD_WITH_AES_128_GCM_SHA256' + algorithm."; + reference + "RFC 8492: + Secure Password Ciphersuites for Transport Layer + Security (TLS)"; + } + enum TLS_ECCPWD_WITH_AES_256_GCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_ECCPWD_WITH_AES_256_GCM_SHA384' + algorithm."; + reference + "RFC 8492: + Secure Password Ciphersuites for Transport Layer + Security (TLS)"; + } + enum TLS_ECCPWD_WITH_AES_128_CCM_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_ECCPWD_WITH_AES_128_CCM_SHA256' + algorithm."; + reference + "RFC 8492: + Secure Password Ciphersuites for Transport Layer + Security (TLS)"; + } + enum TLS_ECCPWD_WITH_AES_256_CCM_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_ECCPWD_WITH_AES_256_CCM_SHA384' + algorithm."; + reference + "RFC 8492: + Secure Password Ciphersuites for Transport Layer + Security (TLS)"; + } + enum TLS_SHA256_SHA256 { + status deprecated; + description + "Enumeration for the 'TLS_SHA256_SHA256' algorithm."; + reference + "RFC 9150: + TLS 1.3 Authentication and Integrity-Only Cipher + Suites"; + } + enum TLS_SHA384_SHA384 { + status deprecated; + description + "Enumeration for the 'TLS_SHA384_SHA384' algorithm."; + reference + "RFC 9150: + TLS 1.3 Authentication and Integrity-Only Cipher + Suites"; + } + enum TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC { + status deprecated; + description + "Enumeration for the + 'TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC' + algorithm."; + reference + "RFC 9189: + GOST Cipher Suites for Transport Layer Security (TLS) + Protocol Version 1.2"; + } + enum TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC { + status deprecated; + description + "Enumeration for the + 'TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC' algorithm."; + reference + "RFC 9189: + GOST Cipher Suites for Transport Layer Security (TLS) + Protocol Version 1.2"; + } + enum TLS_GOSTR341112_256_WITH_28147_CNT_IMIT { + status deprecated; + description + "Enumeration for the + 'TLS_GOSTR341112_256_WITH_28147_CNT_IMIT' algorithm."; + reference + "RFC 9189: + GOST Cipher Suites for Transport Layer Security (TLS) + Protocol Version 1.2"; + } + enum TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L { + status deprecated; + description + "Enumeration for the + 'TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L' algorithm."; + reference + "RFC 9367: + GOST Cipher Suites for Transport Layer Security (TLS) + Protocol Version 1.3"; + } + enum TLS_GOSTR341112_256_WITH_MAGMA_MGM_L { + status deprecated; + description + "Enumeration for the 'TLS_GOSTR341112_256_WITH_MAGMA_MGM_L' + algorithm."; + reference + "RFC 9367: + GOST Cipher Suites for Transport Layer Security (TLS) + Protocol Version 1.3"; + } + enum TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S { + status deprecated; + description + "Enumeration for the + 'TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S' algorithm."; + reference + "RFC 9367: + GOST Cipher Suites for Transport Layer Security (TLS) + Protocol Version 1.3"; + } + enum TLS_GOSTR341112_256_WITH_MAGMA_MGM_S { + status deprecated; + description + "Enumeration for the 'TLS_GOSTR341112_256_WITH_MAGMA_MGM_S' + algorithm."; + reference + "RFC 9367: + GOST Cipher Suites for Transport Layer Security (TLS) + Protocol Version 1.3"; + } + enum TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 { + description + "Enumeration for the + 'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256' algorithm."; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 { + description + "Enumeration for the + 'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256' + algorithm."; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for Transport Layer + Security (TLS)"; + } + enum TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 { + description + "Enumeration for the + 'TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256' algorithm."; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for Transport Layer + Security (TLS)"; + } + enum TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_PSK_WITH_CHACHA20_POLY1305_SHA256' algorithm."; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 { + description + "Enumeration for the + 'TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256' algorithm."; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for Transport Layer + Security (TLS)"; + } + enum TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 { + description + "Enumeration for the + 'TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256' algorithm."; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for Transport Layer + Security (TLS)"; + } + enum TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256' algorithm."; + reference + "RFC 7905: + ChaCha20-Poly1305 Cipher Suites for Transport Layer + Security (TLS)"; + } + enum TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 { + description + "Enumeration for the + 'TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256' algorithm."; + reference + "RFC 8442: + ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites for TLS + 1.2 and DTLS 1.2"; + } + enum TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 { + description + "Enumeration for the + 'TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384' algorithm."; + reference + "RFC 8442: + ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites for TLS + 1.2 and DTLS 1.2"; + } + enum TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256 { + status deprecated; + description + "Enumeration for the + 'TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256' algorithm."; + reference + "RFC 8442: + ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites for TLS + 1.2 and DTLS 1.2"; + } + enum TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256 { + description + "Enumeration for the + 'TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256' algorithm."; + reference + "RFC 8442: + ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites for TLS + 1.2 and DTLS 1.2"; + } + } + description + "An enumeration for TLS cipher-suite algorithms."; + } + +} diff --git a/modules/ietf-crypto-types@2024-10-10.yang b/modules/ietf-crypto-types@2024-10-10.yang new file mode 100755 index 00000000..1b547da2 --- /dev/null +++ b/modules/ietf-crypto-types@2024-10-10.yang @@ -0,0 +1,1109 @@ +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. + + 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. + + Copyright (c) 2024 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 9640 + (https://www.rfc-editor.org/info/rfc9640); see the RFC + itself for full legal notices."; + + revision 2024-10-10 { + description + "Initial version."; + reference + "RFC 9640: 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 p10-csr-format { + description + "Indicates that the server 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 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 cleartext-passwords { + description + "Indicates that the server supports cleartext + passwords."; + } + + feature encrypted-passwords { + description + "Indicates that the server supports password + 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 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."; + } + + /*************************************************/ + /* 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 8017), encoded using ASN.1 + distinguished encoding rules (DER), as specified in + ITU-T X.690."; + reference + "RFC 8017: + 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), encoded using ASN.1 + distinguished encoding rules (DER), as specified in + ITU-T X.690."; + reference + "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 { + if-feature "one-asymmetric-key-format"; + base private-key-format; + description + "Indicates that the private key value is a + Cryptographic Message Syntax (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) 02/2021"; + } + + /***************************************************/ + /* Identities for Public Key Format Structures */ + /***************************************************/ + + identity ssh-public-key-format { + base public-key-format; + description + "Indicates that the public key value is a Secure Shell (SSH) + public key, as specified in 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) 02/2021"; + } + + /******************************************************/ + /* 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. + + 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; + 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) 02/2021"; + } + + /*************************************************/ + /* 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) 02/2021"; + } + + 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., Elliptic Curve Cryptography (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) 02/2021"; + } + + /*********************************************************/ + /* 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-format { + if-feature "p10-csr-format"; + 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) 02/2021"; + } + + 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) 02/2021"; + } + + /***************************************************/ + /* 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) 02/2021"; + } + + 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) 02/2021"; + } + + /***************************************************/ + /* 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) 02/2021"; + } + + 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) 02/2021"; + } + + /***********************************************/ + /* 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) 02/2021"; + } + + typedef data-content-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + data content type, as described in Section 4 of 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 in Section 5 of + 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 in Section 6 + of 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 in Section 7 + of 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 in Section 8 + of 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 in Section 9 + of 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 has 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 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 + 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 (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 + RFC 5652: + Cryptographic Message Syntax (CMS)"; + } + + 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 (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 + RFC 5652: + Cryptographic Message Syntax (CMS)"; + } + + /*****************/ + /* 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 (e.g., + 'choice'/'case' statements are allowed but not a + container)."; + } + 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 an + identity based on 'symmetrically-encrypted-value-format' + MUST be set (e.g., 'cms-encrypted-data-format'). + + If 'encrypted-by' points to an asymmetric key, then an + identity based on 'asymmetrically-encrypted-value-format' + MUST be 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 used for authenticating to a remote system. + + The 'ianach:crypt-hash' typedef from RFC 7317 should be + used instead when needing a password to authenticate a + local account."; + 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; + description + "The cleartext value of the password."; + } + } + case encrypted-password { + if-feature "encrypted-passwords"; + 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 decrypted key's + format (i.e., the 'encrypted-value-format' conveys the + encrypted key's format)."; + } + choice key-type { + nacm:default-deny-write; + mandatory true; + description + "Choice between key types."; + case cleartext-symmetric-key { + leaf cleartext-symmetric-key { + if-feature "cleartext-symmetric-keys"; + 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-symmetric-key { + if-feature "hidden-symmetric-keys"; + leaf hidden-symmetric-key { + type empty; + must 'not(../key-format)'; + description + "A hidden key is not exportable and not extractable; + therefore, it is of type 'empty' as its value is + inaccessible via management interfaces. Though hidden + to users, such keys are not hidden to the server and + may be referenced by configuration to indicate which + key a server should use for a cryptographic operation. + How such keys are created is outside the scope of this + module."; + } + } + case encrypted-symmetric-key { + if-feature "encrypted-symmetric-keys"; + container encrypted-symmetric-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 the 'public-key-format' field."; + } + } + + grouping private-key-grouping { + description + "A private key."; + 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 decrypted key's + format (i.e., the 'encrypted-value-format' conveys the + encrypted key's format)."; + } + choice private-key-type { + nacm:default-deny-write; + mandatory true; + description + "Choice between key types."; + case cleartext-private-key { + if-feature "cleartext-private-keys"; + 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-private-keys"; + leaf hidden-private-key { + type empty; + must 'not(../private-key-format)'; + description + "A hidden key. It is of type 'empty' as its value is + inaccessible via management interfaces. Though hidden + to users, such keys are not hidden to the server and + may be referenced by configuration to indicate which + key a server should use for a cryptographic operation. + How such keys are created is outside the scope of this + module."; + } + } + case encrypted-private-key { + if-feature "encrypted-private-keys"; + 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 asymmetric-key-pair-grouping { + description + "A private key and, optionally, its associated public key. + Implementations MUST ensure that the two keys, when both + are specified, are a matching pair."; + uses public-key-grouping { + refine "public-key-format" { + mandatory false; + } + refine "public-key" { + mandatory false; + } + } + uses private-key-grouping; + } + + grouping certificate-expiration-grouping { + description + "A notification for when a certificate is about to expire or + has already 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. + + If the certificate's issuer maintains a Certificate + Revocation List (CRL), the expiration notification MAY + be sent if the CRL is about to expire."; + 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 expire or has already expired."; + leaf cert-data { + nacm:default-deny-all; + 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 expire or has already expired. Implementations + SHOULD assert that, where used, the end-entity certificate + contains the expected public key."; + leaf cert-data { + nacm:default-deny-all; + 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'."; + input { + leaf csr-format { + type identityref { + base csr-format; + } + mandatory true; + description + "Specifies the format for the returned certificate."; + } + 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 9640: + 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 9640: + 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 MUST assert that the certificate contains + 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 a list of associated + certificates. Implementations MUST 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@2024-10-10.yang b/modules/ietf-keystore@2024-10-10.yang new file mode 100755 index 00000000..88900e46 --- /dev/null +++ b/modules/ietf-keystore@2024-10-10.yang @@ -0,0 +1,407 @@ +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 9640: 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. + + 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. + + Copyright (c) 2024 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 9642 + (https://www.rfc-editor.org/info/rfc9642); see the RFC + itself for full legal notices."; + + revision 2024-10-10 { + description + "Initial version"; + reference + "RFC 9642: A YANG Data Model for a Keystore"; + } + + /****************/ + /* Features */ + /****************/ + + feature central-keystore-supported { + description + "The 'central-keystore-supported' feature indicates that + the server supports the central keystore (i.e., fully + implements the 'ietf-keystore' module)."; + } + + feature inline-definitions-supported { + description + "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 + implements the /keystore/asymmetric-keys subtree."; + + } + + feature symmetric-keys { + description + "The 'symmetric-keys' feature indicates that the server + implements the /keystore/symmetric-keys subtree."; + } + + /****************/ + /* Typedefs */ + /****************/ + + typedef central-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 central keystore."; + } + + typedef central-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 central keystore."; + } + + /*****************/ + /* Groupings */ + /*****************/ + + grouping encrypted-by-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 9640, enabling references to keys + in the central keystore."; + choice encrypted-by { + nacm:default-deny-write; + mandatory true; + description + "A choice amongst other symmetric or asymmetric keys."; + case central-symmetric-key-ref { + if-feature "central-keystore-supported"; + if-feature "symmetric-keys"; + leaf symmetric-key-ref { + type ks:central-symmetric-key-ref; + description + "Identifies the symmetric key used to encrypt the + associated key."; + } + } + case central-asymmetric-key-ref { + if-feature "central-keystore-supported"; + if-feature "asymmetric-keys"; + leaf asymmetric-key-ref { + type ks:central-asymmetric-key-ref; + description + "Identifies the asymmetric key whose public key + encrypted the associated key."; + } + } + } + } + + // *-ref groupings + + grouping central-asymmetric-key-certificate-ref-grouping { + description + "A grouping for the reference to a certificate associated + with an asymmetric key stored in the central keystore."; + leaf asymmetric-key { + nacm:default-deny-write; + if-feature "central-keystore-supported"; + if-feature "asymmetric-keys"; + type ks:central-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."; + } + } + + // inline-or-keystore-* groupings + + grouping inline-or-keystore-symmetric-key-grouping { + description + "A grouping for the configuration of a symmetric key. The + symmetric key may be defined inline or as a reference to + a symmetric key stored in the central keystore. + + Servers that wish to define alternate keystore locations + SHOULD augment in custom 'case' statements enabling + references to those alternate keystore locations."; + 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 inline { + if-feature "inline-definitions-supported"; + container inline-definition { + description + "A container to hold the local key definition."; + uses ct:symmetric-key-grouping; + } + } + case central-keystore { + if-feature "central-keystore-supported"; + if-feature "symmetric-keys"; + leaf central-keystore-reference { + type ks:central-symmetric-key-ref; + description + "A reference to a symmetric key that exists in + the central keystore."; + } + } + } + } + + grouping inline-or-keystore-asymmetric-key-grouping { + description + "A grouping for the configuration of an asymmetric key. The + asymmetric key may be defined inline or as a reference to + an asymmetric key stored in the central keystore. + + Servers that wish to define alternate keystore locations + SHOULD augment in custom 'case' statements enabling + references to those alternate keystore locations."; + 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 inline { + if-feature "inline-definitions-supported"; + container inline-definition { + description + "A container to hold the local key definition."; + uses ct:asymmetric-key-pair-grouping; + } + } + case central-keystore { + if-feature "central-keystore-supported"; + if-feature "asymmetric-keys"; + leaf central-keystore-reference { + type ks:central-asymmetric-key-ref; + description + "A reference to an asymmetric key that exists in + the central keystore. The intent is to reference + just the asymmetric key without any regard for + any certificates that may be associated with it."; + } + } + } + } + + grouping inline-or-keystore-asymmetric-key-with-certs-grouping { + description + "A grouping for the configuration of an asymmetric key and + its associated certificates. The asymmetric key and its + associated certificates may be defined inline or as a + reference to an asymmetric key (and its associated + certificates) in the central keystore. + + Servers that wish to define alternate keystore locations + SHOULD augment in custom 'case' statements enabling + references to those alternate keystore locations."; + 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 inline { + if-feature "inline-definitions-supported"; + container inline-definition { + description + "A container to hold the local key definition."; + uses ct:asymmetric-key-pair-with-certs-grouping; + } + } + case central-keystore { + if-feature "central-keystore-supported"; + if-feature "asymmetric-keys"; + leaf central-keystore-reference { + type ks:central-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 inline-or-keystore-end-entity-cert-with-key-grouping { + description + "A grouping for the configuration of an asymmetric key and + its associated end-entity certificate. The asymmetric key + and its associated end-entity certificate may be defined + inline or as a reference to an asymmetric key (and its + associated end-entity certificate) in the central keystore. + + Servers that wish to define alternate keystore locations + SHOULD augment in custom 'case' statements enabling + references to those alternate keystore locations."; + 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 inline { + if-feature "inline-definitions-supported"; + container inline-definition { + description + "A container to hold the local key definition."; + uses ct:asymmetric-key-pair-with-cert-grouping; + } + } + case central-keystore { + if-feature "central-keystore-supported"; + if-feature "asymmetric-keys"; + container central-keystore-reference { + uses central-asymmetric-key-certificate-ref-grouping; + description + "A reference to a specific certificate associated with + an asymmetric key stored in the central keystore."; + } + } + } + } + + // the keystore grouping + + grouping keystore-grouping { + description + "A grouping definition enables use in other contexts. If ever + done, implementations MUST augment new 'case' statements + into the various inline-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-" + + "symmetric-key/encrypted-symmetric-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-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-grouping; + } + } + } +} diff --git a/modules/ietf-netconf-server@2025-04-24.yang b/modules/ietf-netconf-server@2025-04-24.yang new file mode 100644 index 00000000..925f9f2f --- /dev/null +++ b/modules/ietf-netconf-server@2025-04-24.yang @@ -0,0 +1,683 @@ +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; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + import ietf-ssh-server { + prefix sshs; + reference + "RFC EEEE: YANG Groupings for SSH Clients and SSH Servers"; + } + + import ietf-tls-server { + prefix tlss; + 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 "; + + description + "This module contains a collection of YANG definitions + for configuring NETCONF servers. + + Copyright (c) 2025 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 2025-04-24 { + description + "Initial version"; + reference + "RFC HHHH: A YANG Data Model for NETCONF Clients and Server"; + } + + // 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 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 grouping for configuring a NETCONF server + 'listen' protocol stack for listening on a single port."; + choice transport { + mandatory true; + description + "Selects between available transports."; + case ssh { + if-feature "ssh-listen"; + container ssh { + description + "TCP, SSH, and NETCONF configuration to listen + for NETCONF over SSH connections."; + container tcp-server-parameters { + description + "TCP-level server parameters to listen + for NETCONF over SSH connections."; + uses tcps:tcp-server-grouping { + refine "local-bind/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 + "SSH-level server parameters to listen + for NETCONF over SSH connections."; + uses sshs:ssh-server-grouping; + } + container netconf-server-parameters { + description + "NETCONF-level server parameters to listen + for NETCONF over SSH connections."; + uses ncs:netconf-server-grouping { + refine "client-identity-mappings" { + if-feature "sshcmn:ssh-x509-certs"; + description + "Adds 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 + "TCP, TLS, and NETCONF configuration to listen + for NETCONF over TLS connections."; + container tcp-server-parameters { + description + "TCP-level server parameters to listen + for NETCONF over TLS connections."; + uses tcps:tcp-server-grouping { + refine "local-bind/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 + "TLS-level server parameters to listen + for NETCONF over TLS connections."; + 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 + "NETCONF-level server parameters to listen + for NETCONF over TLS connections."; + 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 grouping for configuring a NETCONF server + 'call-home' protocol stack, for a single outbound + connection."; + choice transport { + mandatory true; + description + "Selects between available transports."; + case ssh { + if-feature "ssh-call-home"; + container ssh { + description + "TCP, SSH, and NETCONF configuration to initiate + a NETCONF over SSH Call Home connection."; + container tcp-client-parameters { + description + "TCP-level client parameters to initiate a + NETCONF over SSH Call Home connection."; + 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-ssh' (4334) if no value is + specified."; + } + } + } + container ssh-server-parameters { + description + "SSH-level server parameters to initiate a + NETCONF over SSH Call Home connection."; + uses sshs:ssh-server-grouping; + } + container netconf-server-parameters { + description + "NETCONF-level server parameters to initiate a + NETCONF over SSH Call Home connection."; + uses ncs:netconf-server-grouping { + refine "client-identity-mappings" { + if-feature "sshcmn:ssh-x509-certs"; + description + "Adds 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 + "TCP, TLS, and NETCONF configuration to initiate + a NETCONF over TLS Call Home connection."; + container tcp-client-parameters { + description + "TCP-level client parameters to initiate a + NETCONF over TLS Call Home connection."; + 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 + "TLS-level server parameters to initiate a + NETCONF over TLS Call Home connection."; + 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 + "NETCONF-level server parameters to initiate a + NETCONF over TLS Call Home connection."; + 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 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 "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."; + } + container endpoints { + description + "Container for a list of endpoints."; + 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 decreases resource + utilization, albeit with increased delay in + NETCONF client to NETCONF server 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. + + 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 + 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 '[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. + + 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 "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."; + } + } + } // 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 known. If + no previous connection is known, then the + first endpoint configured is used."; + } + 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@2024-10-10.yang b/modules/ietf-ssh-common@2024-10-10.yang new file mode 100755 index 00000000..d1346808 --- /dev/null +++ b/modules/ietf-ssh-common@2024-10-10.yang @@ -0,0 +1,469 @@ +module ietf-ssh-common { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-ssh-common"; + prefix sshcmn; + + import ietf-crypto-types { + prefix ct; + reference + "RFC 9640: YANG Data Types and Groupings for Cryptography"; + } + + import ietf-keystore { + prefix ks; + reference + "RFC 9642: A YANG Data Model for a Keystore"; + } + + import iana-ssh-encryption-algs { + prefix sshea; + reference + "RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + import iana-ssh-key-exchange-algs { + prefix sshkea; + reference + "RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + import iana-ssh-mac-algs { + prefix sshma; + reference + "RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + import iana-ssh-public-key-algs { + prefix sshpka; + reference + "RFC 9644: 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 common features and groupings for + Secure Shell (SSH). + + 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. + + Copyright (c) 2024 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 9644 + (https://www.rfc-editor.org/info/rfc9644); see the RFC + itself for full legal notices."; + + revision 2024-10-10 { + description + "Initial version."; + reference + "RFC 9644: 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 asymmetric-key-pair-generation { + description + "Indicates that the server implements the + 'generate-asymmetric-key-pair' RPC."; + } + + feature algorithm-discovery { + description + "Indicates that the server implements the + 'supported-algorithms' container."; + } + + // Typedefs + + typedef ssh-public-key-algorithm { + type union { + type sshpka:ssh-public-key-algorithm; + type string { + length "1..64" { + description + "Non-IANA-maintained algorithms must include the + at sign (@) in them, per Section 4.6.1 of RFC + 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned + Numbers"; + } + pattern '.*@.*' { + description + "Non-IANA-maintained algorithms must include the + at sign (@) in them, per Section 4.6.1 of RFC + 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned + Numbers"; + } + } + } + description + "A type that enables the public key algorithm to be + either an IANA-maintained public key algorithm in + the 'iana-ssh-public-key-algs' YANG module (RFC 9644) + or a locally defined algorithm, per Section 4.6.1 + of RFC 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned Numbers + RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + typedef ssh-key-exchange-algorithm { + type union { + type sshkea:ssh-key-exchange-algorithm; + type string { + length "1..64" { + description + "Non-IANA-maintained algorithms must include the + at sign (@) in them, per Section 4.6.1 of RFC 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned + Numbers"; + } + pattern '.*@.*' { + description + "Non-IANA-maintained algorithms must include the + at sign (@) in them, per Section 4.6.1 of RFC 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned + Numbers"; + } + } + } + description + "A type that enables the key exchange algorithm to be + either an IANA-maintained key exchange algorithm in + the 'iana-ssh-key-exchange-algs' YANG module (RFC 9644) + or a locally defined algorithm, per Section 4.6.1 + of RFC 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned Numbers + RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + typedef ssh-encryption-algorithm { + type union { + type sshea:ssh-encryption-algorithm; + type string { + length "1..64" { + description + "Non-IANA-maintained algorithms must include the + at sign (@) in them, per Section 4.6.1 of RFC + 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned + Numbers"; + } + pattern '.*@.*' { + description + "Non-IANA-maintained algorithms must include the + at sign (@) in them, per Section 4.6.1 of RFC + 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned + Numbers"; + } + } + } + description + "A type that enables the encryption algorithm to be + either an IANA-maintained encryption algorithm in + the 'iana-ssh-encryption-algs' YANG module (RFC 9644) + or a locally defined algorithm, per Section 4.6.1 + of RFC 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned Numbers + RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + typedef ssh-mac-algorithm { + type union { + type sshma:ssh-mac-algorithm; + type string { + length "1..64" { + description + "Non-IANA-maintained algorithms must include the + at sign (@) in them, per Section 4.6.1 of RFC + 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned + Numbers"; + } + pattern '.*@.*' { + description + "Non-IANA-maintained algorithms must include the + at sign (@) in them, per Section 4.6.1 of RFC + 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned + Numbers"; + } + } + } + description + "A type that enables the message authentication code (MAC) + algorithm to be either an IANA-maintained MAC algorithm + in the 'iana-ssh-mac-algs' YANG module (RFC 9644) + or a locally defined algorithm, per Section 4.6.1 + of RFC 4250."; + reference + "RFC 4250: The Secure Shell (SSH) Protocol Assigned Numbers + RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + // 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 ssh-public-key-algorithm; + ordered-by user; + description + "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-defined."; + reference + "RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + } + container key-exchange { + description + "Parameters regarding key exchange."; + leaf-list key-exchange-alg { + type ssh-key-exchange-algorithm; + ordered-by user; + description + "Acceptable key exchange algorithms in order of decreasing + 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 ssh-encryption-algorithm; + ordered-by user; + description + "Acceptable encryption algorithms in order of decreasing + 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 ssh-mac-algorithm; + ordered-by user; + description + "Acceptable MAC algorithms in order of decreasing + preference. + + If this leaf-list is not configured (has zero + elements), the acceptable MAC algorithms are + implementation-defined."; + } + } + } + + // Protocol-accessible Nodes + + container supported-algorithms { + if-feature "algorithm-discovery"; + config false; + description + "Identifies all of the supported algorithms."; + container public-key-algorithms { + description + "A container for a list of public key algorithms + supported by the server."; + leaf-list supported-algorithm { + type ssh-public-key-algorithm; + description + "A public key algorithm supported by the server."; + } + } + container encryption-algorithms { + description + "A container for a list of encryption algorithms + supported by the server."; + leaf-list supported-algorithm { + type ssh-encryption-algorithm; + description + "An encryption algorithm supported by the server."; + } + } + container key-exchange-algorithms { + config false; + description + "A container for a list of key exchange algorithms + supported by the server."; + leaf-list supported-algorithm { + type ssh-key-exchange-algorithm; + description + "A key exchange algorithm supported by the server."; + } + } + container mac-algorithms { + config false; + description + "A container for a list of MAC algorithms + supported by the server."; + leaf-list supported-algorithm { + type ssh-mac-algorithm; + description + "A MAC algorithm supported by the server."; + } + } + } + + rpc generate-asymmetric-key-pair { + if-feature "asymmetric-key-pair-generation"; + description + "Requests the device to generate a public key using + the specified key algorithm."; + input { + leaf algorithm { + type ssh-public-key-algorithm; + mandatory true; + description + "The algorithm to be used when generating the key."; + } + leaf num-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-5. For Elliptic Curve + Digital Signature Algorithm (ECDSA) keys, the + 'num-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 + thus, the 'num-bits' value is not specified."; + reference + "FIPS 186-5: Digital Signature Standard (DSS)"; + } + container private-key-encoding { + description + "Indicates how the private key is to be encoded."; + choice private-key-encoding { + mandatory true; + description + "A choice amongst optional private key handling."; + case cleartext { + if-feature "ct:cleartext-private-keys"; + leaf cleartext { + type empty; + description + "Indicates that the private key is to be returned + as a cleartext value."; + } + } + case encrypted { + if-feature "ct:encrypted-private-keys"; + container encrypted { + description + "Indicates that the private key is to be encrypted + using the specified symmetric or asymmetric key."; + uses ks:encrypted-by-grouping; + } + } + case hidden { + if-feature "ct:hidden-private-keys"; + leaf hidden { + 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 9642 for information about hidden + keys. + + It is expected that the server will instantiate + the hidden key in the same location where built-in + keys are located. Rather than returning the key, + just the key's location is returned in the output."; + } + } + } + } + } + output { + choice key-or-hidden { + case key { + uses ct:asymmetric-key-pair-grouping; + } + case hidden { + leaf location { + type instance-identifier; + description + "The location to where a hidden key was created."; + } + } + description + "The output can be either a key (for cleartext and + encrypted keys) or the location to where the key + was created (for hidden keys)."; + } + } + } // end generate-asymmetric-key-pair + +} diff --git a/modules/ietf-ssh-server@2024-10-10.yang b/modules/ietf-ssh-server@2024-10-10.yang new file mode 100755 index 00000000..cd7dda0c --- /dev/null +++ b/modules/ietf-ssh-server@2024-10-10.yang @@ -0,0 +1,444 @@ +module ietf-ssh-server { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-ssh-server"; + prefix sshs; + + import ietf-yang-types { + prefix yang; + reference + "RFC 6991: Common YANG Data Types"; + } + + 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 9640: YANG Data Types and Groupings for Cryptography"; + } + + import ietf-truststore { + prefix ts; + reference + "RFC 9641: A YANG Data Model for a Truststore"; + } + + import ietf-keystore { + prefix ks; + reference + "RFC 9642: A YANG Data Model for a Keystore"; + } + + import ietf-ssh-common { + prefix sshcmn; + reference + "RFC 9644: 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 "; + + description + "This module defines a reusable grouping for SSH servers that + can be used as a basis for specific SSH server instances. + + 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. + + Copyright (c) 2024 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 9644 + (https://www.rfc-editor.org/info/rfc9644); see the RFC + itself for full legal notices."; + + revision 2024-10-10 { + description + "Initial version."; + reference + "RFC 9644: YANG Groupings for SSH Clients and SSH Servers"; + } + + // Features + + feature ssh-server-keepalives { + description + "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 allow 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 an 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 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 + '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 an SSH connection."; + list host-key { + key "name"; + min-elements 1; + ordered-by user; + description + "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 4251: The Secure Shell (SSH) Protocol Architecture + 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 9642: A YANG Data Model for a Keystore"; + uses ks:inline-or-keystore-asymmetric-key-grouping { + refine "inline-or-keystore/inline/inline-definition" { + must 'not(public-key-format) or derived-from-or-self' + + '(public-key-format, "ct:ssh-public-key-format")'; + + } + refine "inline-or-keystore/central-keystore/" + + "central-keystore-reference" { + must 'not(deref(.)/../ks:public-key-format) or ' + + 'derived-from-or-self(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 9642: A YANG Data Model for a Keystore"; + uses + ks:inline-or-keystore-end-entity-cert-with-key-grouping{ + refine "inline-or-keystore/inline/inline-definition" { + must 'not(public-key-format) or derived-from-or-self' + + '(public-key-format, "ct:subject-public-key-' + + 'info-format")'; + } + refine "inline-or-keystore/central-keystore/" + + "central-keystore-reference/asymmetric-key" { + must 'not(deref(.)/../ks:public-key-format) or ' + + 'derived-from-or-self(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 be configured to + authenticate SSH clients. See RFC 4252 for a general + discussion about SSH authentication."; + reference + "RFC 4252: The Secure Shell (SSH) Authentication Protocol"; + 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 of 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 'username' 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"; + 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 9641: A YANG Data Model for a Truststore"; + 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 "inline-or-truststore/central-truststore/" + + "central-truststore-reference" { + must 'not(deref(.)/../ts:public-key/ts:public-key-' + + 'format[not(derived-from-or-self(., "ct:ssh-' + + 'public-key-format"))])'; + } + } + } + container password { + description + "A password the SSH server may use to authenticate + this user. A user is authenticated if the hash + of the supplied password matches this value."; + leaf hashed-password { + if-feature "local-user-auth-password"; + type ianach:crypt-hash; + description + "The password for this user."; + } + leaf last-modified { + type yang:date-and-time; + config false; + description + "Identifies when the password was last set."; + } + } + container hostbased { + if-feature "local-user-auth-hostbased"; + presence + "Indicates that host-based (RFC 4252) 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 4252: The Secure Shell (SSH) Authentication + Protocol + RFC 9641: A YANG Data Model for a Truststore"; + 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 "inline-or-truststore/central-truststore/" + + "central-truststore-reference" { + must 'not(deref(.)/../ts:public-key/ts:public-key-' + + 'format[not(derived-from-or-self(., "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"; + } + } + } // users + 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 Certification 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 9641: A YANG Data Model for a Truststore"; + uses ts:inline-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 9641: A YANG Data Model for a Truststore"; + uses ts:inline-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 keepalive policy to proactively test + 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 + message with a purposely nonexistent 'request name' + value (e.g., keepalive@example.com) 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 + an SSH-level message will be sent to test the + aliveness of the SSH client if no data has been + received from the SSH client."; + } + leaf max-attempts { + type uint8; + default "3"; + description + "Sets the maximum number of sequential keepalive + messages that can fail to obtain a response from + the SSH client before assuming the SSH client is + no longer alive."; + } + } + } // grouping ssh-server-grouping + +} diff --git a/modules/ietf-tcp-client@2024-10-10.yang b/modules/ietf-tcp-client@2024-10-10.yang new file mode 100755 index 00000000..2648c93f --- /dev/null +++ b/modules/ietf-tcp-client@2024-10-10.yang @@ -0,0 +1,342 @@ +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 9640: YANG Data Types and Groupings for Cryptography"; + } + + import ietf-tcp-common { + prefix tcpcmn; + reference + "RFC 9643: 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. + + 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. + + Copyright (c) 2024 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 9643 + (https://www.rfc-editor.org/info/rfc9643); see the RFC + itself for full legal notices."; + + revision 2024-10-10 { + description + "Initial version."; + reference + "RFC 9643: 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 + "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 + "Indicates the TCP client supports connecting through + TCP proxies."; + } + + feature socks4-supported { + if-feature "proxy-connect"; + description + "Indicates the TCP client supports Socks4-based proxies."; + reference + "SOCKS Proceedings: 1992 Usenix Security Symposium"; + } + + feature socks4a-supported { + if-feature "proxy-connect"; + description + "Indicates the TCP client supports Socks4a-based proxies."; + reference + "OpenSSH message: + SOCKS 4A: A Simple Extension to SOCKS 4 Protocol + "; + } + + feature socks5-supported { + if-feature "proxy-connect"; + description + "Indicates the TCP client supports Socks5-based proxies."; + reference + "RFC 1928: SOCKS Protocol Version 5"; + } + + feature socks5-gss-api { + if-feature "socks5-supported"; + description + "Indicates that the server, when acting as a TCP client, + supports authenticating to a SOCKS Version 5 proxy server + using GSS-API credentials."; + reference + "RFC 1928: SOCKS Protocol Version 5"; + } + + feature socks5-username-password { + if-feature "socks5-supported"; + description + "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"; + } + + // 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; + description + "The port number of the remote TCP server."; + } + leaf local-address { + if-feature "local-binding-supported"; + type inet:ip-address; + description + "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, which the server + can bind to any IPv4 or IPv6 address."; + } + 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 { + if-feature "socks4-supported"; + 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 { + if-feature "socks4a-supported"; + 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 + "; + } + } + case socks5 { + if-feature "socks5-supported"; + 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: + ."; + 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 { + refine "keepalives" { + if-feature "tcp-client-keepalives"; + description + "An 'if-feature' statement so that implementations + can choose to support TCP client keepalives."; + } + } + } +} diff --git a/modules/ietf-tcp-common@2024-10-10.yang b/modules/ietf-tcp-common@2024-10-10.yang new file mode 100755 index 00000000..e37d6208 --- /dev/null +++ b/modules/ietf-tcp-common@2024-10-10.yang @@ -0,0 +1,119 @@ +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 define a reusable 'grouping' that is common + to both TCP clients and TCP servers. This grouping statement + is used by both the 'ietf-tcp-client' and 'ietf-tcp-server' + modules. + + 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. + + Copyright (c) 2024 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 9643 + (https://www.rfc-editor.org/info/rfc9643); see the RFC + itself for full legal notices."; + + revision 2024-10-10 { + description + "Initial version."; + reference + "RFC 9643: 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, aligning to + the requirement in Section 3.8.4 of RFC 9293 that + states keepalives are off by default."; + description + "Configures the keepalive 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. Further guidance can be found + in Section 2.1.5 of RFC 9643."; + reference + "RFC 9293: Transmission Control Protocol (TCP)"; + leaf idle-time { + type uint16 { + range "1..max"; + } + units "seconds"; + default "7200"; + description + "Sets the amount of time after which a TCP-level probe + message will be sent to test the aliveness of the TCP + peer if no data has been received from the TCP peer. + Two hours (7200 seconds) is a safe value, per Section + 3.8.4 of RFC 9293."; + reference + "RFC 9293: Transmission Control Protocol (TCP)"; + } + leaf max-probes { + type uint16 { + range "1..max"; + } + default "9"; + description + "Sets the maximum number of sequential keepalive 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"; + default "75"; + 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@2024-10-10.yang b/modules/ietf-tcp-server@2024-10-10.yang new file mode 100755 index 00000000..f2c0b7f6 --- /dev/null +++ b/modules/ietf-tcp-server@2024-10-10.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 9643: 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) 2024 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 9643 + (https://www.rfc-editor.org/info/rfc9643); see the RFC + itself for full legal notices."; + + revision 2024-10-10 { + description + "Initial version."; + reference + "RFC 9643: YANG Groupings for TCP Clients and TCP Servers"; + } + + // Features + + feature tcp-server-keepalives { + description + "TCP keepalive parameters are configurable for + TCP servers on the server implementing this feature."; + reference + "RFC 9293: Transmission Control Protocol (TCP)"; + } + + // 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."; + list local-bind { + key "local-address"; + min-elements 1; + description + "A list of bind (listen) points for this server + instance. A server instance may have multiple + bind points to support, e.g., the same port in + different address families or different ports + in the same address family."; + leaf local-address { + type inet:ip-address; + description + "The local IP address to listen on for incoming + TCP client connections. To configure listening + on all IPv4 addresses, the value must be '0.0.0.0' + (INADDR_ANY). To configure listening on all IPv6 + addresses, the value must be '::' (INADDR6_ANY)."; + } + leaf local-port { + type inet:port-number; + description + "The local port number to listen on for incoming TCP + client connections."; + } + } + uses tcpcmn:tcp-common-grouping { + refine "keepalives" { + if-feature "tcp-server-keepalives"; + description + "An 'if-feature' statement so that implementations + can choose to support TCP server keepalives."; + } + } + } +} diff --git a/modules/ietf-tls-common@2024-10-10.yang b/modules/ietf-tls-common@2024-10-10.yang new file mode 100755 index 00000000..a4d5ef3d --- /dev/null +++ b/modules/ietf-tls-common@2024-10-10.yang @@ -0,0 +1,314 @@ +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 9645: YANG Groupings for TLS Clients and TLS Servers"; + } + + import ietf-crypto-types { + prefix ct; + reference + "RFC 9640: YANG Data Types and Groupings for Cryptography"; + } + + import ietf-keystore { + prefix ks; + reference + "RFC 9642: 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 common features and groupings for + Transport Layer Security (TLS). + + 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. + + Copyright (c) 2024 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 9645 + (https://www.rfc-editor.org/info/rfc9645); see the RFC + itself for full legal notices."; + + revision 2024-10-10 { + description + "Initial version."; + reference + "RFC 9645: YANG Groupings for TLS Clients and TLS Servers"; + } + + // Features + + feature tls12 { + 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 algorithm-discovery { + description + "Indicates that the server implements the + 'supported-algorithms' container."; + } + + feature asymmetric-key-pair-generation { + description + "Indicates that the server implements the + 'generate-asymmetric-key-pair' RPC."; + } + + // Identities + + identity tls-version-base { + description + "Base identity used to identify TLS protocol versions."; + } + + identity tls12 { + if-feature "tls12"; + base tls-version-base; + 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"; + } + + // Typedefs + + 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"; + } + + // 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 limiting which TLS versions, amongst + those enabled by 'features', are presented during + the TLS handshake."; + leaf min { + type identityref { + base tls-version-base; + } + description + "If not specified, then there is no configured + minimum version."; + } + leaf max { + type identityref { + base tls-version-base; + } + description + "If not specified, then there is no configured + maximum version."; + } + } + container cipher-suites { + description + "Parameters regarding cipher suites."; + leaf-list cipher-suite { + type tlscsa:tls-cipher-suite-algorithm; + 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 9645 for + valid combinations. + + If this leaf-list is not configured (has zero elements), + the acceptable cipher suites are implementation- + defined."; + reference + "RFC 9645: YANG Groupings for TLS Clients and TLS Servers"; + } + } + } // hello-params-grouping + + // Protocol-accessible Nodes + + container supported-algorithms { + if-feature "algorithm-discovery"; + config false; + description + "A container for a list of cipher suite algorithms supported + by the server."; + leaf-list supported-algorithm { + type tlscsa:tls-cipher-suite-algorithm; + description + "A cipher suite algorithm supported by the server."; + } + } + + rpc generate-asymmetric-key-pair { + if-feature "asymmetric-key-pair-generation"; + description + "Requests the device to generate an 'asymmetric-key-pair' + key using the specified key algorithm."; + input { + leaf algorithm { + type tlscsa:tls-cipher-suite-algorithm; + mandatory true; + description + "The cipher suite algorithm that the generated key + works with. Implementations derive the public key + algorithm from the cipher suite algorithm. For + example, cipher suite + 'tls-rsa-with-aes-256-cbc-sha256' maps to the RSA + public key."; + } + leaf num-bits { + type uint16; + description + "Specifies the number of bits to create in the key. + 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 'num-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 + thus the 'num-bits' value is not specified."; + } + container private-key-encoding { + description + "Indicates how the private key is to be encoded."; + choice private-key-encoding { + mandatory true; + description + "A choice amongst optional private key handling."; + case cleartext { + if-feature "ct:cleartext-private-keys"; + leaf cleartext { + type empty; + description + "Indicates that the private key is to be returned + as a cleartext value."; + } + } + case encrypted { + if-feature "ct:encrypted-private-keys"; + container encrypted { + description + "Indicates that the key is to be encrypted using + the specified symmetric or asymmetric key."; + uses ks:encrypted-by-grouping; + } + } + case hidden { + if-feature "ct:hidden-private-keys"; + leaf hidden { + 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 Section 3 of RFC 9642 ('Support + for Built-In Keys') for information about hidden + keys."; + } + } + } + } + } + output { + choice key-or-hidden { + case key { + uses ct:asymmetric-key-pair-grouping; + } + case hidden { + leaf location { + type instance-identifier; + description + "The location to where a hidden key was created."; + } + } + description + "The output can be either a key (for cleartext and + encrypted keys) or the location to where the key + was created (for hidden keys)."; + } + } + } // end generate-asymmetric-key-pair + +} diff --git a/modules/ietf-tls-server@2024-10-10.yang b/modules/ietf-tls-server@2024-10-10.yang new file mode 100755 index 00000000..ba503476 --- /dev/null +++ b/modules/ietf-tls-server@2024-10-10.yang @@ -0,0 +1,519 @@ +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 9640: YANG Data Types and Groupings for Cryptography"; + } + import ietf-truststore { + prefix ts; + reference + "RFC 9641: A YANG Data Model for a Truststore"; + } + import ietf-keystore { + prefix ks; + reference + "RFC 9642: A YANG Data Model for a Keystore"; + } + import ietf-tls-common { + prefix tlscmn; + reference + "RFC 9645: 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 "; + description + "This module defines reusable groupings for TLS servers that + can be used as a basis for specific TLS server instances. + + 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. + + Copyright (c) 2024 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 9645 + (https://www.rfc-editor.org/info/rfc9645); see the RFC + itself for full legal notices."; + + revision 2024-10-10 { + description + "Initial version."; + reference + "RFC 9645: 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 { + if-feature "tlscmn:tls12"; + 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 { + if-feature "tlscmn:tls13"; + 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 (EE) certificate, + including any configured intermediate certificates, that + the TLS server will present when establishing a TLS + connection in its Certificate message, as defined in + Section 7.4.2 of RFC 5246 and Section 4.4.2 of 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 9642: 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:inline-or-keystore-end-entity-cert-with-key-" + + "grouping" { + refine "inline-or-keystore/inline/inline-definition" { + must 'not(public-key-format) or derived-from-or-self' + + '(public-key-format,' + + ' "ct:subject-public-' + + 'key-info-format")'; + } + refine "inline-or-keystore/central-keystore/" + + "central-keystore-reference/asymmetric-key" { + must 'not(deref(.)/../ks:public-key-format) or ' + + 'derived-from-or-self(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:inline-or-keystore-asymmetric-key-grouping { + refine "inline-or-keystore/inline/inline-definition" { + must 'not(public-key-format) or derived-from-or-self' + + '(public-key-format,' + + ' "ct:subject-public-' + + 'key-info-format")'; + } + refine "inline-or-keystore/central-keystore/" + + "central-keystore-reference" { + must 'not(deref(.)/../ks:public-key-format) or ' + + 'derived-from-or-self(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:inline-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). EPSKs 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 in Section 4.2.11 of + RFC 8446, the recommendations from Section 6 of + RFC 9257, and the EPSK input fields detailed in + Section 5.1 of RFC 9258. The base-key is based + upon 'ks:inline-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 + RFC 9257: Guidance for External Pre-Shared Key + (PSK) Usage in TLS + RFC 9258: Importing External Pre-Shared Keys + (PSKs) for TLS 1.3"; + uses ks:inline-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 RFC 9257, 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 + RFC 9257: Guidance for External Pre-Shared Key + (PSK) Usage in TLS"; + } + leaf hash { + type tlscmn:epsk-supported-hash; + default "sha-256"; + description + "As per Section 4.2.11 of RFC 8446, for EPSKs, + the hash algorithm MUST be set when the PSK is + established; otherwise, 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 5.1 of RFC 9258, context MUST + include the context used to determine the EPSK, + if any exists. For example, context may include + information about peer roles or identities + to mitigate Selfie-style reflection attacks. + Since the EPSK is a key derived from an external + protocol or sequence of protocols, context MUST + include a channel binding for the deriving + protocols (see RFC 5056). The details of this + binding are protocol specific and out of scope + for this document."; + reference + "RFC 9258: Importing External Pre-Shared Keys + (PSKs) for TLS 1.3"; + } + leaf target-protocol { + type uint16; + description + "As per Section 3.1 of RFC 9258, the protocol + for which a PSK is imported for use."; + reference + "RFC 9258: Importing External Pre-Shared Keys + (PSKs) for TLS 1.3"; + } + leaf target-kdf { + type uint16; + description + "As per Section 3 of RFC 9258, the KDF for + which a PSK is imported for use."; + reference + "RFC 9258: Importing External Pre-Shared Keys + (PSKs) for TLS 1.3"; + } + } + } + } + } // 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 that 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 authentication + based on PSK (pre-shared or pairwise symmetric key) as the + 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 Certification Authority (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 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 9641: A YANG Data Model for a Truststore"; + uses ts:inline-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., EE 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 9641: A YANG Data Model for a Truststore"; + uses ts:inline-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 9641: A YANG Data Model for a Truststore"; + 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 "inline-or-truststore/central-truststore/" + + "central-truststore-reference" { + must 'not(deref(.)/../ts:public-key/ts:public-key-' + + 'format[not(derived-from-or-self(., "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 keepalive 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 a + TLS-level message will be sent to test the + aliveness of the TLS client if no data has been + received from the TLS client."; + } + leaf max-attempts { + type uint8; + default "3"; + description + "Sets the maximum number of sequential keepalive + 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@2024-10-10.yang b/modules/ietf-truststore@2024-10-10.yang new file mode 100755 index 00000000..e4eeed2a --- /dev/null +++ b/modules/ietf-truststore@2024-10-10.yang @@ -0,0 +1,390 @@ +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 9640: 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. + + 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. + + Copyright (c) 2024 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 9641 + (https://www.rfc-editor.org/info/rfc9641); see the RFC + itself for full legal notices."; + + revision 2024-10-10 { + description + "Initial version."; + reference + "RFC 9641: 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 inline-definitions-supported { + description + "The 'inline-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 central-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 central truststore."; + } + + typedef central-certificate-ref { + type leafref { + path "/ts:truststore/ts:certificate-bags/ts:certificate-bag" + + "[ts:name = current()/../certificate-bag]/" + + "ts:certificate/ts:name"; + } + description + "This typedef defines a reference to a specific certificate + in a certificate bag in the central truststore. This typedef + requires that there exist a sibling 'leaf' node called + 'certificate-bag' that SHOULD have the + 'central-certificate-bag-ref' typedef."; + } + + typedef central-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 central truststore."; + } + + typedef central-public-key-ref { + type leafref { + path "/ts:truststore/ts:public-key-bags/ts:public-key-bag" + + "[ts:name = current()/../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. This typedef + requires that there exist a sibling 'leaf' node called + 'public-key-bag' SHOULD have the + 'central-public-key-bag-ref' typedef."; + } + + /*****************/ + /* Groupings */ + /*****************/ + // *-ref groupings + + grouping central-certificate-ref-grouping { + description + "Grouping for the reference to a certificate in a + certificate-bag in the central truststore."; + leaf certificate-bag { + nacm:default-deny-write; + if-feature "central-truststore-supported"; + if-feature "certificates"; + type ts:central-certificate-bag-ref; + must '../certificate'; + description + "Reference to a certificate-bag in the truststore."; + } + leaf certificate { + nacm:default-deny-write; + if-feature "central-truststore-supported"; + if-feature "certificates"; + type ts:central-certificate-ref; + must '../certificate-bag'; + description + "Reference to a specific certificate in the + referenced certificate-bag."; + } + } + + grouping central-public-key-ref-grouping { + description + "Grouping for the reference to a public key in a + public-key-bag in the central truststore."; + leaf public-key-bag { + nacm:default-deny-write; + if-feature "central-truststore-supported"; + if-feature "public-keys"; + type ts:central-public-key-bag-ref; + description + "Reference of a public key bag in the truststore, including + the certificate to authenticate the TLS client."; + } + leaf public-key { + nacm:default-deny-write; + if-feature "central-truststore-supported"; + if-feature "public-keys"; + type ts:central-public-key-ref; + description + "Reference to a specific public key in the + referenced public-key-bag."; + } + } + + // inline-or-truststore-* groupings + + grouping inline-or-truststore-certs-grouping { + description + "A grouping for the configuration of a list of certificates. + The list of certificates may be defined inline or as a + reference to a certificate bag in the central truststore. + + Servers that wish to define alternate truststore locations + MUST augment in custom 'case' statements, enabling + references to those alternate truststore locations."; + 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 inline { + if-feature "inline-definitions-supported"; + container inline-definition { + description + "A container for locally configured trust anchor + certificates."; + list certificate { + key "name"; + min-elements 1; + description + "A trust anchor certificate or chain of certificates."; + leaf name { + type string; + description + "An arbitrary name for this certificate."; + } + uses ct:trust-anchor-cert-grouping { + refine "cert-data" { + mandatory true; + } + } + } + } + } + case central-truststore { + if-feature "central-truststore-supported"; + if-feature "certificates"; + leaf central-truststore-reference { + type ts:central-certificate-bag-ref; + description + "A reference to a certificate bag that exists in the + central truststore."; + } + } + } + } + + grouping inline-or-truststore-public-keys-grouping { + description + "A grouping that allows the public keys to either be + configured locally, within the data model being used, or be a + reference to a public key bag stored in the truststore. + + Servers that wish to define alternate truststore locations + SHOULD augment in custom 'case' statement, enabling + references to those alternate truststore locations."; + 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 inline { + if-feature "inline-definitions-supported"; + container inline-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 central-truststore { + if-feature "central-truststore-supported"; + if-feature "public-keys"; + leaf central-truststore-reference { + type ts:central-public-key-bag-ref; + description + "A reference to a bag of public keys that exists + in the central truststore."; + } + } + } + } + + // the truststore grouping + + grouping truststore-grouping { + description + "A grouping definition that enables use in other contexts. + Where used, implementations MUST augment new 'case' + statements into the various inline-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 or chain of certificates."; + 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 + 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 public keys."; + } + leaf description { + type string; + description + "A description for this bag of public keys. The + intended purpose for the bag MUST 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/libnetconf2-netconf-server@2025-08-01.yang b/modules/libnetconf2-netconf-server@2025-11-11.yang similarity index 78% rename from modules/libnetconf2-netconf-server@2025-08-01.yang rename to modules/libnetconf2-netconf-server@2025-11-11.yang index 54c5e274..86210180 100644 --- a/modules/libnetconf2-netconf-server@2025-08-01.yang +++ b/modules/libnetconf2-netconf-server@2025-11-11.yang @@ -31,6 +31,10 @@ module libnetconf2-netconf-server { prefix tlss; } + revision "2025-11-11" { + description "Removed obsolete SSH algorithm identities due to IANA algorithms YANG models update."; + } + revision "2025-08-01" { description "Added UNIX socket configuration."; } @@ -119,141 +123,6 @@ 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"; - } - // Typedefs typedef time-period { @@ -384,7 +253,7 @@ module libnetconf2-netconf-server { 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:server-identity" { - uses ssh-authentication-params-grouping; + uses ssh-server-banner-grouping; } augment "/ncs:netconf-server/ncs:listen/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters" + diff --git a/src/server_config.c b/src/server_config.c index c9add550..193f0669 100644 --- a/src/server_config.c +++ b/src/server_config.c @@ -1,10 +1,10 @@ /** * @file server_config.c * @author Roman Janota - * @brief libnetconf2 server configuration functions + * @brief libnetconf2 server configuration through YANG data implementation * * @copyright - * Copyright (c) 2022-2023 CESNET, z.s.p.o. + * Copyright (c) 2022-2025 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. @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -33,4589 +34,5986 @@ #include "config.h" #include "log_p.h" #include "server_config.h" -#include "server_config_p.h" #include "session_p.h" -/* returns a parent node of 'node' that matches the name 'name' */ -static const struct lyd_node * -nc_server_config_get_parent(const struct lyd_node *node, const char *name) -{ - NC_CHECK_ARG_RET(NULL, node, name, NULL); - - while (node) { - if (!strcmp(LYD_NAME(node), name)) { - return node; - } - node = lyd_parent(node); - } - - return NULL; -} - -/* returns a parent list node of 'node' that matches the name 'name' */ -static const struct lyd_node * -nc_server_config_get_parent_list(const struct lyd_node *node, const char *name) -{ - NC_CHECK_ARG_RET(NULL, node, name, NULL); - - while (node) { - /* check if the node is a list and its name matches the param */ - if ((node->schema->nodetype == LYS_LIST) && (!strcmp(LYD_NAME(node), name))) { - return node; - } - node = lyd_parent(node); +/** + * @brief Macro to get the diff operation of a node, defaulting to the parent's operation if not present. + * + * @note Returns 1 on error. + * + * @param[in] node Node to get the operation from. + * @param[in] parent_op Parent node's operation. + * @param[out] op Diff operation of the node. + */ +#define NC_NODE_GET_OP(node, parent_op, op) \ + { \ + struct lyd_meta *_meta = lyd_find_meta(node->meta, NULL, "yang:operation"); \ + if (_meta) { \ + const char *_meta_val = lyd_get_meta_value(_meta); \ + if (!strcmp(_meta_val, "create")) { \ + *(op) = NC_OP_CREATE; \ + } else if (!strcmp(_meta_val, "delete")) { \ + *(op) = NC_OP_DELETE; \ + } else if (!strcmp(_meta_val, "replace")) { \ + *(op) = NC_OP_REPLACE; \ + } else if (!strcmp(_meta_val, "none")) { \ + *(op) = NC_OP_NONE; \ + } else { \ + ERR(NULL, "Unknown operation \"%s\" of node \"%s\".", _meta_val, LYD_NAME(node)); \ + return 1; \ + } \ + } else { \ + *(op) = parent_op; \ + } \ } - return NULL; -} - -/* returns the key of a list node with the name 'name' */ -static const char * -nc_server_config_get_parent_list_key_value(const struct lyd_node *node, const char *name, const char *key_name) -{ - const char *original_name; - - NC_CHECK_ARG_RET(NULL, node, name, key_name, NULL); - original_name = LYD_NAME(node); - - /* get the supposed parent list */ - node = nc_server_config_get_parent_list(node, name); - if (!node) { - ERR(NULL, "Node \"%s\" not contained in \"%s\" subtree.", original_name, name); - return NULL; - } +/** + * @brief Macro to log unsupported configuration nodes. + * + * @param[in] node Node that is unsupported. + */ +#define CONFIG_LOG_UNSUPPORTED(node) \ + WRN(NULL, "Unsupported node \"%s\" in the configuration, ignoring.", LYD_NAME(node)) - /* child should be the key */ - node = lyd_child(node); - if (!node) { - ERR(NULL, "Node \"%s\" has no child nodes.", name); - return NULL; - } - if (strcmp(LYD_NAME(node), key_name)) { - ERR(NULL, "Node \"%s\" child names mismatch (found:\"%s\", expected:\"%s\").", original_name, LYD_NAME(node), key_name); - return NULL; +/** + * @brief Wrapper macro for LY_ARRAY_CREATE_GOTO to disallow zero-size arrays. + */ +#define LN2_LY_ARRAY_CREATE_GOTO_WRAP(ARRAY, SIZE, RET, GOTO) \ + if (!(SIZE)) { \ + (ARRAY) = NULL; \ + } else { \ + LY_ARRAY_CREATE_GOTO(NULL, ARRAY, SIZE, RET, GOTO); \ } - return lyd_get_value(node); -} - -/* returns true if a node is a part of the listen subtree */ -static int -is_listen(const struct lyd_node *node) -{ - node = nc_server_config_get_parent(node, "listen"); - 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) -{ - node = nc_server_config_get_parent(node, "call-home"); - return node != NULL; -} - -#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) -{ - node = nc_server_config_get_parent(node, "ssh"); - return node != NULL; -} - -/* returns true if a node is a part of the tls subtree */ -static int -is_tls(const struct lyd_node *node) -{ - node = nc_server_config_get_parent(node, "tls"); - return node != NULL; -} - -#endif /* NC_ENABLED_SSH_TLS */ - /** - * @brief Gets an endpoint based on the node's location in the YANG data tree. + * @brief Find a child node of a given node and optionally don't fail if not found. * - * Parent nodes of the given node are searched until the "endpoint" parent is hit - * and the endpoint name is extracted from it. + * @note Implicit nodes, such as NP containers/leafs with default values, are always expected to be present. * - * @param[in] node Node in the YANG data tree to search for the endpoint. - * @param[out] endpt Found endpoint. - * @param[out] bind Optional bind associated with the endpoint. - * @return 0 on success, 1 on error. + * @param[in] node Context (parent) node. + * @param[in] child Name of the child node to find. + * @param[in] fail_if_not_found Whether to fail if the node is not present. + * @param[out] match Found node. + * @return 0 on success, 1 if mandatory and not found. */ static int -nc_server_config_get_endpt(const struct lyd_node *node, struct nc_endpt **endpt, struct nc_bind **bind) +nc_lyd_find_child(const struct lyd_node *node, const char *child, int fail_if_not_found, struct lyd_node **match) { - uint16_t i; - const char *name; + *match = NULL; - NC_CHECK_ARG_RET(NULL, node, endpt, 1); - - name = nc_server_config_get_parent_list_key_value(node, "endpoint", "name"); - if (!name) { + lyd_find_path(node, child, 0, match); + if (fail_if_not_found && !*match) { + ERR(NULL, "Implicit child node \"%s\" of node \"%s\" missing.", child, LYD_NAME(node)); return 1; } - for (i = 0; i < server_opts.endpt_count; i++) { - if (!strcmp(server_opts.endpts[i].name, name)) { - *endpt = &server_opts.endpts[i]; - if (bind) { - *bind = &server_opts.binds[i]; - } - return 0; - } - } - - ERR(NULL, "Endpoint \"%s\" was not found.", name); - return 1; + return 0; } +#ifdef NC_ENABLED_SSH_TLS + /** - * @brief Gets the Call Home client structure based on the node's location in the YANG data tree. + * @brief Free SSH server options. * - * @param[in] node Node in the YANG data tree. - * @param[out] ch_client Pointer to the Call Home client structure to be filled. - * @return 0 on success, 1 on error. + * @param[in] opts SSH server options to free. */ -static int -nc_server_config_get_ch_client(const struct lyd_node *node, struct nc_ch_client **ch_client) +static void +nc_server_config_ssh_opts_free(struct nc_server_ssh_opts *opts) { - uint16_t i; - const char *name; + struct nc_hostkey *hostkey; + struct nc_auth_client *auth_client; + struct nc_public_key *pubkey; + LY_ARRAY_COUNT_TYPE i, j; - NC_CHECK_ARG_RET(NULL, node, ch_client, 1); + if (!opts) { + return; + } - name = nc_server_config_get_parent_list_key_value(node, "netconf-client", "name"); - if (!name) { - return 1; + /* free hostkeys */ + LY_ARRAY_FOR(opts->hostkeys, i) { + hostkey = &opts->hostkeys[i]; + free(hostkey->name); + if (hostkey->store == NC_STORE_LOCAL) { + free(hostkey->key.name); + free(hostkey->key.pubkey.data); + free(hostkey->key.privkey.data); + } else if (hostkey->store == NC_STORE_KEYSTORE) { + free(hostkey->ks_ref); + } } + LY_ARRAY_FREE(opts->hostkeys); - for (i = 0; i < server_opts.ch_client_count; i++) { - if (!strcmp(server_opts.ch_clients[i].name, name)) { - *ch_client = &server_opts.ch_clients[i]; - return 0; + /* free authorized clients */ + LY_ARRAY_FOR(opts->auth_clients, i) { + auth_client = &opts->auth_clients[i]; + free(auth_client->username); + if (auth_client->pubkey_store == NC_STORE_LOCAL) { + LY_ARRAY_FOR(auth_client->pubkeys, j) { + pubkey = &auth_client->pubkeys[j]; + free(pubkey->name); + free(pubkey->data); + } + LY_ARRAY_FREE(auth_client->pubkeys); + } else if (auth_client->pubkey_store == NC_STORE_TRUSTSTORE) { + free(auth_client->ts_ref); } + free(auth_client->password); } + LY_ARRAY_FREE(opts->auth_clients); - ERR(NULL, "Call-home client \"%s\" was not found.", name); - return 1; + free(opts->referenced_endpt_name); + free(opts->hostkey_algs); + free(opts->encryption_algs); + free(opts->kex_algs); + free(opts->mac_algs); + free(opts->banner); + free(opts); } /** - * @brief Gets the Call Home endpoint structure based on the node's location in the YANG data tree. + * @brief Free TLS server options. * - * @param[in] node Node in the YANG data tree. - * @param[in] ch_client Call Home client structure. - * @param[out] ch_endpt Pointer to the Call Home endpoint structure to be filled. - * @return 0 on success, 1 on error. + * @param[in] opts TLS server options to free. */ -static 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) +static void +nc_server_config_tls_opts_free(struct nc_server_tls_opts *opts) { - uint16_t i; - const char *name; + struct nc_ctn *ctn, *next; + LY_ARRAY_COUNT_TYPE i; - NC_CHECK_ARG_RET(NULL, node, ch_client, ch_endpt, 1); + if (!opts) { + return; + } - name = nc_server_config_get_parent_list_key_value(node, "endpoint", "name"); - if (!name) { - return 1; + /* free server identity */ + if (opts->cert_store == NC_STORE_LOCAL) { + free(opts->local.key.name); + free(opts->local.key.pubkey.data); + free(opts->local.key.privkey.data); + free(opts->local.cert.name); + free(opts->local.cert.data); + } else if (opts->cert_store == NC_STORE_KEYSTORE) { + free(opts->keystore.asym_key_ref); + free(opts->keystore.cert_ref); } - 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]; - return 0; + /* free ca certificates */ + if (opts->client_auth.ca_certs_store == NC_STORE_LOCAL) { + LY_ARRAY_FOR(opts->client_auth.ca_certs, i) { + free(opts->client_auth.ca_certs[i].name); + free(opts->client_auth.ca_certs[i].data); } + LY_ARRAY_FREE(opts->client_auth.ca_certs); + } else if (opts->client_auth.ca_certs_store == NC_STORE_TRUSTSTORE) { + free(opts->client_auth.ca_cert_bag_ts_ref); } - ERR(NULL, "Call-home client's \"%s\" endpoint \"%s\" was not found.", ch_client->name, name); - return 1; -} - -/** - * @brief Gets the UNIX options structure based on the node's location in the YANG data tree. - * - * @param[in] node Node in the YANG data tree to search the UNIX options for. - * @param[out] opts Pointer to the UNIX options structure to be filled. - * @return 0 on success, 1 on error. - */ -static int -nc_server_config_get_unix_opts(const struct lyd_node *node, struct nc_server_unix_opts **opts) -{ - struct nc_endpt *endpt; + /* free end-entity certificates */ + if (opts->client_auth.ee_certs_store == NC_STORE_LOCAL) { + LY_ARRAY_FOR(opts->client_auth.ee_certs, i) { + free(opts->client_auth.ee_certs[i].name); + free(opts->client_auth.ee_certs[i].data); + } + LY_ARRAY_FREE(opts->client_auth.ee_certs); + } else if (opts->client_auth.ee_certs_store == NC_STORE_TRUSTSTORE) { + free(opts->client_auth.ee_cert_bag_ts_ref); + } - NC_CHECK_RET(nc_server_config_get_endpt(node, &endpt, NULL)); - *opts = endpt->opts.unix; + /* free cert-to-name entries */ + for (ctn = opts->ctn; ctn; ctn = next) { + next = ctn->next; + free(ctn->fingerprint); + free(ctn->name); + free(ctn); + } - return 0; + free(opts->referenced_endpt_name); + free(opts->cipher_suites); + free(opts); } -#ifdef NC_ENABLED_SSH_TLS +#endif /* NC_ENABLED_SSH_TLS */ /** - * @brief Gets the SSH options structure based on the node's location in the YANG data tree. + * @brief Free UNIX server options. * - * @param[in] node Node in the YANG data tree to search the SSH options for. - * @param[in] ch_client Call Home client structure, can be NULL if the node is a part of the listen subtree. - * @param[out] opts Pointer to the SSH options structure to be filled. - * @return 0 on success, 1 on error. + * @param[in] opts UNIX server options to free. */ -static int -nc_server_config_get_ssh_opts(const struct lyd_node *node, const struct nc_ch_client *ch_client, - struct nc_server_ssh_opts **opts) +static void +nc_server_config_unix_opts_free(struct nc_server_unix_opts *opts) { - struct nc_endpt *endpt; - struct nc_ch_endpt *ch_endpt; + struct nc_server_unix_user_mapping *mapping; + LY_ARRAY_COUNT_TYPE i, j; - NC_CHECK_ARG_RET(NULL, node, opts, 1); + if (!opts) { + return; + } - 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_client, &ch_endpt)) { - return 1; + /* free user mappings */ + LY_ARRAY_FOR(opts->user_mappings, i) { + mapping = &opts->user_mappings[i]; + free(mapping->system_user); + + LY_ARRAY_FOR(mapping->allowed_users, j) { + free(mapping->allowed_users[j]); } - *opts = ch_endpt->opts.ssh; + LY_ARRAY_FREE(mapping->allowed_users); } + LY_ARRAY_FREE(opts->user_mappings); - return 0; + free(opts); } -/* 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, const struct nc_ch_client *ch_client, - struct nc_hostkey **hostkey) -{ - uint16_t i; - const char *name; - struct nc_server_ssh_opts *opts; +#ifdef NC_ENABLED_SSH_TLS - NC_CHECK_ARG_RET(NULL, node, hostkey, 1); +/** + * @brief Free keystore configuration data. + * + * @param[in] ks Keystore to free (it's not dynamically allocated). + */ +static void +nc_server_config_keystore_free(struct nc_keystore *ks) +{ + struct nc_keystore_entry *entry; + LY_ARRAY_COUNT_TYPE i, j; - if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) { - return 1; + if (!ks) { + return; } - name = nc_server_config_get_parent_list_key_value(node, "host-key", "name"); - if (!name) { - return 1; - } + LY_ARRAY_FOR(ks->entries, i) { + entry = &ks->entries[i]; + free(entry->asym_key.name); + free(entry->asym_key.pubkey.data); + free(entry->asym_key.privkey.data); - for (i = 0; i < opts->hostkey_count; i++) { - if (!strcmp(opts->hostkeys[i].name, name)) { - *hostkey = &opts->hostkeys[i]; - return 0; + /* free certificates */ + LY_ARRAY_FOR(entry->certs, j) { + free(entry->certs[j].name); + free(entry->certs[j].data); } + LY_ARRAY_FREE(entry->certs); } + LY_ARRAY_FREE(ks->entries); - ERR(NULL, "Host-key \"%s\" was not found.", name); - return 1; + memset(ks, 0, sizeof(*ks)); } -/* 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, const struct nc_ch_client *ch_client, - struct nc_auth_client **auth_client) +/** + * @brief Free truststore configuration data. + * + * @param[in] ts Truststore to free (it's not dynamically allocated). + */ +static void +nc_server_config_truststore_free(struct nc_truststore *ts) { - uint16_t i; - const char *name; - struct nc_server_ssh_opts *opts; - - NC_CHECK_ARG_RET(NULL, node, auth_client, 1); + struct nc_certificate_bag *cbag; + struct nc_public_key_bag *pkbag; + LY_ARRAY_COUNT_TYPE i, j; - if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) { - return 1; + if (!ts) { + return; } - name = nc_server_config_get_parent_list_key_value(node, "user", "name"); - if (!name) { - return 1; - } + /* free certificate bags */ + LY_ARRAY_FOR(ts->cert_bags, i) { + cbag = &ts->cert_bags[i]; - for (i = 0; i < opts->client_count; i++) { - if (!strcmp(opts->auth_clients[i].username, name)) { - *auth_client = &opts->auth_clients[i]; - return 0; + free(cbag->name); + free(cbag->description); + LY_ARRAY_FOR(cbag->certs, j) { + free(cbag->certs[j].name); + free(cbag->certs[j].data); } + LY_ARRAY_FREE(cbag->certs); } + LY_ARRAY_FREE(ts->cert_bags); - ERR(NULL, "Authorized key \"%s\" was not found.", name); - 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, const struct nc_ch_client *ch_client, - struct nc_public_key **pubkey) -{ - uint16_t i; - const char *name; - struct nc_auth_client *auth_client; - - NC_CHECK_ARG_RET(NULL, node, pubkey, 1); - - if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) { - return 1; - } - - name = nc_server_config_get_parent_list_key_value(node, "public-key", "name"); - if (!name) { - return 1; - } + /* free public key bags */ + LY_ARRAY_FOR(ts->pubkey_bags, i) { + pkbag = &ts->pubkey_bags[i]; - for (i = 0; i < auth_client->pubkey_count; i++) { - if (!strcmp(auth_client->pubkeys[i].name, name)) { - *pubkey = &auth_client->pubkeys[i]; - return 0; + free(pkbag->name); + free(pkbag->description); + LY_ARRAY_FOR(pkbag->pubkeys, j) { + free(pkbag->pubkeys[j].name); + free(pkbag->pubkeys[j].data); } + LY_ARRAY_FREE(pkbag->pubkeys); } + LY_ARRAY_FREE(ts->pubkey_bags); - ERR(NULL, "Public key \"%s\" was not found.", name); - return 1; + memset(ts, 0, sizeof(*ts)); } -/* 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, const struct nc_ch_client *ch_client, - struct nc_server_tls_opts **opts) +#endif /* NC_ENABLED_SSH_TLS */ + +/** + * @brief Free server configuration data. + * + * @param[in] config Server configuration to free. + */ +void +nc_server_config_free(struct nc_server_config *config) { struct nc_endpt *endpt; + struct nc_ch_client *ch_client; struct nc_ch_endpt *ch_endpt; + LY_ARRAY_COUNT_TYPE i, j; - NC_CHECK_ARG_RET(NULL, node, opts, 1); - - 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_client, &ch_endpt)) { - return 1; - } - *opts = ch_endpt->opts.tls; + if (!config) { + return; } - 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, const struct nc_ch_client *ch_client, - struct nc_certificate **cert) -{ - uint16_t i; - const char *name; - struct nc_cert_grouping *certs; - struct nc_server_tls_opts *opts; - int is_cert_end_entity; - const struct lyd_node *tmp; - - NC_CHECK_ARG_RET(NULL, node, cert, 1); - - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - return 1; + /* free ignored hello modules */ + LY_ARRAY_FOR(config->ignored_modules, i) { + free(config->ignored_modules[i]); } + LY_ARRAY_FREE(config->ignored_modules); - name = nc_server_config_get_parent_list_key_value(node, "certificate", "name"); - if (!name) { - return 1; - } + /* free listen endpoints */ + LY_ARRAY_FOR(config->endpts, i) { + endpt = &config->endpts[i]; - /* it's in certificate subtree, now check if it's end entity or certificate authority */ - tmp = nc_server_config_get_parent(node, "ee-certs"); - if (tmp) { - is_cert_end_entity = 1; - } else { - tmp = nc_server_config_get_parent(node, "ca-certs"); - if (!tmp) { - ERR(NULL, "Node \"%s\" is not contained in ee-certs nor ca-certs subtree.", name); - return 1; - } - is_cert_end_entity = 0; - } + free(endpt->name); - /* get the right cert stack, either ee or ca */ - if (is_cert_end_entity) { - certs = &opts->ee_certs; - } else { - certs = &opts->ca_certs; - } + /* free binds */ + LY_ARRAY_FOR(endpt->binds, j) { + free(endpt->binds[j].address); + if (endpt->binds[j].sock != -1) { + close(endpt->binds[j].sock); + } + pthread_mutex_destroy(&endpt->bind_lock); + } + LY_ARRAY_FREE(endpt->binds); - for (i = 0; i < certs->cert_count; i++) { - if (!strcmp(certs->certs[i].name, name)) { - *cert = &certs->certs[i]; - return 0; + /* free transport specific options */ + switch (endpt->ti) { +#ifdef NC_ENABLED_SSH_TLS + case NC_TI_SSH: + nc_server_config_ssh_opts_free(endpt->opts.ssh); + break; + case NC_TI_TLS: + nc_server_config_tls_opts_free(endpt->opts.tls); + break; +#endif /* NC_ENABLED_SSH_TLS */ + case NC_TI_UNIX: + nc_server_config_unix_opts_free(endpt->opts.unix); + break; + default: + ERRINT; + break; } } + LY_ARRAY_FREE(config->endpts); - ERR(NULL, "%s certificate \"%s\" was not found.", is_cert_end_entity ? "End-entity" : "Certificate authority", name); - 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, const struct nc_ch_client *ch_client, - struct nc_ctn **ctn) -{ - uint32_t id; - struct nc_ctn *iter; - struct nc_server_tls_opts *opts; - const char *name; - - NC_CHECK_ARG_RET(NULL, node, ctn, 1); + /* free call home clients */ + LY_ARRAY_FOR(config->ch_clients, i) { + ch_client = &config->ch_clients[i]; - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - return 1; - } + free(ch_client->name); - name = LYD_NAME(node); - node = nc_server_config_get_parent_list(node, "cert-to-name"); - if (!node) { - ERR(NULL, "Node \"%s\" is not contained in a cert-to-name subtree.", name); - return 1; - } + /* free call home endpoints */ + LY_ARRAY_FOR(ch_client->ch_endpts, j) { + ch_endpt = &ch_client->ch_endpts[j]; - node = lyd_child(node); - assert(!strcmp(LYD_NAME(node), "id")); - id = ((struct lyd_node_term *)node)->value.uint32; + free(ch_endpt->name); + free(ch_endpt->src_addr); + free(ch_endpt->dst_addr); - iter = opts->ctn; - while (iter) { - if (iter->id == id) { - *ctn = iter; - return 0; + /* free transport specific options */ + switch (ch_endpt->ti) { +#ifdef NC_ENABLED_SSH_TLS + case NC_TI_SSH: + nc_server_config_ssh_opts_free(ch_endpt->opts.ssh); + break; + case NC_TI_TLS: + nc_server_config_tls_opts_free(ch_endpt->opts.tls); + break; +#endif /* NC_ENABLED_SSH_TLS */ + default: + ERRINT; + break; + } } - - iter = iter->next; + LY_ARRAY_FREE(ch_client->ch_endpts); } + LY_ARRAY_FREE(config->ch_clients); - ERR(NULL, "Cert-to-name entry with id \"%d\" was not found.", id); - return 1; -} - -enum 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, "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; - } -} +#ifdef NC_ENABLED_SSH_TLS + /* free keystore and truststore */ + nc_server_config_keystore_free(&config->keystore); + nc_server_config_truststore_free(&config->truststore); + /* free certificate expiration intervals */ + LY_ARRAY_FREE(config->cert_exp_notif_intervals); #endif /* NC_ENABLED_SSH_TLS */ -int -equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name) -{ - uint16_t i; - - assert(node && parent_count && 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; + memset(config, 0, sizeof(*config)); } -int -nc_server_config_realloc(const char *key_value, void **ptr, size_t size, void *count) +API int +nc_server_config_load_modules(struct ly_ctx **ctx) { - int ret = 0; - void *tmp; - char **name; - uint32_t *cnt = count; - - tmp = realloc(*ptr, (*cnt + 1) * size); - NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup); - *ptr = tmp; - - /* set the newly allocated memory to 0 */ - memset((char *)(*ptr) + (*cnt * size), 0, size); - (*cnt)++; - - /* access the first member of the supposed structure */ - name = (char **)((char *)(*ptr) + ((*cnt - 1) * size)); + int i, new_ctx = 0; - /* and set it's value */ - *name = strdup(key_value); - NC_CHECK_ERRMEM_GOTO(!*name, ret = 1, cleanup); - -cleanup: - return ret; -} - -#ifdef NC_ENABLED_SSH_TLS + 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; + } -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); + /* 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, csr-generation, p10-csr-format, certificate-expiration-notification, + * 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[] = {"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 ssh-x509-certs, asymmetric-key-pair-generation */ + const char *ietf_ssh_common[] = {"algorithm-discovery", "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 */ + 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 *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", "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[] = {"algorithm-discovery", "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 *iana_tls_cipher_suite_algs[] = {NULL}; + /* all features */ + const char *libnetconf2_netconf_server[] = {NULL}; - free(hostkey->name); + const char *module_names[] = { + "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server", + "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs", + "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash", + "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs", + "libnetconf2-netconf-server", NULL + }; - if (hostkey->store == NC_STORE_LOCAL) { - free(hostkey->key.pubkey_data); - free(hostkey->key.privkey_data); - } else { - free(hostkey->ks_ref); - } + 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, iana_tls_cipher_suite_algs, + libnetconf2_netconf_server, NULL + }; - opts->hostkey_count--; - if (!opts->hostkey_count) { - free(opts->hostkeys); - opts->hostkeys = NULL; - } else if (hostkey != &opts->hostkeys[opts->hostkey_count]) { - memcpy(hostkey, &opts->hostkeys[opts->hostkey_count], sizeof *opts->hostkeys); + for (i = 0; module_names[i]; 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; + } } -} -static void -nc_server_config_del_auth_client_pubkey(struct nc_auth_client *auth_client, struct nc_public_key *pubkey) -{ - free(pubkey->name); - free(pubkey->data); + return 0; - 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]) { - memcpy(pubkey, &auth_client->pubkeys[auth_client->pubkey_count], sizeof *auth_client->pubkeys); +error: + if (new_ctx) { + ly_ctx_destroy(*ctx); + *ctx = NULL; } + return 1; } -static void -nc_server_config_del_auth_client_pubkeys(struct nc_auth_client *auth_client) -{ - uint16_t i, pubkey_count; +/* + * ===================================================================================== + * ietf-netconf-server handlers + * ===================================================================================== + */ - 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 if (auth_client->store == NC_STORE_TRUSTSTORE) { - free(auth_client->ts_ref); - auth_client->ts_ref = NULL; - } -} +#ifdef NC_ENABLED_SSH_TLS -static void -nc_server_config_del_auth_client(struct nc_server_ssh_opts *opts, struct nc_auth_client *auth_client) +static int +config_local_address(const struct lyd_node *node, enum nc_operation parent_op, struct nc_bind *bind) { - free(auth_client->username); - - nc_server_config_del_auth_client_pubkeys(auth_client); - - free(auth_client->password); + enum nc_operation op; - 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]) { - memcpy(auth_client, &opts->auth_clients[opts->client_count], sizeof *opts->auth_clients); - } -} - -static void -nc_server_config_del_ssh_opts(struct nc_bind *bind, struct nc_server_ssh_opts *opts) -{ - uint16_t i, hostkey_count, client_count; + NC_NODE_GET_OP(node, parent_op, &op); - if (bind) { + if (op == NC_OP_DELETE) { free(bind->address); - 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_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]); + bind->address = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(bind->address); + bind->address = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!bind->address, 1); } - free(opts->hostkey_algs); - free(opts->kex_algs); - free(opts->encryption_algs); - free(opts->mac_algs); - - free(opts->banner); - - free(opts); + return 0; } -/* delete references to endpoint with the name 'referenced_endpt_name' from other endpts */ -static void -nc_server_config_del_endpt_references(const char *referenced_endpt_name) +static int +config_local_port(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), struct nc_bind *bind) { - uint16_t i, j; - - /* first go through listen endpoints */ - 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; + /* default value always present */ + bind->port = strtoul(lyd_get_value(node), NULL, 10); + return 0; +} - if (server_opts.endpts[i].ti == NC_TI_SSH) { - server_opts.endpts[i].opts.ssh->referenced_endpt_name = NULL; - } else { - server_opts.endpts[i].opts.tls->referenced_endpt_name = NULL; - } +static int +config_local_bind(const struct lyd_node *node, enum nc_operation parent_op, struct nc_endpt *endpt) +{ + struct lyd_node *n; + enum nc_operation op; + struct nc_bind *bind = NULL; + const char *local_addr; + LY_ARRAY_COUNT_TYPE i; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* local address (local-bind list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "local-address", 1, &n)); + local_addr = lyd_get_value(n); + assert(local_addr); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the bind we are deleting/modifying */ + LY_ARRAY_FOR(endpt->binds, i) { + if (!strcmp(endpt->binds[i].address, local_addr)) { + break; } } + assert(i < LY_ARRAY_COUNT(endpt->binds)); + bind = &endpt->binds[i]; + } else if (op == NC_OP_CREATE) { + /* create a new bind */ + LY_ARRAY_NEW_RET(LYD_CTX(node), endpt->binds, bind, 1); + /* init the new bind */ + bind->sock = -1; } - /* next go through ch endpoints */ - for (i = 0; i < server_opts.ch_client_count; i++) { - 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; + /* config local address */ + NC_CHECK_RET(config_local_address(n, op, bind)); - if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_SSH) { - 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; - } - } - } + /* config local port (default value => always present) */ + NC_CHECK_RET(nc_lyd_find_child(node, "local-port", 1, &n)); + NC_CHECK_RET(config_local_port(n, op, bind)); + + /* all children processed, we can now delete the bind */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(endpt->binds) - 1) { + endpt->binds[i] = endpt->binds[LY_ARRAY_COUNT(endpt->binds) - 1]; } + LY_ARRAY_DECREMENT_FREE(endpt->binds); } + + return 0; } -void -nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind) +static int +config_idle_time(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), struct nc_keepalives *ka) { - /* 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); - - 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; - } 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); - } + /* default value always present */ + ka->idle_time = strtoul(lyd_get_value(node), NULL, 10); + return 0; } -static void -nc_server_config_del_cert(struct nc_cert_grouping *certs, struct nc_certificate *cert) +static int +config_max_probes(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), struct nc_keepalives *ka) { - free(cert->name); - free(cert->data); - - certs->cert_count--; - if (!certs->cert_count) { - free(certs->certs); - certs->certs = NULL; - } else if (cert != &certs->certs[certs->cert_count]) { - memcpy(cert, &certs->certs[certs->cert_count], sizeof *certs->certs); - } + /* default value always present */ + ka->max_probes = strtoul(lyd_get_value(node), NULL, 10); + return 0; } -static void -nc_server_config_del_certs(struct nc_cert_grouping *certs_grp) +static int +config_probe_interval(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), struct nc_keepalives *ka) { - uint16_t 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); - } - certs_grp->cert_count = 0; - free(certs_grp->certs); - certs_grp->certs = NULL; - } else if (certs_grp->store == NC_STORE_TRUSTSTORE) { - free(certs_grp->ts_ref); - certs_grp->ts_ref = NULL; - } - - /* reset to the default */ - certs_grp->store = NC_STORE_LOCAL; + /* default value always present */ + ka->probe_interval = strtoul(lyd_get_value(node), NULL, 10); + return 0; } -static void -nc_server_config_del_ctn(struct nc_server_tls_opts *opts, struct nc_ctn *ctn) +static int +config_tcp_keepalives(const struct lyd_node *node, enum nc_operation parent_op, struct nc_keepalives *ka) { - struct nc_ctn *iter; + struct lyd_node *n; + enum nc_operation op; - free(ctn->name); - free(ctn->fingerprint); + NC_NODE_GET_OP(node, parent_op, &op); - if (opts->ctn == ctn) { - /* it's the first in the list */ - opts->ctn = ctn->next; - free(ctn); - return; - } + /* config idle-time (default value) */ + NC_CHECK_RET(nc_lyd_find_child(node, "idle-time", 1, &n)); + config_idle_time(n, op, ka); - for (iter = opts->ctn; iter; iter = iter->next) { - if (iter->next == ctn) { - /* found the ctn */ - break; - } - } + /* config max-probes (default value) */ + NC_CHECK_RET(nc_lyd_find_child(node, "max-probes", 1, &n)); + config_max_probes(n, op, ka); - if (!iter) { - ERRINT; - return; + /* config probe-interval (default value) */ + NC_CHECK_RET(nc_lyd_find_child(node, "probe-interval", 1, &n)); + config_probe_interval(n, op, ka); + + /* all children processed */ + if (op == NC_OP_DELETE) { + ka->enabled = 0; + } else if (op == NC_OP_CREATE) { + ka->enabled = 1; } - iter->next = ctn->next; - free(ctn); + return 0; } -static void -nc_server_config_del_ctns(struct nc_server_tls_opts *opts) +static int +config_tcp_server_params(const struct lyd_node *node, enum nc_operation parent_op, struct nc_endpt *endpt) { - struct nc_ctn *cur, *next; + struct lyd_node *n; + enum nc_operation op; + struct ly_set *set = NULL; + uint32_t i; + + NC_NODE_GET_OP(node, parent_op, &op); - for (cur = opts->ctn; cur; cur = next) { - next = cur->next; - free(cur->name); - free(cur->fingerprint); - free(cur); + /* configure all the local binds */ + NC_CHECK_RET(lyd_find_xpath(node, "local-bind", &set), 1); + for (i = 0; i < set->count; i++) { + NC_CHECK_GOTO(config_local_bind(set->dnodes[i], op, endpt), cleanup); } - opts->ctn = NULL; + /* keepalives (presence container) */ + NC_CHECK_GOTO(nc_lyd_find_child(node, "keepalives", 0, &n), cleanup); + if (n) { + NC_CHECK_GOTO(config_tcp_keepalives(n, op, &endpt->ka), cleanup); + } + +cleanup: + ly_set_free(set, NULL); + return 0; } -static void -nc_server_config_del_tls_opts(struct nc_bind *bind, struct nc_server_tls_opts *opts) +static int +config_hostkey_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_hostkey *hostkey) { - if (bind) { - free(bind->address); - if (bind->sock > -1) { - close(bind->sock); - } - } + enum nc_operation op; - if (opts->store == NC_STORE_LOCAL) { - free(opts->pubkey_data); - free(opts->privkey_data); - free(opts->cert_data); - } else if (opts->store == NC_STORE_KEYSTORE) { - free(opts->key_ref); - free(opts->cert_ref); - } + NC_NODE_GET_OP(node, parent_op, &op); - nc_server_config_del_certs(&opts->ca_certs); - nc_server_config_del_certs(&opts->ee_certs); + if (op == NC_OP_DELETE) { + free(hostkey->name); + hostkey->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(hostkey->name); + hostkey->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!hostkey->name, 1); + } - nc_server_config_del_ctns(opts); - free(opts->ciphers); - free(opts); + return 0; } -static void -nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind) +static int +config_pubkey_format(const struct lyd_node *node, enum nc_operation parent_op, struct nc_public_key *pubkey) { - /* delete any references to this endpoint */ - nc_server_config_del_endpt_references(endpt->name); - free(endpt->name); - - free(endpt->referenced_endpt_name); + enum nc_operation op; + const char *format; - nc_server_config_del_tls_opts(bind, endpt->opts.tls); + NC_NODE_GET_OP(node, parent_op, &op); - 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; - } 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); + if (op == NC_OP_DELETE) { + pubkey->type = NC_PUBKEY_FORMAT_UNKNOWN; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + format = ((struct lyd_node_term *)node)->value.ident->name; + assert(format); + if (!strcmp(format, "ssh-public-key-format")) { + pubkey->type = NC_PUBKEY_FORMAT_SSH; + } else if (!strcmp(format, "subject-public-key-info-format")) { + pubkey->type = NC_PUBKEY_FORMAT_X509; + } else { + /* do not fail, the key may still be usable, or it may have come from a keystore/truststore + * and have a different purpose other than NETCONF */ + WRN(NULL, "Public key format \"%s\" not supported. The key may not be usable.", format); + pubkey->type = NC_PUBKEY_FORMAT_UNKNOWN; + } } -} -#endif /* NC_ENABLED_SSH_TLS */ + return 0; +} -static void -nc_server_config_del_user_mapping(struct nc_server_unix_opts *opts, uint32_t idx) +static int +config_pubkey_data(const struct lyd_node *node, enum nc_operation parent_op, struct nc_public_key *pubkey) { - uint32_t i; - - assert(idx < opts->mapping_count); + enum nc_operation op; - /* free the mapping */ - free(opts->user_mappings[idx].system_user); - opts->user_mappings[idx].system_user = NULL; + NC_NODE_GET_OP(node, parent_op, &op); - for (i = 0; i < opts->user_mappings[idx].allowed_user_count; ++i) { - free(opts->user_mappings[idx].allowed_users[i]); + if (op == NC_OP_DELETE) { + free(pubkey->data); + pubkey->data = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(pubkey->data); + pubkey->data = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!pubkey->data, 1); } - free(opts->user_mappings[idx].allowed_users); - opts->user_mappings[idx].allowed_users = NULL; - opts->user_mappings[idx].allowed_user_count = 0; - if (idx != (opts->mapping_count - 1)) { - /* replace the removed item with the last one */ - opts->user_mappings[idx] = opts->user_mappings[opts->mapping_count - 1]; - } - opts->mapping_count--; + return 0; } -static void -nc_server_config_del_unix_opts(struct nc_bind *bind, struct nc_server_unix_opts *opts) +static int +config_privkey_format(const struct lyd_node *node, enum nc_operation parent_op, struct nc_private_key *privkey) { - uint32_t i; + enum nc_operation op; + const char *format; + + NC_NODE_GET_OP(node, parent_op, &op); - if (bind) { - if (bind->sock > -1) { - close(bind->sock); + if (op == NC_OP_DELETE) { + privkey->type = NC_PRIVKEY_FORMAT_UNKNOWN; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + format = ((struct lyd_node_term *)node)->value.ident->name; + assert(format); + + if (!strcmp(format, "rsa-private-key-format")) { + privkey->type = NC_PRIVKEY_FORMAT_RSA; + } else if (!strcmp(format, "ec-private-key-format")) { + privkey->type = NC_PRIVKEY_FORMAT_EC; + } else if (!strcmp(format, "private-key-info-format")) { + privkey->type = NC_PRIVKEY_FORMAT_X509; + } else if (!strcmp(format, "openssh-private-key-format")) { + privkey->type = NC_PRIVKEY_FORMAT_OPENSSH; + } else { + /* do not fail, the key may still be usable, or it may have come from a keystore/truststore + * and have a different purpose other than NETCONF */ + WRN(NULL, "Private key format \"%s\" not supported. The key may not be usable.", format); + privkey->type = NC_PRIVKEY_FORMAT_UNKNOWN; } - unlink(bind->address); - free(bind->address); } - if (opts) { - /* free the path */ - free(opts->path); + return 0; +} - /* free the user mappings */ - for (i = opts->mapping_count; i > 0; i--) { - nc_server_config_del_user_mapping(opts, i - 1); - } - free(opts->user_mappings); +static int +config_cleartext_privkey_data(const struct lyd_node *node, enum nc_operation parent_op, struct nc_private_key *privkey) +{ + enum nc_operation op; - /* free the options structure */ - free(opts); + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(privkey->data); + privkey->data = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(privkey->data); + privkey->data = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!privkey->data, 1); } + + return 0; } -static void -nc_server_config_del_endpt_unix(struct nc_endpt *endpt, struct nc_bind *bind) +static int +config_hidden_privkey_data(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) { - free(endpt->name); - - nc_server_config_del_unix_opts(bind, endpt->opts.unix); + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} - 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; - } else if (endpt != &server_opts.endpts[server_opts.endpt_count]) { - *endpt = server_opts.endpts[server_opts.endpt_count]; - *bind = server_opts.binds[server_opts.endpt_count]; - } +static int +config_encrypted_privkey_data(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; } -static void -nc_server_config_ch_del_endpt(struct nc_ch_client *ch_client, struct nc_ch_endpt *ch_endpt) +static int +config_hostkey_pubkey_inline(const struct lyd_node *node, enum nc_operation parent_op, struct nc_hostkey *hostkey) { - free(ch_endpt->name); + struct lyd_node *n, *cleartext = NULL, *hidden = NULL, *encrypted = NULL; + enum nc_operation op; -#ifdef NC_ENABLED_SSH_TLS - free(ch_endpt->src_addr); - free(ch_endpt->dst_addr); - if (ch_endpt->sock_pending > -1) { - close(ch_endpt->sock_pending); - ch_endpt->sock_pending = -1; + NC_NODE_GET_OP(node, parent_op, &op); + + /* config pubkey format */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key-format", 0, &n)); + if (n) { + NC_CHECK_RET(config_pubkey_format(n, op, &hostkey->key.pubkey)); } - free(ch_endpt->referenced_endpt_name); -#endif /* NC_ENABLED_SSH_TLS */ - switch (ch_endpt->ti) { -#ifdef NC_ENABLED_SSH_TLS - case NC_TI_SSH: - nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh); - break; - case NC_TI_TLS: - nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls); - break; -#endif /* NC_ENABLED_SSH_TLS */ - default: - ERRINT; - break; + /* config pubkey data */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key", 0, &n)); + if (n) { + NC_CHECK_RET(config_pubkey_data(n, op, &hostkey->key.pubkey)); } - ch_client->ch_endpt_count--; - if (!ch_client->ch_endpt_count) { - free(ch_client->ch_endpts); - ch_client->ch_endpts = NULL; + /* config private key format */ + NC_CHECK_RET(nc_lyd_find_child(node, "private-key-format", 0, &n)); + if (n) { + NC_CHECK_RET(config_privkey_format(n, op, &hostkey->key.privkey)); } -} -static void -nc_server_config_destroy_ch_client(struct nc_ch_client *ch_client) -{ - uint16_t i, ch_endpt_count; - - /* CH COND LOCK */ - pthread_mutex_lock(&ch_client->thread_data->cond_lock); - if (ch_client->thread_data->thread_running) { - /* notify the thread to exit, - * it will stop once the current thread is finished applying the configuration - * and releases the config lock */ - ch_client->thread_data->thread_running = 0; - pthread_cond_signal(&ch_client->thread_data->cond); - /* CH COND UNLOCK */ - pthread_mutex_unlock(&ch_client->thread_data->cond_lock); + /* config privkey data, mandatory case/choice node => only one can be present */ + NC_CHECK_RET(nc_lyd_find_child(node, "cleartext-private-key", 0, &cleartext)); + NC_CHECK_RET(nc_lyd_find_child(node, "hidden-private-key", 0, &hidden)); + NC_CHECK_RET(nc_lyd_find_child(node, "encrypted-private-key", 0, &encrypted)); + if (cleartext) { + NC_CHECK_RET(config_cleartext_privkey_data(cleartext, op, &hostkey->key.privkey)); + } else if (hidden) { + NC_CHECK_RET(config_hidden_privkey_data(hidden, op)); } else { - /* CH COND UNLOCK */ - pthread_mutex_unlock(&ch_client->thread_data->cond_lock); + assert(encrypted); + NC_CHECK_RET(config_encrypted_privkey_data(encrypted, op)); } - /* free its members */ - free(ch_client->name); - - 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]); + if (op == NC_OP_DELETE) { + hostkey->store = NC_STORE_UNKNOWN; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + hostkey->store = NC_STORE_LOCAL; } + + return 0; } -static void -nc_server_config_ch_del_client(const struct lyd_node *node) +static int +config_hostkey_pubkey_keystore(const struct lyd_node *node, enum nc_operation parent_op, struct nc_hostkey *hostkey) { - struct nc_ch_client client, *ch_client; - - if (nc_server_config_get_ch_client(node, &ch_client)) { - return; - } + enum nc_operation op; - /* copy the client we want to delete into a local variable */ - memcpy(&client, ch_client, sizeof *ch_client); + NC_NODE_GET_OP(node, parent_op, &op); - /* 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); + if (op == NC_OP_DELETE) { + free(hostkey->ks_ref); + hostkey->ks_ref = NULL; + hostkey->store = NC_STORE_UNKNOWN; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(hostkey->ks_ref); + hostkey->ks_ref = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!hostkey->ks_ref, 1); + hostkey->store = NC_STORE_KEYSTORE; } - nc_server_config_destroy_ch_client(&client); + return 0; } -/* presence container */ -int -nc_server_config_listen(const struct lyd_node *node, enum nc_operation op) +static int +config_hostkey_public_key(const struct lyd_node *node, enum nc_operation parent_op, struct nc_hostkey *hostkey) { - uint16_t i, endpt_count; + enum nc_operation op; + struct lyd_node *inline_def = NULL, *keystore_ref = NULL; - (void) node; + NC_NODE_GET_OP(node, parent_op, &op); - assert(op == NC_OP_CREATE || op == NC_OP_DELETE); - - if (op == NC_OP_DELETE) { - endpt_count = server_opts.endpt_count; - for (i = 0; i < endpt_count; i++) { - switch (server_opts.endpts[i].ti) { -#ifdef NC_ENABLED_SSH_TLS - case NC_TI_SSH: - nc_server_config_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]); - break; - case NC_TI_TLS: - nc_server_config_del_endpt_tls(&server_opts.endpts[i], &server_opts.binds[i]); - break; -#endif /* NC_ENABLED_SSH_TLS */ - case NC_TI_UNIX: - nc_server_config_del_endpt_unix(&server_opts.endpts[i], &server_opts.binds[i]); - break; - case NC_TI_NONE: - case NC_TI_FD: - ERRINT; - return 1; - } - } + /* config inline-definition / keystore ref */ + NC_CHECK_RET(nc_lyd_find_child(node, "inline-definition", 0, &inline_def)); + NC_CHECK_RET(nc_lyd_find_child(node, "central-keystore-reference", 0, &keystore_ref)); + if (inline_def) { + NC_CHECK_RET(config_hostkey_pubkey_inline(inline_def, op, hostkey)); + } else { + assert(keystore_ref); + NC_CHECK_RET(config_hostkey_pubkey_keystore(keystore_ref, op, hostkey)); } return 0; } -int -nc_server_config_ch(const struct lyd_node *node, enum nc_operation op) +static int +config_hostkey_certificate(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} + +static int +config_ssh_hostkey(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - uint16_t i, ch_client_count; - struct nc_ch_client *ch_clients; + struct lyd_node *n, *public_key = NULL, *certificate = NULL; + enum nc_operation op; + struct nc_hostkey *hostkey = NULL; + const char *name; + LY_ARRAY_COUNT_TYPE i; - (void) node; + NC_NODE_GET_OP(node, parent_op, &op); - /* don't do anything if we're not deleting */ - if (op != NC_OP_DELETE) { - return 0; + /* hostkey name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the hostkey we are deleting/modifying */ + LY_ARRAY_FOR(ssh->hostkeys, i) { + if (!strcmp(ssh->hostkeys[i].name, name)) { + break; + } + } + assert(i < LY_ARRAY_COUNT(ssh->hostkeys)); + hostkey = &ssh->hostkeys[i]; + } else if (op == NC_OP_CREATE) { + /* create a new hostkey */ + LY_ARRAY_NEW_RET(LYD_CTX(node), ssh->hostkeys, hostkey, 1); } - ch_client_count = server_opts.ch_client_count; - ch_clients = server_opts.ch_clients; + /* config hostkey name */ + NC_CHECK_RET(config_hostkey_name(n, op, hostkey)); - /* remove them from the server opts */ - server_opts.ch_client_count = 0; - server_opts.ch_clients = NULL; + /* config public-key / certificate */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key", 0, &public_key)); + NC_CHECK_RET(nc_lyd_find_child(node, "certificate", 0, &certificate)); + if (public_key) { + /* config public key */ + NC_CHECK_RET(config_hostkey_public_key(public_key, op, hostkey)); + } else { + /* config certificate */ + assert(certificate); + NC_CHECK_RET(config_hostkey_certificate(certificate, op)); + } - for (i = 0; i < ch_client_count; i++) { - /* now destroy each client */ - nc_server_config_destroy_ch_client(&ch_clients[i]); + /* all children processed, we can now delete the hostkey */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(ssh->hostkeys) - 1) { + ssh->hostkeys[i] = ssh->hostkeys[LY_ARRAY_COUNT(ssh->hostkeys) - 1]; + } + LY_ARRAY_DECREMENT_FREE(ssh->hostkeys); } - free(ch_clients); return 0; } -/* default leaf */ static int -nc_server_config_idle_timeout(const struct lyd_node *node, enum nc_operation op) +config_ssh_banner(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; - assert(!strcmp(LYD_NAME(node), "idle-timeout")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node)) { - /* 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 = ((struct lyd_node_term *)node)->value.uint16; - } else if (op == NC_OP_DELETE) { - ch_client->idle_timeout = 180; - } - } else { - /* listen idle timeout */ - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - server_opts.idle_timeout = ((struct lyd_node_term *)node)->value.uint16; - } else { - /* default value */ - server_opts.idle_timeout = 180; - } + if (op == NC_OP_DELETE) { + free(ssh->banner); + ssh->banner = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(ssh->banner); + ssh->banner = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!ssh->banner, 1); } return 0; } static int -nc_server_config_create_bind(void) +config_ssh_server_identity(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - int ret = 0; - void *tmp; + struct lyd_node *n; + enum nc_operation op; + struct ly_set *set = NULL; + uint32_t i; + + NC_NODE_GET_OP(node, parent_op, &op); - tmp = realloc(server_opts.binds, (server_opts.endpt_count + 1) * sizeof *server_opts.binds); - 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); + /* configure all the hostkeys */ + NC_CHECK_RET(lyd_find_xpath(node, "host-key", &set), 1); + for (i = 0; i < set->count; i++) { + NC_CHECK_GOTO(config_ssh_hostkey(set->dnodes[i], op, ssh), cleanup); + } - server_opts.binds[server_opts.endpt_count].sock = -1; + /* config ssh banner (augment) */ + NC_CHECK_GOTO(nc_lyd_find_child(node, "libnetconf2-netconf-server:banner", 0, &n), cleanup); + if (n) { + NC_CHECK_GOTO(config_ssh_banner(n, op, ssh), cleanup); + } cleanup: - return ret; + ly_set_free(set, NULL); + return 0; } static int -nc_server_config_create_endpoint(const struct lyd_node *node) +config_ssh_user_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) { - if (nc_server_config_create_bind()) { - return 1; - } + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); - node = lyd_child(node); - assert(!strcmp(LYD_NAME(node), "name")); + if (op == NC_OP_DELETE) { + free(user->username); + user->username = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(user->username); + user->username = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!user->username, 1); + } - return nc_server_config_realloc(lyd_get_value(node), (void **)&server_opts.endpts, sizeof *server_opts.endpts, - &server_opts.endpt_count); + return 0; } static int -nc_server_config_ch_create_endpoint(const struct lyd_node *node, struct nc_ch_client *ch_client) +config_pubkey_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_public_key *key) { - node = lyd_child(node); - assert(!strcmp(LYD_NAME(node), "name")); + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); - return nc_server_config_realloc(lyd_get_value(node), (void **)&ch_client->ch_endpts, sizeof *ch_client->ch_endpts, - &ch_client->ch_endpt_count); + if (op == NC_OP_DELETE) { + free(key->name); + key->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(key->name); + key->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!key->name, 1); + } + + return 0; } -/* list */ static int -nc_server_config_endpoint(const struct lyd_node *node, enum nc_operation op) +config_ssh_user_public_key(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) { - int ret = 0; - struct nc_endpt *endpt; - struct nc_bind *bind; - struct nc_ch_endpt *ch_endpt; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + struct lyd_node *n; + struct nc_public_key *key = NULL; + LY_ARRAY_COUNT_TYPE i; + const char *name; - assert(!strcmp(LYD_NAME(node), "endpoint")); + NC_NODE_GET_OP(node, parent_op, &op); - 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; - } + /* public key name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); - switch (endpt->ti) { -#ifdef NC_ENABLED_SSH_TLS - case NC_TI_SSH: - nc_server_config_del_endpt_ssh(endpt, bind); - break; - case NC_TI_TLS: - nc_server_config_del_endpt_tls(endpt, bind); + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the public key we are deleting/modifying */ + LY_ARRAY_FOR(user->pubkeys, i) { + if (!strcmp(user->pubkeys[i].name, name)) { break; -#endif /* NC_ENABLED_SSH_TLS */ - case NC_TI_UNIX: - break; - case NC_TI_NONE: - case NC_TI_FD: - ERRINT; - ret = 1; - goto cleanup; } } - } else if (is_ch(node)) { - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - goto cleanup; - } + assert(i < LY_ARRAY_COUNT(user->pubkeys)); + key = &user->pubkeys[i]; + } else if (op == NC_OP_CREATE) { + /* create a new public key */ + LY_ARRAY_NEW_RET(LYD_CTX(node), user->pubkeys, key, 1); + } - if (op == NC_OP_CREATE) { - ret = nc_server_config_ch_create_endpoint(node, ch_client); - if (ret) { - goto cleanup; - } + /* config public key name */ + NC_CHECK_RET(config_pubkey_name(n, op, key)); - /* 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_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + /* config public key format */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key-format", 1, &n)); + NC_CHECK_RET(config_pubkey_format(n, op, key), 1); + + /* config public key data */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key", 1, &n)); + NC_CHECK_RET(config_pubkey_data(n, op, key), 1); - nc_server_config_ch_del_endpt(ch_client, ch_endpt); + /* all children processed, we can now delete the public key */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(user->pubkeys) - 1) { + user->pubkeys[i] = user->pubkeys[LY_ARRAY_COUNT(user->pubkeys) - 1]; } + LY_ARRAY_DECREMENT_FREE(user->pubkeys); } -cleanup: - return ret; + return 0; } -#ifdef NC_ENABLED_SSH_TLS - static int -nc_server_config_create_ssh(struct nc_endpt *endpt) +config_ssh_user_pubkey_inline(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) { - endpt->ti = NC_TI_SSH; - endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts)); - NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1); + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* config all inline public keys */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_ssh_user_public_key(n, op, user)); + } + + if (op == NC_OP_DELETE) { + user->pubkey_store = NC_STORE_UNKNOWN; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + user->pubkey_store = NC_STORE_LOCAL; + } return 0; } static int -nc_server_config_ch_create_ssh(struct nc_ch_endpt *ch_endpt) +config_ssh_user_pubkey_truststore(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) { - ch_endpt->ti = NC_TI_SSH; - ch_endpt->opts.ssh = calloc(1, sizeof(struct nc_server_ssh_opts)); - NC_CHECK_ERRMEM_RET(!ch_endpt->opts.ssh, 1); + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(user->ts_ref); + user->ts_ref = NULL; + user->pubkey_store = NC_STORE_UNKNOWN; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(user->ts_ref); + user->ts_ref = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!user->ts_ref, 1); + user->pubkey_store = NC_STORE_TRUSTSTORE; + } return 0; } -/* NP container */ static int -nc_server_config_ssh(const struct lyd_node *node, enum nc_operation op) +config_ssh_user_pubkey_system(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) { - struct nc_endpt *endpt; - struct nc_bind *bind; - struct nc_ch_endpt *ch_endpt; - struct nc_ch_client *ch_client = NULL; - int ret = 0; + enum nc_operation op; - assert(!strcmp(LYD_NAME(node), "ssh")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, &bind)) { - ret = 1; - goto cleanup; - } + if (op == NC_OP_DELETE) { + user->pubkey_store = NC_STORE_UNKNOWN; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + user->pubkey_store = NC_STORE_SYSTEM; + } - 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_opts(bind, endpt->opts.ssh); - } - } else { - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - goto cleanup; - } + return 0; +} - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } +static int +config_ssh_user_public_keys(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) +{ + struct lyd_node *inline_def = NULL, *truststore_ref = NULL, *system = NULL; + enum nc_operation op; - if (op == NC_OP_CREATE) { - ret = nc_server_config_ch_create_ssh(ch_endpt); - if (ret) { - goto cleanup; - } - } else if (op == NC_OP_DELETE) { - nc_server_config_del_ssh_opts(NULL, ch_endpt->opts.ssh); - } + NC_NODE_GET_OP(node, parent_op, &op); + + /* config inline-definition / truststore reference / system (augment) */ + NC_CHECK_RET(nc_lyd_find_child(node, "inline-definition", 0, &inline_def), 1); + NC_CHECK_RET(nc_lyd_find_child(node, "central-truststore-reference", 0, &truststore_ref), 1); + NC_CHECK_RET(nc_lyd_find_child(node, "libnetconf2-netconf-server:use-system-keys", 0, &system), 1); + if (inline_def) { + NC_CHECK_RET(config_ssh_user_pubkey_inline(inline_def, op, user)); + } else if (truststore_ref) { + NC_CHECK_RET(config_ssh_user_pubkey_truststore(truststore_ref, op, user)); + } else { + assert(system); + NC_CHECK_RET(config_ssh_user_pubkey_system(system, op, user)); } -cleanup: - return ret; + return 0; } static int -nc_server_config_create_tls(struct nc_endpt *endpt) +config_ssh_user_hashed_password(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) { - endpt->ti = NC_TI_TLS; - endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls); - NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1); + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(user->password); + user->password = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(user->password); + user->password = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!user->password, 1); + } + user->password_last_modified = time(NULL); return 0; } static int -nc_server_config_ch_create_tls(struct nc_ch_endpt *ch_endpt) +config_ssh_user_password(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) { - ch_endpt->ti = NC_TI_TLS; - ch_endpt->opts.tls = calloc(1, sizeof(struct nc_server_tls_opts)); - NC_CHECK_ERRMEM_RET(!ch_endpt->opts.tls, 1); + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* configure hashed password */ + NC_CHECK_RET(nc_lyd_find_child(node, "hashed-password", 0, &n)); + if (n) { + NC_CHECK_RET(config_ssh_user_hashed_password(n, op, user)); + } + /* last modified leaf is config false, we can end */ return 0; } static int -nc_server_config_tls(const struct lyd_node *node, enum nc_operation op) +config_ssh_user_hostbased(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) { - struct nc_endpt *endpt; - struct nc_bind *bind; - struct nc_ch_endpt *ch_endpt; - struct nc_ch_client *ch_client = NULL; - int ret = 0; - - assert(!strcmp(LYD_NAME(node), "tls")); - - if (is_listen(node)) { - if (nc_server_config_get_endpt(node, &endpt, &bind)) { - ret = 1; - goto cleanup; - } + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} - 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_opts(bind, endpt->opts.tls); - } - } else { - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - goto cleanup; - } +static int +config_ssh_user_none(const struct lyd_node *node, enum nc_operation parent_op, struct nc_auth_client *user) +{ + enum nc_operation op; - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - if (op == NC_OP_CREATE) { - ret = nc_server_config_ch_create_tls(ch_endpt); - if (ret) { - goto cleanup; - } - } else if (op == NC_OP_DELETE) { - nc_server_config_del_tls_opts(NULL, ch_endpt->opts.tls); - } + if (op == NC_OP_DELETE) { + user->none_enabled = 0; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + user->none_enabled = 1; } -cleanup: - return ret; + return 0; } -/* leaf */ static int -nc_server_config_local_address(const struct lyd_node *node, enum nc_operation op) +config_ssh_user_keyboard_interactive_system(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_auth_client *user) { - int ret = 0; - struct nc_endpt *endpt; - struct nc_bind *bind; - struct nc_ch_client *ch_client = NULL; - struct nc_ch_endpt *ch_endpt; + enum nc_operation op; - assert(!strcmp(LYD_NAME(node), "local-address")); + NC_NODE_GET_OP(node, parent_op, &op); - 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; - } + if (op == NC_OP_DELETE) { + user->kbdint_method = NC_KBDINT_AUTH_METHOD_NONE; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + user->kbdint_method = NC_KBDINT_AUTH_METHOD_SYSTEM; + } - free(bind->address); - bind->address = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!bind->address, ret = 1, cleanup); - } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - goto cleanup; - } + return 0; +} - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } +static int +config_ssh_user_keyboard_interactive(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_auth_client *user) +{ + struct lyd_node *system = NULL; + enum nc_operation op; - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(ch_endpt->src_addr); - ch_endpt->src_addr = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!ch_endpt->src_addr, ret = 1, cleanup); - } else if (op == NC_OP_DELETE) { - free(ch_endpt->src_addr); - ch_endpt->src_addr = NULL; - } + NC_NODE_GET_OP(node, parent_op, &op); + + /* config method choice, currently only use-system-auth is supported */ + NC_CHECK_RET(nc_lyd_find_child(node, "use-system-auth", 0, &system)); + if (system) { + NC_CHECK_RET(config_ssh_user_keyboard_interactive_system(system, op, user)); } -cleanup: - return ret; + return 0; } -/* leaf with default value */ static int -nc_server_config_local_port(const struct lyd_node *node, enum nc_operation op) +config_ssh_user(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - int ret = 0; - struct nc_endpt *endpt; - struct nc_bind *bind; - struct nc_ch_client *ch_client = NULL; - struct nc_ch_endpt *ch_endpt; - - assert(!strcmp(LYD_NAME(node), "local-port")); - - 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; - } + enum nc_operation op; + struct lyd_node *n; + struct nc_auth_client *user = NULL; + const char *name; + uint32_t i; - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - bind->port = ((struct lyd_node_term *)node)->value.uint16; - } else { - /* delete -> set to default */ - bind->port = 0; - } - } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + /* user name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_endpt->src_port = ((struct lyd_node_term *)node)->value.uint16; - } else if (op == NC_OP_DELETE) { - /* delete -> set to default */ - ch_endpt->src_port = 0; + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the user we are deleting */ + LY_ARRAY_FOR(ssh->auth_clients, i) { + if (!strcmp(ssh->auth_clients[i].username, name)) { + break; + } } + assert(i < LY_ARRAY_COUNT(ssh->auth_clients)); + user = &ssh->auth_clients[i]; + } else if (op == NC_OP_CREATE) { + /* create a new user */ + LY_ARRAY_NEW_RET(LYD_CTX(node), ssh->auth_clients, user, 1); } -cleanup: - return ret; -} + /* config user name */ + NC_CHECK_RET(config_ssh_user_name(n, op, user)); -/* NP container */ -static int -nc_server_config_keepalives(const struct lyd_node *node, enum 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 = NULL; + /* config public keys */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-keys", 0, &n)); + if (n) { + NC_CHECK_RET(config_ssh_user_public_keys(n, op, user)); + } - assert(!strcmp(LYD_NAME(node), "keepalives")); + /* config password */ + NC_CHECK_RET(nc_lyd_find_child(node, "password", 1, &n)); + NC_CHECK_RET(config_ssh_user_password(n, op, user)); - 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; - } + /* config hostbased */ + NC_CHECK_RET(nc_lyd_find_child(node, "hostbased", 0, &n)); + if (n) { + NC_CHECK_RET(config_ssh_user_hostbased(n, op)); + } - if (op == NC_OP_CREATE) { - endpt->ka.enabled = 1; - } else { - endpt->ka.enabled = 0; - } - } else if (is_ch(node) && equal_parent_name(node, 1, "tcp-client-parameters")) { - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - goto cleanup; - } + /* config none */ + NC_CHECK_RET(nc_lyd_find_child(node, "none", 0, &n)); + if (n) { + NC_CHECK_RET(config_ssh_user_none(n, op, user)); + } - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + /* config keyboard-interactive (augment) */ + NC_CHECK_RET(nc_lyd_find_child(node, "libnetconf2-netconf-server:keyboard-interactive", 1, &n)); + NC_CHECK_RET(config_ssh_user_keyboard_interactive(n, op, user)); - if (op == NC_OP_CREATE) { - ch_endpt->ka.enabled = 1; - } else { - ch_endpt->ka.enabled = 0; + /* all children processed, we can now delete the user */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(ssh->auth_clients) - 1) { + ssh->auth_clients[i] = ssh->auth_clients[LY_ARRAY_COUNT(ssh->auth_clients) - 1]; } + LY_ARRAY_DECREMENT_FREE(ssh->auth_clients); } -cleanup: - return ret; + return 0; } -/* leaf with default value */ static int -nc_server_config_idle_time(const struct lyd_node *node, enum nc_operation op) +config_ssh_users(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - int ret = 0; - struct nc_endpt *endpt; - struct nc_bind *bind; - struct nc_ch_endpt *ch_endpt; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + struct lyd_node *n; - assert(!strcmp(LYD_NAME(node), "idle-time")); + NC_NODE_GET_OP(node, parent_op, &op); - 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; - } + /* config all users */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_ssh_user(n, op, ssh)); + } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16; - } else { - /* delete -> set to default */ - endpt->ka.idle_time = 7200; - } - } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - goto cleanup; - } + return 0; +} - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } +static int +config_ssh_ca_certs(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_endpt->ka.idle_time = ((struct lyd_node_term *)node)->value.uint16; - } else { - /* delete -> set to default */ - ch_endpt->ka.idle_time = 7200; - } +static int +config_ssh_ee_certs(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} + +static int +config_ssh_auth_timeout(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), + struct nc_server_ssh_opts *ssh) +{ + /* default value always present */ + ssh->auth_timeout = strtoul(lyd_get_value(node), NULL, 10); + return 0; +} + +static int +config_endpt_reference(const struct lyd_node *node, enum nc_operation parent_op, char **endpt_ref) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(*endpt_ref); + *endpt_ref = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(*endpt_ref); + *endpt_ref = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!*endpt_ref, 1); } -cleanup: - return ret; + return 0; } -/* leaf with default value */ static int -nc_server_config_max_probes(const struct lyd_node *node, enum nc_operation op) +config_ssh_client_auth(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - int ret = 0; - struct nc_endpt *endpt; - struct nc_bind *bind; - struct nc_ch_endpt *ch_endpt; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + struct lyd_node *n; - assert(!strcmp(LYD_NAME(node), "max-probes")); + NC_NODE_GET_OP(node, parent_op, &op); - 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; - } + /* config users */ + NC_CHECK_RET(nc_lyd_find_child(node, "users", 0, &n)); + if (n) { + NC_CHECK_RET(config_ssh_users(n, op, ssh)); + } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16; - } else { - /* delete -> set to default */ - endpt->ka.max_probes = 9; - } - } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - goto cleanup; - } + /* config ca-certs */ + NC_CHECK_RET(nc_lyd_find_child(node, "ca-certs", 0, &n)); + if (n) { + NC_CHECK_RET(config_ssh_ca_certs(n, op)); + } - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + /* config ee-certs */ + NC_CHECK_RET(nc_lyd_find_child(node, "ee-certs", 0, &n)); + if (n) { + NC_CHECK_RET(config_ssh_ee_certs(n, op)); + } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_endpt->ka.max_probes = ((struct lyd_node_term *)node)->value.uint16; - } else { - /* delete -> set to default */ - ch_endpt->ka.max_probes = 9; - } + /* config auth timeout (augment) */ + NC_CHECK_RET(nc_lyd_find_child(node, "libnetconf2-netconf-server:auth-timeout", 1, &n)); + NC_CHECK_RET(config_ssh_auth_timeout(n, op, ssh)); + + /* config endpoint reference (augment) */ + NC_CHECK_RET(nc_lyd_find_child(node, "libnetconf2-netconf-server:endpoint-reference", 0, &n)); + if (n) { + NC_CHECK_RET(config_endpt_reference(n, op, &ssh->referenced_endpt_name)); } -cleanup: - return ret; + return 0; } -/* leaf with default value */ +/** + * @brief Delete an algorithm from a @p sep separated list of algorithms. + * + * @param[in,out] list @p sep separated list of algorithms. + * @param[in] alg Algorithm to delete. + * @param[in] sep Separator character. + * @return 0 on success, 1 on error. + */ static int -nc_server_config_probe_interval(const struct lyd_node *node, enum nc_operation op) +nc_server_config_del_alg(char *list, const char *alg, const char sep) { - int ret = 0; - struct nc_endpt *endpt; - struct nc_bind *bind; - struct nc_ch_endpt *ch_endpt; - struct nc_ch_client *ch_client = NULL; + char *pos, *next; + size_t alg_len = strlen(alg); + int found = 0; - assert(!strcmp(LYD_NAME(node), "probe-interval")); + if (!list) { + ERR(NULL, "No algorithms previously configured, cannot delete \"%s\".", alg); + return 1; + } - 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; + /* find the algorithm in the list */ + pos = list; + while ((next = strchr(pos, sep))) { + if (((size_t)(next - pos) == alg_len) && !strncmp(pos, alg, alg_len)) { + /* found the algorithm */ + found = 1; + break; } + pos = next + 1; + } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16; - } else { - /* delete -> set to default */ - endpt->ka.probe_interval = 75; - } - } else if (is_ch(node) && equal_parent_name(node, 2, "tcp-client-parameters")) { - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - goto cleanup; + if (!found) { + /* check the last element */ + if (!strcmp(pos, alg)) { + found = 1; } + } - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + if (!found) { + ERR(NULL, "Algorithm \"%s\" not previously configured, cannot be deleted.", alg); + return 1; + } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_endpt->ka.probe_interval = ((struct lyd_node_term *)node)->value.uint16; - } else { - /* delete -> set to default */ - ch_endpt->ka.probe_interval = 75; - } + /* delete the algorithm */ + if (next) { + /* not the last element, move the rest of the string to the left */ + memmove(pos, next + 1, strlen(next + 1) + 1); + } else { + /* the last element, just terminate the string here */ + *pos = '\0'; } -cleanup: - return ret; + return 0; } +/** + * @brief Add an algorithm to a @p sep separated list of algorithms. + * + * @param[in,out] list Pointer to a @p sep separated list of algorithms. Will be allocated if NULL. + * @param[in] alg Algorithm to add. + * @param[in] sep Separator character. + * @return 0 on success, 1 on error. + */ static int -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")); +nc_server_config_add_alg(char **list, const char *alg, const char sep) +{ + char *pos; + size_t alg_len = strlen(alg); + + if (*list) { + /* check for duplicates */ + pos = *list; + while ((pos = strchr(pos, sep))) { + if (((size_t)(pos - *list) == alg_len) && !strncmp(*list, alg, alg_len)) { + /* found the algorithm */ + WRN(NULL, "Algorithm \"%s\" already configured.", alg); + return 0; + } + pos++; + } + /* check the last element */ + if (!strcmp(*list, alg)) { + WRN(NULL, "Algorithm \"%s\" already configured.", alg); + return 0; + } + + /* add the algorithm to the end of the list */ + *list = nc_realloc(*list, strlen(*list) + 1 + alg_len + 1); + NC_CHECK_ERRMEM_RET(!*list, 1); + sprintf(*list + strlen(*list), "%c%s", sep, alg); + } else { + /* create a new list with the algorithm */ + *list = strdup(alg); + NC_CHECK_ERRMEM_RET(!*list, 1); + } - return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->hostkeys, sizeof *opts->hostkeys, &opts->hostkey_count); + return 0; } -/* list */ static int -nc_server_config_host_key(const struct lyd_node *node, enum nc_operation op) +config_hostkey_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - int ret = 0; - struct nc_hostkey *hostkey; - struct nc_server_ssh_opts *opts; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "host-key")); + enum nc_operation op; + const char *alg; - if (equal_parent_name(node, 1, "server-identity")) { - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - ret = 1; - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } + alg = lyd_get_value(node); + assert(alg); - if (op == NC_OP_CREATE) { - 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_client, &hostkey)) { - ret = 1; - goto cleanup; - } - nc_server_config_del_hostkey(opts, hostkey); + if (op == NC_OP_DELETE) { + /* delete the alg from the comma separated list */ + NC_CHECK_RET(nc_server_config_del_alg(ssh->hostkey_algs, alg, ',')); + if (!ssh->hostkey_algs[0]) { + /* the list is now empty, free it */ + free(ssh->hostkey_algs); + ssh->hostkey_algs = NULL; } + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* add the alg to the comma separated list, + * the value is either one of the enums from iana-ssh-pk-algs or + * it can contain a '@' character for custom algorithms. + * We can store their names just as they are and let libssh handle it later. */ + NC_CHECK_RET(nc_server_config_add_alg(&ssh->hostkey_algs, alg, ',')); } -cleanup: - return ret; + return 0; } -/* mandatory leaf */ static int -nc_server_config_public_key_format(const struct lyd_node *node, enum nc_operation op) +config_transport_param_hkalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - int ret = 0; - const char *format; - enum nc_pubkey_format pubkey_type; - struct nc_public_key *pubkey; - struct nc_hostkey *hostkey; - struct nc_server_tls_opts *opts; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + struct lyd_node *n; - assert(!strcmp(LYD_NAME(node), "public-key-format")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; + /* configure all host-key algorithms (leaf-lists) */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_hostkey_alg(n, op, ssh)); } - format = ((struct lyd_node_term *)node)->value.ident->name; - if (!strcmp(format, "ssh-public-key-format")) { - pubkey_type = NC_PUBKEY_FORMAT_SSH; - } 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; - } + return 0; +} - if (is_ssh(node) && equal_parent_name(node, 4, "server-identity")) { - /* SSH hostkey public key fmt */ - if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) { - ret = 1; - goto cleanup; - } +static int +config_kex_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) +{ + enum nc_operation op; + const char *alg; - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - hostkey->key.pubkey_type = pubkey_type; - } - } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { - /* SSH client auth public key fmt */ - if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) { - ret = 1; - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - pubkey->type = pubkey_type; - } - } else if (is_tls(node) && equal_parent_name(node, 3, "server-identity")) { - /* TLS server-identity */ - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } + alg = lyd_get_value(node); + assert(alg); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - opts->pubkey_type = pubkey_type; + if (op == NC_OP_DELETE) { + /* delete the alg from the comma separated list */ + NC_CHECK_RET(nc_server_config_del_alg(ssh->kex_algs, alg, ',')); + if (!ssh->kex_algs[0]) { + /* the list is now empty, free it */ + free(ssh->kex_algs); + ssh->kex_algs = NULL; } + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* add the alg to the comma separated list */ + NC_CHECK_RET(nc_server_config_add_alg(&ssh->kex_algs, alg, ',')); } -cleanup: - return ret; + return 0; } static int -nc_server_config_create_auth_key_public_key_list(const struct lyd_node *node, struct nc_auth_client *auth_client) +config_transport_param_kexalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - assert(!strcmp(LYD_NAME(node), "public-key")); + enum nc_operation op; + struct lyd_node *n; + + NC_NODE_GET_OP(node, parent_op, &op); - node = lyd_child(node); - assert(!strcmp(LYD_NAME(node), "name")); + /* configure all kex algorithms (leaf-lists) */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_kex_alg(n, op, ssh)); + } - return nc_server_config_realloc(lyd_get_value(node), (void **)&auth_client->pubkeys, sizeof *auth_client->pubkeys, - &auth_client->pubkey_count); + return 0; } static int -nc_server_config_replace_auth_key_public_key_leaf(const struct lyd_node *node, struct nc_public_key *pubkey) +config_enc_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - free(pubkey->data); - pubkey->data = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_RET(!pubkey->data, 1); + enum nc_operation op; + const char *alg; + + NC_NODE_GET_OP(node, parent_op, &op); + + alg = lyd_get_value(node); + assert(alg); + + if (op == NC_OP_DELETE) { + /* delete the alg from the comma separated list */ + NC_CHECK_RET(nc_server_config_del_alg(ssh->encryption_algs, alg, ',')); + if (!ssh->encryption_algs[0]) { + /* the list is now empty, free it */ + free(ssh->encryption_algs); + ssh->encryption_algs = NULL; + } + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* add the alg to the comma separated list */ + NC_CHECK_RET(nc_server_config_add_alg(&ssh->encryption_algs, alg, ',')); + } return 0; } static int -nc_server_config_replace_host_key_public_key(const struct lyd_node *node, struct nc_hostkey *hostkey) +config_transport_param_encalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - free(hostkey->key.pubkey_data); - hostkey->key.pubkey_data = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_RET(!hostkey->key.pubkey_data, 1); + enum nc_operation op; + struct lyd_node *n; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* configure all encryption algorithms (leaf-lists) */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_enc_alg(n, op, ssh)); + } return 0; } static int -nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, struct nc_server_tls_opts *opts) +config_mac_alg(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - free(opts->pubkey_data); - opts->pubkey_data = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_RET(!opts->pubkey_data, 1); + enum nc_operation op; + const char *alg; + + NC_NODE_GET_OP(node, parent_op, &op); + + alg = lyd_get_value(node); + assert(alg); + + if (op == NC_OP_DELETE) { + /* delete the alg from the comma separated list */ + NC_CHECK_RET(nc_server_config_del_alg(ssh->mac_algs, alg, ',')); + if (!ssh->mac_algs[0]) { + /* the list is now empty, free it */ + free(ssh->mac_algs); + ssh->mac_algs = NULL; + } + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* add the alg to the comma separated list */ + NC_CHECK_RET(nc_server_config_add_alg(&ssh->mac_algs, alg, ',')); + } return 0; } static int -nc_server_config_public_key(const struct lyd_node *node, enum nc_operation op) +config_transport_param_macalgs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) { - int ret = 0; - struct nc_hostkey *hostkey; - struct nc_auth_client *auth_client; - struct nc_public_key *pubkey; - struct nc_server_tls_opts *opts; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + struct lyd_node *n; - assert(!strcmp(LYD_NAME(node), "public-key")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; + /* configure all mac algorithms (leaf-lists) */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_mac_alg(n, op, ssh)); } - if (is_ssh(node) && equal_parent_name(node, 3, "host-key")) { - /* server's public-key, mandatory leaf */ - if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) { - ret = 1; - goto cleanup; - } + return 0; +} - /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */ - 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; - } +static int +config_ssh_transport_params(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) +{ + enum nc_operation op; + struct lyd_node *n; - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to local */ - hostkey->store = NC_STORE_LOCAL; + NC_NODE_GET_OP(node, parent_op, &op); - ret = nc_server_config_replace_host_key_public_key(node, hostkey); - if (ret) { - goto cleanup; - } - } - } else if (is_ssh(node) && equal_parent_name(node, 5, "client-authentication")) { - /* client auth pubkeys, list */ - if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) { - ret = 1; - goto cleanup; - } + /* config host-key */ + NC_CHECK_RET(nc_lyd_find_child(node, "host-key", 1, &n)); + NC_CHECK_RET(config_transport_param_hkalgs(n, op, ssh)); - if (op == NC_OP_CREATE) { - /* set to local */ - auth_client->store = NC_STORE_LOCAL; + /* config kex-algorithms */ + NC_CHECK_RET(nc_lyd_find_child(node, "key-exchange", 1, &n)); + NC_CHECK_RET(config_transport_param_kexalgs(n, op, ssh)); - 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, ch_client, &pubkey)) { - ret = 1; - goto cleanup; - } + /* config encryption-algorithms */ + NC_CHECK_RET(nc_lyd_find_child(node, "encryption", 1, &n)); + NC_CHECK_RET(config_transport_param_encalgs(n, op, ssh)); - nc_server_config_del_auth_client_pubkey(auth_client, pubkey); - } - } else if (is_ssh(node) && equal_parent_name(node, 6, "client-authentication")) { - /* client auth pubkey, leaf */ - if (nc_server_config_get_pubkey(node, ch_client, &pubkey)) { - ret = 1; - goto cleanup; - } + /* config mac-algorithms */ + NC_CHECK_RET(nc_lyd_find_child(node, "mac", 1, &n)); + NC_CHECK_RET(config_transport_param_macalgs(n, op, ssh)); - /* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */ - 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; - } + return 0; +} - 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 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 */ - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } +static int +config_ssh_keepalives(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} - /* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */ - 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; - } +static int +config_ssh_server_params(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_ssh_opts *ssh) +{ + struct lyd_node *n; + enum nc_operation op; - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to local */ - opts->store = NC_STORE_LOCAL; + NC_NODE_GET_OP(node, parent_op, &op); - ret = nc_server_config_tls_replace_server_public_key(node, opts); - if (ret) { - goto cleanup; - } - } + /* server identity */ + NC_CHECK_RET(nc_lyd_find_child(node, "server-identity", 1, &n)); + NC_CHECK_RET(config_ssh_server_identity(n, op, ssh)); + + /* client authentication */ + NC_CHECK_RET(nc_lyd_find_child(node, "client-authentication", 1, &n)); + NC_CHECK_RET(config_ssh_client_auth(n, op, ssh)); + + /* transport parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "transport-params", 0, &n)); + if (n) { + NC_CHECK_RET(config_ssh_transport_params(n, op, ssh)); } -cleanup: - return ret; + /* keepalives */ + NC_CHECK_RET(nc_lyd_find_child(node, "keepalives", 0, &n)); + if (n) { + NC_CHECK_RET(config_ssh_keepalives(n, op)); + } + + return 0; } -/* leaf */ static int -nc_server_config_private_key_format(const struct lyd_node *node, enum nc_operation op) +config_ssh_netconf_server_params(const struct lyd_node *UNUSED(node), enum nc_operation UNUSED(parent_op)) { - int ret = 0; - const char *format; - enum nc_privkey_format privkey_type; - struct nc_hostkey *hostkey; - struct nc_server_tls_opts *opts; - struct nc_ch_client *ch_client = NULL; - - (void) op; + /* nothing to do, this is just a container, its children are not supported in SSH yet */ + return 0; +} - assert(!strcmp(LYD_NAME(node), "private-key-format")); +static int +config_ssh(const struct lyd_node *node, enum nc_operation parent_op, struct nc_endpt *endpt) +{ + struct lyd_node *n; + enum nc_operation op; - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + NC_NODE_GET_OP(node, parent_op, &op); - format = ((struct lyd_node_term *)node)->value.ident->name; - if (!format) { - ret = 1; - goto cleanup; + /* create the ssh opts */ + if (!endpt->opts.ssh) { + /* op should not be NC_OP_DELETE if the diff is valid, otherwise this would have already been created */ + endpt->opts.ssh = calloc(1, sizeof *endpt->opts.ssh); + NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1); + endpt->ti = NC_TI_SSH; } - 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; - } + /* tcp server parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "tcp-server-parameters", 1, &n)); + NC_CHECK_RET(config_tcp_server_params(n, op, endpt)); - if (is_ssh(node)) { - /* ssh */ - if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) { - ret = 1; - goto cleanup; - } + /* ssh server parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "ssh-server-parameters", 1, &n)); + NC_CHECK_RET(config_ssh_server_params(n, op, endpt->opts.ssh)); - hostkey->key.privkey_type = privkey_type; - } else if (is_tls(node)) { - /* tls */ - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } + /* netconf server parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "netconf-server-parameters", 1, &n)); + NC_CHECK_RET(config_ssh_netconf_server_params(n, op)); - opts->privkey_type = privkey_type; + if (op == NC_OP_DELETE) { + free(endpt->opts.ssh); + endpt->opts.ssh = NULL; + endpt->ti = NC_TI_NONE; } -cleanup: - return ret; + return 0; } static int -nc_server_config_cleartext_private_key(const struct lyd_node *node, enum nc_operation op) +config_cert_data(const struct lyd_node *node, enum nc_operation parent_op, struct nc_certificate *cert) { - int ret = 0; - struct nc_hostkey *hostkey; - struct nc_server_tls_opts *opts; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "cleartext-private-key")); - - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } - - if (is_ssh(node)) { - /* ssh */ - if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) { - ret = 1; - goto cleanup; - } + enum nc_operation op; - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(hostkey->key.privkey_data); - hostkey->key.privkey_data = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!hostkey->key.privkey_data, ret = 1, cleanup); - } else { - free(hostkey->key.privkey_data); - hostkey->key.privkey_data = NULL; - } - } else if (is_tls(node)) { - /* tls */ - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(opts->privkey_data); - opts->privkey_data = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!opts->privkey_data, ret = 1, cleanup); - } else { - free(opts->privkey_data); - opts->privkey_data = NULL; - } + if (op == NC_OP_DELETE) { + free(cert->data); + cert->data = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(cert->data); + cert->data = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!cert->data, 1); } -cleanup: - return ret; + return 0; } -/* leaf */ static int -nc_server_config_keystore_reference(const struct lyd_node *node, enum nc_operation op) +config_generate_csr(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) { - int ret = 0; - struct nc_hostkey *hostkey; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "central-keystore-reference")); - - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } - - if (is_ssh(node) && equal_parent_name(node, 3, "server-identity")) { - if (nc_server_config_get_hostkey(node, ch_client, &hostkey)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to keystore */ - hostkey->store = NC_STORE_KEYSTORE; - - free(hostkey->ks_ref); - hostkey->ks_ref = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!hostkey->ks_ref, ret = 1, cleanup); - } else if (op == NC_OP_DELETE) { - free(hostkey->ks_ref); - hostkey->ks_ref = NULL; - } - } - -cleanup: - return ret; + CONFIG_LOG_UNSUPPORTED(node); + return 0; } static int -nc_server_config_create_auth_client(const struct lyd_node *node, struct nc_server_ssh_opts *opts) +config_cert_expiration(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) { - node = lyd_child(node); - assert(!strcmp(LYD_NAME(node), "name")); - - return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->auth_clients, sizeof *opts->auth_clients, &opts->client_count); + CONFIG_LOG_UNSUPPORTED(node); + return 0; } -/* list */ static int -nc_server_config_user(const struct lyd_node *node, enum nc_operation op) +config_tls_server_ident_cert_inline(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *opts) { - int ret = 0; - struct nc_auth_client *auth_client; - struct nc_server_ssh_opts *opts; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + struct lyd_node *n, *cleartext, *hidden, *encrypted; - assert(!strcmp(LYD_NAME(node), "user")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + opts->cert_store = NC_STORE_LOCAL; - if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; + /* config public key format */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key-format", 0, &n)); + if (n) { + NC_CHECK_RET(config_pubkey_format(n, op, &opts->local.key.pubkey), 1); } - if (op == NC_OP_CREATE) { - ret = nc_server_config_create_auth_client(node, opts); - if (ret) { - goto cleanup; - } - } else if (op == NC_OP_DELETE) { - if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) { - ret = 1; - goto cleanup; - } - - nc_server_config_del_auth_client(opts, auth_client); + /* config public key data */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key", 0, &n)); + if (n) { + NC_CHECK_RET(config_pubkey_data(n, op, &opts->local.key.pubkey), 1); } -cleanup: - return ret; -} + /* config private key format */ + NC_CHECK_RET(nc_lyd_find_child(node, "private-key-format", 0, &n)); + if (n) { + NC_CHECK_RET(config_privkey_format(n, op, &opts->local.key.privkey), 1); + } -static int -nc_server_config_auth_timeout(const struct lyd_node *node, enum nc_operation op) -{ - int ret = 0; - struct nc_server_ssh_opts *opts; - struct nc_ch_client *ch_client = NULL; + /* config private key data choice */ + NC_CHECK_RET(nc_lyd_find_child(node, "cleartext-private-key", 0, &cleartext)); + NC_CHECK_RET(nc_lyd_find_child(node, "hidden-private-key", 0, &hidden)); + NC_CHECK_RET(nc_lyd_find_child(node, "encrypted-private-key", 0, &encrypted)); + if (cleartext) { + NC_CHECK_RET(config_cleartext_privkey_data(cleartext, op, &opts->local.key.privkey), 1); + } else if (hidden) { + NC_CHECK_RET(config_hidden_privkey_data(hidden, op), 1); + } else { + assert(encrypted); + NC_CHECK_RET(config_encrypted_privkey_data(encrypted, op), 1); + } - assert(!strcmp(LYD_NAME(node), "auth-timeout")); + /* config certificate data */ + NC_CHECK_RET(nc_lyd_find_child(node, "cert-data", 0, &n)); + if (n) { + NC_CHECK_RET(config_cert_data(n, op, &opts->local.cert), 1); + } - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; + /* config generate csr */ + NC_CHECK_RET(nc_lyd_find_child(node, "generate-csr", 0, &n)); + if (n) { + NC_CHECK_RET(config_generate_csr(n, op), 1); } - if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; + /* config certificate expiration */ + NC_CHECK_RET(nc_lyd_find_child(node, "certificate-expiration", 0, &n)); + if (n) { + NC_CHECK_RET(config_cert_expiration(n, op), 1); } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - opts->auth_timeout = ((struct lyd_node_term *)node)->value.uint16; + if (op == NC_OP_DELETE) { + opts->cert_store = NC_STORE_UNKNOWN; } -cleanup: - return ret; + return 0; } -/* leaf */ static int -nc_server_config_truststore_reference(const struct lyd_node *node, enum nc_operation op) +config_tls_server_ident_cert_keystore_asym_key_ref(const struct lyd_node *node, + enum nc_operation parent_op, struct nc_server_tls_opts *tls) { - int ret = 0; - struct nc_auth_client *auth_client; - struct nc_ch_client *ch_client = NULL; - struct nc_server_tls_opts *opts; - struct nc_cert_grouping *certs_grp; + enum nc_operation op; - assert(!strcmp(LYD_NAME(node), "central-truststore-reference")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; + if (op == NC_OP_DELETE) { + free(tls->keystore.asym_key_ref); + tls->keystore.asym_key_ref = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(tls->keystore.asym_key_ref); + tls->keystore.asym_key_ref = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!tls->keystore.asym_key_ref, 1); } - if (is_ssh(node) && equal_parent_name(node, 1, "public-keys")) { - if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to truststore */ - auth_client->store = NC_STORE_TRUSTSTORE; - - free(auth_client->ts_ref); - auth_client->ts_ref = strdup(lyd_get_value(node)); - 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; - } - } 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, ch_client, &opts)) { - ret = 1; - goto cleanup; - } + return 0; +} - if (equal_parent_name(node, 1, "ca-certs")) { - certs_grp = &opts->ca_certs; - } else { - certs_grp = &opts->ee_certs; - } +static int +config_tls_server_ident_cert_keystore_cert_ref(const struct lyd_node *node, + enum nc_operation parent_op, struct nc_server_tls_opts *tls) +{ + enum nc_operation op; - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to truststore */ - certs_grp->store = NC_STORE_TRUSTSTORE; + NC_NODE_GET_OP(node, parent_op, &op); - free(certs_grp->ts_ref); - certs_grp->ts_ref = strdup(lyd_get_value(node)); - 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; - } + if (op == NC_OP_DELETE) { + free(tls->keystore.cert_ref); + tls->keystore.cert_ref = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(tls->keystore.cert_ref); + tls->keystore.cert_ref = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!tls->keystore.cert_ref, 1); } -cleanup: - return ret; + return 0; } static int -nc_server_config_use_system_keys(const struct lyd_node *node, enum nc_operation op) +config_tls_server_ident_cert_keystore(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_tls_opts *tls) { - int ret = 0; - struct nc_auth_client *auth_client; - struct nc_ch_client *ch_client = NULL; + struct lyd_node *n; + enum nc_operation op; - assert(!strcmp(LYD_NAME(node), "use-system-keys")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; + tls->cert_store = NC_STORE_KEYSTORE; + + /* config asymmetric key reference */ + NC_CHECK_RET(nc_lyd_find_child(node, "asymmetric-key", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_server_ident_cert_keystore_asym_key_ref(n, op, tls), 1); } - if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) { - ret = 1; - goto cleanup; + /* config certificate reference */ + NC_CHECK_RET(nc_lyd_find_child(node, "certificate", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_server_ident_cert_keystore_cert_ref(n, op, tls), 1); } - if (op == NC_OP_CREATE) { - auth_client->store = NC_STORE_SYSTEM; + if (op == NC_OP_DELETE) { + tls->cert_store = NC_STORE_UNKNOWN; } -cleanup: - return ret; + return 0; } static int -nc_server_config_public_keys(const struct lyd_node *node, enum nc_operation op) +config_tls_server_ident_certificate(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { - int ret = 0; - struct nc_auth_client *auth_client; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "public-keys")); - - /* only do something on delete */ - if (op != NC_OP_DELETE) { - return 0; - } + struct lyd_node *inline_def, *keystore_ref; + enum nc_operation op; - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + NC_NODE_GET_OP(node, parent_op, &op); - if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) { - ret = 1; - goto cleanup; + /* config inline-definition / keystore ref choice */ + NC_CHECK_RET(nc_lyd_find_child(node, "inline-definition", 0, &inline_def)); + NC_CHECK_RET(nc_lyd_find_child(node, "central-keystore-reference", 0, &keystore_ref)); + if (inline_def) { + NC_CHECK_RET(config_tls_server_ident_cert_inline(inline_def, op, tls)); + } else { + assert(keystore_ref); + NC_CHECK_RET(config_tls_server_ident_cert_keystore(keystore_ref, op, tls)); } - nc_server_config_del_auth_client_pubkeys(auth_client); - -cleanup: - return ret; + return 0; } -/* leaf */ static int -nc_server_config_password(const struct lyd_node *node, enum nc_operation op) +config_tls_server_ident_raw_key(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) { - int ret = 0; - struct nc_auth_client *auth_client; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "password")); + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } +static int +config_tls_server_ident_tls12_psk(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} - if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) { - ret = 1; - goto cleanup; - } +static int +config_tls_server_ident_tls13_epsk(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(auth_client->password); - auth_client->password = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!auth_client->password, ret = 1, cleanup); +static int +config_tls_server_identity(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) +{ + struct lyd_node *certificate, *raw_private_key, *tls12_psk, *tls13_epsk; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* config authentication type choice node */ + NC_CHECK_RET(nc_lyd_find_child(node, "certificate", 0, &certificate)); + NC_CHECK_RET(nc_lyd_find_child(node, "raw-private-key", 0, &raw_private_key)); + NC_CHECK_RET(nc_lyd_find_child(node, "tls12-psk", 0, &tls12_psk)); + NC_CHECK_RET(nc_lyd_find_child(node, "tls13-epsk", 0, &tls13_epsk)); + if (certificate) { + NC_CHECK_RET(config_tls_server_ident_certificate(certificate, op, tls)); + } else if (raw_private_key) { + NC_CHECK_RET(config_tls_server_ident_raw_key(raw_private_key, op)); + } else if (tls12_psk) { + NC_CHECK_RET(config_tls_server_ident_tls12_psk(tls12_psk, op)); } else { - free(auth_client->password); - auth_client->password = NULL; + assert(tls13_epsk); + NC_CHECK_RET(config_tls_server_ident_tls13_epsk(tls13_epsk, op)); } -cleanup: - return ret; + return 0; } static int -nc_server_config_keyboard_interactive(const struct lyd_node *node, enum nc_operation op) +config_cert_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_certificate *cert) { - struct nc_auth_client *auth_client; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "keyboard-interactive")); - - if (op != NC_OP_DELETE) { - /* only do something on delete */ - return 0; - } + enum nc_operation op; - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + NC_NODE_GET_OP(node, parent_op, &op); - if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) { - return 1; + if (op == NC_OP_DELETE) { + free(cert->name); + cert->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(cert->name); + cert->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!cert->name, 1); } - /* delete the keyboard-interactive authentication method */ - auth_client->kbdint_method = NC_KBDINT_AUTH_METHOD_NONE; - return 0; } static int -nc_server_config_use_system_auth(const struct lyd_node *node, enum nc_operation op) +config_tls_client_auth_ca_cert(const struct lyd_node *node, + enum nc_operation parent_op, struct nc_server_tls_client_auth *client_auth) { - int ret = 0; - struct nc_auth_client *auth_client; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + struct lyd_node *n; + const char *name; + LY_ARRAY_COUNT_TYPE i; + struct nc_certificate *cert = NULL; - assert(!strcmp(LYD_NAME(node), "use-system-auth")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; + /* config ca-cert name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the ca-cert we are deleting/modifying */ + LY_ARRAY_FOR(client_auth->ca_certs, i) { + if (!strcmp(client_auth->ca_certs[i].name, name)) { + break; + } + } + assert(i < LY_ARRAY_COUNT(client_auth->ca_certs)); + cert = &client_auth->ca_certs[i]; + } else if (op == NC_OP_CREATE) { + /* create a new ca-cert */ + LY_ARRAY_NEW_RET(LYD_CTX(node), client_auth->ca_certs, cert, 1); } - if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) { - ret = 1; - goto cleanup; + /* config ca-cert name */ + NC_CHECK_RET(config_cert_name(n, op, cert)); + + /* config ca-cert data */ + NC_CHECK_RET(nc_lyd_find_child(node, "cert-data", 1, &n)); + NC_CHECK_RET(config_cert_data(n, op, cert)); + + /* config certificate expiration */ + NC_CHECK_RET(nc_lyd_find_child(node, "certificate-expiration", 0, &n)); + if (n) { + NC_CHECK_RET(config_cert_expiration(n, op), 1); } - if (op == NC_OP_CREATE) { - auth_client->kbdint_method = NC_KBDINT_AUTH_METHOD_SYSTEM; - } else { - auth_client->kbdint_method = NC_KBDINT_AUTH_METHOD_NONE; + /* all children processed, we can now delete the ca-cert */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(client_auth->ca_certs) - 1) { + client_auth->ca_certs[i] = client_auth->ca_certs[LY_ARRAY_COUNT(client_auth->ca_certs) - 1]; + } + LY_ARRAY_DECREMENT_FREE(client_auth->ca_certs); } -cleanup: - return ret; + return 0; } -/* leaf */ static int -nc_server_config_none(const struct lyd_node *node, enum nc_operation op) +config_tls_client_auth_ca_certs_inline(const struct lyd_node *node, + enum nc_operation parent_op, struct nc_server_tls_client_auth *client_auth) { - int ret = 0; - struct nc_auth_client *auth_client; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + struct lyd_node *n; - assert(!strcmp(LYD_NAME(node), "none")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + client_auth->ca_certs_store = NC_STORE_LOCAL; - if (nc_server_config_get_auth_client(node, ch_client, &auth_client)) { - ret = 1; - goto cleanup; + /* configure all the ca-certs */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_tls_client_auth_ca_cert(n, op, client_auth)); } - if (op == NC_OP_CREATE) { - auth_client->none_enabled = 1; - } else { - auth_client->none_enabled = 0; + if (op == NC_OP_DELETE) { + client_auth->ca_certs_store = NC_STORE_UNKNOWN; } -cleanup: - return ret; + return 0; } static int -nc_server_config_delete_substring(const char *haystack, const char *needle, const char delim) +config_tls_client_auth_ca_certs_truststore(const struct lyd_node *node, + enum nc_operation parent_op, struct nc_server_tls_client_auth *client_auth) { - size_t needle_len = strlen(needle); - char *substr; - int substr_found = 0, ret = 0; + enum nc_operation op; - 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; + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(client_auth->ca_cert_bag_ts_ref); + client_auth->ca_cert_bag_ts_ref = NULL; + client_auth->ca_certs_store = NC_STORE_UNKNOWN; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(client_auth->ca_cert_bag_ts_ref); + client_auth->ca_cert_bag_ts_ref = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!client_auth->ca_cert_bag_ts_ref, 1); + client_auth->ca_certs_store = NC_STORE_TRUSTSTORE; } - return ret; + return 0; } static int -nc_server_config_transport_params(const char *algorithm, char **alg_store, enum nc_operation op) +config_tls_client_auth_ca_certs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_client_auth *client_auth) { - int ret = 0, r; - char *alg = NULL; + struct lyd_node *inline_def, *truststore_ref; + enum nc_operation op; - if (!strncmp(algorithm, "openssh-", 8)) { - /* if the name starts with openssh, convert it to it's original libssh accepted form */ - r = asprintf(&alg, "%s@openssh.com", algorithm + 8); - NC_CHECK_ERRMEM_GOTO(r == -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 */ - r = asprintf(&alg, "%s@libssh.org", algorithm + 7); - NC_CHECK_ERRMEM_GOTO(r == -1, ret = 1; alg = NULL, cleanup); - } else { - alg = strdup(algorithm); - NC_CHECK_ERRMEM_GOTO(!alg, ret = 1, cleanup); - } + NC_NODE_GET_OP(node, parent_op, &op); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - if (!*alg_store) { - /* first call */ - *alg_store = strdup(alg); - 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); - NC_CHECK_ERRMEM_GOTO(!*alg_store, ret = 1, cleanup); - strcat(*alg_store, ","); - strcat(*alg_store, alg); - } + /* config inline-definition / truststore reference choice */ + NC_CHECK_RET(nc_lyd_find_child(node, "inline-definition", 0, &inline_def), 1); + NC_CHECK_RET(nc_lyd_find_child(node, "central-truststore-reference", 0, &truststore_ref), 1); + if (inline_def) { + NC_CHECK_RET(config_tls_client_auth_ca_certs_inline(inline_def, op, client_auth)); } else { - /* delete */ - 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); - goto cleanup; - } + assert(truststore_ref); + NC_CHECK_RET(config_tls_client_auth_ca_certs_truststore(truststore_ref, op, client_auth)); } -cleanup: - free(alg); - return ret; + return 0; } -/* leaf-list */ static int -nc_server_config_host_key_alg(const struct lyd_node *node, enum nc_operation op) +config_tls_client_auth_ee_cert(const struct lyd_node *node, + enum nc_operation parent_op, struct nc_server_tls_client_auth *client_auth) { - int ret = 0; - const char *alg; - struct nc_server_ssh_opts *opts; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + struct lyd_node *n; + const char *name; + LY_ARRAY_COUNT_TYPE i; + struct nc_certificate *cert = NULL; - assert(!strcmp(LYD_NAME(node), "host-key-alg")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; + /* ee-cert name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the ee-cert we are deleting/modifying */ + LY_ARRAY_FOR(client_auth->ee_certs, i) { + if (!strcmp(client_auth->ee_certs[i].name, name)) { + break; + } + } + assert(i < LY_ARRAY_COUNT(client_auth->ee_certs)); + cert = &client_auth->ee_certs[i]; + } else if (op == NC_OP_CREATE) { + /* create a new ee-cert */ + LY_ARRAY_NEW_RET(LYD_CTX(node), client_auth->ee_certs, cert, 1); } - if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; + /* config ee-cert name */ + NC_CHECK_RET(config_cert_name(n, op, cert)); + + /* config ee-cert data */ + NC_CHECK_RET(nc_lyd_find_child(node, "cert-data", 0, &n)); + NC_CHECK_RET(config_cert_data(n, op, cert)); + + /* config certificate expiration */ + NC_CHECK_RET(nc_lyd_find_child(node, "certificate-expiration", 0, &n)); + if (n) { + NC_CHECK_RET(config_cert_expiration(n, op), 1); } - /* get the algorithm name and append it to supported algs */ - alg = ((struct lyd_node_term *)node)->value.ident->name; - if (nc_server_config_transport_params(alg, &opts->hostkey_algs, op)) { - ret = 1; - goto cleanup; + /* all children processed, we can now delete the ee-cert */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(client_auth->ee_certs) - 1) { + client_auth->ee_certs[i] = client_auth->ee_certs[LY_ARRAY_COUNT(client_auth->ee_certs) - 1]; + } + LY_ARRAY_DECREMENT_FREE(client_auth->ee_certs); } -cleanup: - return ret; + return 0; } -/* leaf-list */ static int -nc_server_config_kex_alg(const struct lyd_node *node, enum nc_operation op) +config_tls_client_auth_ee_certs_inline(const struct lyd_node *node, + enum nc_operation parent_op, struct nc_server_tls_client_auth *client_auth) { - int ret = 0; - const char *alg; - struct nc_server_ssh_opts *opts; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + struct lyd_node *n; - assert(!strcmp(LYD_NAME(node), "key-exchange-alg")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + client_auth->ee_certs_store = NC_STORE_LOCAL; - if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; + /* configure all the ee-certs */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_tls_client_auth_ee_cert(n, op, client_auth)); } - /* get the algorithm name and append it to supported algs */ - alg = ((struct lyd_node_term *)node)->value.ident->name; - if (nc_server_config_transport_params(alg, &opts->kex_algs, op)) { - ret = 1; - goto cleanup; + if (op == NC_OP_DELETE) { + client_auth->ee_certs_store = NC_STORE_UNKNOWN; } -cleanup: - return ret; + return 0; } -/* leaf-list */ static int -nc_server_config_encryption_alg(const struct lyd_node *node, enum nc_operation op) +config_tls_client_auth_ee_certs_truststore(const struct lyd_node *node, + enum nc_operation parent_op, struct nc_server_tls_client_auth *client_auth) { - int ret = 0; - const char *alg; - struct nc_server_ssh_opts *opts; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; - assert(!strcmp(LYD_NAME(node), "encryption-alg")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; + if (op == NC_OP_DELETE) { + free(client_auth->ee_cert_bag_ts_ref); + client_auth->ee_cert_bag_ts_ref = NULL; + client_auth->ee_certs_store = NC_STORE_UNKNOWN; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(client_auth->ee_cert_bag_ts_ref); + client_auth->ee_cert_bag_ts_ref = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!client_auth->ee_cert_bag_ts_ref, 1); + client_auth->ee_certs_store = NC_STORE_TRUSTSTORE; } - if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } + return 0; +} - /* get the algorithm name and append it to supported algs */ - alg = ((struct lyd_node_term *)node)->value.ident->name; +static int +config_tls_client_auth_ee_certs(const struct lyd_node *node, + enum nc_operation parent_op, struct nc_server_tls_client_auth *client_auth) +{ + struct lyd_node *inline_def, *truststore_ref; + enum nc_operation op; - /* YANG IDs cannot begin with a number, need to convert them to the correct form */ - if (!strcmp(alg, "triple-des-cbc")) { - alg = "3des-cbc"; - } else if (!strcmp(alg, "triple-des-ctr")) { - alg = "3des-ctr"; - } + NC_NODE_GET_OP(node, parent_op, &op); - if (nc_server_config_transport_params(alg, &opts->encryption_algs, op)) { - ret = 1; - goto cleanup; + /* config inline-definition / truststore reference choice */ + NC_CHECK_RET(nc_lyd_find_child(node, "inline-definition", 0, &inline_def), 1); + NC_CHECK_RET(nc_lyd_find_child(node, "central-truststore-reference", 0, &truststore_ref), 1); + if (inline_def) { + NC_CHECK_RET(config_tls_client_auth_ee_certs_inline(inline_def, op, client_auth)); + } else { + assert(truststore_ref); + NC_CHECK_RET(config_tls_client_auth_ee_certs_truststore(truststore_ref, op, client_auth)); } -cleanup: - return ret; + return 0; } -/* leaf-list */ static int -nc_server_config_mac_alg(const struct lyd_node *node, enum nc_operation op) +config_tls_client_auth_raw_public_keys(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) { - int ret = 0; - const char *alg; - struct nc_server_ssh_opts *opts; - struct nc_ch_client *ch_client = NULL; + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} - assert(!strcmp(LYD_NAME(node), "mac-alg")); +static int +config_tls_client_auth_tls12_psks(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } +static int +config_tls_client_auth_tls13_epsks(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} - if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; +static int +config_tls_client_auth(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) +{ + enum nc_operation op; + struct lyd_node *n; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* config certificate authority certs */ + NC_CHECK_RET(nc_lyd_find_child(node, "ca-certs", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_client_auth_ca_certs(n, op, &tls->client_auth)); } - /* get the algorithm name and append it to supported algs */ - alg = ((struct lyd_node_term *)node)->value.ident->name; - if (nc_server_config_transport_params(alg, &opts->mac_algs, op)) { - ret = 1; - goto cleanup; + /* config end entity certs */ + NC_CHECK_RET(nc_lyd_find_child(node, "ee-certs", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_client_auth_ee_certs(n, op, &tls->client_auth)); } -cleanup: - return ret; -} + /* config raw public keys */ + NC_CHECK_RET(nc_lyd_find_child(node, "raw-public-keys", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_client_auth_raw_public_keys(n, op)); + } -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; + /* config tls12-psks */ + NC_CHECK_RET(nc_lyd_find_child(node, "tls12-psks", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_client_auth_tls12_psks(n, op)); } - 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; - } + /* config tls13-epsks */ + NC_CHECK_RET(nc_lyd_find_child(node, "tls13-epsks", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_client_auth_tls13_epsks(n, op)); + } - /* continue further */ - return nc_server_config_check_endpt_reference_cycle(original, next); + /* config endpoint reference (augment) */ + NC_CHECK_RET(nc_lyd_find_child(node, "libnetconf2-netconf-server:endpoint-reference", 0, &n)); + if (n) { + NC_CHECK_RET(config_endpt_reference(n, op, &tls->referenced_endpt_name)); } + + return 0; } /** - * @brief Set all endpoint references. + * @brief Convert string representation of TLS version YANG identity to enum value. * + * @param[in] str String representation of TLS version YANG identity. + * @param[out] version Corresponding enum value. * @return 0 on success, 1 on error. */ static int -nc_server_config_check_endpt_references(void) +nc_server_config_str2tls_version(const char *str, enum nc_tls_version *version) { - 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) { - /* 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_SSH) && (referenced_endpt->ti != NC_TI_TLS)) { - 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; - } - - /* 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_SSH) { - 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; - } - } - } - - /* now check all the call home endpoints */ - for (i = 0; i < server_opts.ch_client_count; i++) { - 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); - return 1; - } - - /* 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); - return 1; - } else if ((referenced_endpt->ti != NC_TI_SSH) && (referenced_endpt->ti != NC_TI_TLS)) { - 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); - return 1; - } - - /* 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); - return 1; - } + *version = NC_TLS_VERSION_NONE; - /* 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_SSH) { - 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; - } - } - } + if (!strcmp(str, "tls12")) { + *version = NC_TLS_VERSION_1_2; + } else if (!strcmp(str, "tls13")) { + *version = NC_TLS_VERSION_1_3; + } else { + ERR(NULL, "Unknown TLS version \"%s\".", str); + return 1; } return 0; } static int -nc_server_config_endpoint_reference(const struct lyd_node *node, enum nc_operation op) +config_tls_version_min(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { - int ret = 0; - struct nc_endpt *endpt = NULL; - struct nc_ch_client *ch_client = NULL; - struct nc_ch_endpt *ch_endpt = NULL; - struct nc_server_ssh_opts *ssh = NULL; - struct nc_server_tls_opts *tls = NULL; + enum nc_operation op; + const char *ver; + enum nc_tls_version v; - assert(!strcmp(LYD_NAME(node), "endpoint-reference")); - - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + NC_NODE_GET_OP(node, parent_op, &op); - /* get endpt */ - if (is_listen(node)) { - ret = nc_server_config_get_endpt(node, &endpt, NULL); + if (op == NC_OP_DELETE) { + tls->min_version = NC_TLS_VERSION_NONE; } else { - ret = nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt); - } - if (ret) { - goto cleanup; + ver = ((struct lyd_node_term *)node)->value.ident->name; + assert(ver); + + NC_CHECK_RET(nc_server_config_str2tls_version(ver, &v)); + tls->min_version = v; } - if (op == NC_OP_DELETE) { - if (endpt) { - /* listen */ - free(endpt->referenced_endpt_name); - endpt->referenced_endpt_name = NULL; - } else { - /* call home */ - assert(ch_endpt); - free(ch_endpt->referenced_endpt_name); - ch_endpt->referenced_endpt_name = NULL; - } - if (is_ssh(node)) { - if (nc_server_config_get_ssh_opts(node, ch_client, &ssh)) { - ret = 1; - goto cleanup; - } + return 0; +} - ssh->referenced_endpt_name = NULL; - } else { - if (nc_server_config_get_tls_opts(node, ch_client, &tls)) { - ret = 1; - goto cleanup; - } +static int +config_tls_version_max(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) +{ + enum nc_operation op; + const char *ver; + enum nc_tls_version v; - tls->referenced_endpt_name = NULL; - } + NC_NODE_GET_OP(node, parent_op, &op); - goto cleanup; + if (op == NC_OP_DELETE) { + tls->max_version = NC_TLS_VERSION_NONE; } 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 { - assert(ch_endpt); - 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); - } + ver = ((struct lyd_node_term *)node)->value.ident->name; + assert(ver); - goto cleanup; + NC_CHECK_RET(nc_server_config_str2tls_version(ver, &v)); + tls->max_version = v; } -cleanup: - return ret; + return 0; } static int -nc_server_config_cert_data(const struct lyd_node *node, enum nc_operation op) +config_tls_versions(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { - int ret = 0; - struct nc_certificate *cert; - struct nc_server_tls_opts *opts; - struct nc_ch_client *ch_client = NULL; + struct lyd_node *n; + enum nc_operation op; - assert(!strcmp(LYD_NAME(node), "cert-data")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; + /* config min tls version */ + NC_CHECK_RET(nc_lyd_find_child(node, "min", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_version_min(n, op, tls)); } - if (equal_parent_name(node, 3, "server-identity")) { - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(opts->cert_data); - opts->cert_data = strdup(lyd_get_value(node)); - 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, ch_client, &cert)) { - ret = 1; - goto cleanup; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(cert->data); - cert->data = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!cert->data, ret = 1, cleanup); - } else { - free(cert->data); - cert->data = NULL; - } + /* config max tls version */ + NC_CHECK_RET(nc_lyd_find_child(node, "max", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_version_max(n, op, tls)); } -cleanup: - return ret; + return 0; } static int -nc_server_config_asymmetric_key(const struct lyd_node *node, enum nc_operation op) +config_tls_cipher_suite(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { - int ret = 0; - struct nc_server_tls_opts *opts; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + const char *suite; - assert(!strcmp(LYD_NAME(node), "asymmetric-key")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + /* get the original cipher suite string */ + suite = lyd_get_value(node); + assert(suite); - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; + /* convert it to the TLS' backend's format */ + suite = nc_server_tls_cipher_suite_name_to_internal_wrap(suite); + if (!suite) { + WRN(NULL, "Unsupported TLS cipher suite \"%s\", ignoring.", lyd_get_value(node)); + return 0; } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to keystore */ - opts->store = NC_STORE_KEYSTORE; - - free(opts->key_ref); - opts->key_ref = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!opts->key_ref, ret = 1, cleanup); - } else { - free(opts->key_ref); - opts->key_ref = NULL; + if (op == NC_OP_DELETE) { + /* delete the suite from the colon separated list */ + NC_CHECK_RET(nc_server_config_del_alg(tls->cipher_suites, suite, ':')); + if (!tls->cipher_suites[0]) { + /* the list is now empty, free it */ + free(tls->cipher_suites); + tls->cipher_suites = NULL; + } + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* add the suite to the colon separated list */ + NC_CHECK_RET(nc_server_config_add_alg(&tls->cipher_suites, suite, ':')); } -cleanup: - return ret; + return 0; } static int -nc_server_config_banner(const struct lyd_node *node, enum nc_operation op) +config_tls_cipher_suites(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { - int ret = 0; - struct nc_server_ssh_opts *opts; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "banner")); - - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + struct lyd_node *n; + enum nc_operation op; - if (nc_server_config_get_ssh_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(opts->banner); - opts->banner = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!opts->banner, ret = 1, cleanup); - } else { - free(opts->banner); - opts->banner = NULL; + /* config all the cipher suites (leaf-lists) */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_tls_cipher_suite(n, op, tls)); } -cleanup: - return ret; + return 0; } static int -nc_server_config_client_authentication(const struct lyd_node *node, enum nc_operation op) +config_tls_hello_params(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { - int ret = 0; - struct nc_server_tls_opts *opts; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "client-authentication")); + enum nc_operation op; + struct lyd_node *n; - /* only do something on delete and if we're in the TLS subtree, - * because this is a presence container unlike its SSH counterpart */ - if (!is_tls(node) || (op != NC_OP_DELETE)) { - return 0; - } + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + /* config tls versions */ + NC_CHECK_RET(nc_lyd_find_child(node, "tls-versions", 1, &n)); + NC_CHECK_RET(config_tls_versions(n, op, tls)); - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } + /* config cipher suites */ + NC_CHECK_RET(nc_lyd_find_child(node, "cipher-suites", 1, &n)); + NC_CHECK_RET(config_tls_cipher_suites(n, op, tls)); - nc_server_config_del_certs(&opts->ca_certs); - nc_server_config_del_certs(&opts->ee_certs); + return 0; +} -cleanup: - return ret; +static int +config_tls_keepalives(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; } static int -nc_server_config_ca_certs(const struct lyd_node *node, enum nc_operation op) +config_tls_server_params(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { - int ret = 0; - struct nc_server_tls_opts *opts; - struct nc_ch_client *ch_client = NULL; + enum nc_operation op; + struct lyd_node *n; - assert(!strcmp(LYD_NAME(node), "ca-certs")); + NC_NODE_GET_OP(node, parent_op, &op); - /* only do something on delete and if we're in the TLS subtree, - * because SSH certs are not yet supported */ - if (!is_tls(node) || (op != NC_OP_DELETE)) { - return 0; - } + /* config server identity */ + NC_CHECK_RET(nc_lyd_find_child(node, "server-identity", 1, &n)); + NC_CHECK_RET(config_tls_server_identity(n, op, tls)); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; + /* config client-authentication */ + NC_CHECK_RET(nc_lyd_find_child(node, "client-authentication", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_client_auth(n, op, tls)); } - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; + /* config hello parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "hello-params", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_hello_params(n, op, tls)); } - nc_server_config_del_certs(&opts->ca_certs); + /* config tls keepalives */ + NC_CHECK_RET(nc_lyd_find_child(node, "keepalives", 0, &n)); + if (n) { + NC_CHECK_RET(config_tls_keepalives(n, op)); + } -cleanup: - return ret; + return 0; } static int -nc_server_config_ee_certs(const struct lyd_node *node, enum nc_operation op) +config_fingerprint(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ctn *ctn) { - int ret = 0; - struct nc_server_tls_opts *opts; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "ee-certs")); - - /* only do something on delete and if we're in the TLS subtree, - * because SSH certs are not yet supported */ - if (!is_tls(node) || (op != NC_OP_DELETE)) { - return 0; - } + enum nc_operation op; - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + NC_NODE_GET_OP(node, parent_op, &op); - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; + if (op == NC_OP_DELETE) { + free(ctn->fingerprint); + ctn->fingerprint = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(ctn->fingerprint); + ctn->fingerprint = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!ctn->fingerprint, 1); } - nc_server_config_del_certs(&opts->ee_certs); - -cleanup: - return ret; + return 0; } static int -nc_server_config_create_ca_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts) +config_map_type(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ctn *ctn) { - assert(!strcmp(LYD_NAME(node), "certificate")); + enum nc_operation op; + const char *type; - node = lyd_child(node); - assert(!strcmp(LYD_NAME(node), "name")); + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + ctn->map_type = NC_TLS_CTN_UNKNOWN; + } else { + type = ((struct lyd_node_term *)node)->value.ident->name; + assert(type); + + if (!strcmp(type, "specified")) { + ctn->map_type = NC_TLS_CTN_SPECIFIED; + } else if (!strcmp(type, "san-rfc822-name")) { + ctn->map_type = NC_TLS_CTN_SAN_RFC822_NAME; + } else if (!strcmp(type, "san-dns-name")) { + ctn->map_type = NC_TLS_CTN_SAN_DNS_NAME; + } else if (!strcmp(type, "san-ip-address")) { + ctn->map_type = NC_TLS_CTN_SAN_IP_ADDRESS; + } else if (!strcmp(type, "san-any")) { + ctn->map_type = NC_TLS_CTN_SAN_ANY; + } else if (!strcmp(type, "common-name")) { + ctn->map_type = NC_TLS_CTN_COMMON_NAME; + } else { + ERR(NULL, "Unknown cert-to-name mapping type \"%s\".", type); + return 1; + } + } - return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ca_certs.certs, sizeof *opts->ca_certs.certs, - &opts->ca_certs.cert_count); + return 0; } static int -nc_server_config_create_ee_certs_certificate(const struct lyd_node *node, struct nc_server_tls_opts *opts) +config_ctn_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ctn *ctn) { - assert(!strcmp(LYD_NAME(node), "certificate")); + enum nc_operation op; - node = lyd_child(node); - assert(!strcmp(LYD_NAME(node), "name")); + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(ctn->name); + ctn->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(ctn->name); + ctn->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!ctn->name, 1); + } - return nc_server_config_realloc(lyd_get_value(node), (void **)&opts->ee_certs.certs, sizeof *opts->ee_certs.certs, - &opts->ee_certs.cert_count); + return 0; } static int -nc_server_config_certificate(const struct lyd_node *node, enum nc_operation op) +config_cert_to_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { - int ret = 0; - struct nc_server_tls_opts *opts; - struct nc_ch_client *ch_client = NULL; - struct nc_certificate *cert; - - assert(!strcmp(LYD_NAME(node), "certificate")); - - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + struct lyd_node *n; + enum nc_operation op; + uint32_t id; + struct nc_ctn *ctn, *iter, *prev; - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - if (equal_parent_name(node, 1, "central-keystore-reference")) { - /* TLS server-identity */ - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - /* set to keystore */ - opts->store = NC_STORE_KEYSTORE; + /* get the ctn id (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "id", 1, &n)); + id = strtoul(lyd_get_value(n), NULL, 10); - free(opts->cert_ref); - opts->cert_ref = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!opts->cert_ref, ret = 1, cleanup); - } else { - free(opts->cert_ref); - opts->cert_ref = NULL; + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the ctn we are deleting/modifying */ + if (!tls->ctn) { + ERR(NULL, "Trying to modify/delete a non-existing cert-to-name mapping with ID %" PRIu32 ".", id); + return 1; } - } 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, opts); - if (ret) { - goto cleanup; - } + + iter = tls->ctn; + prev = NULL; + while (iter && (iter->id != id)) { + prev = iter; + iter = iter->next; + } + assert(iter); + ctn = iter; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* create a new ctn */ + ctn = calloc(1, sizeof *ctn); + NC_CHECK_ERRMEM_RET(!ctn, 1); + ctn->id = id; + + /* find the correct place to insert the new ctn (keep the list sorted by id) */ + if (!tls->ctn || (tls->ctn->id > id)) { + ctn->next = tls->ctn; + tls->ctn = ctn; } else { - if (nc_server_config_get_cert(node, ch_client, &cert)) { - ret = 1; - goto cleanup; + iter = tls->ctn; + while (iter->next && (iter->next->id < id)) { + iter = iter->next; } - nc_server_config_del_cert(&opts->ca_certs, cert); + ctn->next = iter->next; + iter->next = ctn; } - } 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, opts); - if (ret) { - goto cleanup; - } + } + + /* config fingerprint */ + NC_CHECK_RET(nc_lyd_find_child(node, "fingerprint", 0, &n)); + if (n) { + NC_CHECK_RET(config_fingerprint(n, op, ctn)); + } + + /* config map type */ + NC_CHECK_RET(nc_lyd_find_child(node, "map-type", 1, &n)); + NC_CHECK_RET(config_map_type(n, op, ctn)); + + /* config name */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 0, &n)); + if (n) { + NC_CHECK_RET(config_ctn_name(n, op, ctn)); + } + + /* all children processed, we can now delete the ctn */ + if (op == NC_OP_DELETE) { + if (tls->ctn == ctn) { + /* ctn is the first in the list */ + tls->ctn = ctn->next; } else { - if (nc_server_config_get_cert(node, ch_client, &cert)) { - ret = 1; - goto cleanup; - } - nc_server_config_del_cert(&opts->ee_certs, cert); + /* otherwise we have prev from the search above */ + prev->next = ctn->next; } + free(ctn); } -cleanup: - return ret; + return 0; } static int -nc_server_config_create_cert_to_name(const struct lyd_node *node, struct nc_server_tls_opts *opts) +config_client_identity_mappings(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { - int ret = 0; struct lyd_node *n; - struct nc_ctn *new, *iter; - uint32_t id; + enum nc_operation op; - assert(!strcmp(LYD_NAME(node), "cert-to-name")); - - /* find the list's key - ignore result using assert of reference argument instead */ - lyd_find_path(node, "id", 0, &n); - assert(n); - id = ((struct lyd_node_term *)n)->value.uint32; - - /* create new ctn */ - new = calloc(1, sizeof *new); - NC_CHECK_ERRMEM_GOTO(!new, ret = 1, cleanup); - - /* find the right place for insertion */ - if (!opts->ctn) { - /* inserting the first one */ - opts->ctn = new; - } 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 <= id; iter = iter->next) {} - if (iter->id == id) { - /* collision, replace */ - free(new); - new = iter; - free(new->name); - new->name = NULL; - } else { - new->next = iter->next; - iter->next = new; - } - } + NC_NODE_GET_OP(node, parent_op, &op); - /* set the id, the other members will be filled later */ - new->id = id; + /* config all cert to name mappings */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_cert_to_name(n, op, tls)); + } -cleanup: - return ret; + return 0; } static int -nc_server_config_cert_to_name(const struct lyd_node *node, enum nc_operation op) +config_tls_netconf_server_params(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_tls_opts *tls) { - int ret = 0; - struct nc_server_tls_opts *opts; - struct nc_ctn *ctn; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "cert-to-name")); - - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + struct lyd_node *n; + enum nc_operation op; - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_create_cert_to_name(node, opts); - if (ret) { - goto cleanup; - } - } else { - /* find the given ctn entry */ - if (nc_server_config_get_ctn(node, ch_client, &ctn)) { - ret = 1; - goto cleanup; - } - nc_server_config_del_ctn(opts, ctn); - } + /* config client identity mappings */ + NC_CHECK_RET(nc_lyd_find_child(node, "client-identity-mappings", 1, &n)); + NC_CHECK_RET(config_client_identity_mappings(n, op, tls)); -cleanup: - return ret; + return 0; } static int -nc_server_config_fingerprint(const struct lyd_node *node, enum nc_operation UNUSED(op)) +config_tls(const struct lyd_node *node, enum nc_operation parent_op, struct nc_endpt *endpt) { - int ret = 0; - struct nc_ctn *ctn; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "fingerprint")); + struct lyd_node *n; + enum nc_operation op; - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + NC_NODE_GET_OP(node, parent_op, &op); - if (nc_server_config_get_ctn(node, ch_client, &ctn)) { - ret = 1; - goto cleanup; + /* create the tls opts */ + if (!endpt->opts.tls) { + /* op should not be NC_OP_DELETE if the diff is valid, otherwise this would have already been created */ + endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls); + NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1); + endpt->ti = NC_TI_TLS; } - /* mandatory node, no need to check the op */ - free(ctn->fingerprint); - ctn->fingerprint = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!ctn->fingerprint, ret = 1, cleanup); - -cleanup: - return ret; -} - -static int -nc_server_config_map_type(const struct lyd_node *node, enum nc_operation UNUSED(op)) -{ - int ret = 0; - struct nc_ctn *ctn; - struct nc_ch_client *ch_client = NULL; - const char *map_type; - NC_TLS_CTN_MAPTYPE m_type; - - assert(!strcmp(LYD_NAME(node), "map-type")); + /* tcp server parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "tcp-server-parameters", 1, &n)); + NC_CHECK_RET(config_tcp_server_params(n, op, endpt)); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + /* tls server parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "tls-server-parameters", 1, &n)); + NC_CHECK_RET(config_tls_server_params(n, op, endpt->opts.tls)); - if (nc_server_config_get_ctn(node, ch_client, &ctn)) { - ret = 1; - goto cleanup; - } + /* netconf server parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "netconf-server-parameters", 1, &n)); + NC_CHECK_RET(config_tls_netconf_server_params(n, op, endpt->opts.tls)); - map_type = ((struct lyd_node_term *)node)->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, "CTN map-type \"%s\" not supported.", map_type); - ret = 1; - goto cleanup; + if (op == NC_OP_DELETE) { + free(endpt->opts.tls); + endpt->opts.tls = NULL; + endpt->ti = NC_TI_NONE; } - /* mandatory node, no need to check the op */ - ctn->map_type = m_type; - -cleanup: - return ret; + return 0; } +#endif /* NC_ENABLED_SSH_TLS */ + static int -nc_server_config_name(const struct lyd_node *node, enum nc_operation op) +config_unix_path(const struct lyd_node *node, enum nc_operation parent_op, struct nc_endpt *endpt) { - int ret = 0; - struct nc_ctn *ctn; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "name")); - - /* we only care about this node if it is a child of cert-to-name, - * because otherwise it is most likely a key of a list and such cases are handled together with the list */ - if (!node->parent || strcmp(LYD_NAME(node->parent), "cert-to-name")) { - return 0; - } - - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + enum nc_operation op; + struct nc_bind *bind; - if (nc_server_config_get_ctn(node, ch_client, &ctn)) { - ret = 1; - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(ctn->name); - ctn->name = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!ctn->name, ret = 1, cleanup); - } else { - free(ctn->name); - ctn->name = NULL; + if (op == NC_OP_DELETE) { + /* the endpoint must have a single binding, so we can just free it, + * the socket will be closed in ::nc_server_config_free() */ + assert(endpt->binds); + free(endpt->binds[0].address); + LY_ARRAY_FREE(endpt->binds); + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* the endpoint must not have any bindings yet, so we can just create one */ + assert(!endpt->binds); + LY_ARRAY_NEW_RET(LYD_CTX(node), endpt->binds, bind, 1); + bind->address = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!bind->address, 1); + bind->sock = -1; } -cleanup: - return ret; + return 0; } static int -nc_server_config_tls_version(const struct lyd_node *node, enum nc_operation op) +config_unix_socket_perms_mode(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_unix_opts *unix) { - int ret = 0; - struct nc_server_tls_opts *opts; - const char *version = NULL; - struct nc_ch_client *ch_client = NULL; - NC_TLS_VERSION tls_version; - - assert(!strcmp(LYD_NAME(node), "tls-version")); - - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + enum nc_operation op; + char *endptr; - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - /* str to tls_version */ - version = ((struct lyd_node_term *)node)->value.ident->name; - if (!strcmp(version, "tls10")) { - tls_version = NC_TLS_VERSION_10; - } else if (!strcmp(version, "tls11")) { - tls_version = NC_TLS_VERSION_11; - } else if (!strcmp(version, "tls12")) { - tls_version = NC_TLS_VERSION_12; - } else if (!strcmp(version, "tls13")) { - tls_version = NC_TLS_VERSION_13; + if (op == NC_OP_DELETE) { + unix->mode = (mode_t)-1; } 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; + unix->mode = strtol(lyd_get_value(node), &endptr, 8); + if (*endptr || (unix->mode > 0777)) { + ERR(NULL, "Invalid UNIX socket mode \"%s\".", lyd_get_value(node)); + return 1; + } } -cleanup: - return ret; + return 0; } static int -nc_server_config_create_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher) +config_unix_socket_perms_owner(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_unix_opts *unix) { - int ret = 0; - char *processed_cipher = NULL; + enum nc_operation op; + struct passwd *pw, pwbuf; + char *buf = NULL; + size_t buflen = 0; - ret = nc_tls_process_cipher_suite_wrap(cipher, &processed_cipher); - if (ret) { - ERR(NULL, "Failed to process the cipher suite \"%s\".", cipher); - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - ret = nc_tls_append_cipher_suite_wrap(opts, processed_cipher); - if (ret) { - ERR(NULL, "Failed to append the cipher suite \"%s\".", cipher); - goto cleanup; + if (op == NC_OP_DELETE) { + unix->uid = (uid_t)-1; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* get uid from the name */ + pw = nc_getpw(0, lyd_get_value(node), &pwbuf, &buf, &buflen); + NC_CHECK_RET(!pw, 1); + unix->uid = pw->pw_uid; + free(buf); } -cleanup: - free(processed_cipher); - return ret; + return 0; } static int -nc_server_config_del_cipher_suite(struct nc_server_tls_opts *opts, const char *cipher) +config_unix_socket_perms_group(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_unix_opts *unix) { - int ret = 0; + enum nc_operation op; + struct group *gr, grbuf; + char *buf = NULL; + size_t buflen = 0; - 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; + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + unix->gid = (gid_t)-1; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* get gid from the name */ + gr = nc_getgr(0, lyd_get_value(node), &grbuf, &buf, &buflen); + NC_CHECK_RET(!gr, 1); + unix->gid = gr->gr_gid; + free(buf); } return 0; } static int -nc_server_config_cipher_suite(const struct lyd_node *node, enum nc_operation op) +config_unix_socket_perms(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_unix_opts *unix) { - int ret = 0; - struct nc_server_tls_opts *opts; - const char *cipher = NULL; - struct nc_ch_client *ch_client = NULL; + struct lyd_node *n; + enum nc_operation op; - assert(!strcmp(LYD_NAME(node), "cipher-suite")); + NC_NODE_GET_OP(node, parent_op, &op); - if (is_ch(node) && nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + /* config mode */ + NC_CHECK_RET(nc_lyd_find_child(node, "mode", 1, &n)); + NC_CHECK_RET(config_unix_socket_perms_mode(n, op, unix)); - if (nc_server_config_get_tls_opts(node, ch_client, &opts)) { - ret = 1; - goto cleanup; + /* config owner */ + NC_CHECK_RET(nc_lyd_find_child(node, "owner", 0, &n)); + if (n) { + NC_CHECK_RET(config_unix_socket_perms_owner(n, op, unix)); } - cipher = ((struct lyd_node_term *)node)->value.ident->name; - if (op == NC_OP_CREATE) { - ret = nc_server_config_create_cipher_suite(opts, cipher); - if (ret) { - goto cleanup; - } - } else if (op == NC_OP_DELETE) { - ret = nc_server_config_del_cipher_suite(opts, cipher); - if (ret) { - goto cleanup; - } + /* config group */ + NC_CHECK_RET(nc_lyd_find_child(node, "group", 0, &n)); + if (n) { + NC_CHECK_RET(config_unix_socket_perms_group(n, op, unix)); } -cleanup: - return ret; + return 0; } -#endif /* NC_ENABLED_SSH_TLS */ - static int -nc_server_config_create_netconf_client(const struct lyd_node *node) +config_unix_user_mapping_system_user(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_unix_user_mapping *mapping) { - int ret = 0; + enum nc_operation op; - node = lyd_child(node); - assert(!strcmp(LYD_NAME(node), "name")); + NC_NODE_GET_OP(node, parent_op, &op); - 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; + if (op == NC_OP_DELETE) { + free(mapping->system_user); + mapping->system_user = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(mapping->system_user); + mapping->system_user = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!mapping->system_user, 1); } - 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; - -cleanup: - return ret; + return 0; } static int -nc_server_config_netconf_client(const struct lyd_node *node, enum nc_operation op) +config_unix_user_mapping_netconf_user(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_unix_user_mapping *mapping) { - int ret = 0; + enum nc_operation op; + LY_ARRAY_COUNT_TYPE i; + const char *user; + char **allowed_user; - assert(!strcmp(LYD_NAME(node), "netconf-client")); + NC_NODE_GET_OP(node, parent_op, &op); - if (op == NC_OP_CREATE) { - ret = nc_server_config_create_netconf_client(node); - if (ret) { - goto cleanup; + user = lyd_get_value(node); + assert(user); + + if (op == NC_OP_DELETE) { + /* delete the user from the list */ + LY_ARRAY_FOR(mapping->allowed_users, i) { + if (!strcmp(mapping->allowed_users[i], user)) { + break; + } } -#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) { - /* 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, 1); - if (ret) { - ERR(NULL, "Dispatching a new Call Home thread failed for Call Home client \"%s\".", lyd_get_value(lyd_child(node))); - goto cleanup; + if (i == LY_ARRAY_COUNT(mapping->allowed_users)) { + ERR(NULL, "Trying to delete a non-existing NETCONF user \"%s\" from the UNIX user mapping \"%s\".", + user, mapping->system_user); + return 1; + } + + /* free the user and replace it with the last one */ + free(mapping->allowed_users[i]); + if (i < LY_ARRAY_COUNT(mapping->allowed_users) - 1) { + mapping->allowed_users[i] = mapping->allowed_users[LY_ARRAY_COUNT(mapping->allowed_users) - 1]; + } + LY_ARRAY_DECREMENT_FREE(mapping->allowed_users); + } else if (op == NC_OP_CREATE) { + /* add the user to the list, if it does not already exist */ + LY_ARRAY_FOR(mapping->allowed_users, i) { + if (!strcmp(mapping->allowed_users[i], user)) { + break; } } -#endif /* NC_ENABLED_SSH_TLS */ - } else if (op == NC_OP_DELETE) { - nc_server_config_ch_del_client(node); + + if (i < LY_ARRAY_COUNT(mapping->allowed_users)) { + ERR(NULL, "Trying to create an already existing NETCONF user \"%s\" in the UNIX user mapping \"%s\".", + user, mapping->system_user); + return 1; + } + + LY_ARRAY_NEW_RET(LYD_CTX(node), mapping->allowed_users, allowed_user, 1); + *allowed_user = strdup(user); + NC_CHECK_ERRMEM_RET(!*allowed_user, 1); } -cleanup: - return ret; + return 0; } -#ifdef NC_ENABLED_SSH_TLS - static int -nc_server_config_remote_address(const struct lyd_node *node, enum nc_operation op) +config_unix_user_mapping(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_unix_opts *unix) { - int ret = 0; - struct nc_ch_endpt *ch_endpt; - struct nc_ch_client *ch_client = NULL; + struct lyd_node *n; + enum nc_operation op; + struct nc_server_unix_user_mapping *mapping = NULL; + const char *system_user; + LY_ARRAY_COUNT_TYPE i; + struct ly_set *set = NULL; + uint32_t j; - assert(!strcmp(LYD_NAME(node), "remote-address")); + NC_NODE_GET_OP(node, parent_op, &op); - if (nc_server_config_get_ch_client(node, &ch_client)) { - return 1; + /* get the system-user (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "system-user", 1, &n)); + system_user = lyd_get_value(n); + assert(system_user); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the user mapping we are deleting/modifying */ + LY_ARRAY_FOR(unix->user_mappings, i) { + if (!strcmp(unix->user_mappings[i].system_user, system_user)) { + break; + } + } + assert(i < LY_ARRAY_COUNT(unix->user_mappings)); + mapping = &unix->user_mappings[i]; + } else if (op == NC_OP_CREATE) { + /* create a new user mapping */ + LY_ARRAY_NEW_RET(LYD_CTX(node), unix->user_mappings, mapping, 1); } - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; + /* config system-user */ + NC_CHECK_RET(config_unix_user_mapping_system_user(n, op, mapping)); + + /* configure all netconf-users (leaf-list) */ + NC_CHECK_RET(lyd_find_xpath(node, "netconf-user", &set), 1); + for (j = 0; j < set->count; ++j) { + NC_CHECK_GOTO(config_unix_user_mapping_netconf_user(set->dnodes[j], op, mapping), cleanup); } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(ch_endpt->dst_addr); - ch_endpt->dst_addr = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!ch_endpt->dst_addr, ret = 1, cleanup); - } else { - free(ch_endpt->dst_addr); - ch_endpt->dst_addr = NULL; + /* all children processed, we can now delete the user mapping */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(unix->user_mappings) - 1) { + unix->user_mappings[i] = unix->user_mappings[LY_ARRAY_COUNT(unix->user_mappings) - 1]; + } + LY_ARRAY_DECREMENT_FREE(unix->user_mappings); } cleanup: - return ret; + ly_set_free(set, NULL); + return 0; } static int -nc_server_config_remote_port(const struct lyd_node *node, enum nc_operation op) +config_unix_client_auth(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_unix_opts *unix) { - int ret = 0; - struct nc_ch_endpt *ch_endpt; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "remote-port")); - - if (nc_server_config_get_ch_client(node, &ch_client)) { - return 1; - } + struct lyd_node *n; + enum nc_operation op; - if (nc_server_config_get_ch_endpt(node, ch_client, &ch_endpt)) { - ret = 1; - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_endpt->dst_port = ((struct lyd_node_term *)node)->value.uint16; - } else { - ch_endpt->dst_port = 0; + /* configure all user mappings */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_unix_user_mapping(n, op, unix)); } -cleanup: - return ret; + return 0; } -#endif /* NC_ENABLED_SSH_TLS */ - static int -nc_server_config_persistent(const struct lyd_node *node, enum nc_operation op) +config_unix(const struct lyd_node *node, enum nc_operation parent_op, struct nc_endpt *endpt) { - int ret = 0; - struct nc_ch_client *ch_client = NULL; + struct lyd_node *n; + enum nc_operation op; - assert(!strcmp(LYD_NAME(node), "persistent")); + NC_NODE_GET_OP(node, parent_op, &op); - /* switch to periodic, don't do anything */ - if (op == NC_OP_DELETE) { - return 0; - } + /* create the unix opts */ + if (!endpt->opts.unix) { + /* op should not be NC_OP_DELETE if the diff is valid, otherwise this would have already been created */ + endpt->opts.unix = calloc(1, sizeof *endpt->opts.unix); + NC_CHECK_ERRMEM_RET(!endpt->opts.unix, 1); + endpt->ti = NC_TI_UNIX; - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - return ret; + /* set default values */ + endpt->opts.unix->mode = (mode_t)-1; + endpt->opts.unix->uid = (uid_t)-1; + endpt->opts.unix->gid = (gid_t)-1; } - ch_client->conn_type = NC_CH_PERSIST; + /* config path */ + NC_CHECK_RET(nc_lyd_find_child(node, "path", 1, &n)); + NC_CHECK_RET(config_unix_path(n, op, endpt)); - return ret; -} - -static int -nc_server_config_periodic(const struct lyd_node *node, enum nc_operation op) -{ - int ret = 0; - struct nc_ch_client *ch_client = NULL; + /* config socket permissions */ + NC_CHECK_RET(nc_lyd_find_child(node, "socket-permissions", 1, &n)); + NC_CHECK_RET(config_unix_socket_perms(n, op, endpt->opts.unix)); - assert(!strcmp(LYD_NAME(node), "periodic")); + /* config client authentication */ + NC_CHECK_RET(nc_lyd_find_child(node, "client-authentication", 1, &n)); + NC_CHECK_RET(config_unix_client_auth(n, op, endpt->opts.unix)); - /* switch to persistent, don't do anything */ if (op == NC_OP_DELETE) { - return 0; - } - - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - return ret; + free(endpt->opts.unix); + endpt->opts.unix = NULL; + endpt->ti = NC_TI_NONE; } - ch_client->conn_type = NC_CH_PERIOD; - /* set default values */ - ch_client->period = 60; - ch_client->anchor_time = 0; - ch_client->idle_timeout = 180; - - return ret; + return 0; } static int -nc_server_config_period(const struct lyd_node *node, enum nc_operation op) +config_endpoint_name(const struct lyd_node *node, enum nc_operation op, struct nc_endpt *endpt) { - int ret = 0; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "period")); - - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - return ret; - } - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_client->period = ((struct lyd_node_term *)node)->value.uint16; - } else if (op == NC_OP_DELETE) { - ch_client->period = 60; + if (op == NC_OP_DELETE) { + free(endpt->name); + endpt->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(endpt->name); + endpt->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!endpt->name, 1); } - return ret; + return 0; } static int -nc_server_config_anchor_time(const struct lyd_node *node, enum nc_operation op) +config_endpoint(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_config *config) { - int ret = 0; - struct nc_ch_client *ch_client = NULL; - struct lyd_value_date_and_time *anchor_time; + struct lyd_node *n, *ssh, *tls, *unix; + enum nc_operation op; + struct nc_endpt *endpt = NULL; + const char *name; + LY_ARRAY_COUNT_TYPE i; + int r; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* get the key of this list instance */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); - assert(!strcmp(LYD_NAME(node), "anchor-time")); + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* get the endpoint we are deleting/modifying */ + LY_ARRAY_FOR(config->endpts, i) { + if (!strcmp(config->endpts[i].name, name)) { + break; + } + } + assert(i < LY_ARRAY_COUNT(config->endpts)); + endpt = &config->endpts[i]; + } else if (op == NC_OP_CREATE) { + /* create a new endpoint */ + LY_ARRAY_NEW_RET(LYD_CTX(node), config->endpts, endpt, 1); - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - return ret; + /* init the new endpoint */ + if ((r = pthread_mutex_init(&endpt->bind_lock, NULL))) { + ERR(NULL, "Mutex init failed (%s).", strerror(r)); + return 1; + } } - /* get the value of time from the node directly */ - LYD_VALUE_GET(&((struct lyd_node_term *)node)->value, anchor_time); + /* config name */ + NC_CHECK_RET(config_endpoint_name(n, op, endpt)); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_client->anchor_time = anchor_time->time; - } else if (op == NC_OP_DELETE) { - ch_client->anchor_time = 0; + /* config ssh/tls/unix (augment) choice */ + NC_CHECK_RET(nc_lyd_find_child(node, "ssh", 0, &ssh)); + NC_CHECK_RET(nc_lyd_find_child(node, "tls", 0, &tls)); + NC_CHECK_RET(nc_lyd_find_child(node, "libnetconf2-netconf-server:unix", 0, &unix)); + assert(ssh || tls || unix); + +#ifdef NC_ENABLED_SSH_TLS + if (ssh) { + NC_CHECK_RET(config_ssh(ssh, op, endpt)); + } else if (tls) { + NC_CHECK_RET(config_tls(tls, op, endpt)); + } else +#endif /* NC_ENABLED_SSH_TLS */ + if (unix) { + NC_CHECK_RET(config_unix(unix, op, endpt)); } - return ret; + /* all children processed, we can now delete the endpoint */ + if (op == NC_OP_DELETE) { + pthread_mutex_destroy(&endpt->bind_lock); + if (i < LY_ARRAY_COUNT(config->endpts) - 1) { + config->endpts[i] = config->endpts[LY_ARRAY_COUNT(config->endpts) - 1]; + } + LY_ARRAY_DECREMENT_FREE(config->endpts); + } + + return 0; } static int -nc_server_config_reconnect_strategy(const struct lyd_node *node, enum nc_operation op) +config_endpoints(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_config *config) { - int ret = 0; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "reconnect-strategy")); + struct lyd_node *n; + enum nc_operation op; - (void) op; + NC_NODE_GET_OP(node, parent_op, &op); - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - return ret; + /* configure each endpoint */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_endpoint(n, op, config)); } - /* set to default values */ - ch_client->start_with = NC_CH_FIRST_LISTED; - ch_client->max_wait = 5; - ch_client->max_attempts = 3; - - return ret; + return 0; } static int -nc_server_config_start_with(const struct lyd_node *node, enum nc_operation op) +config_idle_timeout(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), + struct nc_server_config *config) { - int ret = 0; - struct nc_ch_client *ch_client = NULL; - const char *value; + /* default value => value always present */ + config->idle_timeout = strtoul(lyd_get_value(node), NULL, 10); + return 0; +} - assert(!strcmp(LYD_NAME(node), "start-with")); +static int +config_listen(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_config *config) +{ + struct lyd_node *n; + enum nc_operation op; - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - goto cleanup; - } + NC_NODE_GET_OP(node, parent_op, &op); - if (op == NC_OP_DELETE) { - ch_client->start_with = NC_CH_FIRST_LISTED; - goto cleanup; - } + /* configure idle-timeout */ + NC_CHECK_RET(nc_lyd_find_child(node, "idle-timeout", 1, &n)); + NC_CHECK_RET(config_idle_timeout(n, op, config)); - 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; - } + /* configure endpoints */ + NC_CHECK_RET(nc_lyd_find_child(node, "endpoints", 1, &n)); + NC_CHECK_RET(config_endpoints(n, op, config)); -cleanup: - return ret; + return 0; } static int -nc_server_config_max_wait(const struct lyd_node *node, enum nc_operation op) +config_ch_client_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_client *client) { - int ret = 0; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "max-wait")); + enum nc_operation op; - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - return ret; - } + NC_NODE_GET_OP(node, parent_op, &op); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_client->max_wait = ((struct lyd_node_term *)node)->value.uint16; - } else { - ch_client->max_wait = 5; + if (op == NC_OP_DELETE) { + free(client->name); + client->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(client->name); + client->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!client->name, 1); } - return ret; + return 0; } +#ifdef NC_ENABLED_SSH_TLS + static int -nc_server_config_max_attempts(const struct lyd_node *node, enum nc_operation op) +config_remote_address(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_endpt *endpt) { - int ret = 0; - struct nc_ch_client *ch_client = NULL; - - assert(!strcmp(LYD_NAME(node), "max-attempts")); + enum nc_operation op; - if ((ret = nc_server_config_get_ch_client(node, &ch_client))) { - return ret; - } + NC_NODE_GET_OP(node, parent_op, &op); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ch_client->max_attempts = ((struct lyd_node_term *)node)->value.uint8; - } else { - ch_client->max_attempts = 3; + if (op == NC_OP_DELETE) { + free(endpt->dst_addr); + endpt->dst_addr = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(endpt->dst_addr); + endpt->dst_addr = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!endpt->dst_addr, 1); } - return ret; + return 0; } static int -nc_server_config_netconf_user(const struct lyd_node *node, enum nc_operation op) +config_remote_port(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), struct nc_ch_endpt *endpt) { - struct nc_server_unix_opts *opts; - struct nc_server_unix_user_mapping *user_map; - struct lyd_node *n; - const char *system_user; - char ***allowed_users; - uint32_t *allowed_user_count; - uint32_t i, j; - - NC_CHECK_RET(nc_server_config_get_unix_opts(node, &opts)); - - /* get the instance of the user mapping that we are going to modify */ - lyd_find_path((const struct lyd_node *)node->parent, "system-user", 0, &n); - assert(n); - system_user = lyd_get_value(n); - - user_map = NULL; - for (i = 0; i < opts->mapping_count; ++i) { - if (!strcmp(opts->user_mappings[i].system_user, system_user)) { - user_map = &opts->user_mappings[i]; - break; - } - } - NC_CHECK_ERR_RET(!user_map, ERR(NULL, "No user mapping for system-user \"%s\" found.", system_user), 1); - - if (op == NC_OP_CREATE) { - /* create a new mapping */ - allowed_users = &user_map->allowed_users; - allowed_user_count = &user_map->allowed_user_count; + /* default value => value always present */ + endpt->dst_port = strtoul(lyd_get_value(node), NULL, 10); + return 0; +} - *allowed_users = nc_realloc(*allowed_users, (*allowed_user_count + 1) * sizeof **allowed_users); - NC_CHECK_ERRMEM_RET(!*allowed_users, 1); +static int +config_ch_local_address(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_endpt *endpt) +{ + enum nc_operation op; - (*allowed_users)[*allowed_user_count] = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_RET(!(*allowed_users)[*allowed_user_count], 1); + NC_NODE_GET_OP(node, parent_op, &op); - (*allowed_user_count)++; - } else if (op == NC_OP_DELETE) { - /* find the user we want to delete */ - for (j = 0; j < user_map->allowed_user_count; j++) { - if (!strcmp(user_map->allowed_users[j], lyd_get_value(node))) { - break; - } - } - NC_CHECK_ERR_RET(j == user_map->allowed_user_count, - ERR(NULL, "No user \"%s\" found in mapping for system-user \"%s\".", lyd_get_value(node), system_user), 1); - - /* delete the user */ - free(user_map->allowed_users[j]); - user_map->allowed_user_count--; - if (j < user_map->allowed_user_count) { - user_map->allowed_users[j] = user_map->allowed_users[user_map->allowed_user_count]; - } + if (op == NC_OP_DELETE) { + free(endpt->src_addr); + endpt->src_addr = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(endpt->src_addr); + endpt->src_addr = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!endpt->src_addr, 1); } return 0; } static int -nc_server_config_user_mapping(const struct lyd_node *node, enum nc_operation op) +config_ch_local_port(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_endpt *endpt) { - struct nc_server_unix_opts *opts; - const char *system_user; - uint32_t i; - - assert(lyd_child(node) && !strcmp(LYD_NAME(lyd_child(node)), "system-user")); + enum nc_operation op; - NC_CHECK_RET(nc_server_config_get_unix_opts(node, &opts)); + NC_NODE_GET_OP(node, parent_op, &op); - /* list's key */ - system_user = lyd_get_value(lyd_child(node)); - - if (op == NC_OP_CREATE) { - /* create a new mapping */ - NC_CHECK_RET(nc_server_config_realloc(system_user, (void **)&opts->user_mappings, - sizeof *opts->user_mappings, &opts->mapping_count)); - } else if (op == NC_OP_DELETE) { - /* find the mapping we want to delete */ - for (i = 0; i < opts->mapping_count; ++i) { - if (!strcmp(opts->user_mappings[i].system_user, system_user)) { - break; - } - } - NC_CHECK_ERR_RET(i == opts->mapping_count, - ERR(NULL, "No user mapping for system-user \"%s\" found.", system_user), 1); - nc_server_config_del_user_mapping(opts, i); + if (op == NC_OP_DELETE) { + endpt->src_port = 0; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + endpt->src_port = strtoul(lyd_get_value(node), NULL, 10); } return 0; } static int -nc_server_config_group(const struct lyd_node *node, enum nc_operation op) +config_proxy_server(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) { - int rc = 0; - struct nc_server_unix_opts *opts; - struct group *gr, gr_buf; - char *buf = NULL; - size_t buf_size = 0; - - NC_CHECK_RET(nc_server_config_get_unix_opts(node, &opts)); - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - gr = nc_getgr(0, lyd_get_value(node), &gr_buf, &buf, &buf_size); - NC_CHECK_ERR_GOTO(!gr, rc = 1, cleanup); - opts->gid = gr->gr_gid; - } else if (op == NC_OP_DELETE) { - /* reset to default */ - opts->gid = (gid_t)-1; - } - -cleanup: - free(buf); - return rc; + CONFIG_LOG_UNSUPPORTED(node); + return 0; } static int -nc_server_config_owner(const struct lyd_node *node, enum nc_operation op) +config_tcp_client_params(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_endpt *endpt) { - int rc = 0; - struct nc_server_unix_opts *opts; - struct passwd *pw, pw_buf; - char *buf = NULL; - size_t buf_size = 0; + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); - NC_CHECK_RET(nc_server_config_get_unix_opts(node, &opts)); + /* config remote address */ + NC_CHECK_RET(nc_lyd_find_child(node, "remote-address", 1, &n)); + NC_CHECK_RET(config_remote_address(n, op, endpt)); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - pw = nc_getpw(0, lyd_get_value(node), &pw_buf, &buf, &buf_size); - NC_CHECK_ERR_GOTO(!pw, rc = 1, cleanup); - opts->uid = pw->pw_uid; - } else if (op == NC_OP_DELETE) { - /* reset to default */ - opts->uid = (uid_t)-1; + /* config remote port */ + NC_CHECK_RET(nc_lyd_find_child(node, "remote-port", 1, &n)); + if (n) { + NC_CHECK_RET(config_remote_port(n, op, endpt)); } -cleanup: - free(buf); - return rc; -} + /* config local address */ + NC_CHECK_RET(nc_lyd_find_child(node, "local-address", 0, &n)); + if (n) { + NC_CHECK_RET(config_ch_local_address(n, op, endpt)); + } -static int -nc_server_config_mode(const struct lyd_node *node, enum nc_operation op) -{ - struct nc_server_unix_opts *opts; - long mode; + /* config local port */ + NC_CHECK_RET(nc_lyd_find_child(node, "local-port", 0, &n)); + if (n) { + NC_CHECK_RET(config_ch_local_port(n, op, endpt)); + } - NC_CHECK_RET(nc_server_config_get_unix_opts(node, &opts)); + /* config proxy server */ + NC_CHECK_RET(nc_lyd_find_child(node, "proxy-server", 0, &n)); + if (n) { + NC_CHECK_RET(config_proxy_server(n, op)); + } - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - mode = strtol(lyd_get_value(node), NULL, 8); - if ((mode < 0) || (mode > 0777)) { - ERR(NULL, "Invalid UNIX socket mode value \"%s\".", lyd_get_value(node)); - return 1; - } - opts->mode = mode; - } else if (op == NC_OP_DELETE) { - /* reset to default */ - opts->mode = (mode_t)-1; + /* config keepalives */ + NC_CHECK_RET(nc_lyd_find_child(node, "keepalives", 0, &n)); + if (n) { + NC_CHECK_RET(config_tcp_keepalives(n, op, &endpt->ka)); } return 0; } static int -nc_server_config_path(const struct lyd_node *node, enum nc_operation op) +config_ch_endpoint_ssh(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_endpt *endpt) { - struct nc_endpt *endpt; - struct nc_bind *bind; - struct nc_server_unix_opts *opts; - - NC_CHECK_RET(nc_server_config_get_endpt(node, &endpt, &bind)); - opts = endpt->opts.unix; + enum nc_operation op; + struct lyd_node *n; - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - free(opts->path); - opts->path = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_RET(!opts->path, 1); + NC_NODE_GET_OP(node, parent_op, &op); - free(bind->address); - bind->address = strdup(opts->path); - NC_CHECK_ERRMEM_RET(!bind->address, 1); - } else if (op == NC_OP_DELETE) { - free(opts->path); - opts->path = NULL; + if (!endpt->opts.ssh) { + /* op should not be NC_OP_DELETE if the diff is valid, otherwise this would have already been created */ + endpt->opts.ssh = calloc(1, sizeof *endpt->opts.ssh); + NC_CHECK_ERRMEM_RET(!endpt->opts.ssh, 1); + endpt->ti = NC_TI_SSH; } - return 0; -} - -static int -nc_server_config_unix(const struct lyd_node *node, enum nc_operation op) -{ - int ret = 0; - struct nc_endpt *endpt; - struct nc_bind *bind; + /* config tcp client parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "tcp-client-parameters", 1, &n)); + NC_CHECK_RET(config_tcp_client_params(n, op, endpt)); - NC_CHECK_RET(nc_server_config_get_endpt(node, &endpt, &bind)); + /* config ssh server parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "ssh-server-parameters", 1, &n)); + NC_CHECK_RET(config_ssh_server_params(n, op, endpt->opts.ssh)); - if (op == NC_OP_CREATE) { - endpt->ti = NC_TI_UNIX; - endpt->opts.unix = calloc(1, sizeof *endpt->opts.unix); - NC_CHECK_ERRMEM_RET(!endpt->opts.unix, 1); + /* config netconf server parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "netconf-server-parameters", 1, &n)); + NC_CHECK_RET(config_ssh_netconf_server_params(n, op)); - /* set non-zero default values */ - endpt->opts.unix->uid = (uid_t)-1; - endpt->opts.unix->gid = (gid_t)-1; - } else if (op == NC_OP_DELETE) { - nc_server_config_del_unix_opts(bind, endpt->opts.unix); - endpt->opts.unix = NULL; + if (op == NC_OP_DELETE) { + free(endpt->opts.ssh); + endpt->opts.ssh = NULL; endpt->ti = NC_TI_NONE; } - return ret; + return 0; } -/** - * @brief Route a YANG data node to its appropriate configuration handler based on its name. - * - * @param[in] node ietf-netconf-server YANG data node to process. - * @param[in] op Configuration operation to perform (create, replace, delete). - * @return 0 on success, 1 on error. - */ static int -nc_server_config_parse_netconf_server_node(const struct lyd_node *node, enum nc_operation op) +config_ch_endpoint_tls(const struct lyd_node *node, enum nc_operation parent_op, struct nc_ch_endpt *endpt) { - const char *name = LYD_NAME(node); - int ret = 0; + enum nc_operation op; + struct lyd_node *n; - /* not SSH/TLS dependent config nodes */ - if (!strcmp(name, "anchor-time")) { - ret = nc_server_config_anchor_time(node, op); - } else if (!strcmp(name, "call-home")) { - ret = nc_server_config_ch(node, op); - } else if (!strcmp(name, "endpoint")) { - ret = nc_server_config_endpoint(node, op); - } else if (!strcmp(name, "group")) { - ret = nc_server_config_group(node, op); - } else if (!strcmp(name, "idle-timeout")) { - ret = nc_server_config_idle_timeout(node, op); - } else if (!strcmp(name, "listen")) { - ret = nc_server_config_listen(node, op); - } else if (!strcmp(name, "max-attempts")) { - ret = nc_server_config_max_attempts(node, op); - } else if (!strcmp(name, "max-wait")) { - ret = nc_server_config_max_wait(node, op); - } else if (!strcmp(name, "mode")) { - ret = nc_server_config_mode(node, op); - } else if (!strcmp(name, "netconf-client")) { - ret = nc_server_config_netconf_client(node, op); - } else if (!strcmp(name, "netconf-user")) { - ret = nc_server_config_netconf_user(node, op); - } else if (!strcmp(name, "owner")) { - ret = nc_server_config_owner(node, op); - } else if (!strcmp(name, "path")) { - ret = nc_server_config_path(node, op); - } else if (!strcmp(name, "period")) { - ret = nc_server_config_period(node, op); - } else if (!strcmp(name, "periodic")) { - ret = nc_server_config_periodic(node, op); - } else if (!strcmp(name, "persistent")) { - ret = nc_server_config_persistent(node, op); - } else if (!strcmp(name, "reconnect-strategy")) { - ret = nc_server_config_reconnect_strategy(node, op); - } else if (!strcmp(name, "start-with")) { - ret = nc_server_config_start_with(node, op); - } else if (!strcmp(name, "unix")) { - ret = nc_server_config_unix(node, op); - } else if (!strcmp(name, "user-mapping")) { - ret = nc_server_config_user_mapping(node, op); - } -#ifdef NC_ENABLED_SSH_TLS - /* SSH/TLS dependent config nodes */ - else if (!strcmp(name, "auth-timeout")) { - ret = nc_server_config_auth_timeout(node, op); - } else if (!strcmp(name, "asymmetric-key")) { - ret = nc_server_config_asymmetric_key(node, op); - } else if (!strcmp(name, "banner")) { - ret = nc_server_config_banner(node, op); - } else if (!strcmp(name, "ca-certs")) { - ret = nc_server_config_ca_certs(node, op); - } else if (!strcmp(name, "central-keystore-reference")) { - ret = nc_server_config_keystore_reference(node, op); - } else if (!strcmp(name, "central-truststore-reference")) { - ret = nc_server_config_truststore_reference(node, op); - } else if (!strcmp(name, "cert-data")) { - ret = nc_server_config_cert_data(node, op); - } else if (!strcmp(name, "certificate")) { - ret = nc_server_config_certificate(node, op); - } else if (!strcmp(name, "cert-to-name")) { - ret = nc_server_config_cert_to_name(node, op); - } else if (!strcmp(name, "cipher-suite")) { - ret = nc_server_config_cipher_suite(node, op); - } else if (!strcmp(name, "cleartext-private-key")) { - ret = nc_server_config_cleartext_private_key(node, op); - } else if (!strcmp(name, "client-authentication")) { - ret = nc_server_config_client_authentication(node, op); - } else if (!strcmp(name, "ee-certs")) { - ret = nc_server_config_ee_certs(node, op); - } else if (!strcmp(name, "encryption-alg")) { - ret = nc_server_config_encryption_alg(node, op); - } else if (!strcmp(name, "endpoint-reference")) { - ret = nc_server_config_endpoint_reference(node, op); - } else if (!strcmp(name, "fingerprint")) { - ret = nc_server_config_fingerprint(node, op); - } else if (!strcmp(name, "host-key")) { - ret = nc_server_config_host_key(node, op); - } else if (!strcmp(name, "host-key-alg")) { - ret = nc_server_config_host_key_alg(node, op); - } else if (!strcmp(name, "idle-time")) { - ret = nc_server_config_idle_time(node, op); - } else if (!strcmp(name, "keepalives")) { - ret = nc_server_config_keepalives(node, op); - } else if (!strcmp(name, "keyboard-interactive")) { - ret = nc_server_config_keyboard_interactive(node, op); - } else if (!strcmp(name, "key-exchange-alg")) { - ret = nc_server_config_kex_alg(node, op); - } else if (!strcmp(name, "local-address")) { - ret = nc_server_config_local_address(node, op); - } else if (!strcmp(name, "local-port")) { - ret = nc_server_config_local_port(node, op); - } else if (!strcmp(name, "mac-alg")) { - ret = nc_server_config_mac_alg(node, op); - } else if (!strcmp(name, "map-type")) { - ret = nc_server_config_map_type(node, op); - } else if (!strcmp(name, "max-probes")) { - ret = nc_server_config_max_probes(node, op); - } else if (!strcmp(name, "name")) { - ret = nc_server_config_name(node, op); - } else if (!strcmp(name, "none")) { - ret = nc_server_config_none(node, op); - } else if (!strcmp(name, "password")) { - ret = nc_server_config_password(node, op); - } else if (!strcmp(name, "private-key-format")) { - ret = nc_server_config_private_key_format(node, op); - } else if (!strcmp(name, "probe-interval")) { - ret = nc_server_config_probe_interval(node, op); - } else if (!strcmp(name, "public-key")) { - ret = nc_server_config_public_key(node, op); - } else if (!strcmp(name, "public-key-format")) { - ret = nc_server_config_public_key_format(node, op); - } else if (!strcmp(name, "public-keys")) { - ret = nc_server_config_public_keys(node, op); - } else if (!strcmp(name, "remote-address")) { - ret = nc_server_config_remote_address(node, op); - } else if (!strcmp(name, "remote-port")) { - ret = nc_server_config_remote_port(node, op); - } else if (!strcmp(name, "ssh")) { - ret = nc_server_config_ssh(node, op); - } else if (!strcmp(name, "tls")) { - ret = nc_server_config_tls(node, op); - } else if (!strcmp(name, "tls-version")) { - ret = nc_server_config_tls_version(node, op); - } else if (!strcmp(name, "user")) { - ret = nc_server_config_user(node, op); - } else if (!strcmp(name, "use-system-auth")) { - ret = nc_server_config_use_system_auth(node, op); - } else if (!strcmp(name, "use-system-keys")) { - ret = nc_server_config_use_system_keys(node, op); - } -#endif /* NC_ENABLED_SSH_TLS */ + NC_NODE_GET_OP(node, parent_op, &op); - if (ret) { - ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node)); - return 1; + if (!endpt->opts.tls) { + /* op should not be NC_OP_DELETE if the diff is valid, otherwise this would have already been created */ + endpt->opts.tls = calloc(1, sizeof *endpt->opts.tls); + NC_CHECK_ERRMEM_RET(!endpt->opts.tls, 1); + endpt->ti = NC_TI_TLS; } - return 0; -} + /* config tcp client parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "tcp-client-parameters", 1, &n)); + NC_CHECK_RET(config_tcp_client_params(n, op, endpt)); -int -nc_server_config_ln2_netconf_server(const struct lyd_node *UNUSED(node), enum nc_operation op) -{ - uint32_t i; + /* config tls server parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "tls-server-parameters", 1, &n)); + NC_CHECK_RET(config_tls_server_params(n, op, endpt->opts.tls)); - assert((op == NC_OP_CREATE) || (op == NC_OP_DELETE)); + /* config netconf server parameters */ + NC_CHECK_RET(nc_lyd_find_child(node, "netconf-server-parameters", 1, &n)); + NC_CHECK_RET(config_tls_netconf_server_params(n, op, endpt->opts.tls)); if (op == NC_OP_DELETE) { - /* delete ignored modules */ - for (i = 0; i < server_opts.ignored_mod_count; ++i) { - free(server_opts.ignored_modules[i]); - } - free(server_opts.ignored_modules); - server_opts.ignored_modules = NULL; - server_opts.ignored_mod_count = 0; - -#ifdef NC_ENABLED_SSH_TLS - /* delete the intervals */ - pthread_mutex_lock(&server_opts.cert_exp_notif.lock); - free(server_opts.cert_exp_notif.intervals); - server_opts.cert_exp_notif.intervals = NULL; - server_opts.cert_exp_notif.interval_count = 0; - pthread_mutex_unlock(&server_opts.cert_exp_notif.lock); -#endif /* NC_ENABLED_SSH_TLS */ - + free(endpt->opts.tls); + endpt->opts.tls = NULL; + endpt->ti = NC_TI_NONE; } return 0; } -#ifdef NC_ENABLED_SSH_TLS +#endif /* NC_ENABLED_SSH_TLS */ static int -nc_server_config_yang_value2cert_exp_time(const char *value, struct nc_cert_exp_time *cert_exp_time) +config_ch_endpoint_name(const struct lyd_node *node, enum nc_operation op, + struct nc_ch_endpt *endpt) { - char unit; - long val; - - unit = value[strlen(value) - 1]; - val = strtol(value, NULL, 10); - switch (unit) { - case 'm': - cert_exp_time->months = val; - break; - case 'w': - cert_exp_time->weeks = val; - break; - case 'd': - cert_exp_time->days = val; - break; - case 'h': - cert_exp_time->hours = val; - break; - default: - ERR(NULL, "Unexpected unit in the certificate expiration time \"%s\".", value); - return 1; + if (op == NC_OP_DELETE) { + free(endpt->name); + endpt->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(endpt->name); + endpt->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!endpt->name, 1); } return 0; } static int -nc_server_config_create_interval(const char *anchor, const char *period) +config_ch_client_endpoint(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_ch_client *ch_client) { - int ret = 0; - struct nc_cert_exp_time anchor_time = {0}, period_time = {0}; + struct lyd_node *n; + enum nc_operation op; + const char *name; + LY_ARRAY_COUNT_TYPE i; + struct nc_ch_endpt *endpt = NULL; - server_opts.cert_exp_notif.intervals = nc_realloc(server_opts.cert_exp_notif.intervals, - (server_opts.cert_exp_notif.interval_count + 1) * sizeof *server_opts.cert_exp_notif.intervals); - NC_CHECK_ERRMEM_RET(!server_opts.cert_exp_notif.intervals, 1); + NC_NODE_GET_OP(node, parent_op, &op); - /* convert and set the anchor */ - ret = nc_server_config_yang_value2cert_exp_time(anchor, &anchor_time); - if (ret) { - goto cleanup; - } - server_opts.cert_exp_notif.intervals[server_opts.cert_exp_notif.interval_count].anchor = anchor_time; + /* get the name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); - /* convert and set the period */ - ret = nc_server_config_yang_value2cert_exp_time(period, &period_time); - if (ret) { - goto cleanup; + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the endpoint we are deleting/modifying */ + LY_ARRAY_FOR(ch_client->ch_endpts, i) { + if (!strcmp(ch_client->ch_endpts[i].name, name)) { + break; + } + } + assert(i < LY_ARRAY_COUNT(ch_client->ch_endpts)); + endpt = &ch_client->ch_endpts[i]; + } else if (op == NC_OP_CREATE) { + /* create a new endpoint and init it */ + LY_ARRAY_NEW_RET(LYD_CTX(node), ch_client->ch_endpts, endpt, 1); + endpt->sock_pending = -1; } - server_opts.cert_exp_notif.intervals[server_opts.cert_exp_notif.interval_count].period = period_time; - - ++server_opts.cert_exp_notif.interval_count; -cleanup: - return ret; -} + /* config name */ + NC_CHECK_RET(config_ch_endpoint_name(n, op, endpt)); -static void -nc_server_config_del_interval(const char *anchor, const char *period) -{ - int i; - struct nc_cert_exp_time anchor_time = {0}, period_time = {0}; +#ifdef NC_ENABLED_SSH_TLS + struct lyd_node *ssh, *tls; - if (nc_server_config_yang_value2cert_exp_time(anchor, &anchor_time)) { - return; - } - if (nc_server_config_yang_value2cert_exp_time(period, &period_time)) { - return; + /* config ssh/tls choice */ + NC_CHECK_RET(nc_lyd_find_child(node, "ssh", 0, &ssh)); + NC_CHECK_RET(nc_lyd_find_child(node, "tls", 0, &tls)); + if (ssh) { + NC_CHECK_RET(config_ch_endpoint_ssh(ssh, op, endpt)); + } else { + assert(tls); + NC_CHECK_RET(config_ch_endpoint_tls(tls, op, endpt)); } +#endif /* NC_ENABLED_SSH_TLS */ - for (i = 0; i < server_opts.cert_exp_notif.interval_count; ++i) { - if (!memcmp(&server_opts.cert_exp_notif.intervals[i].anchor, &anchor_time, sizeof anchor_time) && - !memcmp(&server_opts.cert_exp_notif.intervals[i].period, &period_time, sizeof period_time)) { - break; + /* all children processed, we can now delete the endpoint */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(ch_client->ch_endpts) - 1) { + ch_client->ch_endpts[i] = ch_client->ch_endpts[LY_ARRAY_COUNT(ch_client->ch_endpts) - 1]; } - } - if (i == server_opts.cert_exp_notif.interval_count) { - ERR(NULL, "Interval \"%s %s\" not found.", anchor, period); - return; + LY_ARRAY_DECREMENT_FREE(ch_client->ch_endpts); } - server_opts.cert_exp_notif.interval_count--; - if (!server_opts.cert_exp_notif.interval_count) { - free(server_opts.cert_exp_notif.intervals); - server_opts.cert_exp_notif.intervals = NULL; - } else if (i != server_opts.cert_exp_notif.interval_count) { - server_opts.cert_exp_notif.intervals[i] = - server_opts.cert_exp_notif.intervals[server_opts.cert_exp_notif.interval_count]; - } + return 0; } static int -nc_server_config_interval(const struct lyd_node *node, enum nc_operation op) +config_ch_client_endpoints(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_ch_client *ch_client) { - int ret = 0; - struct lyd_node *anchor, *period; - - assert(!strcmp(LYD_NAME(node), "interval")); - - anchor = lyd_child(node); - assert(anchor); - period = anchor->next; - assert(period); + struct lyd_node *n; + enum nc_operation op; - /* LOCK */ - pthread_mutex_lock(&server_opts.cert_exp_notif.lock); + NC_NODE_GET_OP(node, parent_op, &op); - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - ret = nc_server_config_create_interval(lyd_get_value(anchor), lyd_get_value(period)); - if (ret) { - goto cleanup; - } - } else { - nc_server_config_del_interval(lyd_get_value(anchor), lyd_get_value(period)); + /* config all the endpoints */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_ch_client_endpoint(n, op, ch_client)); } -cleanup: - pthread_mutex_unlock(&server_opts.cert_exp_notif.lock); - return ret; + return 0; } -#endif /* NC_ENABLED_SSH_TLS */ - static int -nc_server_config_ignored_module(const struct lyd_node *node, enum nc_operation op) +config_ch_conn_type_persistent(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_ch_client *ch_client) { - int ret = 0; - const char *mod_name; - uint16_t i; - - assert(!strcmp(LYD_NAME(node), "ignored-hello-module")); + enum nc_operation op; - mod_name = lyd_get_value(node); - - if (op == NC_OP_CREATE) { - /* add the module */ - ret = nc_server_config_realloc(mod_name, (void **)&server_opts.ignored_modules, - sizeof *server_opts.ignored_modules, &server_opts.ignored_mod_count); - } else { - /* find the module */ - for (i = 0; i < server_opts.ignored_mod_count; ++i) { - if (!strcmp(server_opts.ignored_modules[i], mod_name)) { - break; - } - } - assert(i < server_opts.ignored_mod_count); + NC_NODE_GET_OP(node, parent_op, &op); - /* remove the module by replacing it with the last */ - free(server_opts.ignored_modules[i]); - if (i < server_opts.ignored_mod_count - 1) { - server_opts.ignored_modules[i] = server_opts.ignored_modules[server_opts.ignored_mod_count - 1]; - } - --server_opts.ignored_mod_count; - if (!server_opts.ignored_mod_count) { - free(server_opts.ignored_modules); - server_opts.ignored_modules = NULL; - } + if (op == NC_OP_DELETE) { + ch_client->conn_type = NC_CH_CT_NOT_SET; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + ch_client->conn_type = NC_CH_PERSIST; } - return ret; + return 0; } static int -nc_server_config_parse_libnetconf2_netconf_server_node(const struct lyd_node *node, enum nc_operation op) +config_ch_periodic_period(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), + struct nc_ch_client *ch_client) { - const char *name = LYD_NAME(node); - int ret = 0; + /* default value => value always present */ + ch_client->period = strtoul(lyd_get_value(node), NULL, 10); + return 0; +} - if (!strcmp(name, "ln2-netconf-server")) { - ret = nc_server_config_ln2_netconf_server(node, op); - } -#ifdef NC_ENABLED_SSH_TLS - else if (!strcmp(name, "interval")) { - ret = nc_server_config_interval(node, op); - } -#endif /* NC_ENABLED_SSH_TLS */ - else if (!strcmp(name, "ignored-hello-module")) { - ret = nc_server_config_ignored_module(node, op); - } +static int +config_ch_periodic_anchor_time(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_ch_client *ch_client) +{ + enum nc_operation op; + struct lyd_value_date_and_time *anchor_time; - if (ret) { - ERR(NULL, "Configuring node \"%s\" failed.", LYD_NAME(node)); - return 1; + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + ch_client->anchor_time = 0; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* get the date and time value from the node directly */ + LYD_VALUE_GET(&((struct lyd_node_term *)node)->value, anchor_time); } return 0; } -/** - * @brief Listen on all endpoints defined in the new netconf-server configuration. - * - * This function is called after all netconf-server configuration nodes are processed. - * - * @param[in] node The `netconf-server` configuration node. - * @return 0 on success, 1 on error. - */ static int -nc_server_config_listen_all_endpoints(const struct lyd_node *node) +config_ch_periodic_idle_timeout(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), + struct nc_ch_client *ch_client) { - int r = 0; - struct lyd_node *n, *iter; - struct nc_endpt *endpt; - struct nc_bind *bind; - struct lyd_meta *m; + /* default value => value always present */ + ch_client->idle_timeout = strtoul(lyd_get_value(node), NULL, 10); + return 0; +} + +static int +config_ch_conn_type_periodic(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_ch_client *ch_client) +{ + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); - NC_CHECK_ERR_RET(strcmp(LYD_NAME(node), "netconf-server"), - ERR(NULL, "Unexpected node \"%s\" encountered, expected \"netconf-server\".", LYD_NAME(node)), 1); + ch_client->conn_type = NC_CH_PERIOD; - /* find the listen endpoints */ - r = lyd_find_path(node, "listen/endpoints", 0, &n); - NC_CHECK_RET(r && (r != LY_ENOTFOUND), 1); + /* config period */ + NC_CHECK_RET(nc_lyd_find_child(node, "period", 1, &n)); + NC_CHECK_RET(config_ch_periodic_period(n, op, ch_client)); + /* config anchor time */ + NC_CHECK_RET(nc_lyd_find_child(node, "anchor-time", 0, &n)); if (n) { - /* go over all the endpoints */ - LY_LIST_FOR(lyd_child(n), iter) { - if ((m = lyd_find_meta(iter->meta, NULL, "yang:operation"))) { - if (!strcmp(lyd_get_meta_value(m), "delete")) { - continue; - } - } - /* get the endpoint and bind structs from the node */ - NC_CHECK_RET(nc_server_config_get_endpt(iter, &endpt, &bind)); + NC_CHECK_RET(config_ch_periodic_anchor_time(n, op, ch_client)); + } - /* listen on the endpoint */ - NC_CHECK_RET(nc_server_set_address_port(endpt, bind, bind->address, bind->port)); - } + /* config idle timeout */ + NC_CHECK_RET(nc_lyd_find_child(node, "idle-timeout", 1, &n)); + NC_CHECK_RET(config_ch_periodic_idle_timeout(n, op, ch_client)); + + /* all children processed, we can now delete the connection type */ + if (op == NC_OP_DELETE) { + ch_client->conn_type = NC_CH_CT_NOT_SET; } return 0; } -int -nc_server_config_process_tree(const struct lyd_node *node, enum nc_operation parent_op, NC_MODULE module) +static int +config_ch_client_connection_type(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_ch_client *ch_client) { - struct lyd_node *child; - struct lyd_meta *m; - enum nc_operation current_op = NC_OP_UNKNOWN; - int ret; + struct lyd_node *persistent, *periodic; + enum nc_operation op; - assert(node); + NC_NODE_GET_OP(node, parent_op, &op); - /* 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; - } + /* config persistent / periodic choice, + * the choice itself is mandatory, but both containers are presence, so need to check explicitly */ + NC_CHECK_RET(nc_lyd_find_child(node, "persistent", 0, &persistent)); + NC_CHECK_RET(nc_lyd_find_child(node, "periodic", 0, &periodic)); + if (persistent) { + NC_CHECK_RET(config_ch_conn_type_persistent(persistent, op, ch_client)); + } else if (periodic) { + NC_CHECK_RET(config_ch_conn_type_periodic(periodic, op, ch_client)); } - /* node has no op, inherit from the parent */ - if (!current_op) { - if (!parent_op) { - ERR(NULL, "Unknown operation for node \"%s\".", LYD_NAME(node)); - return 1; - } + return 0; +} - current_op = parent_op; - } +static int +config_ch_reconnect_start_with(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), + struct nc_ch_client *ch_client) +{ + const char *start_with; - switch (current_op) { - case NC_OP_NONE: - break; - case NC_OP_CREATE: - case NC_OP_DELETE: - case NC_OP_REPLACE: -#ifdef NC_ENABLED_SSH_TLS - if (module == NC_MODULE_KEYSTORE) { - ret = nc_server_config_parse_keystore_node(node, current_op); - } else if (module == NC_MODULE_TRUSTSTORE) { - ret = nc_server_config_parse_truststore_node(node, current_op); - } else -#endif /* NC_ENABLED_SSH_TLS */ - if (module == NC_MODULE_LIBNETCONF2_NETCONF_SERVER) { - ret = nc_server_config_parse_libnetconf2_netconf_server_node(node, current_op); - } else if (module == NC_MODULE_NETCONF_SERVER) { - ret = nc_server_config_parse_netconf_server_node(node, current_op); - } else { - ERRINT; - ret = 1; + /* default value => value always present */ + start_with = lyd_get_value(node); + assert(start_with); + + if (!strcmp(start_with, "first-listed")) { + ch_client->start_with = NC_CH_FIRST_LISTED; + } else if (!strcmp(start_with, "last-connected")) { + ch_client->start_with = NC_CH_LAST_CONNECTED; + } else if (!strcmp(start_with, "random-selection")) { + ch_client->start_with = NC_CH_RANDOM; + } else { + ERR(NULL, "Unknown call-home reconnect start-with value \"%s\".", start_with); + return 1; + } + + return 0; +} + +static int +config_ch_reconnect_max_wait(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), + struct nc_ch_client *ch_client) +{ + /* default value => value always present */ + ch_client->max_wait = strtoul(lyd_get_value(node), NULL, 10); + return 0; +} + +static int +config_ch_reconnect_max_attempts(const struct lyd_node *node, enum nc_operation UNUSED(parent_op), + struct nc_ch_client *ch_client) +{ + /* default value => value always present */ + ch_client->max_attempts = strtoul(lyd_get_value(node), NULL, 10); + return 0; +} + +static int +config_ch_client_reconnect_strategy(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_ch_client *ch_client) +{ + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* config start with */ + NC_CHECK_RET(nc_lyd_find_child(node, "start-with", 1, &n)); + NC_CHECK_RET(config_ch_reconnect_start_with(n, op, ch_client)); + + /* config max wait */ + NC_CHECK_RET(nc_lyd_find_child(node, "max-wait", 1, &n)); + NC_CHECK_RET(config_ch_reconnect_max_wait(n, op, ch_client)); + + /* config max attempts */ + NC_CHECK_RET(nc_lyd_find_child(node, "max-attempts", 1, &n)); + NC_CHECK_RET(config_ch_reconnect_max_attempts(n, op, ch_client)); + + return 0; +} + +static int +config_netconf_client(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_config *config) +{ + struct lyd_node *n; + enum nc_operation op; + const char *name; + LY_ARRAY_COUNT_TYPE i, j; + struct nc_ch_client *ch_client = NULL; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* get the name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the client we are deleting/modifying */ + LY_ARRAY_FOR(config->ch_clients, i) { + if (!strcmp(config->ch_clients[i].name, name)) { + break; + } + } + assert(i < LY_ARRAY_COUNT(config->ch_clients)); + ch_client = &config->ch_clients[i]; + } else if (op == NC_OP_CREATE) { + /* create a new client */ + LY_ARRAY_NEW_RET(LYD_CTX(node), config->ch_clients, ch_client, 1); + } + + /* config name */ + NC_CHECK_RET(config_ch_client_name(n, op, ch_client)); + + /* config endpoints */ + NC_CHECK_RET(nc_lyd_find_child(node, "endpoints", 1, &n)); + NC_CHECK_RET(config_ch_client_endpoints(n, op, ch_client)); + + /* config connection type */ + NC_CHECK_RET(nc_lyd_find_child(node, "connection-type", 1, &n)); + NC_CHECK_RET(config_ch_client_connection_type(n, op, ch_client)); + + /* config reconnect strategy */ + NC_CHECK_RET(nc_lyd_find_child(node, "reconnect-strategy", 1, &n)); + NC_CHECK_RET(config_ch_client_reconnect_strategy(n, op, ch_client)); + + /* all children processed, we can now delete the client */ + if (op == NC_OP_DELETE) { + /* CH THREADS DATA RD LOCK */ + NC_CHECK_RET(pthread_rwlock_rdlock(&server_opts.ch_threads_lock), 1); + + /* find the thread data for this CH client, not found <==> CH thread not running */ + LY_ARRAY_FOR(server_opts.ch_threads, j) { + if (!strcmp(server_opts.ch_threads[j]->client_name, name)) { + break; + } } - if (ret) { - return ret; + + if (j < LY_ARRAY_COUNT(server_opts.ch_threads)) { + /* the CH thread is running, notify it to stop */ + pthread_mutex_lock(&server_opts.ch_threads[j]->cond_lock); + server_opts.ch_threads[j]->thread_running = 0; + pthread_cond_signal(&server_opts.ch_threads[j]->cond); + pthread_mutex_unlock(&server_opts.ch_threads[j]->cond_lock); } - break; - default: - break; + + /* CH THREADS DATA UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_threads_lock); + + /* we can use 'i' from above */ + if (i < LY_ARRAY_COUNT(config->ch_clients) - 1) { + config->ch_clients[i] = config->ch_clients[LY_ARRAY_COUNT(config->ch_clients) - 1]; + } + LY_ARRAY_DECREMENT_FREE(config->ch_clients); + } + + return 0; +} + +static int +config_call_home(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_config *config) +{ + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* configure all netconf clients */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_netconf_client(n, op, config)); + } + + return 0; +} + +/** + * @brief Handler for the /ietf-netconf-server:netconf-server configuration subtree. + * + * This function, and all the other config_* functions, traverse the tree in a post-order manner. + * All the children are processed before the parent node. + * In case of a delete operation, the config handlers of the children are called first, + * and only when all children are processed, the parent node's handler may free any configuration associated + * with the given parent node, recursively. + */ +static int +config_netconf_server(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_config *config) +{ + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* configure listen */ + NC_CHECK_RET(nc_lyd_find_child(node, "listen", 0, &n)); + if (n) { + NC_CHECK_RET(config_listen(n, op, config)); + } + + /* configure call-home */ + NC_CHECK_RET(nc_lyd_find_child(node, "call-home", 0, &n)); + if (n) { + NC_CHECK_RET(config_call_home(n, op, config)); + } + + return 0; +} + +/** + * @brief Find and configure the /ietf-netconf-server:netconf-server subtree. + * + * Does nothing if the subtree is not present. + * + * @param[in] tree Configuration YANG data tree to search in. + * @param[in] is_diff Flag indicating if the operation is a diff. + * @param[in,out] config Server configuration to modify. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_netconf_server(const struct lyd_node *tree, int is_diff, struct nc_server_config *config) +{ + int r, rc = 0; + uint32_t prev_lo; + struct lyd_node *subtree; + enum nc_operation initial_op; + + prev_lo = ly_log_options(0); + + /* try to find the netconf-server subtree */ + r = lyd_find_path(tree, "/ietf-netconf-server:netconf-server", 0, &subtree); + if (r) { + if (r == LY_ENOTFOUND) { + /* netconf-server not present, nothing to configure */ + goto cleanup; + } + ERR(NULL, "Unable to find the netconf-server subtree in the YANG data."); + rc = 1; + goto cleanup; + } + + /* configure the netconf-server */ + initial_op = is_diff ? NC_OP_UNKNOWN : NC_OP_CREATE; + rc = config_netconf_server(subtree, initial_op, config); + +cleanup: + ly_log_options(prev_lo); + return rc; +} + +#ifdef NC_ENABLED_SSH_TLS + +/* + * ===================================================================================== + * ietf-keystore handlers + * ===================================================================================== + */ + +static int +config_asymmetric_key_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_asymmetric_key *key) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(key->name); + key->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(key->name); + key->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!key->name, 1); + } + + return 0; +} + +static int +config_certificate_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_certificate *cert) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(cert->name); + cert->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(cert->name); + cert->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!cert->name, 1); + } + + return 0; +} + +static int +config_certificate_data(const struct lyd_node *node, enum nc_operation parent_op, struct nc_certificate *cert) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(cert->data); + cert->data = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(cert->data); + cert->data = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!cert->data, 1); } - if (current_op != NC_OP_DELETE) { - LY_LIST_FOR(lyd_child(node), child) { - if (nc_server_config_process_tree(child, current_op, module)) { - return 1; + return 0; +} + +static int +config_certificate_expiration(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} + +static int +config_asymmetric_key_cert(const struct lyd_node *node, enum nc_operation parent_op, struct nc_keystore_entry *entry) +{ + struct lyd_node *n; + enum nc_operation op; + struct nc_certificate *cert = NULL; + const char *name; + LY_ARRAY_COUNT_TYPE i; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the certificate we are deleting */ + LY_ARRAY_FOR(entry->certs, i) { + if (!strcmp(entry->certs[i].name, name)) { + break; } } + assert(i < LY_ARRAY_COUNT(entry->certs)); + cert = &entry->certs[i]; + } else if (op == NC_OP_CREATE) { + /* create a new certificate */ + LY_ARRAY_NEW_RET(LYD_CTX(node), entry->certs, cert, 1); + } + + /* config certificate name */ + NC_CHECK_RET(config_certificate_name(n, op, cert)); + + /* config certificate data */ + NC_CHECK_RET(nc_lyd_find_child(node, "cert-data", 1, &n)); + NC_CHECK_RET(config_certificate_data(n, op, cert)); + + /* config certificate expiration */ + NC_CHECK_RET(nc_lyd_find_child(node, "certificate-expiration", 0, &n)); + if (n) { + NC_CHECK_RET(config_certificate_expiration(n, op)); } - if (!strcmp(LYD_NAME(node), "netconf-server")) { - /* all of the nodes within the netconf-server module are processed, - * we can now start listening on all new endpoints */ - NC_CHECK_RET(nc_server_config_listen_all_endpoints(node)); + /* all children processed, we can now delete the certificate */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(entry->certs) - 1) { + entry->certs[i] = entry->certs[LY_ARRAY_COUNT(entry->certs) - 1]; + } + LY_ARRAY_DECREMENT_FREE(entry->certs); } return 0; } -API int -nc_server_config_load_modules(struct ly_ctx **ctx) +static int +config_asymmetric_key_certs(const struct lyd_node *node, enum nc_operation parent_op, struct nc_keystore_entry *entry) { - int i, new_ctx = 0; + struct lyd_node *n; + enum nc_operation op; - if (!*ctx) { - if (ly_ctx_new(NC_SERVER_SEARCH_DIR, 0, ctx)) { - ERR(NULL, "Couldn't create new libyang context.\n"); - goto error; + NC_NODE_GET_OP(node, parent_op, &op); + + /* configure all certificates */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_asymmetric_key_cert(n, op, entry)); + } + + return 0; +} + +static int +config_asymmetric_key(const struct lyd_node *node, enum nc_operation parent_op, struct nc_keystore *keystore) +{ + struct lyd_node *n, *cleartext = NULL, *hidden = NULL, *encrypted = NULL; + enum nc_operation op; + const char *name; + struct nc_keystore_entry *entry = NULL; + LY_ARRAY_COUNT_TYPE i; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the asymmetric key (keystore entry) we are deleting */ + LY_ARRAY_FOR(keystore->entries, i) { + if (!strcmp(keystore->entries[i].asym_key.name, name)) { + break; + } } - new_ctx = 1; + assert(i < LY_ARRAY_COUNT(keystore->entries)); + entry = &keystore->entries[i]; + } else if (op == NC_OP_CREATE) { + /* create a new asymmetric key entry */ + LY_ARRAY_NEW_RET(LYD_CTX(node), keystore->entries, entry, 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, csr-generation, p10-csr-format, certificate-expiration-notification, - * 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[] = {"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 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 */ - 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 *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", "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 *iana_tls_cipher_suite_algs[] = {NULL}; - /* all features */ - const char *libnetconf2_netconf_server[] = {NULL}; + /* config asymmetric key name */ + NC_CHECK_RET(config_asymmetric_key_name(n, op, &entry->asym_key)); - const char *module_names[] = { - "ietf-netconf-server", "ietf-x509-cert-to-name", "ietf-crypto-types", "ietf-tcp-common", "ietf-tcp-server", - "ietf-tcp-client", "ietf-ssh-common", "ietf-ssh-server", "iana-ssh-encryption-algs", - "iana-ssh-key-exchange-algs", "iana-ssh-mac-algs", "iana-ssh-public-key-algs", "iana-crypt-hash", - "ietf-keystore", "ietf-truststore", "ietf-tls-common", "ietf-tls-server", "iana-tls-cipher-suite-algs", - "libnetconf2-netconf-server", NULL - }; + /* config asymmetric key public key format */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key-format", 0, &n)); + if (n) { + NC_CHECK_RET(config_pubkey_format(n, op, &entry->asym_key.pubkey)); + } - 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, iana_tls_cipher_suite_algs, - libnetconf2_netconf_server, NULL - }; + /* config asymmetric key public key */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key", 0, &n)); + if (n) { + NC_CHECK_RET(config_pubkey_data(n, op, &entry->asym_key.pubkey)); + } + + /* config asymmetric key private key format */ + NC_CHECK_RET(nc_lyd_find_child(node, "private-key-format", 0, &n)); + if (n) { + NC_CHECK_RET(config_privkey_format(n, op, &entry->asym_key.privkey)); + } + + /* config privkey data, case/choice node => only one can be present */ + NC_CHECK_RET(nc_lyd_find_child(node, "cleartext-private-key", 0, &cleartext)); + NC_CHECK_RET(nc_lyd_find_child(node, "hidden-private-key", 0, &hidden)); + NC_CHECK_RET(nc_lyd_find_child(node, "encrypted-private-key", 0, &encrypted)); + if (cleartext) { + NC_CHECK_RET(config_cleartext_privkey_data(cleartext, op, &entry->asym_key.privkey)); + } else if (hidden) { + NC_CHECK_RET(config_hidden_privkey_data(hidden, op)); + } else if (encrypted) { + NC_CHECK_RET(config_encrypted_privkey_data(encrypted, op)); + } + + /* config asymmetric key certificates */ + NC_CHECK_RET(nc_lyd_find_child(node, "certificates", 1, &n)); + NC_CHECK_RET(config_asymmetric_key_certs(n, op, entry)); + + /* config generate csr */ + NC_CHECK_RET(nc_lyd_find_child(node, "generate-csr", 0, &n)); + if (n) { + NC_CHECK_RET(config_generate_csr(n, op)); + } + + /* all children processed, we can now delete the asymmetric key entry */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(keystore->entries) - 1) { + keystore->entries[i] = keystore->entries[LY_ARRAY_COUNT(keystore->entries) - 1]; + } + LY_ARRAY_DECREMENT_FREE(keystore->entries); + } + + return 0; +} + +static int +config_asymmetric_keys(const struct lyd_node *node, enum nc_operation parent_op, struct nc_keystore *keystore) +{ + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* configure all asymmetric keys */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_asymmetric_key(n, op, keystore)); + } + + return 0; +} + +static int +config_symmetric_keys(const struct lyd_node *node, enum nc_operation UNUSED(parent_op)) +{ + CONFIG_LOG_UNSUPPORTED(node); + return 0; +} + +static int +config_keystore(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_config *config) +{ + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* configure asymmetric keys */ + NC_CHECK_RET(nc_lyd_find_child(node, "asymmetric-keys", 0, &n)); + if (n) { + NC_CHECK_RET(config_asymmetric_keys(n, op, &config->keystore)); + } + + /* configure symmetric keys */ + NC_CHECK_RET(nc_lyd_find_child(node, "symmetric-keys", 0, &n)); + if (n) { + NC_CHECK_RET(config_symmetric_keys(n, op)); + } + + return 0; +} + +/** + * @brief Find and configure the /ietf-keystore:keystore subtree. + * + * Does nothing if the subtree is not present. + * + * @param[in] tree Configuration YANG data tree to search in. + * @param[in] is_diff Flag indicating if the operation is a diff. + * @param[in,out] config Server configuration to modify. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_keystore(const struct lyd_node *tree, int is_diff, struct nc_server_config *config) +{ + int r, rc = 0; + uint32_t prev_lo; + struct lyd_node *subtree; + enum nc_operation initial_op; + + prev_lo = ly_log_options(0); + + /* try to find the keystore subtree */ + r = lyd_find_path(tree, "/ietf-keystore:keystore", 0, &subtree); + if (r) { + if (r == LY_ENOTFOUND) { + /* keystore not present, nothing to configure */ + goto cleanup; + } + ERR(NULL, "Unable to find the keystore subtree in the YANG data."); + rc = 1; + goto cleanup; + } + + /* configure the keystore */ + initial_op = is_diff ? NC_OP_UNKNOWN : NC_OP_CREATE; + rc = config_keystore(subtree, initial_op, config); + +cleanup: + ly_log_options(prev_lo); + return rc; +} + +/* + * ===================================================================================== + * ietf-truststore handlers + * ===================================================================================== + */ + +static int +config_certificate_bag_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_certificate_bag *bag) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(bag->name); + bag->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(bag->name); + bag->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!bag->name, 1); + } + + return 0; +} + +static int +config_certificate_bag_description(const struct lyd_node *node, enum nc_operation parent_op, struct nc_certificate_bag *bag) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(bag->description); + bag->description = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(bag->description); + bag->description = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!bag->description, 1); + } + + return 0; +} + +static int +config_certificate_bag_cert(const struct lyd_node *node, enum nc_operation parent_op, struct nc_certificate_bag *bag) +{ + struct lyd_node *n; + enum nc_operation op; + struct nc_certificate *cert = NULL; + const char *name; + LY_ARRAY_COUNT_TYPE i; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the certificate we are deleting */ + LY_ARRAY_FOR(bag->certs, i) { + if (!strcmp(bag->certs[i].name, name)) { + break; + } + } + assert(i < LY_ARRAY_COUNT(bag->certs)); + cert = &bag->certs[i]; + } else if (op == NC_OP_CREATE) { + /* create a new certificate */ + LY_ARRAY_NEW_RET(LYD_CTX(node), bag->certs, cert, 1); + } + + /* config certificate name */ + NC_CHECK_RET(config_certificate_name(n, op, cert)); + + /* config certificate data */ + NC_CHECK_RET(nc_lyd_find_child(node, "cert-data", 1, &n)); + NC_CHECK_RET(config_certificate_data(n, op, cert)); + + /* config certificate expiration */ + NC_CHECK_RET(nc_lyd_find_child(node, "certificate-expiration", 0, &n)); + if (n) { + NC_CHECK_RET(config_certificate_expiration(n, op)); + } + + /* all children processed, we can now delete the certificate */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(bag->certs) - 1) { + bag->certs[i] = bag->certs[LY_ARRAY_COUNT(bag->certs) - 1]; + } + LY_ARRAY_DECREMENT_FREE(bag->certs); + } + + return 0; +} + +static int +config_certificate_bag(const struct lyd_node *node, enum nc_operation parent_op, struct nc_truststore *truststore) +{ + struct lyd_node *n; + enum nc_operation op; + const char *name; + struct nc_certificate_bag *bag = NULL; + LY_ARRAY_COUNT_TYPE i; + uint32_t j; + struct ly_set *set = NULL; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the certificate bag we are deleting */ + LY_ARRAY_FOR(truststore->cert_bags, i) { + if (!strcmp(truststore->cert_bags[i].name, name)) { + break; + } + } + assert(i < LY_ARRAY_COUNT(truststore->cert_bags)); + bag = &truststore->cert_bags[i]; + } else if (op == NC_OP_CREATE) { + /* create a new certificate bag */ + LY_ARRAY_NEW_RET(LYD_CTX(node), truststore->cert_bags, bag, 1); + } + + /* config certificate bag name */ + NC_CHECK_RET(config_certificate_bag_name(n, op, bag)); + + /* config certificate bag description */ + NC_CHECK_RET(nc_lyd_find_child(node, "description", 0, &n)); + if (n) { + NC_CHECK_RET(config_certificate_bag_description(n, op, bag)); + } + + /* config certificate bag certificates */ + NC_CHECK_RET(lyd_find_xpath(node, "certificate", &set), 1); + for (j = 0; j < set->count; ++j) { + NC_CHECK_GOTO(config_certificate_bag_cert(set->dnodes[j], op, bag), cleanup); + } + + /* all children processed, we can now delete the certificate bag */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(truststore->cert_bags) - 1) { + truststore->cert_bags[i] = truststore->cert_bags[LY_ARRAY_COUNT(truststore->cert_bags) - 1]; + } + LY_ARRAY_DECREMENT_FREE(truststore->cert_bags); + } + +cleanup: + ly_set_free(set, NULL); + return 0; +} + +static int +config_certificate_bags(const struct lyd_node *node, enum nc_operation parent_op, struct nc_truststore *truststore) +{ + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* configure all certificate bags */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_certificate_bag(n, op, truststore)); + } + + return 0; +} + +static int +config_public_key_bag_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_public_key_bag *bag) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(bag->name); + bag->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(bag->name); + bag->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!bag->name, 1); + } + + return 0; +} + +static int +config_public_key_bag_description(const struct lyd_node *node, enum nc_operation parent_op, struct nc_public_key_bag *bag) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(bag->description); + bag->description = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(bag->description); + bag->description = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!bag->description, 1); + } + + return 0; +} + +static int +config_public_key_bag_pubkey_name(const struct lyd_node *node, enum nc_operation parent_op, struct nc_public_key *pubkey) +{ + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + free(pubkey->name); + pubkey->name = NULL; + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + free(pubkey->name); + pubkey->name = strdup(lyd_get_value(node)); + NC_CHECK_ERRMEM_RET(!pubkey->name, 1); + } + + return 0; +} + +static int +config_public_key_bag_pubkey(const struct lyd_node *node, enum nc_operation parent_op, struct nc_public_key_bag *bag) +{ + struct lyd_node *n; + enum nc_operation op; + const char *name; + struct nc_public_key *pubkey = NULL; + LY_ARRAY_COUNT_TYPE i; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the public key we are deleting */ + LY_ARRAY_FOR(bag->pubkeys, i) { + if (!strcmp(bag->pubkeys[i].name, name)) { + break; + } + } + assert(i < LY_ARRAY_COUNT(bag->pubkeys)); + pubkey = &bag->pubkeys[i]; + } else if (op == NC_OP_CREATE) { + /* create a new public key */ + LY_ARRAY_NEW_RET(LYD_CTX(node), bag->pubkeys, pubkey, 1); + } + + /* config public key name */ + NC_CHECK_RET(config_public_key_bag_pubkey_name(n, op, pubkey)); + + /* config public key format */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key-format", 1, &n)); + NC_CHECK_RET(config_pubkey_format(n, op, pubkey)); + + /* config public key data */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key", 1, &n)); + NC_CHECK_RET(config_pubkey_data(n, op, pubkey)); + + /* all children processed, we can now delete the public key */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(bag->pubkeys) - 1) { + bag->pubkeys[i] = bag->pubkeys[LY_ARRAY_COUNT(bag->pubkeys) - 1]; + } + LY_ARRAY_DECREMENT_FREE(bag->pubkeys); + } + + return 0; +} + +static int +config_public_key_bag(const struct lyd_node *node, enum nc_operation parent_op, struct nc_truststore *truststore) +{ + struct lyd_node *n; + enum nc_operation op; + const char *name; + struct nc_public_key_bag *bag = NULL; + LY_ARRAY_COUNT_TYPE i; + struct ly_set *set = NULL; + uint32_t j; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* name (list key) */ + NC_CHECK_RET(nc_lyd_find_child(node, "name", 1, &n)); + name = lyd_get_value(n); + assert(name); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* find the public key bag we are deleting */ + LY_ARRAY_FOR(truststore->pubkey_bags, i) { + if (!strcmp(truststore->pubkey_bags[i].name, name)) { + break; + } + } + assert(i < LY_ARRAY_COUNT(truststore->pubkey_bags)); + bag = &truststore->pubkey_bags[i]; + } else if (op == NC_OP_CREATE) { + /* create a new public key bag */ + LY_ARRAY_NEW_RET(LYD_CTX(node), truststore->pubkey_bags, bag, 1); + } + + /* config public key bag name */ + NC_CHECK_RET(config_public_key_bag_name(n, op, bag)); + + /* config public key bag description */ + NC_CHECK_RET(nc_lyd_find_child(node, "description", 0, &n)); + if (n) { + NC_CHECK_RET(config_public_key_bag_description(n, op, bag)); + } + + /* config public key bag public keys */ + NC_CHECK_RET(lyd_find_xpath(node, "public-key", &set), 1); + for (j = 0; j < set->count; ++j) { + NC_CHECK_GOTO(config_public_key_bag_pubkey(set->dnodes[j], op, bag), cleanup); + } + + /* all children processed, we can now delete the public key bag */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(truststore->pubkey_bags) - 1) { + truststore->pubkey_bags[i] = truststore->pubkey_bags[LY_ARRAY_COUNT(truststore->pubkey_bags) - 1]; + } + LY_ARRAY_DECREMENT_FREE(truststore->pubkey_bags); + } + +cleanup: + ly_set_free(set, NULL); + return 0; +} + +static int +config_public_key_bags(const struct lyd_node *node, enum nc_operation parent_op, struct nc_truststore *truststore) +{ + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* configure all public key bags */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_public_key_bag(n, op, truststore)); + } + + return 0; +} + +static int +config_truststore(const struct lyd_node *node, enum nc_operation parent_op, struct nc_server_config *config) +{ + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* configure certificate bags */ + NC_CHECK_RET(nc_lyd_find_child(node, "certificate-bags", 0, &n)); + if (n) { + NC_CHECK_RET(config_certificate_bags(n, op, &config->truststore)); + } + + /* configure public key bags */ + NC_CHECK_RET(nc_lyd_find_child(node, "public-key-bags", 0, &n)); + if (n) { + NC_CHECK_RET(config_public_key_bags(n, op, &config->truststore)); + } + + return 0; +} + +/** + * @brief Find and configure the /ietf-truststore:truststore subtree. + * + * Does nothing if the subtree is not present. + * + * @param[in] tree Configuration YANG data tree to search in. + * @param[in] is_diff Flag indicating if the operation is a diff. + * @param[in] config Server configuration to update. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_truststore(const struct lyd_node *tree, int is_diff, struct nc_server_config *config) +{ + int r, rc = 0; + uint32_t prev_lo; + struct lyd_node *subtree; + enum nc_operation initial_op; + + prev_lo = ly_log_options(0); + + /* try to find the truststore subtree */ + r = lyd_find_path(tree, "/ietf-truststore:truststore", 0, &subtree); + if (r) { + if (r == LY_ENOTFOUND) { + /* truststore not present, nothing to configure */ + goto cleanup; + } + ERR(NULL, "Unable to find the truststore subtree in the YANG data."); + rc = 1; + goto cleanup; + } + + /* configure the truststore */ + initial_op = is_diff ? NC_OP_UNKNOWN : NC_OP_CREATE; + rc = config_truststore(subtree, initial_op, config); + +cleanup: + ly_log_options(prev_lo); + return rc; +} + +#endif /* NC_ENABLED_SSH_TLS */ + +/* + * ===================================================================================== + * libnetconf2-netconf-server handlers + * ===================================================================================== + */ + +#ifdef NC_ENABLED_SSH_TLS + +/** + * @brief Convert a string representation of certificate expiration time to struct. + * + * @note See libnetconf2-netconf-server.yang for the format of the string. + * + * @param[in] str String representation of the certificate expiration time. + * @param[out] cert_exp_time Converted certificate expiration time struct. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_cert_exp_time_from_str(const char *str, struct nc_cert_exp_time *cert_exp_time) +{ + char unit; + long value; + + unit = str[strlen(str) - 1]; + value = strtol(str, NULL, 10); + + switch (unit) { + case 'm': + cert_exp_time->months = value; + break; + case 'w': + cert_exp_time->weeks = value; + break; + case 'd': + cert_exp_time->days = value; + break; + case 'h': + cert_exp_time->hours = value; + break; + default: + ERR(NULL, "Invalid time interval unit '%c' in the certificate expiration time \"%s\".", unit, str); + return 1; + } + + return 0; +} + +static int +config_cert_exp_notif_anchor(const struct lyd_node *node, enum nc_operation parent_op, struct nc_cert_exp_time *anchor) +{ + enum nc_operation op; + const char *value; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + memset(anchor, 0, sizeof *anchor); + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + value = lyd_get_value(node); + assert(value); + NC_CHECK_RET(nc_server_config_cert_exp_time_from_str(value, anchor)); + } + + return 0; +} + +static int +config_cert_exp_notif_period(const struct lyd_node *node, enum nc_operation parent_op, struct nc_cert_exp_time *period) +{ + enum nc_operation op; + const char *value; + + NC_NODE_GET_OP(node, parent_op, &op); + + if (op == NC_OP_DELETE) { + memset(period, 0, sizeof *period); + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + value = lyd_get_value(node); + assert(value); + NC_CHECK_RET(nc_server_config_cert_exp_time_from_str(value, period)); + } + + return 0; +} + +static int +config_cert_exp_notif_interval(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_config *config) +{ + struct lyd_node *anchor_node, *period_node; + enum nc_operation op; + const char *anchor_str, *period_str; + uint32_t i; + struct nc_cert_exp_time anchor = {0}, period = {0}; + struct nc_cert_exp_time_interval *interval = NULL; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* anchor and period (list keys) */ + NC_CHECK_RET(nc_lyd_find_child(node, "anchor", 1, &anchor_node)); + anchor_str = lyd_get_value(anchor_node); + assert(anchor_str); + NC_CHECK_RET(nc_lyd_find_child(node, "period", 1, &period_node)); + period_str = lyd_get_value(period_node); + assert(period_str); + + /* convert anchor and period from str to time interval */ + NC_CHECK_RET(nc_server_config_cert_exp_time_from_str(anchor_str, &anchor)); + NC_CHECK_RET(nc_server_config_cert_exp_time_from_str(period_str, &period)); + + if ((op == NC_OP_DELETE) || (op == NC_OP_NONE)) { + /* get the interval we are deleting/modifying */ + LY_ARRAY_FOR(config->cert_exp_notif_intervals, i) { + if (!memcmp(&config->cert_exp_notif_intervals[i].anchor, &anchor, sizeof anchor) && + !memcmp(&config->cert_exp_notif_intervals[i].period, &period, sizeof period)) { + break; + } + } + + if (i == LY_ARRAY_COUNT(config->cert_exp_notif_intervals)) { + ERR(NULL, "Trying to delete a non-existing certificate expiration notification interval."); + return 1; + } + interval = &config->cert_exp_notif_intervals[i]; + } else if (op == NC_OP_CREATE) { + /* create a new interval */ + LY_ARRAY_NEW_RET(LYD_CTX(node), config->cert_exp_notif_intervals, interval, 1); + } + + /* config anchor */ + NC_CHECK_RET(config_cert_exp_notif_anchor(anchor_node, op, &interval->anchor)); + + /* config period */ + NC_CHECK_RET(config_cert_exp_notif_period(period_node, op, &interval->period)); + + /* all children processed, we can now delete the interval */ + if (op == NC_OP_DELETE) { + if (i < LY_ARRAY_COUNT(config->cert_exp_notif_intervals) - 1) { + config->cert_exp_notif_intervals[i] = + config->cert_exp_notif_intervals[LY_ARRAY_COUNT(config->cert_exp_notif_intervals) - 1]; + } + LY_ARRAY_DECREMENT_FREE(config->cert_exp_notif_intervals); + } + + return 0; +} + +static int +config_cert_exp_notif_intervals(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_config *config) +{ + struct lyd_node *n; + enum nc_operation op; + + NC_NODE_GET_OP(node, parent_op, &op); + + /* config all intervals */ + LY_LIST_FOR(lyd_child(node), n) { + NC_CHECK_RET(config_cert_exp_notif_interval(n, op, config)); + } + + return 0; +} + +#endif /* NC_ENABLED_SSH_TLS */ + +static int +config_ignored_hello_module(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_config *config) +{ + enum nc_operation op; + const char *module; + uint32_t i; + char **new_ignored_module; + + NC_NODE_GET_OP(node, parent_op, &op); + + module = lyd_get_value(node); + assert(module); + + if (op == NC_OP_DELETE) { + /* find the module we are deleting */ + LY_ARRAY_FOR(config->ignored_modules, i) { + if (!strcmp(config->ignored_modules[i], module)) { + break; + } + } + if (i == LY_ARRAY_COUNT(config->ignored_modules)) { + ERR(NULL, "Trying to delete a non-existing ignored-hello-module \"%s\".", module); + return 1; + } + free(config->ignored_modules[i]); + if (i < LY_ARRAY_COUNT(config->ignored_modules) - 1) { + config->ignored_modules[i] = config->ignored_modules[LY_ARRAY_COUNT(config->ignored_modules) - 1]; + } + LY_ARRAY_DECREMENT_FREE(config->ignored_modules); + } else if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { + /* check if the module is not already present */ + LY_ARRAY_FOR(config->ignored_modules, i) { + if (!strcmp(config->ignored_modules[i], module)) { + break; + } + } + if (i < LY_ARRAY_COUNT(config->ignored_modules)) { + ERR(NULL, "Trying to add an already existing ignored-hello-module \"%s\".", module); + return 1; + } + + /* add the new module */ + LY_ARRAY_NEW_RET(LYD_CTX(node), config->ignored_modules, new_ignored_module, 1); + *new_ignored_module = strdup(module); + NC_CHECK_ERRMEM_RET(!*new_ignored_module, 1); + } + + return 0; +} + +static int +config_ln2_netconf_server(const struct lyd_node *node, enum nc_operation parent_op, + struct nc_server_config *config) +{ + enum nc_operation op; + struct ly_set *set = NULL; + uint32_t i; + + NC_NODE_GET_OP(node, parent_op, &op); + +#ifdef NC_ENABLED_SSH_TLS + struct lyd_node *n; + + /* config certificate-expiration-notif-intervals */ + NC_CHECK_RET(nc_lyd_find_child(node, "certificate-expiration-notif-intervals", 0, &n)); + if (n) { + NC_CHECK_RET(config_cert_exp_notif_intervals(n, op, config)); + } +#endif /* NC_ENABLED_SSH_TLS */ + + /* config all ignored-hello-modules */ + NC_CHECK_RET(lyd_find_xpath(node, "ignored-hello-module", &set), 1); + for (i = 0; i < set->count; ++i) { + NC_CHECK_GOTO(config_ignored_hello_module(set->dnodes[i], op, config), cleanup); + } + +cleanup: + ly_set_free(set, NULL); + return 0; +} + +/** + * @brief Find and configure the /libnetconf2-netconf-server:ln2-netconf-server subtree. + * + * Does nothing if the subtree is not present. + * + * @param[in] tree Configuration YANG data tree to search in. + * @param[in] is_diff Flag indicating if the operation is a diff. + * @param[in,out] config Server configuration to modify. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_libnetconf2_netconf_server(const struct lyd_node *tree, int is_diff, + struct nc_server_config *config) +{ + int r, rc = 0; + uint32_t prev_lo; + struct lyd_node *subtree; + enum nc_operation initial_op; + + prev_lo = ly_log_options(0); + + /* try to find the ln2-netconf-server subtree */ + r = lyd_find_path(tree, "/libnetconf2-netconf-server:ln2-netconf-server", 0, &subtree); + if (r) { + if (r == LY_ENOTFOUND) { + /* ln2-netconf-server not present, nothing to configure */ + goto cleanup; + } + ERR(NULL, "Unable to find the ln2-netconf-server subtree in the YANG data."); + rc = 1; + goto cleanup; + } + + /* configure the ln2-netconf-server */ + initial_op = is_diff ? NC_OP_UNKNOWN : NC_OP_CREATE; + rc = config_ln2_netconf_server(subtree, initial_op, config); + +cleanup: + ly_log_options(prev_lo); + return rc; +} + +/** + * @brief Atomically starts listening on new sockets and reuses existing ones. + * + * @param[in,out] old_cfg Old, currently active server configuration. + * @param[in,out] new_cfg New server configuration currently being applied. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_reconcile_sockets_listen(struct nc_server_config *old_cfg, + struct nc_server_config *new_cfg) +{ + int rc = 0, found; + struct nc_endpt *old_endpt, *new_endpt; + struct nc_bind *new_bind, *old_bind; + + /* + * == PHASE 1: RECONCILE OLD AND NEW SOCKETS == + * Match existing sockets from old_cfg to new_cfg to reuse them, + * then create new sockets for new binds. + */ + + /* reuse existing sockets from old_cfg */ + LY_ARRAY_FOR(new_cfg->endpts, struct nc_endpt, new_endpt) { + LY_ARRAY_FOR(new_endpt->binds, struct nc_bind, new_bind) { + found = 0; + LY_ARRAY_FOR(old_cfg->endpts, struct nc_endpt, old_endpt) { + LY_ARRAY_FOR(old_endpt->binds, struct nc_bind, old_bind) { + if (!strcmp(new_bind->address, old_bind->address) && (new_bind->port == old_bind->port)) { + /* match found, reuse the socket */ + new_bind->sock = old_bind->sock; + found = 1; + break; + } + } + if (found) { + /* break the outer loop as well, we already found a match for this bind */ + break; + } + } + } + } + + /* create new sockets for new binds */ + LY_ARRAY_FOR(new_cfg->endpts, struct nc_endpt, new_endpt) { + LY_ARRAY_FOR(new_endpt->binds, struct nc_bind, new_bind) { + if (new_bind->sock == -1) { + /* this bind is new, create a listening socket */ + if (nc_server_bind_and_listen(new_endpt, new_bind)) { + /* FAILURE! trigger rollback */ + rc = 1; + goto rollback; + } + } + } + } + + /* + * == PHASE 2: COMMIT CHANGES (WRITE TO old_cfg) == + * new_cfg is now fully valid. We can safely modify old_cfg to prevent + * reused sockets from being closed by the caller. + */ + LY_ARRAY_FOR(old_cfg->endpts, struct nc_endpt, old_endpt) { + LY_ARRAY_FOR(old_endpt->binds, struct nc_bind, old_bind) { + found = 0; + if (old_bind->sock == -1) { + /* already handled or was never active */ + continue; + } + + /* check if this old_bind's socket was reused in the new_cfg */ + LY_ARRAY_FOR(new_cfg->endpts, struct nc_endpt, new_endpt) { + LY_ARRAY_FOR(new_endpt->binds, struct nc_bind, new_bind) { + if (old_bind->sock == new_bind->sock) { + /* match found, invalidate the socket in the old config (dont want to close it) */ + old_bind->sock = -1; + found = 1; + break; + } + } + if (found) { + /* break the outer loop as well, we already found a match for this bind */ + break; + } + } + } + } + + return 0; + +rollback: + /* + * == ROLLBACK LOGIC == + * An error occurred. We do not want to close the reused sockets, so we can roll back to old_cfg. + * So we invalidate all reused sockets in new_cfg, the rest will be closed by the caller later. + */ + LY_ARRAY_FOR(new_cfg->endpts, struct nc_endpt, new_endpt) { + LY_ARRAY_FOR(new_endpt->binds, struct nc_bind, new_bind) { + found = 0; + if (new_bind->sock == -1) { + /* this bind was never assigned a socket */ + continue; + } + + /* was this socket reused from the old config? */ + LY_ARRAY_FOR(old_cfg->endpts, struct nc_endpt, old_endpt) { + LY_ARRAY_FOR(old_endpt->binds, struct nc_bind, old_bind) { + if (new_bind->sock == old_bind->sock) { + /* match found, invalidate the socket in the new config */ + new_bind->sock = -1; + found = 1; + break; + } + } + if (found) { + /* break the outer loop as well, we already found a match for this bind */ + break; + } + } + } + } + + return rc; +} + +#ifdef NC_ENABLED_SSH_TLS + +/** + * @brief Atomically dispatch new Call Home clients and reuse existing ones. + * + * @param[in,out] old_cfg Old, currently active server configuration. + * @param[in,out] new_cfg New server configuration currently being applied. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_reconcile_chclients_dispatch(struct nc_server_config *old_cfg, + struct nc_server_config *new_cfg) +{ + int rc = 0; + struct nc_ch_client *old_ch_client, *new_ch_client; + struct nc_server_ch_thread_arg **ch_thread_arg; + int found; + LY_ARRAY_COUNT_TYPE i; + char **started_clients = NULL, **client_name = NULL; + + 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) { + /* Call Home dispatch callbacks not set, nothing to do */ + return 0; + } + + /* + * == PHASE 1: START NEW CLIENTS == + * Start clients present in new_cfg that are not already running. + * Track successfully started clients for potential rollback. + */ + LY_ARRAY_FOR(new_cfg->ch_clients, struct nc_ch_client, new_ch_client) { + found = 0; + + /* CH THREADS LOCK (reading server_opts.ch_threads) */ + pthread_rwlock_rdlock(&server_opts.ch_threads_lock); + + LY_ARRAY_FOR(server_opts.ch_threads, struct nc_server_ch_thread_arg *, ch_thread_arg) { + if (!strcmp(new_ch_client->name, (*ch_thread_arg)->client_name)) { + /* already running, do not start again */ + found = 1; + break; + } + } + + /* CH THREADS UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_threads_lock); + + if (!found) { + /* this is a new Call Home client, dispatch it */ + rc = _nc_connect_ch_client_dispatch(new_ch_client, 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 (rc) { + /* FAILURE! trigger rollback */ + goto rollback; + } + + /* successfully started, track it for potential rollback */ + LY_ARRAY_NEW_GOTO(NULL, started_clients, client_name, rc, rollback); + *client_name = strdup(new_ch_client->name); + NC_CHECK_ERRMEM_GOTO(!*client_name, rc = 1, rollback); + + /* ownership transferred to array */ + client_name = NULL; + } + } + + /* + * == PHASE 2: STOP DELETED CLIENTS (COMMIT) == + * All new clients started successfully. Now stop old clients + * that are not present in the new configuration. + */ + LY_ARRAY_FOR(old_cfg->ch_clients, struct nc_ch_client, old_ch_client) { + found = 0; + LY_ARRAY_FOR(new_cfg->ch_clients, struct nc_ch_client, new_ch_client) { + if (!strcmp(old_ch_client->name, new_ch_client->name)) { + found = 1; + break; + } + } + + if (!found) { + /* this Call Home client was deleted, notify it to stop */ + ch_thread_arg = NULL; + + /* CH THREADS LOCK (reading server_opts.ch_threads) */ + pthread_rwlock_rdlock(&server_opts.ch_threads_lock); + LY_ARRAY_FOR(server_opts.ch_threads, struct nc_server_ch_thread_arg *, ch_thread_arg) { + if (!strcmp(old_ch_client->name, (*ch_thread_arg)->client_name)) { + /* notify the thread to stop */ + pthread_mutex_lock(&(*ch_thread_arg)->cond_lock); + (*ch_thread_arg)->thread_running = 0; + pthread_cond_signal(&(*ch_thread_arg)->cond); + pthread_mutex_unlock(&(*ch_thread_arg)->cond_lock); + break; + } + } + /* CH THREADS UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_threads_lock); + /* Note: if ch_thread_arg is NULL here, the thread wasn't running. That's fine. */ + } + } + + /* success */ + rc = 0; + goto cleanup; + +rollback: + /* + * == ROLLBACK LOGIC == + * An error occurred during PHASE 1. Stop any new threads we *just* started + * to return to the pre-call state. + */ + LY_ARRAY_FOR(started_clients, i) { + ch_thread_arg = NULL; + + /* CH THREADS LOCK (reading server_opts.ch_threads) */ + pthread_rwlock_rdlock(&server_opts.ch_threads_lock); + LY_ARRAY_FOR(server_opts.ch_threads, struct nc_server_ch_thread_arg *, ch_thread_arg) { + if (!strcmp(started_clients[i], (*ch_thread_arg)->client_name)) { + /* notify the newly started thread to stop */ + pthread_mutex_lock(&(*ch_thread_arg)->cond_lock); + (*ch_thread_arg)->thread_running = 0; + pthread_cond_signal(&(*ch_thread_arg)->cond); + pthread_mutex_unlock(&(*ch_thread_arg)->cond_lock); + break; + } + } + /* CH THREADS UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_threads_lock); + } + /* rc is already set to non-zero from the failure point */ + +cleanup: + /* free the tracking list and its contents */ + LY_ARRAY_FOR(started_clients, i) { + free(started_clients[i]); + } + LY_ARRAY_FREE(started_clients); + return rc; +} + +/** + * @brief Create a deep copy of the SSH server options. + * + * @param[in] src Source SSH server options to copy from. + * @param[out] dst SSH server options copy. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_ssh_dup(const struct nc_server_ssh_opts *src, struct nc_server_ssh_opts **dst) +{ + int rc = 0; + uint32_t i, j; + const struct nc_hostkey *src_hostkey; + struct nc_hostkey *dst_hostkey; + const struct nc_auth_client *src_auth_client; + struct nc_auth_client *dst_auth_client; + + *dst = calloc(1, sizeof **dst); + NC_CHECK_ERRMEM_RET(!*dst, 1); + + /* dup host keys */ + LN2_LY_ARRAY_CREATE_GOTO_WRAP((*dst)->hostkeys, LY_ARRAY_COUNT(src->hostkeys), rc, cleanup); + LY_ARRAY_FOR(src->hostkeys, i) { + src_hostkey = &src->hostkeys[i]; + dst_hostkey = &(*dst)->hostkeys[i]; + + dst_hostkey->name = strdup(src_hostkey->name); + NC_CHECK_ERRMEM_GOTO(!dst_hostkey->name, rc = 1, cleanup); + + dst_hostkey->store = src_hostkey->store; + if (src_hostkey->store == NC_STORE_LOCAL) { + if (src_hostkey->key.name) { + /* hostkey's key name is optional */ + dst_hostkey->key.name = strdup(src_hostkey->key.name); + NC_CHECK_ERRMEM_GOTO(!dst_hostkey->key.name, rc = 1, cleanup); + } + + dst_hostkey->key.privkey.type = src_hostkey->key.privkey.type; + dst_hostkey->key.privkey.data = strdup(src_hostkey->key.privkey.data); + NC_CHECK_ERRMEM_GOTO(!dst_hostkey->key.privkey.data, rc = 1, cleanup); + + dst_hostkey->key.pubkey.type = src_hostkey->key.pubkey.type; + if (src_hostkey->key.pubkey.data) { + dst_hostkey->key.pubkey.data = strdup(src_hostkey->key.pubkey.data); + NC_CHECK_ERRMEM_GOTO(!dst_hostkey->key.pubkey.data, rc = 1, cleanup); + } + } else { + dst_hostkey->ks_ref = strdup(src_hostkey->ks_ref); + NC_CHECK_ERRMEM_GOTO(!dst_hostkey->ks_ref, rc = 1, cleanup); + } + + LY_ARRAY_INCREMENT((*dst)->hostkeys); + } + + /* dup auth clients */ + LN2_LY_ARRAY_CREATE_GOTO_WRAP((*dst)->auth_clients, LY_ARRAY_COUNT(src->auth_clients), rc, cleanup); + LY_ARRAY_FOR(src->auth_clients, i) { + src_auth_client = &src->auth_clients[i]; + dst_auth_client = &(*dst)->auth_clients[i]; + + dst_auth_client->username = strdup(src_auth_client->username); + NC_CHECK_ERRMEM_GOTO(!dst_auth_client->username, rc = 1, cleanup); + + dst_auth_client->pubkey_store = src_auth_client->pubkey_store; + if (src_auth_client->pubkey_store == NC_STORE_LOCAL) { + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst_auth_client->pubkeys, + LY_ARRAY_COUNT(src_auth_client->pubkeys), rc, cleanup); + LY_ARRAY_FOR(src_auth_client->pubkeys, j) { + dst_auth_client->pubkeys[j].name = strdup(src_auth_client->pubkeys[j].name); + NC_CHECK_ERRMEM_GOTO(!dst_auth_client->pubkeys[j].name, rc = 1, cleanup); + dst_auth_client->pubkeys[j].type = src_auth_client->pubkeys[j].type; + dst_auth_client->pubkeys[j].data = strdup(src_auth_client->pubkeys[j].data); + NC_CHECK_ERRMEM_GOTO(!dst_auth_client->pubkeys[j].data, rc = 1, cleanup); + LY_ARRAY_INCREMENT(dst_auth_client->pubkeys); + } + } else if (src_auth_client->pubkey_store == NC_STORE_TRUSTSTORE) { + dst_auth_client->ts_ref = strdup(src_auth_client->ts_ref); + NC_CHECK_ERRMEM_GOTO(!dst_auth_client->ts_ref, rc = 1, cleanup); + } + + if (src_auth_client->password) { + dst_auth_client->password = strdup(src_auth_client->password); + NC_CHECK_ERRMEM_GOTO(!dst_auth_client->password, rc = 1, cleanup); + } + dst_auth_client->password_last_modified = src_auth_client->password_last_modified; + dst_auth_client->kbdint_method = src_auth_client->kbdint_method; + dst_auth_client->none_enabled = src_auth_client->none_enabled; + + LY_ARRAY_INCREMENT((*dst)->auth_clients); + } + + if (src->referenced_endpt_name) { + (*dst)->referenced_endpt_name = strdup(src->referenced_endpt_name); + NC_CHECK_ERRMEM_GOTO(!(*dst)->referenced_endpt_name, rc = 1, cleanup); + } + + if (src->hostkey_algs) { + (*dst)->hostkey_algs = strdup(src->hostkey_algs); + NC_CHECK_ERRMEM_GOTO(!(*dst)->hostkey_algs, rc = 1, cleanup); + } + if (src->encryption_algs) { + (*dst)->encryption_algs = strdup(src->encryption_algs); + NC_CHECK_ERRMEM_GOTO(!(*dst)->encryption_algs, rc = 1, cleanup); + } + if (src->kex_algs) { + (*dst)->kex_algs = strdup(src->kex_algs); + NC_CHECK_ERRMEM_GOTO(!(*dst)->kex_algs, rc = 1, cleanup); + } + if (src->mac_algs) { + (*dst)->mac_algs = strdup(src->mac_algs); + NC_CHECK_ERRMEM_GOTO(!(*dst)->mac_algs, rc = 1, cleanup); + } + + if (src->banner) { + (*dst)->banner = strdup(src->banner); + NC_CHECK_ERRMEM_GOTO(!(*dst)->banner, rc = 1, cleanup); + } + + (*dst)->auth_timeout = src->auth_timeout; + +cleanup: + if (rc) { + nc_server_config_ssh_opts_free(*dst); + *dst = NULL; + } + return rc; +} + +/** + * @brief Create a deep copy of the TLS server options. + * + * @param[in] src Source TLS server options to copy from. + * @param[out] dst TLS server options copy. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_tls_dup(const struct nc_server_tls_opts *src, struct nc_server_tls_opts **dst) +{ + int rc = 0; + uint32_t i; + const struct nc_server_tls_client_auth *src_ca; + struct nc_server_tls_client_auth *dst_ca; + const struct nc_ctn *src_ctn; + struct nc_ctn *dst_ctn, *prev_ctn; + + *dst = calloc(1, sizeof **dst); + NC_CHECK_ERRMEM_RET(!*dst, 1); + + (*dst)->cert_store = src->cert_store; + if (src->cert_store == NC_STORE_LOCAL) { + (*dst)->local.key.privkey.type = src->local.key.privkey.type; + (*dst)->local.key.privkey.data = strdup(src->local.key.privkey.data); + NC_CHECK_ERRMEM_GOTO(!(*dst)->local.key.privkey.data, rc = 1, cleanup); + (*dst)->local.key.pubkey.type = src->local.key.pubkey.type; + (*dst)->local.key.pubkey.data = strdup(src->local.key.pubkey.data); + NC_CHECK_ERRMEM_GOTO(!(*dst)->local.key.pubkey.data, rc = 1, cleanup); + (*dst)->local.cert.data = strdup(src->local.cert.data); + NC_CHECK_ERRMEM_GOTO(!(*dst)->local.cert.data, rc = 1, cleanup); + } else { + (*dst)->keystore.asym_key_ref = strdup(src->keystore.asym_key_ref); + NC_CHECK_ERRMEM_GOTO(!(*dst)->keystore.asym_key_ref, rc = 1, cleanup); + (*dst)->keystore.cert_ref = strdup(src->keystore.cert_ref); + NC_CHECK_ERRMEM_GOTO(!(*dst)->keystore.cert_ref, rc = 1, cleanup); + } + + /* dup client auths */ + src_ca = &src->client_auth; + dst_ca = &(*dst)->client_auth; + + dst_ca->ca_certs_store = src_ca->ca_certs_store; + if (src_ca->ca_certs_store == NC_STORE_LOCAL) { + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst_ca->ca_certs, LY_ARRAY_COUNT(src_ca->ca_certs), rc, cleanup); + LY_ARRAY_FOR(src_ca->ca_certs, i) { + dst_ca->ca_certs[i].name = strdup(src_ca->ca_certs[i].name); + NC_CHECK_ERRMEM_GOTO(!dst_ca->ca_certs[i].name, rc = 1, cleanup); + dst_ca->ca_certs[i].data = strdup(src_ca->ca_certs[i].data); + NC_CHECK_ERRMEM_GOTO(!dst_ca->ca_certs[i].data, rc = 1, cleanup); + LY_ARRAY_INCREMENT(dst_ca->ca_certs); + } + } else { + dst_ca->ca_cert_bag_ts_ref = strdup(src_ca->ca_cert_bag_ts_ref); + NC_CHECK_ERRMEM_GOTO(!dst_ca->ca_cert_bag_ts_ref, rc = 1, cleanup); + } + + dst_ca->ee_certs_store = src_ca->ee_certs_store; + if (src_ca->ee_certs_store == NC_STORE_LOCAL) { + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst_ca->ee_certs, LY_ARRAY_COUNT(src_ca->ee_certs), rc, cleanup); + LY_ARRAY_FOR(src_ca->ee_certs, i) { + dst_ca->ee_certs[i].name = strdup(src_ca->ee_certs[i].name); + NC_CHECK_ERRMEM_GOTO(!dst_ca->ee_certs[i].name, rc = 1, cleanup); + dst_ca->ee_certs[i].data = strdup(src_ca->ee_certs[i].data); + NC_CHECK_ERRMEM_GOTO(!dst_ca->ee_certs[i].data, rc = 1, cleanup); + LY_ARRAY_INCREMENT(dst_ca->ee_certs); + } + } else { + dst_ca->ee_cert_bag_ts_ref = strdup(src_ca->ee_cert_bag_ts_ref); + NC_CHECK_ERRMEM_GOTO(!dst_ca->ee_cert_bag_ts_ref, rc = 1, cleanup); + } + + /* dup cert to name entries (linked list) */ + src_ctn = src->ctn; + prev_ctn = NULL; + while (src_ctn) { + dst_ctn = calloc(1, sizeof *dst_ctn); + NC_CHECK_ERRMEM_GOTO(!dst_ctn, rc = 1, cleanup); + + dst_ctn->id = src_ctn->id; + if (src_ctn->fingerprint) { + dst_ctn->fingerprint = strdup(src_ctn->fingerprint); + NC_CHECK_ERRMEM_GOTO(!dst_ctn->fingerprint, rc = 1, cleanup); + } + dst_ctn->map_type = src_ctn->map_type; + if (src_ctn->name) { + dst_ctn->name = strdup(src_ctn->name); + NC_CHECK_ERRMEM_GOTO(!dst_ctn->name, rc = 1, cleanup); + } + + if (prev_ctn) { + prev_ctn->next = dst_ctn; + } else { + (*dst)->ctn = dst_ctn; + } + + prev_ctn = dst_ctn; + src_ctn = src_ctn->next; + } + + if (src->referenced_endpt_name) { + (*dst)->referenced_endpt_name = strdup(src->referenced_endpt_name); + NC_CHECK_ERRMEM_GOTO(!(*dst)->referenced_endpt_name, rc = 1, cleanup); + } + + (*dst)->min_version = src->min_version; + (*dst)->max_version = src->max_version; + + if (src->cipher_suites) { + (*dst)->cipher_suites = strdup(src->cipher_suites); + NC_CHECK_ERRMEM_GOTO(!(*dst)->cipher_suites, rc = 1, cleanup); + } + +cleanup: + if (rc) { + nc_server_config_tls_opts_free(*dst); + *dst = NULL; + } + return rc; +} + +#endif /* NC_ENABLED_SSH_TLS */ + +/** + * @brief Create a deep copy of the UNIX server options. + * + * @param[in] src Source UNIX server options to copy from. + * @param[out] dst UNIX server options copy. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_unix_dup(const struct nc_server_unix_opts *src, struct nc_server_unix_opts **dst) +{ + int rc = 0; + uint32_t i, j; + const struct nc_server_unix_user_mapping *src_um; + struct nc_server_unix_user_mapping *dst_um; + + *dst = calloc(1, sizeof **dst); + NC_CHECK_ERRMEM_RET(!*dst, 1); + + (*dst)->mode = src->mode; + (*dst)->uid = src->uid; + (*dst)->gid = src->gid; + + LN2_LY_ARRAY_CREATE_GOTO_WRAP((*dst)->user_mappings, LY_ARRAY_COUNT(src->user_mappings), rc, cleanup); + LY_ARRAY_FOR(src->user_mappings, i) { + src_um = &src->user_mappings[i]; + dst_um = &(*dst)->user_mappings[i]; + + dst_um->system_user = strdup(src_um->system_user); + NC_CHECK_ERRMEM_GOTO(!dst_um->system_user, rc = 1, cleanup); + + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst_um->allowed_users, LY_ARRAY_COUNT(src_um->allowed_users), rc, cleanup); + LY_ARRAY_FOR(src_um->allowed_users, j) { + dst_um->allowed_users[j] = strdup(src_um->allowed_users[j]); + NC_CHECK_ERRMEM_GOTO(!dst_um->allowed_users[j], rc = 1, cleanup); + LY_ARRAY_INCREMENT(dst_um->allowed_users); + } + LY_ARRAY_INCREMENT((*dst)->user_mappings); + } + +cleanup: + if (rc) { + nc_server_config_unix_opts_free(*dst); + *dst = NULL; + } + return rc; +} + +#ifdef NC_ENABLED_SSH_TLS + +/** + * @brief Create a deep copy of the keystore. + * + * @param[in] src Source keystore to copy from. + * @param[out] dst Keystore copy. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_keystore_dup(const struct nc_keystore *src, struct nc_keystore *dst) +{ + int rc = 0; + uint32_t i, j; + const struct nc_keystore_entry *src_entry; + struct nc_keystore_entry *dst_entry; + const struct nc_certificate *src_cert; + struct nc_certificate *dst_cert; + + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst->entries, LY_ARRAY_COUNT(src->entries), rc, cleanup); + LY_ARRAY_FOR(src->entries, i) { + src_entry = &src->entries[i]; + dst_entry = &dst->entries[i]; + + dst_entry->asym_key.name = strdup(src_entry->asym_key.name); + NC_CHECK_ERRMEM_GOTO(!dst_entry->asym_key.name, rc = 1, cleanup); + + dst_entry->asym_key.privkey.type = src_entry->asym_key.privkey.type; + if (src_entry->asym_key.privkey.data) { + dst_entry->asym_key.privkey.data = strdup(src_entry->asym_key.privkey.data); + NC_CHECK_ERRMEM_GOTO(!dst_entry->asym_key.privkey.data, rc = 1, cleanup); + } + + dst_entry->asym_key.pubkey.type = src_entry->asym_key.pubkey.type; + if (src_entry->asym_key.pubkey.data) { + dst_entry->asym_key.pubkey.data = strdup(src_entry->asym_key.pubkey.data); + NC_CHECK_ERRMEM_GOTO(!dst_entry->asym_key.pubkey.data, rc = 1, cleanup); + } + + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst_entry->certs, LY_ARRAY_COUNT(src_entry->certs), rc, cleanup); + LY_ARRAY_FOR(src_entry->certs, j) { + src_cert = &src_entry->certs[j]; + dst_cert = &dst_entry->certs[j]; + + dst_cert->name = strdup(src_cert->name); + NC_CHECK_ERRMEM_GOTO(!dst_cert->name, rc = 1, cleanup); + + if (src_cert->data) { + dst_cert->data = strdup(src_cert->data); + NC_CHECK_ERRMEM_GOTO(!dst_cert->data, rc = 1, cleanup); + } + + LY_ARRAY_INCREMENT(dst_entry->certs); + } + + LY_ARRAY_INCREMENT(dst->entries); + } + +cleanup: + if (rc) { + nc_server_config_keystore_free(dst); + } + return rc; +} + +/** + * @brief Create a deep copy of the truststore. + * + * @param[in] src Source truststore to copy from. + * @param[out] dst Truststore copy. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_truststore_dup(const struct nc_truststore *src, struct nc_truststore *dst) +{ + int rc = 0; + LY_ARRAY_COUNT_TYPE i, j; + const struct nc_certificate_bag *src_cbag; + struct nc_certificate_bag *dst_cbag; + const struct nc_certificate *src_cert; + struct nc_certificate *dst_cert; + const struct nc_public_key_bag *src_pkbag; + struct nc_public_key_bag *dst_pkbag; + const struct nc_public_key *src_pk; + struct nc_public_key *dst_pk; + + /* copy certificate bags */ + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst->cert_bags, LY_ARRAY_COUNT(src->cert_bags), rc, cleanup); + LY_ARRAY_FOR(src->cert_bags, i) { + src_cbag = &src->cert_bags[i]; + dst_cbag = &dst->cert_bags[i]; + + dst_cbag->name = strdup(src_cbag->name); + NC_CHECK_ERRMEM_GOTO(!dst_cbag->name, rc = 1, cleanup); + + if (src_cbag->description) { + dst_cbag->description = strdup(src_cbag->description); + NC_CHECK_ERRMEM_GOTO(!dst_cbag->description, rc = 1, cleanup); + } + + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst_cbag->certs, LY_ARRAY_COUNT(src_cbag->certs), rc, cleanup); + LY_ARRAY_FOR(src_cbag->certs, j) { + src_cert = &src_cbag->certs[j]; + dst_cert = &dst_cbag->certs[j]; + + dst_cert->name = strdup(src_cert->name); + NC_CHECK_ERRMEM_GOTO(!dst_cert->name, rc = 1, cleanup); + + if (src_cert->data) { + dst_cert->data = strdup(src_cert->data); + NC_CHECK_ERRMEM_GOTO(!dst_cert->data, rc = 1, cleanup); + } + + LY_ARRAY_INCREMENT(dst_cbag->certs); + } + + LY_ARRAY_INCREMENT(dst->cert_bags); + } + + /* copy public key bags */ + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst->pubkey_bags, LY_ARRAY_COUNT(src->pubkey_bags), rc, cleanup); + LY_ARRAY_FOR(src->pubkey_bags, i) { + src_pkbag = &src->pubkey_bags[i]; + dst_pkbag = &dst->pubkey_bags[i]; + + dst_pkbag->name = strdup(src_pkbag->name); + NC_CHECK_ERRMEM_GOTO(!dst_pkbag->name, rc = 1, cleanup); + + if (src_pkbag->description) { + dst_pkbag->description = strdup(src_pkbag->description); + NC_CHECK_ERRMEM_GOTO(!dst_pkbag->description, rc = 1, cleanup); + } + + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst_pkbag->pubkeys, LY_ARRAY_COUNT(src_pkbag->pubkeys), rc, cleanup); + LY_ARRAY_FOR(src_pkbag->pubkeys, j) { + src_pk = &src_pkbag->pubkeys[j]; + dst_pk = &dst_pkbag->pubkeys[j]; + + dst_pk->name = strdup(src_pk->name); + NC_CHECK_ERRMEM_GOTO(!dst_pk->name, rc = 1, cleanup); + dst_pk->type = src_pk->type; + if (src_pk->data) { + dst_pk->data = strdup(src_pk->data); + NC_CHECK_ERRMEM_GOTO(!dst_pk->data, rc = 1, cleanup); + } + + LY_ARRAY_INCREMENT(dst_pkbag->pubkeys); + } + + LY_ARRAY_INCREMENT(dst->pubkey_bags); + } + +cleanup: + if (rc) { + nc_server_config_truststore_free(dst); + } + return rc; +} + +#endif /* NC_ENABLED_SSH_TLS */ + +/** + * @brief Create a deep copy of the server configuration. + * + * @param[in] src Source server configuration to copy from. + * @param[out] dst Server configuration copy. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_dup(const struct nc_server_config *src, struct nc_server_config *dst) +{ + int rc = 0; + uint32_t i, j; + const struct nc_endpt *src_endpt; + struct nc_endpt *dst_endpt; + const struct nc_ch_client *src_ch_client; + struct nc_ch_client *dst_ch_client; + const struct nc_ch_endpt *src_ch_endpt; + struct nc_ch_endpt *dst_ch_endpt; + + dst->idle_timeout = src->idle_timeout; + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst->ignored_modules, LY_ARRAY_COUNT(src->ignored_modules), rc, cleanup); + LY_ARRAY_FOR(src->ignored_modules, i) { + dst->ignored_modules[i] = strdup(src->ignored_modules[i]); + NC_CHECK_ERRMEM_GOTO(!dst->ignored_modules[i], rc = 1, cleanup); + LY_ARRAY_INCREMENT(dst->ignored_modules); + } + + /* endpoints */ + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst->endpts, LY_ARRAY_COUNT(src->endpts), rc, cleanup); + LY_ARRAY_FOR(src->endpts, i) { + src_endpt = &src->endpts[i]; + dst_endpt = &dst->endpts[i]; + + dst_endpt->name = strdup(src_endpt->name); + NC_CHECK_ERRMEM_GOTO(!dst_endpt->name, rc = 1, cleanup); + + /* binds */ + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst_endpt->binds, LY_ARRAY_COUNT(src_endpt->binds), rc, cleanup); + LY_ARRAY_FOR(src_endpt->binds, j) { + dst_endpt->binds[j].address = strdup(src_endpt->binds[j].address); + NC_CHECK_ERRMEM_GOTO(!dst_endpt->binds[j].address, rc = 1, cleanup); + dst_endpt->binds[j].port = src_endpt->binds[j].port; + + /* mark the socket as uninitialized, it will be reassigned in ::nc_server_config_reconcile_sockets_listen() */ + dst_endpt->binds[j].sock = -1; + LY_ARRAY_INCREMENT(dst_endpt->binds); + } + pthread_mutex_init(&dst_endpt->bind_lock, NULL); + + dst_endpt->ka = src_endpt->ka; + + dst_endpt->ti = src_endpt->ti; + switch (src_endpt->ti) { +#ifdef NC_ENABLED_SSH_TLS + case NC_TI_SSH: + NC_CHECK_ERR_GOTO(rc = nc_server_config_ssh_dup(src_endpt->opts.ssh, &dst_endpt->opts.ssh), + ERR(NULL, "Duplicating SSH transport information failed."), cleanup); + break; + case NC_TI_TLS: + NC_CHECK_ERR_GOTO(rc = nc_server_config_tls_dup(src_endpt->opts.tls, &dst_endpt->opts.tls), + ERR(NULL, "Duplicating TLS transport information failed."), cleanup); + break; +#endif /* NC_ENABLED_SSH_TLS */ + case NC_TI_UNIX: + NC_CHECK_ERR_GOTO(rc = nc_server_config_unix_dup(src_endpt->opts.unix, &dst_endpt->opts.unix), + ERR(NULL, "Duplicating UNIX transport information failed."), cleanup); + break; + default: + break; + } + + LY_ARRAY_INCREMENT(dst->endpts); + } + + /* call-home clients */ + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst->ch_clients, LY_ARRAY_COUNT(src->ch_clients), rc, cleanup); + LY_ARRAY_FOR(src->ch_clients, i) { + src_ch_client = &src->ch_clients[i]; + dst_ch_client = &dst->ch_clients[i]; + + dst_ch_client->name = strdup(src_ch_client->name); + NC_CHECK_ERRMEM_GOTO(!dst_ch_client->name, rc = 1, cleanup); + + /* ch endpoints */ + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst_ch_client->ch_endpts, + LY_ARRAY_COUNT(src_ch_client->ch_endpts), rc, cleanup); + LY_ARRAY_FOR(src_ch_client->ch_endpts, j) { + src_ch_endpt = &src_ch_client->ch_endpts[j]; + dst_ch_endpt = &dst_ch_client->ch_endpts[j]; + + dst_ch_endpt->name = strdup(src_ch_endpt->name); + NC_CHECK_ERRMEM_GOTO(!dst_ch_endpt->name, rc = 1, cleanup); + + if (src_ch_endpt->src_addr) { + dst_ch_endpt->src_addr = strdup(src_ch_endpt->src_addr); + NC_CHECK_ERRMEM_GOTO(!dst_ch_endpt->src_addr, rc = 1, cleanup); + } + dst_ch_endpt->src_port = src_ch_endpt->src_port; + + if (src_ch_endpt->dst_addr) { + dst_ch_endpt->dst_addr = strdup(src_ch_endpt->dst_addr); + NC_CHECK_ERRMEM_GOTO(!dst_ch_endpt->dst_addr, rc = 1, cleanup); + } + dst_ch_endpt->dst_port = src_ch_endpt->dst_port; + dst_ch_endpt->sock_pending = -1; + + dst_ch_endpt->ka = src_ch_endpt->ka; + + dst_ch_endpt->ti = src_ch_endpt->ti; + switch (src_ch_endpt->ti) { +#ifdef NC_ENABLED_SSH_TLS + case NC_TI_SSH: + NC_CHECK_ERR_GOTO(rc = nc_server_config_ssh_dup(src_ch_endpt->opts.ssh, &dst_ch_endpt->opts.ssh), + ERR(NULL, "Duplicating SSH transport information failed."), cleanup); + break; + case NC_TI_TLS: + NC_CHECK_ERR_GOTO(rc = nc_server_config_tls_dup(src_ch_endpt->opts.tls, &dst_ch_endpt->opts.tls), + ERR(NULL, "Duplicating TLS transport information failed."), cleanup); + break; +#endif /* NC_ENABLED_SSH_TLS */ + default: + break; + } + + LY_ARRAY_INCREMENT(dst_ch_client->ch_endpts); + } + + dst_ch_client->conn_type = src_ch_client->conn_type; + if (src_ch_client->conn_type == NC_CH_PERIOD) { + dst_ch_client->period = src_ch_client->period; + dst_ch_client->anchor_time = src_ch_client->anchor_time; + dst_ch_client->idle_timeout = src_ch_client->idle_timeout; + } + + dst_ch_client->start_with = src_ch_client->start_with; + dst_ch_client->max_attempts = src_ch_client->max_attempts; + dst_ch_client->max_wait = src_ch_client->max_wait; + + LY_ARRAY_INCREMENT(dst->ch_clients); + } + +#ifdef NC_ENABLED_SSH_TLS + /* dup keystore */ + NC_CHECK_ERR_GOTO(rc = nc_server_config_keystore_dup(&src->keystore, &dst->keystore), + ERR(NULL, "Duplicating keystore failed."), cleanup); + + /* dup truststore */ + NC_CHECK_ERR_GOTO(rc = nc_server_config_truststore_dup(&src->truststore, &dst->truststore), + ERR(NULL, "Duplicating truststore failed."), cleanup); - 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; - } + /* dup cert expiration notif intervals */ + LN2_LY_ARRAY_CREATE_GOTO_WRAP(dst->cert_exp_notif_intervals, + LY_ARRAY_COUNT(src->cert_exp_notif_intervals), rc, cleanup); + LY_ARRAY_FOR(src->cert_exp_notif_intervals, i) { + dst->cert_exp_notif_intervals[i] = src->cert_exp_notif_intervals[i]; + LY_ARRAY_INCREMENT(dst->cert_exp_notif_intervals); } +#endif /* NC_ENABLED_SSH_TLS */ - return 0; +cleanup: + if (rc) { + nc_server_config_free(dst); + } -error: - if (new_ctx) { - ly_ctx_destroy(*ctx); - *ctx = NULL; + return rc; +} + +#ifdef NC_ENABLED_SSH_TLS + +/** + * @brief Wake up the certificate expiration notification thread to update its data. + */ +static void +nc_server_config_cert_exp_notif_thread_wakeup(void) +{ + pthread_mutex_lock(&server_opts.cert_exp_notif.lock); + if (server_opts.cert_exp_notif.thread_running) { + pthread_cond_signal(&server_opts.cert_exp_notif.cond); } - return 1; + pthread_mutex_unlock(&server_opts.cert_exp_notif.lock); } +#endif /* NC_ENABLED_SSH_TLS */ + +/** + * @brief Wait for any pending updates to complete, then mark the server as "applying configuration". + * + * @return 0 on success, 1 on timeout. + */ static int -nc_server_config_fill_netconf_server(const struct lyd_node *data, enum nc_operation op) +nc_server_config_update_start(void) { - int ret = 0; - uint32_t log_options = 0; - struct lyd_node *tree; + int r; + struct timespec ts_timeout; - /* silently search for ietf-netconf-server, it may not be present */ - ly_temp_log_options(&log_options); + /* get the time point of timeout */ + nc_timeouttime_get(&ts_timeout, NC_SERVER_CONFIG_UPDATE_WAIT_TIMEOUT_SEC * 1000); - ret = lyd_find_path(data, "/ietf-netconf-server:netconf-server", 0, &tree); - if (ret || (tree->flags & LYD_DEFAULT)) { - /* not found */ - ret = 0; - goto cleanup; - } + while (nc_timeouttime_cur_diff(&ts_timeout) > 0) { + /* WR LOCK */ + r = pthread_rwlock_clockwrlock(&server_opts.config_lock, COMPAT_CLOCK_ID, &ts_timeout); + if (r == ETIMEDOUT) { + break; + } else if (r) { + ERR(NULL, "Failed to acquire server configuration write lock (%s).", strerror(r)); + return 1; + } - if (nc_server_config_process_tree(tree, op, NC_MODULE_NETCONF_SERVER)) { - ret = 1; - goto cleanup; - } + if (!server_opts.applying_config) { + /* set the flag and end */ + server_opts.applying_config = 1; -#ifdef NC_ENABLED_SSH_TLS - /* check and set all endpoint references */ - if (nc_server_config_check_endpt_references()) { - ret = 1; - goto cleanup; + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); + return 0; + } + + /* UNLOCK and wait */ + pthread_rwlock_unlock(&server_opts.config_lock); + usleep(NC_TIMEOUT_STEP); } -#endif /* NC_ENABLED_SSH_TLS */ -cleanup: - /* reset the logging options back to what they were */ - ly_temp_log_options(NULL); - return ret; + ERR(NULL, "Timeout expired while waiting for the server to apply the previous configuration."); + return 1; } -static int -nc_server_config_fill_libnetconf2_netconf_server(const struct lyd_node *data, enum nc_operation op) +/** + * @brief Clear the "applying configuration" flag once the configuration update is done. + */ +static void +nc_server_config_update_end(void) { - int ret = 0; - struct lyd_node *tree; - uint32_t log_options = 0; + int r; + struct timespec ts_timeout; - /* silently search for ln2-netconf-server, it may not be present */ - ly_temp_log_options(&log_options); + /* get the time point of timeout */ + nc_timeouttime_get(&ts_timeout, NC_SERVER_CONFIG_UPDATE_WAIT_TIMEOUT_SEC * 1000); - ret = lyd_find_path(data, "/libnetconf2-netconf-server:ln2-netconf-server", 0, &tree); - if (ret || (tree->flags & LYD_DEFAULT)) { - /* not found */ - ret = 0; - goto cleanup; + /* WR LOCK */ + r = pthread_rwlock_clockwrlock(&server_opts.config_lock, COMPAT_CLOCK_ID, &ts_timeout); + if (r) { + /* just log the error, there is nothing we can do */ + ERR(NULL, "Failed to acquire server configuration write lock (%s).", strerror(r)); } - if (nc_server_config_process_tree(tree, op, NC_MODULE_LIBNETCONF2_NETCONF_SERVER)) { - ret = 1; - goto cleanup; - } + /* clear the flag */ + server_opts.applying_config = 0; -cleanup: - /* reset the logging options back to what they were */ - ly_temp_log_options(NULL); - return ret; + if (!r) { + /* UNLOCK only if we locked it */ + pthread_rwlock_unlock(&server_opts.config_lock); + } } API int nc_server_config_setup_diff(const struct lyd_node *data) { int ret = 0; + struct nc_server_config config_copy = {0}; NC_CHECK_ARG_RET(NULL, data, 1); - /* LOCK */ - pthread_rwlock_wrlock(&server_opts.config_lock); + /* wait until previous is done, then mark us as applying */ + NC_CHECK_RET(nc_server_config_update_start()); + + /* CONFIG RD LOCK */ + pthread_rwlock_rdlock(&server_opts.config_lock); + + /* create a copy of the current config to work with, so that we can revert to it in case of error */ + NC_CHECK_ERR_GOTO(ret = nc_server_config_dup(&server_opts.config, &config_copy), + ERR(NULL, "Duplicating current server configuration failed."), cleanup_unlock); + + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); #ifdef NC_ENABLED_SSH_TLS /* configure keystore */ - ret = nc_server_config_fill_keystore(data, NC_OP_UNKNOWN); - if (ret) { - ERR(NULL, "Applying ietf-keystore configuration failed."); - goto cleanup; - } + NC_CHECK_ERR_GOTO(ret = nc_server_config_keystore(data, 1, &config_copy), + ERR(NULL, "Applying ietf-keystore configuration failed."), cleanup); /* configure truststore */ - ret = nc_server_config_fill_truststore(data, NC_OP_UNKNOWN); - if (ret) { - ERR(NULL, "Applying ietf-truststore configuration failed."); - goto cleanup; - } + NC_CHECK_ERR_GOTO(ret = nc_server_config_truststore(data, 1, &config_copy), + ERR(NULL, "Applying ietf-truststore configuration failed."), cleanup); #endif /* NC_ENABLED_SSH_TLS */ /* configure netconf-server */ - ret = nc_server_config_fill_netconf_server(data, NC_OP_UNKNOWN); - if (ret) { - ERR(NULL, "Applying ietf-netconf-server configuration failed."); - goto cleanup; - } + NC_CHECK_ERR_GOTO(ret = nc_server_config_netconf_server(data, 1, &config_copy), + ERR(NULL, "Applying ietf-netconf-server configuration failed."), cleanup); /* configure libnetconf2-netconf-server */ - ret = nc_server_config_fill_libnetconf2_netconf_server(data, NC_OP_UNKNOWN); - if (ret) { - ERR(NULL, "Applying libnetconf2-netconf-server configuration failed."); - goto cleanup; - } + NC_CHECK_ERR_GOTO(ret = nc_server_config_libnetconf2_netconf_server(data, NC_OP_UNKNOWN, &config_copy), + ERR(NULL, "Applying libnetconf2-netconf-server configuration failed."), cleanup); + + /* CONFIG WR LOCK */ + pthread_rwlock_wrlock(&server_opts.config_lock); + + /* start listening on new endpoints */ + NC_CHECK_ERR_GOTO(ret = nc_server_config_reconcile_sockets_listen(&server_opts.config, &config_copy), + ERR(NULL, "Starting to listen on new endpoints failed."), cleanup_unlock); #ifdef NC_ENABLED_SSH_TLS - /* wake up the cert expiration notif thread if it's running */ - pthread_mutex_lock(&server_opts.cert_exp_notif.lock); - if (server_opts.cert_exp_notif.thread_running) { - pthread_cond_signal(&server_opts.cert_exp_notif.cond); - } - pthread_mutex_unlock(&server_opts.cert_exp_notif.lock); + /* dispatch new call-home threads */ + NC_CHECK_ERR_GOTO(ret = nc_server_config_reconcile_chclients_dispatch(&server_opts.config, &config_copy), + ERR(NULL, "Dispatching new call-home threads failed."), cleanup_unlock); #endif /* NC_ENABLED_SSH_TLS */ -cleanup: - /* UNLOCK */ + /* swap: free old, keep new, zero out the copy just in case to avoid double free */ + nc_server_config_free(&server_opts.config); + server_opts.config = config_copy; + memset(&config_copy, 0, sizeof config_copy); + +#ifdef NC_ENABLED_SSH_TLS + /* wake up the cert expiration notif thread */ + nc_server_config_cert_exp_notif_thread_wakeup(); +#endif /* NC_ENABLED_SSH_TLS */ + +cleanup_unlock: + /* CONFIG UNLOCK */ pthread_rwlock_unlock(&server_opts.config_lock); + +cleanup: + if (ret) { + /* free the new config in case of error */ + nc_server_config_free(&config_copy); + } + nc_server_config_update_end(); + return ret; } @@ -4623,22 +6021,16 @@ API int nc_server_config_setup_data(const struct lyd_node *data) { int ret = 0; - struct lyd_node *tree, *iter, *root; + const struct lyd_node *tree, *iter; + struct nc_server_config config = {0}; NC_CHECK_ARG_RET(NULL, data, 1); - /* 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; - } + /* wait until previous is done, then mark us as applying */ + NC_CHECK_RET(nc_server_config_update_start()); - /* iterate through all the nodes and make sure there is no operation attribute */ - LY_LIST_FOR(root, tree) { + /* check that the config data are not diff (no op attr) */ + LY_LIST_FOR(data, 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."); @@ -4649,54 +6041,63 @@ 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); + /* create a new empty config, we can use it to fill it with new data, 2 main benefits: + * - if something fails, the old config is still intact + * - not having to hold the config_lock for a long time while applying the new config + */ +#ifdef NC_ENABLED_SSH_TLS /* configure keystore */ - ret = nc_server_config_fill_keystore(data, NC_OP_CREATE); - if (ret) { - ERR(NULL, "Applying ietf-keystore configuration failed."); - goto cleanup; - } + NC_CHECK_ERR_GOTO(ret = nc_server_config_keystore(data, 0, &config), + ERR(NULL, "Applying ietf-keystore configuration failed."), cleanup); /* configure truststore */ - ret = nc_server_config_fill_truststore(data, NC_OP_CREATE); - if (ret) { - ERR(NULL, "Applying ietf-truststore configuration failed."); - goto cleanup; - } + NC_CHECK_ERR_GOTO(ret = nc_server_config_truststore(data, 0, &config), + ERR(NULL, "Applying ietf-truststore configuration failed."), cleanup); #endif /* NC_ENABLED_SSH_TLS */ /* configure netconf-server */ - ret = nc_server_config_fill_netconf_server(data, NC_OP_CREATE); - if (ret) { - ERR(NULL, "Applying ietf-netconf-server configuration failed."); - goto cleanup; - } + NC_CHECK_ERR_GOTO(ret = nc_server_config_netconf_server(data, 0, &config), + ERR(NULL, "Applying ietf-netconf-server configuration failed."), cleanup); /* configure libnetconf2-netconf-server */ - ret = nc_server_config_fill_libnetconf2_netconf_server(data, NC_OP_CREATE); - if (ret) { - ERR(NULL, "Applying libnetconf2-netconf-server configuration failed."); - goto cleanup; - } + NC_CHECK_ERR_GOTO(ret = nc_server_config_libnetconf2_netconf_server(data, NC_OP_UNKNOWN, &config), + ERR(NULL, "Applying libnetconf2-netconf-server configuration failed."), cleanup); + + /* CONFIG LOCK */ + pthread_rwlock_wrlock(&server_opts.config_lock); + + /* start listening on new endpoints */ + NC_CHECK_ERR_GOTO(ret = nc_server_config_reconcile_sockets_listen(&server_opts.config, &config), + ERR(NULL, "Starting to listen on new endpoints failed."), cleanup_unlock); #ifdef NC_ENABLED_SSH_TLS - /* wake up the cert expiration notif thread if it's running */ - pthread_mutex_lock(&server_opts.cert_exp_notif.lock); - if (server_opts.cert_exp_notif.thread_running) { - pthread_cond_signal(&server_opts.cert_exp_notif.cond); - } - pthread_mutex_unlock(&server_opts.cert_exp_notif.lock); + /* dispatch new call-home connections */ + NC_CHECK_ERR_GOTO(ret = nc_server_config_reconcile_chclients_dispatch(&server_opts.config, &config), + ERR(NULL, "Dispatching new call-home connections failed."), cleanup_unlock); #endif /* NC_ENABLED_SSH_TLS */ -cleanup: - /* UNLOCK */ + /* swap: free old, keep new, zero out the copy just in case to avoid double free */ + nc_server_config_free(&server_opts.config); + server_opts.config = config; + memset(&config, 0, sizeof config); + +#ifdef NC_ENABLED_SSH_TLS + /* wake up the cert expiration notif thread */ + nc_server_config_cert_exp_notif_thread_wakeup(); +#endif /* NC_ENABLED_SSH_TLS */ + +cleanup_unlock: + /* CONFIG UNLOCK */ pthread_rwlock_unlock(&server_opts.config_lock); + +cleanup: + if (ret) { + /* free the new config in case of error */ + nc_server_config_free(&config); + } + nc_server_config_update_end(); + return ret; } @@ -4725,143 +6126,296 @@ nc_server_config_setup_path(const struct ly_ctx *ctx, const char *path) #ifdef NC_ENABLED_SSH_TLS +/** + * @brief Create operational data for supported algorithms. + * + * @param[in] ctx libyang context. + * @param[in] mod Module name. + * @param[in] alg_type Optional algorithm type (container name). + * @param[in] supported_algs Array of supported algorithms. + * @param[out] algs Created operational data tree. + * @return 0 on success, 1 on error. + */ static int -nc_server_config_oper_get_algs(const struct ly_ctx *ctx, const char *mod_name, const char *ln2_algs[], - const char *mod_algs[], struct lyd_node **algs) +nc_server_config_oper_get_algs(const struct ly_ctx *ctx, const char *mod, const char *alg_type, + const char *supported_algs[], struct lyd_node **algs) { - int ret, r, i; - struct lyd_node *parent = NULL; + int rc = 0, r, i; + struct lyd_node *parent = NULL, *node = NULL; char *path = NULL; - NC_CHECK_ARG_RET(NULL, ctx, mod_name, ln2_algs, mod_algs, algs, 1); - *algs = NULL; - r = asprintf(&path, "/%s:supported-algorithms", mod_name); + /* prepare path to supported-algorithms container */ + if (alg_type) { + r = asprintf(&path, "/%s:supported-algorithms/%s", mod, alg_type); + } else { + r = asprintf(&path, "/%s:supported-algorithms", mod); + } NC_CHECK_ERRMEM_RET(r == -1, 1); /* create supported algorithms container */ - ret = lyd_new_path(NULL, ctx, path, NULL, 0, &parent); - free(path); - if (ret) { - ERR(NULL, "Creating supported algorithms container failed."); - goto cleanup; - } + NC_CHECK_ERR_GOTO(lyd_new_path(NULL, ctx, path, NULL, 0, &node), rc = 1, cleanup); - /* append algs from libnetconf2-netconf-server */ - for (i = 0; ln2_algs[i]; i++) { - r = asprintf(&path, "libnetconf2-netconf-server:%s", ln2_algs[i]); - NC_CHECK_ERRMEM_GOTO(r == -1, ret = 1, cleanup); - ret = lyd_new_term(parent, NULL, "supported-algorithm", path, 0, NULL); - free(path); - if (ret) { - ERR(NULL, "Creating new supported algorithm failed."); - goto cleanup; - } + if (alg_type) { + /* we need to go one level deeper because of the alg_type container */ + parent = lyd_child(node); + } else { + parent = node; } - /* append algs from mod_name module */ - for (i = 0; mod_algs[i]; i++) { - r = asprintf(&path, "%s:%s", mod_name, mod_algs[i]); - NC_CHECK_ERRMEM_GOTO(r == -1, ret = 1, cleanup); - ret = lyd_new_term(parent, NULL, "supported-algorithm", path, 0, NULL); - free(path); - if (ret) { - ERR(NULL, "Creating new supported algorithm failed."); - goto cleanup; - } + /* create supported-algorithm leaf-list entries */ + for (i = 0; supported_algs[i]; i++) { + NC_CHECK_ERR_GOTO(lyd_new_term(parent, NULL, "supported-algorithm", supported_algs[i], 0, NULL), rc = 1, cleanup); } + /* success */ + *algs = parent; cleanup: - if (ret) { - lyd_free_tree(parent); - } else { - *algs = parent; + if (rc) { + lyd_free_tree(node); } - return ret; + if (!rc && alg_type) { + /* success, we need to unlink and free the node we don't want to return */ + lyd_unlink_tree(parent); + lyd_free_tree(node); + } + free(path); + return rc; } -API int +/** + * @brief Get operational data for supported hostkey algorithms. + * + * @param[in] ctx libyang context. + * @param[out] hostkey_algs Created operational data tree. + * @return 0 on success, 1 on error. + */ +static int nc_server_config_oper_get_hostkey_algs(const struct ly_ctx *ctx, struct lyd_node **hostkey_algs) { - /* identities of hostkey algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */ - const char *libnetconf2_hostkey_algs[] = { - "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", NULL - }; - - /* identities of hostkey algs supported by libssh (v0.10.5) defined in iana-ssh-public-key-algs yang module */ - const char *iana_hostkey_algs[] = { + /* hostkey algs supported by libssh (v0.11.0) */ + const char *supported_algs[] = { "ssh-ed25519", "ecdsa-sha2-nistp521", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256", - "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", "ssh-dss", NULL + "sk-ssh-ed25519@openssh.com", "sk-ecdsa-sha2-nistp256@openssh.com", "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa", + "ssh-ed25519-cert-v01@openssh.com", "sk-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", "sk-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", NULL }; + const char *mod = "ietf-ssh-common", *alg_type = "public-key-algorithms"; - NC_CHECK_ARG_RET(NULL, ctx, hostkey_algs, 1); - - return nc_server_config_oper_get_algs(ctx, "iana-ssh-public-key-algs", libnetconf2_hostkey_algs, - iana_hostkey_algs, hostkey_algs); + return nc_server_config_oper_get_algs(ctx, mod, alg_type, supported_algs, hostkey_algs); } -API int +/** + * @brief Get operational data for supported key exchange algorithms. + * + * @param[in] ctx libyang context. + * @param[out] kex_algs Created operational data tree. + * @return 0 on success, 1 on error. + */ +static int nc_server_config_oper_get_kex_algs(const struct ly_ctx *ctx, struct lyd_node **kex_algs) { - /* identities of kex algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */ - const char *libnetconf2_kex_algs[] = { - "libssh-curve25519-sha256", NULL - }; - - /* identities of kex algs supported by libssh (v0.10.5) defined in iana-ssh-key-exchange-algs yang module */ - const char *iana_kex_algs[] = { - "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", + /* kex algs supported by libssh (v0.11.0) */ + const char *supported_algs[] = { + "diffie-hellman-group-exchange-sha1", "curve25519-sha256", "curve25519-sha256@libssh.org", + "sntrup761x25519-sha512", "sntrup761x25519-sha512@openssh.com", "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 + "diffie-hellman-group-exchange-sha256", "diffie-hellman-group14-sha256", + "diffie-hellman-group14-sha1", "diffie-hellman-group1-sha1", NULL }; + const char *mod = "ietf-ssh-common", *alg_type = "key-exchange-algorithms"; - NC_CHECK_ARG_RET(NULL, ctx, kex_algs, 1); - - return nc_server_config_oper_get_algs(ctx, "iana-ssh-key-exchange-algs", libnetconf2_kex_algs, - iana_kex_algs, kex_algs); + return nc_server_config_oper_get_algs(ctx, mod, alg_type, supported_algs, kex_algs); } -API int +/** + * @brief Get operational data for supported encryption algorithms. + * + * @param[in] ctx libyang context. + * @param[out] encryption_algs Created operational data tree. + * @return 0 on success, 1 on error. + */ +static int nc_server_config_oper_get_encryption_algs(const struct ly_ctx *ctx, struct lyd_node **encryption_algs) { - /* identities of encryption algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */ - const char *libnetconf2_encryption_algs[] = { - "openssh-chacha20-poly1305", "openssh-aes256-gcm", "openssh-aes128-gcm", NULL + /* encryption algs supported by libssh (v0.11.0) */ + const char *supported_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 }; + const char *mod = "ietf-ssh-common", *alg_type = "encryption-algorithms"; - /* identities of encryption algs supported by libssh (v0.10.5) defined in iana-ssh-encryption-algs yang module */ - const char *iana_encryption_algs[] = { - "aes256-ctr", "aes192-ctr", "aes128-ctr", "aes256-cbc", "aes192-cbc", "aes128-cbc", - "blowfish-cbc", "triple-des-cbc", "none", NULL + return nc_server_config_oper_get_algs(ctx, mod, alg_type, supported_algs, encryption_algs); +} + +/** + * @brief Get operational data for supported MAC algorithms. + * + * @param[in] ctx libyang context. + * @param[out] mac_algs Created operational data tree. + * @return 0 on success, 1 on error. + */ +static int +nc_server_config_oper_get_mac_algs(const struct ly_ctx *ctx, struct lyd_node **mac_algs) +{ + /* mac algs supported by libssh (v0.11.0) */ + const char *supported_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", "none", NULL }; + const char *mod = "ietf-ssh-common", *alg_type = "mac-algorithms"; + + return nc_server_config_oper_get_algs(ctx, mod, alg_type, supported_algs, mac_algs); +} + +API int +nc_server_config_oper_get_supported_ssh_algs(const struct ly_ctx *ctx, struct lyd_node **supported_algs) +{ + int rc = 0; + struct lyd_node *parent, *hostkey_algs, *kex_algs, *encryption_algs, *mac_algs; + + NC_CHECK_ARG_RET(NULL, ctx, supported_algs, 1); + + parent = hostkey_algs = kex_algs = encryption_algs = mac_algs = NULL; + + /* hostkey algorithms */ + NC_CHECK_ERR_GOTO(rc = nc_server_config_oper_get_hostkey_algs(ctx, &hostkey_algs), + ERR(NULL, "Getting supported hostkey algorithms failed."), cleanup); + + /* key exchange algorithms */ + NC_CHECK_ERR_GOTO(rc = nc_server_config_oper_get_kex_algs(ctx, &kex_algs), + ERR(NULL, "Getting supported key exchange algorithms failed."), cleanup); + + /* encryption algorithms */ + NC_CHECK_ERR_GOTO(rc = nc_server_config_oper_get_encryption_algs(ctx, &encryption_algs), + ERR(NULL, "Getting supported encryption algorithms failed."), cleanup); + + /* MAC algorithms */ + NC_CHECK_ERR_GOTO(rc = nc_server_config_oper_get_mac_algs(ctx, &mac_algs), + ERR(NULL, "Getting supported MAC algorithms failed."), cleanup); + + /* create supported-algorithms container */ + NC_CHECK_ERR_GOTO(lyd_new_path(NULL, ctx, "/ietf-ssh-common:supported-algorithms", NULL, 0, &parent), + rc = 1, cleanup); + + /* insert all algorithm containers */ + if (lyd_insert_child(parent, hostkey_algs) || + lyd_insert_child(parent, kex_algs) || + lyd_insert_child(parent, encryption_algs) || + lyd_insert_child(parent, mac_algs)) { + rc = 1; + goto cleanup; + } + + /* success */ + *supported_algs = parent; + parent = hostkey_algs = kex_algs = encryption_algs = mac_algs = NULL; +cleanup: + lyd_free_tree(parent); + lyd_free_tree(hostkey_algs); + lyd_free_tree(kex_algs); + lyd_free_tree(encryption_algs); + lyd_free_tree(mac_algs); + return rc; +} + +API int +nc_server_config_oper_get_supported_tls_algs(const struct ly_ctx *ctx, struct lyd_node **supported_algs) +{ + const char *mod = "ietf-tls-common"; - NC_CHECK_ARG_RET(NULL, ctx, encryption_algs, 1); + NC_CHECK_ARG_RET(NULL, ctx, supported_algs, 1); - return nc_server_config_oper_get_algs(ctx, "iana-ssh-encryption-algs", libnetconf2_encryption_algs, - iana_encryption_algs, encryption_algs); + /* cipher suites are based on the used TLS library */ + return nc_server_config_oper_get_algs(ctx, mod, NULL, nc_tls_supported_cipher_suites, supported_algs); } API int -nc_server_config_oper_get_mac_algs(const struct ly_ctx *ctx, struct lyd_node **mac_algs) +nc_server_config_oper_get_user_password_last_modified(const char *ch_client, const char *endpoint, + const char *username, time_t *last_modified) { - /* identities of mac algs supported by libssh (v0.10.5) defined in libnetconf2-netconf-server yang module */ - const char *libnetconf2_mac_algs[] = { - "openssh-hmac-sha2-256-etm", "openssh-hmac-sha2-512-etm", "openssh-hmac-sha1-etm", NULL - }; + int rc = 0; + LY_ARRAY_COUNT_TYPE i; + struct nc_server_ssh_opts *ssh_opts = NULL; + struct nc_endpt *endpt = NULL; + struct nc_ch_client *client = NULL; + struct nc_ch_endpt *ch_endpt = NULL; + time_t found_time = 0; - /* identities of mac algs supported by libssh (v0.10.5) defined in iana-ssh-mac-algs yang module */ - const char *iana_mac_algs[] = { - "hmac-sha2-256", "hmac-sha2-512", "hmac-sha1", NULL - }; + NC_CHECK_ARG_RET(NULL, endpoint, username, last_modified, 1); + + *last_modified = 0; + + /* LOCK */ + pthread_rwlock_rdlock(&server_opts.config_lock); + + if (ch_client) { + /* find the call-home client */ + LY_ARRAY_FOR(server_opts.config.ch_clients, i) { + if (!strcmp(server_opts.config.ch_clients[i].name, ch_client)) { + client = &server_opts.config.ch_clients[i]; + break; + } + } + if (!client) { + ERR(NULL, "Call-home client '%s' not found.", ch_client); + rc = 1; + goto cleanup; + } + + /* find the endpoint */ + LY_ARRAY_FOR(client->ch_endpts, struct nc_ch_endpt, ch_endpt) { + if (!strcmp(ch_endpt->name, endpoint) && (ch_endpt->ti == NC_TI_SSH)) { + ssh_opts = ch_endpt->opts.ssh; + break; + } + } + + if (!ssh_opts) { + ERR(NULL, "Endpoint '%s' with SSH transport not found in call-home client '%s'.", endpoint, ch_client); + rc = 1; + goto cleanup; + } + } else { + /* no call-home client specified, search in listening endpoints */ + LY_ARRAY_FOR(server_opts.config.endpts, struct nc_endpt, endpt) { + if (!strcmp(endpt->name, endpoint) && (endpt->ti == NC_TI_SSH)) { + ssh_opts = endpt->opts.ssh; + break; + } + } + + if (!ssh_opts) { + ERR(NULL, "Endpoint '%s' with SSH transport not found in listening endpoints.", endpoint); + rc = 1; + goto cleanup; + } + } + + /* find the SSH user */ + LY_ARRAY_FOR(ssh_opts->auth_clients, i) { + if (!strcmp(ssh_opts->auth_clients[i].username, username)) { + found_time = ssh_opts->auth_clients[i].password_last_modified; + break; + } + } + if (i == LY_ARRAY_COUNT(ssh_opts->auth_clients)) { + ERR(NULL, "SSH user '%s' not found on endpoint '%s'.", username, endpoint); + rc = 1; + goto cleanup; + } - NC_CHECK_ARG_RET(NULL, ctx, mac_algs, 1); + *last_modified = found_time; - return nc_server_config_oper_get_algs(ctx, "iana-ssh-mac-algs", libnetconf2_mac_algs, - iana_mac_algs, mac_algs); +cleanup: + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); + return rc; } #endif /* NC_ENABLED_SSH_TLS */ diff --git a/src/server_config.h b/src/server_config.h index 706d9f9c..95569c61 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -74,6 +74,9 @@ int nc_server_config_load_modules(struct ly_ctx **ctx); * * Context must already have implemented the required modules, see ::nc_server_config_load_modules(). * + * @note All the implicit nodes, such as non-presence containers and + * leafs with default values, must be present in the diff. + * * @param[in] diff YANG diff belonging to either ietf-netconf-server, ietf-keystore or ietf-truststore modules. * The top level node HAS to have an operation (create, replace, delete or none). * @return 0 on success, 1 on error. @@ -83,10 +86,13 @@ int nc_server_config_setup_diff(const struct lyd_node *diff); /** * @brief Configure server based on the given 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 be applied. + * The current configuration will be completely replaced by the given data. + * * Context must already have implemented the required modules, see ::nc_server_config_load_modules(). * + * @note All the implicit nodes, such as non-presence containers and + * leafs with default values, must be present in the data. + * * @param[in] data YANG data belonging to either ietf-netconf-server, ietf-keystore or ietf-truststore modules. * This data __must be valid__. No node can have an operation attribute. * @return 0 on success, 1 on error. @@ -320,40 +326,39 @@ int nc_server_config_del_truststore_cert(const char *cert_bag_name, const char *cert_name, struct lyd_node **config); /** - * @brief Gets the hostkey algorithms supported by the server from the 'iana-ssh-public-key-algs' YANG module. + * @brief Gets all the SSH transport algorithms supported by the server. * - * @param[in] ctx libyang context. - * @param[out] hostkey_algs Container with leaf-lists containing the supported algorithms. - * @return 0 on success, non-zero otherwise. - */ -int nc_server_config_oper_get_hostkey_algs(const struct ly_ctx *ctx, struct lyd_node **hostkey_algs); - -/** - * @brief Gets the key exchange algorithms supported by the server from the 'iana-ssh-key-exchange-algs' YANG module. + * @note Actual usable algorithms depend on the underlying libssh library version, + * the returned list is based on libssh v0.11.0. * * @param[in] ctx libyang context. - * @param[out] kex_algs Container with leaf-lists containing the supported algorithms. + * @param[out] supported_algs Supported SSH transport algorithms. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_oper_get_kex_algs(const struct ly_ctx *ctx, struct lyd_node **kex_algs); +int nc_server_config_oper_get_supported_ssh_algs(const struct ly_ctx *ctx, struct lyd_node **supported_algs); /** - * @brief Gets the encryption algorithms supported by the server from the 'iana-ssh-encryption-algs' YANG module. + * @brief Gets all the TLS transport cipher suites supported by the server. + * + * @note Actual usable cipher suites depend on the underlying TLS library and its version. * * @param[in] ctx libyang context. - * @param[out] encryption_algs Container with leaf-lists containing the supported algorithms. + * @param[out] supported_algs Supported cipher suites. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_oper_get_encryption_algs(const struct ly_ctx *ctx, struct lyd_node **encryption_algs); +int nc_server_config_oper_get_supported_tls_algs(const struct ly_ctx *ctx, struct lyd_node **supported_algs); /** - * @brief Gets the MAC algorithms supported by the server from the 'iana-ssh-mac-algs' YANG module. + * @brief Gets the last modified time of an SSH user's password. * - * @param[in] ctx libyang context. - * @param[out] mac_algs Container with leaf-lists containing the supported algorithms. + * @param[in] ch_client Name of the call-home client the user is configured on. NULL if the user is on a listening endpoint. + * @param[in] endpoint Name of the endpoint the user is configured on. Can be either a listening or call-home endpoint. + * @param[in] username Name of the SSH user. + * @param[out] last_modified Time of the last password modification. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_oper_get_mac_algs(const struct ly_ctx *ctx, struct lyd_node **mac_algs); +int nc_server_config_oper_get_user_password_last_modified(const char *ch_client, + const char *endpoint, const char *username, time_t *last_modified); /** * @} Server Configuration Functions diff --git a/src/server_config_ks.c b/src/server_config_ks.c deleted file mode 100644 index 13d46964..00000000 --- a/src/server_config_ks.c +++ /dev/null @@ -1,445 +0,0 @@ -/** - * @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 - -#include - -#include "compat.h" -#include "log_p.h" -#include "server_config_p.h" -#include "session_p.h" - -/** - * @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; - const char *node_name = LYD_NAME(node); - - assert(node && askey); - - 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.", node_name); - 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, struct nc_certificate **cert) -{ - uint16_t i; - const char *cert_name; - struct nc_asymmetric_key *askey; - const char *node_name = LYD_NAME(node); - - assert(node && cert); - - if (nc_server_config_get_asymmetric_key(node, &askey)) { - return 1; - } - - 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.", node_name); - 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); - free(cert->data); - - key->cert_count--; - 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_asymmetric_key(struct nc_asymmetric_key *key) -{ - uint16_t i, cert_count; - struct nc_keystore *ks = &server_opts.keystore; - - free(key->name); - free(key->pubkey_data); - free(key->privkey_data); - - 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; - } else if (key != &ks->asym_keys[ks->asym_key_count]) { - memcpy(key, &ks->asym_keys[ks->asym_key_count], sizeof *ks->asym_keys); - } -} - -static int -nc_server_config_ks_asymmetric_keys(const struct lyd_node *node, enum 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, enum 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, enum 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, enum 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_PUBKEY_FORMAT_SSH; - } else if (!strcmp(format, "subject-public-key-info-format")) { - key->pubkey_type = NC_PUBKEY_FORMAT_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, enum 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 */ - free(key->pubkey_data); - key->pubkey_data = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_RET(!key->pubkey_data, 1); - - return 0; -} - -static int -nc_server_config_ks_private_key_format(const struct lyd_node *node, enum nc_operation op) -{ - struct nc_asymmetric_key *key; - const char *format; - enum nc_privkey_format privkey_type; - - (void) op; - - 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 (!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; -} - -static int -nc_server_config_ks_cleartext_private_key(const struct lyd_node *node, enum 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 */ - free(key->privkey_data); - key->privkey_data = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_RET(!key->privkey_data, 1); - } else if (op == NC_OP_DELETE) { - free(key->privkey_data); - key->privkey_data = NULL; - } - - 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, enum 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, &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, enum nc_operation op) -{ - struct nc_certificate *cert; - - assert(!strcmp(LYD_NAME(node), "cert-data")); - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - if (nc_server_config_get_certificate(node, &cert)) { - return 1; - } - - /* replace the cert data */ - free(cert->data); - cert->data = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_RET(!cert->data, 1); - } - - return 0; -} - -int -nc_server_config_parse_keystore_node(const struct lyd_node *node, enum nc_operation op) -{ - const char *name = LYD_NAME(node); - int ret = 0; - - if (!strcmp(name, "keystore")) { - ret = nc_server_config_ks_keystore(node, op); - } else if (!strcmp(name, "asymmetric-keys")) { - ret = nc_server_config_ks_asymmetric_keys(node, op); - } else if (!strcmp(name, "asymmetric-key")) { - ret = nc_server_config_ks_asymmetric_key(node, op); - } else if (!strcmp(name, "public-key-format")) { - ret = nc_server_config_ks_public_key_format(node, op); - } else if (!strcmp(name, "public-key")) { - ret = nc_server_config_ks_public_key(node, op); - } else if (!strcmp(name, "private-key-format")) { - ret = nc_server_config_ks_private_key_format(node, op); - } else if (!strcmp(name, "cleartext-private-key")) { - ret = nc_server_config_ks_cleartext_private_key(node, op); - } else if (!strcmp(name, "certificate")) { - ret = nc_server_config_ks_certificate(node, op); - } else if (!strcmp(name, "cert-data")) { - ret = nc_server_config_ks_cert_data(node, op); - } - - if (ret) { - ERR(NULL, "Configuring (%s) failed.", name); - return 1; - } - - return 0; -} - -int -nc_server_config_fill_keystore(const struct lyd_node *data, enum 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)) { - /* not found */ - ret = 0; - goto cleanup; - } - - if (nc_server_config_process_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 deleted file mode 100644 index aa90aee4..00000000 --- a/src/server_config_p.h +++ /dev/null @@ -1,169 +0,0 @@ -/** - * @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_ - -#include -#include -#include - -#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_LIBNETCONF2_NETCONF_SERVER -} NC_MODULE; - -#ifdef NC_ENABLED_SSH_TLS - -/** - * @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. - */ -enum nc_privkey_format nc_server_config_get_private_key_type(const char *format); - -#endif /* NC_ENABLED_SSH_TLS */ - -/** - * @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, void *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_server_config_process_tree(const struct lyd_node *node, enum 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(const struct lyd_node *node, enum 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, enum nc_operation op); - -#ifdef NC_ENABLED_SSH_TLS - -/** 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, enum 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_node(const struct lyd_node *node, enum 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, enum 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, enum 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_node(const struct lyd_node *node, enum 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, enum nc_operation op); - -/** LIBNETCONF2-NETCONF-SERVER **/ - -/** - * @brief Configures the ln2-netconf-server subtree in the libnetconf2-netconf-server module. - * - * @param[in] node Optional ln2-netconf-server 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_ln2_netconf_server(const struct lyd_node *node, enum nc_operation op); - -#endif /* NC_ENABLED_SSH_TLS */ - -#endif /* NC_CONFIG_SERVER_P_H_ */ diff --git a/src/server_config_ts.c b/src/server_config_ts.c deleted file mode 100644 index b59dca9f..00000000 --- a/src/server_config_ts.c +++ /dev/null @@ -1,600 +0,0 @@ -/** - * @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 - -#include - -#include "compat.h" -#include "log_p.h" -#include "server_config_p.h" -#include "session_p.h" - -/** - * @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; - const char *node_name = LYD_NAME(node); - - assert(node && cbag); - - 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.", node_name); - 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[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, struct nc_certificate **cert) -{ - uint16_t i; - const char *cert_name; - struct nc_certificate_bag *cbag; - const char *node_name = LYD_NAME(node); - - assert(node && cert); - - if (nc_server_config_get_certificate_bag(node, &cbag)) { - return 1; - } - - 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.", node_name); - 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; - const char *node_name = LYD_NAME(node); - - assert(node && pbag); - - 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.", node_name); - 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[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, struct nc_public_key **pkey) -{ - uint16_t i; - const char *pkey_name; - struct nc_public_key_bag *pbag; - const char *node_name = LYD_NAME(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")) { - 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.", node_name); - 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_certificate(struct nc_certificate_bag *cbag, struct nc_certificate *cert) -{ - free(cert->name); - free(cert->data); - - cbag->cert_count--; - 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); - } -} - -static void -nc_server_config_ts_del_public_key(struct nc_public_key_bag *pbag, struct nc_public_key *pkey) -{ - free(pkey->name); - free(pkey->data); - - pbag->pubkey_count--; - 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); - } -} - -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); - - 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) { - 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); - } -} - -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); - - 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) { - 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); - } -} - -static int -nc_server_config_ts_certificate_bags(const struct lyd_node *node, enum 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, enum 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, enum 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, enum 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, enum 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, &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, enum nc_operation op) -{ - struct nc_certificate *cert; - - if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) { - if (nc_server_config_get_certificate(node, &cert)) { - return 1; - } - - free(cert->data); - cert->data = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_RET(!cert->data, 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, enum 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, enum 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, &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, &pkey)) { - ret = 1; - goto cleanup; - } - - /* replace the public key */ - free(pkey->data); - pkey->data = strdup(lyd_get_value(node)); - NC_CHECK_ERRMEM_GOTO(!pkey->data, ret = 1, cleanup); - } - -cleanup: - return ret; -} - -static int -nc_server_config_ts_public_key_format(const struct lyd_node *node, enum nc_operation op) -{ - const char *format; - struct nc_public_key *pkey; - - (void) op; - - if (nc_server_config_get_public_key(node, &pkey)) { - return 1; - } - - format = ((struct lyd_node_term *)node)->value.ident->name; - if (!strcmp(format, "ssh-public-key-format")) { - pkey->type = NC_PUBKEY_FORMAT_SSH; - } else if (!strcmp(format, "subject-public-key-info-format")) { - pkey->type = NC_PUBKEY_FORMAT_X509; - } else { - ERR(NULL, "Public key format (%s) not supported.", format); - } - - return 0; -} - -int -nc_server_config_parse_truststore_node(const struct lyd_node *node, enum nc_operation op) -{ - const char *name = LYD_NAME(node); - int ret = 0; - - if (!strcmp(name, "truststore")) { - ret = nc_server_config_ts_truststore(node, op); - } else if (!strcmp(name, "certificate-bags")) { - ret = nc_server_config_ts_certificate_bags(node, op); - } else if (!strcmp(name, "certificate-bag")) { - ret = nc_server_config_ts_certificate_bag(node, op); - } else if (!strcmp(name, "certificate")) { - ret = nc_server_config_ts_certificate(node, op); - } else if (!strcmp(name, "cert-data")) { - ret = nc_server_config_ts_cert_data(node, op); - } else if (!strcmp(name, "public-key-bags")) { - ret = nc_server_config_ts_public_key_bags(node, op); - } else if (!strcmp(name, "public-key-bag")) { - ret = nc_server_config_ts_public_key_bag(node, op); - } else if (!strcmp(name, "public-key")) { - ret = nc_server_config_ts_public_key(node, op); - } else if (!strcmp(name, "public-key-format")) { - ret = nc_server_config_ts_public_key_format(node, op); - } - - if (ret) { - ERR(NULL, "Configuring (%s) failed.", name); - return 1; - } - - return 0; -} - -int -nc_server_config_fill_truststore(const struct lyd_node *data, enum 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)) { - /* not found */ - ret = 0; - goto cleanup; - } - - if (nc_server_config_process_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/src/server_config_util.c b/src/server_config_util.c index 96acf9eb..36e21122 100644 --- a/src/server_config_util.c +++ b/src/server_config_util.c @@ -41,6 +41,7 @@ int nc_server_config_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...) { int ret = 0; + struct lyd_node *iter; va_list ap; char *path = NULL; @@ -69,10 +70,12 @@ nc_server_config_create(const struct ly_ctx *ctx, struct lyd_node **tree, const goto cleanup; } - /* add all default nodes */ - ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; + /* add all implicit nodes of ietf-netconf-server, ietf-keystore and ietf-truststore */ + LY_LIST_FOR(lyd_first_sibling(*tree), iter) { + ret = lyd_new_implicit_tree(iter, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } } cleanup: @@ -86,6 +89,7 @@ nc_server_config_append(const struct ly_ctx *ctx, const char *parent_path, const const char *value, struct lyd_node **tree) { int ret = 0; + struct lyd_node *iter; char *path = NULL; NC_CHECK_ARG_RET(NULL, ctx, parent_path, child_name, tree, 1); @@ -111,10 +115,12 @@ nc_server_config_append(const struct ly_ctx *ctx, const char *parent_path, const goto cleanup; } - /* add all default nodes */ - ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; + /* add all implicit nodes of ietf-netconf-server, ietf-keystore and ietf-truststore */ + LY_LIST_FOR(lyd_first_sibling(*tree), iter) { + ret = lyd_new_implicit_tree(iter, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } } cleanup: @@ -128,7 +134,7 @@ nc_server_config_delete(struct lyd_node **tree, const char *path_fmt, ...) int ret = 0; va_list ap; char *path = NULL; - struct lyd_node *sub = NULL; + struct lyd_node *sub = NULL, *iter; NC_CHECK_ARG_RET(NULL, tree, path_fmt, 1); @@ -146,16 +152,18 @@ nc_server_config_delete(struct lyd_node **tree, const char *path_fmt, ...) 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; } - /* add all default nodes */ - ret = lyd_new_implicit_tree(*tree, LYD_IMPLICIT_NO_STATE, NULL); - if (ret) { - goto cleanup; + /* add all implicit nodes of ietf-netconf-server, ietf-keystore and ietf-truststore */ + LY_LIST_FOR(lyd_first_sibling(*tree), iter) { + ret = lyd_new_implicit_tree(iter, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } } cleanup: @@ -170,7 +178,7 @@ nc_server_config_check_delete(struct lyd_node **tree, const char *path_fmt, ...) int ret = 0; va_list ap; char *path = NULL; - struct lyd_node *sub = NULL; + struct lyd_node *sub = NULL, *iter; NC_CHECK_ARG_RET(NULL, tree, path_fmt, 1); @@ -192,12 +200,20 @@ nc_server_config_check_delete(struct lyd_node **tree, const char *path_fmt, ...) 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; } + /* add all implicit nodes of ietf-netconf-server, ietf-keystore and ietf-truststore */ + LY_LIST_FOR(lyd_first_sibling(*tree), iter) { + ret = lyd_new_implicit_tree(iter, LYD_IMPLICIT_NO_STATE, NULL); + if (ret) { + goto cleanup; + } + } + cleanup: free(path); va_end(ap); @@ -988,32 +1004,27 @@ nc_server_config_add_address_port(const struct ly_ctx *ctx, const char *endpt_na const char *address, uint16_t port, struct lyd_node **config) { int ret = 0; - const char *address_fmt, *port_fmt; + const char *path_fmt, *transport_str; char port_buf[6] = {0}; NC_CHECK_ARG_RET(NULL, ctx, endpt_name, address, config, 1); + /* prepare the path */ + path_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/%s/tcp-server-parameters/" + "local-bind[local-address='%s']/local-port"; + if (transport == NC_TI_SSH) { - /* SSH path */ - address_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/tcp-server-parameters/local-address"; - port_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/tcp-server-parameters/local-port"; + transport_str = "ssh"; } else if (transport == NC_TI_TLS) { - /* TLS path */ - address_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/tcp-server-parameters/local-address"; - port_fmt = "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/tcp-server-parameters/local-port"; + transport_str = "tls"; } else { ERR(NULL, "Can not set address and port of a non SSH/TLS endpoint."); ret = 1; goto cleanup; } - ret = nc_server_config_create(ctx, config, address, address_fmt, endpt_name); - if (ret) { - goto cleanup; - } - - sprintf(port_buf, "%d", port); - ret = nc_server_config_create(ctx, config, port_buf, port_fmt, endpt_name); + snprintf(port_buf, sizeof(port_buf), "%u", port); + ret = nc_server_config_create(ctx, config, port_buf, path_fmt, endpt_name, transport_str, address); if (ret) { goto cleanup; } diff --git a/src/server_config_util.h b/src/server_config_util.h index e38366ac..e2f93843 100644 --- a/src/server_config_util.h +++ b/src/server_config_util.h @@ -149,7 +149,7 @@ int nc_server_config_append(const struct ly_ctx *ctx, const char *parent_path, c /** * @brief Deletes a subtree from the YANG data. * - * @param tree YANG data from which the subtree will be deleted. + * @param[in,out] 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. @@ -159,7 +159,7 @@ 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. * - * @param tree YANG data from which the subtree will be deleted. + * @param[in,out] 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. diff --git a/src/server_config_util_ssh.c b/src/server_config_util_ssh.c index aca2ad1b..fcfb5e0a 100644 --- a/src/server_config_util_ssh.c +++ b/src/server_config_util_ssh.c @@ -511,7 +511,7 @@ _nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char *tr goto cleanup; } - ret = nc_server_config_append(ctx, tree_path, "password", hashed_pw, config); + ret = nc_server_config_append(ctx, tree_path, "hashed-password", hashed_pw, config); if (ret) { goto cleanup; } @@ -531,7 +531,7 @@ 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); ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/" - "client-authentication/users/user[name='%s']", endpt_name, user_name); + "client-authentication/users/user[name='%s']/password", 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); @@ -555,7 +555,7 @@ nc_server_config_add_ch_ssh_user_password(const struct ly_ctx *ctx, const char * 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); + "users/user[name='%s']/password", 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); diff --git a/src/session.c b/src/session.c index 3688dd4a..e803c0db 100644 --- a/src/session.c +++ b/src/session.c @@ -1406,7 +1406,7 @@ nc_send_hello_io(struct nc_session *session) if (session->flags & NC_SESSION_CALLHOME) { timeout_io = NC_SERVER_CH_HELLO_TIMEOUT * 1000; } else { - timeout_io = server_opts.idle_timeout ? server_opts.idle_timeout * 1000 : -1; + timeout_io = server_opts.config.idle_timeout ? server_opts.config.idle_timeout * 1000 : -1; } sid = &session->id; } @@ -1528,7 +1528,7 @@ nc_server_recv_hello_io(struct nc_session *session) if (session->flags & NC_SESSION_CALLHOME) { timeout_io = NC_SERVER_CH_HELLO_TIMEOUT * 1000; } else { - timeout_io = server_opts.idle_timeout ? server_opts.idle_timeout * 1000 : -1; + timeout_io = server_opts.config.idle_timeout ? server_opts.config.idle_timeout * 1000 : -1; } r = nc_read_msg_poll_io(session, timeout_io, &msg); diff --git a/src/session.h b/src/session.h index c4f9f79a..2fd87f7b 100644 --- a/src/session.h +++ b/src/session.h @@ -58,16 +58,6 @@ 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_client_ssh.c b/src/session_client_ssh.c index fe5b2715..b1bb6cac 100644 --- a/src/session_client_ssh.c +++ b/src/session_client_ssh.c @@ -1798,8 +1798,6 @@ 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); } /* prepare session structure */ diff --git a/src/session_client_tls.c b/src/session_client_tls.c index 1d3aa717..8224dd18 100644 --- a/src/session_client_tls.c +++ b/src/session_client_tls.c @@ -270,7 +270,7 @@ nc_client_tls_session_new(int sock, const char *host, int timeout, struct nc_cli } /* init TLS context and store data which may be needed later in it */ - if (nc_tls_init_ctx_wrap(cli_cert, cli_pkey, cert_store, crl_store, tls_ctx)) { + if (nc_tls_init_ctx_wrap(cli_cert, cli_pkey, cert_store, crl_store, NULL, tls_ctx)) { goto fail; } diff --git a/src/session_mbedtls.c b/src/session_mbedtls.c index 9313eb73..b7375eef 100644 --- a/src/session_mbedtls.c +++ b/src/session_mbedtls.c @@ -51,6 +51,44 @@ #include #include +/** + * @brief List of supported cipher suites for MbedTLS. + * + * This list is used to populate the operational data for supported cipher suites. + * Obtained from v4.0.0. + */ +const char *nc_tls_supported_cipher_suites[] = { + "TLS_PSK_WITH_NULL_SHA", "TLS_PSK_WITH_AES_128_CBC_SHA", "TLS_PSK_WITH_AES_256_CBC_SHA", + "TLS_PSK_WITH_AES_128_GCM_SHA256", "TLS_PSK_WITH_AES_256_GCM_SHA384", "TLS_PSK_WITH_AES_128_CBC_SHA256", + "TLS_PSK_WITH_AES_256_CBC_SHA384", "TLS_PSK_WITH_NULL_SHA256", "TLS_PSK_WITH_NULL_SHA384", + "TLS_ECDHE_ECDSA_WITH_NULL_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_NULL_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_PSK_WITH_NULL_SHA", "TLS_ECDHE_PSK_WITH_NULL_SHA256", + "TLS_ECDHE_PSK_WITH_NULL_SHA384", "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", "TLS_PSK_WITH_ARIA_128_CBC_SHA256", "TLS_PSK_WITH_ARIA_256_CBC_SHA384", + "TLS_PSK_WITH_ARIA_128_GCM_SHA256", "TLS_PSK_WITH_ARIA_256_GCM_SHA384", "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", + "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", "TLS_PSK_WITH_AES_128_CCM", "TLS_PSK_WITH_AES_256_CCM", + "TLS_PSK_WITH_AES_128_CCM_8", "TLS_PSK_WITH_AES_256_CCM_8", "TLS_ECDHE_ECDSA_WITH_AES_128_CCM", + "TLS_ECDHE_ECDSA_WITH_AES_256_CCM", "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", NULL +}; + /** * @brief Converts MbedTLS error code to a string and merges it with an arbitrary error message. * @@ -503,24 +541,19 @@ nc_server_tls_add_crl_to_store_wrap(const unsigned char *crl_data, size_t size, } int -nc_server_tls_set_tls_versions_wrap(void *tls_cfg, unsigned int tls_versions) +nc_server_tls_set_tls_versions_wrap(void *tls_cfg, enum nc_tls_version min, enum nc_tls_version max) { - if ((tls_versions & NC_TLS_VERSION_10) || ((tls_versions & NC_TLS_VERSION_11))) { - /* skip TLS versions 1.0 and 1.1 */ - WRN(NULL, "mbedTLS does not support TLS1.0 and TLS1.1"); - } - - /* first set the minimum version */ - if (tls_versions & NC_TLS_VERSION_12) { + /* set the minimum version if any, otherwise leave it to MbedTLS default */ + if (min & NC_TLS_VERSION_1_2) { mbedtls_ssl_conf_min_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_2); - } else if (tls_versions & NC_TLS_VERSION_13) { + } else if (min & NC_TLS_VERSION_1_3) { mbedtls_ssl_conf_min_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_3); } - /* then set the maximum version */ - if (tls_versions & NC_TLS_VERSION_13) { + /* set the maximum version if any, otherwise leave it to MbedTLS default */ + if (max & NC_TLS_VERSION_1_3) { mbedtls_ssl_conf_max_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_3); - } else if (tls_versions & NC_TLS_VERSION_12) { + } else if (max & NC_TLS_VERSION_1_2) { mbedtls_ssl_conf_max_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_2); } @@ -1043,6 +1076,7 @@ nc_tls_ctx_destroy_wrap(struct nc_tls_ctx *tls_ctx) nc_tls_cert_store_destroy_wrap(tls_ctx->cert_store); nc_tls_crl_store_destroy_wrap(tls_ctx->crl_store); free(tls_ctx->sock); + free(tls_ctx->cipher_suites); } void * @@ -1141,7 +1175,8 @@ nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname) } int -nc_tls_init_ctx_wrap(void *cert, void *pkey, void *cert_store, void *crl_store, struct nc_tls_ctx *tls_ctx) +nc_tls_init_ctx_wrap(void *cert, void *pkey, void *cert_store, + void *crl_store, void *cipher_suites, struct nc_tls_ctx *tls_ctx) { /* setup rng */ if (nc_tls_rng_new(&tls_ctx->ctr_drbg, &tls_ctx->entropy)) { @@ -1149,6 +1184,7 @@ nc_tls_init_ctx_wrap(void *cert, void *pkey, void *cert_store, void *crl_store, } /* fill the context */ + tls_ctx->cipher_suites = cipher_suites; tls_ctx->sock = malloc(sizeof *tls_ctx->sock); NC_CHECK_ERRMEM_RET(!tls_ctx->sock, 1); tls_ctx->cert = cert; @@ -1904,69 +1940,433 @@ nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, cha return ret; } -int -nc_tls_process_cipher_suite_wrap(const char *cipher, char **out) -{ - const char *begin, *ptr; - - /* check if it's a TLS 1.3 cipher suite */ - if (!strcmp(cipher, "tls-aes-256-gcm-sha384") || !strcmp(cipher, "tls-aes-128-gcm-sha256") || - !strcmp(cipher, "tls-chacha20-poly1305-sha256") || !strcmp(cipher, "tls-aes-128-ccm-sha256") || - !strcmp(cipher, "tls-aes-128-ccm-8-sha256")) { - /* + 3 because mbedtls has "TLS1-3" prefix for 1.3 suites */ - *out = malloc(strlen(cipher) + 3 + 1); - NC_CHECK_ERRMEM_RET(!*out, 1); - sprintf(*out, "TLS1-3"); - begin = cipher + 4; - } else { - *out = malloc(strlen(cipher) + 1); - NC_CHECK_ERRMEM_RET(!*out, 1); - begin = cipher; - } - - /* convert to uppercase */ - for (ptr = begin; *ptr; ptr++) { - (*out)[ptr - begin] = toupper(*ptr); - } - - (*out)[ptr - begin] = '\0'; - return 0; +const char * +nc_server_tls_cipher_suite_name_to_internal_wrap(const char *iana_name) +{ + if (!strcmp(iana_name, "TLS_AES_128_GCM_SHA256")) { + return "TLS1-3-AES-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_AES_256_GCM_SHA384")) { + return "TLS1-3-AES-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_CHACHA20_POLY1305_SHA256")) { + return "TLS1-3-CHACHA20-POLY1305-SHA256"; + } else if (!strcmp(iana_name, "TLS_AES_128_CCM_SHA256")) { + return "TLS1-3-AES-128-CCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_AES_128_CCM_8_SHA256")) { + return "TLS1-3-AES-128-CCM-8-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")) { + return "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")) { + return "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256")) { + return "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")) { + return "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256")) { + return "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256")) { + return "TLS-PSK-WITH-CHACHA20-POLY1305-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256")) { + return "TLS-ECDHE-PSK-WITH-CHACHA20-POLY1305-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256")) { + return "TLS-DHE-PSK-WITH-CHACHA20-POLY1305-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256")) { + return "TLS-RSA-PSK-WITH-CHACHA20-POLY1305-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA")) { + return "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA")) { + return "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256")) { + return "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256")) { + return "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384")) { + return "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384")) { + return "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM")) { + return "TLS-ECDHE-ECDSA-WITH-AES-256-CCM"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8")) { + return "TLS-ECDHE-ECDSA-WITH-AES-256-CCM-8"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM")) { + return "TLS-ECDHE-ECDSA-WITH-AES-128-CCM"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8")) { + return "TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384")) { + return "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256")) { + return "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384")) { + return "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_NULL_SHA")) { + return "TLS-ECDHE-ECDSA-WITH-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")) { + return "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA")) { + return "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256")) { + return "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")) { + return "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384")) { + return "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384")) { + return "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384")) { + return "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256")) { + return "TLS-ECDHE-RSA-WITH-CAMELLIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384")) { + return "TLS-ECDHE-RSA-WITH-CAMELLIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_NULL_SHA")) { + return "TLS-ECDHE-RSA-WITH-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384")) { + return "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256")) { + return "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256")) { + return "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256")) { + return "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA")) { + return "TLS-DHE-RSA-WITH-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA")) { + return "TLS-DHE-RSA-WITH-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_256_CCM")) { + return "TLS-DHE-RSA-WITH-AES-256-CCM"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_256_CCM_8")) { + return "TLS-DHE-RSA-WITH-AES-256-CCM-8"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_128_CCM")) { + return "TLS-DHE-RSA-WITH-AES-128-CCM"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_128_CCM_8")) { + return "TLS-DHE-RSA-WITH-AES-128-CCM-8"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256")) { + return "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA")) { + return "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA")) { + return "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256")) { + return "TLS-DHE-RSA-WITH-CAMELLIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384")) { + return "TLS-DHE-RSA-WITH-CAMELLIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_256_GCM_SHA384")) { + return "TLS-RSA-WITH-AES-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_128_GCM_SHA256")) { + return "TLS-RSA-WITH-AES-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_128_CBC_SHA256")) { + return "TLS-RSA-WITH-AES-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_256_CBC_SHA256")) { + return "TLS-RSA-WITH-AES-256-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_128_CBC_SHA")) { + return "TLS-RSA-WITH-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_256_CBC_SHA")) { + return "TLS-RSA-WITH-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_256_CCM")) { + return "TLS-RSA-WITH-AES-256-CCM"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_256_CCM_8")) { + return "TLS-RSA-WITH-AES-256-CCM-8"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_128_CCM")) { + return "TLS-RSA-WITH-AES-128-CCM"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_128_CCM_8")) { + return "TLS-RSA-WITH-AES-128-CCM-8"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256")) { + return "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA")) { + return "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA")) { + return "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256")) { + return "TLS-RSA-WITH-CAMELLIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384")) { + return "TLS-RSA-WITH-CAMELLIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA")) { + return "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA")) { + return "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256")) { + return "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256")) { + return "TLS-ECDH-RSA-WITH-AES-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384")) { + return "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384")) { + return "TLS-ECDH-RSA-WITH-AES-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "TLS-ECDH-RSA-WITH-CAMELLIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384")) { + return "TLS-ECDH-RSA-WITH-CAMELLIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256")) { + return "TLS-ECDH-RSA-WITH-CAMELLIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384")) { + return "TLS-ECDH-RSA-WITH-CAMELLIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_NULL_SHA")) { + return "TLS-ECDH-RSA-WITH-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA")) { + return "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA")) { + return "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256")) { + return "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256")) { + return "TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384")) { + return "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384")) { + return "TLS-ECDH-ECDSA-WITH-AES-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384")) { + return "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256")) { + return "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384")) { + return "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_NULL_SHA")) { + return "TLS-ECDH-ECDSA-WITH-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_128_GCM_SHA256")) { + return "TLS-PSK-WITH-AES-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_256_GCM_SHA384")) { + return "TLS-PSK-WITH-AES-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_128_CBC_SHA256")) { + return "TLS-PSK-WITH-AES-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_256_CBC_SHA384")) { + return "TLS-PSK-WITH-AES-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_128_CBC_SHA")) { + return "TLS-PSK-WITH-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_256_CBC_SHA")) { + return "TLS-PSK-WITH-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_256_CCM")) { + return "TLS-PSK-WITH-AES-256-CCM"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_256_CCM_8")) { + return "TLS-PSK-WITH-AES-256-CCM-8"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_128_CCM")) { + return "TLS-PSK-WITH-AES-128-CCM"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_128_CCM_8")) { + return "TLS-PSK-WITH-AES-128-CCM-8"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256")) { + return "TLS-PSK-WITH-CAMELLIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384")) { + return "TLS-PSK-WITH-CAMELLIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256")) { + return "TLS-PSK-WITH-CAMELLIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384")) { + return "TLS-PSK-WITH-CAMELLIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256")) { + return "TLS-DHE-PSK-WITH-AES-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384")) { + return "TLS-DHE-PSK-WITH-AES-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256")) { + return "TLS-DHE-PSK-WITH-AES-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384")) { + return "TLS-DHE-PSK-WITH-AES-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA")) { + return "TLS-DHE-PSK-WITH-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA")) { + return "TLS-DHE-PSK-WITH-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_AES_256_CCM")) { + return "TLS-DHE-PSK-WITH-AES-256-CCM"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_AES_128_CCM")) { + return "TLS-DHE-PSK-WITH-AES-128-CCM"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256")) { + return "TLS-DHE-PSK-WITH-CAMELLIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384")) { + return "TLS-DHE-PSK-WITH-CAMELLIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256")) { + return "TLS-DHE-PSK-WITH-CAMELLIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384")) { + return "TLS-DHE-PSK-WITH-CAMELLIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256")) { + return "TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384")) { + return "TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA")) { + return "TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA")) { + return "TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256")) { + return "TLS-ECDHE-PSK-WITH-CAMELLIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384")) { + return "TLS-ECDHE-PSK-WITH-CAMELLIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256")) { + return "TLS-RSA-PSK-WITH-AES-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384")) { + return "TLS-RSA-PSK-WITH-AES-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256")) { + return "TLS-RSA-PSK-WITH-AES-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384")) { + return "TLS-RSA-PSK-WITH-AES-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA")) { + return "TLS-RSA-PSK-WITH-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA")) { + return "TLS-RSA-PSK-WITH-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256")) { + return "TLS-RSA-PSK-WITH-CAMELLIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384")) { + return "TLS-RSA-PSK-WITH-CAMELLIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256")) { + return "TLS-RSA-PSK-WITH-CAMELLIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384")) { + return "TLS-RSA-PSK-WITH-CAMELLIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_NULL_MD5")) { + return "TLS-RSA-WITH-NULL-MD5"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_NULL_SHA")) { + return "TLS-RSA-WITH-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_NULL_SHA256")) { + return "TLS-RSA-WITH-NULL-SHA256"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_NULL_SHA")) { + return "TLS-PSK-WITH-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_NULL_SHA256")) { + return "TLS-PSK-WITH-NULL-SHA256"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_NULL_SHA384")) { + return "TLS-PSK-WITH-NULL-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_NULL_SHA")) { + return "TLS-DHE-PSK-WITH-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_NULL_SHA256")) { + return "TLS-DHE-PSK-WITH-NULL-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_NULL_SHA384")) { + return "TLS-DHE-PSK-WITH-NULL-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_NULL_SHA")) { + return "TLS-ECDHE-PSK-WITH-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_NULL_SHA256")) { + return "TLS-ECDHE-PSK-WITH-NULL-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_NULL_SHA384")) { + return "TLS-ECDHE-PSK-WITH-NULL-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_NULL_SHA")) { + return "TLS-RSA-PSK-WITH-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_NULL_SHA256")) { + return "TLS-RSA-PSK-WITH-NULL-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_NULL_SHA384")) { + return "TLS-RSA-PSK-WITH-NULL-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_ARIA_256_GCM_SHA384")) { + return "TLS-RSA-WITH-ARIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_ARIA_256_CBC_SHA384")) { + return "TLS-RSA-WITH-ARIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_ARIA_128_GCM_SHA256")) { + return "TLS-RSA-WITH-ARIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_ARIA_128_CBC_SHA256")) { + return "TLS-RSA-WITH-ARIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384")) { + return "TLS-RSA-PSK-WITH-ARIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384")) { + return "TLS-RSA-PSK-WITH-ARIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256")) { + return "TLS-RSA-PSK-WITH-ARIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256")) { + return "TLS-RSA-PSK-WITH-ARIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_ARIA_256_GCM_SHA384")) { + return "TLS-PSK-WITH-ARIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_ARIA_256_CBC_SHA384")) { + return "TLS-PSK-WITH-ARIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_ARIA_128_GCM_SHA256")) { + return "TLS-PSK-WITH-ARIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_ARIA_128_CBC_SHA256")) { + return "TLS-PSK-WITH-ARIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384")) { + return "TLS-ECDH-RSA-WITH-ARIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384")) { + return "TLS-ECDH-RSA-WITH-ARIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256")) { + return "TLS-ECDH-RSA-WITH-ARIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256")) { + return "TLS-ECDH-RSA-WITH-ARIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384")) { + return "TLS-ECDHE-RSA-WITH-ARIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384")) { + return "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256")) { + return "TLS-ECDHE-RSA-WITH-ARIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256")) { + return "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384")) { + return "TLS-ECDHE-PSK-WITH-ARIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256")) { + return "TLS-ECDHE-PSK-WITH-ARIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384")) { + return "TLS-ECDHE-ECDSA-WITH-ARIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384")) { + return "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256")) { + return "TLS-ECDHE-ECDSA-WITH-ARIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256")) { + return "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384")) { + return "TLS-ECDH-ECDSA-WITH-ARIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384")) { + return "TLS-ECDH-ECDSA-WITH-ARIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256")) { + return "TLS-ECDH-ECDSA-WITH-ARIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256")) { + return "TLS-ECDH-ECDSA-WITH-ARIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384")) { + return "TLS-DHE-RSA-WITH-ARIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384")) { + return "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256")) { + return "TLS-DHE-RSA-WITH-ARIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256")) { + return "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384")) { + return "TLS-DHE-PSK-WITH-ARIA-256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384")) { + return "TLS-DHE-PSK-WITH-ARIA-256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256")) { + return "TLS-DHE-PSK-WITH-ARIA-128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256")) { + return "TLS-DHE-PSK-WITH-ARIA-128-CBC-SHA256"; + } + + /* not found */ + WRN(NULL, "Cipher suite name \"%s\" not supported by MbedTLS.", iana_name); + return NULL; } int -nc_tls_append_cipher_suite_wrap(struct nc_server_tls_opts *opts, const char *cipher_suite) -{ - int cipher_id; - - cipher_id = mbedtls_ssl_get_ciphersuite_id(cipher_suite); - if (!cipher_id) { - return 1; +nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, const char *cipher_suites, void **cipher_suites_out) +{ + int rc = 0, *mbedtls_ciphersuites, i; + size_t count; + const char *p; + char *suites_copy, *suite, *saveptr; + + /* copy the suites for strtok_r */ + suites_copy = strdup(cipher_suites); + NC_CHECK_ERRMEM_RET(!suites_copy, 1); + + /* count the amount of cipher suites in the colon-separated list, we always have at least one */ + count = 1; + for (p = cipher_suites; *p; p++) { + if (*p == ':') { + count++; + } } - /* append the cipher suite to a zero terminated array */ - if (!opts->ciphers) { - /* first entry, account for terminating 0 */ - opts->ciphers = malloc(2 * sizeof cipher_id); - NC_CHECK_ERRMEM_RET(!opts->ciphers, 1); - ((int *)opts->ciphers)[0] = cipher_id; - opts->cipher_count = 1; - } else { - /* +2 because of terminating 0 */ - opts->ciphers = nc_realloc(opts->ciphers, (opts->cipher_count + 2) * sizeof cipher_id); - NC_CHECK_ERRMEM_RET(!opts->ciphers, 1); - ((int *)opts->ciphers)[opts->cipher_count] = cipher_id; - opts->cipher_count++; + /* allocate this many mbedtls ciphersuites + 1 for terminating 0 */ + mbedtls_ciphersuites = malloc((count + 1) * sizeof *mbedtls_ciphersuites); + NC_CHECK_ERRMEM_GOTO(!mbedtls_ciphersuites, rc = 1, cleanup); + + /* convert each cipher suite name to mbedtls internal ID */ + i = 0; + while ((suite = strtok_r(i ? NULL : suites_copy, ":", &saveptr))) { + mbedtls_ciphersuites[i] = mbedtls_ssl_get_ciphersuite_id(suite); + i++; } + mbedtls_ciphersuites[i] = 0; - /* terminate the array */ - ((int *)opts->ciphers)[opts->cipher_count] = 0; - return 0; -} + mbedtls_ssl_conf_ciphersuites(tls_cfg, mbedtls_ciphersuites); -void -nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites) -{ - mbedtls_ssl_conf_ciphersuites(tls_cfg, cipher_suites); + *cipher_suites_out = mbedtls_ciphersuites; + +cleanup: + free(suites_copy); + return rc; } time_t diff --git a/src/session_openssl.c b/src/session_openssl.c index de8ad54f..472d8c3d 100644 --- a/src/session_openssl.c +++ b/src/session_openssl.c @@ -44,6 +44,88 @@ #include #include +/** + * @brief List of supported cipher suites for OpenSSL. + * + * This list is used to populate the operational data for supported cipher suites. + * Obtained from: https://testssl.sh/openssl-iana.mapping.html + */ +const char *nc_tls_supported_cipher_suites[] = { + "TLS_RSA_WITH_NULL_MD5", "TLS_RSA_WITH_NULL_SHA", "TLS_RSA_EXPORT_WITH_RC4_40_MD5", "TLS_RSA_WITH_RC4_128_MD5", + "TLS_RSA_WITH_RC4_128_SHA", "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", "TLS_RSA_WITH_IDEA_CBC_SHA", + "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", "TLS_RSA_WITH_DES_CBC_SHA", "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", "TLS_DH_DSS_WITH_DES_CBC_SHA", "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", "TLS_DH_RSA_WITH_DES_CBC_SHA", "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", "TLS_DHE_DSS_WITH_DES_CBC_SHA", "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "TLS_DHE_RSA_WITH_DES_CBC_SHA", "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_KRB5_WITH_DES_CBC_SHA", "TLS_KRB5_WITH_3DES_EDE_CBC_SHA", "TLS_KRB5_WITH_RC4_128_SHA", + "TLS_KRB5_WITH_IDEA_CBC_SHA", "TLS_KRB5_WITH_DES_CBC_MD5", "TLS_KRB5_WITH_3DES_EDE_CBC_MD5", + "TLS_KRB5_WITH_RC4_128_MD5", "TLS_KRB5_WITH_IDEA_CBC_MD5", "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", + "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", "TLS_KRB5_EXPORT_WITH_RC4_40_SHA", "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", + "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", "TLS_KRB5_EXPORT_WITH_RC4_40_MD5", "TLS_PSK_WITH_NULL_SHA", + "TLS_DHE_PSK_WITH_NULL_SHA", "TLS_RSA_PSK_WITH_NULL_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_DH_DSS_WITH_AES_128_CBC_SHA", "TLS_DH_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_DH_DSS_WITH_AES_256_CBC_SHA", + "TLS_DH_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_NULL_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", + "TLS_DH_DSS_WITH_AES_128_CBC_SHA256", "TLS_DH_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", + "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DH_DSS_WITH_AES_256_CBC_SHA256", "TLS_DH_RSA_WITH_AES_256_CBC_SHA256", + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", + "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", + "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", "TLS_PSK_WITH_RC4_128_SHA", + "TLS_PSK_WITH_3DES_EDE_CBC_SHA", "TLS_PSK_WITH_AES_128_CBC_SHA", "TLS_PSK_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_SEED_CBC_SHA", "TLS_DH_DSS_WITH_SEED_CBC_SHA", "TLS_DH_RSA_WITH_SEED_CBC_SHA", + "TLS_DHE_DSS_WITH_SEED_CBC_SHA", "TLS_DHE_RSA_WITH_SEED_CBC_SHA", "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_DH_RSA_WITH_AES_128_GCM_SHA256", "TLS_DH_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", + "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DH_DSS_WITH_AES_128_GCM_SHA256", "TLS_DH_DSS_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256", "TLS_AES_128_CCM_SHA256", "TLS_AES_128_CCM_8_SHA256", + "TLS_ECDH_ECDSA_WITH_NULL_SHA", "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_NULL_SHA", + "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDH_RSA_WITH_NULL_SHA", "TLS_ECDH_RSA_WITH_RC4_128_SHA", + "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_NULL_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", + "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", + "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_PSK_WITH_RC4_128_SHA", + "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_PSK_WITH_NULL_SHA", + "TLS_ECDHE_PSK_WITH_NULL_SHA256", "TLS_ECDHE_PSK_WITH_NULL_SHA384", "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", "TLS_RSA_WITH_AES_128_CCM", "TLS_RSA_WITH_AES_256_CCM", + "TLS_DHE_RSA_WITH_AES_128_CCM", "TLS_DHE_RSA_WITH_AES_256_CCM", "TLS_RSA_WITH_AES_128_CCM_8", + "TLS_RSA_WITH_AES_256_CCM_8", "TLS_DHE_RSA_WITH_AES_128_CCM_8", "TLS_DHE_RSA_WITH_AES_256_CCM_8", + "TLS_PSK_WITH_AES_128_CCM", "TLS_PSK_WITH_AES_256_CCM", "TLS_DHE_PSK_WITH_AES_128_CCM", + "TLS_DHE_PSK_WITH_AES_256_CCM", "TLS_PSK_WITH_AES_128_CCM_8", "TLS_PSK_WITH_AES_256_CCM_8", + "TLS_PSK_DHE_WITH_AES_128_CCM_8", "TLS_PSK_DHE_WITH_AES_256_CCM_8", "TLS_ECDHE_ECDSA_WITH_AES_128_CCM", + "TLS_ECDHE_ECDSA_WITH_AES_256_CCM", "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", + "TLS_SHA256_SHA256", "TLS_SHA384_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", + "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256", NULL +}; + int nc_tls_backend_init_wrap(void) { @@ -259,18 +341,14 @@ nc_server_tls_add_crl_to_store_wrap(const unsigned char *crl_data, size_t size, } int -nc_server_tls_set_tls_versions_wrap(void *tls_cfg, unsigned int tls_versions) +nc_server_tls_set_tls_versions_wrap(void *tls_cfg, enum nc_tls_version min, enum nc_tls_version max) { int rc = 1; - /* first set the minimum version */ - if (tls_versions & NC_TLS_VERSION_10) { - rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_VERSION); - } else if (tls_versions & NC_TLS_VERSION_11) { - rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_1_VERSION); - } else if (tls_versions & NC_TLS_VERSION_12) { + /* set the minimum version if any, otherwise leave it to OpenSSL default */ + if (min & NC_TLS_VERSION_1_2) { rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_2_VERSION); - } else if (tls_versions & NC_TLS_VERSION_13) { + } else if (min & NC_TLS_VERSION_1_3) { rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_3_VERSION); } if (!rc) { @@ -278,15 +356,11 @@ nc_server_tls_set_tls_versions_wrap(void *tls_cfg, unsigned int tls_versions) return 1; } - /* then set the maximum version */ - if (tls_versions & NC_TLS_VERSION_13) { + /* set the maximum version if any, otherwise leave it to OpenSSL default */ + if (max & NC_TLS_VERSION_1_3) { rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_3_VERSION); - } else if (tls_versions & NC_TLS_VERSION_12) { + } else if (max & NC_TLS_VERSION_1_2) { rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_2_VERSION); - } else if (tls_versions & NC_TLS_VERSION_11) { - rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_1_VERSION); - } else if (tls_versions & NC_TLS_VERSION_10) { - rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_VERSION); } if (!rc) { ERR(NULL, "Setting TLS max version failed (%s).", ERR_reason_error_string(ERR_get_error())); @@ -761,7 +835,8 @@ nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname) } int -nc_tls_init_ctx_wrap(void *cert, void *pkey, void *cert_store, void *crl_store, struct nc_tls_ctx *tls_ctx) +nc_tls_init_ctx_wrap(void *cert, void *pkey, void *cert_store, + void *crl_store, void *UNUSED(cipher_suites), struct nc_tls_ctx *tls_ctx) { tls_ctx->cert = cert; tls_ctx->pkey = pkey; @@ -1425,53 +1500,421 @@ nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, cha return ret; } -int -nc_tls_process_cipher_suite_wrap(const char *cipher, char **out) -{ - int i; - - *out = malloc(strlen(cipher) + 1); - NC_CHECK_ERRMEM_RET(!*out, 1); - - /* convert to uppercase */ - for (i = 0; cipher[i]; i++) { - if (cipher[i] == '-') { - /* OpenSSL requires _ instead of - in cipher names */ - (*out)[i] = '_'; - } else { - (*out)[i] = toupper(cipher[i]); - } - } - - (*out)[i] = '\0'; - return 0; +const char * +nc_server_tls_cipher_suite_name_to_internal_wrap(const char *iana_name) +{ + if (!strcmp(iana_name, "TLS_RSA_WITH_NULL_MD5")) { + return "NULL-MD5"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_NULL_SHA")) { + return "NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_EXPORT_WITH_RC4_40_MD5")) { + return "EXP-RC4-MD5"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_RC4_128_MD5")) { + return "RC4-MD5"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_RC4_128_SHA")) { + return "RC4-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5")) { + return "EXP-RC2-CBC-MD5"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_IDEA_CBC_SHA")) { + return "IDEA-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA")) { + return "EXP-DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_DES_CBC_SHA")) { + return "DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_3DES_EDE_CBC_SHA")) { + return "DES-CBC3-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA")) { + return "EXP-DH-DSS-DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_DES_CBC_SHA")) { + return "DH-DSS-DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA")) { + return "DH-DSS-DES-CBC3-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA")) { + return "EXP-DH-RSA-DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_DES_CBC_SHA")) { + return "DH-RSA-DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA")) { + return "DH-RSA-DES-CBC3-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA")) { + return "EXP-EDH-DSS-DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_DES_CBC_SHA")) { + return "EDH-DSS-DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA")) { + return "EDH-DSS-DES-CBC3-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA")) { + return "EXP-EDH-RSA-DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_DES_CBC_SHA")) { + return "EDH-RSA-DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA")) { + return "EDH-RSA-DES-CBC3-SHA"; + } else if (!strcmp(iana_name, "TLS_KRB5_WITH_DES_CBC_SHA")) { + return "KRB5-DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA")) { + return "KRB5-DES-CBC3-SHA"; + } else if (!strcmp(iana_name, "TLS_KRB5_WITH_RC4_128_SHA")) { + return "KRB5-RC4-SHA"; + } else if (!strcmp(iana_name, "TLS_KRB5_WITH_IDEA_CBC_SHA")) { + return "KRB5-IDEA-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_KRB5_WITH_DES_CBC_MD5")) { + return "KRB5-DES-CBC-MD5"; + } else if (!strcmp(iana_name, "TLS_KRB5_WITH_3DES_EDE_CBC_MD5")) { + return "KRB5-DES-CBC3-MD5"; + } else if (!strcmp(iana_name, "TLS_KRB5_WITH_RC4_128_MD5")) { + return "KRB5-RC4-MD5"; + } else if (!strcmp(iana_name, "TLS_KRB5_WITH_IDEA_CBC_MD5")) { + return "KRB5-IDEA-CBC-MD5"; + } else if (!strcmp(iana_name, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA")) { + return "EXP-KRB5-DES-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA")) { + return "EXP-KRB5-RC2-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_KRB5_EXPORT_WITH_RC4_40_SHA")) { + return "EXP-KRB5-RC4-SHA"; + } else if (!strcmp(iana_name, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5")) { + return "EXP-KRB5-DES-CBC-MD5"; + } else if (!strcmp(iana_name, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5")) { + return "EXP-KRB5-RC2-CBC-MD5"; + } else if (!strcmp(iana_name, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5")) { + return "EXP-KRB5-RC4-MD5"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_NULL_SHA")) { + return "PSK-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_NULL_SHA")) { + return "DHE-PSK-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_NULL_SHA")) { + return "RSA-PSK-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_128_CBC_SHA")) { + return "AES128-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_AES_128_CBC_SHA")) { + return "DH-DSS-AES128-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_AES_128_CBC_SHA")) { + return "DH-RSA-AES128-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA")) { + return "DHE-DSS-AES128-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA")) { + return "DHE-RSA-AES128-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_256_CBC_SHA")) { + return "AES256-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_AES_256_CBC_SHA")) { + return "DH-DSS-AES256-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_AES_256_CBC_SHA")) { + return "DH-RSA-AES256-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA")) { + return "DHE-DSS-AES256-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA")) { + return "DHE-RSA-AES256-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_NULL_SHA256")) { + return "NULL-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_128_CBC_SHA256")) { + return "AES128-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_256_CBC_SHA256")) { + return "AES256-SHA256"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256")) { + return "DH-DSS-AES128-SHA256"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256")) { + return "DH-RSA-AES128-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256")) { + return "DHE-DSS-AES128-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA")) { + return "CAMELLIA128-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA")) { + return "DH-DSS-CAMELLIA128-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA")) { + return "DH-RSA-CAMELLIA128-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA")) { + return "DHE-DSS-CAMELLIA128-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA")) { + return "DHE-RSA-CAMELLIA128-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256")) { + return "DHE-RSA-AES128-SHA256"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256")) { + return "DH-DSS-AES256-SHA256"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256")) { + return "DH-RSA-AES256-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256")) { + return "DHE-DSS-AES256-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256")) { + return "DHE-RSA-AES256-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA")) { + return "CAMELLIA256-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA")) { + return "DH-DSS-CAMELLIA256-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA")) { + return "DH-RSA-CAMELLIA256-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA")) { + return "DHE-DSS-CAMELLIA256-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA")) { + return "DHE-RSA-CAMELLIA256-SHA"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_RC4_128_SHA")) { + return "PSK-RC4-SHA"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_3DES_EDE_CBC_SHA")) { + return "PSK-3DES-EDE-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_128_CBC_SHA")) { + return "PSK-AES128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_256_CBC_SHA")) { + return "PSK-AES256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_SEED_CBC_SHA")) { + return "SEED-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_SEED_CBC_SHA")) { + return "DH-DSS-SEED-SHA"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_SEED_CBC_SHA")) { + return "DH-RSA-SEED-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_SEED_CBC_SHA")) { + return "DHE-DSS-SEED-SHA"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_SEED_CBC_SHA")) { + return "DHE-RSA-SEED-SHA"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_128_GCM_SHA256")) { + return "AES128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_256_GCM_SHA384")) { + return "AES256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256")) { + return "DHE-RSA-AES128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384")) { + return "DHE-RSA-AES256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256")) { + return "DH-RSA-AES128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384")) { + return "DH-RSA-AES256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256")) { + return "DHE-DSS-AES128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384")) { + return "DHE-DSS-AES256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256")) { + return "DH-DSS-AES128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384")) { + return "DH-DSS-AES256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256")) { + return "DH-DSS-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "DH-RSA-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256")) { + return "DHE-DSS-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "DHE-RSA-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { + return "TLS_FALLBACK_SCSV"; + } else if (!strcmp(iana_name, "TLS_AES_128_GCM_SHA256")) { + return "TLS_AES_128_GCM_SHA256"; + } else if (!strcmp(iana_name, "TLS_AES_256_GCM_SHA384")) { + return "TLS_AES_256_GCM_SHA384"; + } else if (!strcmp(iana_name, "TLS_CHACHA20_POLY1305_SHA256")) { + return "TLS_CHACHA20_POLY1305_SHA256"; + } else if (!strcmp(iana_name, "TLS_AES_128_CCM_SHA256")) { + return "TLS_AES_128_CCM_SHA256"; + } else if (!strcmp(iana_name, "TLS_AES_128_CCM_8_SHA256")) { + return "TLS_AES_128_CCM_8_SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_NULL_SHA")) { + return "ECDH-ECDSA-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA")) { + return "ECDH-ECDSA-RC4-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA")) { + return "ECDH-ECDSA-DES-CBC3-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA")) { + return "ECDH-ECDSA-AES128-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA")) { + return "ECDH-ECDSA-AES256-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_NULL_SHA")) { + return "ECDHE-ECDSA-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA")) { + return "ECDHE-ECDSA-RC4-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA")) { + return "ECDHE-ECDSA-DES-CBC3-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA")) { + return "ECDHE-ECDSA-AES128-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA")) { + return "ECDHE-ECDSA-AES256-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_NULL_SHA")) { + return "ECDH-RSA-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_RC4_128_SHA")) { + return "ECDH-RSA-RC4-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA")) { + return "ECDH-RSA-DES-CBC3-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA")) { + return "ECDH-RSA-AES128-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA")) { + return "ECDH-RSA-AES256-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_NULL_SHA")) { + return "ECDHE-RSA-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_RC4_128_SHA")) { + return "ECDHE-RSA-RC4-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA")) { + return "ECDHE-RSA-DES-CBC3-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")) { + return "ECDHE-RSA-AES128-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA")) { + return "ECDHE-RSA-AES256-SHA"; + } else if (!strcmp(iana_name, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA")) { + return "SRP-3DES-EDE-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA")) { + return "SRP-RSA-3DES-EDE-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA")) { + return "SRP-DSS-3DES-EDE-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA")) { + return "SRP-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA")) { + return "SRP-RSA-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA")) { + return "SRP-DSS-AES-128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA")) { + return "SRP-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA")) { + return "SRP-RSA-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA")) { + return "SRP-DSS-AES-256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256")) { + return "ECDHE-ECDSA-AES128-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384")) { + return "ECDHE-ECDSA-AES256-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256")) { + return "ECDH-ECDSA-AES128-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384")) { + return "ECDH-ECDSA-AES256-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256")) { + return "ECDHE-RSA-AES128-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384")) { + return "ECDHE-RSA-AES256-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256")) { + return "ECDH-RSA-AES128-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384")) { + return "ECDH-RSA-AES256-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256")) { + return "ECDHE-ECDSA-AES128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384")) { + return "ECDHE-ECDSA-AES256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256")) { + return "ECDH-ECDSA-AES128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384")) { + return "ECDH-ECDSA-AES256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")) { + return "ECDHE-RSA-AES128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384")) { + return "ECDHE-RSA-AES256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256")) { + return "ECDH-RSA-AES128-GCM-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384")) { + return "ECDH-RSA-AES256-GCM-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_RC4_128_SHA")) { + return "ECDHE-PSK-RC4-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA")) { + return "ECDHE-PSK-3DES-EDE-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA")) { + return "ECDHE-PSK-AES128-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA")) { + return "ECDHE-PSK-AES256-CBC-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256")) { + return "ECDHE-PSK-AES128-CBC-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384")) { + return "ECDHE-PSK-AES256-CBC-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_NULL_SHA")) { + return "ECDHE-PSK-NULL-SHA"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_NULL_SHA256")) { + return "ECDHE-PSK-NULL-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_NULL_SHA384")) { + return "ECDHE-PSK-NULL-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "ECDHE-ECDSA-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384")) { + return "ECDHE-ECDSA-CAMELLIA256-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "ECDH-ECDSA-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384")) { + return "ECDH-ECDSA-CAMELLIA256-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "ECDHE-RSA-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384")) { + return "ECDHE-RSA-CAMELLIA256-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256")) { + return "ECDH-RSA-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384")) { + return "ECDH-RSA-CAMELLIA256-SHA384"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256")) { + return "PSK-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384")) { + return "PSK-CAMELLIA256-SHA384"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256")) { + return "DHE-PSK-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384")) { + return "DHE-PSK-CAMELLIA256-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256")) { + return "RSA-PSK-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384")) { + return "RSA-PSK-CAMELLIA256-SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256")) { + return "ECDHE-PSK-CAMELLIA128-SHA256"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384")) { + return "ECDHE-PSK-CAMELLIA256-SHA384"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_128_CCM")) { + return "AES128-CCM"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_256_CCM")) { + return "AES256-CCM"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_128_CCM")) { + return "DHE-RSA-AES128-CCM"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_256_CCM")) { + return "DHE-RSA-AES256-CCM"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_128_CCM_8")) { + return "AES128-CCM8"; + } else if (!strcmp(iana_name, "TLS_RSA_WITH_AES_256_CCM_8")) { + return "AES256-CCM8"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_128_CCM_8")) { + return "DHE-RSA-AES128-CCM8"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_AES_256_CCM_8")) { + return "DHE-RSA-AES256-CCM8"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_128_CCM")) { + return "PSK-AES128-CCM"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_256_CCM")) { + return "PSK-AES256-CCM"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_AES_128_CCM")) { + return "DHE-PSK-AES128-CCM"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_AES_256_CCM")) { + return "DHE-PSK-AES256-CCM"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_128_CCM_8")) { + return "PSK-AES128-CCM8"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_AES_256_CCM_8")) { + return "PSK-AES256-CCM8"; + } else if (!strcmp(iana_name, "TLS_PSK_DHE_WITH_AES_128_CCM_8")) { + return "DHE-PSK-AES128-CCM8"; + } else if (!strcmp(iana_name, "TLS_PSK_DHE_WITH_AES_256_CCM_8")) { + return "DHE-PSK-AES256-CCM8"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM")) { + return "ECDHE-ECDSA-AES128-CCM"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM")) { + return "ECDHE-ECDSA-AES256-CCM"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8")) { + return "ECDHE-ECDSA-AES128-CCM8"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8")) { + return "ECDHE-ECDSA-AES256-CCM8"; + } else if (!strcmp(iana_name, "TLS_SHA256_SHA256")) { + return "TLS_SHA256_SHA256"; + } else if (!strcmp(iana_name, "TLS_SHA384_SHA384")) { + return "TLS_SHA384_SHA384"; + } else if (!strcmp(iana_name, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256")) { + return "ECDHE-RSA-CHACHA20-POLY1305"; + } else if (!strcmp(iana_name, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")) { + return "ECDHE-ECDSA-CHACHA20-POLY1305"; + } else if (!strcmp(iana_name, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256")) { + return "DHE-RSA-CHACHA20-POLY1305"; + } else if (!strcmp(iana_name, "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256")) { + return "PSK-CHACHA20-POLY1305"; + } else if (!strcmp(iana_name, "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256")) { + return "ECDHE-PSK-CHACHA20-POLY1305"; + } else if (!strcmp(iana_name, "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256")) { + return "DHE-PSK-CHACHA20-POLY1305"; + } else if (!strcmp(iana_name, "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256")) { + return "RSA-PSK-CHACHA20-POLY1305"; + } + + return NULL; } int -nc_tls_append_cipher_suite_wrap(struct nc_server_tls_opts *opts, const char *cipher_suite) -{ - if (!opts->ciphers) { - /* first entry */ - opts->ciphers = strdup(cipher_suite); - NC_CHECK_ERRMEM_RET(!opts->ciphers, 1); - } else { - /* + 1 because of : between entries */ - opts->ciphers = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(cipher_suite) + 1 + 1); - NC_CHECK_ERRMEM_RET(!opts->ciphers, 1); - strcat(opts->ciphers, ":"); - strcat(opts->ciphers, cipher_suite); - } - - return 0; -} - -void -nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites) +nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, const char *cipher_suites, void **UNUSED(cipher_suites_out)) { /* set for TLS1.2 and lower */ SSL_CTX_set_cipher_list(tls_cfg, cipher_suites); /* set for TLS1.3 */ SSL_CTX_set_ciphersuites(tls_cfg, cipher_suites); + + return 0; } time_t diff --git a/src/session_p.h b/src/session_p.h index d62cee06..1219b91e 100644 --- a/src/session_p.h +++ b/src/session_p.h @@ -78,6 +78,12 @@ extern struct nc_server_opts server_opts; */ #define NC_PS_QUEUE_TIMEOUT 5000 +/** + * @brief Maximum time (in seconds) to wait for a pending configuration + * update to complete before rejecting a new update request. + */ +#define NC_SERVER_CONFIG_UPDATE_WAIT_TIMEOUT_SEC 5 + /** * Time slept in msec if no endpoint was created for a running Call Home client. */ @@ -131,10 +137,11 @@ enum nc_operation { * Enumeration of key or certificate store type. */ enum nc_store_type { - 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_SYSTEM /**< key/certificate is managed by the system */ + NC_STORE_UNKNOWN = 0, /**< unknown store type */ + 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_SYSTEM /**< key/certificate is managed by the system */ }; #ifdef NC_ENABLED_SSH_TLS @@ -148,22 +155,23 @@ enum nc_store_type { #define NC_SSH_TIMEOUT 10 /** - * Enumeration of SSH public key formats. + * @brief Enumeration of SSH public key formats. */ enum nc_pubkey_format { + NC_PUBKEY_FORMAT_UNKNOWN = 0, /**< Unknown format */ NC_PUBKEY_FORMAT_SSH, /**< see RFC 4253, section 6.6 */ NC_PUBKEY_FORMAT_X509 /**< see RFC 5280 sec. 4.1.2.7 */ }; /** - * Enumeration of private key file formats. + * @brief Enumeration of private key file formats. */ enum nc_privkey_format { - NC_PRIVKEY_FORMAT_RSA, /**< PKCS1 RSA format */ - NC_PRIVKEY_FORMAT_EC, /**< SEC1 EC format */ - NC_PRIVKEY_FORMAT_X509, /**< X509 (PKCS8) format */ - NC_PRIVKEY_FORMAT_OPENSSH, /**< OpenSSH format */ - NC_PRIVKEY_FORMAT_UNKNOWN /**< Unknown format */ + NC_PRIVKEY_FORMAT_UNKNOWN = 0, /**< Unknown format */ + NC_PRIVKEY_FORMAT_RSA, /**< PKCS1 RSA format */ + NC_PRIVKEY_FORMAT_EC, /**< SEC1 EC format */ + NC_PRIVKEY_FORMAT_X509, /**< X509 (PKCS8) format */ + NC_PRIVKEY_FORMAT_OPENSSH /**< OpenSSH format */ }; /** @@ -175,74 +183,71 @@ enum nc_kbdint_auth_method { }; /** - * @brief A basic certificate. + * @brief Certificate representation. */ struct nc_certificate { - char *name; /**< Arbitrary name of the certificate. */ + char *name; /**< Optional identifier of the certificate. */ char *data; /**< Base-64 encoded certificate. */ }; -struct nc_certificate_bag { - char *name; - struct nc_certificate *certs; - uint16_t cert_count; -}; - /** - * @brief An asymmetric key. + * @brief Public key representation. */ -struct nc_asymmetric_key { - char *name; /**< Arbitrary name of the key. */ - - enum nc_pubkey_format pubkey_type; /**< Type of the public key. */ - char *pubkey_data; /**< Base-64 encoded public key. */ - enum 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. */ +struct nc_public_key { + char *name; /**< Optional identifier of the public key. */ + enum nc_pubkey_format type; /**< Type of the public key. */ + char *data; /**< Base-64 encoded public key. */ }; /** - * @brief A symmetric key. + * @brief Private key representation. */ -struct nc_symmetric_key { - char *name; /**< Arbitrary name of the key. */ - char *data; /**< Base-64 encoded key. */ +struct nc_private_key { + enum nc_privkey_format type; /**< Type of the private key. */ + char *data; /**< Base-64 encoded private key. */ }; /** - * @brief A public key. + * @brief Asymmetric key pair representation. */ -struct nc_public_key { - char *name; /**< Arbitrary name of the public key. */ - enum nc_pubkey_format type; /**< Type of the public key. */ - char *data; /**< Base-64 encoded public key. */ -}; +struct nc_asymmetric_key { + char *name; /**< Optional identifier of the key pair. */ -struct nc_public_key_bag { - char *name; - struct nc_public_key *pubkeys; - uint16_t pubkey_count; + struct nc_public_key pubkey; /**< Public key. */ + struct nc_private_key privkey; /**< Private key. */ }; +/** + * @brief Store of trusted certificates and public keys. + */ struct nc_truststore { - struct nc_certificate_bag *cert_bags; - uint16_t cert_bag_count; + /** + * @brief Bag of certificates that should share the same purpose. + */ + struct nc_certificate_bag { + char *name; /**< Identifier of the certificate bag. */ + char *description; /**< Optional description of the certificate bag. */ + struct nc_certificate *certs; /**< Certificates in the bag (sized-array, see libyang docs). */ + } *cert_bags; /**< Certificate bags (sized-array, see libyang docs). */ - struct nc_public_key_bag *pub_bags; - uint16_t pub_bag_count; + /** + * @brief Bag of public keys that should share the same purpose. + */ + struct nc_public_key_bag { + char *name; /**< Identifier of the public key bag. */ + char *description; /**< Optional description of the public key bag. */ + struct nc_public_key *pubkeys; /**< Public keys in the bag (sized-array, see libyang docs). */ + } *pubkey_bags; /**< Public key bags (sized-array, see libyang docs). */ }; /** * @brief Keystore YANG module representation. */ struct nc_keystore { - struct nc_asymmetric_key *asym_keys; /**< Stored asymmetric keys. */ - uint16_t asym_key_count; /**< Count of stored asymmetric keys. */ - - struct nc_symmetric_key *sym_keys; /**< Stored symmetric keys. */ - uint16_t sym_key_count; /**< Count of stored symmetric keys. */ + struct nc_keystore_entry { + struct nc_asymmetric_key asym_key; /**< Stored asymmetric key. */ + struct nc_certificate *certs; /**< Certificates associated with the asymmetric key (sized-array, see libyang docs). */ + } *entries; /**< Asymmetric key + certs entries (sized-array, see libyang docs). */ }; /** @@ -256,36 +261,35 @@ struct nc_auth_state { }; /** - * @brief A server's authorized client. + * @brief Client authorized to connect to the server over SSH. */ struct nc_auth_client { - char *username; /**< Arbitrary username. */ + char *username; /**< Identifier of the client. */ - enum nc_store_type store; /**< Specifies how/where the client's public key is stored. */ + enum nc_store_type pubkey_store; /**< Specifies how/where the client's public keys are stored. */ union { - struct { - struct nc_public_key *pubkeys; /**< The client's public keys. */ - uint16_t pubkey_count; /**< The number of client's public keys. */ - }; - char *ts_ref; /**< Name of the referenced truststore key. */ + struct nc_public_key *pubkeys; /**< Locally-defined public keys (sized-array, see libyang docs). */ + char *ts_ref; /**< Name of the referenced truststore public key bag. */ }; - char *password; /**< Client's password */ + char *password; /**< Password for password authentication. */ + time_t password_last_modified; /**< Time of the last password modification. */ + enum nc_kbdint_auth_method kbdint_method; /**< Keyboard-interactive authentication method, * may be extended by e.g. a union for each method when needed. */ - int none_enabled; /**< Implies that the client supports the none authentication method. */ + int none_enabled; /**< Whether "none" authentication is enabled for this user. */ }; /** - * @brief The server's hostkey. + * @brief Server's SSH host key. */ struct nc_hostkey { - char *name; /**< Arbitrary name of the host key. */ + char *name; /**< Identifier of the hostkey. */ - enum nc_store_type store; /**< Specifies how/where the key is stored. */ + enum nc_store_type store; /**< Specifies how/where the key is stored. */ union { - struct nc_asymmetric_key key; /**< The server's hostkey. */ - char *ks_ref; /**< Name of the referenced key. */ + struct nc_asymmetric_key key; /**< Locally-defined key. */ + char *ks_ref; /**< Name of the referenced keystore key. */ }; }; @@ -293,38 +297,22 @@ struct nc_hostkey { * @brief Server options for configuring the SSH transport protocol. */ struct nc_server_ssh_opts { - struct nc_hostkey *hostkeys; /**< Server's hostkeys. */ - uint16_t hostkey_count; /**< Number of server's hostkeys. */ + struct nc_hostkey *hostkeys; /**< Server's hostkeys (sized-array, see libyang docs). */ - struct nc_auth_client *auth_clients; /**< Server's authorized clients. */ - uint16_t client_count; /**< Number of server's authorized clients. */ + struct nc_auth_client *auth_clients; /**< Server's authorized clients (sized-array, see libyang docs). */ 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. */ - char *kex_algs; /**< Key exchange algorithms supported by the server. */ - char *mac_algs; /**< MAC algorithms supported by the server. */ + char *hostkey_algs; /**< Used hostkey algorithms (comma-separated list). */ + char *encryption_algs; /**< Used encryption algorithms (comma-separated list). */ + char *kex_algs; /**< Used key exchange algorithms (comma-separated list). */ + char *mac_algs; /**< Used MAC algorithms (comma-separated list). */ char *banner; /**< SSH banner message. */ uint16_t auth_timeout; /**< Authentication timeout. */ }; -/** - * @brief Certificate grouping (either local-definition or truststore reference). - */ -struct nc_cert_grouping { - enum 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. */ - }; - char *ts_ref; /**< Name of the referenced truststore certificate bag. */ - }; -}; - /** * @brief Storing downloaded data via CURL. */ @@ -344,44 +332,64 @@ struct nc_ctn { struct nc_ctn *next; /**< Linked-list reference to the next entry */ }; +/** + * @brief Enumeration of supported TLS versions. + */ +enum nc_tls_version { + NC_TLS_VERSION_NONE = 0, /**< Unknown TLS version */ + NC_TLS_VERSION_1_2, /**< TLS version 1.2 */ + NC_TLS_VERSION_1_3 /**< TLS version 1.3 */ +}; + +/** + * @brief Server's TLS client authentication configuration. + */ +struct nc_server_tls_client_auth { + enum nc_store_type ca_certs_store; /**< Specifies how/where the CA certificates are stored. */ + union { + struct nc_certificate *ca_certs; /**< Locally-defined CA certificates (sized-array, see libyang docs). */ + char *ca_cert_bag_ts_ref; /**< Name of the referenced truststore certificate bag. */ + }; + + enum nc_store_type ee_certs_store; /**< Specifies how/where the end-entity certificates are stored. */ + union { + struct nc_certificate *ee_certs; /**< Locally-defined end-entity certificates (sized-array, see libyang docs). */ + char *ee_cert_bag_ts_ref; /**< Name of the referenced truststore certificate bag. */ + }; +}; + /** * @brief Server options for configuring the TLS transport protocol. */ struct nc_server_tls_opts { - enum nc_store_type store; /**< Specifies how/where the server identity is stored. */ + enum nc_store_type cert_store; /**< Specifies how/where the server's key and certificate are stored. */ union { struct { - enum nc_pubkey_format pubkey_type; /**< Server public key type */ - char *pubkey_data; /**< Server's public key */ - - enum nc_privkey_format privkey_type; /**< Server private key type */ - char *privkey_data; /**< Server's private key */ - - char *cert_data; /**< Server's certificate */ - }; - + struct nc_asymmetric_key key; /**< Locally-defined key. */ + struct nc_certificate cert; /**< Locally-defined certificate. */ + } local; /**< Local definition of the server's key and certificate. */ struct { - char *key_ref; /**< Reference to the server's key */ - char *cert_ref; /**< Reference to the concrete server's certificate */ - }; + char *asym_key_ref; /**< Name of the referenced keystore asymmetric key. */ + char *cert_ref; /**< Name of the referenced keystore certificate. */ + } keystore; /**< Keystore reference of the server's key and certificate. */ }; - struct nc_cert_grouping ca_certs; /**< Client certificate authorities */ - struct nc_cert_grouping ee_certs; /**< Client end-entity certificates */ + struct nc_server_tls_client_auth client_auth; /**< Client authentication configuration. */ - char *referenced_endpt_name; /**< Reference to another endpoint (used for client authentication). */ + struct nc_ctn *ctn; /**< Cert-to-name entries linked list */ - unsigned int tls_versions; /**< TLS versions */ - void *ciphers; /**< TLS ciphers */ - uint16_t cipher_count; /**< Number of TLS ciphers */ + char *referenced_endpt_name; /**< Reference to another endpoint (used for client authentication). */ - struct nc_ctn *ctn; /**< Cert-to-name entries */ + enum nc_tls_version min_version; /**< Minimum supported TLS version. */ + enum nc_tls_version max_version; /**< Maximum supported TLS version. */ + + char *cipher_suites; /**< Allowed cipher suites (colon-separated list). */ }; #endif /* NC_ENABLED_SSH_TLS */ /** - * @brief Keepalives configuration data. + * @brief TCP keepalives configuration. */ struct nc_keepalives { int enabled; /**< Indicates that keepalives are enabled. */ @@ -391,30 +399,26 @@ struct nc_keepalives { }; /** - * @brief UNIX socket connection configuration. + * @brief Server options for configuring the UNIX transport protocol. */ struct nc_server_unix_opts { - char *path; /**< Filesystem path to the UNIX socket. */ - mode_t mode; /**< Socket file permissions (defaults to rw-rw----). */ uid_t uid; /**< Owner of the socket file. */ gid_t gid; /**< Group owner of the socket file. */ struct nc_server_unix_user_mapping { char *system_user; /**< System username for authentication. */ - char **allowed_users; /**< Permitted NETCONF usernames. */ - uint32_t allowed_user_count; /**< Number of allowed usernames. */ - } *user_mappings; /**< Array of username mappings for the UNIX socket connection. */ - uint32_t mapping_count; /**< Number of user mapping entries. */ + char **allowed_users; /**< Permitted NETCONF usernames (sized-array, see libyang docs). */ + } *user_mappings; /**< Username mappings for the UNIX socket connection (sized-array, see libyang docs). */ }; /** - * @brief Stores information about a bind. + * @brief Stores information about a server endpoint binding. */ struct nc_bind { - char *address; /**< Bind's address. */ - uint16_t port; /**< Bind's port. */ - int sock; /**< Bind's socket. */ + char *address; /**< Either IPv4/IPv6 address or path to UNIX socket. */ + uint16_t port; /**< Either port number or 0 for UNIX socket. */ + int sock; /**< Socket file descriptor, -1 if not created yet. */ int pollin; /**< Specifies, which sockets to poll on. */ }; @@ -590,7 +594,7 @@ struct nc_cert_path_aux { /** * @brief Call Home client thread data. */ -struct nc_ch_client_thread_arg { +struct nc_server_ch_thread_arg { char *client_name; const struct ly_ctx *(*acquire_ctx_cb)(void *cb_data); /**< acquiring libyang context cb */ @@ -604,68 +608,35 @@ struct nc_ch_client_thread_arg { pthread_cond_t cond; /**< Condition used for signalling the thread to terminate */ }; -struct nc_server_opts { - /* ACCESS locked - hello lock - separate lock to not always hold config_lock */ - pthread_rwlock_t hello_lock; /**< Needs to be held while the server message is being generated. */ +struct nc_server_config { + uint16_t idle_timeout; /**< Idle timeout of the server sessions. */ - char **ignored_modules; /**< Names of YANG modules that are not reported in the server message. */ - uint16_t ignored_mod_count; /**< Number of ignored modules. */ - NC_WD_MODE wd_basic_mode; /**< With-defaults basic mode of the server. */ - int wd_also_supported; /**< Bitmap of with-defaults modes that are also supported by the server. */ - char **capabilities; /**< Array of server's capabilities. */ - uint32_t capabilities_count; /**< Number of server's capabilities. */ - - char *(*content_id_clb)(void *user_data); /**< Callback for generating content_id for ietf-yang-library data. */ - void *content_id_data; /**< Data passed to the content_id_clb callback. */ - void (*content_id_data_free)(void *data); /**< Callback to free the content_id_data. */ - - /* ACCESS locked - options modified by YANG data/API - WRITE lock - * - options read when accepting sessions - READ lock */ - pthread_rwlock_t config_lock; - - uint16_t idle_timeout; /**< Idle timeout of the server sessions. */ - -#ifdef NC_ENABLED_SSH_TLS - char *authkey_path_fmt; /**< Path to users' public keys that may contain tokens with special meaning. */ - char *pam_config_name; /**< PAM configuration file name. */ - 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); - - int (*user_verify_clb)(const struct nc_session *session); - - struct nc_keystore keystore; /**< Stored asymmetric and symmetric keys used by the server. */ - struct nc_truststore truststore; /**< Stored certificates and public keys used for authentication. */ -#endif /* NC_ENABLED_SSH_TLS */ + char **ignored_modules; /**< Names of YANG modules that are not reported in the server message (sized-array, see libyang docs). */ struct nc_endpt { - char *name; /**< Identifier of the endpoint. */ -#ifdef NC_ENABLED_SSH_TLS - char *referenced_endpt_name; /**< Reference to another endpoint (used for client authentication). */ -#endif /* NC_ENABLED_SSH_TLS */ + char *name; /**< Identifier of the endpoint. */ + + /* ACCESS locked - bind_lock */ + struct nc_bind *binds; /**< Listening binds of the endpoint (sized-array, see libyang docs). */ + pthread_mutex_t bind_lock; /**< To avoid concurrent calls of poll and accept on the bound sockets. **/ - struct nc_keepalives ka; /**< Keepalives configuration data. */ + struct nc_keepalives ka; /**< TCP keepalives configuration. */ - NC_TRANSPORT_IMPL ti; /**< Transport implementation of the endpoint. */ + NC_TRANSPORT_IMPL ti; /**< Transport implementation of the endpoint. */ union { #ifdef NC_ENABLED_SSH_TLS - struct nc_server_ssh_opts *ssh; /**< SSH transport options. */ - struct nc_server_tls_opts *tls; /**< TLS transport options. */ + struct nc_server_ssh_opts *ssh; /**< SSH transport options. */ + struct nc_server_tls_opts *tls; /**< TLS transport options. */ #endif /* NC_ENABLED_SSH_TLS */ - struct nc_server_unix_opts *unix; /**< UNIX socket transport options. */ + struct nc_server_unix_opts *unix; /**< UNIX socket transport options. */ } opts; - } *endpts; /**< Array of server's endpoints. */ - uint16_t endpt_count; /**< Number of server's endpoints. */ + } *endpts; /**< Listening endpoints (sized-array, see libyang docs). */ struct nc_ch_client { - char *name; /**< Identifier of the Call Home client. */ - struct nc_ch_client_thread_arg *thread_data; /**< Data of the Call Home client's thread */ + char *name; /**< Identifier of the Call Home client. */ struct nc_ch_endpt { char *name; /**< Identifier of the Call Home endpoint. */ -#ifdef NC_ENABLED_SSH_TLS - char *referenced_endpt_name; /**< Reference to another endpoint (used for client authentication). */ -#endif /* NC_ENABLED_SSH_TLS */ char *src_addr; /**< IP address to bind to when connecting to a Call Home client. */ uint16_t src_port; /**< Port to bind to when connecting to a Call Home client. */ @@ -682,28 +653,73 @@ struct nc_server_opts { struct nc_server_tls_opts *tls; /**< TLS transport options for the Call Home endpoint. */ #endif /* NC_ENABLED_SSH_TLS */ } opts; - } *ch_endpts; /**< Array of Call Home endpoints. */ - uint16_t ch_endpt_count; /**< Number of Call Home endpoints. */ + } *ch_endpts; /**< Call Home endpoints (sized-array, see libyang docs). */ - NC_CH_CONN_TYPE conn_type; /**< Type of the Call Home connection. */ + NC_CH_CONN_TYPE conn_type; /**< Type of the Call Home connection. */ struct { - uint16_t period; /**< Period of a periodic Call Home connection in seconds. */ - time_t anchor_time; /**< Anchor time of a periodic Call Home connection. */ - uint16_t idle_timeout; /**< Idle timeout of a periodic Call Home connection in seconds. */ + uint16_t period; /**< Period of a periodic Call Home connection in seconds. */ + time_t anchor_time; /**< Anchor time of a periodic Call Home connection. */ + uint16_t idle_timeout; /**< Idle timeout of a periodic Call Home connection in seconds. */ }; - NC_CH_START_WITH start_with; /**< How to select the Call Home endpoint to connect to. */ - uint8_t max_attempts; /**< Maximum number of attempts to connect to the given Call Home endpoint. */ - uint16_t max_wait; /**< Maximum time to wait for a Call Home connection in seconds. */ - uint32_t id; - } *ch_clients; /**< Array of Call Home clients. */ - uint16_t ch_client_count; /**< Number of Call Home clients. */ + NC_CH_START_WITH start_with; /**< How to select the Call Home endpoint to connect to. */ + uint8_t max_attempts; /**< Maximum number of attempts to connect to the given Call Home endpoint. */ + uint16_t max_wait; /**< Maximum time to wait for a Call Home connection in seconds. */ + } *ch_clients; /**< Call Home clients (sized-array, see libyang docs). */ + +#ifdef NC_ENABLED_SSH_TLS + struct nc_keystore keystore; /**< Asymmetric and symmetric key storage used for server identity. */ + struct nc_truststore truststore; /**< Public keys and certificates storage used for client authentication. */ + + /** + * @brief Time intervals for certificate expiration notifications. + * + * See libnetconf2-netconf-server YANG module for more details. + */ + struct nc_cert_exp_time_interval { + struct nc_cert_exp_time anchor; /**< Lower bound of the given interval. */ + struct nc_cert_exp_time period; /**< Period of the given interval. */ + } *cert_exp_notif_intervals; /**< Certificate expiration notification intervals (sized-array, see libyang docs). */ +#endif /* NC_ENABLED_SSH_TLS */ +}; + +struct nc_server_opts { + /* ACCESS locked - hello lock - separate lock to not always hold config_lock */ + pthread_rwlock_t hello_lock; /**< Needs to be held while the server message is being generated. */ + + NC_WD_MODE wd_basic_mode; /**< With-defaults basic mode of the server. */ + int wd_also_supported; /**< Bitmap of with-defaults modes that are also supported by the server. */ + char **capabilities; /**< Array of server's capabilities. */ + uint32_t capabilities_count; /**< Number of server's capabilities. */ + + char *(*content_id_clb)(void *user_data); /**< Callback for generating content_id for ietf-yang-library data. */ + void *content_id_data; /**< Data passed to the content_id_clb callback. */ + void (*content_id_data_free)(void *data); /**< Callback to free the content_id_data. */ + + /* ACCESS locked - call home thread creation/deletion - WRITE lock + * - call home threads data access (e.g. to signal thread to end) - READ lock */ + pthread_rwlock_t ch_threads_lock; /**< Lock for data of Call Home threads. */ + struct nc_server_ch_thread_arg **ch_threads; /**< Call Home threads' data, one for each CH client (sized-array, see libyang docs). */ + + /* ACCESS locked - options modified by YANG data/API - WRITE lock + * - options read when accepting sessions - READ lock */ + pthread_rwlock_t config_lock; /**< Lock for the server configuration. */ + struct nc_server_config config; /**< YANG Server configuration. */ + int applying_config; /**< Flag indicating that the server configuration is currently being applied. */ #ifdef NC_ENABLED_SSH_TLS + char *authkey_path_fmt; /**< Path to users' public keys that may contain tokens with special meaning. */ + char *pam_config_name; /**< PAM configuration file name. */ + 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); + + int (*user_verify_clb)(const struct nc_session *session); + /** - * @brief Data for dispatching Call Home clients. + * @brief Data for automatically dispatching Call Home clients. */ - struct nc_ch_dispatch_data { + struct { nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb; /**< Acquiring libyang context callback. */ nc_server_ch_session_release_ctx_cb release_ctx_cb; /**< Releasing libyang context callback. */ void *ctx_cb_data; /**< Data passed to the callbacks above. */ @@ -716,22 +732,9 @@ struct nc_server_opts { int thread_running; /**< Flag representing the runningness of the cert exp notification thread. */ pthread_mutex_t lock; /**< Certificate expiration notification thread's data and cond lock. */ pthread_cond_t cond; /**< Condition for the certificate expiration notification thread. */ - - /** - * @brief Intervals for certificate expiration notifications. - */ - struct nc_interval { - struct nc_cert_exp_time anchor; /**< Lower bound of the given interval. */ - struct nc_cert_exp_time period; /**< Period of the given interval. */ - } *intervals; - int interval_count; /**< Number of intervals. */ } cert_exp_notif; #endif /* NC_ENABLED_SSH_TLS */ - /* ACCESS locked - bind_lock */ - struct nc_bind *binds; /**< Array of server's socket binds. The count is the same as endpt_count. */ - pthread_mutex_t bind_lock; /**< To avoid concurrent calls of poll and accept on the bound sockets. **/ - /* ACCESS unlocked */ ATOMIC_T new_session_id; @@ -951,15 +954,13 @@ void nc_client_monitoring_session_stop(struct nc_session *session, int lock); void *nc_realloc(void *ptr, size_t size); /** - * @brief Set the andress and port of an endpoint. + * @brief Bind and listen on a socket for the given endpoint and its bind. * - * @param[in] endpt Endpoint to set the address/port for. - * @param[in] bind Bind to set the address/port for. - * @param[in] address Address to set, can be a path to a UNIX socket. - * @param[in] port Port to set, invalid for UNIX socket endpoint. + * @param[in] endpt Endpoint the bind belongs to. + * @param[in] bind Bind to bind and listen for. * @return 0 on success, 1 on error. */ -int nc_server_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port); +int nc_server_bind_and_listen(struct nc_endpt *endpt, struct nc_bind *bind); /** * @brief Frees memory allocated by a UNIX socket endpoint. @@ -969,6 +970,13 @@ int nc_server_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, con */ void _nc_server_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind); +/** + * @brief Free server configuration data (only YANG config data). + * + * @param[in] config Server configuration to free. + */ +void nc_server_config_free(struct nc_server_config *config); + /** * @brief Get passwd entry for UID or a user. * @@ -1199,13 +1207,13 @@ int nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, pthread_mut int nc_connect_unix_session(struct nc_session *session, int sock, const char *username, int timeout_ms); /** - * @brief Gets an endpoint structure based on its name. + * @brief Gets a listening endpoint 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); +int nc_server_endpt_get(const char *name, struct nc_endpt **endpt); /** * @brief Add a client Call Home bind, listen on it. @@ -1245,18 +1253,19 @@ NC_MSG_TYPE nc_connect_callhome(const char *host, uint16_t port, NC_TRANSPORT_IM /** * @brief Dispatch a thread connecting to a listening NETCONF client and creating Call Home sessions. * - * @param[in] client_name Existing client name. + * @note The config lock MUST be held. + * + * @param[in] ch_client Call Home client to dispatch the thread for. * @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. - * @param[in] config_locked Whether the server configuration is locked. * @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, +int _nc_connect_ch_client_dispatch(const struct nc_ch_client *ch_client, 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, int config_locked); + void *new_session_cb_data); /** * @brief Accept a server Call Home connection on a socket. diff --git a/src/session_server.c b/src/session_server.c index 7df3b642..cff7c07b 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -38,7 +38,6 @@ #include "messages_p.h" #include "messages_server.h" #include "server_config.h" -#include "server_config_p.h" #include "session.h" #include "session_p.h" #include "session_server.h" @@ -55,8 +54,7 @@ struct nc_server_opts server_opts = { .hello_lock = PTHREAD_RWLOCK_INITIALIZER, - .config_lock = PTHREAD_RWLOCK_INITIALIZER, - .idle_timeout = 180, /**< default idle timeout (not in config for UNIX socket) */ + .config_lock = PTHREAD_RWLOCK_INITIALIZER }; static nc_rpc_clb global_rpc_clb = NULL; @@ -74,36 +72,36 @@ static nc_rpc_clb global_rpc_clb = NULL; static struct nc_ch_client * nc_server_ch_client_get(const char *name) { - uint16_t i; struct nc_ch_client *client = NULL; assert(name); - for (i = 0; i < server_opts.ch_client_count; ++i) { - if (server_opts.ch_clients[i].name && !strcmp(server_opts.ch_clients[i].name, name)) { - client = &server_opts.ch_clients[i]; - break; + LY_ARRAY_FOR(server_opts.config.ch_clients, struct nc_ch_client, client) { + if (client->name && !strcmp(client->name, name)) { + return client; } } - return client; + return NULL; } #endif /* NC_ENABLED_SSH_TLS */ int -nc_server_get_referenced_endpt(const char *name, struct nc_endpt **endpt) +nc_server_endpt_get(const char *name, struct nc_endpt **endpt) { - uint16_t i; + struct nc_endpt *ep; - for (i = 0; i < server_opts.endpt_count; i++) { - if (!strcmp(name, server_opts.endpts[i].name)) { - *endpt = &server_opts.endpts[i]; + *endpt = NULL; + + LY_ARRAY_FOR(server_opts.config.endpts, struct nc_endpt, ep) { + if (ep->name && !strcmp(ep->name, name)) { + *endpt = ep; return 0; } } - ERR(NULL, "Referenced endpoint \"%s\" was not found.", name); + ERR(NULL, "Endpoint \"%s\" not found in the configuration.", name); return 1; } @@ -363,20 +361,21 @@ nc_sock_listen_inet(const char *address, uint16_t port) /** * @brief Create a listening socket (AF_UNIX). * - * @param[in] opts The server options (unix permissions and address of the socket). + * @param[in] address Path to the UNIX socket. + * @param[in] opts The server options (unix permissions). * @return Listening socket, -1 on error. */ static int -nc_sock_listen_unix(const struct nc_server_unix_opts *opts) +nc_sock_listen_unix(const char *address, const struct nc_server_unix_opts *opts) { struct sockaddr_un sun; int sock = -1; - if (!opts->path) { + if (!address) { ERR(NULL, "No socket path set."); goto fail; - } else if (strlen(opts->path) > sizeof(sun.sun_path) - 1) { - ERR(NULL, "Socket path \"%s\" is longer than maximum length %d.", opts->path, (int)(sizeof(sun.sun_path) - 1)); + } else 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)); goto fail; } @@ -388,11 +387,11 @@ nc_sock_listen_unix(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", opts->path); + snprintf(sun.sun_path, sizeof(sun.sun_path) - 1, "%s", address); unlink(sun.sun_path); if (bind(sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) { - ERR(NULL, "Could not bind \"%s\" (%s).", opts->path, strerror(errno)); + ERR(NULL, "Could not bind \"%s\" (%s).", address, strerror(errno)); goto fail; } @@ -411,7 +410,7 @@ nc_sock_listen_unix(const struct nc_server_unix_opts *opts) } if (listen(sock, NC_REVERSE_QUEUE) == -1) { - ERR(NULL, "Unable to start listening on \"%s\" (%s).", opts->path, strerror(errno)); + ERR(NULL, "Unable to start listening on \"%s\" (%s).", address, strerror(errno)); goto fail; } @@ -863,7 +862,9 @@ nc_server_init_rwlock(pthread_rwlock_t *rwlock) API int nc_server_init(void) { +#ifdef NC_ENABLED_SSH_TLS int r; +#endif /* NC_ENABLED_SSH_TLS */ ATOMIC_STORE_RELAXED(server_opts.new_session_id, 1); @@ -887,14 +888,12 @@ nc_server_init(void) ERR(NULL, "%s: failed to init libssh.", __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)); + /* CH threads data rwlock */ + if (nc_server_init_rwlock(&server_opts.ch_threads_lock)) { goto error; } -#ifdef NC_ENABLED_SSH_TLS if ((r = pthread_mutex_init(&server_opts.cert_exp_notif.lock, NULL))) { ERR(NULL, "%s: failed to init certificate expiration notification thread lock(%s).", __func__, strerror(r)); goto error; @@ -906,7 +905,7 @@ nc_server_init(void) /* try to open the keylog file for writing TLS secrets */ nc_server_keylog_file_open(); -#endif +#endif /* NC_ENABLED_SSH_TLS */ return 0; @@ -932,13 +931,30 @@ nc_server_destroy(void) #ifdef NC_ENABLED_SSH_TLS /* destroy the certificate expiration notification thread */ nc_server_notif_cert_expiration_thread_stop(1); - nc_server_config_ln2_netconf_server(NULL, NC_OP_DELETE); #endif /* NC_ENABLED_SSH_TLS */ - nc_server_config_listen(NULL, NC_OP_DELETE); - nc_server_config_ch(NULL, NC_OP_DELETE); + /* CONFIG WR LOCK */ + pthread_rwlock_wrlock(&server_opts.config_lock); + + /* destroy the server configuration */ + nc_server_config_free(&server_opts.config); + + /* CH THREADS LOCK */ + pthread_rwlock_rdlock(&server_opts.ch_threads_lock); - pthread_mutex_destroy(&server_opts.bind_lock); + /* notify the CH threads to exit */ + LY_ARRAY_FOR(server_opts.ch_threads, i) { + pthread_mutex_lock(&server_opts.ch_threads[i]->cond_lock); + server_opts.ch_threads[i]->thread_running = 0; + pthread_cond_signal(&server_opts.ch_threads[i]->cond); + pthread_mutex_unlock(&server_opts.ch_threads[i]->cond_lock); + } + + /* CH THREADS UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_threads_lock); + + /* CONFIG WR UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); #ifdef NC_ENABLED_SSH_TLS free(server_opts.authkey_path_fmt); @@ -951,8 +967,6 @@ nc_server_destroy(void) server_opts.interactive_auth_data = NULL; server_opts.interactive_auth_data_free = NULL; - nc_server_config_ks_keystore(NULL, NC_OP_DELETE); - nc_server_config_ts_truststore(NULL, NC_OP_DELETE); curl_global_cleanup(); nc_tls_backend_destroy_wrap(); ssh_finalize(); @@ -1871,6 +1885,7 @@ nc_ps_poll_session_io(struct nc_session *session, int io_timeout, time_t now_mon { struct pollfd pfd; int r, ret = 0; + uint16_t idle_timeout; #ifdef NC_ENABLED_SSH_TLS ssh_message ssh_msg; @@ -1878,8 +1893,9 @@ nc_ps_poll_session_io(struct nc_session *session, int io_timeout, time_t now_mon #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 + (unsigned) server_opts.idle_timeout)) { + idle_timeout = server_opts.config.idle_timeout; + if (!(session->flags & NC_SESSION_CALLHOME) && !nc_session_get_notif_status(session) && idle_timeout && + (now_mono >= session->opts.server.last_rpc + idle_timeout)) { sprintf(msg, "Session idle timeout elapsed"); session->status = NC_STATUS_INVALID; session->term_reason = NC_SESSION_TERM_TIMEOUT; @@ -2279,54 +2295,48 @@ nc_ps_clear(struct nc_pollsession *ps, int all, void (*data_free)(void *)) } int -nc_server_set_address_port(struct nc_endpt *endpt, struct nc_bind *bind, const char *address, uint16_t port) +nc_server_bind_and_listen(struct nc_endpt *endpt, struct nc_bind *bind) { - int sock = -1, ret = 0; - - assert(address && (port || (endpt->ti == NC_TI_UNIX))); + int sock = -1, rc = 0; - /* 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(endpt->opts.unix); - } else { - sock = nc_sock_listen_inet(address, port); - } - - if (sock == -1) { - ret = 1; - goto cleanup; - } + /* start listening on the endpoint */ + if (endpt->ti == NC_TI_UNIX) { + sock = nc_sock_listen_unix(bind->address, endpt->opts.unix); + } else { + assert(bind->address && bind->port); + sock = nc_sock_listen_inet(bind->address, bind->port); + } + if (sock == -1) { + rc = 1; + goto cleanup; + } - if (bind->sock > -1) { - close(bind->sock); - } - bind->sock = sock; + /* close the old socket if any and store the new one */ + if (bind->sock > -1) { + close(bind->sock); } + bind->sock = sock; - if (sock > -1) { - switch (endpt->ti) { - case NC_TI_UNIX: - VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unix->path); - break; + switch (endpt->ti) { + case NC_TI_UNIX: + VRB(NULL, "Listening on %s for UNIX connections.", bind->address); + break; #ifdef NC_ENABLED_SSH_TLS - case NC_TI_SSH: - VRB(NULL, "Listening on %s:%u for SSH connections.", address, port); - break; - case NC_TI_TLS: - VRB(NULL, "Listening on %s:%u for TLS connections.", address, port); - break; + case NC_TI_SSH: + VRB(NULL, "Listening on %s:%u for SSH connections.", bind->address, bind->port); + break; + case NC_TI_TLS: + VRB(NULL, "Listening on %s:%u for TLS connections.", bind->address, bind->port); + break; #endif /* NC_ENABLED_SSH_TLS */ - default: - ERRINT; - ret = 1; - break; - } + default: + ERRINT; + rc = 1; + break; } cleanup: - return ret; + return rc; } /** @@ -2411,15 +2421,15 @@ nc_accept_unix_auth_username(struct nc_session *session, const char *effective_u { int match = 0; struct nc_server_unix_opts *opts = session->data; - uint32_t i, j; + LY_ARRAY_COUNT_TYPE i, j; /* try to find a mapping entry for this system user */ - for (i = 0; i < opts->mapping_count; i++) { + LY_ARRAY_FOR(opts->user_mappings, i) { if (!strcmp(opts->user_mappings[i].system_user, effective_uname)) { break; } } - if (i == opts->mapping_count) { + if (i == LY_ARRAY_COUNT(opts->user_mappings)) { /* matching entry not found, the user can only authenticate if its * requested username is the same as the effective one */ if (strcmp(effective_uname, requested_uname)) { @@ -2428,7 +2438,7 @@ nc_accept_unix_auth_username(struct nc_session *session, const char *effective_u } } else { /* found a mapping entry, check if the requested username is allowed for this system user */ - for (j = 0; j < opts->user_mappings[i].allowed_user_count; j++) { + LY_ARRAY_FOR(opts->user_mappings[i].allowed_users, j) { if (!strcmp(opts->user_mappings[i].allowed_users[j], "*")) { /* special case, the user can authenticate as any username */ match = 1; @@ -2514,10 +2524,20 @@ nc_accept_unix_session(struct nc_session *session, int sock) return -1; } -API int +API uint32_t nc_server_endpt_count(void) { - return server_opts.endpt_count; + uint32_t cnt; + + /* CONFIG READ LOCK */ + pthread_rwlock_rdlock(&server_opts.config_lock); + + cnt = LY_ARRAY_COUNT(server_opts.config.endpts); + + /* CONFIG UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); + + return cnt; } API NC_MSG_TYPE @@ -2526,8 +2546,10 @@ nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session) NC_MSG_TYPE msgtype; int sock = -1, ret; char *host = NULL; - uint16_t port, bind_idx; + uint16_t port = 0; struct timespec ts_cur; + LY_ARRAY_COUNT_TYPE endpt_idx; + struct nc_server_config *config; NC_CHECK_ARG_RET(NULL, ctx, session, NC_MSG_ERROR); @@ -2541,21 +2563,34 @@ nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session) /* CONFIG LOCK */ pthread_rwlock_rdlock(&server_opts.config_lock); - if (!server_opts.endpt_count) { + config = &server_opts.config; + + if (!config->endpts) { ERR(NULL, "No endpoints to accept sessions on."); msgtype = NC_MSG_ERROR; goto cleanup; } - ret = nc_sock_accept_binds(server_opts.binds, server_opts.endpt_count, &server_opts.bind_lock, timeout, &host, - &port, &bind_idx, &sock); - if (ret < 1) { - msgtype = (!ret ? NC_MSG_WOULDBLOCK : NC_MSG_ERROR); + /* try to accept a new connection on any of the endpoints */ + LY_ARRAY_FOR(config->endpts, endpt_idx) { + ret = nc_sock_accept_binds(config->endpts[endpt_idx].binds, LY_ARRAY_COUNT(config->endpts[endpt_idx].binds), + &config->endpts[endpt_idx].bind_lock, timeout, &host, &port, NULL, &sock); + if (ret < 0) { + msgtype = NC_MSG_ERROR; + goto cleanup; + } else if (ret > 0) { + /* accepted */ + break; + } + } + if (sock == -1) { + /* timeout, no connection established */ + msgtype = NC_MSG_WOULDBLOCK; goto cleanup; } /* configure keepalives */ - if (nc_sock_configure_ka(sock, &server_opts.endpts[bind_idx].ka)) { + if (nc_sock_configure_ka(sock, &config->endpts[endpt_idx].ka)) { msgtype = NC_MSG_ERROR; goto cleanup; } @@ -2571,8 +2606,8 @@ nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session) /* sock gets assigned to session or closed */ #ifdef NC_ENABLED_SSH_TLS - if (server_opts.endpts[bind_idx].ti == NC_TI_SSH) { - ret = nc_accept_ssh_session(*session, server_opts.endpts[bind_idx].opts.ssh, sock, NC_TRANSPORT_TIMEOUT); + if (config->endpts[endpt_idx].ti == NC_TI_SSH) { + ret = nc_accept_ssh_session(*session, config->endpts[endpt_idx].opts.ssh, sock, NC_TRANSPORT_TIMEOUT); sock = -1; if (ret < 0) { msgtype = NC_MSG_ERROR; @@ -2581,9 +2616,9 @@ nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session) msgtype = NC_MSG_WOULDBLOCK; goto cleanup; } - } else if (server_opts.endpts[bind_idx].ti == NC_TI_TLS) { - (*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); + } else if (config->endpts[endpt_idx].ti == NC_TI_TLS) { + (*session)->data = config->endpts[endpt_idx].opts.tls; + ret = nc_accept_tls_session(*session, config->endpts[endpt_idx].opts.tls, sock, NC_TRANSPORT_TIMEOUT); sock = -1; if (ret < 0) { msgtype = NC_MSG_ERROR; @@ -2594,8 +2629,8 @@ nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session) } } else #endif /* NC_ENABLED_SSH_TLS */ - if (server_opts.endpts[bind_idx].ti == NC_TI_UNIX) { - (*session)->data = server_opts.endpts[bind_idx].opts.unix; + if (config->endpts[endpt_idx].ti == NC_TI_UNIX) { + (*session)->data = config->endpts[endpt_idx].opts.unix; ret = nc_accept_unix_session(*session, sock); sock = -1; if (ret < 0) { @@ -2650,7 +2685,7 @@ nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session) API int nc_server_ch_is_client(const char *name) { - uint16_t i; + struct nc_ch_client *client; int found = 0; if (!name) { @@ -2660,9 +2695,9 @@ nc_server_ch_is_client(const char *name) /* CONFIG READ LOCK */ pthread_rwlock_rdlock(&server_opts.config_lock); - /* check name uniqueness */ - for (i = 0; i < server_opts.ch_client_count; ++i) { - if (!strcmp(server_opts.ch_clients[i].name, name)) { + /* check name against all configured clients */ + LY_ARRAY_FOR(server_opts.config.ch_clients, struct nc_ch_client, client) { + if (!strcmp(client->name, name)) { found = 1; break; } @@ -2677,8 +2712,8 @@ nc_server_ch_is_client(const char *name) 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; + struct nc_ch_endpt *endpt = NULL; int found = 0; if (!client_name || !endpt_name) { @@ -2688,21 +2723,15 @@ nc_server_ch_client_is_endpt(const char *client_name, const char *endpt_name) /* CONFIG READ LOCK */ pthread_rwlock_rdlock(&server_opts.config_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; - } - } - + client = nc_server_ch_client_get(client_name); if (!client) { goto cleanup; } - for (i = 0; i < client->ch_endpt_count; ++i) { - if (!strcmp(client->ch_endpts[i].name, endpt_name)) { + LY_ARRAY_FOR(client->ch_endpts, struct nc_ch_endpt, endpt) { + if (!strcmp(endpt->name, endpt_name)) { found = 1; - break; + goto cleanup; } } @@ -2862,7 +2891,7 @@ nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_tim * @return -1 on error. */ static int -nc_server_ch_client_thread_session_cond_wait(struct nc_ch_client_thread_arg *data, struct nc_session *session) +nc_server_ch_client_thread_session_cond_wait(struct nc_server_ch_thread_arg *data, struct nc_session *session) { int rc = 0, r; uint32_t idle_timeout; @@ -2956,7 +2985,7 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_ch_client_thread_arg *dat * @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) +nc_server_ch_client_thread_is_running_wait(struct nc_session *session, struct nc_server_ch_thread_arg *data, uint64_t cond_wait_time) { struct timespec ts; int ret = 0, thread_running; @@ -3000,7 +3029,7 @@ nc_server_ch_client_thread_is_running_wait(struct nc_session *session, struct nc * @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) +nc_server_ch_client_thread_is_running(struct nc_server_ch_thread_arg *data) { int ret = -1; @@ -3026,7 +3055,7 @@ nc_server_ch_client_thread_is_running(struct nc_ch_client_thread_arg *data) * @return Pointer to the CH client, NULL if the client was removed. */ static struct nc_ch_client * -nc_server_ch_client_with_endpt_get(struct nc_ch_client_thread_arg *data, const char *name) +nc_server_ch_client_with_endpt_get(struct nc_server_ch_thread_arg *data, const char *name) { struct nc_ch_client *client; @@ -3038,7 +3067,7 @@ nc_server_ch_client_with_endpt_get(struct nc_ch_client_thread_arg *data, const c } /* check if it has at least one endpoint defined */ - if (client->ch_endpt_count) { + if (client->ch_endpts) { return client; } @@ -3065,7 +3094,7 @@ nc_server_ch_client_with_endpt_get(struct nc_ch_client_thread_arg *data, const c static void * nc_ch_client_thread(void *arg) { - struct nc_ch_client_thread_arg *data = arg; + struct nc_server_ch_thread_arg *data = arg; NC_MSG_TYPE msgtype; uint8_t cur_attempts = 0; uint16_t next_endpt_index, max_wait; @@ -3074,6 +3103,12 @@ nc_ch_client_thread(void *arg) struct nc_session *session = NULL; struct nc_ch_client *client; uint32_t reconnect_in; + LY_ARRAY_COUNT_TYPE i; + + /* mark the thread as running */ + pthread_mutex_lock(&data->cond_lock); + data->thread_running = 1; + pthread_mutex_unlock(&data->cond_lock); /* CONFIG READ LOCK */ pthread_rwlock_rdlock(&server_opts.config_lock); @@ -3163,20 +3198,19 @@ nc_ch_client_thread(void *arg) next_endpt_index = 0; } else if (client->start_with == NC_CH_LAST_CONNECTED) { /* we keep the current one but due to unlock/lock we have to find it again */ - for (next_endpt_index = 0; next_endpt_index < client->ch_endpt_count; ++next_endpt_index) { + LY_ARRAY_FOR(client->ch_endpts, next_endpt_index) { if (!strcmp(client->ch_endpts[next_endpt_index].name, cur_endpt_name)) { break; } } - if (next_endpt_index >= client->ch_endpt_count) { + if (next_endpt_index >= LY_ARRAY_COUNT(client->ch_endpts)) { /* endpoint was removed, start with the first one */ next_endpt_index = 0; } } else { /* just get a random index */ - next_endpt_index = rand() % client->ch_endpt_count; + next_endpt_index = rand() % LY_ARRAY_COUNT(client->ch_endpts); } - } else { /* session was not created, wait a little bit and try again */ max_wait = client->max_wait; @@ -3203,13 +3237,13 @@ nc_ch_client_thread(void *arg) ++cur_attempts; /* try to find our endpoint again */ - for (next_endpt_index = 0; next_endpt_index < client->ch_endpt_count; ++next_endpt_index) { + LY_ARRAY_FOR(client->ch_endpts, next_endpt_index) { if (!strcmp(client->ch_endpts[next_endpt_index].name, cur_endpt_name)) { break; } } - if (next_endpt_index >= client->ch_endpt_count) { + if (next_endpt_index >= LY_ARRAY_COUNT(client->ch_endpts)) { /* endpoint was removed, start with the first one */ VRB(session, "Call Home client \"%s\" endpoint \"%s\" removed.", data->client_name, cur_endpt_name); next_endpt_index = 0; @@ -3226,7 +3260,7 @@ nc_ch_client_thread(void *arg) cur_endpt->sock_pending = -1; } - if (next_endpt_index < client->ch_endpt_count - 1) { + if (next_endpt_index < LY_ARRAY_COUNT(client->ch_endpts) - 1) { /* just go to the next endpoint */ ++next_endpt_index; } else { @@ -3249,6 +3283,24 @@ nc_ch_client_thread(void *arg) cleanup: VRB(session, "Call Home client \"%s\" thread exit.", data->client_name); free(cur_endpt_name); + + /* CH THREADS WR LOCK */ + pthread_rwlock_wrlock(&server_opts.ch_threads_lock); + + /* remove the thread data from the global array */ + LY_ARRAY_FOR(server_opts.ch_threads, i) { + if (server_opts.ch_threads[i] == data) { + break; + } + } + if (i < LY_ARRAY_COUNT(server_opts.ch_threads) - 1) { + server_opts.ch_threads[i] = server_opts.ch_threads[LY_ARRAY_COUNT(server_opts.ch_threads) - 1]; + } + LY_ARRAY_DECREMENT_FREE(server_opts.ch_threads); + + /* CH THREADS UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_threads_lock); + free(data->client_name); pthread_mutex_lock(&data->cond_lock); pthread_cond_destroy(&data->cond); @@ -3259,14 +3311,13 @@ nc_ch_client_thread(void *arg) } int -_nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb, +_nc_connect_ch_client_dispatch(const struct nc_ch_client *ch_client, 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, int config_locked) + void *new_session_cb_data) { - int rc = 0, r; + int rc = 0, r, ch_threads_locked = 0; pthread_t tid; - struct nc_ch_client_thread_arg *arg = NULL; - struct nc_ch_client *ch_client; + struct nc_server_ch_thread_arg *arg = NULL, **new_item; pthread_attr_t attr; /* init pthread attribute */ @@ -3282,29 +3333,10 @@ _nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_acq goto cleanup; } - if (!config_locked) { - /* CONFIG READ LOCK */ - pthread_rwlock_rdlock(&server_opts.config_lock); - } - - /* check ch client existence */ - ch_client = nc_server_ch_client_get(client_name); - - if (!config_locked) { - /* CONFIG READ UNLOCK */ - pthread_rwlock_unlock(&server_opts.config_lock); - } - - if (!ch_client) { - ERR(NULL, "Client \"%s\" not found.", client_name); - rc = -1; - goto cleanup; - } - /* create the thread argument */ arg = calloc(1, sizeof *arg); NC_CHECK_ERRMEM_GOTO(!arg, rc = -1, cleanup); - arg->client_name = strdup(client_name); + arg->client_name = strdup(ch_client->name); NC_CHECK_ERRMEM_GOTO(!arg->client_name, rc = -1, cleanup); arg->acquire_ctx_cb = acquire_ctx_cb; arg->release_ctx_cb = release_ctx_cb; @@ -3314,19 +3346,35 @@ _nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_acq pthread_cond_init(&arg->cond, NULL); pthread_mutex_init(&arg->cond_lock, NULL); - /* creating the thread */ - arg->thread_running = 1; + /* CH THREADS WR LOCK */ + pthread_rwlock_wrlock(&server_opts.ch_threads_lock); + ch_threads_locked = 1; + + /* Append the thread data pointer to the global array. + * Pointer instead of struct so that server_opts.ch_thread_lock does not have to be + * locked everytime the arg is accessed */ + LY_ARRAY_NEW_GOTO(NULL, server_opts.ch_threads, new_item, rc, cleanup); + *new_item = arg; + + /* CH THREADS UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_threads_lock); + ch_threads_locked = 0; + + /* create the CH thread */ if ((r = pthread_create(&tid, &attr, nc_ch_client_thread, arg))) { ERR(NULL, "Creating a new thread failed (%s).", strerror(r)); rc = -1; goto cleanup; } - /* the thread now manages arg */ - ch_client->thread_data = arg; + /* arg is now owned by the thread */ arg = NULL; cleanup: + if (ch_threads_locked) { + /* CH THREADS UNLOCK */ + pthread_rwlock_unlock(&server_opts.ch_threads_lock); + } pthread_attr_destroy(&attr); if (arg) { free(arg->client_name); @@ -3340,12 +3388,27 @@ nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_acqu 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 rc = 0; + struct nc_ch_client *ch_client; + NC_CHECK_ARG_RET(NULL, client_name, acquire_ctx_cb, release_ctx_cb, new_session_cb, -1); NC_CHECK_SRV_INIT_RET(-1); - return _nc_connect_ch_client_dispatch(client_name, acquire_ctx_cb, release_ctx_cb, ctx_cb_data, - new_session_cb, new_session_cb_data, 0); + /* CONFIG READ LOCK */ + pthread_rwlock_rdlock(&server_opts.config_lock); + + /* check ch client existence */ + ch_client = nc_server_ch_client_get(client_name); + NC_CHECK_ERR_GOTO(!ch_client, rc = -1; ERR(NULL, "Call Home client \"%s\" not found.", client_name), cleanup); + + rc = _nc_connect_ch_client_dispatch(ch_client, acquire_ctx_cb, release_ctx_cb, ctx_cb_data, + new_session_cb, new_session_cb_data); + +cleanup: + /* CONFIG READ UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); + return rc; } #endif /* NC_ENABLED_SSH_TLS */ @@ -3543,7 +3606,8 @@ nc_server_notif_cert_exp_time_sub(time_t orig_time, struct nc_cert_exp_time *sub * @return Calendar time of the next notification or -1 on error. */ static time_t -nc_server_notif_cert_exp_next_notif_time_get(struct nc_interval *intervals, int interval_count, struct nc_cert_expiration *exp) +nc_server_notif_cert_exp_next_notif_time_get(struct nc_cert_exp_time_interval *intervals, int interval_count, + struct nc_cert_expiration *exp) { time_t new_notif_time, now; double diff; @@ -3589,7 +3653,8 @@ nc_server_notif_cert_exp_next_notif_time_get(struct nc_interval *intervals, int * @return 0 on success, 1 on error. */ static int -nc_server_notif_cert_exp_init_intervals(struct nc_interval *intervals, int interval_count, struct nc_cert_expiration *exp) +nc_server_notif_cert_exp_init_intervals(struct nc_cert_exp_time_interval *intervals, int interval_count, + struct nc_cert_expiration *exp) { int i; @@ -3616,7 +3681,8 @@ nc_server_notif_cert_exp_init_intervals(struct nc_interval *intervals, int inter * @return 0 on success. */ static int -nc_server_notif_cert_exp_first_notif_time_get(struct nc_interval *intervals, int interval_count, struct nc_cert_expiration *exp) +nc_server_notif_cert_exp_first_notif_time_get(struct nc_cert_exp_time_interval *intervals, int interval_count, + struct nc_cert_expiration *exp) { int i; time_t now, notif_time; @@ -3685,7 +3751,8 @@ nc_server_notif_cert_exp_first_notif_time_get(struct nc_interval *intervals, int */ static int nc_server_notif_cert_exp_date_append(const char *cert_data, struct nc_cert_path_aux *cp, - struct nc_interval *intervals, int interval_count, struct nc_cert_expiration **exp_dates, int *exp_date_count) + struct nc_cert_exp_time_interval *intervals, uint32_t interval_count, + struct nc_cert_expiration **exp_dates, uint32_t *exp_date_count) { int ret = 0; void *cert = NULL; @@ -3749,28 +3816,28 @@ nc_server_notif_cert_exp_date_append(const char *cert_data, struct nc_cert_path_ */ static int nc_server_notif_cert_exp_dates_endpt_get(const char *ch_client_name, const char *endpt_name, struct nc_server_tls_opts *opts, - struct nc_interval *intervals, int interval_count, struct nc_cert_expiration **exp_dates, int *exp_date_count) + struct nc_cert_exp_time_interval *intervals, uint32_t interval_count, + struct nc_cert_expiration **exp_dates, uint32_t *exp_date_count) { - int ret = 0, i; + int ret = 0; + LY_ARRAY_COUNT_TYPE i; struct nc_certificate *certs; - uint16_t ncerts; struct nc_cert_path_aux cp = {0}; /* append server cert first */ - if (opts->store == NC_STORE_LOCAL) { + if (opts->cert_store == NC_STORE_LOCAL) { NC_CERT_EXP_UPDATE_CERT_PATH(&cp, ch_client_name, endpt_name, NULL, NULL, NULL, NULL, NULL, NULL); - ret = nc_server_notif_cert_exp_date_append(opts->cert_data, &cp, intervals, interval_count, exp_dates, exp_date_count); + ret = nc_server_notif_cert_exp_date_append(opts->local.cert.data, &cp, intervals, interval_count, exp_dates, exp_date_count); if (ret) { goto cleanup; } } /* append CA certs */ - if (opts->ca_certs.store == NC_STORE_LOCAL) { - certs = opts->ca_certs.certs; - ncerts = opts->ca_certs.cert_count; + if (opts->client_auth.ca_certs_store == NC_STORE_LOCAL) { + certs = opts->client_auth.ca_certs; - for (i = 0; i < ncerts; i++) { + LY_ARRAY_FOR(certs, i) { NC_CERT_EXP_UPDATE_CERT_PATH(&cp, ch_client_name, endpt_name, certs[i].name, NULL, NULL, NULL, NULL, NULL); ret = nc_server_notif_cert_exp_date_append(certs[i].data, &cp, intervals, interval_count, exp_dates, exp_date_count); if (ret) { @@ -3780,11 +3847,10 @@ nc_server_notif_cert_exp_dates_endpt_get(const char *ch_client_name, const char } /* append end entity certs */ - if (opts->ee_certs.store == NC_STORE_LOCAL) { - certs = opts->ee_certs.certs; - ncerts = opts->ee_certs.cert_count; + if (opts->client_auth.ee_certs_store == NC_STORE_LOCAL) { + certs = opts->client_auth.ee_certs; - for (i = 0; i < ncerts; i++) { + LY_ARRAY_FOR(certs, i) { NC_CERT_EXP_UPDATE_CERT_PATH(&cp, ch_client_name, endpt_name, NULL, certs[i].name, NULL, NULL, NULL, NULL); ret = nc_server_notif_cert_exp_date_append(certs[i].data, &cp, intervals, interval_count, exp_dates, exp_date_count); if (ret) { @@ -3807,13 +3873,18 @@ nc_server_notif_cert_exp_dates_endpt_get(const char *ch_client_name, const char * @return 0 on success, 1 on error. */ static int -nc_server_notif_cert_exp_dates_get(struct nc_interval *intervals, int interval_count, struct nc_cert_expiration **exp_dates, int *exp_date_count) +nc_server_notif_cert_exp_dates_get(struct nc_cert_exp_time_interval *intervals, uint32_t interval_count, + struct nc_cert_expiration **exp_dates, uint32_t *exp_date_count) { int ret = 0; - uint16_t i, j; - struct nc_keystore *ks = &server_opts.keystore; - struct nc_truststore *ts = &server_opts.truststore; + struct nc_endpt *endpt; + struct nc_ch_client *ch_client; + struct nc_ch_endpt *ch_endpt; + struct nc_certificate *cert; + struct nc_keystore *ks = &server_opts.config.keystore; + struct nc_truststore *ts = &server_opts.config.truststore; struct nc_cert_path_aux cp = {0}; + LY_ARRAY_COUNT_TYPE i; NC_CHECK_ARG_RET(NULL, intervals, interval_count, exp_dates, exp_date_count, 1); @@ -3824,10 +3895,10 @@ nc_server_notif_cert_exp_dates_get(struct nc_interval *intervals, int interval_c pthread_rwlock_rdlock(&server_opts.config_lock); /* first go through listen certs */ - for (i = 0; i < server_opts.endpt_count; ++i) { - if (server_opts.endpts[i].ti == NC_TI_TLS) { - ret = nc_server_notif_cert_exp_dates_endpt_get(NULL, server_opts.endpts[i].name, - server_opts.endpts[i].opts.tls, intervals, interval_count, exp_dates, exp_date_count); + LY_ARRAY_FOR(server_opts.config.endpts, struct nc_endpt, endpt) { + if (endpt->ti == NC_TI_TLS) { + ret = nc_server_notif_cert_exp_dates_endpt_get(NULL, endpt->name, endpt->opts.tls, + intervals, interval_count, exp_dates, exp_date_count); if (ret) { goto cleanup; } @@ -3835,11 +3906,10 @@ nc_server_notif_cert_exp_dates_get(struct nc_interval *intervals, int interval_c } /* then go through all the ch clients and their endpts */ - for (i = 0; i < server_opts.ch_client_count; ++i) { - for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; ++j) { - if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_TLS) { - ret = nc_server_notif_cert_exp_dates_endpt_get(server_opts.ch_clients[i].name, - server_opts.ch_clients[i].ch_endpts[j].name, server_opts.ch_clients[i].ch_endpts[j].opts.tls, + LY_ARRAY_FOR(server_opts.config.ch_clients, struct nc_ch_client, ch_client) { + LY_ARRAY_FOR(ch_client->ch_endpts, struct nc_ch_endpt, ch_endpt) { + if (ch_endpt->ti == NC_TI_TLS) { + ret = nc_server_notif_cert_exp_dates_endpt_get(ch_client->name, ch_endpt->name, ch_endpt->opts.tls, intervals, interval_count, exp_dates, exp_date_count); if (ret) { goto cleanup; @@ -3849,10 +3919,10 @@ nc_server_notif_cert_exp_dates_get(struct nc_interval *intervals, int interval_c } /* keystore certs */ - for (i = 0; i < ks->asym_key_count; i++) { - for (j = 0; j < ks->asym_keys[i].cert_count; j++) { - NC_CERT_EXP_UPDATE_CERT_PATH(&cp, NULL, NULL, NULL, NULL, ks->asym_keys[i].name, ks->asym_keys[i].certs[j].name, NULL, NULL); - ret = nc_server_notif_cert_exp_date_append(ks->asym_keys[i].certs[j].data, &cp, intervals, interval_count, exp_dates, exp_date_count); + LY_ARRAY_FOR(ks->entries, i) { + LY_ARRAY_FOR(ks->entries[i].certs, struct nc_certificate, cert) { + NC_CERT_EXP_UPDATE_CERT_PATH(&cp, NULL, NULL, NULL, NULL, ks->entries[i].asym_key.name, cert->name, NULL, NULL); + ret = nc_server_notif_cert_exp_date_append(cert->data, &cp, intervals, interval_count, exp_dates, exp_date_count); if (ret) { goto cleanup; } @@ -3860,10 +3930,10 @@ nc_server_notif_cert_exp_dates_get(struct nc_interval *intervals, int interval_c } /* truststore certs */ - for (i = 0; i < ts->cert_bag_count; i++) { - for (j = 0; j < ts->cert_bags[i].cert_count; j++) { - NC_CERT_EXP_UPDATE_CERT_PATH(&cp, NULL, NULL, NULL, NULL, NULL, NULL, ts->cert_bags[i].name, ts->cert_bags[i].certs[j].name); - ret = nc_server_notif_cert_exp_date_append(ts->cert_bags[i].certs[j].data, &cp, intervals, interval_count, exp_dates, exp_date_count); + LY_ARRAY_FOR(ts->cert_bags, i) { + LY_ARRAY_FOR(ts->cert_bags[i].certs, struct nc_certificate, cert) { + NC_CERT_EXP_UPDATE_CERT_PATH(&cp, NULL, NULL, NULL, NULL, NULL, NULL, ts->cert_bags[i].name, cert->name); + ret = nc_server_notif_cert_exp_date_append(cert->data, &cp, intervals, interval_count, exp_dates, exp_date_count); if (ret) { goto cleanup; } @@ -3925,9 +3995,11 @@ nc_server_notif_cert_exp_wakeup_time_get(struct nc_cert_expiration *exp_dates, i * * @param[in] exp_dates Expiration dates. * @param[in] exp_date_count Expiration date count. + * @param[in] intervals Time intervals to destroy. */ static void -nc_server_notif_cert_exp_dates_destroy(struct nc_cert_expiration *exp_dates, int exp_date_count) +nc_server_notif_cert_exp_data_destroy(struct nc_cert_expiration *exp_dates, int exp_date_count, + struct nc_cert_exp_time_interval *intervals) { int i; @@ -3936,6 +4008,8 @@ nc_server_notif_cert_exp_dates_destroy(struct nc_cert_expiration *exp_dates, int free(exp_dates[i].xpath); } free(exp_dates); + + free(intervals); } /** @@ -3964,30 +4038,42 @@ nc_server_notif_cert_exp_thread_is_running() /** * @brief Get the certificate expiration notification time intervals either from the config or the default ones. * + * @note The caller is responsible for freeing the allocated intervals. + * * @param[in] default_intervals Default intervals. * @param[in] default_interval_count Default interval count. * @param[out] intervals Actual intervals to be used. * @param[out] interval_count Used interval count. + * @return 0 on success, 1 on error. */ -static void -nc_server_notif_cert_exp_intervals_get(struct nc_interval *default_intervals, int default_interval_count, - struct nc_interval **intervals, int *interval_count) +static int +nc_server_notif_cert_exp_intervals_get(struct nc_cert_exp_time_interval *default_intervals, uint32_t default_interval_count, + struct nc_cert_exp_time_interval **intervals, uint32_t *interval_count) { - /* LOCK */ - pthread_mutex_lock(&server_opts.cert_exp_notif.lock); + int rc = 0; + + /* CONFIG LOCK */ + pthread_rwlock_rdlock(&server_opts.config_lock); - if (!server_opts.cert_exp_notif.intervals) { - /* using the default intervals */ - *intervals = default_intervals; + if (!server_opts.config.cert_exp_notif_intervals) { + /* dup the default intervals */ + *intervals = malloc(default_interval_count * sizeof **intervals); + NC_CHECK_ERRMEM_GOTO(!*intervals, rc = 1, cleanup); + memcpy(*intervals, default_intervals, default_interval_count * sizeof **intervals); *interval_count = default_interval_count; } else { - /* using configured intervals */ - *intervals = server_opts.cert_exp_notif.intervals; - *interval_count = server_opts.cert_exp_notif.interval_count; + /* dup the configured intervals */ + *intervals = malloc(LY_ARRAY_COUNT(server_opts.config.cert_exp_notif_intervals) * sizeof **intervals); + NC_CHECK_ERRMEM_GOTO(!*intervals, rc = 1, cleanup); + memcpy(*intervals, server_opts.config.cert_exp_notif_intervals, + LY_ARRAY_COUNT(server_opts.config.cert_exp_notif_intervals) * sizeof **intervals); + *interval_count = LY_ARRAY_COUNT(server_opts.config.cert_exp_notif_intervals); } - /* UNLOCK */ - pthread_mutex_unlock(&server_opts.cert_exp_notif.lock); +cleanup: + /* CONFIG UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); + return rc; } /** @@ -4000,21 +4086,25 @@ nc_server_notif_cert_exp_intervals_get(struct nc_interval *default_intervals, in static void * nc_server_notif_cert_exp_thread(void *arg) { - int r = 0, exp_date_count = 0; + int r = 0; struct nc_cert_exp_notif_thread_arg *targ = arg; struct nc_cert_expiration *exp_dates = NULL, *curr_cert = NULL; struct timespec wakeup_time = {0}; char *exp_time = NULL; - struct nc_interval default_intervals[3] = { + struct nc_cert_exp_time_interval default_intervals[3] = { {.anchor = {.months = 3}, .period = {.months = 1}}, {.anchor = {.weeks = 2}, .period = {.weeks = 1}}, {.anchor = {.days = 7}, .period = {.days = 1}} }; - struct nc_interval *intervals; - int interval_count; + struct nc_cert_exp_time_interval *intervals; + uint32_t interval_count = 0, exp_date_count = 0; /* get certificate expiration time intervals */ - nc_server_notif_cert_exp_intervals_get(default_intervals, 3, &intervals, &interval_count); + r = nc_server_notif_cert_exp_intervals_get(default_intervals, + sizeof(default_intervals) / sizeof(default_intervals[0]), &intervals, &interval_count); + if (r) { + goto cleanup; + } /* get the expiration dates */ r = nc_server_notif_cert_exp_dates_get(intervals, interval_count, &exp_dates, &exp_date_count); @@ -4040,7 +4130,7 @@ nc_server_notif_cert_exp_thread(void *arg) } /* config changed, reload the certificates and intervals */ - nc_server_notif_cert_exp_dates_destroy(exp_dates, exp_date_count); + nc_server_notif_cert_exp_data_destroy(exp_dates, exp_date_count, intervals); nc_server_notif_cert_exp_intervals_get(default_intervals, 3, &intervals, &interval_count); @@ -4082,7 +4172,7 @@ nc_server_notif_cert_exp_thread(void *arg) targ->clb_free_data(targ->clb_data); } if (exp_dates) { - nc_server_notif_cert_exp_dates_destroy(exp_dates, exp_date_count); + nc_server_notif_cert_exp_data_destroy(exp_dates, exp_date_count, intervals); } free(targ); return NULL; @@ -4172,13 +4262,21 @@ nc_server_notif_cert_expiration_thread_stop(int wait) int nc_server_is_mod_ignored(const char *mod_name) { - uint16_t i; + int ignored = 0; + LY_ARRAY_COUNT_TYPE i; - for (i = 0; i < server_opts.ignored_mod_count; ++i) { - if (!strcmp(server_opts.ignored_modules[i], mod_name)) { - return 1; + /* LOCK */ + pthread_rwlock_rdlock(&server_opts.config_lock); + + LY_ARRAY_FOR(server_opts.config.ignored_modules, i) { + if (!strcmp(server_opts.config.ignored_modules[i], mod_name)) { + ignored = 1; + break; } } - return 0; + /* UNLOCK */ + pthread_rwlock_unlock(&server_opts.config_lock); + + return ignored; } diff --git a/src/session_server.h b/src/session_server.h index dc24871d..fe3f8728 100644 --- a/src/session_server.h +++ b/src/session_server.h @@ -384,12 +384,10 @@ void nc_ps_clear(struct nc_pollsession *ps, int all, void (*data_free)(void *)); /** * @brief Get the number of currently configured listening endpoints. - * Note that an ednpoint without address and/or port will be included - * even though it is not, in fact, listening. * - * @return Number of added listening endpoints. + * @return Number of listening endpoints. */ -int nc_server_endpt_count(void); +uint32_t nc_server_endpt_count(void); /** @} */ diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c index 5acf5e1f..88ef1971 100644 --- a/src/session_server_ssh.c +++ b/src/session_server_ssh.c @@ -126,27 +126,26 @@ nc_server_ssh_privkey_data_to_tmp_file(const char *in, const char *privkey_forma static int nc_server_ssh_ks_ref_get_key(const char *referenced_name, struct nc_asymmetric_key **askey) { - uint16_t i; - struct nc_keystore *ks = &server_opts.keystore; + LY_ARRAY_COUNT_TYPE i; + struct nc_keystore *ks = &server_opts.config.keystore; *askey = NULL; /* lookup name */ - for (i = 0; i < ks->asym_key_count; i++) { - if (!strcmp(referenced_name, ks->asym_keys[i].name)) { + LY_ARRAY_FOR(ks->entries, i) { + if (!strcmp(referenced_name, ks->entries[i].asym_key.name)) { break; } } - - if (i == ks->asym_key_count) { + if (i == LY_ARRAY_COUNT(ks->entries)) { ERR(NULL, "Keystore entry \"%s\" not found.", referenced_name); return 1; } - *askey = &ks->asym_keys[i]; + *askey = &ks->entries[i].asym_key; /* check if the referenced public key is SubjectPublicKeyInfo */ - if ((*askey)->pubkey_data && nc_is_pk_subject_public_key_info((*askey)->pubkey_data)) { + 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; @@ -164,37 +163,37 @@ nc_server_ssh_ks_ref_get_key(const char *referenced_name, struct nc_asymmetric_k * @return 0 on success, 1 on error. */ static int -nc_server_ssh_ts_ref_get_keys(const char *referenced_name, struct nc_public_key **pubkeys, uint16_t *pubkey_count) +nc_server_ssh_ts_ref_get_keys(const char *referenced_name, struct nc_public_key **pubkeys, uint32_t *pubkey_count) { - uint16_t i, j; - struct nc_truststore *ts = &server_opts.truststore; + LY_ARRAY_COUNT_TYPE i; + struct nc_public_key *pubkey; + struct nc_truststore *ts = &server_opts.config.truststore; *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)) { + LY_ARRAY_FOR(ts->pubkey_bags, i) { + if (!strcmp(referenced_name, ts->pubkey_bags[i].name)) { break; } } - - if (i == ts->pub_bag_count) { + if (i == LY_ARRAY_COUNT(ts->pubkey_bags)) { ERR(NULL, "Truststore entry \"%s\" not found.", referenced_name); return 1; } /* 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)) { + LY_ARRAY_FOR(ts->pubkey_bags[i].pubkeys, struct nc_public_key, pubkey) { + if (nc_is_pk_subject_public_key_info(pubkey->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); + "which is not allowed in SSH!", referenced_name); return 1; } } - *pubkeys = ts->pub_bags[i].pubkeys; - *pubkey_count = ts->pub_bags[i].pubkey_count; + *pubkeys = ts->pubkey_bags[i].pubkeys; + *pubkey_count = LY_ARRAY_COUNT(ts->pubkey_bags[i].pubkeys); return 0; } @@ -363,7 +362,7 @@ nc_server_ssh_get_system_keys_path(const char *username, char **out_path) * @return 0 on success, 1 on error. */ static int -nc_server_ssh_read_authorized_keys_file(const char *path, struct nc_public_key **pubkeys, uint16_t *pubkey_count) +nc_server_ssh_read_authorized_keys_file(const char *path, struct nc_public_key **pubkeys, uint32_t *pubkey_count) { int ret = 0, rc, line_num = 0; FILE *f = NULL; @@ -443,7 +442,7 @@ nc_server_ssh_read_authorized_keys_file(const char *path, struct nc_public_key * * @return 0 on success, non-zero on error. */ static int -nc_server_ssh_get_system_keys(const char *username, struct nc_public_key **pubkeys, uint16_t *pubkey_count) +nc_server_ssh_get_system_keys(const char *username, struct nc_public_key **pubkeys, uint32_t *pubkey_count) { int ret = 0; char *path = NULL; @@ -1282,21 +1281,21 @@ nc_server_ssh_auth_pubkey(struct nc_session *session, int local_users_supported, { int signature_state, ret = 0; struct nc_public_key *pubkeys = NULL; - uint16_t pubkey_count = 0, i; + uint32_t pubkey_count = 0, i; assert(!local_users_supported || auth_client); /* get the public keys */ - if (!local_users_supported || (auth_client->store == NC_STORE_SYSTEM)) { + if (!local_users_supported || (auth_client->pubkey_store == NC_STORE_SYSTEM)) { /* system user or the user has 'use system keys' configured, these need to be free'd */ ret = nc_server_ssh_get_system_keys(session->username, &pubkeys, &pubkey_count); if (ret) { goto cleanup; } - } else if (auth_client->store == NC_STORE_LOCAL) { + } else if (auth_client->pubkey_store == NC_STORE_LOCAL) { pubkeys = auth_client->pubkeys; - pubkey_count = auth_client->pubkey_count; - } else if (auth_client->store == NC_STORE_TRUSTSTORE) { + pubkey_count = LY_ARRAY_COUNT(auth_client->pubkeys); + } else if (auth_client->pubkey_store == NC_STORE_TRUSTSTORE) { ret = nc_server_ssh_ts_ref_get_keys(auth_client->ts_ref, &pubkeys, &pubkey_count); if (ret) { goto cleanup; @@ -1321,7 +1320,7 @@ nc_server_ssh_auth_pubkey(struct nc_session *session, int local_users_supported, } cleanup: - if (!local_users_supported || (auth_client->store == NC_STORE_SYSTEM)) { + if (!local_users_supported || (auth_client->pubkey_store == NC_STORE_SYSTEM)) { for (i = 0; i < pubkey_count; i++) { free(pubkeys[i].name); free(pubkeys[i].data); @@ -1483,7 +1482,7 @@ nc_server_ssh_auth(struct nc_session *session, struct nc_server_ssh_opts *opts, { const char *username; int ret = 0; - uint16_t i; + LY_ARRAY_COUNT_TYPE u; struct nc_auth_client *auth_client = NULL; struct nc_endpt *referenced_endpt; @@ -1493,9 +1492,9 @@ nc_server_ssh_auth(struct nc_session *session, struct nc_server_ssh_opts *opts, if (local_users_supported) { /* get the locally configured user */ - for (i = 0; i < opts->client_count; i++) { - if (!strcmp(opts->auth_clients[i].username, username)) { - auth_client = &opts->auth_clients[i]; + LY_ARRAY_FOR(opts->auth_clients, u) { + if (!strcmp(opts->auth_clients[u].username, username)) { + auth_client = &opts->auth_clients[u]; break; } } @@ -1503,7 +1502,7 @@ nc_server_ssh_auth(struct nc_session *session, struct nc_server_ssh_opts *opts, if (!auth_client) { 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)) { + if (nc_server_endpt_get(opts->referenced_endpt_name, &referenced_endpt)) { ERRINT; return 1; } @@ -1527,10 +1526,9 @@ nc_server_ssh_auth(struct nc_session *session, struct nc_server_ssh_opts *opts, /* configure and count accepted auth methods */ if (local_users_supported) { - if (((auth_client->store == NC_STORE_LOCAL) && (auth_client->pubkey_count)) || - (auth_client->store == NC_STORE_TRUSTSTORE) || (auth_client->store == NC_STORE_SYSTEM)) { - /* either locally configured pubkeys, or truststore or system (need to check for - * pubkey count, because NC_STORE_LOCAL is the default enum value) */ + if ((auth_client->pubkey_store == NC_STORE_LOCAL) || + (auth_client->pubkey_store == NC_STORE_TRUSTSTORE) || (auth_client->pubkey_store == NC_STORE_SYSTEM)) { + /* either locally configured pubkeys, or truststore or system */ auth_state->methods |= SSH_AUTH_METHOD_PUBLICKEY; auth_state->method_count++; } @@ -1844,54 +1842,38 @@ nc_accept_ssh_session_open_netconf_channel(struct nc_session *session, struct nc * @brief Set hostkeys to be used for an SSH bind. * * @param[in] sbind SSH bind to use. - * @param[in] hostkeys Array of hostkeys. - * @param[in] hostkey_count Count of @p hostkeys. - * @return 0 on success. - * @return -1 on error. + * @param[in] opts SSH server options. + * @return 0 on success, -1 on error. */ static int -nc_ssh_bind_add_hostkeys(ssh_bind sbind, struct nc_server_ssh_opts *opts, uint16_t hostkey_count) +nc_ssh_bind_add_hostkeys(ssh_bind sbind, struct nc_server_ssh_opts *opts) { - uint16_t i; + int rc; char *privkey_path; - int ret; + struct nc_hostkey *hostkey = NULL; struct nc_asymmetric_key *key = NULL; - for (i = 0; i < hostkey_count; ++i) { + LY_ARRAY_FOR(opts->hostkeys, struct nc_hostkey, hostkey) { privkey_path = NULL; /* get the asymmetric key */ - if (opts->hostkeys[i].store == NC_STORE_LOCAL) { + if (hostkey->store == NC_STORE_LOCAL) { /* stored locally */ - key = &opts->hostkeys[i].key; + key = &hostkey->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 = nc_server_ssh_privkey_data_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; + NC_CHECK_RET(nc_server_ssh_ks_ref_get_key(hostkey->ks_ref, &key), -1); } - ret = ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_HOSTKEY, privkey_path); + privkey_path = nc_server_ssh_privkey_data_to_tmp_file(key->privkey.data, nc_privkey_format_to_str(key->privkey.type)); + NC_CHECK_ERR_RET(!privkey_path, ERR(NULL, "Temporarily storing a host key into a file failed."), -1); - /* cleanup */ + rc = ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_HOSTKEY, privkey_path); if (unlink(privkey_path)) { WRN(NULL, "Removing a temporary host key file \"%s\" failed (%s).", privkey_path, strerror(errno)); } - - if (ret != SSH_OK) { - ERR(NULL, "Failed to set hostkey \"%s\" (%s).", opts->hostkeys[i].name, privkey_path); - } free(privkey_path); - - if (ret != SSH_OK) { - return -1; - } + NC_CHECK_ERR_RET(rc != SSH_OK, ERR(NULL, "Failed to set hostkey \"%s\".", hostkey->name), -1); } return 0; @@ -1973,36 +1955,32 @@ nc_accept_ssh_session(struct nc_session *session, struct nc_server_ssh_opts *opt } /* configure host keys */ - if (nc_ssh_bind_add_hostkeys(sbind, opts, opts->hostkey_count)) { + if (nc_ssh_bind_add_hostkeys(sbind, opts)) { rc = -1; goto cleanup; } /* configure supported algorithms */ if (opts->hostkey_algs && ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, opts->hostkey_algs)) { + ERR(session, "Failed to set hostkey algorithms (%s).", ssh_get_error(sbind)); rc = -1; goto cleanup; } if (opts->encryption_algs) { if (ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_CIPHERS_S_C, opts->encryption_algs)) { - rc = -1; - goto cleanup; - } - if (ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_CIPHERS_C_S, opts->encryption_algs)) { + ERR(session, "Failed to set encryption algorithms (%s).", ssh_get_error(sbind)); rc = -1; goto cleanup; } } if (opts->kex_algs && ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_KEY_EXCHANGE, opts->kex_algs)) { + ERR(session, "Failed to set key exchange algorithms (%s).", ssh_get_error(sbind)); rc = -1; goto cleanup; } if (opts->mac_algs) { if (ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_HMAC_S_C, opts->mac_algs)) { - rc = -1; - goto cleanup; - } - if (ssh_bind_options_set(sbind, SSH_BIND_OPTIONS_HMAC_C_S, opts->mac_algs)) { + ERR(session, "Failed to set MAC algorithms (%s).", ssh_get_error(sbind)); rc = -1; goto cleanup; } diff --git a/src/session_server_tls.c b/src/session_server_tls.c index 03574c2c..9066c7df 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -33,67 +33,84 @@ #include "session_p.h" #include "session_wrapper.h" +/** + * @brief Get certificate and private key data from keystore. + * + * @param[in] referenced_key_name Name of the asymmetric key in the keystore. + * @param[in] referenced_cert_name Name of the certificate in the keystore. + * @param[out] privkey_data Retrieved private key data. + * @param[out] privkey_type Retrieved private key type. + * @param[out] cert_data Retrieved certificate data. + * @return 0 on success, -1 on error. + */ static int nc_server_tls_ks_ref_get_cert_key(const char *referenced_key_name, const char *referenced_cert_name, char **privkey_data, enum nc_privkey_format *privkey_type, char **cert_data) { - uint16_t i, j; - struct nc_keystore *ks = &server_opts.keystore; + LY_ARRAY_COUNT_TYPE i, j; + struct nc_keystore *ks = &server_opts.config.keystore; *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)) { + /* lookup key */ + LY_ARRAY_FOR(ks->entries, i) { + if (!strcmp(referenced_key_name, ks->entries[i].asym_key.name)) { break; } } - if (i == ks->asym_key_count) { - ERR(NULL, "Keystore entry \"%s\" not found.", referenced_key_name); + if (i == LY_ARRAY_COUNT(ks->entries)) { + ERR(NULL, "Keystore asymmetric key 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[j].name)) { + LY_ARRAY_FOR(ks->entries[i].certs, j) { + if (!strcmp(referenced_cert_name, ks->entries[i].certs[j].name)) { break; } } - if (j == ks->asym_keys[i].cert_count) { + if (j == LY_ARRAY_COUNT(ks->entries[i].certs)) { ERR(NULL, "Keystore certificate entry \"%s\" associated with the key \"%s\" not found.", referenced_cert_name, referenced_key_name); return -1; } - *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; + *privkey_data = ks->entries[i].asym_key.privkey.data; + *privkey_type = ks->entries[i].asym_key.privkey.type; + *cert_data = ks->entries[i].certs[j].data; return 0; } +/** + * @brief Get certificates from truststore. + * + * @param[in] referenced_name Name of the certificate bag in the truststore. + * @param[out] certs Retrieved certificates. + * @param[out] cert_count Number of retrieved certificates. + * @return 0 on success, -1 on error. + */ static int -nc_server_tls_truststore_ref_get_certs(const char *referenced_name, struct nc_certificate **certs, uint16_t *cert_count) +nc_server_tls_truststore_ref_get_certs(const char *referenced_name, struct nc_certificate **certs, uint32_t *cert_count) { - uint16_t i; - struct nc_truststore *ts = &server_opts.truststore; + LY_ARRAY_COUNT_TYPE i; + struct nc_truststore *ts = &server_opts.config.truststore; *certs = NULL; *cert_count = 0; /* lookup name */ - for (i = 0; i < ts->cert_bag_count; i++) { + LY_ARRAY_FOR(ts->cert_bags, i) { if (!strcmp(referenced_name, ts->cert_bags[i].name)) { break; } } - - if (i == ts->cert_bag_count) { - ERR(NULL, "Truststore entry \"%s\" not found.", referenced_name); + if (i == LY_ARRAY_COUNT(ts->cert_bags)) { + ERR(NULL, "Truststore certificate bag \"%s\" not found.", referenced_name); return -1; } *certs = ts->cert_bags[i].certs; - *cert_count = ts->cert_bags[i].cert_count; + *cert_count = LY_ARRAY_COUNT(ts->cert_bags[i].certs); return 0; } @@ -480,7 +497,7 @@ _nc_server_tls_cert_to_name(struct nc_server_tls_opts *opts, void *cert_chain, c /* do the same for referenced endpoint's ctn entries */ if (opts->referenced_endpt_name) { - if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) { + if (nc_server_endpt_get(opts->referenced_endpt_name, &referenced_endpt)) { ERRINT; ret = -1; goto cleanup; @@ -500,21 +517,21 @@ _nc_server_tls_cert_to_name(struct nc_server_tls_opts *opts, void *cert_chain, c } static int -_nc_server_tls_verify_peer_cert(void *peer_cert, struct nc_cert_grouping *ee_certs) +_nc_server_tls_verify_peer_cert(void *peer_cert, struct nc_server_tls_client_auth *client_auth) { - int i, ret; + int ret; void *cert; struct nc_certificate *certs; - uint16_t cert_count; + uint32_t i, cert_count; - if (ee_certs->store == NC_STORE_LOCAL) { + if (client_auth->ee_certs_store == NC_STORE_LOCAL) { /* local definition */ - certs = ee_certs->certs; - cert_count = ee_certs->cert_count; - } else { + certs = client_auth->ee_certs; + cert_count = LY_ARRAY_COUNT(client_auth->ee_certs); + } else if (client_auth->ee_certs_store == NC_STORE_TRUSTSTORE) { /* truststore reference */ - if (nc_server_tls_truststore_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); + if (nc_server_tls_truststore_ref_get_certs(client_auth->ee_cert_bag_ts_ref, &certs, &cert_count)) { + ERR(NULL, "Error getting end-entity certificates from the truststore reference \"%s\".", client_auth->ee_cert_bag_ts_ref); return -1; } } @@ -542,18 +559,18 @@ nc_server_tls_verify_peer_cert(void *peer_cert, struct nc_server_tls_opts *opts) int rc; struct nc_endpt *referenced_endpt; - rc = _nc_server_tls_verify_peer_cert(peer_cert, &opts->ee_certs); + rc = _nc_server_tls_verify_peer_cert(peer_cert, &opts->client_auth); if (!rc) { return 0; } if (opts->referenced_endpt_name) { - if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) { + if (nc_server_endpt_get(opts->referenced_endpt_name, &referenced_endpt)) { ERRINT; return -1; } - rc = _nc_server_tls_verify_peer_cert(peer_cert, &referenced_endpt->opts.tls->ee_certs); + rc = _nc_server_tls_verify_peer_cert(peer_cert, &referenced_endpt->opts.tls->client_auth); if (!rc) { return 0; } @@ -664,15 +681,15 @@ nc_server_tls_load_server_cert_key(struct nc_server_tls_opts *opts, void **srv_c *srv_cert = *srv_pkey = NULL; /* get data needed for setting the server cert */ - if (opts->store == NC_STORE_LOCAL) { + if (opts->cert_store == NC_STORE_LOCAL) { /* local definition */ - cert_data = opts->cert_data; - privkey_data = opts->privkey_data; - privkey_type = opts->privkey_type; - } else { + cert_data = opts->local.cert.data; + privkey_data = opts->local.key.privkey.data; + privkey_type = opts->local.key.privkey.type; + } else if (opts->cert_store == NC_STORE_KEYSTORE) { /* keystore */ - if (nc_server_tls_ks_ref_get_cert_key(opts->key_ref, opts->cert_ref, &privkey_data, &privkey_type, &cert_data)) { - ERR(NULL, "Getting server certificate from the keystore reference \"%s\" failed.", opts->key_ref); + if (nc_server_tls_ks_ref_get_cert_key(opts->keystore.asym_key_ref, opts->keystore.cert_ref, &privkey_data, &privkey_type, &cert_data)) { + ERR(NULL, "Getting server certificate from the keystore reference \"%s\" failed.", opts->keystore.asym_key_ref); return 1; } } @@ -698,20 +715,20 @@ nc_server_tls_load_server_cert_key(struct nc_server_tls_opts *opts, void **srv_c } int -nc_server_tls_load_trusted_certs(struct nc_cert_grouping *ca_certs, void *cert_store) +nc_server_tls_load_trusted_certs(struct nc_server_tls_client_auth *client_auth, void *cert_store) { struct nc_certificate *certs; - uint16_t i, cert_count; + uint32_t i, cert_count = 0; void *cert; - if (ca_certs->store == NC_STORE_LOCAL) { + if (client_auth->ca_certs_store == NC_STORE_LOCAL) { /* local definition */ - certs = ca_certs->certs; - cert_count = ca_certs->cert_count; - } else { + certs = client_auth->ca_certs; + cert_count = LY_ARRAY_COUNT(client_auth->ca_certs); + } else if (client_auth->ca_certs_store == NC_STORE_TRUSTSTORE) { /* truststore */ - if (nc_server_tls_truststore_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); + if (nc_server_tls_truststore_ref_get_certs(client_auth->ca_cert_bag_ts_ref, &certs, &cert_count)) { + ERR(NULL, "Error getting certificate-authority certificates from the truststore reference \"%s\".", client_auth->ca_cert_bag_ts_ref); return 1; } } @@ -762,22 +779,31 @@ nc_server_tls_accept_check(int accept_ret, void *tls_session) * @param[in] certs_grp Certificate grouping to get the number of certificates from. * @return Number of certificates in the grouping, or -1 on error. */ -static uint16_t -nc_server_tls_get_num_certs(struct nc_cert_grouping *certs_grp) +static uint32_t +nc_server_tls_get_num_certs(struct nc_server_tls_client_auth *client_auth) { - uint16_t count = 0; + uint32_t ca_count = 0, ee_count = 0; struct nc_certificate *certs; - if (certs_grp->store == NC_STORE_LOCAL) { - count = certs_grp->cert_count; - } else if (certs_grp->store == NC_STORE_TRUSTSTORE) { - if (nc_server_tls_truststore_ref_get_certs(certs_grp->ts_ref, &certs, &count)) { - ERR(NULL, "Getting CA certificates from the truststore reference \"%s\" failed.", certs_grp->ts_ref); + if (client_auth->ca_certs_store == NC_STORE_LOCAL) { + ca_count = LY_ARRAY_COUNT(client_auth->ca_certs); + } else if (client_auth->ca_certs_store == NC_STORE_TRUSTSTORE) { + if (nc_server_tls_truststore_ref_get_certs(client_auth->ca_cert_bag_ts_ref, &certs, &ca_count)) { + ERR(NULL, "Getting CA certificates from the truststore reference \"%s\" failed.", client_auth->ca_cert_bag_ts_ref); + return -1; + } + } + + if (client_auth->ee_certs_store == NC_STORE_LOCAL) { + ee_count += LY_ARRAY_COUNT(client_auth->ee_certs); + } else if (client_auth->ee_certs_store == NC_STORE_TRUSTSTORE) { + if (nc_server_tls_truststore_ref_get_certs(client_auth->ee_cert_bag_ts_ref, &certs, &ee_count)) { + ERR(NULL, "Getting end-entity certificates from the truststore reference \"%s\" failed.", client_auth->ee_cert_bag_ts_ref); return -1; } } - return count; + return ca_count + ee_count; } int @@ -787,10 +813,10 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt struct timespec ts_timeout; struct nc_tls_verify_cb_data cb_data = {0}; struct nc_endpt *referenced_endpt; - void *tls_cfg, *srv_cert, *srv_pkey, *cert_store, *crl_store; + void *tls_cfg, *srv_cert, *srv_pkey, *cert_store, *crl_store, *cipher_suites; uint32_t cert_count = 0; - tls_cfg = srv_cert = srv_pkey = cert_store = crl_store = NULL; + tls_cfg = srv_cert = srv_pkey = cert_store = crl_store = cipher_suites = NULL; /* set verify cb data */ cb_data.session = session; @@ -815,19 +841,19 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt } /* load trusted CA certificates */ - if (nc_server_tls_load_trusted_certs(&opts->ca_certs, cert_store)) { + if (nc_server_tls_load_trusted_certs(&opts->client_auth, cert_store)) { ERR(session, "Loading server CA certs failed."); goto fail; } /* load referenced endpoint's trusted CA certs if set */ if (opts->referenced_endpt_name) { - if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) { + if (nc_server_endpt_get(opts->referenced_endpt_name, &referenced_endpt)) { ERR(session, "Referenced endpoint \"%s\" not found.", opts->referenced_endpt_name); goto fail; } - if (nc_server_tls_load_trusted_certs(&referenced_endpt->opts.tls->ca_certs, cert_store)) { + if (nc_server_tls_load_trusted_certs(&referenced_endpt->opts.tls->client_auth, cert_store)) { ERR(session, "Loading server CA certs from referenced endpoint failed."); goto fail; } @@ -836,11 +862,9 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt /* Check if there are no CA/end entity certs configured, which is a valid config. * However, that would imply not using TLS for auth, which is not (yet) supported */ if (!opts->referenced_endpt_name) { - cert_count = nc_server_tls_get_num_certs(&opts->ca_certs) + nc_server_tls_get_num_certs(&opts->ee_certs); + cert_count = nc_server_tls_get_num_certs(&opts->client_auth); } else { - cert_count = nc_server_tls_get_num_certs(&opts->ca_certs) + nc_server_tls_get_num_certs(&opts->ee_certs) + - nc_server_tls_get_num_certs(&referenced_endpt->opts.tls->ca_certs) + - nc_server_tls_get_num_certs(&referenced_endpt->opts.tls->ee_certs); + cert_count = nc_server_tls_get_num_certs(&opts->client_auth) + nc_server_tls_get_num_certs(&referenced_endpt->opts.tls->client_auth); } if (cert_count <= 0) { ERR(session, "Neither CA nor end-entity certificates configured."); @@ -853,28 +877,28 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt } /* set supported TLS versions */ - if (opts->tls_versions) { - if (nc_server_tls_set_tls_versions_wrap(tls_cfg, opts->tls_versions)) { - ERR(session, "Setting supported server TLS versions failed."); - goto fail; - } + if (nc_server_tls_set_tls_versions_wrap(tls_cfg, opts->min_version, opts->max_version)) { + ERR(session, "Setting supported server TLS versions failed."); + goto fail; } - /* set supported cipher suites */ - if (opts->ciphers) { - nc_server_tls_set_cipher_suites_wrap(tls_cfg, opts->ciphers); + /* set supported cipher suites if any, otherwise leave defaults */ + if (opts->cipher_suites) { + if (nc_server_tls_set_cipher_suites_wrap(tls_cfg, opts->cipher_suites, &cipher_suites)) { + goto fail; + } } /* set verify flags, callback and its data */ nc_server_tls_set_verify_wrap(tls_cfg, &cb_data); /* init TLS context and store data which may be needed later in it */ - if (nc_tls_init_ctx_wrap(srv_cert, srv_pkey, cert_store, crl_store, &session->ti.tls.ctx)) { + if (nc_tls_init_ctx_wrap(srv_cert, srv_pkey, cert_store, crl_store, cipher_suites, &session->ti.tls.ctx)) { goto fail; } /* memory is managed by context now */ - srv_cert = srv_pkey = cert_store = crl_store = NULL; + srv_cert = srv_pkey = cert_store = crl_store = cipher_suites = NULL; /* setup config from ctx */ if (nc_tls_setup_config_from_ctx_wrap(&session->ti.tls.ctx, tls_cfg)) { @@ -929,6 +953,7 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt nc_tls_privkey_destroy_wrap(srv_pkey); nc_tls_cert_store_destroy_wrap(cert_store); nc_tls_crl_store_destroy_wrap(crl_store); + free(cipher_suites); if (timeouted) { return 0; diff --git a/src/session_wrapper.h b/src/session_wrapper.h index 9332a29d..229bf5a2 100644 --- a/src/session_wrapper.h +++ b/src/session_wrapper.h @@ -19,6 +19,7 @@ #include #include "config.h" +#include "session_p.h" #ifdef HAVE_MBEDTLS @@ -34,6 +35,7 @@ */ struct nc_tls_ctx { int *sock; /**< Socket FD. */ + int *cipher_suites; /**< List of allowed cipher suite IDs. */ mbedtls_entropy_context *entropy; /**< Entropy. */ mbedtls_ctr_drbg_context *ctr_drbg; /**< Random bit generator. */ mbedtls_x509_crt *cert; /**< Certificate. */ @@ -60,6 +62,11 @@ struct nc_tls_ctx { #endif +/** + * @brief List of supported cipher suites. + */ +extern const char *nc_tls_supported_cipher_suites[]; + /** * @brief Server side TLS verify callback data. */ @@ -69,6 +76,9 @@ struct nc_tls_verify_cb_data { void *chain; /**< Certificate chain used to verify the client cert. */ }; +/* forward declaration */ +enum nc_tls_version; + /** * @brief Initializes the TLS backend. * @@ -201,11 +211,12 @@ int nc_server_tls_add_crl_to_store_wrap(const unsigned char *crl_data, size_t si * @brief Sets the TLS version. * * @param[in] tls_cfg TLS configuration. - * @param[in] tls_versions Bit-field of supported TLS versions. + * @param[in] min Optional minimum TLS version. + * @param[in] max Optional maximum TLS version. * * @return 0 on success, non-zero on fail. */ -int nc_server_tls_set_tls_versions_wrap(void *tls_cfg, unsigned int tls_versions); +int nc_server_tls_set_tls_versions_wrap(void *tls_cfg, enum nc_tls_version min, enum nc_tls_version max); /** * @brief Set TLS server's verify flags, verify cb and its data. @@ -443,10 +454,12 @@ int nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname); * @param[in] pkey Private key. * @param[in] cert_store Certificate store. * @param[in] crl_store CRL store. + * @param[in] cipher_suites List of cipher suites. * @param[in,out] tls_ctx TLS context. * @return 0 on success, non-zero on fail. */ -int nc_tls_init_ctx_wrap(void *cert, void *pkey, void *cert_store, void *crl_store, struct nc_tls_ctx *tls_ctx); +int nc_tls_init_ctx_wrap(void *cert, void *pkey, void *cert_store, + void *crl_store, void *cipher_suites, struct nc_tls_ctx *tls_ctx); /** * @brief Setup a TLS configuration from a TLS context. @@ -708,30 +721,25 @@ void * nc_tls_import_pubkey_file_wrap(const char *pubkey_path); int nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, char ***uris, int *uri_count); /** - * @brief Process a cipher suite so that it can be set by the underlying TLS lib. + * @brief Convert IANA cipher suite name to internal TLS library name. * - * @param[in] cipher Cipher suite identity value. - * @param[out] out Processed cipher suite. - * @return 0 on success, 1 on fail. - */ -int nc_tls_process_cipher_suite_wrap(const char *cipher, char **out); - -/** - * @brief Append a cipher suite to the list of cipher suites. + * @note For MbedTLS, all cipher suites up to v4.0.0 are supported. + * For OpenSSL, the list was obtained from: https://testssl.sh/openssl-iana.mapping.html * - * @param[in] opts TLS options. - * @param[in] cipher_suite Cipher suite to append. - * @return 0 on success, 1 on fail. + * @param[in] iana_name IANA cipher suite name. + * @return Internal TLS library cipher suite name, NULL if not found. */ -int nc_tls_append_cipher_suite_wrap(struct nc_server_tls_opts *opts, const char *cipher_suite); +const char *nc_server_tls_cipher_suite_name_to_internal_wrap(const char *iana_name); /** * @brief Set the list of cipher suites for the TLS configuration. * * @param[in] tls_cfg TLS configuration. - * @param[in] cipher_suites List of cipher suites. + * @param[in] cipher_suites List of colon-separated cipher suites. + * @param[out] cipher_suites_out Parsed cipher suites object (for MbedTLS), ignored for OpenSSL. + * @return 0 on success, non-zero on fail. */ -void nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites); +int nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, const char *cipher_suites, void **cipher_suites_out); /** * @brief Get the certificate's expiration time. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8fbe3ee5..cbea5b60 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -69,11 +69,11 @@ libnetconf2_test(NAME test_unix_socket) # tests depending on SSH/TLS if(ENABLE_SSH_TLS) - libnetconf2_test(NAME test_auth_ssh) libnetconf2_test(NAME test_authkeys) libnetconf2_test(NAME test_cert_exp_notif) libnetconf2_test(NAME test_ch PORT_COUNT 2) libnetconf2_test(NAME test_client_monitoring) + libnetconf2_test(NAME test_config PORT_COUNT 6) libnetconf2_test(NAME test_endpt_share_clients PORT_COUNT 4) libnetconf2_test(NAME test_ks_ts) if (LIBPAM_HAVE_CONFDIR) @@ -81,6 +81,7 @@ if(ENABLE_SSH_TLS) endif() libnetconf2_test(NAME test_replace) libnetconf2_test(NAME test_runtime_changes PORT_COUNT 2) + libnetconf2_test(NAME test_ssh) libnetconf2_test(NAME test_tls) libnetconf2_test(NAME test_two_channels) endif() diff --git a/tests/data/config.xml b/tests/data/config.xml new file mode 100644 index 00000000..3d6c99ed --- /dev/null +++ b/tests/data/config.xml @@ -0,0 +1,437 @@ + + + 420 + + + ssh + + + + 127.0.0.1 + %s + + + + + + ssh-rsa + + + ct:ssh-public-key-format + AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl + ct:rsa-private-key-format + MIIEpAIBAAKCAQEAz2r1QC4jO0MEyFAJ3TvBPRjpEg0Fo7hMJM2yd5DgT2u5JKu9VDmRXnnA4xW/XoqZJY3xcrPyWBxkGmFRfP7L09CleYex5brUXResr6khG46W0zkW9u6XR194hRMgwsAiKKvbzHl/sMl57Xsp9NRqSC9IoNFgJ75Kl/0j47qZV+WSLVEq9DIVzO3zUl+dAQ+hvCDtP3Y1HHTFHI04xr+90sQfWcy78Z4V7lCW8xCSSS4+qmo8hCFWiUmu97wN9yQg/Ks2q67LiE6I1SzwxZnh8EgKAeXT/OsqKenusqbl8yscXn+sjV3BPKE4/FBWASF7ICD9pwb1pONRGitFZN2BZQIDAQABAoIBAQC1jeTQYdI67EXCZLTNrqFNroFMaJOYJBiaWmat2+VL/3nWzHDzyVQiQyaAXyfcRCsbQSyn/zTQxUEmCis+4vRdGpPNVeZ0tN1wAuoH9F3jdiM1DhK44E0Qj1O5/+08Ktt7iDrjtzH699A+/ADUqh3Bw4mqIrss7pbyhQSmME5LLTbaWikZ8LgtUiF9f5JWzsqjPb6Yd8JEg0O+5lDngLfgEYevKCJxxBMtQQQ6gZCjQQWmir+/0NBezSHsoltPlw1m8Vs8Y5zz684yv33J/qxDM7+rbGbte2fSQ06OuK7abCZMyfXyWdp4cQpG1JZRxGp4Y8vQKvsU5ZOQUT/v7ur9AoGBAO+Li/vUzU3GlL7mxBlPTg5LavItWq6C7Rnwftjql7yPxrQ/+m5RZa0YujnqvZq5SpdpljCZbF9KYrFr92wgFqlt5uYptI4eD0/6xALEUcJJIlllTjiKtJmuyFkkD45WEn1IlDGAURQiDn6aqd40odlPsv4L5EdnQEQQz6Kfv6JLAoGBAN2qchHTKv1PBXfqRm0ABYSPyFhki2RqI4DWsbwykFXn3qP7tDDnmR/VMsAbApgTVW77LGffJ7DZXsqgzujwcqvLBKf8Wl5MRJg2jTe0GkKEBYqhGWNzBhuIwnIcKu/6HsEdFfCD93hwUPaVTBE+2ckXQVb9RSUCpGarXKk9cZ0PAoGBAJ/Hku29OdwA80KKpo7DSStbvtAe1HfGuOQueE2z3NZXiJC+hAqFnK5i6gSrwSCtK0XnldiA3bqJ4V66x2SF2tfUiMlJVDffcRNGDuxRir9vDMxYOF6alnBUFyruVLn6S4bpnH+QOYSWWtizzU58CODsulWeFPxTsJg2Jmkw6SAVAoGANWBGqX4k2uw9T9vM65BWw83vm0FSw3I/bFXGZJ/0W4tC9E+22xPZrm2jE9ktLbtyFhBLaBO3NgGRrs88I6FKq41uaJj+lbhdyB1SsfgfXqb1wqT6PRVEgjrTP7ECsdiTsUK0tr7AR3McO9RFhd2Ribec1zqTfM7/EW3wGRyfkAcCgYAtw6KO+5fXHE79v9pUdZAJ4PAc/KdHjv0zE9s5snwUrh7TO5fIB62di6nPBWLwD5InDZ9sNgxzTBt+0o2N6PsvKQFtfEBemKimmZShMytFkx9/KTRNR9se2qcBMiJsdAaz6hHUliYVWV3Ui+Uy+vYh5reuEhcvEjEzT6ySaCrZfg== + + + + Welcome to libnetconf2 test server over SSH! + + + 14 + + + user1 + + + + user1-key + ct:ssh-public-key-format + AAAAC3NzaC1lZDI1NTE5AAAAIOr46rptg6BsWhO1JMomuh3cuCYmeuO6JfOUPs/YO35w + + + + + $0$cleartext + + + + + + + + ssh + + + + ecdsa-sha2-nistp256 + + + sntrup761x25519-sha512@openssh.com + + + aes256-ctr + + + hmac-sha2-512 + + + + + + + tls + + + + 127.0.0.1 + %s + + + + + + + ct:subject-public-key-info-format + MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ== + ct:rsa-private-key-format + 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 + + + + + + + + tls-test-ca + MIIDnDCCAoSgAwIBAgIJAIjf7UNx4uabMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5vMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVyY2EwHhcNMTgxMTA1MDcyNjM5WhcNMjgxMTAyMDcyNjM5WjBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXDLeomt6893NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gyic4aOpy2s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCKA7vmNSgQOtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkRsWoF/0pglV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4wEXIhYwM51kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABo1MwUTAdBgNVHQ4EFgQU60nJ4q3ItcfaOOBjJSqadAPiMg8wHwYDVR0jBBgwFoAU60nJ4q3ItcfaOOBjJSqadAPiMg8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxIqIQ5SCXnKslZfrXiAEbB5dglxVOSa8me5a/70uHK/27JZ6veeIgRqZ4VgPHnBCa3m6EHr+mnTjjqSUcGIUiKV3g2Dumw8paqZC+Qv+Ib/NKquS1lO2Ry1wHBtXzn5KKHHyM1bWMDaDszirw2+pp22VdRrPZNA9NWXheEDYOLyQekyL2CfidhxhaXvUZyWgalLyF2XRZ5/jAT+NjfWw39EmWPUGk13Jm83OaFc1VdrXNCiD0sGCQ+BTCllDinQvR08yzd4fzA3YXthvX1dBu1SvqQAGOS7gssRCyv9uWI6MXta25X91eY1ZMz1euJ04mB8EdyYiZc0kzrb9dv5d0g== + + + + + + + tls-test-ee + MIIEQDCCAygCCQCV65JgDvfWkDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEwNTA3MzAzOVoXDTI4MTEwMjA3MzAzOVowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC+kqPqDL9GbWmqVQhp4qla4vYo4kFuh2HG48b7RLp/4l/guik4Hvq2aDVFD9sBcs3FeQbjoLH1Q4doUr8jG6VwJsfovE5SD3T8dVLs2dtpW0OyXTccb0I9lOVDMz6f6IUBe/m5vk8XNbdUII0NJ8y1dQ51VH3e784Bzu7PSdaMaFac4fkw8kJA9LxkWkv2FDFC7IBcVjRgtb/15EwODH849O6+VPEgX5gdozNj5bL45rKDBvvx0KjD7dFBGAIHbSjmjp7HHadfYKqvtQnMb83fRcK6wohxNP3vy13wBTtSOlvOg16Gb+2ZB0Or7wgOw19ZvEIcNgswPwhHfZQNcYMNVLCu02BSzwdY00IEqNM0J5B/W//KJF3uFF/ZqP7D2wO7w8j5UL2lpuxF7YrGecNT1Kr7ggHdkzcLlekkNu7wNWKAZlJ6+Kbun8PqZbamGXLG2Ur1aZDkyKyD9nyMzsRneAlxO+HbQhLojimUbsMm+wgL89zchLYkL/DSmsJlryA4qhvzHaaONBw4DV5UhSbLDpZtXVfrn+MAm8hLpqf+gUCThsFN8kDp9h9Tg9v01ai9jGb941HkFtGYUWHS5drSz3ZLnSI6i1/wKdbs9ns9YqDMqq2c305v5h7taMN0b40KuGSIME4K4cOsdfCprFYGZQgKjaadQwrsm4k1Jl7kMwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAtwH2u1o16jkABlqEGDIvAJSMwBmZzNTNHgOXtWDlkzWGsj+L1wc/DNjDRBkE31h4h7ASthhqi1nzzHYQ1hhPVhUUqI532AS/V7EPsBg3f+BI8gxqQ31TUBEQ4Ll6FtW36nqpJOe6Uui2rH2FonuUg2Av5BvDRil42Tu7fYW4WpSU3e00HiGJ0J0t+QjoKRnnoLJJqlmzk8Y4aIlQim7Azvrlo1WEtOhI3L9UE1GEqxLjRB45P36FSe1wfkgt7xmD0Xjy33Wh6Ae2Fvx7OfJ0K1zy0LHr4rDDJ3tLTqjPqHIFhaa73jGXwXk8sZnbAk542Oa6C6AjzNFyqV7T5Q5lg + + + + tls + + + + tlscmn:tls12 + tlscmn:tls13 + + + TLS_AES_128_GCM_SHA256 + + + + + + + 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 + x509c2n:specified + client + + + + + + + unix + + /tmp/netconf-test-server.sock + + 0770 + + + + testuser + netconf-user1 + netconf-user2 + + + + + + + + + persistent + + + ssh + + + 127.0.0.1 + %s + 127.0.0.1 + 0 + + + + + ssh-rsa + + + ct:ssh-public-key-format + AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl + ct:rsa-private-key-format + MIIEpAIBAAKCAQEAz2r1QC4jO0MEyFAJ3TvBPRjpEg0Fo7hMJM2yd5DgT2u5JKu9VDmRXnnA4xW/XoqZJY3xcrPyWBxkGmFRfP7L09CleYex5brUXResr6khG46W0zkW9u6XR194hRMgwsAiKKvbzHl/sMl57Xsp9NRqSC9IoNFgJ75Kl/0j47qZV+WSLVEq9DIVzO3zUl+dAQ+hvCDtP3Y1HHTFHI04xr+90sQfWcy78Z4V7lCW8xCSSS4+qmo8hCFWiUmu97wN9yQg/Ks2q67LiE6I1SzwxZnh8EgKAeXT/OsqKenusqbl8yscXn+sjV3BPKE4/FBWASF7ICD9pwb1pONRGitFZN2BZQIDAQABAoIBAQC1jeTQYdI67EXCZLTNrqFNroFMaJOYJBiaWmat2+VL/3nWzHDzyVQiQyaAXyfcRCsbQSyn/zTQxUEmCis+4vRdGpPNVeZ0tN1wAuoH9F3jdiM1DhK44E0Qj1O5/+08Ktt7iDrjtzH699A+/ADUqh3Bw4mqIrss7pbyhQSmME5LLTbaWikZ8LgtUiF9f5JWzsqjPb6Yd8JEg0O+5lDngLfgEYevKCJxxBMtQQQ6gZCjQQWmir+/0NBezSHsoltPlw1m8Vs8Y5zz684yv33J/qxDM7+rbGbte2fSQ06OuK7abCZMyfXyWdp4cQpG1JZRxGp4Y8vQKvsU5ZOQUT/v7ur9AoGBAO+Li/vUzU3GlL7mxBlPTg5LavItWq6C7Rnwftjql7yPxrQ/+m5RZa0YujnqvZq5SpdpljCZbF9KYrFr92wgFqlt5uYptI4eD0/6xALEUcJJIlllTjiKtJmuyFkkD45WEn1IlDGAURQiDn6aqd40odlPsv4L5EdnQEQQz6Kfv6JLAoGBAN2qchHTKv1PBXfqRm0ABYSPyFhki2RqI4DWsbwykFXn3qP7tDDnmR/VMsAbApgTVW77LGffJ7DZXsqgzujwcqvLBKf8Wl5MRJg2jTe0GkKEBYqhGWNzBhuIwnIcKu/6HsEdFfCD93hwUPaVTBE+2ckXQVb9RSUCpGarXKk9cZ0PAoGBAJ/Hku29OdwA80KKpo7DSStbvtAe1HfGuOQueE2z3NZXiJC+hAqFnK5i6gSrwSCtK0XnldiA3bqJ4V66x2SF2tfUiMlJVDffcRNGDuxRir9vDMxYOF6alnBUFyruVLn6S4bpnH+QOYSWWtizzU58CODsulWeFPxTsJg2Jmkw6SAVAoGANWBGqX4k2uw9T9vM65BWw83vm0FSw3I/bFXGZJ/0W4tC9E+22xPZrm2jE9ktLbtyFhBLaBO3NgGRrs88I6FKq41uaJj+lbhdyB1SsfgfXqb1wqT6PRVEgjrTP7ECsdiTsUK0tr7AR3McO9RFhd2Ribec1zqTfM7/EW3wGRyfkAcCgYAtw6KO+5fXHE79v9pUdZAJ4PAc/KdHjv0zE9s5snwUrh7TO5fIB62di6nPBWLwD5InDZ9sNgxzTBt+0o2N6PsvKQFtfEBemKimmZShMytFkx9/KTRNR9se2qcBMiJsdAaz6hHUliYVWV3Ui+Uy+vYh5reuEhcvEjEzT6ySaCrZfg== + + + + Welcome to libnetconf2 test server over SSH! + + + 14 + + + user1 + + + + + $0$cleartext + + + + + + + + ssh + + + + ecdsa-sha2-nistp256 + + + sntrup761x25519-sha512@openssh.com + + + aes256-ctr + + + hmac-sha2-512 + + + + + + + tls + + + 127.0.0.1 + %s + 127.0.0.1 + 0 + + + + + + ct:subject-public-key-info-format + MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ== + ct:rsa-private-key-format + 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 + + + + + + + + tls-test-ca + MIIDnDCCAoSgAwIBAgIJAIjf7UNx4uabMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5vMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVyY2EwHhcNMTgxMTA1MDcyNjM5WhcNMjgxMTAyMDcyNjM5WjBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXDLeomt6893NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gyic4aOpy2s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCKA7vmNSgQOtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkRsWoF/0pglV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4wEXIhYwM51kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABo1MwUTAdBgNVHQ4EFgQU60nJ4q3ItcfaOOBjJSqadAPiMg8wHwYDVR0jBBgwFoAU60nJ4q3ItcfaOOBjJSqadAPiMg8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxIqIQ5SCXnKslZfrXiAEbB5dglxVOSa8me5a/70uHK/27JZ6veeIgRqZ4VgPHnBCa3m6EHr+mnTjjqSUcGIUiKV3g2Dumw8paqZC+Qv+Ib/NKquS1lO2Ry1wHBtXzn5KKHHyM1bWMDaDszirw2+pp22VdRrPZNA9NWXheEDYOLyQekyL2CfidhxhaXvUZyWgalLyF2XRZ5/jAT+NjfWw39EmWPUGk13Jm83OaFc1VdrXNCiD0sGCQ+BTCllDinQvR08yzd4fzA3YXthvX1dBu1SvqQAGOS7gssRCyv9uWI6MXta25X91eY1ZMz1euJ04mB8EdyYiZc0kzrb9dv5d0g== + + + + + + + tls-test-ee + MIIEQDCCAygCCQCV65JgDvfWkDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEwNTA3MzAzOVoXDTI4MTEwMjA3MzAzOVowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC+kqPqDL9GbWmqVQhp4qla4vYo4kFuh2HG48b7RLp/4l/guik4Hvq2aDVFD9sBcs3FeQbjoLH1Q4doUr8jG6VwJsfovE5SD3T8dVLs2dtpW0OyXTccb0I9lOVDMz6f6IUBe/m5vk8XNbdUII0NJ8y1dQ51VH3e784Bzu7PSdaMaFac4fkw8kJA9LxkWkv2FDFC7IBcVjRgtb/15EwODH849O6+VPEgX5gdozNj5bL45rKDBvvx0KjD7dFBGAIHbSjmjp7HHadfYKqvtQnMb83fRcK6wohxNP3vy13wBTtSOlvOg16Gb+2ZB0Or7wgOw19ZvEIcNgswPwhHfZQNcYMNVLCu02BSzwdY00IEqNM0J5B/W//KJF3uFF/ZqP7D2wO7w8j5UL2lpuxF7YrGecNT1Kr7ggHdkzcLlekkNu7wNWKAZlJ6+Kbun8PqZbamGXLG2Ur1aZDkyKyD9nyMzsRneAlxO+HbQhLojimUbsMm+wgL89zchLYkL/DSmsJlryA4qhvzHaaONBw4DV5UhSbLDpZtXVfrn+MAm8hLpqf+gUCThsFN8kDp9h9Tg9v01ai9jGb941HkFtGYUWHS5drSz3ZLnSI6i1/wKdbs9ns9YqDMqq2c305v5h7taMN0b40KuGSIME4K4cOsdfCprFYGZQgKjaadQwrsm4k1Jl7kMwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAtwH2u1o16jkABlqEGDIvAJSMwBmZzNTNHgOXtWDlkzWGsj+L1wc/DNjDRBkE31h4h7ASthhqi1nzzHYQ1hhPVhUUqI532AS/V7EPsBg3f+BI8gxqQ31TUBEQ4Ll6FtW36nqpJOe6Uui2rH2FonuUg2Av5BvDRil42Tu7fYW4WpSU3e00HiGJ0J0t+QjoKRnnoLJJqlmzk8Y4aIlQim7Azvrlo1WEtOhI3L9UE1GEqxLjRB45P36FSe1wfkgt7xmD0Xjy33Wh6Ae2Fvx7OfJ0K1zy0LHr4rDDJ3tLTqjPqHIFhaa73jGXwXk8sZnbAk542Oa6C6AjzNFyqV7T5Q5lg + + + + tls + + + + tlscmn:tls12 + tlscmn:tls13 + + + TLS_AES_128_GCM_SHA256 + + + + + + + 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 + x509c2n:specified + client + + + + + + + + + + + first-listed + 37 + 10 + + + + periodic + + + ssh + + + 127.0.0.1 + %s + 127.0.0.1 + 0 + + + + + ssh-rsa + + + ct:ssh-public-key-format + AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl + ct:rsa-private-key-format + MIIEpAIBAAKCAQEAz2r1QC4jO0MEyFAJ3TvBPRjpEg0Fo7hMJM2yd5DgT2u5JKu9VDmRXnnA4xW/XoqZJY3xcrPyWBxkGmFRfP7L09CleYex5brUXResr6khG46W0zkW9u6XR194hRMgwsAiKKvbzHl/sMl57Xsp9NRqSC9IoNFgJ75Kl/0j47qZV+WSLVEq9DIVzO3zUl+dAQ+hvCDtP3Y1HHTFHI04xr+90sQfWcy78Z4V7lCW8xCSSS4+qmo8hCFWiUmu97wN9yQg/Ks2q67LiE6I1SzwxZnh8EgKAeXT/OsqKenusqbl8yscXn+sjV3BPKE4/FBWASF7ICD9pwb1pONRGitFZN2BZQIDAQABAoIBAQC1jeTQYdI67EXCZLTNrqFNroFMaJOYJBiaWmat2+VL/3nWzHDzyVQiQyaAXyfcRCsbQSyn/zTQxUEmCis+4vRdGpPNVeZ0tN1wAuoH9F3jdiM1DhK44E0Qj1O5/+08Ktt7iDrjtzH699A+/ADUqh3Bw4mqIrss7pbyhQSmME5LLTbaWikZ8LgtUiF9f5JWzsqjPb6Yd8JEg0O+5lDngLfgEYevKCJxxBMtQQQ6gZCjQQWmir+/0NBezSHsoltPlw1m8Vs8Y5zz684yv33J/qxDM7+rbGbte2fSQ06OuK7abCZMyfXyWdp4cQpG1JZRxGp4Y8vQKvsU5ZOQUT/v7ur9AoGBAO+Li/vUzU3GlL7mxBlPTg5LavItWq6C7Rnwftjql7yPxrQ/+m5RZa0YujnqvZq5SpdpljCZbF9KYrFr92wgFqlt5uYptI4eD0/6xALEUcJJIlllTjiKtJmuyFkkD45WEn1IlDGAURQiDn6aqd40odlPsv4L5EdnQEQQz6Kfv6JLAoGBAN2qchHTKv1PBXfqRm0ABYSPyFhki2RqI4DWsbwykFXn3qP7tDDnmR/VMsAbApgTVW77LGffJ7DZXsqgzujwcqvLBKf8Wl5MRJg2jTe0GkKEBYqhGWNzBhuIwnIcKu/6HsEdFfCD93hwUPaVTBE+2ckXQVb9RSUCpGarXKk9cZ0PAoGBAJ/Hku29OdwA80KKpo7DSStbvtAe1HfGuOQueE2z3NZXiJC+hAqFnK5i6gSrwSCtK0XnldiA3bqJ4V66x2SF2tfUiMlJVDffcRNGDuxRir9vDMxYOF6alnBUFyruVLn6S4bpnH+QOYSWWtizzU58CODsulWeFPxTsJg2Jmkw6SAVAoGANWBGqX4k2uw9T9vM65BWw83vm0FSw3I/bFXGZJ/0W4tC9E+22xPZrm2jE9ktLbtyFhBLaBO3NgGRrs88I6FKq41uaJj+lbhdyB1SsfgfXqb1wqT6PRVEgjrTP7ECsdiTsUK0tr7AR3McO9RFhd2Ribec1zqTfM7/EW3wGRyfkAcCgYAtw6KO+5fXHE79v9pUdZAJ4PAc/KdHjv0zE9s5snwUrh7TO5fIB62di6nPBWLwD5InDZ9sNgxzTBt+0o2N6PsvKQFtfEBemKimmZShMytFkx9/KTRNR9se2qcBMiJsdAaz6hHUliYVWV3Ui+Uy+vYh5reuEhcvEjEzT6ySaCrZfg== + + + + Welcome to libnetconf2 test server over SSH! + + + 14 + + + user1 + + + + user1-key + ct:ssh-public-key-format + AAAAC3NzaC1lZDI1NTE5AAAAIOr46rptg6BsWhO1JMomuh3cuCYmeuO6JfOUPs/YO35w + + + + + $0$cleartext + + + + + + + + ssh + + + + ecdsa-sha2-nistp256 + + + sntrup761x25519-sha512@openssh.com + + + aes256-ctr + + + hmac-sha2-512 + + + + + + + tls + + + 127.0.0.1 + %s + 127.0.0.1 + 0 + + + + + + ct:subject-public-key-info-format + MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ== + ct:rsa-private-key-format + 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 + + + + + + + + tls-test-ca + MIIDnDCCAoSgAwIBAgIJAIjf7UNx4uabMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5vMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVyY2EwHhcNMTgxMTA1MDcyNjM5WhcNMjgxMTAyMDcyNjM5WjBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXDLeomt6893NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gyic4aOpy2s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCKA7vmNSgQOtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkRsWoF/0pglV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4wEXIhYwM51kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABo1MwUTAdBgNVHQ4EFgQU60nJ4q3ItcfaOOBjJSqadAPiMg8wHwYDVR0jBBgwFoAU60nJ4q3ItcfaOOBjJSqadAPiMg8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxIqIQ5SCXnKslZfrXiAEbB5dglxVOSa8me5a/70uHK/27JZ6veeIgRqZ4VgPHnBCa3m6EHr+mnTjjqSUcGIUiKV3g2Dumw8paqZC+Qv+Ib/NKquS1lO2Ry1wHBtXzn5KKHHyM1bWMDaDszirw2+pp22VdRrPZNA9NWXheEDYOLyQekyL2CfidhxhaXvUZyWgalLyF2XRZ5/jAT+NjfWw39EmWPUGk13Jm83OaFc1VdrXNCiD0sGCQ+BTCllDinQvR08yzd4fzA3YXthvX1dBu1SvqQAGOS7gssRCyv9uWI6MXta25X91eY1ZMz1euJ04mB8EdyYiZc0kzrb9dv5d0g== + + + + + + + tls-test-ee + MIIEQDCCAygCCQCV65JgDvfWkDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEwNTA3MzAzOVoXDTI4MTEwMjA3MzAzOVowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC+kqPqDL9GbWmqVQhp4qla4vYo4kFuh2HG48b7RLp/4l/guik4Hvq2aDVFD9sBcs3FeQbjoLH1Q4doUr8jG6VwJsfovE5SD3T8dVLs2dtpW0OyXTccb0I9lOVDMz6f6IUBe/m5vk8XNbdUII0NJ8y1dQ51VH3e784Bzu7PSdaMaFac4fkw8kJA9LxkWkv2FDFC7IBcVjRgtb/15EwODH849O6+VPEgX5gdozNj5bL45rKDBvvx0KjD7dFBGAIHbSjmjp7HHadfYKqvtQnMb83fRcK6wohxNP3vy13wBTtSOlvOg16Gb+2ZB0Or7wgOw19ZvEIcNgswPwhHfZQNcYMNVLCu02BSzwdY00IEqNM0J5B/W//KJF3uFF/ZqP7D2wO7w8j5UL2lpuxF7YrGecNT1Kr7ggHdkzcLlekkNu7wNWKAZlJ6+Kbun8PqZbamGXLG2Ur1aZDkyKyD9nyMzsRneAlxO+HbQhLojimUbsMm+wgL89zchLYkL/DSmsJlryA4qhvzHaaONBw4DV5UhSbLDpZtXVfrn+MAm8hLpqf+gUCThsFN8kDp9h9Tg9v01ai9jGb941HkFtGYUWHS5drSz3ZLnSI6i1/wKdbs9ns9YqDMqq2c305v5h7taMN0b40KuGSIME4K4cOsdfCprFYGZQgKjaadQwrsm4k1Jl7kMwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAtwH2u1o16jkABlqEGDIvAJSMwBmZzNTNHgOXtWDlkzWGsj+L1wc/DNjDRBkE31h4h7ASthhqi1nzzHYQ1hhPVhUUqI532AS/V7EPsBg3f+BI8gxqQ31TUBEQ4Ll6FtW36nqpJOe6Uui2rH2FonuUg2Av5BvDRil42Tu7fYW4WpSU3e00HiGJ0J0t+QjoKRnnoLJJqlmzk8Y4aIlQim7Azvrlo1WEtOhI3L9UE1GEqxLjRB45P36FSe1wfkgt7xmD0Xjy33Wh6Ae2Fvx7OfJ0K1zy0LHr4rDDJ3tLTqjPqHIFhaa73jGXwXk8sZnbAk542Oa6C6AjzNFyqV7T5Q5lg + + + + tls + + + + tlscmn:tls12 + tlscmn:tls13 + + + TLS_AES_128_GCM_SHA256 + + + + + + + 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 + x509c2n:specified + client + + + + + + + + + 45 + 0000-01-01T00:00:00+00:00 + 666 + + + + first-listed + 37 + 10 + + + + diff --git a/tests/ln2_test.c b/tests/ln2_test.c index 938c35d2..3bfc450c 100644 --- a/tests/ln2_test.c +++ b/tests/ln2_test.c @@ -97,6 +97,24 @@ ln2_glob_test_server_thread(void *arg) return NULL; } +void * +ln2_glob_test_server_thread_fail(void *arg) +{ + NC_MSG_TYPE msgtype; + struct nc_session *session = NULL; + struct ln2_test_ctx *test_ctx = arg; + + /* wait for the client to be ready to connect */ + pthread_barrier_wait(&test_ctx->barrier); + + /* try to accept a session, but we expect it to fail */ + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, test_ctx->ctx, &session); + assert(msgtype == NC_MSG_ERROR); + assert(!session); + + return NULL; +} + int ln2_glob_test_setup(struct ln2_test_ctx **test_ctx) { diff --git a/tests/ln2_test.h b/tests/ln2_test.h index d5667191..efcec05c 100644 --- a/tests/ln2_test.h +++ b/tests/ln2_test.h @@ -52,7 +52,15 @@ int ln2_glob_test_get_ports(int port_count, ...); * @param[in] arg Test context. * @return NULL. */ -void * ln2_glob_test_server_thread(void *arg); +void *ln2_glob_test_server_thread(void *arg); + +/** + * @brief Default server thread for the tests, expecting the client connection to fail. + * + * @param[in] arg Test context. + * @return NULL. + */ +void *ln2_glob_test_server_thread_fail(void *arg); /** * @brief Default setup of the test context (init server, client, libyang context and a barrier). diff --git a/tests/test_auth_ssh.c b/tests/test_auth_ssh.c deleted file mode 100644 index ec615743..00000000 --- a/tests/test_auth_ssh.c +++ /dev/null @@ -1,354 +0,0 @@ -/** - * @file test_auth_ssh.c - * @author Roman Janota - * @brief libnetconf2 SSH authentication test - * - * @copyright - * Copyright (c) 2023 - 2024 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 "ln2_test.h" - -struct test_auth_ssh_data { - const char *username; - const char *pubkey_path; - const char *privkey_path; - int check_banner; -}; - -int TEST_PORT = 10050; -const char *TEST_PORT_STR = "10050"; - -static char * -auth_password(const char *username, const char *hostname, void *priv) -{ - (void) hostname; - (void) priv; - - /* set the reply to password authentication */ - if (!strcmp(username, "test_pw")) { - return strdup("testpw"); - } else { - return NULL; - } -} - -static void -check_banner(const struct nc_session *session) -{ - const char *banner; - - banner = nc_session_ssh_get_banner(session); - assert_non_null(banner); - - assert_string_equal(banner, "SSH-2.0-test-banner"); -} - -static void * -client_thread_ssh(void *arg) -{ - int ret; - struct nc_session *session = NULL; - struct ln2_test_ctx *test_ctx = arg; - struct test_auth_ssh_data *test_data = test_ctx->test_data; - - /* 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(test_data->username); - assert_int_equal(ret, 0); - - if (test_data->pubkey_path) { - ret = nc_client_ssh_add_keypair(test_data->pubkey_path, test_data->privkey_path); - assert_int_equal(ret, 0); - } else { - nc_client_ssh_set_auth_password_clb(auth_password, NULL); - } - - pthread_barrier_wait(&test_ctx->barrier); - session = nc_connect_ssh("127.0.0.1", TEST_PORT, NULL); - assert_non_null(session); - - if (test_data->check_banner) { - check_banner(session); - } - - nc_session_free(session, NULL); - return NULL; -} - -static void -test_nc_auth_ssh_password(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct ln2_test_ctx *test_ctx = *state; - struct test_auth_ssh_data *test_data = test_ctx->test_data; - - test_data->username = "test_pw"; - - ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); - assert_int_equal(ret, 0); - ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); - assert_int_equal(ret, 0); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static void -test_nc_auth_ssh_none(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct ln2_test_ctx *test_ctx = *state; - struct test_auth_ssh_data *test_data = test_ctx->test_data; - - test_data->username = "test_none"; - - ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); - assert_int_equal(ret, 0); - ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); - assert_int_equal(ret, 0); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static void -test_nc_auth_ssh_rsa_pubkey(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct ln2_test_ctx *test_ctx = *state; - struct test_auth_ssh_data *test_data = test_ctx->test_data; - - test_data->username = "test_pk"; - test_data->pubkey_path = TESTS_DIR "/data/key_rsa.pub"; - test_data->privkey_path = TESTS_DIR "/data/key_rsa"; - - ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); - assert_int_equal(ret, 0); - ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); - assert_int_equal(ret, 0); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static void -test_nc_auth_ssh_ec256_pubkey(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct ln2_test_ctx *test_ctx = *state; - struct test_auth_ssh_data *test_data = test_ctx->test_data; - - test_data->username = "test_ec256"; - test_data->pubkey_path = TESTS_DIR "/data/id_ecdsa256.pub"; - test_data->privkey_path = TESTS_DIR "/data/id_ecdsa256"; - - ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); - assert_int_equal(ret, 0); - ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); - assert_int_equal(ret, 0); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static void -test_nc_auth_ssh_ec384_pubkey(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct ln2_test_ctx *test_ctx = *state; - struct test_auth_ssh_data *test_data = test_ctx->test_data; - - test_data->username = "test_ec384"; - test_data->pubkey_path = TESTS_DIR "/data/id_ecdsa384.pub"; - test_data->privkey_path = TESTS_DIR "/data/id_ecdsa384"; - - ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); - assert_int_equal(ret, 0); - ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); - assert_int_equal(ret, 0); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static void -test_nc_auth_ssh_ec521_pubkey(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct ln2_test_ctx *test_ctx = *state; - struct test_auth_ssh_data *test_data = test_ctx->test_data; - - test_data->username = "test_ec521"; - test_data->pubkey_path = TESTS_DIR "/data/id_ecdsa521.pub"; - test_data->privkey_path = TESTS_DIR "/data/id_ecdsa521"; - - ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); - assert_int_equal(ret, 0); - ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); - assert_int_equal(ret, 0); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static void -test_nc_auth_ssh_ed25519_pubkey(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct ln2_test_ctx *test_ctx = *state; - struct test_auth_ssh_data *test_data = test_ctx->test_data; - - test_data->username = "test_ed25519"; - test_data->pubkey_path = TESTS_DIR "/data/id_ed25519.pub"; - test_data->privkey_path = TESTS_DIR "/data/id_ed25519"; - - ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); - assert_int_equal(ret, 0); - ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); - assert_int_equal(ret, 0); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static void -test_nc_auth_ssh_banner(void **state) -{ - int ret, i; - pthread_t tids[2]; - struct ln2_test_ctx *test_ctx = *state; - struct test_auth_ssh_data *test_data = test_ctx->test_data; - - test_data->username = "test_ed25519"; - test_data->pubkey_path = TESTS_DIR "/data/id_ed25519.pub"; - test_data->privkey_path = TESTS_DIR "/data/id_ed25519"; - test_data->check_banner = 1; - - ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); - assert_int_equal(ret, 0); - ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); - assert_int_equal(ret, 0); - - for (i = 0; i < 2; i++) { - pthread_join(tids[i], NULL); - } -} - -static int -setup_ssh(void **state) -{ - int ret; - struct lyd_node *tree = NULL; - struct ln2_test_ctx *test_ctx; - struct test_auth_ssh_data *test_data; - - ret = ln2_glob_test_setup(&test_ctx); - assert_int_equal(ret, 0); - - test_data = calloc(1, sizeof *test_data); - assert_non_null(test_data); - - test_ctx->test_data = test_data; - test_ctx->free_test_data = ln2_glob_test_free_test_data; - *state = test_ctx; - - ret = nc_server_config_add_address_port(test_ctx->ctx, "endpt", NC_TI_SSH, "127.0.0.1", TEST_PORT, &tree); - assert_int_equal(ret, 0); - - ret = nc_server_config_add_ssh_hostkey(test_ctx->ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); - assert_int_equal(ret, 0); - - ret = nc_server_config_add_ssh_user_pubkey(test_ctx->ctx, "endpt", "test_pk", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); - assert_int_equal(ret, 0); - - ret = nc_server_config_add_ssh_user_pubkey(test_ctx->ctx, "endpt", "test_ec256", "pubkey", TESTS_DIR "/data/id_ecdsa256.pub", &tree); - assert_int_equal(ret, 0); - - ret = nc_server_config_add_ssh_user_pubkey(test_ctx->ctx, "endpt", "test_ec384", "pubkey", TESTS_DIR "/data/id_ecdsa384.pub", &tree); - assert_int_equal(ret, 0); - - ret = nc_server_config_add_ssh_user_pubkey(test_ctx->ctx, "endpt", "test_ec521", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); - assert_int_equal(ret, 0); - - ret = nc_server_config_add_ssh_user_pubkey(test_ctx->ctx, "endpt", "test_ed25519", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); - assert_int_equal(ret, 0); - - ret = nc_server_config_add_ssh_user_password(test_ctx->ctx, "endpt", "test_pw", "testpw", &tree); - assert_int_equal(ret, 0); - - ret = lyd_new_path(tree, test_ctx->ctx, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='endpt']/ssh/" - "ssh-server-parameters/server-identity/libnetconf2-netconf-server:banner", "test-banner", 0, NULL); - assert_int_equal(ret, 0); - - ret = lyd_new_path(tree, test_ctx->ctx, "/ietf-netconf-server:netconf-server/listen/endpoints/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 */ - ret = nc_server_config_setup_data(tree); - assert_int_equal(ret, 0); - - lyd_free_all(tree); - - return 0; -} - -int -main(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_nc_auth_ssh_password, setup_ssh, ln2_glob_test_teardown), - cmocka_unit_test_setup_teardown(test_nc_auth_ssh_none, setup_ssh, ln2_glob_test_teardown), - cmocka_unit_test_setup_teardown(test_nc_auth_ssh_rsa_pubkey, setup_ssh, ln2_glob_test_teardown), - cmocka_unit_test_setup_teardown(test_nc_auth_ssh_ec256_pubkey, setup_ssh, ln2_glob_test_teardown), - cmocka_unit_test_setup_teardown(test_nc_auth_ssh_ec384_pubkey, setup_ssh, ln2_glob_test_teardown), - cmocka_unit_test_setup_teardown(test_nc_auth_ssh_ec521_pubkey, setup_ssh, ln2_glob_test_teardown), - cmocka_unit_test_setup_teardown(test_nc_auth_ssh_ed25519_pubkey, setup_ssh, ln2_glob_test_teardown), - cmocka_unit_test_setup_teardown(test_nc_auth_ssh_banner, setup_ssh, ln2_glob_test_teardown) - }; - - /* try to get ports from the environment, otherwise use the default */ - if (ln2_glob_test_get_ports(1, &TEST_PORT, &TEST_PORT_STR)) { - return 1; - } - - setenv("CMOCKA_TEST_ABORT", "1", 1); - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/tests/test_config.c b/tests/test_config.c new file mode 100644 index 00000000..35093e09 --- /dev/null +++ b/tests/test_config.c @@ -0,0 +1,983 @@ +/** + * @file test_config.c + * @author Roman Janota + * @brief libnetconf2 YANG data configuration test + * + * @copyright + * Copyright (c) 2025 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 "ln2_test.h" + +int TEST_PORT = 10050, TEST_PORT_2 = 10051, TEST_PORT_3 = 10052, + TEST_PORT_4 = 10053, TEST_PORT_5 = 10054, TEST_PORT_6 = 10055; +const char *TEST_PORT_STR = "10050", *TEST_PORT_2_STR = "10051", + *TEST_PORT_3_STR = "10052", *TEST_PORT_4_STR = "10053", + *TEST_PORT_5_STR = "10054", *TEST_PORT_6_STR = "10055"; + +const char *keystore_truststore_data = + "" + "" + "" + "hostkey" + "ct:ssh-public-key-format" + "AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl" + "ct:rsa-private-key-format" + "MIIEpAIBAAKCAQEAz2r1QC4jO0MEyFAJ3TvBPRjpEg0Fo7hMJM2yd5DgT2u5JKu9VDmRXnnA4xW/XoqZJY3xcrPyWBxkGmFRfP7L09CleYex5brUXResr6khG46W0zkW9u6XR194hRMgwsAiKKvbzHl/sMl57Xsp9NRqSC9IoNFgJ75Kl/0j47qZV+WSLVEq9DIVzO3zUl+dAQ+hvCDtP3Y1HHTFHI04xr+90sQfWcy78Z4V7lCW8xCSSS4+qmo8hCFWiUmu97wN9yQg/Ks2q67LiE6I1SzwxZnh8EgKAeXT/OsqKenusqbl8yscXn+sjV3BPKE4/FBWASF7ICD9pwb1pONRGitFZN2BZQIDAQABAoIBAQC1jeTQYdI67EXCZLTNrqFNroFMaJOYJBiaWmat2+VL/3nWzHDzyVQiQyaAXyfcRCsbQSyn/zTQxUEmCis+4vRdGpPNVeZ0tN1wAuoH9F3jdiM1DhK44E0Qj1O5/+08Ktt7iDrjtzH699A+/ADUqh3Bw4mqIrss7pbyhQSmME5LLTbaWikZ8LgtUiF9f5JWzsqjPb6Yd8JEg0O+5lDngLfgEYevKCJxxBMtQQQ6gZCjQQWmir+/0NBezSHsoltPlw1m8Vs8Y5zz684yv33J/qxDM7+rbGbte2fSQ06OuK7abCZMyfXyWdp4cQpG1JZRxGp4Y8vQKvsU5ZOQUT/v7ur9AoGBAO+Li/vUzU3GlL7mxBlPTg5LavItWq6C7Rnwftjql7yPxrQ/+m5RZa0YujnqvZq5SpdpljCZbF9KYrFr92wgFqlt5uYptI4eD0/6xALEUcJJIlllTjiKtJmuyFkkD45WEn1IlDGAURQiDn6aqd40odlPsv4L5EdnQEQQz6Kfv6JLAoGBAN2qchHTKv1PBXfqRm0ABYSPyFhki2RqI4DWsbwykFXn3qP7tDDnmR/VMsAbApgTVW77LGffJ7DZXsqgzujwcqvLBKf8Wl5MRJg2jTe0GkKEBYqhGWNzBhuIwnIcKu/6HsEdFfCD93hwUPaVTBE+2ckXQVb9RSUCpGarXKk9cZ0PAoGBAJ/Hku29OdwA80KKpo7DSStbvtAe1HfGuOQueE2z3NZXiJC+hAqFnK5i6gSrwSCtK0XnldiA3bqJ4V66x2SF2tfUiMlJVDffcRNGDuxRir9vDMxYOF6alnBUFyruVLn6S4bpnH+QOYSWWtizzU58CODsulWeFPxTsJg2Jmkw6SAVAoGANWBGqX4k2uw9T9vM65BWw83vm0FSw3I/bFXGZJ/0W4tC9E+22xPZrm2jE9ktLbtyFhBLaBO3NgGRrs88I6FKq41uaJj+lbhdyB1SsfgfXqb1wqT6PRVEgjrTP7ECsdiTsUK0tr7AR3McO9RFhd2Ribec1zqTfM7/EW3wGRyfkAcCgYAtw6KO+5fXHE79v9pUdZAJ4PAc/KdHjv0zE9s5snwUrh7TO5fIB62di6nPBWLwD5InDZ9sNgxzTBt+0o2N6PsvKQFtfEBemKimmZShMytFkx9/KTRNR9se2qcBMiJsdAaz6hHUliYVWV3Ui+Uy+vYh5reuEhcvEjEzT6ySaCrZfg==" + "" + "" + "" + "" + "" + "" + "pkbag" + "Test public key bag" + "" + "ED25519 key" + "ct:ssh-public-key-format" + "AAAAC3NzaC1lZDI1NTE5AAAAIOr46rptg6BsWhO1JMomuh3cuCYmeuO6JfOUPs/YO35w" + "" + "" + "" + ""; + +const char *data = + "" + " " + " " + " " + " e1" + " " + " " + " " + " 127.0.0.1" + " %s" + " " + " " + " " + " " + " " + " hostkey1" + " " + " hostkey" + " " + " " + " " + " " + " " + " " + " user1" + " " + " pkbag" + " " + " " + " " + " " + " " + " " + " " + " " + " " + "\n"; + +const char *data2 = + "\n" + " \n" + " \n" + " \n" + " e1\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " hostkey1\n" + " \n" + " hostkey\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " user1\n" + " \n" + " pkbag\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " e2\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " 0\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " hostkey1\n" + " \n" + " hostkey\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " user1\n" + " \n" + " pkbag\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ssh-rsa\n" // invalid, not set before + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; + +const char *data3 = + "\n" + " \n" + " \n" + " \n" + " e1\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " hostkey1\n" + " \n" + " hostkey\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " user1\n" + " \n" + " pkbag\n" + " \n" + " \n" + " $0$cleartextpassword\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +const char *diff1 = + "\n" + " \n" + " 420\n" + " \n" + " \n" + " test-e1\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " 17\n" + " 42\n" + " 59\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " hostkey1\n" + " \n" + " hostkey\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " user1\n" + " \n" + " pkbag\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " e2\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " 0\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " hostkey1\n" + " \n" + " hostkey\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " user1\n" + " \n" + " pkbag\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ssh-rsa\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static void * +client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct ln2_test_ctx *test_ctx = 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("user1"); + 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); + + /* wait for the server to reach polling */ + pthread_barrier_wait(&test_ctx->barrier); + + /* connect */ + session = nc_connect_ssh("127.0.0.1", TEST_PORT, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + return NULL; +} + +static void +test_rollback(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct lyd_node *tree = NULL; + struct ln2_test_ctx *test_ctx = *state; + char *data_filled = NULL; + + /* print port number into the diff */ + ret = asprintf(&data_filled, data, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + /* setup base configuration */ + ret = lyd_parse_data_mem(test_ctx->ctx, data_filled, LYD_XML, LYD_PARSE_ONLY, 0, &tree); + assert_int_equal(ret, 0); + + /* add all implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + lyd_free_all(tree); + free(data_filled); + + /* print port number into the new data */ + ret = asprintf(&data_filled, data2, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + /* edit the configuration, try to delete existing endpoint and add a new one with invalid operation, + * which should cause the whole edit to be rejected and rolled back */ + ret = lyd_parse_data_mem(test_ctx->ctx, data_filled, LYD_XML, LYD_PARSE_ONLY, 0, &tree); + assert_int_equal(ret, 0); + + /* add all implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 1); + lyd_free_all(tree); + free(data_filled); + + /* start client and server threads, the client should be able to connect */ + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void * +conn_preserve_client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct ln2_test_ctx *test_ctx = arg; + struct nc_rpc *rpc; + uint64_t msgid; + NC_MSG_TYPE msgtype; + struct lyd_node *envp = NULL, *op = NULL; + + /* 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("user1"); + 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); + + /* wait for the server to reach polling */ + pthread_barrier_wait(&test_ctx->barrier); + + /* connect */ + session = nc_connect_ssh("127.0.0.1", TEST_PORT, NULL); + assert_non_null(session); + + /* create a simple get-config rpc */ + rpc = nc_rpc_getconfig(NC_DATASTORE_RUNNING, NULL, 0, NC_PARAMTYPE_CONST); + assert_non_null(rpc); + + /* wait until the server applied its new config */ + pthread_barrier_wait(&test_ctx->barrier); + + /* send the rpc */ + ret = nc_send_rpc(session, rpc, 1000, &msgid); + assert_int_equal(ret, NC_MSG_RPC); + + /* receive the reply */ + msgtype = nc_recv_reply(session, rpc, msgid, 1000, &envp, &op); + assert_int_equal(msgtype, NC_MSG_REPLY); + + /* wait for the server thread to finish */ + pthread_barrier_wait(&test_ctx->barrier); + + lyd_free_all(envp); + lyd_free_all(op); + nc_rpc_free(rpc); + nc_session_free(session, NULL); + return NULL; +} + +static struct nc_server_reply * +glob_rpc(struct lyd_node *rpc, struct nc_session *session) +{ + (void)rpc; + (void)session; + return nc_server_reply_ok(); +} + +static void * +conn_preserve_server_thread(void *arg) +{ + int ret; + NC_MSG_TYPE msgtype; + struct nc_session *session = NULL; + struct nc_pollsession *ps = NULL; + struct ln2_test_ctx *test_ctx = arg; + struct lyd_node *tree = NULL; + char *data_filled = NULL; + + /* set the global rpc cb */ + nc_set_global_rpc_clb(glob_rpc); + + ps = nc_ps_new(); + assert_non_null(ps); + + /* wait for the client to be ready to connect */ + pthread_barrier_wait(&test_ctx->barrier); + + /* accept a session and add it to the poll session structure */ + msgtype = nc_accept(NC_ACCEPT_TIMEOUT, test_ctx->ctx, &session); + assert_int_equal(msgtype, NC_MSG_HELLO); + + ret = nc_ps_add_session(ps, session); + assert_int_equal(ret, 0); + + /* poll until the session is fully established */ + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + } while (ret & NC_PSPOLL_RPC); + + /* print port number into the new data */ + ret = asprintf(&data_filled, data3, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + /* connection established, change the server configuration */ + ret = lyd_parse_data_mem(test_ctx->ctx, data_filled, LYD_XML, LYD_PARSE_ONLY, 0, &tree); + assert_int_equal(ret, 0); + + /* add all implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + lyd_free_all(tree); + free(data_filled); + + /* wait for the client */ + pthread_barrier_wait(&test_ctx->barrier); + + /* poll until we receive the rpc from the client */ + do { + ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL); + } while (!(ret & NC_PSPOLL_RPC)); + + /* wait for the client */ + pthread_barrier_wait(&test_ctx->barrier); + + nc_ps_clear(ps, 1, NULL); + nc_ps_free(ps); + return NULL; +} + +static void +test_preserve_conn(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct lyd_node *tree = NULL; + struct ln2_test_ctx *test_ctx = *state; + char *data_filled = NULL; + + /* print port number into the diff */ + ret = asprintf(&data_filled, data, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + /* setup base configuration */ + ret = lyd_parse_data_mem(test_ctx->ctx, data_filled, LYD_XML, LYD_PARSE_ONLY, 0, &tree); + assert_int_equal(ret, 0); + + /* add all implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + lyd_free_all(tree); + free(data_filled); + + ret = pthread_create(&tids[0], NULL, conn_preserve_client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, conn_preserve_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_transport_params_oper_get(void **state) +{ + int ret; + struct lyd_node *algs = NULL; + const char *expected_algs; + struct ln2_test_ctx *test_ctx = *state; + char *buf; + + /* check ssh supported algorithms */ + expected_algs = "" + "" + "ssh-ed25519" + "ecdsa-sha2-nistp521" + "ecdsa-sha2-nistp384" + "ecdsa-sha2-nistp256" + "sk-ssh-ed25519@openssh.com" + "sk-ecdsa-sha2-nistp256@openssh.com" + "rsa-sha2-512" + "rsa-sha2-256" + "ssh-rsa" + "ssh-ed25519-cert-v01@openssh.com" + "sk-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" + "sk-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" + "" + "" + "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" + "" + "" + "diffie-hellman-group-exchange-sha1" + "curve25519-sha256" + "curve25519-sha256@libssh.org" + "sntrup761x25519-sha512" + "sntrup761x25519-sha512@openssh.com" + "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" + "diffie-hellman-group14-sha1" + "diffie-hellman-group1-sha1" + "" + "" + "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" + "none" + "" + ""; + ret = nc_server_config_oper_get_supported_ssh_algs(test_ctx->ctx, &algs); + assert_int_equal(ret, 0); + ret = lyd_print_mem(&buf, algs, LYD_XML, LYD_PRINT_SHRINK); + + assert_string_equal(buf, expected_algs); + free(buf); + lyd_free_all(algs); + + /* for tls supported algorithms only try getting them without comparing */ + ret = nc_server_config_oper_get_supported_tls_algs(test_ctx->ctx, &algs); + assert_int_equal(ret, 0); + lyd_free_all(algs); +} + +static void +read_config_file(const char *path, char **mem) +{ + FILE *f; + long fsize; + + f = fopen(path, "r"); + assert_non_null(f); + + fseek(f, 0, SEEK_END); + fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + *mem = malloc(fsize + 1); + assert_non_null(*mem); + + fread(*mem, 1, fsize, f); + (*mem)[fsize] = '\0'; + + fclose(f); +} + +static void +test_config_all_nodes(void **state) +{ + int ret; + struct lyd_node *tree = NULL, *dup = NULL, *n; + struct lyd_meta *meta; + struct ln2_test_ctx *test_ctx = *state; + char *mem = NULL, *mem_filled = NULL; + + /* read the config file into memory */ + read_config_file(TESTS_DIR "/data/config.xml", &mem); + + /* print the port numbers into the config */ + ret = asprintf(&mem_filled, mem, TEST_PORT_STR, TEST_PORT_2_STR, TEST_PORT_3_STR, + TEST_PORT_4_STR, TEST_PORT_5_STR, TEST_PORT_6_STR); + assert_int_not_equal(ret, -1); + + /* load configuration from memory */ + ret = lyd_parse_data_mem(test_ctx->ctx, mem_filled, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree); + assert_int_equal(ret, 0); + + /* apply the configuration */ + ret = nc_server_config_setup_data(tree); + assert_int_equal(ret, 0); + + /* apply it again, should succeed without changes */ + ret = nc_server_config_setup_data(tree); + assert_int_equal(ret, 0); + + /* duplicate the configuration */ + ret = lyd_dup_single(tree, NULL, LYD_DUP_RECURSIVE, &dup); + assert_int_equal(ret, 0); + + /* add the delete operation to the root */ + ret = lyd_new_meta(test_ctx->ctx, dup, NULL, "yang:operation", "delete", 0, &meta); + assert_int_equal(ret, 0); + + /* should delete everything without errors */ + ret = nc_server_config_setup_diff(dup); + assert_int_equal(ret, 0); + + /* change the meta to create, should add everything back without errors */ + ret = lyd_change_meta(meta, "create"); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_diff(dup); + assert_int_equal(ret, 0); + + /* set the operation to none */ + ret = lyd_change_meta(meta, "none"); + assert_int_equal(ret, 0); + + /* try to delete the SSH endpoint only */ + ret = lyd_find_path(dup, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='ssh']", 0, &n); + assert_int_equal(ret, 0); + + ret = lyd_new_meta(test_ctx->ctx, n, NULL, "yang:operation", "delete", 0, NULL); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_diff(dup); + assert_int_equal(ret, 0); + + lyd_free_tree(n); + + /* try to delete the TLS endpoint only */ + ret = lyd_find_path(dup, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='tls']", 0, &n); + assert_int_equal(ret, 0); + + ret = lyd_new_meta(test_ctx->ctx, n, NULL, "yang:operation", "delete", 0, NULL); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_diff(dup); + assert_int_equal(ret, 0); + + lyd_free_tree(n); + + /* try to delete call home ssh endpoint only */ + ret = lyd_find_path(dup, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='persistent']/" + "endpoints/endpoint[name='ssh']", 0, &n); + assert_int_equal(ret, 0); + + ret = lyd_new_meta(test_ctx->ctx, n, NULL, "yang:operation", "delete", 0, NULL); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_diff(dup); + assert_int_equal(ret, 0); + + lyd_free_tree(n); + + /* try to delete call home tls endpoint only */ + ret = lyd_find_path(dup, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='persistent']/" + "endpoints/endpoint[name='tls']", 0, &n); + assert_int_equal(ret, 0); + + ret = lyd_new_meta(test_ctx->ctx, n, NULL, "yang:operation", "delete", 0, NULL); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_diff(dup); + assert_int_equal(ret, 0); + + lyd_free_tree(n); + + /* try to delete a persistent call home client */ + ret = lyd_find_path(dup, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='persistent']", 0, &n); + assert_int_equal(ret, 0); + + ret = lyd_new_meta(test_ctx->ctx, n, NULL, "yang:operation", "delete", 0, NULL); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_diff(dup); + assert_int_equal(ret, 0); + + lyd_free_tree(n); + + /* try to delete a periodic call home client */ + ret = lyd_find_path(dup, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='periodic']", 0, &n); + assert_int_equal(ret, 0); + + ret = lyd_new_meta(test_ctx->ctx, n, NULL, "yang:operation", "delete", 0, NULL); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_diff(dup); + assert_int_equal(ret, 0); + + free(mem); + free(mem_filled); + lyd_free_all(dup); + lyd_free_all(tree); +} + +static void * +unsupported_asymkey_client_thread(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct ln2_test_ctx *test_ctx = 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("user1"); + assert_int_equal(ret, 0); + + /* wait for the server to reach polling */ + pthread_barrier_wait(&test_ctx->barrier); + + /* connect, expecting fail */ + session = nc_connect_ssh("127.0.0.1", TEST_PORT, NULL); + assert_null(session); + + return NULL; +} + +static void +test_unusupported_asymkey_format(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct ln2_test_ctx *test_ctx = *state; + const char *data, *mod; + pthread_t tids[2]; + char *data_filled = NULL; + + /* create a module defining libnetconf2 unsupported key formats */ + mod = + "module a {yang-version 1.1; namespace urn:a; prefix a; import ietf-crypto-types {prefix ct;}" + "identity unsupported-public-key-format {base ct:public-key-format;}" + "identity unsupported-private-key-format {base ct:private-key-format;}}"; + + /* load the module */ + ret = lys_parse_mem(test_ctx->ctx, mod, LYS_IN_YANG, NULL); + assert_int_equal(ret, 0); + + /* prepare data with unsupported asymmetric key formats */ + data = + "" + " " + " " + " UNSUPPORTED" + " a:unsupported-public-key-format" + " base64blob==" + " a:unsupported-private-key-format" + " base64blob==" + " " + " " + " " + ""; + + /* parse the data */ + ret = lyd_parse_data_mem(test_ctx->ctx, data, LYD_XML, LYD_PARSE_ONLY, 0, &tree); + assert_int_equal(ret, 0); + + /* applying the data should succeed, unsupported formats are allowed */ + ret = nc_server_config_setup_data(tree); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + /* use the asymmetric key in netconf-server config */ + data = + "" + " " + " " + " " + " e1" + " " + " " + " " + " 127.0.0.1" + " %s" + " " + " " + " " + " " + " " + " hostkey1" + " " + " UNSUPPORTED" // use it here + " " + " " + " " + " " + " " + " " + " user1" + " " // no keys or password + " " + " " + " " + " " + " " + " " + " " + " " + "\n"; + + /* print port number into the data */ + ret = asprintf(&data_filled, data, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + /* parse the data */ + ret = lyd_parse_data_mem(test_ctx->ctx, data_filled, LYD_XML, LYD_PARSE_ONLY, 0, &tree); + assert_int_equal(ret, 0); + + /* add all implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* applying the data should succeed, unsupported key formats are allowed */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + /* start client and server threads, the client should NOT be able to connect */ + ret = pthread_create(&tids[0], NULL, unsupported_asymkey_client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread_fail, *state); + assert_int_equal(ret, 0); + + for (int i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } + + free(data_filled); + lyd_free_all(tree); +} + +static int +setup_f(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct ln2_test_ctx *test_ctx; + + ret = ln2_glob_test_setup(&test_ctx); + assert_int_equal(ret, 0); + + *state = test_ctx; + + /* setup keystore and truststore */ + ret = lyd_parse_data_mem(test_ctx->ctx, keystore_truststore_data, LYD_XML, + LYD_PARSE_ONLY, 0, &tree); + assert_int_equal(ret, 0); + + /* add all implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + ret = nc_server_config_setup_data(tree); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_rollback, setup_f, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_preserve_conn, setup_f, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_transport_params_oper_get, setup_f, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_config_all_nodes, setup_f, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_unusupported_asymkey_format, setup_f, ln2_glob_test_teardown), + }; + + /* try to get ports from the environment, otherwise use the default */ + if (ln2_glob_test_get_ports(1, &TEST_PORT, &TEST_PORT_STR)) { + return 1; + } + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/test_ssh.c b/tests/test_ssh.c new file mode 100644 index 00000000..5aa8cca6 --- /dev/null +++ b/tests/test_ssh.c @@ -0,0 +1,700 @@ +/** + * @file test_ssh.c + * @author Roman Janota + * @brief libnetconf2 NETCONF over SSH test + * + * @copyright + * Copyright (c) 2023 - 2024 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 "ln2_test.h" + +struct test_ssh_data { + const char *username; + const char *pubkey_path; + const char *privkey_path; + int check_banner; + int expect_fail; +}; + +int TEST_PORT = 10050; +const char *TEST_PORT_STR = "10050"; + +static char * +auth_password(const char *username, const char *hostname, void *priv) +{ + (void) hostname; + (void) priv; + + /* set the reply to password authentication */ + if (!strcmp(username, "test_pw")) { + return strdup("testpw"); + } else { + return NULL; + } +} + +static void +check_banner(const struct nc_session *session) +{ + const char *banner; + + banner = nc_session_ssh_get_banner(session); + assert_non_null(banner); + + assert_string_equal(banner, "SSH-2.0-test-banner"); +} + +static void * +client_thread_ssh(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct ln2_test_ctx *test_ctx = arg; + struct test_ssh_data *test_data = test_ctx->test_data; + + /* 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(test_data->username); + assert_int_equal(ret, 0); + + if (test_data->pubkey_path) { + ret = nc_client_ssh_add_keypair(test_data->pubkey_path, test_data->privkey_path); + assert_int_equal(ret, 0); + } else { + nc_client_ssh_set_auth_password_clb(auth_password, NULL); + } + + /* wait for the server to be ready */ + pthread_barrier_wait(&test_ctx->barrier); + + /* connect */ + session = nc_connect_ssh("127.0.0.1", TEST_PORT, NULL); + + if (test_data->expect_fail) { + /* the connection is expected to fail */ + assert_null(session); + return NULL; + } + + assert_non_null(session); + + if (test_data->check_banner) { + check_banner(session); + } + + nc_session_free(session, NULL); + return NULL; +} + +static void +test_password(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct ln2_test_ctx *test_ctx = *state; + struct test_ssh_data *test_data = test_ctx->test_data; + + test_data->username = "test_pw"; + + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_none(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct ln2_test_ctx *test_ctx = *state; + struct test_ssh_data *test_data = test_ctx->test_data; + + test_data->username = "test_none"; + + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_rsa_pubkey(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct ln2_test_ctx *test_ctx = *state; + struct test_ssh_data *test_data = test_ctx->test_data; + + test_data->username = "test_pk"; + test_data->pubkey_path = TESTS_DIR "/data/key_rsa.pub"; + test_data->privkey_path = TESTS_DIR "/data/key_rsa"; + + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_ec256_pubkey(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct ln2_test_ctx *test_ctx = *state; + struct test_ssh_data *test_data = test_ctx->test_data; + + test_data->username = "test_ec256"; + test_data->pubkey_path = TESTS_DIR "/data/id_ecdsa256.pub"; + test_data->privkey_path = TESTS_DIR "/data/id_ecdsa256"; + + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_ec384_pubkey(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct ln2_test_ctx *test_ctx = *state; + struct test_ssh_data *test_data = test_ctx->test_data; + + test_data->username = "test_ec384"; + test_data->pubkey_path = TESTS_DIR "/data/id_ecdsa384.pub"; + test_data->privkey_path = TESTS_DIR "/data/id_ecdsa384"; + + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_ec521_pubkey(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct ln2_test_ctx *test_ctx = *state; + struct test_ssh_data *test_data = test_ctx->test_data; + + test_data->username = "test_ec521"; + test_data->pubkey_path = TESTS_DIR "/data/id_ecdsa521.pub"; + test_data->privkey_path = TESTS_DIR "/data/id_ecdsa521"; + + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_ed25519_pubkey(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct ln2_test_ctx *test_ctx = *state; + struct test_ssh_data *test_data = test_ctx->test_data; + + test_data->username = "test_ed25519"; + test_data->pubkey_path = TESTS_DIR "/data/id_ed25519.pub"; + test_data->privkey_path = TESTS_DIR "/data/id_ed25519"; + + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_banner(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct ln2_test_ctx *test_ctx = *state; + struct test_ssh_data *test_data = test_ctx->test_data; + + test_data->username = "test_ed25519"; + test_data->pubkey_path = TESTS_DIR "/data/id_ed25519.pub"; + test_data->privkey_path = TESTS_DIR "/data/id_ed25519"; + test_data->check_banner = 1; + + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static void +test_transport_params(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct ln2_test_ctx *test_ctx = *state; + struct test_ssh_data *test_data = test_ctx->test_data; + const char *diff; + char *diff_filled; + struct lyd_node *tree = NULL; + + /* setup a client */ + test_data->username = "test_pw"; + + /* try deleting a MAC alg, none was set before so should fail */ + diff = "\n" + " \n" + " \n" + " \n" + " endpt\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " hostkey\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" + " test_pw\n" + " \n" + " $0$testpw\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " hmac-sha1\n" // not set before + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + /* print port number into the diff */ + ret = asprintf(&diff_filled, diff, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + ret = lyd_parse_data_mem(test_ctx->ctx, diff_filled, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree); + assert_int_equal(ret, 0); + + /* add implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* apply the diff, should fail */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 1); + + free(diff_filled); + lyd_free_all(tree); + + /* set only a RSA host key supported algorithm, even though an ECDSA host key is used */ + diff = "\n" + " \n" + " \n" + " \n" + " endpt\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " hostkey\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" + " test_pw\n" + " \n" + " $0$testpw\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ecdsa-sha2-nistp384\n" // restrict to ECDSA + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + /* print port number into the diff */ + ret = asprintf(&diff_filled, diff, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + ret = lyd_parse_data_mem(test_ctx->ctx, diff_filled, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree); + assert_int_equal(ret, 0); + + /* add implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* apply the diff, should succeed */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + /* create client and server threads, the client should not be able to connect if the server + * transport parameters are applied correctly */ + test_data->expect_fail = 1; + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread_fail, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } + + test_data->expect_fail = 0; + free(diff_filled); + lyd_free_all(tree); + + /* unset the host key algorithm restriction, since there should be no algs set now, + * the default ones will be used and the client should be able to connect */ + diff = "\n" + " \n" + " \n" + " \n" + " endpt\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " hostkey\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" + " test_pw\n" + " \n" + " $0$testpw\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ecdsa-sha2-nistp384\n" // remove restriction + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + /* print port number into the diff */ + ret = asprintf(&diff_filled, diff, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + ret = lyd_parse_data_mem(test_ctx->ctx, diff_filled, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree); + assert_int_equal(ret, 0); + + /* add implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* apply the diff, should succeed */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + /* create client and server threads, the client should be able to connect now */ + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } + + free(diff_filled); + lyd_free_all(tree); + + /* set "reasonable" (= should be able to connect) transport parameters, overwriting the libssh defaults */ + diff = "\n" + " \n" + " \n" + " \n" + " endpt\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " hostkey\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" + " test_pw\n" + " \n" + " $0$testpw\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ecdsa-sha2-nistp256\n" + " \n" + " \n" + " curve25519-sha256\n" + " \n" + " \n" + " aes256-ctr\n" + " \n" + " \n" + " hmac-sha2-512\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + /* print port number into the diff */ + ret = asprintf(&diff_filled, diff, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + ret = lyd_parse_data_mem(test_ctx->ctx, diff_filled, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree); + assert_int_equal(ret, 0); + + /* add implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* apply the diff, should succeed */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + /* create client and server threads, the client should be able to connect now */ + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } + + free(diff_filled); + lyd_free_all(tree); +} + +static int +setup_ssh(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct ln2_test_ctx *test_ctx; + struct test_ssh_data *test_data; + + ret = ln2_glob_test_setup(&test_ctx); + assert_int_equal(ret, 0); + + test_data = calloc(1, sizeof *test_data); + assert_non_null(test_data); + + test_ctx->test_data = test_data; + test_ctx->free_test_data = ln2_glob_test_free_test_data; + *state = test_ctx; + + ret = nc_server_config_add_address_port(test_ctx->ctx, "endpt", NC_TI_SSH, "127.0.0.1", TEST_PORT, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_add_ssh_hostkey(test_ctx->ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_add_ssh_user_pubkey(test_ctx->ctx, "endpt", "test_pk", "pubkey", TESTS_DIR "/data/key_rsa.pub", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_add_ssh_user_pubkey(test_ctx->ctx, "endpt", "test_ec256", "pubkey", TESTS_DIR "/data/id_ecdsa256.pub", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_add_ssh_user_pubkey(test_ctx->ctx, "endpt", "test_ec384", "pubkey", TESTS_DIR "/data/id_ecdsa384.pub", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_add_ssh_user_pubkey(test_ctx->ctx, "endpt", "test_ec521", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_add_ssh_user_pubkey(test_ctx->ctx, "endpt", "test_ed25519", "pubkey", TESTS_DIR "/data/id_ed25519.pub", &tree); + assert_int_equal(ret, 0); + + ret = nc_server_config_add_ssh_user_password(test_ctx->ctx, "endpt", "test_pw", "testpw", &tree); + assert_int_equal(ret, 0); + + ret = lyd_new_path(tree, test_ctx->ctx, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='endpt']/ssh/" + "ssh-server-parameters/server-identity/libnetconf2-netconf-server:banner", "test-banner", 0, NULL); + assert_int_equal(ret, 0); + + ret = lyd_new_path(tree, test_ctx->ctx, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='endpt']/ssh/" + "ssh-server-parameters/client-authentication/users/user[name='test_none']/none", NULL, 0, NULL); + assert_int_equal(ret, 0); + + /* add all the default nodes/np containers */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup_data(tree); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_password, setup_ssh, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_none, setup_ssh, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_rsa_pubkey, setup_ssh, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_ec256_pubkey, setup_ssh, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_ec384_pubkey, setup_ssh, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_ec521_pubkey, setup_ssh, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_ed25519_pubkey, setup_ssh, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_banner, setup_ssh, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_transport_params, setup_ssh, ln2_glob_test_teardown), + }; + + /* try to get ports from the environment, otherwise use the default */ + if (ln2_glob_test_get_ports(1, &TEST_PORT, &TEST_PORT_STR)) { + return 1; + } + + setenv("CMOCKA_TEST_ABORT", "1", 1); + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/test_tls.c b/tests/test_tls.c index e7bdc9ce..5900b006 100644 --- a/tests/test_tls.c +++ b/tests/test_tls.c @@ -21,6 +21,10 @@ #include #include +#ifdef HAVE_MBEDTLS +#include +#endif /* HAVE_MBEDTLS */ + #include #include "ln2_test.h" @@ -31,6 +35,7 @@ struct test_tls_data { struct lyd_node *tree; /**< Test data for the server configuration. */ int root_ca; /**< Whether the root CA is used (client-only). */ int intermediate_ca; /**< Whether the intermediate CA is used (client-only). */ + int expect_fail; /**< Whether the connection is expected to fail. */ }; int TEST_PORT = 10050; @@ -42,6 +47,7 @@ client_thread(void *arg) int ret; struct nc_session *session = NULL; struct ln2_test_ctx *test_ctx = arg; + struct test_tls_data *test_data = test_ctx->test_data; ret = nc_client_set_schema_searchpath(MODULES_DIR); assert_int_equal(ret, 0); @@ -56,6 +62,13 @@ client_thread(void *arg) pthread_barrier_wait(&test_ctx->barrier); session = nc_connect_tls("127.0.0.1", TEST_PORT, NULL); + + if (test_data->expect_fail) { + /* the connection is expected to fail */ + assert_null(session); + return NULL; + } + assert_non_null(session); nc_session_free(session, NULL); @@ -356,6 +369,609 @@ test_nc_tls_keylog(void **state) check_keylog_file(KEYLOG_FILENAME); } +static void +test_cipher_suites(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct ln2_test_ctx *test_ctx = *state; + struct test_tls_data *test_data = test_ctx->test_data; + const char *diff; + char *diff_filled; + struct lyd_node *tree = NULL; + + /* try deleting a cipher suite when none is configured */ + diff = "\n" + " \n" + " \n" + " \n" + " endpt\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ct:rsa-private-key-format\n" + " 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\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_ca\n" + " MIIDnDCCAoSgAwIBAgIJAIjf7UNx4uabMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5vMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVyY2EwHhcNMTgxMTA1MDcyNjM5WhcNMjgxMTAyMDcyNjM5WjBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXDLeomt6893NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gyic4aOpy2s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCKA7vmNSgQOtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkRsWoF/0pglV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4wEXIhYwM51kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABo1MwUTAdBgNVHQ4EFgQU60nJ4q3ItcfaOOBjJSqadAPiMg8wHwYDVR0jBBgwFoAU60nJ4q3ItcfaOOBjJSqadAPiMg8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxIqIQ5SCXnKslZfrXiAEbB5dglxVOSa8me5a/70uHK/27JZ6veeIgRqZ4VgPHnBCa3m6EHr+mnTjjqSUcGIUiKV3g2Dumw8paqZC+Qv+Ib/NKquS1lO2Ry1wHBtXzn5KKHHyM1bWMDaDszirw2+pp22VdRrPZNA9NWXheEDYOLyQekyL2CfidhxhaXvUZyWgalLyF2XRZ5/jAT+NjfWw39EmWPUGk13Jm83OaFc1VdrXNCiD0sGCQ+BTCllDinQvR08yzd4fzA3YXthvX1dBu1SvqQAGOS7gssRCyv9uWI6MXta25X91eY1ZMz1euJ04mB8EdyYiZc0kzrb9dv5d0g==\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_cert\n" + " MIIEQDCCAygCCQCV65JgDvfWkDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEwNTA3MzAzOVoXDTI4MTEwMjA3MzAzOVowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC+kqPqDL9GbWmqVQhp4qla4vYo4kFuh2HG48b7RLp/4l/guik4Hvq2aDVFD9sBcs3FeQbjoLH1Q4doUr8jG6VwJsfovE5SD3T8dVLs2dtpW0OyXTccb0I9lOVDMz6f6IUBe/m5vk8XNbdUII0NJ8y1dQ51VH3e784Bzu7PSdaMaFac4fkw8kJA9LxkWkv2FDFC7IBcVjRgtb/15EwODH849O6+VPEgX5gdozNj5bL45rKDBvvx0KjD7dFBGAIHbSjmjp7HHadfYKqvtQnMb83fRcK6wohxNP3vy13wBTtSOlvOg16Gb+2ZB0Or7wgOw19ZvEIcNgswPwhHfZQNcYMNVLCu02BSzwdY00IEqNM0J5B/W//KJF3uFF/ZqP7D2wO7w8j5UL2lpuxF7YrGecNT1Kr7ggHdkzcLlekkNu7wNWKAZlJ6+Kbun8PqZbamGXLG2Ur1aZDkyKyD9nyMzsRneAlxO+HbQhLojimUbsMm+wgL89zchLYkL/DSmsJlryA4qhvzHaaONBw4DV5UhSbLDpZtXVfrn+MAm8hLpqf+gUCThsFN8kDp9h9Tg9v01ai9jGb941HkFtGYUWHS5drSz3ZLnSI6i1/wKdbs9ns9YqDMqq2c305v5h7taMN0b40KuGSIME4K4cOsdfCprFYGZQgKjaadQwrsm4k1Jl7kMwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAtwH2u1o16jkABlqEGDIvAJSMwBmZzNTNHgOXtWDlkzWGsj+L1wc/DNjDRBkE31h4h7ASthhqi1nzzHYQ1hhPVhUUqI532AS/V7EPsBg3f+BI8gxqQ31TUBEQ4Ll6FtW36nqpJOe6Uui2rH2FonuUg2Av5BvDRil42Tu7fYW4WpSU3e00HiGJ0J0t+QjoKRnnoLJJqlmzk8Y4aIlQim7Azvrlo1WEtOhI3L9UE1GEqxLjRB45P36FSe1wfkgt7xmD0Xjy33Wh6Ae2Fvx7OfJ0K1zy0LHr4rDDJ3tLTqjPqHIFhaa73jGXwXk8sZnbAk542Oa6C6AjzNFyqV7T5Q5lg\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " TLS_AES_128_GCM_SHA256\n" // not set before + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 1\n" + " 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\n" + " x509c2n:specified\n" + " client\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + /* print port number into the diff */ + ret = asprintf(&diff_filled, diff, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + ret = lyd_parse_data_mem(test_ctx->ctx, diff_filled, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree); + assert_int_equal(ret, 0); + + /* add implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* apply the diff, should fail */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 1); + + free(diff_filled); + lyd_free_all(tree); + + /* reset to original config */ + ret = nc_server_config_setup_data(test_data->tree); + assert_int_equal(ret, 0); + + /* try deleting a cipher suite that was not set before */ + diff = "\n" + " \n" + " \n" + " \n" + " endpt\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ct:rsa-private-key-format\n" + " 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\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_ca\n" + " MIIDnDCCAoSgAwIBAgIJAIjf7UNx4uabMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5vMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVyY2EwHhcNMTgxMTA1MDcyNjM5WhcNMjgxMTAyMDcyNjM5WjBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXDLeomt6893NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gyic4aOpy2s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCKA7vmNSgQOtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkRsWoF/0pglV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4wEXIhYwM51kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABo1MwUTAdBgNVHQ4EFgQU60nJ4q3ItcfaOOBjJSqadAPiMg8wHwYDVR0jBBgwFoAU60nJ4q3ItcfaOOBjJSqadAPiMg8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxIqIQ5SCXnKslZfrXiAEbB5dglxVOSa8me5a/70uHK/27JZ6veeIgRqZ4VgPHnBCa3m6EHr+mnTjjqSUcGIUiKV3g2Dumw8paqZC+Qv+Ib/NKquS1lO2Ry1wHBtXzn5KKHHyM1bWMDaDszirw2+pp22VdRrPZNA9NWXheEDYOLyQekyL2CfidhxhaXvUZyWgalLyF2XRZ5/jAT+NjfWw39EmWPUGk13Jm83OaFc1VdrXNCiD0sGCQ+BTCllDinQvR08yzd4fzA3YXthvX1dBu1SvqQAGOS7gssRCyv9uWI6MXta25X91eY1ZMz1euJ04mB8EdyYiZc0kzrb9dv5d0g==\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_cert\n" + " MIIEQDCCAygCCQCV65JgDvfWkDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEwNTA3MzAzOVoXDTI4MTEwMjA3MzAzOVowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC+kqPqDL9GbWmqVQhp4qla4vYo4kFuh2HG48b7RLp/4l/guik4Hvq2aDVFD9sBcs3FeQbjoLH1Q4doUr8jG6VwJsfovE5SD3T8dVLs2dtpW0OyXTccb0I9lOVDMz6f6IUBe/m5vk8XNbdUII0NJ8y1dQ51VH3e784Bzu7PSdaMaFac4fkw8kJA9LxkWkv2FDFC7IBcVjRgtb/15EwODH849O6+VPEgX5gdozNj5bL45rKDBvvx0KjD7dFBGAIHbSjmjp7HHadfYKqvtQnMb83fRcK6wohxNP3vy13wBTtSOlvOg16Gb+2ZB0Or7wgOw19ZvEIcNgswPwhHfZQNcYMNVLCu02BSzwdY00IEqNM0J5B/W//KJF3uFF/ZqP7D2wO7w8j5UL2lpuxF7YrGecNT1Kr7ggHdkzcLlekkNu7wNWKAZlJ6+Kbun8PqZbamGXLG2Ur1aZDkyKyD9nyMzsRneAlxO+HbQhLojimUbsMm+wgL89zchLYkL/DSmsJlryA4qhvzHaaONBw4DV5UhSbLDpZtXVfrn+MAm8hLpqf+gUCThsFN8kDp9h9Tg9v01ai9jGb941HkFtGYUWHS5drSz3ZLnSI6i1/wKdbs9ns9YqDMqq2c305v5h7taMN0b40KuGSIME4K4cOsdfCprFYGZQgKjaadQwrsm4k1Jl7kMwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAtwH2u1o16jkABlqEGDIvAJSMwBmZzNTNHgOXtWDlkzWGsj+L1wc/DNjDRBkE31h4h7ASthhqi1nzzHYQ1hhPVhUUqI532AS/V7EPsBg3f+BI8gxqQ31TUBEQ4Ll6FtW36nqpJOe6Uui2rH2FonuUg2Av5BvDRil42Tu7fYW4WpSU3e00HiGJ0J0t+QjoKRnnoLJJqlmzk8Y4aIlQim7Azvrlo1WEtOhI3L9UE1GEqxLjRB45P36FSe1wfkgt7xmD0Xjy33Wh6Ae2Fvx7OfJ0K1zy0LHr4rDDJ3tLTqjPqHIFhaa73jGXwXk8sZnbAk542Oa6C6AjzNFyqV7T5Q5lg\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " TLS_AES_128_GCM_SHA256\n" // should succeed + " TLS_CHACHA20_POLY1305_SHA256\n" // not set before, should fail + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 1\n" + " 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\n" + " x509c2n:specified\n" + " client\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + /* print port number into the diff */ + ret = asprintf(&diff_filled, diff, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + ret = lyd_parse_data_mem(test_ctx->ctx, diff_filled, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree); + assert_int_equal(ret, 0); + + /* add implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* apply the diff, should fail */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 1); + + free(diff_filled); + lyd_free_all(tree); + + /* reset to original config */ + ret = nc_server_config_setup_data(test_data->tree); + assert_int_equal(ret, 0); + + /* set one commonly used TLS1.3 and one TLS1.2 cipher suite, should be able to connect */ + diff = "\n" + " \n" + " \n" + " \n" + " endpt\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ct:rsa-private-key-format\n" + " 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\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_ca\n" + " MIIDnDCCAoSgAwIBAgIJAIjf7UNx4uabMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5vMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVyY2EwHhcNMTgxMTA1MDcyNjM5WhcNMjgxMTAyMDcyNjM5WjBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXDLeomt6893NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gyic4aOpy2s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCKA7vmNSgQOtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkRsWoF/0pglV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4wEXIhYwM51kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABo1MwUTAdBgNVHQ4EFgQU60nJ4q3ItcfaOOBjJSqadAPiMg8wHwYDVR0jBBgwFoAU60nJ4q3ItcfaOOBjJSqadAPiMg8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxIqIQ5SCXnKslZfrXiAEbB5dglxVOSa8me5a/70uHK/27JZ6veeIgRqZ4VgPHnBCa3m6EHr+mnTjjqSUcGIUiKV3g2Dumw8paqZC+Qv+Ib/NKquS1lO2Ry1wHBtXzn5KKHHyM1bWMDaDszirw2+pp22VdRrPZNA9NWXheEDYOLyQekyL2CfidhxhaXvUZyWgalLyF2XRZ5/jAT+NjfWw39EmWPUGk13Jm83OaFc1VdrXNCiD0sGCQ+BTCllDinQvR08yzd4fzA3YXthvX1dBu1SvqQAGOS7gssRCyv9uWI6MXta25X91eY1ZMz1euJ04mB8EdyYiZc0kzrb9dv5d0g==\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_cert\n" + " MIIEQDCCAygCCQCV65JgDvfWkDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEwNTA3MzAzOVoXDTI4MTEwMjA3MzAzOVowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC+kqPqDL9GbWmqVQhp4qla4vYo4kFuh2HG48b7RLp/4l/guik4Hvq2aDVFD9sBcs3FeQbjoLH1Q4doUr8jG6VwJsfovE5SD3T8dVLs2dtpW0OyXTccb0I9lOVDMz6f6IUBe/m5vk8XNbdUII0NJ8y1dQ51VH3e784Bzu7PSdaMaFac4fkw8kJA9LxkWkv2FDFC7IBcVjRgtb/15EwODH849O6+VPEgX5gdozNj5bL45rKDBvvx0KjD7dFBGAIHbSjmjp7HHadfYKqvtQnMb83fRcK6wohxNP3vy13wBTtSOlvOg16Gb+2ZB0Or7wgOw19ZvEIcNgswPwhHfZQNcYMNVLCu02BSzwdY00IEqNM0J5B/W//KJF3uFF/ZqP7D2wO7w8j5UL2lpuxF7YrGecNT1Kr7ggHdkzcLlekkNu7wNWKAZlJ6+Kbun8PqZbamGXLG2Ur1aZDkyKyD9nyMzsRneAlxO+HbQhLojimUbsMm+wgL89zchLYkL/DSmsJlryA4qhvzHaaONBw4DV5UhSbLDpZtXVfrn+MAm8hLpqf+gUCThsFN8kDp9h9Tg9v01ai9jGb941HkFtGYUWHS5drSz3ZLnSI6i1/wKdbs9ns9YqDMqq2c305v5h7taMN0b40KuGSIME4K4cOsdfCprFYGZQgKjaadQwrsm4k1Jl7kMwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAtwH2u1o16jkABlqEGDIvAJSMwBmZzNTNHgOXtWDlkzWGsj+L1wc/DNjDRBkE31h4h7ASthhqi1nzzHYQ1hhPVhUUqI532AS/V7EPsBg3f+BI8gxqQ31TUBEQ4Ll6FtW36nqpJOe6Uui2rH2FonuUg2Av5BvDRil42Tu7fYW4WpSU3e00HiGJ0J0t+QjoKRnnoLJJqlmzk8Y4aIlQim7Azvrlo1WEtOhI3L9UE1GEqxLjRB45P36FSe1wfkgt7xmD0Xjy33Wh6Ae2Fvx7OfJ0K1zy0LHr4rDDJ3tLTqjPqHIFhaa73jGXwXk8sZnbAk542Oa6C6AjzNFyqV7T5Q5lg\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\n" + " TLS_AES_256_GCM_SHA384\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 1\n" + " 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\n" + " x509c2n:specified\n" + " client\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + /* print port number into the diff */ + ret = asprintf(&diff_filled, diff, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + ret = lyd_parse_data_mem(test_ctx->ctx, diff_filled, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree); + assert_int_equal(ret, 0); + + /* add implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* apply the diff */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + free(diff_filled); + lyd_free_all(tree); + + /* should be able to connect */ + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } + + /* reset to original config */ + ret = nc_server_config_setup_data(test_data->tree); + assert_int_equal(ret, 0); +} + +static void +test_tls_version(void **state) +{ + int ret, i; + pthread_t tids[2]; + struct ln2_test_ctx *test_ctx = *state; + struct test_tls_data *test_data = test_ctx->test_data; + const char *diff; + char *diff_filled; + struct lyd_node *tree = NULL; + + /* set TLS1.2 and check if connection works */ + diff = "\n" + " \n" + " \n" + " \n" + " endpt\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ct:rsa-private-key-format\n" + " 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\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_ca\n" + " MIIDnDCCAoSgAwIBAgIJAIjf7UNx4uabMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5vMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVyY2EwHhcNMTgxMTA1MDcyNjM5WhcNMjgxMTAyMDcyNjM5WjBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXDLeomt6893NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gyic4aOpy2s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCKA7vmNSgQOtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkRsWoF/0pglV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4wEXIhYwM51kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABo1MwUTAdBgNVHQ4EFgQU60nJ4q3ItcfaOOBjJSqadAPiMg8wHwYDVR0jBBgwFoAU60nJ4q3ItcfaOOBjJSqadAPiMg8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxIqIQ5SCXnKslZfrXiAEbB5dglxVOSa8me5a/70uHK/27JZ6veeIgRqZ4VgPHnBCa3m6EHr+mnTjjqSUcGIUiKV3g2Dumw8paqZC+Qv+Ib/NKquS1lO2Ry1wHBtXzn5KKHHyM1bWMDaDszirw2+pp22VdRrPZNA9NWXheEDYOLyQekyL2CfidhxhaXvUZyWgalLyF2XRZ5/jAT+NjfWw39EmWPUGk13Jm83OaFc1VdrXNCiD0sGCQ+BTCllDinQvR08yzd4fzA3YXthvX1dBu1SvqQAGOS7gssRCyv9uWI6MXta25X91eY1ZMz1euJ04mB8EdyYiZc0kzrb9dv5d0g==\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_cert\n" + " MIIEQDCCAygCCQCV65JgDvfWkDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEwNTA3MzAzOVoXDTI4MTEwMjA3MzAzOVowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC+kqPqDL9GbWmqVQhp4qla4vYo4kFuh2HG48b7RLp/4l/guik4Hvq2aDVFD9sBcs3FeQbjoLH1Q4doUr8jG6VwJsfovE5SD3T8dVLs2dtpW0OyXTccb0I9lOVDMz6f6IUBe/m5vk8XNbdUII0NJ8y1dQ51VH3e784Bzu7PSdaMaFac4fkw8kJA9LxkWkv2FDFC7IBcVjRgtb/15EwODH849O6+VPEgX5gdozNj5bL45rKDBvvx0KjD7dFBGAIHbSjmjp7HHadfYKqvtQnMb83fRcK6wohxNP3vy13wBTtSOlvOg16Gb+2ZB0Or7wgOw19ZvEIcNgswPwhHfZQNcYMNVLCu02BSzwdY00IEqNM0J5B/W//KJF3uFF/ZqP7D2wO7w8j5UL2lpuxF7YrGecNT1Kr7ggHdkzcLlekkNu7wNWKAZlJ6+Kbun8PqZbamGXLG2Ur1aZDkyKyD9nyMzsRneAlxO+HbQhLojimUbsMm+wgL89zchLYkL/DSmsJlryA4qhvzHaaONBw4DV5UhSbLDpZtXVfrn+MAm8hLpqf+gUCThsFN8kDp9h9Tg9v01ai9jGb941HkFtGYUWHS5drSz3ZLnSI6i1/wKdbs9ns9YqDMqq2c305v5h7taMN0b40KuGSIME4K4cOsdfCprFYGZQgKjaadQwrsm4k1Jl7kMwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAtwH2u1o16jkABlqEGDIvAJSMwBmZzNTNHgOXtWDlkzWGsj+L1wc/DNjDRBkE31h4h7ASthhqi1nzzHYQ1hhPVhUUqI532AS/V7EPsBg3f+BI8gxqQ31TUBEQ4Ll6FtW36nqpJOe6Uui2rH2FonuUg2Av5BvDRil42Tu7fYW4WpSU3e00HiGJ0J0t+QjoKRnnoLJJqlmzk8Y4aIlQim7Azvrlo1WEtOhI3L9UE1GEqxLjRB45P36FSe1wfkgt7xmD0Xjy33Wh6Ae2Fvx7OfJ0K1zy0LHr4rDDJ3tLTqjPqHIFhaa73jGXwXk8sZnbAk542Oa6C6AjzNFyqV7T5Q5lg\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " tlscmn:tls12\n" // set to TLS1.2 + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 1\n" + " 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\n" + " x509c2n:specified\n" + " client\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + /* print port number into the diff */ + ret = asprintf(&diff_filled, diff, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + ret = lyd_parse_data_mem(test_ctx->ctx, diff_filled, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree); + assert_int_equal(ret, 0); + + /* add implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* apply the diff */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + free(diff_filled); + lyd_free_all(tree); + + /* should be able to connect */ + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } + + /* reset to original config */ + ret = nc_server_config_setup_data(test_data->tree); + assert_int_equal(ret, 0); + + /* set TLS1.2 with TLS1.3 ciphers and check that connection fails */ + diff = "\n" + " \n" + " \n" + " \n" + " endpt\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ct:rsa-private-key-format\n" + " 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\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_ca\n" + " MIIDnDCCAoSgAwIBAgIJAIjf7UNx4uabMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5vMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVyY2EwHhcNMTgxMTA1MDcyNjM5WhcNMjgxMTAyMDcyNjM5WjBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXDLeomt6893NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gyic4aOpy2s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCKA7vmNSgQOtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkRsWoF/0pglV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4wEXIhYwM51kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABo1MwUTAdBgNVHQ4EFgQU60nJ4q3ItcfaOOBjJSqadAPiMg8wHwYDVR0jBBgwFoAU60nJ4q3ItcfaOOBjJSqadAPiMg8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxIqIQ5SCXnKslZfrXiAEbB5dglxVOSa8me5a/70uHK/27JZ6veeIgRqZ4VgPHnBCa3m6EHr+mnTjjqSUcGIUiKV3g2Dumw8paqZC+Qv+Ib/NKquS1lO2Ry1wHBtXzn5KKHHyM1bWMDaDszirw2+pp22VdRrPZNA9NWXheEDYOLyQekyL2CfidhxhaXvUZyWgalLyF2XRZ5/jAT+NjfWw39EmWPUGk13Jm83OaFc1VdrXNCiD0sGCQ+BTCllDinQvR08yzd4fzA3YXthvX1dBu1SvqQAGOS7gssRCyv9uWI6MXta25X91eY1ZMz1euJ04mB8EdyYiZc0kzrb9dv5d0g==\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_cert\n" + " MIIEQDCCAygCCQCV65JgDvfWkDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEwNTA3MzAzOVoXDTI4MTEwMjA3MzAzOVowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC+kqPqDL9GbWmqVQhp4qla4vYo4kFuh2HG48b7RLp/4l/guik4Hvq2aDVFD9sBcs3FeQbjoLH1Q4doUr8jG6VwJsfovE5SD3T8dVLs2dtpW0OyXTccb0I9lOVDMz6f6IUBe/m5vk8XNbdUII0NJ8y1dQ51VH3e784Bzu7PSdaMaFac4fkw8kJA9LxkWkv2FDFC7IBcVjRgtb/15EwODH849O6+VPEgX5gdozNj5bL45rKDBvvx0KjD7dFBGAIHbSjmjp7HHadfYKqvtQnMb83fRcK6wohxNP3vy13wBTtSOlvOg16Gb+2ZB0Or7wgOw19ZvEIcNgswPwhHfZQNcYMNVLCu02BSzwdY00IEqNM0J5B/W//KJF3uFF/ZqP7D2wO7w8j5UL2lpuxF7YrGecNT1Kr7ggHdkzcLlekkNu7wNWKAZlJ6+Kbun8PqZbamGXLG2Ur1aZDkyKyD9nyMzsRneAlxO+HbQhLojimUbsMm+wgL89zchLYkL/DSmsJlryA4qhvzHaaONBw4DV5UhSbLDpZtXVfrn+MAm8hLpqf+gUCThsFN8kDp9h9Tg9v01ai9jGb941HkFtGYUWHS5drSz3ZLnSI6i1/wKdbs9ns9YqDMqq2c305v5h7taMN0b40KuGSIME4K4cOsdfCprFYGZQgKjaadQwrsm4k1Jl7kMwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAtwH2u1o16jkABlqEGDIvAJSMwBmZzNTNHgOXtWDlkzWGsj+L1wc/DNjDRBkE31h4h7ASthhqi1nzzHYQ1hhPVhUUqI532AS/V7EPsBg3f+BI8gxqQ31TUBEQ4Ll6FtW36nqpJOe6Uui2rH2FonuUg2Av5BvDRil42Tu7fYW4WpSU3e00HiGJ0J0t+QjoKRnnoLJJqlmzk8Y4aIlQim7Azvrlo1WEtOhI3L9UE1GEqxLjRB45P36FSe1wfkgt7xmD0Xjy33Wh6Ae2Fvx7OfJ0K1zy0LHr4rDDJ3tLTqjPqHIFhaa73jGXwXk8sZnbAk542Oa6C6AjzNFyqV7T5Q5lg\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " tlscmn:tls12\n" // set to TLS1.2 + " \n" + " \n" + " TLS_AES_128_GCM_SHA256\n" + " TLS_AES_256_GCM_SHA384\n" + " TLS_CHACHA20_POLY1305_SHA256\n" + " TLS_AES_128_CCM_SHA256\n" + " TLS_AES_128_CCM_8_SHA256\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 1\n" + " 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\n" + " x509c2n:specified\n" + " client\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + /* print port number into the diff */ + ret = asprintf(&diff_filled, diff, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + ret = lyd_parse_data_mem(test_ctx->ctx, diff_filled, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree); + assert_int_equal(ret, 0); + + /* add implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* apply the diff */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + free(diff_filled); + lyd_free_all(tree); + + /* should not be able to connect */ + test_data->expect_fail = 1; + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread_fail, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } + test_data->expect_fail = 0; + + /* reset to original config */ + ret = nc_server_config_setup_data(test_data->tree); + assert_int_equal(ret, 0); + +#if defined (MBEDTLS_TLS1_3_AES_256_GCM_SHA384) || !defined (HAVE_MBEDTLS) + /* mbedtls v3.5.2 doesnt support TLS1.3 ciphersuites by default, so this can only + * be tested when OpenSSL is used or mbedtls is built with TLS1.3 ciphersuites */ + + /* set TLS1.3 with TLS1.3 ciphers and check that connection is ok */ + diff = "\n" + " \n" + " \n" + " \n" + " endpt\n" + " \n" + " \n" + " \n" + " 127.0.0.1\n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " ct:rsa-private-key-format\n" + " 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\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_ca\n" + " MIIDnDCCAoSgAwIBAgIJAIjf7UNx4uabMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5vMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVyY2EwHhcNMTgxMTA1MDcyNjM5WhcNMjgxMTAyMDcyNjM5WjBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXDLeomt6893NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gyic4aOpy2s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCKA7vmNSgQOtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkRsWoF/0pglV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4wEXIhYwM51kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABo1MwUTAdBgNVHQ4EFgQU60nJ4q3ItcfaOOBjJSqadAPiMg8wHwYDVR0jBBgwFoAU60nJ4q3ItcfaOOBjJSqadAPiMg8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxIqIQ5SCXnKslZfrXiAEbB5dglxVOSa8me5a/70uHK/27JZ6veeIgRqZ4VgPHnBCa3m6EHr+mnTjjqSUcGIUiKV3g2Dumw8paqZC+Qv+Ib/NKquS1lO2Ry1wHBtXzn5KKHHyM1bWMDaDszirw2+pp22VdRrPZNA9NWXheEDYOLyQekyL2CfidhxhaXvUZyWgalLyF2XRZ5/jAT+NjfWw39EmWPUGk13Jm83OaFc1VdrXNCiD0sGCQ+BTCllDinQvR08yzd4fzA3YXthvX1dBu1SvqQAGOS7gssRCyv9uWI6MXta25X91eY1ZMz1euJ04mB8EdyYiZc0kzrb9dv5d0g==\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " client_cert\n" + " MIIEQDCCAygCCQCV65JgDvfWkDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJDWjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEwNTA3MzAzOVoXDTI4MTEwMjA3MzAzOVowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC+kqPqDL9GbWmqVQhp4qla4vYo4kFuh2HG48b7RLp/4l/guik4Hvq2aDVFD9sBcs3FeQbjoLH1Q4doUr8jG6VwJsfovE5SD3T8dVLs2dtpW0OyXTccb0I9lOVDMz6f6IUBe/m5vk8XNbdUII0NJ8y1dQ51VH3e784Bzu7PSdaMaFac4fkw8kJA9LxkWkv2FDFC7IBcVjRgtb/15EwODH849O6+VPEgX5gdozNj5bL45rKDBvvx0KjD7dFBGAIHbSjmjp7HHadfYKqvtQnMb83fRcK6wohxNP3vy13wBTtSOlvOg16Gb+2ZB0Or7wgOw19ZvEIcNgswPwhHfZQNcYMNVLCu02BSzwdY00IEqNM0J5B/W//KJF3uFF/ZqP7D2wO7w8j5UL2lpuxF7YrGecNT1Kr7ggHdkzcLlekkNu7wNWKAZlJ6+Kbun8PqZbamGXLG2Ur1aZDkyKyD9nyMzsRneAlxO+HbQhLojimUbsMm+wgL89zchLYkL/DSmsJlryA4qhvzHaaONBw4DV5UhSbLDpZtXVfrn+MAm8hLpqf+gUCThsFN8kDp9h9Tg9v01ai9jGb941HkFtGYUWHS5drSz3ZLnSI6i1/wKdbs9ns9YqDMqq2c305v5h7taMN0b40KuGSIME4K4cOsdfCprFYGZQgKjaadQwrsm4k1Jl7kMwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAtwH2u1o16jkABlqEGDIvAJSMwBmZzNTNHgOXtWDlkzWGsj+L1wc/DNjDRBkE31h4h7ASthhqi1nzzHYQ1hhPVhUUqI532AS/V7EPsBg3f+BI8gxqQ31TUBEQ4Ll6FtW36nqpJOe6Uui2rH2FonuUg2Av5BvDRil42Tu7fYW4WpSU3e00HiGJ0J0t+QjoKRnnoLJJqlmzk8Y4aIlQim7Azvrlo1WEtOhI3L9UE1GEqxLjRB45P36FSe1wfkgt7xmD0Xjy33Wh6Ae2Fvx7OfJ0K1zy0LHr4rDDJ3tLTqjPqHIFhaa73jGXwXk8sZnbAk542Oa6C6AjzNFyqV7T5Q5lg\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " tlscmn:tls13\n" // set to TLS1.3 + " \n" + " \n" + " TLS_AES_128_GCM_SHA256\n" + " TLS_AES_256_GCM_SHA384\n" + " TLS_CHACHA20_POLY1305_SHA256\n" + " TLS_AES_128_CCM_SHA256\n" + " TLS_AES_128_CCM_8_SHA256\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " 1\n" + " 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\n" + " x509c2n:specified\n" + " client\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + /* print port number into the diff */ + ret = asprintf(&diff_filled, diff, TEST_PORT_STR); + assert_int_not_equal(ret, -1); + + ret = lyd_parse_data_mem(test_ctx->ctx, diff_filled, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree); + assert_int_equal(ret, 0); + + /* add implicit nodes */ + ret = lyd_new_implicit_tree(tree, LYD_IMPLICIT_NO_STATE, NULL); + assert_int_equal(ret, 0); + + /* apply the diff */ + ret = nc_server_config_setup_diff(tree); + assert_int_equal(ret, 0); + + free(diff_filled); + lyd_free_all(tree); + + /* should not be able to connect */ + ret = pthread_create(&tids[0], NULL, client_thread, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, ln2_glob_test_server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } + + /* reset to original config */ + ret = nc_server_config_setup_data(test_data->tree); + assert_int_equal(ret, 0); +#endif +} + static void test_nc_tls_free_test_data(void *test_data) { @@ -484,7 +1100,9 @@ main(void) cmocka_unit_test_setup_teardown(test_nc_tls_intermediate_ca_server, setup_intermediate_ca, ln2_glob_test_teardown), cmocka_unit_test_setup_teardown(test_nc_tls_intermediate_ca_client, setup_intermediate_ca, ln2_glob_test_teardown), cmocka_unit_test_setup_teardown(test_nc_tls_ec_key, setup_f, ln2_glob_test_teardown), - cmocka_unit_test_setup_teardown(test_nc_tls_keylog, keylog_setup_f, ln2_glob_test_teardown) + cmocka_unit_test_setup_teardown(test_nc_tls_keylog, keylog_setup_f, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_cipher_suites, setup_f, ln2_glob_test_teardown), + cmocka_unit_test_setup_teardown(test_tls_version, setup_f, ln2_glob_test_teardown), }; /* try to get ports from the environment, otherwise use the default */