Skip to content

Commit 9f9db16

Browse files
Roytakmichalvasko
authored andcommitted
session server tls UPDATE ctn logic
Instead of obtaining username only from the cert with matching fingerprint, try to obtain it from the whole chain starting from the client cert. Also refactor the ctn code. Fixes CESNET/netopeer2#1797
1 parent c6e89ef commit 9f9db16

8 files changed

Lines changed: 503 additions & 157 deletions

File tree

src/server_config.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ int nc_server_config_del_tls_endpoint_client_ref(const char *endpt_name, struct
826826
* @param[in] fingerprint Optional fingerprint of the entry. The fingerprint should always be set, however if it is
827827
* not set, it will match any certificate. Entry with no fingerprint should therefore be placed only as the last entry.
828828
* @param[in] map_type Mapping username to the certificate option.
829-
* @param[in] name Username for this cert-to-name entry.
829+
* @param[in] name Username for this cert-to-name entry. Mandatory if @p map_type is set to ::NC_TLS_CTN_SPECIFIED.
830830
* @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created.
831831
* Otherwise the new YANG data will be added to the previous data and may override it.
832832
* @return 0 on success, non-zero otherwise.
@@ -1479,7 +1479,7 @@ int nc_server_config_del_ch_tls_ca_cert_truststore_ref(const char *client_name,
14791479
* @param[in] fingerprint Optional fingerprint of the entry. The fingerprint should always be set, however if it is
14801480
* not set, it will match any certificate. Entry with no fingerprint should therefore be placed only as the last entry.
14811481
* @param[in] map_type Mapping username to the certificate option.
1482-
* @param[in] name Username for this cert-to-name entry.
1482+
* @param[in] name Username for this cert-to-name entry. Mandatory if @p map_type is set to ::NC_TLS_CTN_SPECIFIED.
14831483
* @param[in,out] config Configuration YANG data tree. If *config is NULL, it will be created.
14841484
* Otherwise the new YANG data will be added to the previous data and may override it.
14851485
* @return 0 on success, non-zero otherwise.

src/server_config_util_tls.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,10 @@ _nc_server_config_add_tls_ctn(const struct ly_ctx *ctx, const char *tree_path, c
660660
int ret = 0;
661661
const char *map;
662662

663-
NC_CHECK_ARG_RET(NULL, ctx, tree_path, name, config, 1);
663+
if ((map_type == NC_TLS_CTN_SPECIFIED) && !name) {
664+
ERR(NULL, "Client name must be provided for the \"specified\" CTN mapping type.");
665+
return 1;
666+
}
664667

665668
if (fingerprint) {
666669
/* optional */
@@ -682,9 +685,11 @@ _nc_server_config_add_tls_ctn(const struct ly_ctx *ctx, const char *tree_path, c
682685
goto cleanup;
683686
}
684687

685-
ret = nc_server_config_append(ctx, tree_path, "name", name, config);
686-
if (ret) {
687-
goto cleanup;
688+
if (name) {
689+
ret = nc_server_config_append(ctx, tree_path, "name", name, config);
690+
if (ret) {
691+
goto cleanup;
692+
}
688693
}
689694

690695
cleanup:
@@ -698,7 +703,7 @@ nc_server_config_add_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, u
698703
int ret = 0;
699704
char *path = NULL;
700705

701-
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, name, config, 1);
706+
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, config, 1);
702707

703708
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/netconf-server-parameters/"
704709
"client-identity-mappings/cert-to-name[id='%" PRIu32 "']", endpt_name, id);
@@ -736,7 +741,7 @@ nc_server_config_add_ch_tls_ctn(const struct ly_ctx *ctx, const char *client_nam
736741
int ret = 0;
737742
char *path = NULL;
738743

739-
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, id, name, config, 1);
744+
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, id, config, 1);
740745

741746
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
742747
"endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/"

src/session_mbedtls.c

Lines changed: 126 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -587,37 +587,125 @@ nc_tls_cert_dup(const mbedtls_x509_crt *cert)
587587
}
588588

