Skip to content

Commit a9f9164

Browse files
committed
Add new nua_reload_tls() API for TLS certificate hot-reload
1 parent 0106ad0 commit a9f9164

File tree

13 files changed

+357
-171
lines changed

13 files changed

+357
-171
lines changed

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,19 @@ test-driver
7070
utils/sip-date
7171
utils/sip-dig
7272
utils/sip-options
73+
libsofia-sip-ua/http/http_tag_dll.c
74+
libsofia-sip-ua/iptsec/auth_tag_dll.c
75+
libsofia-sip-ua/msg/msg_tag_dll.c
76+
libsofia-sip-ua/msg/msg_tag_ref.c
77+
libsofia-sip-ua/nea/nea_tag_dll.c
78+
libsofia-sip-ua/nta/nta_tag_dll.c
79+
libsofia-sip-ua/nth/nth_tag_dll.c
80+
libsofia-sip-ua/nua/nua_tag_dll.c
81+
libsofia-sip-ua/sdp/sdp_tag_dll.c
82+
libsofia-sip-ua/sip/sip_tag_dll.c
83+
libsofia-sip-ua/soa/soa_tag_dll.c
84+
libsofia-sip-ua/stun/stun_tag_dll.c
85+
libsofia-sip-ua/su/su_tag_dll.c
86+
libsofia-sip-ua/tport/tport_tag_dll.c
87+
libsofia-sip-ua/url/url_tag_dll.c
88+
win32/gawk.exe

libsofia-sip-ua/nta/nta.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,13 @@ void nta_agent_resolver_clean_cache(nta_agent_t *agent)
11201120
#endif
11211121
}
11221122

1123+
int nta_agent_reload_tls(nta_agent_t *agent, char const *cert_dir)
1124+
{
1125+
if (!agent || !agent->sa_tports)
1126+
return -1;
1127+
return tport_reload_tls(agent->sa_tports, cert_dir);
1128+
}
1129+
11231130
/** Return agent context. */
11241131
nta_agent_magic_t *nta_agent_magic(nta_agent_t const *agent)
11251132
{

libsofia-sip-ua/nta/sofia-sip/nta.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ nta_agent_t *nta_agent_create(su_root_t *root,
136136

137137
SOFIAPUBFUN void nta_agent_destroy(nta_agent_t *agent);
138138
SOFIAPUBFUN void nta_agent_resolver_clean_cache(nta_agent_t *agent);
139+
SOFIAPUBFUN int nta_agent_reload_tls(nta_agent_t *agent, char const *cert_dir);
139140

140141
SOFIAPUBFUN char const *nta_agent_version(nta_agent_t const *a);
141142
SOFIAPUBFUN nta_agent_magic_t *nta_agent_magic(nta_agent_t const *a);

libsofia-sip-ua/nua/nua.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include <sofia-sip/sip_status.h>
4848
#include <sofia-sip/sip_header.h>
4949
#include <sofia-sip/nta.h>
50+
#include <sofia-sip/tport_tag.h>
5051

5152
#include "sofia-sip/nua.h"
5253
#include "sofia-sip/nua_tag.h"
@@ -89,7 +90,7 @@ su_log_t nua_log[] = { SU_LOG_INIT("nua", "NUA_DEBUG", SU_DEBUG) };
8990
* @param root Pointer to a root object
9091
* @param callback Pointer to event callback function
9192
* @param magic Pointer to callback context
92-
* @param tag, value, ... List of tagged parameters
93+
* @param tag, value, ... List of tagged parameters
9394
*
9495
* @retval !=NULL a pointer to a @nua stack object
9596
* @retval NULL upon an error
@@ -1131,6 +1132,21 @@ nta_agent_t *nua_get_agent(nua_t *nua)
11311132
return NULL;
11321133
}
11331134

1135+
/** Reload TLS certificates for all TLS transports in this nua instance.
1136+
* Sends a signal to the nua event loop so the reload happens on the
1137+
* internal thread that handles signals.
1138+
*/
1139+
int nua_reload_tls(nua_t *nua, char const *cert_dir)
1140+
{
1141+
if (!nua || !cert_dir)
1142+
return -1;
1143+
1144+
enter;
1145+
1146+
return nua_signal(nua, NULL, NULL, nua_r_reload_tls, 0, NULL,
1147+
TPTAG_CERTIFICATE(cert_dir), TAG_NULL());
1148+
}
1149+
11341150
/** Set has invite of a nua handle */
11351151
void nua_handle_set_has_invite(nua_handle_t *nh, unsigned val)
11361152
{

libsofia-sip-ua/nua/nua_common.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ char const *nua_event_name(nua_event_t event)
378378
case nua_r_ack: return "nua_r_ack";
379379
case nua_r_handle_unref: return "nua_r_handle_unref";
380380
case nua_r_unref: return "nua_r_unref";
381+
case nua_r_reload_tls: return "nua_r_reload_tls";
381382
default: return "NUA_UNKNOWN";
382383
}
383384
}

