blob: 091f5dabbc697f5222a8e5c6a6a54a1c5a6c78e0 [file] [log] [blame]
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +02001/* Component implementing a IMS server towards Asterisk's IMS UE
2 * (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
3 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
4 * All rights reserved.
5 *
6 * Released under the terms of GNU General Public License, Version 2 or
7 * (at your option) any later version.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11module IMS_ConnectionHandler {
12
Pau Espin Pedrol717379f2024-05-17 18:36:51 +020013import from TCCEncoding_Functions all;
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020014import from TCCOpenSecurity_Functions all;
15import from General_Types all;
16import from Osmocom_Types all;
17import from Native_Functions all;
18import from Misc_Helpers all;
19
Pau Espin Pedrola674d612024-05-14 19:56:33 +020020/* the PIPE asp port allows us to interact with ip xfrm via stdin/stdout */
21import from PIPEasp_PortType all;
22import from PIPEasp_Types all;
23import from PIPEasp_Templates all;
24
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020025import from SDP_Types all;
26import from SDP_Templates all;
27
28import from SIP_Emulation all;
29import from SIPmsg_Types all;
30import from SIP_Templates all;
31
Pau Espin Pedrola674d612024-05-14 19:56:33 +020032
33modulepar {
34 charstring mp_ipsec_setup_script_path := "./IMS_ipsec_setup.sh";
35}
36
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +020037const char c_sip_server_name := "osmo-ttcn3-hacks/0.23";
38
39
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020040type port IMSCoord_PT message
41{
42 inout charstring;
43} with { extension "internal" };
44
45const charstring IMS_COORD_CMD_REGISTERED := "COORD_CMD_REGISTERED";
46
47type component IMS_ConnHdlr extends SIP_ConnHdlr {
48 var charstring g_name;
49 var IMS_ConnHdlrPars g_pars;
50 timer g_Tguard;
51 var PDU_SIP_Request g_rx_sip_req;
52 var PDU_SIP_Response g_rx_sip_resp;
53
54 port IMSCoord_PT COORD;
Pau Espin Pedrola674d612024-05-14 19:56:33 +020055 port PIPEasp_PT PIPE;
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020056}
57type record of IMS_ConnHdlr IMS_ConnHdlrList;
58
59type record IMS_ConnHdlrPars {
60 float t_guard,
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +020061 charstring realm,
62 charstring local_sip_host,
63 uint16_t local_sip_port,
64 charstring remote_sip_host optional,
65 uint16_t remote_sip_port optional,
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020066 charstring user,
67 charstring display_name,
68 charstring password,
Pau Espin Pedrol0c5c6472024-05-21 13:13:49 +020069 /* Expected User-Location-Info in P-Access-Network-Info */
70 charstring uli_str,
Pau Espin Pedrol717379f2024-05-17 18:36:51 +020071 octetstring rand,
72 octetstring autn,
Pau Espin Pedrola674d612024-05-14 19:56:33 +020073 charstring ipsec_auth_key,
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +020074 integer ipsec_local_spi_c,
75 integer ipsec_local_spi_s,
76 integer ipsec_remote_spi_c optional,
77 integer ipsec_remote_spi_s optional,
Pau Espin Pedrola674d612024-05-14 19:56:33 +020078 uint16_t ipsec_remote_port_c optional,
79 uint16_t ipsec_remote_port_s optional,
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020080 SipUrl registrar_sip_req_uri,
81 SipAddr registrar_sip_record,
82 CallidString registrar_sip_call_id,
83 integer registrar_sip_seq_nr,
84 Via local_via,
85 SipUrl local_sip_url_ext,
86 SipAddr local_sip_record,
87 Contact local_contact,
88 IMS_CallPars cp optional
89}
90type record of IMS_ConnHdlrPars IMS_ConnHdlrParsList;
91
92type record IMS_CallParsMT {
93 /* Whether to wait for COORD.receive(COORD_CMD_PICKUP) before accepting the call. */
94 boolean wait_coord_cmd_pickup,
95 /* Whether to expect CANCEL instead of ACK as answer to our OK */
96 boolean exp_cancel
97}
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +020098template (value) IMS_CallParsMT t_IMS_CallParsMT := {
99 wait_coord_cmd_pickup := false,
100 exp_cancel := false
101}
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +0200102
103type record IMS_CallPars {
104 SipAddr calling optional,
105 SipAddr called optional,
106
107 SipAddr from_addr optional,
108 SipAddr to_addr optional,
109
110 CallidString sip_call_id,
111 integer sip_seq_nr,
112 charstring sip_body optional,
113
114 charstring local_rtp_addr,
115 uint16_t local_rtp_port,
116
117 SDP_Message peer_sdp optional,
118 IMS_CallParsMT mt
119}
120
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200121template (value) IMS_CallPars t_IMS_CallPars(charstring local_rtp_addr,
122 uint16_t local_rtp_port := 0,
123 template (omit) SipAddr calling := omit,
124 template (omit) SipAddr called := omit) := {
125 calling := calling,
126 called := called,
127 from_addr := omit,
128 to_addr := omit,
129 sip_call_id := hex2str(f_rnd_hexstring(15)),
130 sip_seq_nr := f_sip_rand_seq_nr(),
131 sip_body := omit,
132 local_rtp_addr := local_rtp_addr,
133 local_rtp_port := local_rtp_port,
134 peer_sdp := omit,
135 mt := t_IMS_CallParsMT
136}
137
138template (value) IMS_ConnHdlrPars t_IMS_Pars(charstring local_sip_host,
139 uint16_t local_sip_port,
140 charstring user,
141 charstring display_name := "Anonymous",
142 charstring password := "secret",
143 template (omit) IMS_CallPars cp := omit) := {
144 t_guard := 30.0,
145 realm := local_sip_host,
146 local_sip_host := local_sip_host,
147 local_sip_port := local_sip_port,
148 remote_sip_host := omit,
149 remote_sip_port := omit,
150 user := user,
151 display_name := f_sip_str_quote(display_name),
152 password := password,
Pau Espin Pedrol0c5c6472024-05-21 13:13:49 +0200153 uli_str := "2380100010000101",
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200154 /* The Nonce field is the Base64 encoded version of the RAND value and concatenated with the AUTN: */
Pau Espin Pedrol717379f2024-05-17 18:36:51 +0200155 rand := '14987631f65f8e3788a0798b6ebcd08e'O,
156 autn := 'f6e19a7ccb028000a06b19c9544516e5'O,
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200157 ipsec_auth_key := "0x5238297dfcca759bd05d48ff49bc63fa00000000",
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200158 ipsec_local_spi_c := 4142,
159 ipsec_local_spi_s := 4143,
160 ipsec_remote_spi_c := omit,
161 ipsec_remote_spi_s := omit,
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200162 ipsec_remote_port_c := omit,
163 ipsec_remote_port_s := omit,
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200164 registrar_sip_req_uri := valueof(ts_SipUrlHost(local_sip_host)),
165 registrar_sip_record := ts_SipAddr(ts_HostPort(local_sip_host),
166 ts_UserInfo(user),
167 f_sip_str_quote(display_name)),
168 registrar_sip_call_id := hex2str(f_rnd_hexstring(15)) & "@" & local_sip_host,
169 registrar_sip_seq_nr := f_sip_rand_seq_nr(),
170 local_via := ts_Via_from(ts_HostPort(local_sip_host, local_sip_port)),
171 local_sip_url_ext := ts_SipUrl(ts_HostPort(local_sip_host, local_sip_port),
172 ts_UserInfo(user)),
173 local_sip_record := ts_SipAddr(ts_HostPort(local_sip_host),
174 ts_UserInfo(user)),
175 local_contact := valueof(ts_Contact({
176 ts_ContactAddress(
177 ts_Addr_Union_SipUrl(ts_SipUrl(ts_HostPort(
178 local_sip_host,
179 local_sip_port),
180 ts_UserInfo(user))),
181 omit)
182 })),
183 cp := cp
184}
185
186private altstep as_Tguard() runs on IMS_ConnHdlr {
187 [] g_Tguard.timeout {
188 setverdict(fail, "Tguard timeout");
189 mtc.stop;
190 }
191}
192
193type function ims_void_fn(charstring id) runs on IMS_ConnHdlr;
194function f_ims_handler_init(ims_void_fn fn, charstring id, IMS_ConnHdlrPars pars)
195runs on IMS_ConnHdlr {
196 g_name := id;
197 g_pars := pars;
198 g_Tguard.start(pars.t_guard);
199 activate(as_Tguard());
200
201 /* call the user-supied test case function */
202 fn.apply(id);
203}
204
205private altstep as_SIP_fail_req(charstring exp_msg_str := "") runs on IMS_ConnHdlr
206{
207 var PDU_SIP_Request sip_req;
208 [] SIP.receive(PDU_SIP_Request:?) -> value sip_req {
209 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
210 log2str(g_name & ": Received unexpected SIP Req message := ", sip_req, "\nvs exp := ", exp_msg_str));
211 }
212}
213
214private altstep as_SIP_fail_resp(charstring exp_msg_str := "") runs on IMS_ConnHdlr
215{
216 var PDU_SIP_Response sip_resp;
217 [] SIP.receive(PDU_SIP_Response:?) -> value sip_resp {
218 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
219 log2str(g_name & ": Received unexpected SIP Resp message := ", sip_resp, "\nvs exp := ", exp_msg_str));
220 }
221}
222
Pau Espin Pedrol717379f2024-05-17 18:36:51 +0200223private function f_nonce_from_rand_autn(octetstring rand, octetstring autn) return charstring {
224 var octetstring concat := rand & autn;
225 var charstring nonce := enc_MIME_Base64(concat);
226 log("rand=", rand, " & autn=",autn, " => nonce=", nonce);
227 return nonce;
228}
229
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200230/* HTTP Digest Authentication Using AKA (AKAv1-MD5): RFC 3310 */
231function f_tr_Authorization_AKAv1MD5(WwwAuthenticate www_authenticate,
232 charstring username,
233 charstring uri,
234 integer nc_int := 1)
235return template (present) Authorization {
236 var CommaParam_List digestCln;
237 var template (present) Authorization authorization;
238 var template (present) Credentials cred;
239 var template (omit) GenericParam rx_param;
240
241 digestCln := www_authenticate.challenge[0].digestCln;
242
243 var charstring algorithm := f_sip_param_get_value_present_or_fail(digestCln, "algorithm");
244 var charstring realm := f_sip_param_get_value_present_or_fail(digestCln, "realm");
245 var charstring nonce := f_sip_param_get_value_present_or_fail(digestCln, "nonce");
246
247 var template (present) CommaParam_List digestResponse := superset(
248 tr_Param("username", f_sip_str_quote(username)),
249 tr_Param("realm", f_sip_str_quote(realm)),
250 tr_Param("nonce", f_sip_str_quote(nonce)),
251 tr_Param("uri", f_sip_str_quote(uri)),
252 tr_Param("response", ?),
253 tr_Param("algorithm", algorithm),
254 tr_Param("qop", "auth"),
255 tr_Param("cnonce", ?),
256 tr_Param("nc", ?)
257 );
258 cred := tr_Credentials_DigestResponse(digestResponse);
259 authorization := tr_Authorization(cred);
260 return authorization;
261}
262
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200263private function f_ims_validate_register_contact(Contact rx_contact)
264{
265/* IMS contact shows up like this:
266 * Contact: <sip:8adf9f3d-9342-4060-aa4f-a909f37fd6f6@192.168.101.2:5060>;+g.3gpp.accesstype="cellular2";video;audio;+g.3gpp.smsip;+g.3gpp.nw-init-ussi;+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel";+sip.instance="<urn:gsma:imei:35589811-338445-0>"
267 */
268 /* TODO: "that the UE must include the IMS Communication Service Identifier (ICSI)
269in the contact: header to indicate IMS Multimedia Telephony." */
270 /* TODO: "The UE must include an IMEI URN in the +sip.instance header field
271parameter of the contact: header." */
272 /* TODO: "If the UE supports SMS over IP, it must include the feature tag
273“+g.3gpp.smsip” in the contact: header." */
274 /* TODO: "If the UE supports conversational audio and video service, then this must
275be indicated by adding a “video” media feature tag to the contact: header." */
276}
277
Pau Espin Pedrol0c5c6472024-05-21 13:13:49 +0200278/* Validate P-Access-Network-Info: RFC7315 6.4 */
279private function f_ims_validate_register_P_Access_Network_info(PDU_SIP_Request req,
280 boolean exp_present := true) runs on IMS_ConnHdlr
281
282{
283 if (not exp_present) {
284 if (ispresent(g_rx_sip_req.msgHeader.p_access_network_info)) {
285 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
286 log2str(g_name & ": Received unexpected [rfc7315 6.4] P-Access-Info := ",
287 g_rx_sip_req.msgHeader.p_access_network_info));
288 }
289 return;
290 }
291
292 /* exp_present: */
293 var template (present) P_Access_Network_Info expl_tmpl :=
294 tr_P_Access_Network_Info({ tr_Access_net_spec_EUTRAN(g_pars.uli_str) });
295
296 if (not ispresent(g_rx_sip_req.msgHeader.p_access_network_info)) {
297 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
298 log2str(g_name & ": Received no P-Access-Info vs exp := ",
299 expl_tmpl));
300 }
301 if (not match(g_rx_sip_req.msgHeader.p_access_network_info, expl_tmpl)) {
302 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
303 log2str(g_name & ": Received unexpected P-Access-Info := ",
304 g_rx_sip_req.msgHeader.p_access_network_info,
305 "\nvs exp := ", expl_tmpl));
306 }
307}
308
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200309private function f_ims_parse_security_client(Security_client security_client) runs on IMS_ConnHdlr
310{
311 var boolean found := false;
312 for (var integer i := 0; i < lengthof(security_client.sec_mechanism_list); i := i + 1) {
313 var Security_mechanism sec_mec := security_client.sec_mechanism_list[i];
314 if (sec_mec.mechanism_name != "ipsec-3gpp") {
315 log("Skipping Security Mechansim: ", sec_mec.mechanism_name);
316 continue;
317 }
318 var SemicolonParam_List sec_pars := sec_mec.mechanism_params;
319 var charstring par_val;
320 par_val := f_sip_param_get_value_present_or_fail(sec_pars, "alg");
321 if (par_val != "hmac-sha-1-96") {
322 log("Skipping Security Mechansim Algo: ", par_val);
323 continue;
324 }
325 par_val := f_sip_param_get_value_present_or_fail(sec_pars, "spi-c");
326 g_pars.ipsec_remote_spi_c := str2int(par_val);
327 par_val := f_sip_param_get_value_present_or_fail(sec_pars, "spi-s");
328 g_pars.ipsec_remote_spi_s := str2int(par_val);
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200329 par_val := f_sip_param_get_value_present_or_fail(sec_pars, "port-c");
330 g_pars.ipsec_remote_port_c := str2int(par_val);
331 par_val := f_sip_param_get_value_present_or_fail(sec_pars, "port-s");
332 g_pars.ipsec_remote_port_s := str2int(par_val);
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200333 found := true;
334 break;
335 }
336
337 if (not found) {
338 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
339 log2str(g_name & "alg=hmac-sha-1-96 not found: ", security_client));
340 }
341
342 log("ipsec: remote_spi_c=", g_pars.ipsec_remote_spi_c, " remote_spi_s=", g_pars.ipsec_remote_spi_s,
343 "local_spi_c=", g_pars.ipsec_local_spi_c, " local_spi_s=", g_pars.ipsec_local_spi_s);
344}
345
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200346private function f_IMS_exec_sync(charstring cmdline, template (present) integer rc := 0)
347 runs on IMS_ConnHdlr return ASP_PResult {
348 var ASP_PResult res;
349
350 map(self:PIPE, system:PIPE);
351 res := f_PIPEasp_exec_sync_PResult(PIPE, cmdline, tr_PResult(?, ?, rc));
352 unmap(self:PIPE, system:PIPE);
353
354 return res;
355}
356
357private function f_ims_setup_ipsec() runs on IMS_ConnHdlr
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200358{
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200359 var ASP_PResult res;
360
361 var charstring cmd := mp_ipsec_setup_script_path & " " &
362 g_pars.local_sip_host & " " &
363 int2str(g_pars.local_sip_port) & " " & int2str(g_pars.ipsec_local_spi_c) & " " &
364 int2str(g_pars.local_sip_port) & " " & int2str(g_pars.ipsec_local_spi_s) & " " &
365 g_pars.remote_sip_host & " " &
366 int2str(g_pars.ipsec_remote_port_c) & " " & int2str(g_pars.ipsec_remote_spi_c) & " " &
367 int2str(g_pars.ipsec_remote_port_s) & " " & int2str(g_pars.ipsec_remote_spi_s) & " " &
368 g_pars.ipsec_auth_key;
369
370 res := f_IMS_exec_sync(cmd);
371
372 /* Debug applied rules: */
373 /*
374 res := f_IMS_exec_sync("ip xfrm state");
375 log("ip-xfrm-state Result-Stdout: " & res.stdout);
376
377 res := f_IMS_exec_sync("ip xfrm policy");
378 log("ip-xfrm-policy Result-Stdout: " & res.stdout);
379 */
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200380}
381
382/* Peer is calling us, accept it: */
383altstep as_IMS_register(boolean exp_update_to_direct_rtp := true,
384 boolean fail_others := true) runs on IMS_ConnHdlr
385{
386 var template (present) PDU_SIP_Request exp_req :=
387 tr_SIP_REGISTER(g_pars.registrar_sip_req_uri,
388 ?,
389 tr_SipAddr(),
390 tr_SipAddr(),
391 tr_Via_from(?),
392 require := tr_Require(superset("sec-agree")),
393 security_client := tr_Security_client(superset(tr_Security_mechanism("ipsec-3gpp",
394 superset(tr_Param("alg","hmac-sha-1-96"))))),
395 supported := tr_Supported(superset("path", "sec-agree")));
396 var charstring sip_expect_str := log2str(exp_req);
397
398 [] SIP.receive(exp_req) -> value g_rx_sip_req {
399 var template (value) PDU_SIP_Response tx_resp;
400 var Via via;
401 var CallidString sip_call_id;
402 var Contact contact;
403 var template (value) SipAddr from_addr;
404 var template (value) SipAddr to_addr;
405 var template (value) CommaParam_List digestCln ;
406 var template (value) WwwAuthenticate wwwAuthenticate;
407 var template (value) Security_server security_server;
408 var template (value) Server server_name := ts_Server({c_sip_server_name});
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200409 var template (value) Require require := ts_Require({"sec-agree"});
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200410 var template (value) Supported supported := ts_Supported({"sec-agree"});
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200411 var template (present) Authorization authorization;
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200412 var integer sip_seq_nr;
413 var charstring tx_sdp;
414
415 sip_call_id := g_rx_sip_req.msgHeader.callId.callid;
416 via := g_rx_sip_req.msgHeader.via;
417 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "rport", "1234"); /* TODO: set remote src port of the REGISTER */
418 from_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.fromField.addressField,
419 g_rx_sip_req.msgHeader.fromField.fromParams);
420 to_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.toField.addressField,
421 g_rx_sip_req.msgHeader.toField.toParams);
422 sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
423
424 contact := g_rx_sip_req.msgHeader.contact;
425 f_ims_validate_register_contact(contact);
426
Pau Espin Pedrol0c5c6472024-05-21 13:13:49 +0200427 /* Validate P-Access-Network-Info: rfc7315 6.4:
428 * "3GPP will use the P-Access-Network-Info header field to
429 * carry relatively sensitive information like the cell ID. Therefore,
430 * the information MUST NOT be sent outside of the 3GPP domain.""
431 * [...] "the sensitive information carried in the
432 * P-Access-Network-Info header field MUST NOT be sent in any initial
433 * unauthenticated and unprotected requests (e.g., REGISTER)."
434 */
435 f_ims_validate_register_P_Access_Network_info(g_rx_sip_req, exp_present := false);
436
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200437 /* TODO: Validate "Expires" is 600000 */
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200438
439 /* Tx 100 Tyring */
440 tx_resp := ts_SIP_Response_Trying(sip_call_id,
441 from_addr,
442 to_addr,
443 via,
444 sip_seq_nr,
445 "REGISTER",
446 allow := omit,
447 server := server_name,
448 userAgent := omit);
449 SIP.send(tx_resp);
450
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200451 g_pars.remote_sip_host := valueof(contact.contactBody.contactAddresses[0].addressField.nameAddr.addrSpec.hostPort.host);
452 f_ims_parse_security_client(g_rx_sip_req.msgHeader.security_client);
453 f_ims_setup_ipsec();
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200454
455 to_addr.params := f_sip_param_set(to_addr.params, "tag", f_sip_rand_tag());
456
457 digestCln := {
458 ts_Param("realm", f_sip_str_quote(g_pars.realm)),
459 ts_Param("qop", f_sip_str_quote("auth")),
460 ts_Param("algorithm", "AKAv1-MD5"),
Pau Espin Pedrol717379f2024-05-17 18:36:51 +0200461 ts_Param("nonce", f_sip_str_quote(f_nonce_from_rand_autn(g_pars.rand, g_pars.autn)))
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200462 /* "opaque not needed in IMS "*/
463 };
464 wwwAuthenticate := ts_WwwAuthenticate( { ts_Challenge_digestCln(digestCln) } )
465
466 /* Security-Server: ipsec-3gpp;q=0.1;prot=esp;mod=trans;spi-c=4096;spi-s=4097;port-c=5104;port-s=6104;alg=hmac-sha-1-96;ealg=null */
467 var template (value) SemicolonParam_List sec_params := {
468 ts_Param("q", "0.1"),
469 ts_Param("prot", "esp"),
470 ts_Param("mod", "trans"),
471 ts_Param("spi-c", int2str(g_pars.ipsec_local_spi_c)),
472 ts_Param("spi-s", int2str(g_pars.ipsec_local_spi_s)),
473 ts_Param("port-c", int2str(g_pars.local_sip_port)),
474 ts_Param("port-s", int2str(g_pars.local_sip_port)),
475 ts_Param("alg", "hmac-sha-1-96"),
476 ts_Param("ealg", "null")
477 };
478 security_server := ts_Security_server({
479 ts_Security_mechanism("ipsec-3gpp", sec_params)
480 });
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200481
482 /* Tx 401 Unauthorized */
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200483 tx_resp := ts_SIP_Response_Unauthorized(sip_call_id,
484 from_addr,
485 to_addr,
486 via,
487 wwwAuthenticate,
488 sip_seq_nr,
489 "REGISTER",
490 security_server := security_server,
491 server := server_name,
492 supported := supported,
493 userAgent := omit);
494 SIP.send(tx_resp);
495
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200496 /* Now we should receive a new REGISTER over ipsec: */
497
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200498 /* TODO: Generate expected Authoritzation based on AKAv1-MD5: */
499 /*authorization := f_sip_digest_gen_Authorization(valueof(wwwAuthenticate),
500 g_pars.user, g_pars.password,
501 "REGISTER",
502 f_sip_SipUrl_to_str(g_pars.registrar_sip_record.addr.nameAddr.addrSpec))
503 */
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200504 authorization := f_tr_Authorization_AKAv1MD5(valueof(wwwAuthenticate),
505 g_pars.user & "@" & g_pars.realm,
Pau Espin Pedrolb0dbf7a2024-05-22 18:12:15 +0200506 f_sip_SipUrl_to_str(g_pars.registrar_sip_req_uri));
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200507 /* TODO: match Authorization from above: */
508 exp_req :=
509 tr_SIP_REGISTER(g_pars.registrar_sip_req_uri,
510 ?,
511 tr_SipAddr(),
512 tr_SipAddr(),
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200513 tr_Via_from(?),
514 authorization := authorization);
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200515 SIP.receive(exp_req) -> value g_rx_sip_req;
516
517 sip_call_id := g_rx_sip_req.msgHeader.callId.callid;
518 via := g_rx_sip_req.msgHeader.via;
519 from_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.fromField.addressField,
520 g_rx_sip_req.msgHeader.fromField.fromParams);
521 to_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.toField.addressField,
522 g_rx_sip_req.msgHeader.toField.toParams);
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200523 sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
524
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200525 /* Tx 100 Trying */
526 tx_resp := ts_SIP_Response_Trying(sip_call_id,
527 from_addr,
528 to_addr,
529 via,
530 sip_seq_nr,
531 "REGISTER",
532 allow := omit,
533 server := server_name,
534 userAgent := omit);
535 SIP.send(tx_resp);
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200536
Pau Espin Pedrol0c5c6472024-05-21 13:13:49 +0200537 /* Validate P-Access-Network-Info: */
538 f_ims_validate_register_P_Access_Network_info(g_rx_sip_req, exp_present := true);
539
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200540 /* Tx 200 OK */
541 to_addr.params := f_sip_param_set(to_addr.params, "tag", f_sip_rand_tag());
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200542 tx_resp := ts_SIP_Response(sip_call_id,
543 from_addr,
544 to_addr,
545 "REGISTER", 200,
546 sip_seq_nr,
547 "OK",
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200548 via,
549 require := require,
550 server := server_name,
551 supported := supported,
552 userAgent := omit);
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200553 SIP.send(tx_resp);
554 }
555 [fail_others] as_SIP_fail_resp(sip_expect_str);
556 [fail_others] as_SIP_fail_req(sip_expect_str);
557
558}
559
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +0200560}