diff --git a/src/config_new.c b/src/config_new.c index 8cea603c..4cefadf6 100644 --- a/src/config_new.c +++ b/src/config_new.c @@ -911,7 +911,7 @@ nc_server_config_new_ch_del_endpt(const char *client_name, const char *endpt_nam } API int -nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *name, const char *privkey_path, +nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *asym_key_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config) { int ret = 0; @@ -920,7 +920,7 @@ nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *nam NC_PUBKEY_FORMAT pubkey_type; const char *privkey_format, *pubkey_format; - NC_CHECK_ARG_RET(NULL, ctx, name, privkey_path, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, asym_key_name, privkey_path, config, 1); /* get the keys as a string from the given files */ ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type); @@ -944,25 +944,25 @@ nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *nam } ret = nc_config_new_create(ctx, config, pubkey_format, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/public-key-format", name); + "asymmetric-key[name='%s']/public-key-format", asym_key_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, pubkey, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/public-key", name); + "asymmetric-key[name='%s']/public-key", asym_key_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, privkey_format, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/private-key-format", name); + "asymmetric-key[name='%s']/private-key-format", asym_key_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, privkey, "/ietf-keystore:keystore/asymmetric-keys/" - "asymmetric-key[name='%s']/cleartext-private-key", name); + "asymmetric-key[name='%s']/cleartext-private-key", asym_key_name); if (ret) { goto cleanup; } @@ -974,19 +974,56 @@ nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *nam } API int -nc_server_config_new_del_keystore_asym_key(const char *name, struct lyd_node **config) +nc_server_config_new_del_keystore_asym_key(const char *asym_key_name, struct lyd_node **config) { NC_CHECK_ARG_RET(NULL, config, 1); - if (name) { - return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']", name); + if (asym_key_name) { + return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']", asym_key_name); } else { return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key"); } } API int -nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag_name, const char *pubkey_name, +nc_server_config_new_keystore_cert(const struct ly_ctx *ctx, const char *asym_key_name, const char *cert_name, + const char *cert_path, struct lyd_node **config) +{ + int ret = 0; + char *cert = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, asym_key_name, cert_name, cert_path, config, 1); + + /* get cert data */ + ret = nc_server_config_new_read_certificate(cert_path, &cert); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, cert, "/ietf-keystore:keystore/asymmetric-keys/" + "asymmetric-key[name='%s']/certificates/certificate[name='%s']/cert-data", asym_key_name, cert_name); + +cleanup: + free(cert); + return ret; +} + +API int +nc_server_config_new_del_keystore_cert(const char *asym_key_name, const char *cert_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, asym_key_name, config, 1); + + if (cert_name) { + return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/" + "certificates/certificate[name='%s']", asym_key_name, cert_name); + } else { + return nc_config_new_delete(config, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='%s']/" + "certificates/certificate", asym_key_name); + } +} + +API int +nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *pub_bag_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config) { int ret = 0; @@ -994,7 +1031,7 @@ nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag NC_PUBKEY_FORMAT pubkey_format; const char *format; - NC_CHECK_ARG_RET(NULL, ctx, bag_name, pubkey_name, pubkey_path, config, 1); + NC_CHECK_ARG_RET(NULL, ctx, pub_bag_name, pubkey_name, pubkey_path, config, 1); ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_format); if (ret) { @@ -1009,13 +1046,13 @@ nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag } ret = nc_config_new_create(ctx, config, format, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", bag_name, pubkey_name); + "public-key-bag[name='%s']/public-key[name='%s']/public-key-format", pub_bag_name, pubkey_name); if (ret) { goto cleanup; } ret = nc_config_new_create(ctx, config, pubkey, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key[name='%s']/public-key", bag_name, pubkey_name); + "public-key-bag[name='%s']/public-key[name='%s']/public-key", pub_bag_name, pubkey_name); if (ret) { goto cleanup; } @@ -1026,17 +1063,57 @@ nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag } API int -nc_server_config_new_del_truststore_pubkey(const char *bag_name, +nc_server_config_new_del_truststore_pubkey(const char *pub_bag_name, const char *pubkey_name, struct lyd_node **config) { - NC_CHECK_ARG_RET(NULL, bag_name, config, 1); + NC_CHECK_ARG_RET(NULL, pub_bag_name, config, 1); if (pubkey_name) { return nc_config_new_delete(config, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key[name='%s']", bag_name, pubkey_name); + "public-key-bag[name='%s']/public-key[name='%s']", pub_bag_name, pubkey_name); } else { return nc_config_new_delete(config, "/ietf-truststore:truststore/public-key-bags/" - "public-key-bag[name='%s']/public-key", bag_name); + "public-key-bag[name='%s']/public-key", pub_bag_name); + } +} + +API int +nc_server_config_new_truststore_cert(const struct ly_ctx *ctx, const char *cert_bag_name, const char *cert_name, + const char *cert_path, struct lyd_node **config) +{ + int ret = 0; + char *cert = NULL; + + NC_CHECK_ARG_RET(NULL, ctx, cert_bag_name, cert_name, cert_path, config, 1); + + ret = nc_server_config_new_read_certificate(cert_path, &cert); + if (ret) { + goto cleanup; + } + + ret = nc_config_new_create(ctx, config, cert, "/ietf-truststore:truststore/certificate-bags/" + "certificate-bag[name='%s']/certificate[name='%s']/cert-data", cert_bag_name, cert_name); + if (ret) { + goto cleanup; + } + +cleanup: + free(cert); + return ret; +} + +API int +nc_server_config_new_del_truststore_cert(const char *cert_bag_name, + const char *cert_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, cert_bag_name, config, 1); + + if (cert_name) { + return nc_config_new_delete(config, "/ietf-truststore:truststore/certificate-bags/" + "certificate-bag[name='%s']/certificate[name='%s']", cert_bag_name, cert_name); + } else { + return nc_config_new_delete(config, "/ietf-truststore:truststore/certificate-bags/" + "certificate-bag[name='%s']/certificate", cert_bag_name); } } diff --git a/src/config_new_tls.c b/src/config_new_tls.c index 1ba72ddf..d80af8a2 100644 --- a/src/config_new_tls.c +++ b/src/config_new_tls.c @@ -181,6 +181,38 @@ nc_server_config_new_ch_tls_del_server_certificate(const char *client_name, cons "certificate/inline-definition", client_name, endpt_name); } +API int +nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *asym_key_ref, + const char *cert_ref, struct lyd_node **config) +{ + int ret = 0; + + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, asym_key_ref, cert_ref, config, 1); + + /* create asymmetric key pair reference */ + ret = nc_config_new_create(ctx, config, asym_key_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/keystore-reference/asymmetric-key", endpt_name); + if (ret) { + goto cleanup; + } + + /* create cert reference, this cert has to belong to the asym key */ + ret = nc_config_new_create(ctx, config, cert_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/keystore-reference/certificate", endpt_name); + +cleanup: + return ret; +} + +API int +nc_server_config_new_tls_del_keystore_reference(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/" + "tls/tls-server-parameters/server-identity/certificate/keystore-reference", endpt_name); +} + static int _nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const char *tree_path, const char *cert_path, struct lyd_node **config) @@ -295,6 +327,25 @@ nc_server_config_new_ch_tls_del_client_certificate(const char *client_name, cons } } +API int +nc_server_config_new_tls_client_cert_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, + const char *cert_bag_ref, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1); + + return nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/truststore-reference", endpt_name); +} + +API int +nc_server_config_new_tls_del_client_cert_truststore_ref(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ee-certs/truststore-reference", endpt_name); +} + API int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name, const char *cert_path, struct lyd_node **config) @@ -386,6 +437,25 @@ nc_server_config_new_ch_tls_del_client_ca(const char *client_name, const char *e } } +API int +nc_server_config_new_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, + const char *cert_bag_ref, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1); + + return nc_config_new_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/truststore-reference", endpt_name); +} + +API int +nc_server_config_new_tls_del_client_ca_truststore_ref(const char *endpt_name, struct lyd_node **config) +{ + NC_CHECK_ARG_RET(NULL, endpt_name, config, 1); + + return nc_config_new_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/" + "tls-server-parameters/client-authentication/ca-certs/truststore-reference", endpt_name); +} + static const char * nc_config_new_tls_maptype2str(NC_TLS_CTN_MAPTYPE map_type) { diff --git a/src/server_config.h b/src/server_config.h index b53036ac..34562915 100644 --- a/src/server_config.h +++ b/src/server_config.h @@ -126,8 +126,8 @@ int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **con * @brief Creates new YANG data nodes for an asymmetric key in the keystore. * * @param[in] ctx libyang context. - * @param[in] name Name of the asymmetric key pair. - * This name is used to reference the key pair. + * @param[in] asym_key_name Identifier of the asymmetric key pair. + * This identifier is used to reference the key pair. * @param[in] privkey_path Path to a private key file. * @param[in] pubkey_path Optional path a public key file. * If not supplied, it will be generated from the private key. @@ -135,46 +135,109 @@ int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **con * Otherwise the new YANG data will be added to the previous data and may override it. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *name, const char *privkey_path, +int nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *asym_key_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config); /** * @brief Deletes a keystore's asymmetric key from the YANG data. * - * @param[in] name Optional identifier of the asymmetric key to be deleted. + * @param[in] asym_key_name Optional identifier of the asymmetric key to be deleted. * If NULL, all of the asymmetric keys in the keystore will be deleted. * @param[in,out] config Configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_del_keystore_asym_key(const char *name, struct lyd_node **config); +int nc_server_config_new_del_keystore_asym_key(const char *asym_key_name, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a certificate in the keystore. + * + * A certificate can not exist without its asymmetric key, so you must call ::nc_server_config_new_keystore_asym_key() + * either before or after calling this with the same identifier for the asymmetric key. + * + * An asymmetric key pair can have zero or more certificates associated with this key pair, however a certificate must + * have exactly one key pair it belongs to. + * + * @param[in] ctx libyang context. + * @param[in] asym_key_name Arbitrary identifier of the asymmetric key. + * If an asymmetric key pair with this name already exists, its contents will be changed. + * @param[in] cert_name Arbitrary identifier of the key pair's certificate. + * If a certificate with this name already exists, its contents will be changed. + * @param[in] cert_path Path to the PEM encoded certificate file. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_keystore_cert(const struct ly_ctx *ctx, const char *asym_key_name, const char *cert_name, + const char *cert_path, struct lyd_node **config); + +/** + * @brief Deletes a keystore's certificate from the YANG data. + * + * @param[in] asym_key_name Identifier of an existing asymmetric key pair. + * @param[in] cert_name Optional identifier of a certificate to be deleted. + * If NULL, all of the certificates belonging to the asymmetric key pair will be deleted. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_del_keystore_cert(const char *asym_key_name, const char *cert_name, struct lyd_node **config); /** * @brief Creates new YANG data nodes for a public key in the truststore. * * @param[in] ctx libyang context. - * @param[in] bag_name Arbitrary identifier of the public key bag. + * @param[in] pub_bag_name Arbitrary identifier of the public key bag. * This name is used to reference the public keys in the bag. * If a public key bag with this name already exists, its contents will be changed. * @param[in] pubkey_name Arbitrary identifier of the public key. - * If a public key with this name already exists, its contents will be changed. + * If a public key with this name already exists in the given bag, its contents will be changed. * @param[in] pubkey_path Path to a file containing a public key. * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. * Otherwise the new YANG data will be added to the previous data and may override it. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *bag_name, const char *pubkey_name, +int nc_server_config_new_truststore_pubkey(const struct ly_ctx *ctx, const char *pub_bag_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config); /** * @brief Deletes a truststore's public key from the YANG data. * - * @param[in] bag_name Identifier of an existing public key bag. + * @param[in] pub_bag_name Identifier of an existing public key bag. * @param[in] pubkey_name Optional identifier of a public key to be deleted. * If NULL, all of the public keys in the given bag will be deleted. * @param[in,out] config Configuration YANG data tree. * @return 0 on success, non-zero otherwise. */ -int nc_server_config_new_del_truststore_pubkey(const char *bag_name, const char *pubkey_name, struct lyd_node **config); +int nc_server_config_new_del_truststore_pubkey(const char *pub_bag_name, const char *pubkey_name, struct lyd_node **config); + +/** + * @brief Creates new YANG data nodes for a certificate in the truststore. + * + * @param[in] ctx libyang context. + * @param[in] cert_bag_name Arbitrary identifier of the certificate bag. + * This name is used to reference the certificates in the bag. + * If a certificate bag with this name already exists, its contents will be changed. + * @param[in] cert_name Arbitrary identifier of the certificate. + * If a certificate with this name already exists in the given bag, its contents will be changed. + * @param[in] cert_path Path to a file containing a PEM encoded certificate. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_truststore_cert(const struct ly_ctx *ctx, const char *cert_bag_name, const char *cert_name, + const char *cert_path, struct lyd_node **config); + +/** + * @brief Deletes a truststore's certificate from the YANG data. + * + * @param[in] cert_bag_name Identifier of an existing certificate bag. + * @param[in] cert_name Optional identifier of a certificate to be deleted. + * If NULL, all of the certificates in the given bag will be deleted. + * @param[in,out] config Configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_del_truststore_cert(const char *cert_bag_name, + const char *cert_name, struct lyd_node **config); /** * @} @@ -615,6 +678,30 @@ int nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const */ int nc_server_config_new_tls_del_server_certificate(const char *endpt_name, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes for a keystore reference to the TLS server's certificate. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] asym_key_ref Name of the asymmetric key pair in the keystore to be referenced. + * @param[in] cert_ref Name of the certificate, which must belong to the given asymmetric key pair, to be referenced. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_keystore_reference(const struct ly_ctx *ctx, const char *endpt_name, const char *asym_key_ref, + const char *cert_ref, struct lyd_node **config); + +/** + * @brief Deletes a TLS server certificate keystore reference from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_del_keystore_reference(const char *endpt_name, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a client's (end-entity) certificate. * @@ -642,6 +729,29 @@ int nc_server_config_new_tls_client_certificate(const struct ly_ctx *ctx, const */ int nc_server_config_new_tls_del_client_certificate(const char *endpt_name, const char *cert_name, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes for a truststore reference to a set of client (end-entity) certificates. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] cert_bag_ref Identifier of the certificate bag in the truststore to be referenced. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_client_cert_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, + const char *cert_bag_ref, struct lyd_node **config); + +/** + * @brief Deletes a client (end-entity) certificates truststore reference from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_del_client_cert_truststore_ref(const char *endpt_name, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a client certificate authority (trust-anchor) certificate. * @@ -669,6 +779,29 @@ int nc_server_config_new_tls_client_ca(const struct ly_ctx *ctx, const char *end */ int nc_server_config_new_tls_del_client_ca(const char *endpt_name, const char *cert_name, struct lyd_node **config); +/** + * @brief Creates new YANG configuration data nodes for a truststore reference to a set of client certificate authority (trust-anchor) certificates. + * + * @param[in] ctx libyang context. + * @param[in] endpt_name Arbitrary identifier of the endpoint. + * If an endpoint with this identifier already exists, its contents will be changed. + * @param[in] cert_bag_ref Identifier of the certificate bag in the truststore to be referenced. + * @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created. + * Otherwise the new YANG data will be added to the previous data and may override it. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_client_ca_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, + const char *cert_bag_ref, struct lyd_node **config); + +/** + * @brief Deletes a client certificate authority (trust-anchor) certificates truststore reference from the YANG data. + * + * @param[in] endpt_name Identifier of an existing endpoint. + * @param[in,out] config Modified configuration YANG data tree. + * @return 0 on success, non-zero otherwise. + */ +int nc_server_config_new_tls_del_client_ca_truststore_ref(const char *endpt_name, struct lyd_node **config); + /** * @brief Creates new YANG configuration data nodes for a cert-to-name entry. * diff --git a/src/session_server_tls.c b/src/session_server_tls.c index f6bb796b..3c389823 100644 --- a/src/session_server_tls.c +++ b/src/session_server_tls.c @@ -610,6 +610,8 @@ nc_server_tls_do_preverify(struct nc_session *session, X509_STORE_CTX *x509_ctx, struct nc_cert_grouping *ee_certs; int i, ret; X509 *cert; + struct nc_certificate *certs; + uint16_t cert_count; store = X509_STORE_CTX_get0_store(x509_ctx); if (!store) { @@ -624,8 +626,18 @@ nc_server_tls_do_preverify(struct nc_session *session, X509_STORE_CTX *x509_ctx, return -1; } - for (i = 0; i < ee_certs->cert_count; i++) { - cert = base64der_to_cert(ee_certs->certs[i].data); + if (ee_certs->store == NC_STORE_LOCAL) { + /* local definition */ + certs = ee_certs->certs; + cert_count = ee_certs->cert_count; + } else { + /* truststore reference */ + certs = ee_certs->ts_ref->certs; + cert_count = ee_certs->ts_ref->cert_count; + } + + for (i = 0; i < cert_count; i++) { + cert = base64der_to_cert(certs[i].data); ret = cert_pubkey_match(session->opts.server.client_cert, cert); X509_free(cert); if (ret) { @@ -981,23 +993,25 @@ tls_store_add_trusted_cert(X509_STORE *cert_store, const char *cert_data) } static int -nc_tls_store_set_trusted_certs(X509_STORE *cert_store, struct nc_cert_grouping *certs) +nc_tls_store_set_trusted_certs(X509_STORE *cert_store, struct nc_cert_grouping *ca_certs) { uint16_t i; + struct nc_certificate *certs; + uint16_t cert_count; - if (certs->store == NC_STORE_LOCAL) { + if (ca_certs->store == NC_STORE_LOCAL) { /* local definition */ - for (i = 0; i < certs->cert_count; i++) { - if (tls_store_add_trusted_cert(cert_store, certs->certs[i].data)) { - return -1; - } - } + certs = ca_certs->certs; + cert_count = ca_certs->cert_count; } else { /* truststore */ - for (i = 0; i < certs->ts_ref->cert_count; i++) { - if (tls_store_add_trusted_cert(cert_store, certs->ts_ref->certs[i].data)) { - return -1; - } + certs = ca_certs->ts_ref->certs; + cert_count = ca_certs->ts_ref->cert_count; + } + + for (i = 0; i < cert_count; i++) { + if (tls_store_add_trusted_cert(cert_store, certs[i].data)) { + return -1; } } diff --git a/tests/test_ks_ts.c b/tests/test_ks_ts.c index fb179e06..2d125fad 100644 --- a/tests/test_ks_ts.c +++ b/tests/test_ks_ts.c @@ -36,75 +36,6 @@ struct test_state { pthread_barrier_t barrier; }; -const char *data = - "\n" - " \n" - " 10\n" - " \n" - " default-ssh\n" - " \n" - " \n" - " 127.0.0.1\n" - " 10005\n" - " \n" - " \n" - " \n" - " \n" - " key\n" - " \n" - " test_keystore\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " test_ts\n" - " \n" - " \n" - " \n" - " test\n" - " ct:ssh-public-key-format\n" - " AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " sshpka:rsa-sha2-512\n" - " \n" - " \n" - " sshkea:curve25519-sha256\n" - " \n" - " \n" - " sshea:aes256-ctr\n" - " \n" - " \n" - " sshma:hmac-sha2-512\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n" - "\n" - "\n" - " \n" - " \n" - " test_keystore\n" - " ct:ssh-public-key-format\n" - " MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==\n" - " ct:rsa-private-key-format\n" - " MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAHX8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXBRgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMkcjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rEDMlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuarAhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNtxZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2RnLkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+UXA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmGvWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRLZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7vIQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bfJAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhgW4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFyfSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/bBY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SRq7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJvnwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcairBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4SSBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinbTsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPoSwr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JBdOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/KqDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8TbstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=\n" - " \n" - " \n" - " \n" - "\n"; - static void * server_thread(void *arg) { @@ -136,7 +67,7 @@ server_thread(void *arg) } static void * -client_thread(void *arg) +client_thread_ssh(void *arg) { int ret; struct nc_session *session = NULL; @@ -163,14 +94,14 @@ client_thread(void *arg) } static void -test_nc_ks_ts(void **state) +test_nc_ks_ts_ssh(void **state) { int ret, i; pthread_t tids[2]; assert_non_null(state); - ret = pthread_create(&tids[0], NULL, client_thread, *state); + ret = pthread_create(&tids[0], NULL, client_thread_ssh, *state); assert_int_equal(ret, 0); ret = pthread_create(&tids[1], NULL, server_thread, *state); assert_int_equal(ret, 0); @@ -181,7 +112,7 @@ test_nc_ks_ts(void **state) } static int -setup_f(void **state) +setup_ssh(void **state) { int ret; struct lyd_node *tree = NULL; @@ -234,6 +165,130 @@ setup_f(void **state) return 0; } +static void * +client_thread_tls(void *arg) +{ + int ret; + struct nc_session *session = NULL; + struct test_state *state = arg; + + ret = nc_client_set_schema_searchpath(MODULES_DIR); + assert_int_equal(ret, 0); + + /* set client cert */ + ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key"); + assert_int_equal(ret, 0); + + /* set client ca */ + ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data"); + assert_int_equal(ret, 0); + + pthread_barrier_wait(&state->barrier); + session = nc_connect_tls("127.0.0.1", 10005, NULL); + assert_non_null(session); + + nc_session_free(session, NULL); + return NULL; +} + +static void +test_nc_ks_ts_tls(void **state) +{ + int ret, i; + pthread_t tids[2]; + + assert_non_null(state); + + ret = pthread_create(&tids[0], NULL, client_thread_tls, *state); + assert_int_equal(ret, 0); + ret = pthread_create(&tids[1], NULL, server_thread, *state); + assert_int_equal(ret, 0); + + for (i = 0; i < 2; i++) { + pthread_join(tids[i], NULL); + } +} + +static int +setup_tls(void **state) +{ + int ret; + struct lyd_node *tree = NULL; + struct test_state *test_state; + + nc_verbosity(NC_VERB_VERBOSE); + + /* init barrier */ + test_state = malloc(sizeof *test_state); + assert_non_null(test_state); + + ret = pthread_barrier_init(&test_state->barrier, NULL, 2); + assert_int_equal(ret, 0); + + *state = test_state; + + /* new ctx */ + ret = ly_ctx_new(MODULES_DIR, 0, &ctx); + assert_int_equal(ret, 0); + + /* init ctx */ + ret = nc_server_init_ctx(&ctx); + assert_int_equal(ret, 0); + + /* load ietf netconf server module and its requisities */ + ret = nc_server_config_load_modules(&ctx); + assert_int_equal(ret, 0); + + /* new tls bind */ + ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", 10005, &tree); + assert_int_equal(ret, 0); + + /* new keystore asym key pair */ + ret = nc_server_config_new_keystore_asym_key(ctx, "server_key", TESTS_DIR "/data/server.key", NULL, &tree); + assert_int_equal(ret, 0); + + /* new keystore cert belonging to the key pair */ + ret = nc_server_config_new_keystore_cert(ctx, "server_key", "server_cert", TESTS_DIR "/data/server.crt", &tree); + assert_int_equal(ret, 0); + + /* new truststore client cert */ + ret = nc_server_config_new_truststore_cert(ctx, "ee_cert_bag", "ee_cert", TESTS_DIR "/data/client.crt", &tree); + assert_int_equal(ret, 0); + + /* new truststore client CA cert */ + ret = nc_server_config_new_truststore_cert(ctx, "ca_cert_bag", "ca_cert", TESTS_DIR "/data/serverca.pem", &tree); + assert_int_equal(ret, 0); + + /* new keystore ref for the TLS server cert */ + ret = nc_server_config_new_tls_keystore_reference(ctx, "endpt", "server_key", "server_cert", &tree); + assert_int_equal(ret, 0); + + /* new truststore ref for the client cert */ + ret = nc_server_config_new_tls_client_cert_truststore_ref(ctx, "endpt", "ee_cert_bag", &tree); + assert_int_equal(ret, 0); + + /* new truststore ref for the client CA cert */ + ret = nc_server_config_new_tls_client_ca_truststore_ref(ctx, "endpt", "ca_cert_bag", &tree); + assert_int_equal(ret, 0); + + /* new cert-to-name */ + ret = nc_server_config_new_tls_ctn(ctx, "endpt", 1, + "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D", + NC_TLS_CTN_SPECIFIED, "client", &tree); + assert_int_equal(ret, 0); + + /* configure the server based on the data */ + ret = nc_server_config_setup_data(tree); + assert_int_equal(ret, 0); + + ret = nc_server_init(); + assert_int_equal(ret, 0); + + lyd_free_all(tree); + + return 0; +} + static int teardown_f(void **state) { @@ -258,7 +313,8 @@ int main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_nc_ks_ts, setup_f, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_ks_ts_ssh, setup_ssh, teardown_f), + cmocka_unit_test_setup_teardown(test_nc_ks_ts_tls, setup_tls, teardown_f), }; setenv("CMOCKA_TEST_ABORT", "1", 1);