libsofia-sip-ua/nua/nua_stack.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,14 @@ void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_ee_data_t *ee)
699699
case nua_r_nta_agent_resolver_clean_dns_cache:
700700
nta_agent_resolver_clean_cache(nua->nua_nta);
701701
break;
702+
case nua_r_reload_tls:
703+
{
704+
char const *cert_dir = NULL;
705+
706+
tl_gets(tags, TPTAG_CERTIFICATE_REF(cert_dir), TAG_END());
707+
nta_agent_reload_tls(nua->nua_nta, cert_dir);
708+
break;
709+
}
702710
default:
703711
break;
704712
}

libsofia-sip-ua/nua/sofia-sip/nua.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ typedef enum nua_event_e {
161161
nua_i_register, /**< Incoming REGISTER. @NEW_1_12_4. */
162162
nua_r_unref, /** Calls nua_unref() from dispatcher @NEW_1_13_3 */
163163
nua_r_handle_unref, /** Calls nua_handle_unref() from dispatcher @NEW_1_13_3 */
164-
nua_r_nta_agent_resolver_clean_dns_cache /** Calls nua_resolver_clean_dns_cache() from dispatcher @NEW_1_13_12 */
164+
nua_r_nta_agent_resolver_clean_dns_cache, /** Calls nua_resolver_clean_dns_cache() from dispatcher @NEW_1_13_12 */
165+
nua_r_reload_tls /** Calls nta_agent_reload_tls() from dispatcher @NEW_1_13_18 */
165166
} nua_event_t;
166167

