dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/onomondo-ipa/+/43438?usp=email )
Change subject: proc_indirect_prfle_dwnld: refactor module, fix spec references ...................................................................... proc_indirect_prfle_dwnld: refactor module, fix spec references The Indirect Profile Download Procedure uses incorrect spec references. As it seems it was a bit mixed up with the Direct Profile Download Procedure, which is very similar, but not identical. With this patch we: - Move the steps from proc_prfle_dwnld.c into proc_indirect_prfle_dwnld.c - restructure the code - Fix the incorrect spec references - Refactor the error handling (session cancellation) - Add TODOs for parts that are still missing Related: SYS#8101 Change-Id: I69571280c7b52f2cb09f733bc0466cb77c0d2590 --- M src/ipa/libipa/CMakeLists.txt M src/ipa/libipa/proc_cmn_mtl_auth.c M src/ipa/libipa/proc_indirect_prfle_dwnld.c D src/ipa/libipa/proc_prfle_dwnld.c D src/ipa/libipa/proc_prfle_dwnld.h 5 files changed, 65 insertions(+), 122 deletions(-) git pull ssh://gerrit.osmocom.org:29418/onomondo-ipa refs/changes/38/43438/1 diff --git a/src/ipa/libipa/CMakeLists.txt b/src/ipa/libipa/CMakeLists.txt index 83084e9..ad3670a 100644 --- a/src/ipa/libipa/CMakeLists.txt +++ b/src/ipa/libipa/CMakeLists.txt @@ -51,7 +51,6 @@ proc_euicc_data_req.c proc_euicc_pkg_dwnld_exec.c proc_notif_delivery.c - proc_prfle_dwnld.c proc_prfle_inst.c utils.c ) diff --git a/src/ipa/libipa/proc_cmn_mtl_auth.c b/src/ipa/libipa/proc_cmn_mtl_auth.c index e625c70..c866604 100644 --- a/src/ipa/libipa/proc_cmn_mtl_auth.c +++ b/src/ipa/libipa/proc_cmn_mtl_auth.c @@ -5,7 +5,8 @@ * * Author: Philipp Maier <[email protected]> / sysmocom - s.f.m.c. GmbH * - * See also: GSMA SGP.22, section 3.0.1: Common Mutual Authentication Procedure + * See also: GSMA SGP.22, section 3.0.2: Common Mutual Authentication Procedure + * and GSMA SGP.32, section 3.2.2: Common Mutual Authentication */ #include <stdio.h> diff --git a/src/ipa/libipa/proc_indirect_prfle_dwnld.c b/src/ipa/libipa/proc_indirect_prfle_dwnld.c index 9b233d3..a99266f 100644 --- a/src/ipa/libipa/proc_indirect_prfle_dwnld.c +++ b/src/ipa/libipa/proc_indirect_prfle_dwnld.c @@ -19,12 +19,13 @@ #include "utils.h" #include "activation_code.h" #include "esipa_auth_clnt.h" -#include "proc_cmn_mtl_auth.h" -#include "proc_prfle_dwnld.h" #include "esipa_get_bnd_prfle_pkg.h" -#include "proc_cmn_cancel_sess.h" +#include "esipa_get_bnd_prfle_pkg.h" +#include "es10b_prep_dwnld.h" +#include "proc_cmn_mtl_auth.h" #include "proc_prfle_inst.h" #include "proc_indirect_prfle_dwnld.h" +#include "proc_cmn_cancel_sess.h" /*! Perform Indirect Profile Download Procedure. * \param[inout] ctx pointer to ipa_context. @@ -33,16 +34,23 @@ int ipa_proc_indirect_prfle_dwnlod(struct ipa_context *ctx, const struct ipa_proc_indirect_prfle_dwnlod_pars *pars) { struct ipa_activation_code *activation_code = NULL; - struct ipa_esipa_auth_clnt_res *auth_clnt_res = NULL; - struct ipa_esipa_get_bnd_prfle_pkg_res *get_bnd_prfle_pkg_res = NULL; struct ipa_proc_cmn_mtl_auth_pars cmn_mtl_auth_pars = { 0 }; - struct ipa_proc_cmn_cancel_sess_pars cmn_cancel_sess_pars = { 0 }; - struct ipa_proc_prfle_dwnlod_pars prfle_dwnlod_pars = { 0 }; + struct ipa_esipa_auth_clnt_res *auth_clnt_res = NULL; + struct ipa_es10b_prep_dwnld_req prep_dwnld_req = { 0 }; + struct ipa_es10b_prep_dwnld_res *prep_dwnld_res = NULL; + struct ipa_esipa_get_bnd_prfle_pkg_req get_bnd_prfle_pkg_req = { 0 }; + struct ipa_esipa_get_bnd_prfle_pkg_res *get_bnd_prfle_pkg_res = NULL; struct ipa_proc_prfle_inst_pars prfle_inst_pars = { 0 }; + struct ipa_proc_cmn_cancel_sess_pars cmn_cancel_sess_pars = { 0 }; + bool cancel_session = false; /* This procedure is called when the IPAd receives an eIM package with a download trigger request * (which contains the activation code) */ + /* Preset the CancelSessionReason to "undefinedReason" */ + cmn_cancel_sess_pars.reason = CancelSessionReason_undefinedReason; + + /* Step #4: Parse activation code */ activation_code = ipa_activation_code_parse(pars->ac); ipa_activation_code_dump(activation_code, 0, SIPA, LDEBUG); if (!activation_code) { @@ -50,7 +58,12 @@ goto error; } - /* Execute sub procedure: Common Mutual Authentication Procedure */ + /* Step #5-#15: Execute sub procedure: Common Mutual Authentication Procedure */ + /* TODO: The Common Mutual Authentication Procedure described in GSMA SGP.32, section 3.2.2 is technically + * very similar to step #5-#15 of GSMA SGP.32, section 3.2.3.2, but it is not identical. Unlinke to the Direct + * Profile Download procedure, the Indirect Profile Download procedure re-defines the steps of the Common + * Mutual Authentication Procedure. Review and compare the affected steps and if necessary, re-implement them + * according to GSMA SGP.32, section 3.2.3.2. */ cmn_mtl_auth_pars.tac = pars->tac; cmn_mtl_auth_pars.allowed_ca = pars->allowed_ca; cmn_mtl_auth_pars.smdp_addr = activation_code->sm_dp_plus_address; @@ -65,29 +78,60 @@ /* TODO: Check if ProfileMetadata contains Profile Policy Rulses (PPRs) and apply the PPRs as configured on the * eUICC. (This is an optional feature, which we currently do not support, see also proc_euicc_data_req.c) */ - /* Execute sub procedure: Sub-procedure Profile Download and Installation – Download Confirmation */ - prfle_dwnlod_pars.auth_clnt_ok_dpe = auth_clnt_res->auth_clnt_ok_dpe; - get_bnd_prfle_pkg_res = ipa_proc_prfle_dwnlod(ctx, &prfle_dwnlod_pars); - if (!get_bnd_prfle_pkg_res) { - IPA_LOGP(SIPA, LERROR, "sub procedure profile download has failed -- canceling session!\n"); - cmn_cancel_sess_pars.reason = CancelSessionReason_loadBppExecutionError; - cmn_cancel_sess_pars.transaction_id = *auth_clnt_res->transaction_id; - ipa_proc_cmn_cancel_sess(ctx, &cmn_cancel_sess_pars); + /* Step #16: ES10b Prepare Download, in case this function call returns a PrepareDownloadResponseError, the + * procedure is stopped and the RSP session is canceled. In all other cases we will forward the unmodified + * result to the eIM to continue the procedure normally. */ + prep_dwnld_req.req.smdpSigned2 = auth_clnt_res->auth_clnt_ok_dpe->smdpSigned2; + prep_dwnld_req.req.smdpSignature2 = auth_clnt_res->auth_clnt_ok_dpe->smdpSignature2; + prep_dwnld_req.req.smdpSignature2.size = + ipa_strip_tlv_envelope(prep_dwnld_req.req.smdpSignature2.buf, prep_dwnld_req.req.smdpSignature2.size, + 0x5f37); + prep_dwnld_req.req.hashCc = auth_clnt_res->auth_clnt_ok_dpe->hashCc; + prep_dwnld_req.req.smdpCertificate = auth_clnt_res->auth_clnt_ok_dpe->smdpCertificate; + prep_dwnld_res = ipa_es10b_prep_dwnld(ctx, &prep_dwnld_req); + if (!prep_dwnld_res || prep_dwnld_res->prep_dwnld_err) { + IPA_LOGP(SIPA, LERROR, "cannot continue, download preparation failed!\n"); + cancel_session = true; goto error; } - /* Execute sub procedure: Sub-procedure Profile Installation (See also section 3.1.3.3 of SGP.22) */ + /* Step #17: ESipa GetBoundProfilePackage */ + get_bnd_prfle_pkg_req.prep_dwnld_res = prep_dwnld_res->res; + get_bnd_prfle_pkg_res = ipa_esipa_get_bnd_prfle_pkg(ctx, &get_bnd_prfle_pkg_req); + if (!get_bnd_prfle_pkg_res || get_bnd_prfle_pkg_res->get_bnd_prfle_pkg_err + || !get_bnd_prfle_pkg_res->get_bnd_prfle_pkg_ok) { + IPA_LOGP(SIPA, LERROR, "cannot continue, get bound profile package failed!\n"); + cancel_session = true; + goto error; + } + + /* TODO: SGP.32, section 3.2.3.2, step 19 requires us to compare the SGP32_StoreMetadataRequest from + pars->auth_clnt_ok_dpe->profileMetaData (optional field) against the SGP32_StoreMetadataRequest from + the ES8+ StoreMetadata (see SGP.22, section 5.5.3) function call in the BoundProfilePackage we have + just received. + + The ES8+ StoreMetadata function call is not encrypted, so we can decode it and extract the + SGP32_StoreMetadataRequest contents from it. Then we can do the comparison. In case a mismatch is + detected, the session should be cancelled (metadataMismatch) */ + + /* Step #20: Execute sub procedure: Sub-procedure Profile Installation (See also section 3.1.3.3 of SGP.22) */ prfle_inst_pars.bound_profile_package = &get_bnd_prfle_pkg_res->get_bnd_prfle_pkg_ok->boundProfilePackage; if (ipa_proc_prfle_inst(ctx, &prfle_inst_pars) < 0) { - IPA_LOGP(SIPA, LERROR, "sub procedure profile installation has failed -- canceling session!\n"); cmn_cancel_sess_pars.reason = CancelSessionReason_loadBppExecutionError; + cancel_session = true; + } + +error: + /* Cancal the ongoing RSP session */ + if (cancel_session && auth_clnt_res) { + IPA_LOGP(SIPA, LERROR, "profile download has failed -- canceling session ...\n"); cmn_cancel_sess_pars.transaction_id = *auth_clnt_res->transaction_id; ipa_proc_cmn_cancel_sess(ctx, &cmn_cancel_sess_pars); } -error: ipa_activation_code_free(activation_code); ipa_esipa_auth_clnt_res_free(auth_clnt_res); + ipa_es10b_prep_dwnld_res_free(prep_dwnld_res); ipa_esipa_get_bnd_prfle_pkg_res_free(get_bnd_prfle_pkg_res); return 0; } diff --git a/src/ipa/libipa/proc_prfle_dwnld.c b/src/ipa/libipa/proc_prfle_dwnld.c deleted file mode 100644 index f9c5176..0000000 --- a/src/ipa/libipa/proc_prfle_dwnld.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2025-2026 Onomondo ApS & sysmocom - s.f.m.c. GmbH. All rights reserved. - * - * SPDX-License-Identifier: AGPL-3.0-only - * - * Author: Philipp Maier <[email protected]> / sysmocom - s.f.m.c. GmbH - * - * See also: GSMA SGP.22, section 3.1.3.2: Sub-procedure Profile Download and Installation – Download Confirmation - */ - -#include <stdio.h> -#include <assert.h> -#include <string.h> -#include <errno.h> -#include <onomondo/ipa/mem.h> -#include <onomondo/ipa/utils.h> -#include <onomondo/ipa/log.h> -#include "context.h" -#include "utils.h" -#include "es10b_prep_dwnld.h" -#include "esipa_get_bnd_prfle_pkg.h" -#include "proc_prfle_dwnld.h" - -/*! Perform Sub-procedure Profile Download and Installation – Download Confirmation. - * \param[inout] ctx pointer to ipa_context. - * \param[in] pars pointer to struct that holds the procedure parameters. - * \returns pointer newly allocated struct with procedure result, NULL on error. */ -struct ipa_esipa_get_bnd_prfle_pkg_res *ipa_proc_prfle_dwnlod(struct ipa_context *ctx, - const struct ipa_proc_prfle_dwnlod_pars *pars) -{ - struct ipa_es10b_prep_dwnld_req prep_dwnld_req = { 0 }; - struct ipa_es10b_prep_dwnld_res *prep_dwnld_res = NULL; - struct ipa_esipa_get_bnd_prfle_pkg_req get_bnd_prfle_pkg_req = { 0 }; - struct ipa_esipa_get_bnd_prfle_pkg_res *get_bnd_prfle_pkg_res = NULL; - - prep_dwnld_req.req.smdpSigned2 = pars->auth_clnt_ok_dpe->smdpSigned2; - prep_dwnld_req.req.smdpSignature2 = pars->auth_clnt_ok_dpe->smdpSignature2; - prep_dwnld_req.req.smdpSignature2.size = - ipa_strip_tlv_envelope(prep_dwnld_req.req.smdpSignature2.buf, prep_dwnld_req.req.smdpSignature2.size, - 0x5f37); - prep_dwnld_req.req.hashCc = pars->auth_clnt_ok_dpe->hashCc; - prep_dwnld_req.req.smdpCertificate = pars->auth_clnt_ok_dpe->smdpCertificate; - - prep_dwnld_res = ipa_es10b_prep_dwnld(ctx, &prep_dwnld_req); - if (!prep_dwnld_res) - goto error; - if (prep_dwnld_res->prep_dwnld_err) - goto error; - - /* In case the ES10b PrepareDownload returns a PrepareDownloadResponseError, the procedure is stopped. - * In all other cases we will forward the unmodified result to the eIM to continue the procedure normally. - * (see also: GSMA SGP.32, section 3.2.3.2, step 16) */ - - get_bnd_prfle_pkg_req.prep_dwnld_res = prep_dwnld_res->res; - get_bnd_prfle_pkg_res = ipa_esipa_get_bnd_prfle_pkg(ctx, &get_bnd_prfle_pkg_req); - if (!get_bnd_prfle_pkg_res) - goto error; - else if (get_bnd_prfle_pkg_res->get_bnd_prfle_pkg_err) - goto error; - else if (!get_bnd_prfle_pkg_res->get_bnd_prfle_pkg_ok) - goto error; - - /* TODO: SGP.32, section 3.2.3.2, step 19 requires us to compare the SGP32_StoreMetadataRequest from - pars->auth_clnt_ok_dpe->profileMetaData (optional field) against the SGP32_StoreMetadataRequest from - the ES8+ StoreMetadata (see SGP.22, section 5.5.3) function call in the BoundProfilePackage we have - just received. - - The ES8+ StoreMetadata function call is not encrypted, so we can decode it and extract the - SGP32_StoreMetadataRequest contents from it. Then we can do the comparison. In case a mismatch is - detected, the session should be cancelled (metadataMismatch) */ - - /* In case of error it is the responsibility of the caller to call the Common Cancel Session procedure. - * In case of success, the caller should ask the user for consent before continuing with the profile - * installation. */ - - ipa_es10b_prep_dwnld_res_free(prep_dwnld_res); - return get_bnd_prfle_pkg_res; -error: - ipa_es10b_prep_dwnld_res_free(prep_dwnld_res); - ipa_esipa_get_bnd_prfle_pkg_res_free(get_bnd_prfle_pkg_res); - return NULL; -} diff --git a/src/ipa/libipa/proc_prfle_dwnld.h b/src/ipa/libipa/proc_prfle_dwnld.h deleted file mode 100644 index 6c16951..0000000 --- a/src/ipa/libipa/proc_prfle_dwnld.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2025-2026 Onomondo ApS & sysmocom - s.f.m.c. GmbH. All rights reserved. - * - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#pragma once - -#include <AuthenticateClientOkDPEsipa.h> - -struct ipa_context; -struct ipa_esipa_get_bnd_prfle_pkg_res; - -struct ipa_proc_prfle_dwnlod_pars { - const AuthenticateClientOkDPEsipa_t *auth_clnt_ok_dpe; -}; - -struct ipa_esipa_get_bnd_prfle_pkg_res *ipa_proc_prfle_dwnlod(struct ipa_context *ctx, - const struct ipa_proc_prfle_dwnlod_pars *pars); -- To view, visit https://gerrit.osmocom.org/c/onomondo-ipa/+/43438?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: newchange Gerrit-Project: onomondo-ipa Gerrit-Branch: master Gerrit-Change-Id: I69571280c7b52f2cb09f733bc0466cb77c0d2590 Gerrit-Change-Number: 43438 Gerrit-PatchSet: 1 Gerrit-Owner: dexter <[email protected]>
