From aa8fad43899853178cfd89c17cf39c60764bd56f Mon Sep 17 00:00:00 2001 From: Maximilian Fridrich Date: Wed, 31 Jul 2024 11:08:53 +0200 Subject: [PATCH] sip/transp: add client certificate to all TLS transports Currently, when a client certificate is added to a SIP transport, it is only added to the first matching transport in the transport list. Then, if multiple SIP transports exist (e.g if there are multiple network interfaces), the certificate might not be present in the transport when it is needed. Now, the certificate is added to all matching transports. --- src/sip/transp.c | 89 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 23 deletions(-) diff --git a/src/sip/transp.c b/src/sip/transp.c index 5a6506a96..f0a490144 100644 --- a/src/sip/transp.c +++ b/src/sip/transp.c @@ -47,6 +47,12 @@ struct sip_ccert { }; +struct ccert_data { + uint32_t hsup; + struct sip_ccert *ccert; +}; + + struct sip_transport { struct le le; struct sa laddr; @@ -191,6 +197,33 @@ static const struct sip_transport *transp_find(struct sip *sip, } +static struct le *transp_apply_all(struct sip *sip, enum sip_transp tp, int af, + list_apply_h ah, void *arg) +{ + struct le *le; + + if (!ah) + return NULL; + + for (le = sip->transpl.head; le; le = le->next) { + + const struct sip_transport *transp = le->data; + const struct sa *laddr = &transp->laddr; + + if (transp->tp != tp) + continue; + + if (af != AF_UNSPEC && sa_af(laddr) != af) + continue; + + if (ah(le, arg)) + return le; + } + + return NULL; +} + + static struct sip_conn *conn_find(struct sip *sip, const struct sa *paddr, bool secure) { @@ -1401,6 +1434,27 @@ int sip_transp_add_websock(struct sip *sip, enum sip_transp tp, } +static bool add_ccert(struct le *le, void *arg) +{ + const struct sip_transport *transp = le->data; + struct ccert_data *cc = arg; + + if (!cc->ccert->he.list) + hash_append(transp->ht_ccert, cc->hsup, &cc->ccert->he, + cc->ccert); + else { + struct sip_ccert *ccert = mem_zalloc(sizeof(*ccert), NULL); + if (!ccert) + return false; + + ccert->file = cc->ccert->file; + hash_append(transp->ht_ccert, cc->hsup, &ccert->he, ccert); + } + + return false; +} + + /** * Add a client certificate to the TLS transport object * Client certificates are saved as hash-table. @@ -1416,10 +1470,9 @@ int sip_transp_add_ccert(struct sip *sip, const struct uri *uri, const char *cert) { int err = 0; - const struct sip_transport *transp = NULL; struct sip_ccert *ccert = NULL; + struct ccert_data cc_data; struct mbuf *sup = NULL; - uint32_t hsup = 0; if (!sip || !uri || !cert) return EINVAL; @@ -1435,30 +1488,20 @@ int sip_transp_add_ccert(struct sip *sip, const struct uri *uri, mbuf_set_pos(sup, 0); - hsup = hash_joaat(mbuf_buf(sup), mbuf_get_left(sup)); - transp = transp_find(sip, SIP_TRANSP_TLS, AF_INET, NULL); - if (transp) { - ccert = mem_zalloc(sizeof(*ccert), NULL); - if (!ccert) { - err = ENOMEM; - goto out; - } - - pl_set_str(&ccert->file, cert); - hash_append(transp->ht_ccert, hsup, &ccert->he, ccert); + ccert = mem_zalloc(sizeof(*ccert), NULL); + if (!ccert) { + err = ENOMEM; + goto out; } + pl_set_str(&ccert->file, cert); - transp = transp_find(sip, SIP_TRANSP_TLS, AF_INET6, NULL); - if (transp) { - ccert = mem_zalloc(sizeof(*ccert), NULL); - if (!ccert) { - err = ENOMEM; - goto out; - } + cc_data.hsup = hash_joaat(mbuf_buf(sup), mbuf_get_left(sup)); + cc_data.ccert = ccert; - pl_set_str(&ccert->file, cert); - hash_append(transp->ht_ccert, hsup, &ccert->he, ccert); - } + (void)transp_apply_all(sip, SIP_TRANSP_TLS, AF_INET, add_ccert, + &cc_data); + (void)transp_apply_all(sip, SIP_TRANSP_TLS, AF_INET6, add_ccert, + &cc_data); out: mem_deref(sup);