29 #define _TRACE_PREFIX_ "pjss",__LINE__, ""
32 #include "asterisk/res_pjsip.h"
33 #include "asterisk/res_pjsip_session.h"
37 #include "asterisk/res_stir_shaken.h"
39 static const pj_str_t identity_hdr_str = {
"Identity", 8 };
40 static const pj_str_t date_hdr_str = {
"Date", 4 };
43 enum sip_response_code {
44 SIP_RESPONSE_CODE_OK = 200,
45 SIP_RESPONSE_CODE_STALE_DATE = 403,
46 SIP_RESPONSE_CODE_USE_IDENTITY_HEADER = 428,
47 SIP_RESPONSE_CODE_BAD_IDENTITY_INFO = 436,
48 SIP_RESPONSE_CODE_UNSUPPORTED_CREDENTIAL = 437,
49 SIP_RESPONSE_CODE_INVALID_IDENTITY_HEADER = 438,
50 SIP_RESPONSE_CODE_USE_SUPPORTED_PASSPORT_FORMAT = 428,
51 SIP_RESPONSE_CODE_INTERNAL_ERROR = 500,
54 #define SIP_RESPONSE_CODE_OK_STR "OK"
56 #define SIP_RESPONSE_CODE_STALE_DATE_STR "Stale Date"
57 #define SIP_RESPONSE_CODE_USE_IDENTITY_HEADER_STR "Use Identity Header"
58 #define SIP_RESPONSE_CODE_USE_SUPPORTED_PASSPORT_FORMAT_STR "Use Supported PASSporT Format"
59 #define SIP_RESPONSE_CODE_BAD_IDENTITY_INFO_STR "Bad Identity Info"
60 #define SIP_RESPONSE_CODE_UNSUPPORTED_CREDENTIAL_STR "Unsupported Credential"
61 #define SIP_RESPONSE_CODE_INVALID_IDENTITY_HEADER_STR "Invalid Identity Header"
62 #define SIP_RESPONSE_CODE_INTERNAL_ERROR_STR "Internal Error"
64 #define response_to_str(_code) \
68 static const char *sip_response_code_to_str(
enum sip_response_code code)
71 response_to_str(SIP_RESPONSE_CODE_OK)
72 response_to_str(SIP_RESPONSE_CODE_STALE_DATE)
73 response_to_str(SIP_RESPONSE_CODE_USE_IDENTITY_HEADER)
74 response_to_str(SIP_RESPONSE_CODE_BAD_IDENTITY_INFO)
75 response_to_str(SIP_RESPONSE_CODE_UNSUPPORTED_CREDENTIAL)
76 response_to_str(SIP_RESPONSE_CODE_INVALID_IDENTITY_HEADER)
83 #define translate_code(_vs_rc, _sip_rc) \
84 case AST_STIR_SHAKEN_VS_ ## _vs_rc: \
85 return SIP_RESPONSE_CODE_ ## _sip_rc;
87 static enum sip_response_code vs_code_to_sip_code(
88 enum ast_stir_shaken_vs_response_code vs_rc)
96 translate_code(SUCCESS, OK)
97 translate_code(DISABLED, OK)
98 translate_code(INVALID_ARGUMENTS, INTERNAL_ERROR)
99 translate_code(INTERNAL_ERROR, INTERNAL_ERROR)
100 translate_code(NO_IDENTITY_HDR, USE_IDENTITY_HEADER)
101 translate_code(NO_DATE_HDR, STALE_DATE)
102 translate_code(DATE_HDR_PARSE_FAILURE, STALE_DATE)
103 translate_code(DATE_HDR_EXPIRED, STALE_DATE)
104 translate_code(NO_JWT_HDR, INVALID_IDENTITY_HEADER)
105 translate_code(INVALID_OR_NO_X5U, INVALID_IDENTITY_HEADER)
106 translate_code(CERT_CACHE_MISS, INVALID_IDENTITY_HEADER)
107 translate_code(CERT_CACHE_INVALID, INVALID_IDENTITY_HEADER)
108 translate_code(CERT_CACHE_EXPIRED, INVALID_IDENTITY_HEADER)
109 translate_code(CERT_RETRIEVAL_FAILURE, BAD_IDENTITY_INFO)
110 translate_code(CERT_CONTENTS_INVALID, UNSUPPORTED_CREDENTIAL)
111 translate_code(CERT_NOT_TRUSTED, UNSUPPORTED_CREDENTIAL)
112 translate_code(CERT_DATE_INVALID, UNSUPPORTED_CREDENTIAL)
113 translate_code(CERT_NO_TN_AUTH_EXT, UNSUPPORTED_CREDENTIAL)
114 translate_code(CERT_NO_SPC_IN_TN_AUTH_EXT, UNSUPPORTED_CREDENTIAL)
115 translate_code(NO_RAW_KEY, UNSUPPORTED_CREDENTIAL)
116 translate_code(SIGNATURE_VALIDATION, INVALID_IDENTITY_HEADER)
117 translate_code(NO_IAT, INVALID_IDENTITY_HEADER)
118 translate_code(IAT_EXPIRED, STALE_DATE)
119 translate_code(INVALID_OR_NO_PPT, INVALID_IDENTITY_HEADER)
120 translate_code(INVALID_OR_NO_ALG, INVALID_IDENTITY_HEADER)
121 translate_code(INVALID_OR_NO_TYP, INVALID_IDENTITY_HEADER)
122 translate_code(INVALID_OR_NO_ATTEST, INVALID_IDENTITY_HEADER)
123 translate_code(NO_ORIGID, INVALID_IDENTITY_HEADER)
124 translate_code(NO_ORIG_TN, INVALID_IDENTITY_HEADER)
125 translate_code(NO_DEST_TN, INVALID_IDENTITY_HEADER)
126 translate_code(INVALID_HEADER, INVALID_IDENTITY_HEADER)
127 translate_code(INVALID_GRANT, INVALID_IDENTITY_HEADER)
128 translate_code(INVALID_OR_NO_GRANTS, INVALID_IDENTITY_HEADER)
129 translate_code(CID_ORIG_TN_MISMATCH, INVALID_IDENTITY_HEADER)
130 translate_code(RESPONSE_CODE_MAX, INVALID_IDENTITY_HEADER)
136 enum process_failure_rc {
137 PROCESS_FAILURE_CONTINUE = 0,
138 PROCESS_FAILURE_REJECT,
139 PROCESS_FAILURE_SYSTEM_FAILURE,
143 enum sip_response_code response_code)
145 ast_sip_session_terminate(session, response_code);
151 pjsip_rx_data *rdata,
enum ast_stir_shaken_vs_response_code vs_rc)
153 enum sip_response_code response_code = vs_code_to_sip_code(vs_rc);
154 pj_str_t response_str;
155 const char *response_string =
156 sip_response_code_to_str(response_code);
157 enum stir_shaken_failure_action_enum failure_action =
158 ast_stir_shaken_vs_get_failure_action(ctx);
159 const char *tag = ast_sip_session_get_name(session);
160 SCOPE_ENTER(1,
"%s: FA: %d RC: %d\n", tag,
161 failure_action, response_code);
163 pj_cstr(&response_str, response_string);
165 if (failure_action == stir_shaken_failure_action_REJECT_REQUEST) {
166 reject_incoming_call(session, response_code);
167 SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_REJECT,
168 "%s: Rejecting request and terminating session\n",
172 ast_stir_shaken_vs_ctx_set_response_code(ctx, vs_rc);
173 ast_stir_shaken_add_result_to_channel(ctx);
175 if (failure_action == stir_shaken_failure_action_CONTINUE_RETURN_REASON) {
176 int rc = ast_sip_session_add_reason_header(session,
177 ast_stir_shaken_vs_get_use_rfc9410_responses(ctx) ?
"STIR" :
"SIP",
178 response_code, response_str.ptr);
180 SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_SYSTEM_FAILURE,
181 "%s: Failed to add Reason header\n", tag);
183 SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_CONTINUE,
184 "%s: Attaching reason code to session\n", tag);
186 SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_CONTINUE,
187 "%s: Continuing\n", tag);
200 static int stir_shaken_incoming_request(
struct ast_sip_session *session, pjsip_rx_data *rdata)
204 RAII_VAR(
char *, payload, NULL, ast_free);
205 char *identity_hdr_val;
208 const char *session_name = ast_sip_session_get_name(session);
210 enum ast_stir_shaken_vs_response_code vs_rc;
211 enum process_failure_rc p_rc;
212 SCOPE_ENTER(1,
"%s: Enter\n", session_name);
215 SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR,
"No session\n");
218 SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR,
"%s: No channel\n", session_name);
221 SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR,
"%s: No rdata\n", session_name);
225 if (rdata->msg_info.to->tag.slen) {
226 SCOPE_EXIT_RTN_VALUE(0,
"%s: Reinvite. No action needed\n", session_name);
233 if (ast_strlen_zero(caller_id)
235 SCOPE_EXIT_RTN_VALUE(0,
"%s: No callerid or profile name. No action needed\n", session_name);
238 vs_rc = ast_stir_shaken_vs_ctx_create(caller_id, chan,
241 if (vs_rc == AST_STIR_SHAKEN_VS_DISABLED) {
242 SCOPE_EXIT_RTN_VALUE(0,
"%s: VS Disabled\n", session_name);
243 }
else if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
244 reject_incoming_call(session, 500);
245 SCOPE_EXIT_RTN_VALUE(1,
"%s: Unable to create context. Call terminated\n",
249 identity_hdr_val = ast_sip_rdata_get_header_value(rdata, identity_hdr_str);
250 if (ast_strlen_zero(identity_hdr_val)) {
251 p_rc = process_failure(ctx, caller_id, session, rdata,
252 AST_STIR_SHAKEN_VS_NO_IDENTITY_HDR);
253 if (p_rc == PROCESS_FAILURE_CONTINUE) {
254 SCOPE_EXIT_RTN_VALUE(0,
"%s: No Identity header found. Call continuing\n",
257 SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR,
"%s: No Identity header found. Call terminated\n",
261 vs_rc = ast_stir_shaken_vs_ctx_add_identity_hdr(ctx, identity_hdr_val);
262 if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
263 reject_incoming_call(session, 500);
264 SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR,
"%s: Unable to add Identity header. Call terminated.\n",
268 date_hdr_val = ast_sip_rdata_get_header_value(rdata, date_hdr_str);
269 if (ast_strlen_zero(date_hdr_val)) {
270 p_rc = process_failure(ctx, caller_id, session, rdata,
271 AST_STIR_SHAKEN_VS_NO_DATE_HDR);
272 if (p_rc == PROCESS_FAILURE_CONTINUE) {
273 SCOPE_EXIT_RTN_VALUE(0,
"%s: No Date header found. Call continuing\n",
276 SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR,
"%s: No Date header found. Call terminated\n",
280 ast_stir_shaken_vs_ctx_add_date_hdr(ctx, date_hdr_val);
281 if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
282 reject_incoming_call(session, 500);
283 SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR,
"%s: Unable to add Date header. Call terminated.\n",
287 vs_rc = ast_stir_shaken_vs_verify(ctx);
288 if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
289 p_rc = process_failure(ctx, caller_id, session, rdata, vs_rc);
290 if (p_rc == PROCESS_FAILURE_CONTINUE) {
291 SCOPE_EXIT_RTN_VALUE(0,
"%s: Verification failed. Call continuing\n",
294 SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR,
"%s: Verification failed. Call terminated\n",
299 ast_stir_shaken_add_result_to_channel(ctx);
301 SCOPE_EXIT_RTN_VALUE(0,
"Passed\n");
304 static void add_fingerprints_if_present(
struct ast_sip_session *session,
312 const char *tag = ast_sip_session_get_name(session);
314 SCOPE_ENTER(4,
"%s: Check %zu media sessions for fingerprints\n",
317 if (!ast_stir_shaken_as_ctx_wants_fingerprints(ctx)) {
318 SCOPE_EXIT_RTN(
"%s: Fingerprints not needed\n", tag);
321 for (i = 0; i < count; i++) {
326 ast_trace(1,
"Session: %d: No session or rtp instance\n", i);
333 ast_stir_shaken_as_ctx_add_fingerprint(ctx,
336 SCOPE_EXIT_RTN(
"%s: Done\n", tag);
339 static char *get_dest_tn(pjsip_tx_data *tdata,
const char *tag)
341 pjsip_fromto_hdr *to;
343 char *dest_tn = NULL;
344 SCOPE_ENTER(4,
"%s: Enter\n", tag);
346 to = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_TO, NULL);
348 SCOPE_EXIT_RTN_VALUE(NULL,
"%s: Failed to find To header\n", tag);
351 uri = pjsip_uri_get_uri(to->uri);
353 SCOPE_EXIT_RTN_VALUE(NULL,
354 "%s: Failed to retrieve URI from To header\n", tag);
359 SCOPE_EXIT_RTN_VALUE(NULL,
360 "%s: Failed to allocate memory for dest_tn\n", tag);
363 ast_copy_pj_str(dest_tn, &uri->user, uri->user.slen + 1);
365 SCOPE_EXIT_RTN_VALUE(dest_tn,
"%s: Done\n", tag);
368 static void add_date_header(
const struct ast_sip_session *session, pjsip_tx_data *tdata)
370 pjsip_fromto_hdr *old_date;
371 const char *session_name = ast_sip_session_get_name(session);
372 SCOPE_ENTER(1,
"%s: Enter\n", session_name);
374 old_date = pjsip_msg_find_hdr_by_name(tdata->msg, &date_hdr_str, NULL);
376 SCOPE_EXIT_RTN(
"Found existing Date header, no need to add one\n");
379 ast_sip_add_date_header(tdata);
380 SCOPE_EXIT_RTN(
"Done\n");
383 static void stir_shaken_outgoing_request(
struct ast_sip_session *session,
384 pjsip_tx_data *tdata)
388 pjsip_generic_string_hdr *old_identity;
389 pjsip_generic_string_hdr *identity_hdr;
390 pj_str_t identity_val;
394 enum ast_stir_shaken_as_response_code as_rc;
395 const char *session_name = ast_sip_session_get_name(session);
396 SCOPE_ENTER(1,
"%s: Enter\n", session_name);
399 SCOPE_EXIT_LOG_RTN(LOG_ERROR,
"No session\n");
402 SCOPE_EXIT_LOG_RTN(LOG_ERROR,
"%s: No channel\n", session_name);
405 SCOPE_EXIT_LOG_RTN(LOG_ERROR,
"%s: No tdata\n", session_name);
408 old_identity = pjsip_msg_find_hdr_by_name(tdata->msg, &identity_hdr_str, NULL);
410 SCOPE_EXIT_RTN(
"Found an existing Identity header\n");
413 dest_tn = get_dest_tn(tdata, session_name);
415 SCOPE_EXIT_LOG_RTN(LOG_ERROR,
"%s: Unable to find destination tn\n",
420 ast_channel_lock(session->
channel);
421 effective_id = ast_channel_connected_effective_id(session->
channel);
423 ast_channel_unlock(session->
channel);
425 if (!ast_sip_can_present_connected_id(session, &connected_id)) {
428 SCOPE_EXIT_RTN(
"Unable to get caller id\n");
431 as_rc = ast_stir_shaken_as_ctx_create(connected_id.number.str,
439 if (as_rc == AST_STIR_SHAKEN_AS_DISABLED) {
440 SCOPE_EXIT_RTN(
"%s: AS Disabled\n", session_name);
441 }
else if (as_rc != AST_STIR_SHAKEN_AS_SUCCESS) {
442 SCOPE_EXIT_RTN(
"%s: Unable to create context\n",
446 add_date_header(session, tdata);
447 add_fingerprints_if_present(session, ctx);
449 as_rc = ast_stir_shaken_attest(ctx, &identity_str);
450 if (as_rc != AST_STIR_SHAKEN_AS_SUCCESS) {
453 "%s: Failed to create attestation\n", session_name);
456 ast_trace(1,
"%s: Identity header: %s\n", session_name, identity_str);
457 identity_val = pj_str(identity_str);
458 identity_hdr = pjsip_generic_string_hdr_create(tdata->pool, &identity_hdr_str, &identity_val);
459 ast_free(identity_str);
462 SCOPE_EXIT_LOG_RTN(LOG_ERROR,
463 "%s: Unable to create Identity header\n", session_name);
466 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)identity_hdr);
469 SCOPE_EXIT_RTN(
"Done\n");
474 .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1,
475 .incoming_request = stir_shaken_incoming_request,
476 .outgoing_request = stir_shaken_outgoing_request,
479 static int unload_module(
void)
481 ast_sip_session_unregister_supplement(&stir_shaken_supplement);
485 static int load_module(
void)
487 ast_sip_session_register_supplement(&stir_shaken_supplement);
491 #undef AST_BUILDOPT_SUM
492 #define AST_BUILDOPT_SUM ""
494 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"PJSIP STIR/SHAKEN Module for Asterisk",
495 .support_level = AST_MODULE_SUPPORT_CORE,
497 .unload = unload_module,
499 .requires =
"res_pjsip,res_pjsip_session,res_stir_shaken",
Information needed to identify an endpoint in a call.
Main Channel structure associated with a channel.
struct ast_sip_endpoint * endpoint
char * str
Subscriber phone number (Malloced)
Asterisk main include file. File version handling, generic pbx functions.
struct ast_sip_session_media_state * pending_media_state
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
const char *(* get_fingerprint)(struct ast_rtp_instance *instance)
void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src)
Copy the source party id information to the destination party id.
#define SCOPE_EXIT_LOG(__log_level,...)
void ast_party_id_free(struct ast_party_id *doomed)
Destroy the party id contents.
A structure describing a SIP session.
enum ast_rtp_dtls_hash(* get_fingerprint_hash)(struct ast_rtp_instance *instance)
struct ast_channel * channel
#define ast_malloc(len)
A wrapper for malloc()
Structure that represents the optional DTLS SRTP support within an RTP engine.
struct ast_rtp_engine_dtls * ast_rtp_instance_get_dtls(struct ast_rtp_instance *instance)
Obtain a pointer to the DTLS support present on an RTP instance.
ast_rtp_dtls_hash
DTLS fingerprint hashes.
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
void ast_party_id_init(struct ast_party_id *init)
Initialize the given party id structure.
const ast_string_field stir_shaken_profile
A supplement to SIP message processing.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Pluggable RTP Architecture.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
struct ast_party_number number
Subscriber phone number.