167168
typedef struct event_s {
@@ -404,6 +405,7 @@ SOFIAPUBFUN void nua_unref_user(nua_t *nua);
404405
SOFIAPUBFUN void nua_handle_unref_user(nua_handle_t *nh);
405406
SOFIAPUBFUN su_home_t *nua_get_home(nua_t *nua);
406407
SOFIAPUBFUN nta_agent_t *nua_get_agent(nua_t *nua);
408+
SOFIAPUBFUN int nua_reload_tls(nua_t *nua, char const *cert_dir);
407409
SOFIAPUBFUN void nua_handle_set_has_invite(nua_handle_t *nh, unsigned val);
408410
SOFIAPUBFUN unsigned nua_handle_is_destroyed(nua_handle_t *nh);
409411
SOFIAPUBFUN void nua_handle_dialog_usage_set_refresh_range(nua_handle_t *nh,

libsofia-sip-ua/tport/sofia-sip/tport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,9 @@ TPORT_DLL int tport_has_tls(tport_t const *tport);
273273
/** Test if transport provided a verified certificate chain (TLS only) */
274274
TPORT_DLL int tport_is_verified(tport_t const *tport);
275275

276+
/** Reload TLS certificates on all TLS primaries (including WSS). */
277+
TPORT_DLL int tport_reload_tls(tport_t *self, char const *cert_dir);
278+
276279
/** Return true if transport is being updated. */
277280
TPORT_DLL int tport_is_updating(tport_t const *self);
278281

libsofia-sip-ua/tport/tport.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ typedef struct tport_nat_s tport_nat_t;
6262
#include <errno.h>
6363
#include <limits.h>
6464

65+
#if HAVE_WIN32
66+
#include <io.h>
67+
#define access(_filename, _mode) _access(_filename, _mode)
68+
#define R_OK (04)
69+
#else
70+
#include <unistd.h>
71+
#endif
72+
6573
#ifndef IPPROTO_SCTP
6674
#define IPPROTO_SCTP (132)
6775
#endif
@@ -71,6 +79,8 @@ typedef struct tport_nat_s tport_nat_t;
7179
#include <sofia-sip/rbtree.h>
7280

7381
#include "tport_internal.h"
82+
#include "tport_tls.h"
83+
#include "tport_ws.h"
7484

7585
#if HAVE_FUNC
7686
#elif HAVE_FUNCTION
@@ -280,6 +290,59 @@ int tport_is_verified(tport_t const *self)
280290
return tport_has_tls(self) && self->tp_is_connected && self->tp_verified;
281291
}
282292

293+
/** Reload TLS certificates on all TLS primary transports. */
294+
int tport_reload_tls(tport_t *self, char const *cert_dir)
295+
{
296+
su_home_t autohome[SU_HOME_AUTO_SIZE(1024)];
297+
tls_issues_t ti = {0};
298+
tport_t *tp;
299+
int reloaded = 0;
300+
301+
if (!self || !cert_dir)
302+
return -1;
303+
304+
su_home_auto(autohome, sizeof autohome);
305+
306+
ti.key = su_sprintf(autohome, "%s/%s", cert_dir, "agent.pem");
307+
if (access(ti.key, R_OK) != 0)
308+
ti.key = su_sprintf(autohome, "%s/%s", cert_dir, "tls.pem");
309+
ti.cert = ti.key;
310+
ti.CAfile = su_sprintf(autohome, "%s/%s", cert_dir, "cafile.pem");
311+
if (access(ti.CAfile, R_OK) != 0)
312+
ti.CAfile = su_sprintf(autohome, "%s/%s", cert_dir, "tls.pem");
313+
ti.CApath = su_strdup(autohome, cert_dir);
314+
ti.randFile = su_sprintf(autohome, "%s/%s", cert_dir, "tls_seed.dat");
315+
ti.configured = 1;
316+
317+
for (tp = tport_primaries(self); tp; tp = tport_next(tp)) {
318+
/* Reload WSS transport certificates */
319+
if (tp->tp_protoname && strcasecmp(tp->tp_protoname, "wss") == 0) {
320+
tport_ws_primary_t *wspri = (tport_ws_primary_t *)tp->tp_pri;
321+
if (wspri->ssl_ctx) {
322+
SSL_CTX *new_ctx = tport_wss_create_ssl_ctx(cert_dir);
323+
if (new_ctx) {
324+
SSL_CTX_free(wspri->ssl_ctx);
325+
wspri->ssl_ctx = new_ctx;
326+
reloaded++;
327+
SU_DEBUG_3(("tport_reload_tls: WSS certificates reloaded successfully\n" VA_NONE));
328+
} else {
329+
SU_DEBUG_1(("tport_reload_tls: WSS certificate reload failed\n" VA_NONE));
330+
}
331+
}
332+
} else if (tport_has_tls(tp)) {
333+
tport_tls_primary_t *tlspri = (tport_tls_primary_t *)tp->tp_pri;
334+
if (tlspri->tlspri_master) {
335+
if (tls_reload_cert(tlspri->tlspri_master, &ti) == 0)
336+
reloaded++;
337+
}
338+
}
339+
}
340+
341+
su_home_deinit(autohome);
342+
343+
return reloaded;
344+
}
345+
283346
/** Return true if transport is being updated. */
284347
int tport_is_updating(tport_t const *self)
285348
{

0 commit comments

Comments
 (0)