% Copyright (c) 2025 Onomondo ApS & sysmocom - s.f.m.c. GmbH. All rights reserved. % % SPDX-License-Identifier: AGPL-3.0-only % % Author: Philipp Maier / sysmocom - s.f.m.c. GmbH -module(esipa_asn1_handler_utils). -export([ handle_euiccPackageResult/3, handle_ipaEuiccDataResponse/3, handle_eimPackageResultResponseError/3 ]). eimTransactionId_from_euiccPackageResult(EuiccPackageResult) -> case EuiccPackageResult of {euiccPackageResultSigned, EuiccPackageResultSigned} -> EuiccPackageResultDataSigned = maps:get( euiccPackageResultDataSigned, EuiccPackageResultSigned ), maps:get(eimTransactionId, EuiccPackageResultDataSigned, none); {euiccPackageErrorSigned, EuiccPackageErrorSigned} -> EuiccPackageErrorDataSigned = maps:get( euiccPackageErrorDataSigned, EuiccPackageErrorSigned ), maps:get(eimTransactionId, EuiccPackageErrorDataSigned, none); {euiccPackageErrorUnsigned, EuiccPackageErrorUnsigned} -> maps:get(eimTransactionId, EuiccPackageErrorUnsigned, none); _ -> none end. eimTransactionId_from_ipaEuiccDataResponse(IpaEuiccDataResponse) -> case IpaEuiccDataResponse of {ipaEuiccData, IpaEuiccData} -> maps:get(eimTransactionId, IpaEuiccData, none); {ipaEuiccDataResponseError, IpaEuiccDataResponseError} -> maps:get(eimTransactionId, IpaEuiccDataResponseError, none); _ -> none end. % Handle an EuiccPackageResult, this includes everything from the handling of the work items in mnesia_db, down to % signature checks and the generation of an appropriate outcome for the REST API. handle_euiccPackageResult(Pid, EuiccPackageResult, Debuginfo) -> EimTransactionId = eimTransactionId_from_euiccPackageResult(EuiccPackageResult), {EidValue, _, _} = mnesia_db_work:pickup(Pid, EimTransactionId), CheckCounterValue = fun(Map) -> CounterValueIpad = maps:get(counterValue, Map), {ok, CounterValueEim} = mnesia_db_euicc:state_get(EidValue, counterValue), case CounterValueIpad of CounterValueEim -> ok; _ -> logger:error( "invalid eUICC signature, counterValue mismatch: CounterValueIpad=~p, CounterValueEim=~p~n", [CounterValueIpad, CounterValueEim] ), error end end, Outcome = case EuiccPackageResult of {euiccPackageResultSigned, EuiccPackageResultSigned} -> case crypto_utils:verify_euiccPackageResultSigned(EuiccPackageResultSigned, EidValue) of ok -> EuiccPackageResultDataSigned = maps:get( euiccPackageResultDataSigned, EuiccPackageResultSigned ), case CheckCounterValue(EuiccPackageResultDataSigned) of ok -> esipa_rest_utils:euiccPackageResultDataSigned_to_outcome( EuiccPackageResultDataSigned ); _ -> [{[{euiccPackageErrorCode, counterValueMismatch}]}] end; _ -> [{[{procedureError, euiccSignatureInvalid}]}] end; {euiccPackageErrorSigned, EuiccPackageErrorSigned} -> case crypto_utils:verify_euiccPackageErrorSigned(EuiccPackageErrorSigned, EidValue) of ok -> EuiccPackageErrorDataSigned = maps:get( euiccPackageErrorDataSigned, EuiccPackageErrorSigned ), EuiccPackageErrorCode = maps:get( euiccPackageErrorCode, EuiccPackageErrorDataSigned ), case CheckCounterValue(EuiccPackageErrorDataSigned) of ok -> [{[{euiccPackageErrorCode, EuiccPackageErrorCode}]}]; _ -> [{[{euiccPackageErrorCode, counterValueMismatch}]}] end; _ -> [{[{procedureError, euiccSignatureInvalid}]}] end; {euiccPackageErrorUnsigned, _} -> [{[{euiccPackageErrorCode, undefinedError}]}] end, mnesia_db_work:finish(Pid, Outcome, Debuginfo). % Handle an IpaEuiccDataResponse, this includes everything from the handling of the work items in mnesia_db as well % as the generation of an appropriate outcome for the REST API. In case IpaEuiccDataResponse contains an eUICC public % key, we will automatically store it so that we can use it to check the signatures of PSMOs and eCOs. handle_ipaEuiccDataResponse(Pid, IpaEuiccDataResponse, Debuginfo) -> EimTransactionId = eimTransactionId_from_ipaEuiccDataResponse(IpaEuiccDataResponse), {EidValue, _, _} = mnesia_db_work:pickup(Pid, EimTransactionId), % drive-by store the eUICC public key so that we can use it later to check the signatures of PSMOs or eCOs crypto_utils:store_euicc_pubkey_from_ipaEuiccDataResponse(IpaEuiccDataResponse, EidValue), Outcome = esipa_rest_utils:ipaEuiccDataResponse_to_outcome(IpaEuiccDataResponse), mnesia_db_work:finish(Pid, Outcome, Debuginfo). % Handle an EimPackageResultResponseError, this includes handling of the work items in mnesia_db and the generation of % an appropriate REST outcome for the REST API. handle_eimPackageResultResponseError(Pid, EimPackageResultResponseError, Debuginfo) -> EimTransactionId = maps:get(eimTransactionId, EimPackageResultResponseError), {_, _, _} = mnesia_db_work:pickup(Pid, EimTransactionId), EimPackageResultErrorCode = maps:get(eimPackageResultErrorCode, EimPackageResultResponseError), Outcome = [{[{eimPackageError, EimPackageResultErrorCode}]}], mnesia_db_work:finish(Pid, Outcome, Debuginfo).