Compare commits

...

2 Commits

Author SHA1 Message Date
Andreas Eversberg bde5092a06 fixup "WIP: Volte support for outgoing SIP registration" 2024-04-25 20:41:31 +02:00
Andreas Eversberg dcffb4e1b1 fixup: "Add support for IMS AKA authentication configuration" 2024-04-25 20:40:45 +02:00
4 changed files with 93 additions and 20 deletions

View File

@ -400,7 +400,7 @@ int ast_sip_initialize_sorcery_auth(void)
ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "nonce_lifetime",
"32", OPT_UINT_T, 0, FLDSET(struct ast_sip_auth, nonce_lifetime));
ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "usim_ami",
"no", OPT_BOOL_T, 0, FLDSET(struct ast_sip_auth, usim_ami));
"no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_auth, usim_ami));
ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "usim_opc",
"", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, usim_opc));
ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "usim_k",

View File

@ -388,10 +388,14 @@ struct sip_outbound_registration {
enum ims_state {
/* !\brief Send first registration. */
IMS_STATE_REGISTER,
/* !\brief Wait for SIM keys to be provided. */
IMS_STATE_REGISTER_SIM,
/* !\brief Send second registration with authentication response. */
IMS_STATE_RESPONSE,
IMS_STATE_REGISTER_RESPONSE,
/* !\brief Send second registration with resync token. */
IMS_STATE_RESYNC,
/* !\brief Wait for SIM keys to be provided after resync. */
IMS_STATE_RESYNC_SIM,
/* !\brief Send third registration with authentication response after resync. */
IMS_STATE_RESYNC_RESPONSE,
/* !\breif IMS registration process failed. */
@ -885,8 +889,11 @@ static pj_status_t registration_client_send(struct sip_outbound_registration_cli
/* Create initial IMS headers and reset transport. */
if (client_state->ims_aka && client_state->ims_state == IMS_STATE_REGISTER) {
if (ims_registration_client(client_state, tdata))
if (ims_registration_client(client_state, tdata)) {
pjsip_tx_data_dec_ref(tdata);
ao2_ref(client_state, -1);
return -1;
}
}
status = pjsip_regc_send(client_state->client, tdata);
@ -1392,7 +1399,8 @@ static int handle_ims_unauthorized(struct registration_response *response, uint8
{
struct security_server sec;
struct ast_sip_auth *auth;
uint8_t out_ik[16], out_ck[16];
pj_str_t algo;
uint8_t rand[16], autn[16], out_ik[16], out_ck[16];
int rc;
/* Remove existing autorization header. */
@ -1406,12 +1414,29 @@ static int handle_ims_unauthorized(struct registration_response *response, uint8
return -1;
}
if (volte_get_auth(&response->client_state->volte, response->rdata,
(response->code == 401) ? PJSIP_H_WWW_AUTHENTICATE : PJSIP_H_PROXY_AUTHENTICATE,
&algo, rand, autn)) {
ast_log(LOG_ERROR, "Failed to parse the authenticate header.\n");
return -1;
}
if (!(auth = ims_get_sip_auth(&response->client_state->outbound_auths)))
return -1;
rc = volte_authenticate(&response->client_state->volte, response->rdata,
(response->code == 401) ? PJSIP_H_WWW_AUTHENTICATE : PJSIP_H_PROXY_AUTHENTICATE,
auth->usim_opc, auth->usim_k, auth->usim_sqn, (uint8_t *)auth->ims_res,
if (auth->usim_ami) {
volte_send_authrequest(&algo, rand, autn);
if (response->client_state->ims_state == IMS_STATE_REGISTER)
response->client_state->ims_state = IMS_STATE_REGISTER_SIM;
else
response->client_state->ims_state = IMS_STATE_RESYNC_SIM;
return 0;
#warning das folgende muss gesplittet werden, es muss volte_auth aufgerufen werden oder es muss der authrequest gesendet werden. der authresponse muss weitermachen, aber nur wenn ein pendig-authrequest gesendet wurde.
#warning das register muss per AMI gesteuert werden. wie muss die config aussehen,damit das nicht automatisch geht?
}
rc = volte_authenticate(&response->client_state->volte, auth->usim_opc, auth->usim_k,
auth->usim_sqn, rand, autn, (uint8_t *)auth->ims_res,
out_ik, out_ck, out_auts);
if (rc == -EAGAIN) {
if (response->client_state->ims_state == IMS_STATE_RESYNC) {
@ -1440,7 +1465,7 @@ static int handle_ims_unauthorized(struct registration_response *response, uint8
return -1;
}
if (response->client_state->ims_state == IMS_STATE_REGISTER)
response->client_state->ims_state = IMS_STATE_RESPONSE;
response->client_state->ims_state = IMS_STATE_REGISTER_RESPONSE;
else
response->client_state->ims_state = IMS_STATE_RESYNC_RESPONSE;
response->client_state->auth_attempted = 0;
@ -1448,6 +1473,13 @@ static int handle_ims_unauthorized(struct registration_response *response, uint8
return 0;
}
static int ami_authresponse(struct mansession *s, const struct message *m)
{
// astman_send_error(s, m, "Park action failed\n");
manager_event(0, "HALLO", "Meetme: \r\n");
return 0;
}
/*! \brief Callback function for handling a response to a registration attempt */
static int handle_registration_response(void *data)
{
@ -1475,6 +1507,11 @@ static int handle_registration_response(void *data)
response->client_state->ims_state = IMS_STATE_FAILED;
goto ims_failed;
}
/* Wait for the SIM to respond. */
if (response->client_state->ims_state == IMS_STATE_REGISTER_SIM ||
response->client_state->ims_state == IMS_STATE_RESYNC_SIM)
return 0;
#warning do ao2_ref(response, -1); once the sim responded or timed out
}
if (response->code == 408 || response->code == 503) {
@ -2982,6 +3019,7 @@ static int unload_module(void)
ast_manager_unregister("PJSIPShowRegistrationsOutbound");
ast_manager_unregister("PJSIPUnregister");
ast_manager_unregister("PJSIPRegister");
ast_manager_unregister("AuthResponse");
ast_cli_unregister_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
ast_sip_unregister_cli_formatter(cli_formatter);
@ -3115,6 +3153,7 @@ static int load_module(void)
ast_manager_register_xml("PJSIPUnregister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_unregister);
ast_manager_register_xml("PJSIPRegister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_register);
ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_show_outbound_registrations);
ast_manager_register_xml_core("AuthResponse", 0, ami_authresponse);
/* Clear any previous statsd gauges in case we weren't shutdown cleanly */
ast_statsd_log("PJSIP.registrations.count", AST_STATSD_GAUGE, 0);

View File

@ -18,6 +18,7 @@
#include "asterisk.h"
#include "asterisk/utils.h"
#include "asterisk/manager.h"
#include <pjsip.h>
@ -25,6 +26,7 @@
#include "milenage.h"
#define fmt_str(str) (int)(str).slen, (str).ptr
#define fmt_strp(strp) (int)(strp)->slen, (strp)->ptr
/* Socket for transform configuration */
static struct mnl_socket *g_mnl_socket = NULL;
@ -507,6 +509,7 @@ pj_status_t volte_reset_transport(struct volte_states *volte)
/* Cleanup old transport. */
old_port_c = pj_sockaddr_get_port(&volte->local_addr_c);
printf("port=%d\n", old_port_c);
if (old_port_c > 0 && old_port_c < 65535) {
if (!volte->transport) {
ast_log(LOG_ERROR, "No transport set. Please fix!\n");
@ -769,15 +772,11 @@ static pj_status_t my_hex_to_octet_string(const char *name, const char *input, u
return PJ_SUCCESS;
}
pj_status_t volte_authenticate(struct volte_states *volte, pjsip_rx_data *rdata, pjsip_hdr_e auth_type,
const char *opc_str, const char *k_str, const char *sqn_str, uint8_t *out_res,
uint8_t *out_ik, uint8_t *out_ck, uint8_t *out_auts)
pj_status_t volte_get_auth(struct volte_states *volte, pjsip_rx_data *rdata, pjsip_hdr_e auth_type, pj_str_t *algo,
uint8_t *rand, uint8_t *autn)
{
pjsip_www_authenticate_hdr *auth_hdr;
uint8_t opc[16], k[16], sqn[6], rand_auth[32], *rand = rand_auth, *autn = rand_auth + 16;
size_t out_res_len = 8;
int rc;
pj_status_t status;
uint8_t rand_autn[32];
auth_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, auth_type, NULL);
if (!auth_hdr || !auth_hdr->challenge.digest.nonce.ptr || !auth_hdr->challenge.digest.algorithm.ptr) {
@ -794,6 +793,40 @@ pj_status_t volte_authenticate(struct volte_states *volte, pjsip_rx_data *rdata,
return -EINVAL;
}
*algo = auth_hdr->challenge.digest.algorithm;
ast_base64decode(rand_autn, auth_hdr->challenge.digest.nonce.ptr, sizeof(rand_autn));
memcpy(rand, rand_autn, 16);
memcpy(autn, rand_autn + 16, 16);
return PJ_SUCCESS;
}
pj_status_t volte_send_authrequest(pj_str_t *algo, uint8_t *rand, uint8_t *autn)
{
char rand_str[33] = " ", autn_str[33] = " ";
int i;
for (i = 0; i < 16; i++) {
sprintf(rand_str + 2 * i, "%02x", rand[i]);
sprintf(autn_str + 2 * i, "%02x", autn[i]);
}
manager_event(0, "AuthRequest", "Algorithm:%.*s\r\nRAND:%s\r\nAUTN:%s",
fmt_strp(algo), rand_str, autn_str);
return PJ_SUCCESS;
}
pj_status_t volte_authenticate(struct volte_states *volte, const char *opc_str, const char *k_str, const char *sqn_str,
uint8_t *rand, uint8_t *autn, uint8_t *out_res, uint8_t *out_ik, uint8_t *out_ck,
uint8_t *out_auts)
{
uint8_t opc[16], k[16], sqn[6];
size_t out_res_len = 8;
int rc;
pj_status_t status;
status = my_hex_to_octet_string("OPC", opc_str, opc, sizeof(opc));
if (status)
return status;
@ -804,8 +837,6 @@ pj_status_t volte_authenticate(struct volte_states *volte, pjsip_rx_data *rdata,
if (status)
return status;
ast_base64decode(rand_auth, auth_hdr->challenge.digest.nonce.ptr, sizeof(rand_auth));
rc = milenage_check(opc, k, sqn, rand, autn, out_ik, out_ck, out_res, &out_res_len, out_auts);
if (rc == -1) {
ast_log(LOG_ERROR, "Milenage authentication failed.\n");

View File

@ -46,7 +46,10 @@ pj_status_t volte_set_transport(struct volte_states *volte, pjsip_tx_data *tdata
uint16_t remote_port_c, uint16_t remote_port_s);
pj_status_t volte_get_security_server(struct volte_states *volte, pjsip_rx_data *rdata, struct security_server *sec);
pj_status_t volte_add_security_verify(struct volte_states *volte, pjsip_tx_data *tdata);
pj_status_t volte_authenticate(struct volte_states *volte, pjsip_rx_data *rdata, pjsip_hdr_e auth_type,
const char *opc_str, const char *k_str, const char *sqn_str, uint8_t *out_res,
uint8_t *out_ik, uint8_t *out_ck, uint8_t *out_auts);
pj_status_t volte_get_auth(struct volte_states *volte, pjsip_rx_data *rdata, pjsip_hdr_e auth_type, pj_str_t *algo,
uint8_t *rand, uint8_t *autn);
pj_status_t volte_send_authrequest(pj_str_t *algo, uint8_t *rand, uint8_t *autn);
pj_status_t volte_authenticate(struct volte_states *volte, const char *opc_str, const char *k_str, const char *sqn_str,
uint8_t *rand, uint8_t *autn, uint8_t *out_res, uint8_t *out_ik, uint8_t *out_ck,
uint8_t *out_auts);
pj_status_t volte_add_auts(struct volte_states *volte, pjsip_tx_data *tdata, uint8_t *auts);