diff options
author | Philipp Maier <pmaier@sysmocom.de> | 2024-03-11 14:57:17 +0100 |
---|---|---|
committer | Philipp Maier <pmaier@sysmocom.de> | 2024-05-24 17:20:55 +0200 |
commit | 32ddca9f5920ac9d4e05ee10e062132ee7825cc1 (patch) | |
tree | 99bbfbbb6993c1f917707a951f851901311a9b5f | |
parent | 1ff26e8af920e33e763fcdb8f3fdaa8af4ecaadf (diff) |
WIP: eIM_Tests: add testsuite for an eIMpmaier/ipad
Change-Id: Iba72ee00d10aba7831feedadacd943bf943de53e
Related: SYS#6824
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | eim/REST_Types_JSON.ttcn | 256 | ||||
-rw-r--r-- | eim/eIM_Tests.cfg | 23 | ||||
-rw-r--r-- | eim/eIM_Tests.default | 8 | ||||
-rw-r--r-- | eim/eIM_Tests.ttcn | 801 | ||||
-rw-r--r-- | eim/es9p_Types_JSON.ttcn | 235 | ||||
-rwxr-xr-x | eim/gen_links.sh | 46 | ||||
-rwxr-xr-x | eim/regen_makefile.sh | 25 | ||||
-rw-r--r-- | eim/server.crt | 23 | ||||
-rw-r--r-- | eim/server.key | 27 |
10 files changed, 1445 insertions, 0 deletions
@@ -21,6 +21,7 @@ SUBDIRS= \ cbc \ ccid \ dia2gsup \ + eim \ fr \ fr-net \ epdg \ diff --git a/eim/REST_Types_JSON.ttcn b/eim/REST_Types_JSON.ttcn new file mode 100644 index 00000000..1feaa325 --- /dev/null +++ b/eim/REST_Types_JSON.ttcn @@ -0,0 +1,256 @@ +/* REST message definitions for eIM REST API + * + * Author: Philipp Maier <pmaier@sysmocom.de> / sysmocom - s.f.m.c. GmbH + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +module REST_Types_JSON { + +type record JSON_REST_download { + charstring activationCode +}; + +type union JSON_REST_psmo { + record { + octetstring iccid, + boolean rollback + } enable, + record { + octetstring iccid + } disable, + record { + octetstring iccid + } delete, + record { + union { + octetstring isdpAid, + octetstring iccid, + integer profileClass + } searchCriteria optional, + octetstring tagList optional + } listProfileInfo, + record { + } getRAT, + record { + boolean autoEnableFlag, + objid smdpOid optional, + charstring smdpAddress optional + } configureAutoEnable +}; + +type union JSON_REST_eco { + record { + /* ASN.1 pre-encoded EimConfigurationData */ + octetstring eimConfigurationData + } addEim, + record { + charstring eimId + } deleteEim, + record { + /* ASN.1 pre-encoded EimConfigurationData */ + octetstring eimConfigurationData + } updateEim, + record { + } listEim +}; + +type record JSON_REST_resource { + charstring eidValue, + union { + JSON_REST_download download, + record of JSON_REST_psmo psmo, + record of JSON_REST_eco eco + } order +}; + +type record JSON_REST_ProfileInfo { + charstring iccid optional, + charstring isdpAid optional, + charstring profileState optional, + charstring profileNickname optional, + charstring serviceProviderName optional, + charstring profileName optional, + charstring iconType optional, + charstring icon optional, + charstring profileClass optional + //TODO: notificationConfigurationInfo + //TODO: profileOwner + //TODO: dpProprietaryData + //TODO: profilePolicyRules + //TODO: serviceSpecificDataStoredInEuicc +}; + +type record JSON_REST_eimIdList { + charstring iccid, + charstring eimIdType optional +} + +type union JSON_REST_result { + charstring enableResult, + charstring disableResult, + charstring deleteResult, + record { + charstring finalResult, + record of JSON_REST_ProfileInfo profileInfoList optional + } listProfileInfoResult, + charstring getRATResult, + charstring configureAutoEnableResult, + record { + charstring addEimResultCode, + integer associationToken optional + } addEimResult, + charstring deleteEimResult, + charstring updateEimResult, + record { + charstring finalResult, + record of JSON_REST_eimIdList eimIdList optional + } listEimResult, + charstring rollbackResult, + charstring processingTerminated, + charstring notificationResult, + charstring cancelSessionResult, + record { + charstring finalResult, + charstring iccid + } profileInstallationResult +} + +type record JSON_REST_response_long { + charstring status, + charstring timestamp, + JSON_REST_resource resource, + record of JSON_REST_result outcome, + charstring debuginfo +}; + +type record JSON_REST_response_short { + charstring status +}; + +/* Definition for JSON REST responses */ +type union JSON_REST_response { + JSON_REST_response_long long, + JSON_REST_response_short short +} with { + variant "JSON : as value" +} + +external function enc_JSON_REST_response(in JSON_REST_response msg) +return octetstring with { + extension "prototype (convert) encode(JSON)"; + extension "errorbehavior(ALL:ERROR)" +} +external function dec_JSON_REST_response(in octetstring stream) return JSON_REST_response with { + extension "prototype (convert) decode(JSON)" + extension "errorbehavior(ALL:ERROR)" +} + +external function enc_JSON_REST_resource(in JSON_REST_resource msg) +return octetstring with { + extension "prototype (convert) encode(JSON)"; + extension "errorbehavior(ALL:ERROR)" +} +external function dec_JSON_REST_resource(in octetstring stream) return JSON_REST_resource with { + extension "prototype (convert) decode(JSON)" + extension "errorbehavior(ALL:ERROR)" +} + + +template (present) JSON_REST_response tr_JSON_REST_success := { + long := { + status := "done", + timestamp := ?, + resource := ?, + outcome := ?, + debuginfo := ? + } +} + +template (present) JSON_REST_response tr_JSON_REST_deleted := { + short := { status := "deleted" } +} + +template (present) JSON_REST_response tr_JSON_REST_absent := { + short := { status := "absent" } +} + +template (value) JSON_REST_resource ts_JSON_REST_download_order(octetstring eidValue, charstring activationCode) := { + eidValue := oct2str(eidValue), + order := { download := { activationCode := activationCode } } +} + +template (value) JSON_REST_resource ts_JSON_REST_psmo_order_enable(octetstring eidValue, octetstring iccid, boolean rollback) := { + eidValue := oct2str(eidValue), + order := { psmo := { { enable := { iccid := iccid, rollback := rollback } } } } +} + +template (value) JSON_REST_resource ts_JSON_REST_psmo_order_disable(octetstring eidValue, octetstring iccid) := { + eidValue := oct2str(eidValue), + order := { psmo := { { disable := { iccid := iccid } } } } +} + +template (value) JSON_REST_resource ts_JSON_REST_psmo_order_delete(octetstring eidValue, octetstring iccid) := { + eidValue := oct2str(eidValue), + order := { psmo := { { delete := { iccid := iccid } } } } +} + +template (value) JSON_REST_resource ts_JSON_REST_psmo_order_disable_and_delete(octetstring eidValue, octetstring iccid) := { + eidValue := oct2str(eidValue), + order := { psmo := { { disable := { iccid := iccid } }, { delete := { iccid := iccid } } } } +} + +template (value) JSON_REST_resource ts_JSON_REST_psmo_order_listProfileInfo(octetstring eidValue, octetstring iccid) := { + eidValue := oct2str(eidValue), + order := { psmo := { { listProfileInfo := {searchCriteria := {iccid := iccid}, tagList := '92'O /* profileName */} } } } +} + +template (value) JSON_REST_resource ts_JSON_REST_psmo_order_getRAT(octetstring eidValue) := { + eidValue := oct2str(eidValue), + order := { psmo := { { getRAT := {} } } } +} + +template (value) JSON_REST_resource ts_JSON_REST_psmo_order_configureAutoEnable(octetstring eidValue) := { + eidValue := oct2str(eidValue), + order := { psmo := { { configureAutoEnable := { autoEnableFlag := true, smdpOid := objid {1 2 3}, smdpAddress := "smdp.example.com" } } } } +} + +const octetstring eimConfigurationData := +'30820145800365494D810E3132372E302E302E313A383030308301008401 +FFA5820126A0820122300D06092A864886F70D01010105000382010F0030 +82010A0282010100AEDD235E43D7F9FE6B122298742F41D870CE914636EF +CF41CF968A654D4F8C97E4F11B2E0897F8ECC9321BA64CC5366BFADD3525 +802806BF7CAF17F1CC8576C27484EBD3B5AFB568DCF0BD5A6A8C74708332 +A0C23490EB6E5DBA392BCED11165C33B8EBBF8FAB6D4EA415CE96F216F8C +F877AE9126C0DED1CC2DB00BCFF5A8A9C2D3885B8FBA21D71DB87D2000DB +0F69D79B533EC273597C2D441D7DBC14FFC555B65AF64473CCBE24A27566 +30A2B725618573337CEF1CCD5B39BA3F3CD081B2AF33F65F0A249A9C661B +08F49F99FF93F31923464AF23B079E405191F3B7F13CE82691A46AD4AFE2 +9CB55EA3CFA083C1D64756CC51B8CBD62AC00BE41C3AE4BB0203010001'O + +template (value) JSON_REST_resource ts_JSON_REST_eco_order_addEim(octetstring eidValue) := { + eidValue := oct2str(eidValue), + order := { eco := { { addEim := { eimConfigurationData := eimConfigurationData } } } } +} + +template (value) JSON_REST_resource ts_JSON_REST_eco_order_deleteEim(octetstring eidValue) := { + eidValue := oct2str(eidValue), + order := { eco := { { deleteEim := { eimId := "eIM" } } } } +} + +template (value) JSON_REST_resource ts_JSON_REST_eco_order_updateEim(octetstring eidValue) := { + eidValue := oct2str(eidValue), + order := { eco := { { updateEim := { eimConfigurationData := eimConfigurationData } } } } +} + +template (value) JSON_REST_resource ts_JSON_REST_eco_order_listEim(octetstring eidValue) := { + eidValue := oct2str(eidValue), + order := { eco := { { listEim := { } } } } +} + +} with { + encode "JSON"; +} diff --git a/eim/eIM_Tests.cfg b/eim/eIM_Tests.cfg new file mode 100644 index 00000000..dfc66c84 --- /dev/null +++ b/eim/eIM_Tests.cfg @@ -0,0 +1,23 @@ +[ORDERED_INCLUDE] +# Common configuration, shared between test suites +"../Common.cfg" +# testsuite specific configuration, not expected to change +"./eIM_Tests.default" + +# Local configuration below + +[LOGGING] + +[TESTPORT_PARAMETERS] +system.HTTP_server_port.use_notification_ASPs := "no" +system.HTTP_server_port.KEYFILE := "/home/owner/work/ttcn3/testsuite/osmo-ttcn3-hacks/eim/server.key" +system.HTTP_server_port.CERTIFICATEFILE := "/home/owner/work/ttcn3/testsuite/osmo-ttcn3-hacks/eim/server.crt" +system.HTTP_server_port.PASSWORD := "katinka1" +system.HTTP_server_port.http_debugging := "yes" + +[MODULE_PARAMETERS] + +[MAIN_CONTROLLER] + +[EXECUTE] +eIM_Tests.control diff --git a/eim/eIM_Tests.default b/eim/eIM_Tests.default new file mode 100644 index 00000000..95b42e94 --- /dev/null +++ b/eim/eIM_Tests.default @@ -0,0 +1,8 @@ +[LOGGING] +mtc.FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING; // | DEBUG_ENCDEC; + +[TESTPORT_PARAMETERS] + +[MODULE_PARAMETERS] + +[EXECUTE] diff --git a/eim/eIM_Tests.ttcn b/eim/eIM_Tests.ttcn new file mode 100644 index 00000000..d0e7c023 --- /dev/null +++ b/eim/eIM_Tests.ttcn @@ -0,0 +1,801 @@ +/* eIM testsuite in TTCN-3 + * + * Author: Philipp Maier <pmaier@sysmocom.de> / sysmocom - s.f.m.c. GmbH + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +module eIM_Tests { + +import from Misc_Helpers all; +import from General_Types all; +import from Osmocom_Types all; + +import from SGP32Definitions all; +import from SGP32Definitions_Types all; +import from SGP32Definitions_Templates all; + +import from RSPDefinitions all; +import from RSPDefinitions_Types all; +import from RSPDefinitions_Templates all; + +import from PKIX1Explicit88 all; +import from PKIX1Explicit88_Templates all; +import from PKIX1Explicit88_Types all; + +import from PKIX1Implicit88 all; +import from PKIX1Implicit88_Templates all; +import from PKIX1Implicit88_Types all; + +import from HTTP_Server_Emulation all; +import from HTTPmsg_Types all; + +import from HTTPmsg_PortType all; +import from HTTP_Adapter all; + +import from es9p_Types_JSON all; +import from REST_Types_JSON all; + +/* the PIPEasp port allows us to interact with restop.py via stdin/stdout */ +import from PIPEasp_PortType all; +import from PIPEasp_Types all; + +type component MTC_CT { + timer g_Tguard; + + /* HTTP server */ + var HTTP_Server_Emulation_CT vc_HTTP; +}; + +type component eIM_ConnHdlr extends HTTP_ConnHdlr, http_CT { + port PIPEasp_PT PIPE; + var eIM_ConnHdlrPars g_pars_EIM; + var template integer g_http_client_id := omit; /* ESipa client */ +}; + +type record eIM_ConnHdlrPars { + /* TODO: add some useful parameters */ +}; + +private function f_init_pars() +runs on MTC_CT return eIM_ConnHdlrPars { + var eIM_ConnHdlrPars pars := { + /* TODO: fill parameters with meaninful values */ + }; + return pars; +} + +modulepar { + /* emulated ES9+ SMDP+ server */ + charstring mp_es9p_ip := "127.0.0.1"; + integer mp_es9p_port := 8090; + boolean mp_es9p_disable_ssl := true; + + /* emulated ESipa IPAd HTTPs client */ + charstring mp_esipa_ip := "127.0.0.1"; + integer mp_esipa_port := 8000; + boolean mp_esipa_disable_ssl := true; + + /* REST API tool */ + /* TODO: no absolute path here */ + charstring mp_restop_path := "/home/user/work/eIM_IPAd/git/onomondo-eim/contrib/restop.py" +} + +private altstep as_Tguard() runs on MTC_CT { + [] g_Tguard.timeout { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout"); + } +} + +private type function void_fn(charstring id) runs on eIM_ConnHdlr; + +private function f_init_handler(void_fn fn, charstring id, eIM_ConnHdlrPars pars) runs on eIM_ConnHdlr { + g_pars_EIM := pars; + fn.apply(id); +} + +private function f_start_handler(void_fn fn, eIM_ConnHdlrPars pars) +runs on MTC_CT return eIM_ConnHdlr { + var eIM_ConnHdlr vc_conn; + var charstring id := testcasename(); + + vc_conn := eIM_ConnHdlr.create(id); + + /* connect ES9+/HTTP-server ports */ + if (isbound(vc_HTTP)) { + connect(vc_conn:HTTP_SRV, vc_HTTP:CLIENT); + connect(vc_conn:HTTP_SRV_PROC, vc_HTTP:CLIENT_PROC); + } + + vc_conn.start(f_init_handler(fn, id, pars)); + return vc_conn; +} + +private function f_init(charstring id, float t_guard := 40.0) runs on MTC_CT { + g_Tguard.start(t_guard); + activate(as_Tguard()); + + /* start ES9+/HTTP-server */ + var HttpServerEmulationCfg http_cfg := { + http_bind_ip := mp_es9p_ip, + http_bind_port := mp_es9p_port, + use_ssl := not mp_es9p_disable_ssl + }; + vc_HTTP := HTTP_Server_Emulation_CT.create(id); + vc_HTTP.start(HTTP_Server_Emulation.main(http_cfg)); +} + + + +/* ********************************************* */ +/* ************* ES9+/HTTP-server ************** */ +/* ********************************************* */ + +/* Helper function to send HTTP responses (ES9+) */ +private function f_make_http_resp(charstring resp) return HTTPMessage { + var HTTPMessage resp_msg; + var HTTPResponse resp_body := { + client_id := omit, + version_major := 1, + version_minor := 1, + statuscode := 200, + statustext := "OK", + /* See also SGP.32, section 6.1.1 */ + header := { + { + header_name := "X-Admin-Protocol", + header_value := "gsma/rsp/v1.0.0" + }, + { + header_name := "Content-Type", + header_value := "application/json" + }, + { + header_name := "Content-Length", + header_value := int2str(lengthof(resp)) + } + }, + body := resp + }; + + resp_msg := { response := resp_body }; + return resp_msg; +} + +/* Receive one Es9p HTTP request */ +private function f_es9p_receive() runs on eIM_ConnHdlr return RemoteProfileProvisioningRequest { + var HTTPMessage es9p_req; + timer T := 10.0; + var RemoteProfileProvisioningRequest request; + + T.start; + alt { + [] HTTP_SRV.receive({ request := ? }) -> value es9p_req { + dec_RemoteProfileProvisioningRequest_from_JSON(es9p_req.request.body, request); + } + [] T.timeout { + setverdict(fail, "no HTTP request received?"); + } + } + + return request; +} + +/* Send Es9p HTTP response */ +private function f_es9p_send(RemoteProfileProvisioningResponse response) runs on eIM_ConnHdlr { + var charstring es9p_res; + enc_RemoteProfileProvisioningResponse_to_JSON(response, es9p_res); + HTTP_SRV.send(f_make_http_resp(es9p_res)); +} + +/* Perform Es9p HTTP request/response cycle */ +private function f_es9p_transceive(RemoteProfileProvisioningResponse response) +runs on eIM_ConnHdlr return RemoteProfileProvisioningRequest { + var RemoteProfileProvisioningRequest request; + request := f_es9p_receive(); + f_es9p_send(response); + return request; +} + +/* Perform Es9p HTTP request/response cycle but with an empty response */ +private function f_es9p_transceive_empty_response() +runs on eIM_ConnHdlr return RemoteProfileProvisioningRequest { + var RemoteProfileProvisioningResponse response; /* Intentionally left unbound */ + return f_es9p_transceive(response); +} + + + +/* ********************************************* */ +/* ************ PIPEasp (REST API) ************* */ +/* ********************************************* */ + +template (value) ASP_PExecute ts_Exec(charstring cmd) := { + command := cmd, + stdin := "" +} + +template (present) ASP_PResult tr_Result(template (present) charstring stdout, + template (present) charstring stderr, + template (present) integer code) := { + stdout := stdout, + stderr := stderr, + code := code +} + +private function f_init_pipe() runs on eIM_ConnHdlr { + map(self:PIPE, system:PIPE); +} + +/* Create a new rest resource (generic) */ +private function f_rest_create(charstring cmdline) +runs on eIM_ConnHdlr return charstring { + var ASP_PResult result; + + PIPE.send(ts_Exec(cmdline)); + timer T := 4.0; + T.start; + alt { + [] PIPE.receive(tr_Result(?,?,0)) -> value result { + /* On success, stdout should contain an URL to a resource */ + if (substr(result.stdout, 0, 7) != "http://") { + setverdict(fail, "got malformed resource URL from REST API while creating resource"); + } + return regexp(result.stdout, "(?+)(lookup/)(?+)", 2); + } + [] PIPE.receive { + setverdict(fail, "unexpected response from REST API while creating resource"); + } + [] T.timeout { + setverdict(fail, "no response from REST API while creating resource"); + } + } + + setverdict(fail, "got no resource URL from REST API while creating resource"); + return "no resource"; +} + +/* Create a new rest resource (download) */ +private function f_rest_create_dwnld(octetstring eID, charstring activationCode) +runs on eIM_ConnHdlr return charstring { + var charstring cmdline; + cmdline := mp_restop_path & " -c -f download -j " & + oct2char(enc_JSON_REST_resource(valueof(ts_JSON_REST_download_order(eID, activationCode)))) + return f_rest_create(cmdline); +} + +/* Create a new rest resource (psmo) */ +private function f_rest_create_psmo(template JSON_REST_resource psmo_order) +runs on eIM_ConnHdlr return charstring { + var charstring cmdline; + cmdline := mp_restop_path & " -c -f psmo -j " & + oct2char(enc_JSON_REST_resource(valueof(psmo_order))); + return f_rest_create(cmdline); +} + +/* Lookup an existing REST resource */ +private function f_rest_lookup_resource(charstring resource_id, charstring facility, + template JSON_REST_response expected_rest_res := omit) +runs on eIM_ConnHdlr return JSON_REST_response { + var charstring cmdline; + var ASP_PResult result; + var JSON_REST_response rest_res; + + cmdline := mp_restop_path & " -l -f " & facility & " -r " & resource_id; + + PIPE.send(ts_Exec(cmdline)); + timer T := 4.0; + T.start; + alt { + [] PIPE.receive(tr_Result(?,?,0)) -> value result { + rest_res := dec_JSON_REST_response(char2oct(result.stdout)); + } + [] PIPE.receive { + setverdict(fail, "unexpected response from REST API while looking up resource"); + } + [] T.timeout { + setverdict(fail, "no response from REST API while looking up resource"); + } + } + + if (not istemplatekind(expected_rest_res, "omit") and not match(rest_res, tr_JSON_REST_success)) { + setverdict(fail, "unexpected REST lookup result from eIM"); + } + + return rest_res; +} + +/* Delete REST resource */ +private function f_rest_delete_resource(charstring resource_id, charstring facility) +runs on eIM_ConnHdlr { + var charstring cmdline; + var ASP_PResult result; + var JSON_REST_response rest_res; + cmdline := mp_restop_path & " -d -f " & facility & " -r " & resource_id; + + PIPE.send(ts_Exec(cmdline)); + timer T := 4.0; + T.start; + alt { + [] PIPE.receive(tr_Result(?,?,0)) -> value result { + /* Verify that the resource has been deleted */ + rest_res := dec_JSON_REST_response(char2oct(result.stdout)); + if (not match(rest_res, tr_JSON_REST_deleted)) { + setverdict(fail, "unexpected REST delete result from eIM"); + } + + /* Make sure that the resource has really been deleted */ + if (not match(f_rest_lookup_resource(resource_id, facility), tr_JSON_REST_absent)) { + setverdict(fail, "unexpected REST result from eIM while checking resource deletion"); + } + + } + [] PIPE.receive { + setverdict(fail, "unexpected response from REST API while deleting resource"); + } + [] T.timeout { + setverdict(fail, "no response from REST API while deleting resource"); + } + } +} + + + +/* ********************************************* */ +/* ************* ESipa/HTTP-client ************* */ +/* ********************************************* */ + +private function f_enc_http_req(in RemoteProfileProvisioningResponse es9p_res, out HTTPMessage http_res) { + var charstring json_body; + var HTTPResponse resp_body; + + enc_RemoteProfileProvisioningResponse_to_JSON(es9p_res, json_body); + resp_body := { + client_id := omit, + version_major := 1, + version_minor := 1, + statuscode := 200, + statustext := "OK", + /* See also SGP.32, section 6.1.1 */ + header := { + { + header_name := "X-Admin-Protocol", + header_value := "gsma/rsp/v1.0.0" + }, + { + header_name := "Content-Type", + header_value := "application/x-gsma-rsp-asn1" + }, + { + header_name := "Content-Length", + header_value := int2str(lengthof(json_body)) + } + }, + body := json_body + }; + + http_res := { response := resp_body }; +} with { extension "prototype(fast)" } + +template (value) HeaderLines ts_esipa_HTTP_Header := { + { header_name := "User-Agent", header_value := "TTCN3 eIM testsuite" }, + { header_name := "X-Admin-Protocol", header_value := "gsma/rsp/v2.5.0" }, + { header_name := "Content-Type", header_value := "application/x-gsma-rsp-asn1" } +}; + +/* Send ESipa HTTP request */ +private function f_esipa_send(EsipaMessageFromIpaToEim request) runs on eIM_ConnHdlr { + var octetstring request_enc; + request_enc := enc_EsipaMessageFromIpaToEim(request); + f_http_tx_request(url := "/gsma/rsp2/asn1", + method := "POST", + binary_body:= request_enc, + custom_hdr := valueof(ts_esipa_HTTP_Header), + client_id := g_http_client_id); +} + +/* Receive ESipa HTTP response */ +private function f_esipa_receive() runs on eIM_ConnHdlr return template EsipaMessageFromEimToIpa { + + var HTTPMessage response_http; + response_http := f_http_rx_response(exp := ?, + client_id := g_http_client_id, + keep_connection := true); + + if (istemplatekind(g_http_client_id, "omit")) { + /* Memorize client_id of the first request. The client_id will identify the HTTP connection + * in all consecutive requests. */ + g_http_client_id := f_http_client_id_from_http_response(response_http); + } else if (valueof(g_http_client_id) != valueof(f_http_client_id_from_http_response(response_http))) { + /* The client_id must not change. A sudden change of the client_id may indicate an interrupted + * HTTP connection. This must not happen unexpectetly. */ + setverdict(fail, "unexpected ESipa HTTP connection"); + } + + if (ispresent(response_http.response_binary)) { + return dec_EsipaMessageFromEimToIpa(response_http.response_binary.body); + } else { + setverdict(fail, "unexpected ESipa response, the HTTP body did either contain no or a non binary response"); + return omit; + } +} + +/* Perform one ESipa HTTP request/response cycle */ +private function f_esipa_transceive(EsipaMessageFromIpaToEim request) +runs on eIM_ConnHdlr return template EsipaMessageFromEimToIpa { + f_esipa_send(request); + return f_esipa_receive(); +} + + + +/* ********************************************* */ +/* ********** BELOW ONLY TESTCASES! ************ */ +/* ********************************************* */ + +/* Common Mutual Authentication Procedure, see also: GSMA SGP.22, section 3.0.1 */ +private function f_proc_cmn_mtl_auth() runs on eIM_ConnHdlr { + var EsipaMessageFromIpaToEim esipa_req; + var template EsipaMessageFromEimToIpa esipa_res; + var template RemoteProfileProvisioningRequest es9p_req; + var RemoteProfileProvisioningResponse es9p_res; + + /* InitiateAuthentication cycle */ + esipa_req := valueof(ts_initiateAuthenticationRequestEsipa(smdpAddress := mp_es9p_ip & ":" & int2str(mp_es9p_port))); + f_esipa_send(esipa_req); + + es9p_res := valueof(ts_initiateAuthenticationResponse); + es9p_req := f_es9p_transceive(es9p_res); + if (not match(valueof(es9p_req), tr_initiateAuthenticationRequest)) { + setverdict(fail, "unexpected request from eIM on ES9p"); + } + + esipa_res := f_esipa_receive(); + if (not match(valueof(esipa_res), tr_initiateAuthenticationResponseEsipa)) { + setverdict(fail, "unexpected response from eIM on ESipa"); + } + + /* AuthenticateClient cycle */ + esipa_req := valueof(ts_authenticateClientRequestEsipa); + f_esipa_send(esipa_req); + + es9p_res := valueof(ts_authenticateClientResponseEs9); + es9p_req := f_es9p_transceive(es9p_res); + if (not match(valueof(es9p_req), tr_authenticateClientRequest)) { + setverdict(fail, "unexpected request from eIM on ES9p"); + } + + esipa_res := f_esipa_receive(); + if (not match(valueof(esipa_res), tr_authenticateClientResponseEsipa_dpe)) { + setverdict(fail, "unexpected response from eIM on ESipa"); + } +} + +/* A testcase to try out an indirect profile download, + * See also: GSMA SGP.32, section 3.2.3.2: Indirect Profile Download */ +private function f_TC_proc_indirect_prfle_dwnld(charstring id) runs on eIM_ConnHdlr { + var charstring resource_id; + var HTTP_Adapter_Params http_adapter_pars; + var EsipaMessageFromIpaToEim esipa_req; + var template EsipaMessageFromEimToIpa esipa_res; + var template RemoteProfileProvisioningRequest es9p_req; + var RemoteProfileProvisioningResponse es9p_res; + + var charstring activationCode := "1$" & mp_es9p_ip & ":" & int2str(mp_es9p_port) & "$MyMatchingId" + var octetstring eID := '89882119900000000000000000000005'O + + f_http_register(); + + f_init_pipe(); + http_adapter_pars := { + http_host := mp_esipa_ip, + http_port := mp_esipa_port, + use_ssl := not mp_esipa_disable_ssl + }; + f_http_init(http_adapter_pars); + + /* Create a new download at the eIM */ + resource_id := f_rest_create_dwnld(eID, activationCode); + + /* Check the eIM for new eIM packages, we expect to get a profileDownloadTriggerRequest that contains the activationCode + * that we have created the download with (see above) */ + esipa_req := valueof(ts_getEimPackageRequest(eID)); + esipa_res := valueof(f_esipa_transceive(esipa_req)); + if (not match(valueof(esipa_res), tr_getEimPackageResponse_dnlTrigReq(activationCode))) { + setverdict(fail, "unexpected response from eIM on ESipa"); + } + + /* Perform common mutial authentication procedure */ + f_proc_cmn_mtl_auth(); + + /* Request/download bound profile package */ + esipa_req := valueof(ts_getBoundProfilePackageRequestEsipa); + f_esipa_send(esipa_req); + es9p_res := valueof(ts_getBoundProfilePackageResponse); + es9p_req := f_es9p_transceive(es9p_res); + if (not match(valueof(es9p_req), tr_getBoundProfilePackageRequest)) { + setverdict(fail, "unexpected request from eIM on ES9p"); + } + esipa_res := f_esipa_receive(); + if (not match(valueof(esipa_res), tr_getBoundProfilePackageResponseEsipa)) { + setverdict(fail, "unexpected response from eIM on ESipa"); + } + + /* Handle notification */ + esipa_req := valueof(ts_handleNotificationEsipa_prfleInstRslt); + f_esipa_send(esipa_req); + es9p_req := f_es9p_transceive_empty_response(); + if (not match(valueof(es9p_req), tr_handleNotification)) { + setverdict(fail, "unexpected request from eIM on ES9p"); + } + + f_rest_lookup_resource(resource_id, "download", tr_JSON_REST_success); + f_rest_delete_resource(resource_id, "download"); + + f_sleep(2.0); + setverdict(pass); +} +testcase TC_proc_indirect_prfle_dwnld() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_indirect_prfle_dwnld), pars); + vc_conn.done; + setverdict(pass); +} + +/* A testcase to try out an the Generic eUICC Package Download and Execution Procedure (PSMO), + * See also: GSMA SGP.32, section 3.3.1: Generic eUICC Package Download and Execution */ +private function f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(charstring id, JSON_REST_resource order, + template (present) EuiccPackage euiccPackage, + template (present) EuiccPackageResult euiccPackageResult) runs on eIM_ConnHdlr { + var charstring resource_id; + var HTTP_Adapter_Params http_adapter_pars; + var EsipaMessageFromIpaToEim esipa_req; + var template EsipaMessageFromEimToIpa esipa_res; + var template RemoteProfileProvisioningRequest es9p_req; + var RemoteProfileProvisioningResponse es9p_res; + + f_http_register(); + + f_init_pipe(); + http_adapter_pars := { + http_host := mp_esipa_ip, + http_port := mp_esipa_port, + use_ssl := not mp_esipa_disable_ssl + }; + f_http_init(http_adapter_pars); + + /* Create a new download at the eIM */ + resource_id := f_rest_create_psmo(order); + + /* Check the eIM for new eIM packages, we expect to get an euiccPackageRequest that contains the PSMO + * that we have created (see above) */ + esipa_req := valueof(ts_getEimPackageRequest(str2oct(order.eidValue))); + esipa_res := valueof(f_esipa_transceive(esipa_req)); + if (not match(valueof(esipa_res), tr_getEimPackageResponse_euiccPkgReq(euiccPackage))) { + setverdict(fail, "unexpected response from eIM on ESipa"); + } + + /* Respond with a plausible EimPackage result */ + esipa_req := valueof(ts_provideEimPackageResult_ePRAndNotif(euiccPackageResult)); + esipa_res := valueof(f_esipa_transceive(esipa_req)); + if (not match(valueof(esipa_res), tr_provideEimPackageResultResponse_eimAck)) { + setverdict(fail, "unexpected response from eIM on ESipa"); + } + + f_rest_lookup_resource(resource_id, "psmo", tr_JSON_REST_success); + f_rest_delete_resource(resource_id, "psmo"); + + f_sleep(2.0); + setverdict(pass); +} + +/* (see also above) Test enable PSMO */ +private function f_TC_proc_euicc_pkg_dwnld_exec_enable_psmo(charstring id) runs on eIM_ConnHdlr { + var octetstring eID := '89882119900000000000000000000005'O; + var JSON_REST_resource psmo_order := valueof(ts_JSON_REST_psmo_order_enable(eID, '123456789ABCDEFFAAAA'O, false)); + var template EuiccPackage euiccPackage := tr_euiccPackage_enablePsmo; + f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(id, psmo_order, euiccPackage, ts_euiccPackageResultSigned_enablePsmo); +} +testcase TC_proc_euicc_pkg_dwnld_exec_enable_psmo() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_enable_psmo), pars); + vc_conn.done; + setverdict(pass); +} + +/* (see also above) Test disable PSMO */ +private function f_TC_proc_euicc_pkg_dwnld_exec_disable_psmo(charstring id) runs on eIM_ConnHdlr { + var octetstring eID := '89882119900000000000000000000005'O; + var JSON_REST_resource psmo_order := valueof(ts_JSON_REST_psmo_order_disable(eID, '123456789ABCDEFFAAAA'O)); + var template EuiccPackage euiccPackage := tr_euiccPackage_disablePsmo; + f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(id, psmo_order, euiccPackage, ts_euiccPackageResultSigned_disablePsmo); +} +testcase TC_proc_euicc_pkg_dwnld_exec_disable_psmo() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_disable_psmo), pars); + vc_conn.done; + setverdict(pass); +} + +/* (see also above) Test delete PSMO */ +private function f_TC_proc_euicc_pkg_dwnld_exec_delete_psmo(charstring id) runs on eIM_ConnHdlr { + var octetstring eID := '89882119900000000000000000000005'O; + var JSON_REST_resource psmo_order := valueof(ts_JSON_REST_psmo_order_delete(eID, '123456789ABCDEFFAAAA'O)); + var template EuiccPackage euiccPackage := tr_euiccPackage_deletePsmo; + f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(id, psmo_order, euiccPackage, ts_euiccPackageResultSigned_deletePsmo); +} +testcase TC_proc_euicc_pkg_dwnld_exec_delete_psmo() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_delete_psmo), pars); + vc_conn.done; + setverdict(pass); +} + +/* (see also above) Test disable and delete PSMO at the same time to make sure that eUICC packages with multiple PSMOs + * are also accepted and processed correctly. */ +private function f_TC_proc_euicc_pkg_dwnld_exec_disable_and_delete_psmo(charstring id) runs on eIM_ConnHdlr { + var octetstring eID := '89882119900000000000000000000005'O; + var JSON_REST_resource psmo_order := valueof(ts_JSON_REST_psmo_order_disable_and_delete(eID, '123456789ABCDEFFAAAA'O)); + var template EuiccPackage euiccPackage := tr_euiccPackage_disableAndDeletePsmo; + f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(id, psmo_order, euiccPackage, ts_euiccPackageResultSigned_disableAndDeletePsmo); +} +testcase TC_proc_euicc_pkg_dwnld_exec_disable_and_delete_psmo() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_disable_and_delete_psmo), pars); + vc_conn.done; + setverdict(pass); +} + +/* (see also above) Test listProfileInfo PSMO */ +private function f_TC_proc_euicc_pkg_dwnld_exec_listProfileInfo_psmo(charstring id) runs on eIM_ConnHdlr { + var octetstring eID := '89882119900000000000000000000005'O; + var JSON_REST_resource psmo_order := valueof(ts_JSON_REST_psmo_order_listProfileInfo(eID, '123456789ABCDEFFAAAA'O)); + var template EuiccPackage euiccPackage := tr_euiccPackage_listProfileInfo; + f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(id, psmo_order, euiccPackage, ts_euiccPackageResultSigned_listProfileInfo); +} +testcase TC_proc_euicc_pkg_dwnld_exec_listProfileInfo_psmo() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_listProfileInfo_psmo), pars); + vc_conn.done; + setverdict(pass); +} + +/* (see also above) Test getRAT PSMO */ +private function f_TC_proc_euicc_pkg_dwnld_exec_getRAT_psmo(charstring id) runs on eIM_ConnHdlr { + var octetstring eID := '89882119900000000000000000000005'O; + var JSON_REST_resource psmo_order := valueof(ts_JSON_REST_psmo_order_getRAT(eID)); + var template EuiccPackage euiccPackage := tr_euiccPackage_getRAT; + f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(id, psmo_order, euiccPackage, ts_euiccPackageResultSigned_getRAT); +} +testcase TC_proc_euicc_pkg_dwnld_exec_getRAT_psmo() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_getRAT_psmo), pars); + vc_conn.done; + setverdict(pass); +} + +/* (see also above) Test configureAutoEnable PSMO */ +private function f_TC_proc_euicc_pkg_dwnld_exec_configureAutoEnable_psmo(charstring id) runs on eIM_ConnHdlr { + var octetstring eID := '89882119900000000000000000000005'O; + var JSON_REST_resource psmo_order := valueof(ts_JSON_REST_psmo_order_configureAutoEnable(eID)); + var template EuiccPackage euiccPackage := tr_euiccPackage_configureAutoEnable; + f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(id, psmo_order, euiccPackage, ts_euiccPackageResultSigned_configureAutoEnable); +} +testcase TC_proc_euicc_pkg_dwnld_exec_configureAutoEnable_psmo() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_configureAutoEnable_psmo), pars); + vc_conn.done; + setverdict(pass); +} + +/* (see also above) Test addEim eCO */ +private function f_TC_proc_euicc_pkg_dwnld_exec_addEim_eco(charstring id) runs on eIM_ConnHdlr { + var octetstring eID := '89882119900000000000000000000005'O; + var JSON_REST_resource eco_order := valueof(ts_JSON_REST_eco_order_addEim(eID)); + var template EuiccPackage euiccPackage := tr_euiccPackage_addEim; + f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(id, eco_order, euiccPackage, ts_euiccPackageResultSigned_addEim); +} +testcase TC_proc_euicc_pkg_dwnld_exec_addEim_eco() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_addEim_eco), pars); + vc_conn.done; + setverdict(pass); +} + +/* (see also above) Test deleteEim eCO */ +private function f_TC_proc_euicc_pkg_dwnld_exec_deleteEim_eco(charstring id) runs on eIM_ConnHdlr { + var octetstring eID := '89882119900000000000000000000005'O; + var JSON_REST_resource eco_order := valueof(ts_JSON_REST_eco_order_deleteEim(eID)); + var template EuiccPackage euiccPackage := tr_euiccPackage_deleteEim; + f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(id, eco_order, euiccPackage, ts_euiccPackageResultSigned_deleteEim); +} +testcase TC_proc_euicc_pkg_dwnld_exec_deleteEim_eco() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_deleteEim_eco), pars); + vc_conn.done; + setverdict(pass); +} + +/* (see also above) Test updateEim eCO */ +private function f_TC_proc_euicc_pkg_dwnld_exec_updateEim_eco(charstring id) runs on eIM_ConnHdlr { + var octetstring eID := '89882119900000000000000000000005'O; + var JSON_REST_resource eco_order := valueof(ts_JSON_REST_eco_order_updateEim(eID)); + var template EuiccPackage euiccPackage := tr_euiccPackage_updateEim; + f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(id, eco_order, euiccPackage, ts_euiccPackageResultSigned_updateEim); +} +testcase TC_proc_euicc_pkg_dwnld_exec_updateEim_eco() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_updateEim_eco), pars); + vc_conn.done; + setverdict(pass); +} + +/* (see also above) Test listEim eCO */ +private function f_TC_proc_euicc_pkg_dwnld_exec_listEim_eco(charstring id) runs on eIM_ConnHdlr { + var octetstring eID := '89882119900000000000000000000005'O; + var JSON_REST_resource eco_order := valueof(ts_JSON_REST_eco_order_listEim(eID)); + var template EuiccPackage euiccPackage := tr_euiccPackage_listEim; + f_TC_proc_euicc_pkg_dwnld_exec_psmo_or_eco(id, eco_order, euiccPackage, ts_euiccPackageResultSigned_listEim); +} +testcase TC_proc_euicc_pkg_dwnld_exec_listEim_eco() runs on MTC_CT { + var charstring id := testcasename(); + var eIM_ConnHdlrPars pars := f_init_pars(); + var eIM_ConnHdlr vc_conn; + f_init(id); + vc_conn := f_start_handler(refers(f_TC_proc_euicc_pkg_dwnld_exec_updateEim_eco), pars); + vc_conn.done; + setverdict(pass); +} + +control { + execute ( TC_proc_indirect_prfle_dwnld() ); + execute ( TC_proc_euicc_pkg_dwnld_exec_enable_psmo() ); + execute ( TC_proc_euicc_pkg_dwnld_exec_disable_psmo() ); + execute ( TC_proc_euicc_pkg_dwnld_exec_delete_psmo() ); + execute ( TC_proc_euicc_pkg_dwnld_exec_disable_and_delete_psmo() ); + execute ( TC_proc_euicc_pkg_dwnld_exec_listProfileInfo_psmo() ); + execute ( TC_proc_euicc_pkg_dwnld_exec_getRAT_psmo() ); + execute ( TC_proc_euicc_pkg_dwnld_exec_configureAutoEnable_psmo() ); + execute ( TC_proc_euicc_pkg_dwnld_exec_addEim_eco() ); + execute ( TC_proc_euicc_pkg_dwnld_exec_deleteEim_eco() ); + execute ( TC_proc_euicc_pkg_dwnld_exec_updateEim_eco() ); + execute ( TC_proc_euicc_pkg_dwnld_exec_listEim_eco() ); +} + +}
\ No newline at end of file diff --git a/eim/es9p_Types_JSON.ttcn b/eim/es9p_Types_JSON.ttcn new file mode 100644 index 00000000..5a8587b2 --- /dev/null +++ b/eim/es9p_Types_JSON.ttcn @@ -0,0 +1,235 @@ +/* JSON message definitions for ES9+ + * + * Author: Philipp Maier <pmaier@sysmocom.de> / sysmocom - s.f.m.c. GmbH + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +module es9p_Types_JSON { + +import from RSPDefinitions all; +import from RSPDefinitions_Types all; +import from RSPDefinitions_Templates all; + +import from PKIX1Explicit88 all; +import from PKIX1Explicit88_Templates all; +import from PKIX1Explicit88_Types all; + +import from PKIX1Implicit88 all; +import from PKIX1Implicit88_Templates all; +import from PKIX1Implicit88_Types all; + + +/* GSMA SGP.22, section 6.5.1.3 */ +type record JSON_ES9p_RequestHeader { + charstring functionRequesterIdentifier, + charstring functionCallIdentifier +}; + +/* GSMA SGP.22, section 6.5.1.4 */ +type record JSON_ES9p_FunctionExecutionStatus { + charstring status +}; +type record JSON_ES9p_ResponseHeader { + JSON_ES9p_FunctionExecutionStatus functionExecutionStatus +}; + +/* GSMA SGP.22, section 6.5.2.6 */ +type record JSON_ES9p_InitiateAuthenticationRequest { + JSON_ES9p_RequestHeader header, + charstring euiccChallenge, + charstring euiccInfo1, + charstring smdpAddress +}; +type record JSON_ES9p_InitiateAuthenticationResponse { + JSON_ES9p_ResponseHeader header, + charstring transactionId, + charstring serverSigned1, + charstring serverSignature1, + charstring euiccCiPKIdToBeUsed, + charstring serverCertificate +}; + +/* GSMA SGP.22, section 6.5.2.7 */ +type record JSON_ES9p_GetBoundProfilePackageRequest { + JSON_ES9p_RequestHeader header, + charstring transactionId, + charstring prepareDownloadResponse +}; +type record JSON_ES9p_GetBoundProfilePackageResponse { + JSON_ES9p_ResponseHeader header, + charstring transactionId, + charstring boundProfilePackage +}; + +/* GSMA SGP.22, section 6.5.2.8 */ +type record JSON_ES9p_AuthenticateClientRequest { + JSON_ES9p_RequestHeader header, + charstring transactionId, + charstring authenticateServerResponse +}; +type record JSON_ES9p_AuthenticateClientResponseEs9 { + JSON_ES9p_ResponseHeader header, + charstring transactionId, + charstring profileMetadata, + charstring smdpSigned2, + charstring smdpSignature2, + charstring smdpCertificate +}; + +/* GSMA SGP.22, section 6.5.2.9 */ +type record JSON_ES9p_HandleNotification { + JSON_ES9p_RequestHeader header, + charstring pendingNotification +}; + +/* GSMA SGP.22, section 6.5.2.10 */ +type record JSON_ES9p_CancelSessionRequestEs9 { + JSON_ES9p_RequestHeader header, + charstring transactionId, + charstring cancelSessionResponse +}; + +/* An empty response that is used when the response only consists of a JSON header */ +type record JSON_ES9p_EmptyResponse { + JSON_ES9p_ResponseHeader header +}; + + +/* Definition for JSON ES9+ requests */ +type union JSON_ES9p_RemoteProfileProvisioningRequest { + JSON_ES9p_InitiateAuthenticationRequest initiateAuthenticationRequest, + JSON_ES9p_GetBoundProfilePackageRequest getBoundProfilePackageRequest, + JSON_ES9p_AuthenticateClientRequest authenticateClientRequest, + JSON_ES9p_HandleNotification handleNotification, + JSON_ES9p_CancelSessionRequestEs9 cancelSessionRequestEs9 +} with { + variant "JSON : as value" +} + +external function enc_JSON_ES9p_RemoteProfileProvisioningRequest(in JSON_ES9p_RemoteProfileProvisioningRequest msg) return octetstring +with { + extension "prototype (convert) encode(JSON)"; + extension "printing(pretty)"; + extension "errorbehavior(ALL:ERROR)" +} +external function dec_JSON_ES9p_RemoteProfileProvisioningRequest(in octetstring stream) return JSON_ES9p_RemoteProfileProvisioningRequest +with { + extension "prototype (convert) decode(JSON)" + extension "errorbehavior(ALL:ERROR)" +} + + +/* Definition for JSON ES9+ responses */ +type union JSON_ES9p_RemoteProfileProvisioningResponse +{ + JSON_ES9p_InitiateAuthenticationResponse initiateAuthenticationResponse, + JSON_ES9p_GetBoundProfilePackageResponse getBoundProfilePackageResponse, + JSON_ES9p_AuthenticateClientResponseEs9 authenticateClientResponseEs9, + JSON_ES9p_EmptyResponse emptyResponse +} with { + variant "JSON : as value" +} + +external function enc_JSON_ES9p_RemoteProfileProvisioningResponse(in JSON_ES9p_RemoteProfileProvisioningResponse msg) return octetstring +with { + extension "prototype (convert) encode(JSON)"; + extension "printing(pretty)"; + extension "errorbehavior(ALL:ERROR)" +} +external function dec_JSON_ES9p_RemoteProfileProvisioningResponse(in octetstring stream) return JSON_ES9p_RemoteProfileProvisioningResponse +with { + extension "prototype (convert) decode(JSON)" + extension "errorbehavior(ALL:ERROR)" +} + +/* Converter function to decode a JSON formatted ES9+ request to its ASN.1 ES9+ record representation */ +function dec_RemoteProfileProvisioningRequest_from_JSON(in charstring json_pdu_enc, out RemoteProfileProvisioningRequest asn1_pdu_dec) { + var JSON_ES9p_RemoteProfileProvisioningRequest json_pdu; + json_pdu := dec_JSON_ES9p_RemoteProfileProvisioningRequest(char2oct(json_pdu_enc)); + + if (ispresent(json_pdu.initiateAuthenticationRequest)) { + asn1_pdu_dec := valueof(ts_initiateAuthenticationRequest( + decode_base64(json_pdu.initiateAuthenticationRequest.euiccChallenge), + json_pdu.initiateAuthenticationRequest.smdpAddress, + dec_EUICCInfo1(decode_base64(json_pdu.initiateAuthenticationRequest.euiccInfo1)))); + } else if (ispresent(json_pdu.getBoundProfilePackageRequest)) { + asn1_pdu_dec := valueof(ts_getBoundProfilePackageRequest( + str2oct(json_pdu.getBoundProfilePackageRequest.transactionId), + dec_PrepareDownloadResponse(decode_base64(json_pdu.getBoundProfilePackageRequest.prepareDownloadResponse)))); + } else if (ispresent(json_pdu.authenticateClientRequest)) { + asn1_pdu_dec := valueof(ts_authenticateClientRequest( + str2oct(json_pdu.authenticateClientRequest.transactionId), + dec_AuthenticateServerResponse(decode_base64(json_pdu.authenticateClientRequest.authenticateServerResponse)))); + } else if (ispresent(json_pdu.handleNotification)) { + asn1_pdu_dec := valueof(ts_handleNotification( + dec_PendingNotification(decode_base64(json_pdu.handleNotification.pendingNotification)))); + } else if (ispresent(json_pdu.cancelSessionRequestEs9)) { + asn1_pdu_dec := valueof(ts_cancelSessionRequestEs9( + str2oct(json_pdu.cancelSessionRequestEs9.transactionId), + dec_CancelSessionResponse(decode_base64(json_pdu.cancelSessionRequestEs9.cancelSessionResponse)))); + } else { + setverdict(fail, "decoder path not implemented for JSON ES9+ message"); + } +} with { extension "prototype(fast)" } + +/* Converter function to encode an ASN.1 ES9+ response record to its JSON formatted ES9+ representation */ +function enc_RemoteProfileProvisioningResponse_to_JSON(in RemoteProfileProvisioningResponse asn1_pdu_dec, out charstring json_pdu_enc) { + var JSON_ES9p_RemoteProfileProvisioningResponse json_pdu; + + if (ispresent(asn1_pdu_dec.initiateAuthenticationResponse)) { + json_pdu.initiateAuthenticationResponse.header.functionExecutionStatus.status := "Executed-Success"; + json_pdu.initiateAuthenticationResponse.transactionId := + oct2str(asn1_pdu_dec.initiateAuthenticationResponse.initiateAuthenticationOk.transactionId); + json_pdu.initiateAuthenticationResponse.serverSigned1 := + encode_base64(enc_ServerSigned1(asn1_pdu_dec.initiateAuthenticationResponse.initiateAuthenticationOk.serverSigned1)); + json_pdu.initiateAuthenticationResponse.serverSignature1 := + encode_base64(asn1_pdu_dec.initiateAuthenticationResponse.initiateAuthenticationOk.serverSignature1); + json_pdu.initiateAuthenticationResponse.euiccCiPKIdToBeUsed := + encode_base64(enc_SubjectKeyIdentifier(asn1_pdu_dec.initiateAuthenticationResponse.initiateAuthenticationOk.euiccCiPKIdToBeUsed)); + json_pdu.initiateAuthenticationResponse.serverCertificate := + encode_base64(enc_Certificate(asn1_pdu_dec.initiateAuthenticationResponse.initiateAuthenticationOk.serverCertificate)); + json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningResponse(json_pdu)); + } else if (ispresent(asn1_pdu_dec.getBoundProfilePackageResponse)) { + json_pdu.getBoundProfilePackageResponse.header.functionExecutionStatus.status := "Executed-Success"; + json_pdu.getBoundProfilePackageResponse.transactionId := + oct2str(asn1_pdu_dec.getBoundProfilePackageResponse.getBoundProfilePackageOk.transactionId); + json_pdu.getBoundProfilePackageResponse.boundProfilePackage := + encode_base64(enc_BoundProfilePackage(asn1_pdu_dec.getBoundProfilePackageResponse.getBoundProfilePackageOk.boundProfilePackage)); + json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningResponse(json_pdu)); + } else if (ispresent(asn1_pdu_dec.authenticateClientResponseEs9)) { + json_pdu.authenticateClientResponseEs9.header.functionExecutionStatus.status := "Executed-Success"; + json_pdu.authenticateClientResponseEs9.transactionId := + oct2str(asn1_pdu_dec.authenticateClientResponseEs9.authenticateClientOk.transactionId); + json_pdu.authenticateClientResponseEs9.profileMetadata := + encode_base64(enc_StoreMetadataRequest(asn1_pdu_dec.authenticateClientResponseEs9.authenticateClientOk.profileMetaData)); + json_pdu.authenticateClientResponseEs9.smdpSigned2 := + encode_base64(enc_SmdpSigned2(asn1_pdu_dec.authenticateClientResponseEs9.authenticateClientOk.smdpSigned2)); + json_pdu.authenticateClientResponseEs9.smdpSignature2 := + encode_base64(asn1_pdu_dec.authenticateClientResponseEs9.authenticateClientOk.smdpSignature2); + json_pdu.authenticateClientResponseEs9.smdpCertificate := + encode_base64(enc_Certificate(asn1_pdu_dec.authenticateClientResponseEs9.authenticateClientOk.smdpCertificate)); + json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningResponse(json_pdu)); + } else if (ispresent(asn1_pdu_dec.cancelSessionResponseEs9)) { + /* This message has no JSON body, see also GSMA SGP.22, section 6.5.2.10 */ + json_pdu.emptyResponse.header.functionExecutionStatus.status := "Executed-Success"; + json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningResponse(json_pdu)); + } else if (ispresent(asn1_pdu_dec.authenticateClientResponseEs11)) { + setverdict(fail, "encoder path not implemented for JSON ES9+ message AuthenticateClientResponseEs11"); + } else { + json_pdu.emptyResponse.header.functionExecutionStatus.status := "Executed-Success"; + json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningResponse(json_pdu)); + } +} with { extension "prototype(fast)" } + +} with { + encode "JSON"; +} + + + + + diff --git a/eim/gen_links.sh b/eim/gen_links.sh new file mode 100755 index 00000000..4bb1ea8c --- /dev/null +++ b/eim/gen_links.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +BASEDIR=../deps + +. ../gen_links.sh.inc + +DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src +FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCInterface.cc TCCInterface_ip.h" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.Common_Components.Abstract_Socket/src +FILES="Abstract_Socket.cc Abstract_Socket.hh " +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.HTTPmsg/src +FILES="HTTPmsg_MessageLen.ttcn HTTPmsg_MessageLen_Function.cc HTTPmsg_PT.cc HTTPmsg_PT.hh HTTPmsg_PortType.ttcn " +FILES+="HTTPmsg_Types.ttcn" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src +FILES="Socket_API_Definitions.ttcn" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.IPL4asp/src +FILES="IPL4asp_Functions.ttcn IPL4asp_PT.cc IPL4asp_PT.hh IPL4asp_PortType.ttcn IPL4asp_Types.ttcn " +FILES+="IPL4asp_discovery.cc IPL4asp_protocol_L234.hh" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.PIPEasp/src +FILES="PIPEasp_PT.cc PIPEasp_PT.hh PIPEasp_Types.ttcn PIPEasp_PortType.ttcn " +gen_links $DIR $FILES + +DIR=../library/euicc +FILES="PEDefinitions.asn PKIX1Explicit88.asn PKIX1Implicit88.asn RSPDefinitions.asn SGP32Definitions.asn " +FILES+="PKIX1Explicit88_Templates.ttcn PKIX1Explicit88_Types.ttcn PKIX1Implicit88_Templates.ttcn " +FILES+="PKIX1Implicit88_Types.ttcn RSPDefinitions_Templates.ttcn RSPDefinitions_Types.ttcn " +FILES+="SGP32Definitions_Templates.ttcn SGP32Definitions_Types.ttcn " +FILES+="PKIX1Explicit88_EncDec.cc PKIX1Implicit88_EncDec.cc RSPDefinitions_EncDec.cc SGP32Definitions_EncDec.cc" +gen_links $DIR $FILES + +DIR=../library +FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn Native_Functions.ttcn Native_FunctionDefs.cc " +FILES+="HTTP_Server_Emulation.ttcn HTTP_Adapter.ttcn" +gen_links $DIR $FILES + +ignore_pp_results diff --git a/eim/regen_makefile.sh b/eim/regen_makefile.sh new file mode 100755 index 00000000..cc0fd8ef --- /dev/null +++ b/eim/regen_makefile.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +NAME=eIM_Tests + +FILES=" + *.ttcn + *.asn + Abstract_Socket.cc + HTTPmsg_MessageLen_Function.cc + HTTPmsg_PT.cc + IPL4asp_PT.cc + IPL4asp_discovery.cc + Native_FunctionDefs.cc + TCCConversion.cc + TCCInterface.cc + SGP32Definitions_EncDec.cc + RSPDefinitions_EncDec.cc + PKIX1Explicit88_EncDec.cc + PKIX1Implicit88_EncDec.cc + PIPEasp_PT.cc +" +../regen-makefile.sh eIM_Tests.ttcn $FILES + +# required for forkpty(3) used by PIPEasp +sed -i -e '/^LINUX_LIBS/ s/$/ -lutil/' Makefile diff --git a/eim/server.crt b/eim/server.crt new file mode 100644 index 00000000..c113a770 --- /dev/null +++ b/eim/server.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDyTCCArECFEz9Tzs8MSJUbUSExuS62RPPnfhjMA0GCSqGSIb3DQEBCwUAMIGg +MQswCQYDVQQGEwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4x +HTAbBgNVBAoMFElQQWQgdGVzdCBpbmR1c3RyaWVzMRswGQYDVQQLDBJ0ZXN0aW5n +IGRlcGFydG1lbnQxEjAQBgNVBAMMCTEyNy4wLjAuMTEfMB0GCSqGSIb3DQEJARYQ +dGVzdEBleGFtcGxlLm5ldDAeFw0yNDAxMTUxMDMxMTJaFw0yNTAxMTQxMDMxMTJa +MIGgMQswCQYDVQQGEwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJs +aW4xHTAbBgNVBAoMFElQQWQgdGVzdCBpbmR1c3RyaWVzMRswGQYDVQQLDBJ0ZXN0 +aW5nIGRlcGFydG1lbnQxEjAQBgNVBAMMCTEyNy4wLjAuMTEfMB0GCSqGSIb3DQEJ +ARYQdGVzdEBleGFtcGxlLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAK7dI15D1/n+axIimHQvQdhwzpFGNu/PQc+WimVNT4yX5PEbLgiX+OzJMhum +TMU2a/rdNSWAKAa/fK8X8cyFdsJ0hOvTta+1aNzwvVpqjHRwgzKgwjSQ625dujkr +ztERZcM7jrv4+rbU6kFc6W8hb4z4d66RJsDe0cwtsAvP9aipwtOIW4+6IdcduH0g +ANsPadebUz7Cc1l8LUQdfbwU/8VVtlr2RHPMviSidWYworclYYVzM3zvHM1bObo/ +PNCBsq8z9l8KJJqcZhsI9J+Z/5PzGSNGSvI7B55AUZHzt/E86CaRpGrUr+KctV6j +z6CDwdZHVsxRuMvWKsAL5Bw65LsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAnPK4 +dyWCA9mYm5swYEcavhtyJvNwZ1zEp/MHJ40egZFpSnGqNbpEYgjCmqCrpHQxU1Qc +CtgXKgQMuUbvzJio5Mdp1JeSWJD18cBEhWcuufVMvN/HqMw/yJBCmizarUKjRNrE +o2C1P9287fUWdzGxXYPtevMV0E1DQ6v+xTnt1/gyiCtElctYO3f7tkioTmWXGzJY +AyelLfp0F/+lX3Ep1uUIvO7Dofzu+tKilbqqZjBO+gqPQFPRXrbXO90p7bvBieb5 +dBG2segL2hmzYzfKXnKaXU42CgyJgJ2DFChz3RwD41Y8q53wrZjjqM5e8rLNwJEI +dBbKBUSZVr0r9mY7dA== +-----END CERTIFICATE----- diff --git a/eim/server.key b/eim/server.key new file mode 100644 index 00000000..936d6034 --- /dev/null +++ b/eim/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEArt0jXkPX+f5rEiKYdC9B2HDOkUY2789Bz5aKZU1PjJfk8Rsu +CJf47MkyG6ZMxTZr+t01JYAoBr98rxfxzIV2wnSE69O1r7Vo3PC9WmqMdHCDMqDC +NJDrbl26OSvO0RFlwzuOu/j6ttTqQVzpbyFvjPh3rpEmwN7RzC2wC8/1qKnC04hb +j7oh1x24fSAA2w9p15tTPsJzWXwtRB19vBT/xVW2WvZEc8y+JKJ1ZjCityVhhXMz +fO8czVs5uj880IGyrzP2XwokmpxmGwj0n5n/k/MZI0ZK8jsHnkBRkfO38TzoJpGk +atSv4py1XqPPoIPB1kdWzFG4y9YqwAvkHDrkuwIDAQABAoIBAQCN/JQ+c7pIjTSl +uh+un7zIofipb6kmGlWm2OcxkJAaajAFMvuzEKuYoVolp2hI7oLJZZtFAwX9TLlS +d4/ocSrYhMJ1tyedMCGg3X3zj/bSiZWOo4huJIp2yHZw+8hobMcDuzWQHoB9uu8n ++ei2SyEIB60uu0ALdiJGt4ZuYQNpWm55+TwC7j33+8dnPQQof+2vlxMhKoQmZV68 +2VK01o+P1184CqYisecjmKK1zqEvvHFr0QV5hjznZwJXA3eshJe2hydAI3aDamAz +ZD3j54nKtGkwSB4W82SCHEzANTwF5QQYEUiKiGu8EjeTNpSlQ1P4Szf9tjx3rc2m +gcot2YXRAoGBAOQyGQWazJ8EjNDwguc6qeOkSgnWq6HyxcATY9lB2QsPGDs6h6bM +wfnrqEMD8DWyzCuFNtAHcV+KZaNWnGPSQT8pEGGFPgIuH0xSIKbuzu8bE1lv88jU +nPrR+2+N0bd98ilVLQHRb3IlT9FswBF3c2wAm9+c7LoNJ/7pMUM7YQizAoGBAMQr +geewxNjNd8p5NdAi3wp7W8e5XzoJ4iK6y8fnCm2XsVTROtP8xxc6dI4I3OcUzYIa +woN0+RZ1PudC5oGmkPsXzoyORqjAuCOfrYZ62pg7pwRemGGq2Mk+eHfo09d1PrMT +HpkzNRNOk/+pcyKfWUm81NTILPRm/XbIhB6d2+fZAoGBANsg9IA6T2YgQ2zcmIed +AMk12VcrSrOAYr74n7hgECEbhKRTpzHYjCkHUBPSc1fNc1wTVzha/VbGmqVIJXOB +0t/o+e77uTj0u19ZujszNYnMUT9gTxS6fmgpPi64W/u9OM7SGR8W09Mj20r7CFF9 +iFvdFdGcaoKa4Z5apdCu85YbAoGAW3EAY9S1XW4hecMYf4XRvBwWgzn4lqBGxfOW +y/75kG5WXfgN2QUKdNxtukuNVTYQOaZpp0deWMacZMZ9lk/jYvgM8t3bOAxliU2E +YJxhyvZ7ewDxPQ2bcetp0lM4dEWVzXmLGNSS2AYX3OPK5Ies4j9gYjNRKTfczILZ +e0AQYrkCgYEAjJk1an5S6JQMMcdU1KX0uAUJOVu1xkkTvUBYOaC3VzeyYhMJXdOC +g8z/xrFDm7spyCbQPfsA3RHb40ZiGpb2oYhdunEI3f3ZW7RVJSdVeeZAP+IXZOCd +v4+rGNjjXLfpK+TOGkeSNkOivAvpw0mzskCRDfKcsndtwC28OElzCPc= +-----END RSA PRIVATE KEY----- |