blob: c5ee41271a4a77de4cf290752bba865c887c59fc [file] [log] [blame]
Philipp Maierbb169b22024-03-04 11:09:00 +01001/* IPAd testsuite in TTCN-3
2 *
3 * Author: Philipp Maier <pmaier@sysmocom.de> / sysmocom - s.f.m.c. GmbH
4 *
5 * Released under the terms of GNU General Public License, Version 2 or
6 * (at your option) any later version.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11module IPAd_Tests {
12
13import from Misc_Helpers all;
14import from General_Types all;
15import from Osmocom_Types all;
16
17import from SGP32Definitions all;
18import from SGP32Definitions_Types all;
19import from SGP32Definitions_Templates all;
20
21import from RSPDefinitions all;
22import from RSPDefinitions_Types all;
23import from RSPDefinitions_Templates all;
24
25import from PKIX1Explicit88 all;
26import from PKIX1Explicit88_Templates all;
27import from PKIX1Explicit88_Types all;
28
29import from HTTP_Server_Emulation all;
30import from HTTPmsg_Types all;
31
32import from VPCD_Types all;
33import from VPCD_CodecPort all;
34import from VPCD_Adapter all;
35
36modulepar {
37 /* emulated eIM HTTPs server */
38 charstring mp_esipa_ip := "127.0.0.1";
39 integer mp_esipa_port := 4430;
40 boolean mp_esipa_disable_ssl := false;
41 boolean mp_use_vpcd := true;
42 float mp_restart_guardtime := 2.0
43}
44
45/* Altstep to handle card power up/down and ATR transmission */
46private altstep as_vpcd_atr() runs on VPCD_Adapter_CT {
47 [] VPCD.receive(tr_VPCD_Recv(g_vpcd_conn_id, tr_VPCD_CTRL_ATR)) {
48 f_vpcd_send(ts_VPCD_DATA('3B9F96801FC78031A073BE21136743200718000001A5'O));
49 repeat;
50 }
51 [] VPCD.receive(tr_VPCD_Recv(g_vpcd_conn_id, tr_VPCD_CTRL_OFF)) {
52 repeat;
53 }
54 [] VPCD.receive(tr_VPCD_Recv(g_vpcd_conn_id, tr_VPCD_CTRL_ON)) {
55 repeat;
56 }
57}
58
59/* Helper template to format HTTP responses */
60private template (value) HTTPMessage ts_http_resp(template (value) octetstring resp := ''O) := {
61 response_binary := {
62 client_id := omit,
63 version_major := 1,
64 version_minor := 1,
65 statuscode := 200,
66 statustext := "OK",
67 /* See also SGP.32, section 6.1.1 */
68 header := {
69 {
70 header_name := "X-Admin-Protocol",
71 header_value := "gsma/rsp/v1.0.0"
72 },
73 {
74 header_name := "Content-Type",
75 header_value := "application/x-gsma-rsp-asn1"
76 },
77 {
78 header_name := "Content-Length",
79 header_value := int2str(lengthof(resp))
80 }
81 },
82 body := resp
83 }
84}
85
86type component MTC_CT {
87 timer g_Tguard;
88
89 /* HTTP server */
90 var HTTP_Server_Emulation_CT vc_HTTP;
91};
92
93type component IPAd_ConnHdlr extends HTTP_ConnHdlr, VPCD_Adapter_CT {
94 var IPAd_ConnHdlrPars g_pars;
95};
96
97type record IPAd_ConnHdlrPars {
98 /* TODO: add some useful parameters */
99};
100
101private function f_init_pars()
102runs on MTC_CT return IPAd_ConnHdlrPars {
103 var IPAd_ConnHdlrPars pars := {
104 /* TODO: fill parameters with meaninful values */
105 };
106 return pars;
107}
108
109private altstep as_Tguard() runs on MTC_CT {
110 [] g_Tguard.timeout {
111 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout");
112 }
113}
114
115private type function void_fn(charstring id) runs on IPAd_ConnHdlr;
116
117private function f_init_handler(void_fn fn, charstring id, IPAd_ConnHdlrPars pars) runs on IPAd_ConnHdlr {
118 g_pars := pars;
119
120 /* Initialize VPDC (virtual smartcard) */
121 if (mp_use_vpcd) {
122 VPCD_Adapter.f_connect();
123 activate(as_vpcd_atr());
124 }
125
126 fn.apply(id);
127}
128
129private function f_start_handler(void_fn fn, IPAd_ConnHdlrPars pars)
130runs on MTC_CT return IPAd_ConnHdlr {
131 var IPAd_ConnHdlr vc_conn;
132 var charstring id := testcasename();
133
134 vc_conn := IPAd_ConnHdlr.create(id);
135
136 if (isbound(vc_HTTP)) {
137 connect(vc_conn:HTTP_SRV, vc_HTTP:CLIENT);
138 connect(vc_conn:HTTP_SRV_PROC, vc_HTTP:CLIENT_PROC);
139 }
140
141 vc_conn.start(f_init_handler(fn, id, pars));
142 return vc_conn;
143}
144
145function f_init_esipa(charstring id) runs on MTC_CT {
146 var HttpServerEmulationCfg http_cfg := {
147 http_bind_ip := mp_esipa_ip,
148 http_bind_port := mp_esipa_port,
149 use_ssl := not mp_esipa_disable_ssl
150 };
151
152 vc_HTTP := HTTP_Server_Emulation_CT.create(id);
153 vc_HTTP.start(HTTP_Server_Emulation.main(http_cfg));
154}
155
156private function f_init(charstring id, float t_guard := 40.0) runs on MTC_CT {
157 /* Ensure a guard time inbetween tests. This is to make sure that the IPAd is able to finish its current poll
158 * cycle. In practice this means that the IPAd will notice that the connectivity towards the eIM is lost and
159 * since this is one of the conditions for ending the current poll cycle it will exit. A freshly restarted
160 * IPAd is a mandatory start condition for the tests since all tests expect the initialization procedure
161 * (selection of ISD-P etc.) that the IPAd executes on startup. */
162 f_sleep(mp_restart_guardtime);
163
164 g_Tguard.start(t_guard);
165 activate(as_Tguard());
166 f_init_esipa(id);
167}
168
169/* Expect a GetResponse request from IUT and transfer as many response bytes the IUT requests */
170private function f_vpcd_get_response(octetstring response) runs on IPAd_ConnHdlr return integer {
171 var octetstring sw;
172 var VPCD_PDU req;
173 var integer len;
174
175 req := f_vpcd_exp(tr_VPCD_DATA(?));
176 len := oct2int(req.u.data[4]);
177 if (len == 0) {
178 len := 256;
179 }
180
181 /* Make sure that the request APDU is actually a GetResponse request (on logical channel 2) */
182 if (substr(req.u.data, 0, 4) != '01c00000'O) {
183 setverdict(fail, "unexpected APDU, expecting GetResponse");
184 return 0;
185 }
186
187 /* Compute status word, in case the requested data is shorter then the response data we intend to send, we must
188 * tell the IUT that there is still data available, so that a consecutive GetResponse request can be issued.
189 * (caller must check return code to determine if a consecutive GetResponse is needed/expected) */
190 if (lengthof(response) > len) {
191 if (lengthof(response) - len > 255) {
192 sw := '6100'O;
193 } else {
194 sw := '61'O & int2oct(lengthof(response) - len, 1);
195 }
196 } else {
197 sw := '9000'O;
198 }
199
200 /* Send response to IUT */
201 f_vpcd_send(ts_VPCD_DATA(substr(response, 0, len) & sw));
202
203 /* Return how many bytes have sent */
204 return len;
205}
206
207/* Expect one or more GetResponse requests from IUT until the full response is transferred */
208private function f_vpcd_get_response_multi(octetstring response) runs on IPAd_ConnHdlr {
209 var integer bytes_sent := 0;
210 var octetstring response_remainder := response;
211
212 while (true) {
213 response_remainder := substr(response_remainder, bytes_sent, lengthof(response_remainder) - bytes_sent);
214 bytes_sent := f_vpcd_get_response(response_remainder);
215
216 /* Check if we reached the last chunk */
217 if (lengthof(response_remainder) <= bytes_sent) {
218 return;
219 }
220 }
221}
222
223/* Expect one or more STORE DATA requests until the IUT has completed the transmision cycle */
224private function f_vpcd_store_data(octetstring exp := ''O) runs on IPAd_ConnHdlr return octetstring {
225
226 var VPCD_PDU req;
227 var octetstring block;
228 var integer len;
229 var octetstring data := ''O;
230
231 while (true) {
232 req := f_vpcd_exp(tr_VPCD_DATA(?));
233
234 /* Make sure that the request APDU is actually a STORE DATA request (on logical channel 1) */
235 if (substr(req.u.data, 0, 3) != '81E291'O and
236 substr(req.u.data, 0, 3) != '81E211'O) {
237 setverdict(fail, "unexpected APDU, expecting GetResponse");
238 return ''O;
239 }
240
241 if (lengthof(req.u.data) - 5 > 255) {
242 len := 255;
243 } else {
244 len := lengthof(req.u.data) - 5;
245 }
246 block := substr(req.u.data, 5, len);
247 data := data & block;
248
249 /* The final status word contains the length of the response. We can not send it right now
250 * since the caller must first process the received data block and compute a response. When
251 * the exact length of the response data is known. The final status word can be sent using
252 * f_vpcd_store_data_final_ack() */
253 if (substr(req.u.data, 2, 1) == '91'O) {
254 if (exp != ''O and block != exp) {
255 setverdict(fail, "received block contains unexpected data (", block, " != ", exp, ")");
256 }
257 return block;
258 }
259
260 f_vpcd_send(ts_VPCD_DATA('9000'O));
261 }
262
263 setverdict(fail, "no data? (we should not reach this code path)");
264 return ''O;
265}
266
267/* Send a final status word to acknowledge the last block of a STORE DATA transmission. The status word will tell
268 * the IUT how many response bytes are available. (The IUT will immediately begin to fetch the response using
269 * one or more GetResponse requests */
270private function f_vpcd_store_data_final_ack(integer response_len) runs on IPAd_ConnHdlr {
271 var octetstring second_sw_byte;
272 var octetstring first_sw_byte;
273
274 if (response_len > 255) {
275 second_sw_byte := '00'O;
276 } else {
277 second_sw_byte := int2oct(response_len, 1);
278 }
279
280 if (response_len > 0) {
281 first_sw_byte := '61'O; /* 61xx */
282 } else {
283 first_sw_byte := '90'O; /* 9000 */
284 }
285
286 f_vpcd_send(ts_VPCD_DATA(first_sw_byte & second_sw_byte));
287}
288
289/* Expect a pre-defined request (optional), and send a pre-defined response. This is a shortcut that only works in case
290 * the response does not depend on the request. */
291private function f_vpcd_transceive(octetstring response, octetstring expected_request := ''O) runs on IPAd_ConnHdlr {
292
293 /* In case we do not use the VPCD (because we have some other kind of eUICC emulation or even a real card
294 * present), we just skip. */
295 if (mp_use_vpcd == false) {
296 return;
297 }
298
299 f_vpcd_store_data(expected_request);
300 f_vpcd_store_data_final_ack(lengthof(response));
301 if (response != ''O) {
302 f_vpcd_get_response_multi(response);
303 }
304}
305
306/* Handle the opening of logical channel 1 and the selection of the ISD-R */
307private function f_es10x_init() runs on IPAd_ConnHdlr {
308 var charstring eim_fqdn := mp_esipa_ip & ":" & int2str(mp_esipa_port);
309
310 /* If we decide not to use vpcd, then we must not initialize anything here */
311 if (mp_use_vpcd == false) {
312 return;
313 }
314
Philipp Maier9df87342024-05-13 14:26:13 +0200315 /* Expect a TERMINAL CAPABILITIES request
316 * (see also: 3GPP TS 102.221, section 11.1.19.2.4 and SGP.22, section 3.4.2) */
317 f_vpcd_exp(tr_VPCD_DATA('80AA000005A903830107'O));
318 f_vpcd_send(ts_VPCD_DATA('9000'O));
319
Philipp Maierbb169b22024-03-04 11:09:00 +0100320 /* Expect a MANAGE CHANNEL request that opens logical channel 1 */
321 f_vpcd_exp(tr_VPCD_DATA('0070000100'O));
322 f_vpcd_send(ts_VPCD_DATA('9000'O));
323
324 /* Expect selection of ISD-R request */
325 f_vpcd_exp(tr_VPCD_DATA('01a4040410a0000005591010ffffffff8900000100'O));
326 f_vpcd_send(ts_VPCD_DATA('6121'O)); /* 21 bytes of response, which are not requested by the ipad. */
327
328 /* Expect the IPAd to query the eID from the eUICC */
329 f_vpcd_transceive(enc_GetEuiccDataResponse(valueof(ts_getEuiccDataResponse)), 'BF3E035C015A'O);
330
331 /* Expect the IPAd to query the eIM configuration data from the eUICC */
332 f_vpcd_transceive(enc_GetEimConfigurationDataResponse(valueof(ts_getEimConfigurationDataResponse(eim_fqdn))), 'BF5500'O);
333}
334
335/* Handle the closing of logical channel 1 */
336private function f_es10x_close() runs on IPAd_ConnHdlr {
337
338 /* Expect a MANAGE CHANNEL request that closes logical channel 1 */
339 f_vpcd_exp(tr_VPCD_DATA('0070800100'O));
340 f_vpcd_send(ts_VPCD_DATA('9000'O));
341}
342
343/* Receive ESipa HTTP request */
344private function f_esipa_receive() runs on IPAd_ConnHdlr return EsipaMessageFromIpaToEim {
345 var HTTPMessage esipa_req;
346 timer T := 10.0;
347 var EsipaMessageFromIpaToEim request;
348
349 T.start;
350 alt {
351 [] HTTP_SRV.receive({ request_binary := ? }) -> value esipa_req {
352 request := dec_EsipaMessageFromIpaToEim(esipa_req.request_binary.body);
353 }
354 [] T.timeout {
355 setverdict(fail, "no HTTP request received?");
356 }
357 }
358
359 return request;
360}
361
362/* Send ESipa HTTP response */
363private function f_esipa_send(EsipaMessageFromEimToIpa response) runs on IPAd_ConnHdlr {
364 var octetstring esipa_res;
365 esipa_res := enc_EsipaMessageFromEimToIpa(response);
366 HTTP_SRV.send(ts_http_resp(esipa_res));
367}
368
369/* Perform one ESipa HTTP request/response cycle */
370private function f_esipa_transceive(EsipaMessageFromEimToIpa response) runs on IPAd_ConnHdlr return EsipaMessageFromIpaToEim {
371 var EsipaMessageFromIpaToEim request;
372
373 request := f_esipa_receive();
374 f_esipa_send(response);
375
376 return request;
377}
378
379/* Perform one ESipa HTTP request/response cycle but with an empty response */
380private function f_esipa_transceive_empty_response() runs on IPAd_ConnHdlr return EsipaMessageFromIpaToEim {
381 var EsipaMessageFromIpaToEim request;
382
383 request := f_esipa_receive();
384 HTTP_SRV.send(ts_http_resp(''O));
385 return request;
386}
387
388/* Common Mutual Authentication Procedure, see also: GSMA SGP.22, section 3.0.1 */
389private function f_proc_cmn_mtl_auth() runs on IPAd_ConnHdlr {
390 var EsipaMessageFromIpaToEim esipa_req;
391 var EsipaMessageFromEimToIpa esipa_res;
392
393 /* Step #1 */
394 f_vpcd_transceive(enc_EUICCInfo1(valueof(ts_EUICCInfo1)), 'bf2000'O);
395
396 /* Step #2-#4 */
397 f_vpcd_transceive(enc_GetEuiccChallengeResponse(valueof(ts_GetEuiccChallengeResponse)), 'bf2e00'O);
398
399 /* Step #5-#10 */
400 esipa_req := f_esipa_receive();
401 if (not match(esipa_req, tr_initiateAuthenticationRequestEsipa)) {
402 setverdict(fail, "unexpected message from IPAd");
403 }
404 esipa_res := valueof(ts_initiateAuthenticationResponseEsipa(euiccChallenge := esipa_req.initiateAuthenticationRequestEsipa.euiccChallenge));
405 f_esipa_send(esipa_res);
406
407 /* Step #11-#14 */
408 f_vpcd_transceive(enc_AuthenticateServerResponse(valueof(ts_authenticateServerResponse)));
409
410 /* Step #15-#17 */
411 esipa_req := f_esipa_transceive(valueof(ts_authenticateClientResponseEsipa_dpe));
412 if (not match(esipa_req, tr_authenticateClientRequestEsipa)) {
413 setverdict(fail, "unexpected message from IPAd");
414 }
415}
416
417/* ********************************************* */
418/* ********** BELOW ONLY TESTCASES! ************ */
419/* ********************************************* */
420
421
Philipp Maier119ac3f2024-05-16 10:03:26 +0200422/* A testcase to try out an indirect profile download,
423 * See also: GSMA SGP.32, section 3.2.3.2: Indirect Profile Download */
Philipp Maierc50a8d42024-05-13 14:38:56 +0200424private function f_TC_proc_indirect_prfle_dwnld(charstring id) runs on IPAd_ConnHdlr {
Philipp Maierbb169b22024-03-04 11:09:00 +0100425 var EsipaMessageFromIpaToEim esipa_req;
426 var EsipaMessageFromEimToIpa esipa_res;
427 var integer i;
428 var charstring eim_fqdn := mp_esipa_ip & ":" & int2str(mp_esipa_port);
429 var BoundProfilePackage boundProfilePackage;
430
431 f_es10x_init();
432 f_http_register();
433
Philipp Maierc50a8d42024-05-13 14:38:56 +0200434 /* Prepare indirect profile download by responding with a download trigger request */
Philipp Maierbb169b22024-03-04 11:09:00 +0100435 esipa_res := valueof(ts_getEimPackageResponse_dnlTrigReq);
436 esipa_req := f_esipa_transceive(esipa_res);
437 if (not match(esipa_req, tr_getEimPackageRequest)) {
438 setverdict(fail, "unexpected message from IPAd");
439 }
440
441 /* Expect the IPAd to query the eIM configuration data from the eUICC */
442 f_vpcd_transceive(enc_GetEimConfigurationDataResponse(valueof(ts_getEimConfigurationDataResponse(eim_fqdn))), 'BF5500'O);
443
444 f_proc_cmn_mtl_auth();
445
446 f_vpcd_transceive(enc_PrepareDownloadResponse(valueof(ts_prepareDownloadResponse)));
447
448 esipa_res := valueof(ts_getBoundProfilePackageResponseEsipa);
449 esipa_req := f_esipa_transceive(esipa_res);
450 boundProfilePackage := esipa_res.getBoundProfilePackageResponseEsipa.getBoundProfilePackageOkEsipa.boundProfilePackage;
451 /* TODO: match response (we do not have a template yet) */
452
453 /* initialiseSecureChannelRequest */
454 f_vpcd_transceive(''O);
455
456 /* Step #3 (ES8+.ConfigureISDP) */
457 for (i := 0; i < sizeof(boundProfilePackage.firstSequenceOf87); i := i + 1) {
458 f_vpcd_transceive(''O);
459 }
460
461 /* Step #4 (ES8+.StoreMetadata) */
462 for (i := 0; i < sizeof(boundProfilePackage.sequenceOf88); i := i + 1) {
463 f_vpcd_transceive(''O);
464 }
465
466 /* Step #5 (ES8+.ReplaceSessionKeys", optional, left out) */
467 if (ispresent(boundProfilePackage.secondSequenceOf87)) {
468 for (i := 0; i < sizeof(boundProfilePackage.secondSequenceOf87); i := i + 1) {
469 f_vpcd_transceive(''O);
470 }
471 }
472
473 /* Step #6 (ES8+.LoadProfileElements) */
474 for (i := 0; i < sizeof(boundProfilePackage.sequenceOf86); i := i + 1) {
475 if (i < sizeof(boundProfilePackage.sequenceOf86) - 1) {
476 f_vpcd_transceive(''O);
477 } else {
478 /* In the last message we send the ProfileInstallationResult */
479 f_vpcd_transceive(enc_ProfileInstallationResult(valueof(ts_profileInstallationResult)));
480 }
481 }
482
483 /* Receive ProfileInstallationResult from iPAD->eIM */
484 esipa_req := f_esipa_transceive_empty_response();
485 /* TODO: match response (we do not have a template yet) */
486
487 /* Receive RemoveNotificationFromList from iPAD->eUICC */
488 f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
489
490 /* Wait some time until the the last HTTP response is actually delivered */
491 f_sleep(2.0);
492
493 f_es10x_close();
494
495 setverdict(pass);
496}
Philipp Maierc50a8d42024-05-13 14:38:56 +0200497testcase TC_proc_indirect_prfle_dwnld() runs on MTC_CT {
Philipp Maierbb169b22024-03-04 11:09:00 +0100498 var charstring id := testcasename();
499 var IPAd_ConnHdlrPars pars := f_init_pars();
500 var IPAd_ConnHdlr vc_conn;
501 f_init(id);
Philipp Maierc50a8d42024-05-13 14:38:56 +0200502 vc_conn := f_start_handler(refers(f_TC_proc_indirect_prfle_dwnld), pars);
Philipp Maierbb169b22024-03-04 11:09:00 +0100503 vc_conn.done;
504 setverdict(pass);
505}
506
507
Philipp Maier119ac3f2024-05-16 10:03:26 +0200508/* A testcase to try out an the Generic eUICC Package Download and Execution Procedure,
509 * See also: GSMA SGP.32, section 3.3.1: Generic eUICC Package Download and Execution */
Philipp Maierbb169b22024-03-04 11:09:00 +0100510private function f_TC_proc_euicc_pkg_dwnld_exec(charstring id) runs on IPAd_ConnHdlr {
511 var EsipaMessageFromIpaToEim esipa_req;
512 var EsipaMessageFromEimToIpa esipa_res;
513
514 f_es10x_init();
515 f_http_register();
516
517 /* Step #1-#2 */
518 esipa_res := valueof(ts_getEimPackageResponse_euiccPkgReq);
519 esipa_req := f_esipa_transceive(esipa_res);
520 if (not match(esipa_req, tr_getEimPackageRequest)) {
521 setverdict(fail, "unexpected message from IPAd");
522 }
523
524 /* Step #3-#8 */
525 f_vpcd_transceive(enc_EuiccPackageResult(valueof(ts_euiccPackageResult)));
526
527 /* Step #9 */
528 f_vpcd_transceive(enc_RetrieveNotificationsListResponse(valueof(ts_retrieveNotificationsListResponse)));
529
530 /* Step #10-14 */
531 esipa_res := valueof(ts_provideEimPackageResultResponse_eimAck(eimAcknowledgements := {1,2,3,4}));
532 esipa_req := f_esipa_transceive(esipa_res);
533 if (not match(esipa_req, tr_provideEimPackageResult_ePRAndNotif)) {
534 setverdict(fail, "unexpected message from IPAd");
535 }
536
537 /* Step #15-17 */
538 f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
539 f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
540 f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
541 f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
542 f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
543
544 /* Wait some time until the the last HTTP response is actually delivered */
545 f_sleep(2.0);
546
547 f_es10x_close();
548
549 setverdict(pass);
550}
551
552testcase TC_proc_euicc_pkg_dwnld_exec() runs on MTC_CT {
553 var charstring id := testcasename();
554 var IPAd_ConnHdlrPars pars := f_init_pars();
555 var IPAd_ConnHdlr vc_conn;
556 f_init(id);
557 vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec), pars);
558 vc_conn.done;
559 setverdict(pass);
560}
561
562
Philipp Maier119ac3f2024-05-16 10:03:26 +0200563/* A testcase to try out an the Generic eUICC Package Download and Execution Procedure,
564 * but this time we force a rollback meneuver */
Philipp Maierbb169b22024-03-04 11:09:00 +0100565private function f_TC_proc_euicc_pkg_dwnld_exec_rollback(charstring id) runs on IPAd_ConnHdlr {
566 var EsipaMessageFromIpaToEim esipa_req;
567 var EsipaMessageFromEimToIpa esipa_res;
568
569 f_es10x_init();
570 f_http_register();
571
572 /* Step #1-#2 */
573 esipa_res := valueof(ts_getEimPackageResponse_euiccPkgReq);
574 esipa_req := f_esipa_transceive(esipa_res);
575 if (not match(esipa_req, tr_getEimPackageRequest)) {
576 setverdict(fail, "unexpected message from IPAd");
577 }
578
579 /* Step #3-#8 */
580 f_vpcd_transceive(enc_EuiccPackageResult(valueof(ts_euiccPackageResult)));
581
582 /* Step #9 */
583 f_vpcd_transceive(enc_RetrieveNotificationsListResponse(valueof(ts_retrieveNotificationsListResponse)));
584
585 /* We now ignore the response from the IPAd. The IPAd will interpret this as a disturbed IP connection. */
586 f_esipa_receive();
587
588 /* To fix the problem, the IPAd will now try a profile rollback meneuver. */
589 f_vpcd_transceive(enc_ProfileRollbackResponse(valueof(ts_profileRollbackResponse)),
590 enc_ProfileRollbackRequest(valueof(ts_profileRollbackRequest)));
591
592 /* At this point the old profile is active again. The IPAd is now expected to start at Step #9 again
593 * to continue the procedure normally. */
594
595 /* Step #9 */
596 f_vpcd_transceive(enc_RetrieveNotificationsListResponse(valueof(ts_retrieveNotificationsListResponse)));
597
598 /* Step #10-14 */
599 esipa_res := valueof(ts_provideEimPackageResultResponse_eimAck(eimAcknowledgements := {1,2,3,4}));
600 esipa_req := f_esipa_transceive(esipa_res);
Philipp Maier485c77b2024-05-16 16:15:10 +0200601 if (not match(esipa_req, tr_provideEimPackageResult_ePRAndNotif(euiccPackageResult := ?))) {
Philipp Maierbb169b22024-03-04 11:09:00 +0100602 setverdict(fail, "unexpected message from IPAd");
603 }
604
605 /* Step #15-17 */
606 f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
607 f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
608 f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
609 f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
610 f_vpcd_transceive(enc_NotificationSentResponse(valueof(ts_notificationSentResponse)));
611
612 /* Wait some time until the the last HTTP response is actually delivered */
613 f_sleep(2.0);
614
615 f_es10x_close();
616
617 setverdict(pass);
618}
619
620testcase TC_proc_euicc_pkg_dwnld_exec_rollback() runs on MTC_CT {
621 var charstring id := testcasename();
622 var IPAd_ConnHdlrPars pars := f_init_pars();
623 var IPAd_ConnHdlr vc_conn;
624 f_init(id);
625 vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_rollback), pars);
626 vc_conn.done;
627 setverdict(pass);
628}
629
630
631/* A testcase to try out an IpaEuiccDataRequest */
632private function f_TC_proc_euicc_data_req(charstring id) runs on IPAd_ConnHdlr {
633 var EsipaMessageFromIpaToEim esipa_req;
634 var EsipaMessageFromEimToIpa esipa_res;
635 var charstring eim_fqdn := mp_esipa_ip & ":" & int2str(mp_esipa_port);
636
637 f_es10x_init();
638 f_http_register();
639
640 /* IPAd requests a package, we tell it to execute an ipaEuiccDataRequest */
641 esipa_res := valueof(ts_getEimPackageResponse_euiccDataReq);
642 esipa_req := f_esipa_transceive(esipa_res);
643 if (not match(esipa_req, tr_getEimPackageRequest)) {
644 setverdict(fail, "unexpected message from IPAd");
645 }
646
647 /* IPAd will obtain the data from the eUICC */
648 f_vpcd_transceive(enc_EuiccConfiguredAddressesResponse(valueof(ts_euiccConfiguredAddressesResponse)));
649 f_vpcd_transceive(enc_EUICCInfo1(valueof(ts_EUICCInfo1)));
650 f_vpcd_transceive(enc_EUICCInfo2(valueof(ts_EUICCInfo2)));
651 f_vpcd_transceive(enc_GetEimConfigurationDataResponse(valueof(ts_getEimConfigurationDataResponse(eim_fqdn))));
652 f_vpcd_transceive(enc_GetCertsResponse(valueof(ts_getCertsResponse)));
653 f_vpcd_transceive(enc_RetrieveNotificationsListResponse(valueof(ts_retrieveNotificationsListResponse)));
654
655 /* IPAd will return the data to us */
656 esipa_res := valueof(ts_provideEimPackageResultResponse_eimAck(eimAcknowledgements := {1,2,3,4}));
657 esipa_req := f_esipa_transceive(esipa_res);
658
659 /* Wait some time until the the last HTTP response is actually delivered */
660 f_sleep(2.0);
661
662 f_es10x_close();
663
664 setverdict(pass);
665}
666testcase TC_proc_euicc_data_req() runs on MTC_CT {
667 var charstring id := testcasename();
668 var IPAd_ConnHdlrPars pars := f_init_pars();
669 var IPAd_ConnHdlr vc_conn;
670 f_init(id);
671 vc_conn := f_start_handler(refers(f_TC_proc_euicc_data_req), pars);
672 vc_conn.done;
673 setverdict(pass);
674}
675
676/* A testcase to try out what happens when the eIM package request is rejected */
677private function f_TC_get_eim_pkg_req_rej(charstring id) runs on IPAd_ConnHdlr {
678 var EsipaMessageFromIpaToEim esipa_req;
679 var EsipaMessageFromEimToIpa esipa_res;
680
681 f_es10x_init();
682 f_http_register();
683
684 /* IPAd requests a package, we respond with an eimPackageError code 127 (undefined error) */
685 esipa_res := valueof(ts_getEimPackageResponse_eimPkgErrUndef);
686 esipa_req := f_esipa_transceive(esipa_res);
687 if (not match(esipa_req, tr_getEimPackageRequest)) {
688 setverdict(fail, "unexpected message from IPAd");
689 }
690
691 /* Wait some time until the the last HTTP response is actually delivered */
692 f_sleep(2.0);
693
694 f_es10x_close();
695
696 setverdict(pass);
697}
698testcase TC_get_eim_pkg_req_rej() runs on MTC_CT {
699 var charstring id := testcasename();
700 var IPAd_ConnHdlrPars pars := f_init_pars();
701 var IPAd_ConnHdlr vc_conn;
702 f_init(id);
703 vc_conn := f_start_handler(refers(f_TC_get_eim_pkg_req_rej), pars);
704 vc_conn.done;
705 setverdict(pass);
706}
707
708control {
Philipp Maierc50a8d42024-05-13 14:38:56 +0200709 execute ( TC_proc_indirect_prfle_dwnld() );
Philipp Maierbb169b22024-03-04 11:09:00 +0100710 execute ( TC_proc_euicc_pkg_dwnld_exec() );
711 execute ( TC_proc_euicc_pkg_dwnld_exec_rollback() );
712 execute ( TC_proc_euicc_data_req() );
713 execute ( TC_get_eim_pkg_req_rej() );
714}
715
716}