dexter has uploaded this change for review.

View Change

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 <pmaier@sysmocom.de> / 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 <pmaier@sysmocom.de> / 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 change 43438. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: newchange
Gerrit-Project: onomondo-ipa
Gerrit-Branch: master
Gerrit-Change-Id: I69571280c7b52f2cb09f733bc0466cb77c0d2590
Gerrit-Change-Number: 43438
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier@sysmocom.de>