589589
/**
590-
* @brief Duplicate a certificate and append it to a chain.
590+
* @brief Duplicate a certificate and prepend it to a chain.
591591
*
592-
* @param[in] cert Certificate to duplicate and append.
593-
* @param[in,out] chain Chain to append the certificate to.
592+
* @param[in] cert Certificate to duplicate and prepend.
593+
* @param[in,out] chain Chain to prepend the certificate to.
594594
* @return 0 on success, -1 on error.
595595
*/
596596
static int
597-
nc_server_tls_append_cert_to_chain(mbedtls_x509_crt *cert, mbedtls_x509_crt **chain)
597+
nc_server_tls_prepend_cert_to_chain(mbedtls_x509_crt *cert, mbedtls_x509_crt **chain)
598598
{
599-
mbedtls_x509_crt *iter, *copy;
599+
mbedtls_x509_crt *copy;
600600

601601
copy = nc_tls_cert_dup(cert);
602602
if (!copy) {
603603
return -1;
604604
}
605605

606-
if (!*chain) {
607-
/* first in the list */
608-
*chain = copy;
609-
} else {
610-
/* find the last cert */
611-
iter = *chain;
612-
while (iter->next) {
613-
iter = iter->next;
606+
copy->next = *chain;
607+
*chain = copy;
608+
609+
return 0;
610+
}
611+
612+
/**
613+
* @brief Check whether a certificate is already present in a chain.
614+
*
615+
* @param[in] cert Certificate to search for.
616+
* @param[in] chain Certificate chain.
617+
* @return 1 if found, 0 otherwise.
618+
*/
619+
static int
620+
nc_server_tls_cert_in_chain(const mbedtls_x509_crt *cert, const mbedtls_x509_crt *chain)
621+
{
622+
const mbedtls_x509_crt *iter;
623+
624+
for (iter = chain; iter; iter = iter->next) {
625+
if (cert->raw.p && iter->raw.p && (cert->raw.len == iter->raw.len) && !memcmp(cert->raw.p, iter->raw.p, cert->raw.len)) {
626+
return 1;
614627
}
615-
iter->next = copy;
616628
}
617629

618630
return 0;
619631
}
620632

633+
/**
634+
* @brief Prepend issuer chain for a certificate.
635+
*
636+
* Repeatedly parse issuer_raw of @p cert into a certificate, then parse issuer_raw
637+
* of that parsed issuer, and so on. Parsed issuers are prepended into @p chain in
638+
* root-first order so that prepending the actual cert afterwards yields peer-first
639+
* order.
640+
*
641+
* @param[in] cert Certificate whose issuers are to be prepended.
642+
* @param[in,out] chain Chain to prepend issuer certificates to.
643+
* @return 0 on success, -1 on error.
644+
*/
645+
static int
646+
nc_server_tls_prepend_issuer_chain(mbedtls_x509_crt *cert, mbedtls_x509_crt **chain)
647+
{
648+
size_t i = 0;
649+
mbedtls_x509_crt *copy;
650+
const mbedtls_x509_crt *issuer, *iter, *cur;
651+
mbedtls_x509_crt *issuers[MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE - 1];
652+
653+
cur = cert;
654+
while (cur && (i < (sizeof issuers / sizeof *issuers))) {
655+
if (!cur->issuer_raw.p || !cur->issuer_raw.len) {
656+
break;
657+
}
658+
659+
if ((cur->issuer_raw.len == cur->subject_raw.len) && !memcmp(cur->issuer_raw.p, cur->subject_raw.p, cur->issuer_raw.len)) {
660+
/* self-issued root reached */
661+
break;
662+
}
663+
664+
/* find issuer cert by matching issuer DN to subject DN */
665+
issuer = NULL;
666+
for (iter = cert; iter; iter = iter->next) {
667+
if ((iter->subject_raw.len == cur->issuer_raw.len) &&
668+
!memcmp(iter->subject_raw.p, cur->issuer_raw.p, cur->issuer_raw.len)) {
669+
issuer = iter;
670+
break;
671+
}
672+
}
673+
if (!issuer) {
674+
/* no more issuers available in the certificate set */
675+
break;
676+
}
677+
678+
if (nc_server_tls_cert_in_chain(issuer, *chain)) {
679+
/* already present in chain */
680+
break;
681+
}
682+
683+
copy = nc_tls_cert_dup(issuer);
684+
if (!copy) {
685+
goto error;
686+
}
687+
688+
issuers[i] = copy;
689+
++i;
690+
cur = issuer;
691+
}
692+
693+
while (i) {
694+
--i;
695+
issuers[i]->next = *chain;
696+
*chain = issuers[i];
697+
}
698+
699+
return 0;
700+
701+
error:
702+
while (i) {
703+
--i;
704+
nc_tls_cert_destroy_wrap(issuers[i]);
705+
}
706+
return -1;
707+
}
708+
621709
/**
622710
* @brief Verify a certificate.
623711
*
@@ -634,11 +722,22 @@ nc_server_tls_verify_cb(void *cb_data, mbedtls_x509_crt *cert, int depth, uint32
634722
struct nc_tls_verify_cb_data *data = cb_data;
635723
char *err;
636724

637-
/* append to the chain we're building */
638-
ret = nc_server_tls_append_cert_to_chain(cert, (mbedtls_x509_crt **)&data->chain);
639-
if (ret) {
640-
nc_tls_cert_destroy_wrap(data->chain);
641-
return MBEDTLS_ERR_X509_ALLOC_FAILED;
725+
if (!data->chain) {
726+
/* first call, prepend the issuer chain so that we have the whole chain available for CTN */
727+
ret = nc_server_tls_prepend_issuer_chain(cert, (mbedtls_x509_crt **)&data->chain);
728+
if (ret) {
729+
nc_tls_cert_destroy_wrap(data->chain);
730+
return MBEDTLS_ERR_X509_ALLOC_FAILED;
731+
}
732+
}
733+
734+
/* prepend to the chain we're building to maintain peer-first order */
735+
if (!nc_server_tls_cert_in_chain(cert, (const mbedtls_x509_crt *)data->chain)) {
736+
ret = nc_server_tls_prepend_cert_to_chain(cert, (mbedtls_x509_crt **)&data->chain);
737+
if (ret) {
738+
nc_tls_cert_destroy_wrap(data->chain);
739+
return MBEDTLS_ERR_X509_ALLOC_FAILED;
740+
}
642741
}
643742

644743
if (!*flags) {
@@ -836,18 +935,22 @@ nc_tls_get_num_certs_wrap(void *chain)
836935
return n;
837936
}
838937

839-
void
840-
nc_tls_get_cert_wrap(void *chain, int idx, void **cert)
938+
void *
939+
nc_tls_get_cert_wrap(void *chain, int idx)
841940
{
842941
int i;
843942
mbedtls_x509_crt *iter;
844943

944+
if (!chain || (idx < 0)) {
945+
return NULL;
946+
}
947+
845948
iter = chain;
846-
for (i = 0; i < idx; i++) {
949+
for (i = 0; iter && (i < idx); i++) {
847950
iter = iter->next;
848951
}
849952

850-
*cert = iter;
953+
return iter;
851954
}
852955

853956
int

src/session_openssl.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -616,10 +616,14 @@ nc_tls_get_num_certs_wrap(void *chain)
616616
return sk_X509_num(chain);
617617
}
618618

619-
void
620-
nc_tls_get_cert_wrap(void *chain, int idx, void **cert)
619+
void *
620+
nc_tls_get_cert_wrap(void *chain, int idx)
621621
{
622-
*cert = sk_X509_value(chain, idx);
622+
if (!chain || (idx < 0)) {
623+
return NULL;
624+
}
625+
626+
return sk_X509_value(chain, idx);
623627
}
624628

625629
int

0 commit comments

Comments
 (0)