/* SM-DP+ testsuite in TTCN-3
 * Implemented parts conform to sgp 23 v1.13-v1.15
 *
 * Author: Eric Wild <ewild@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 smdpp_Tests {

import from Misc_Helpers all;
import from General_Types all;
import from Osmocom_Types all;
import from Native_Functions 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 es12_Types_JSON all;
import from es9p_Types_JSON all;
import from es2p_Types_JSON all;
import from esx_header_Types_JSON all;
import from ES2Plus_Tests all;

/* The external function ext_RSPClient_create requires a path and a name filter as input to load test certificates.
 * While those certificates are required for the ES9+ interface related tests (smdpp_Tests.ttcn), for the ES2+
 * interface tests those certificates have no relevance. */
const charstring c_es2plus_cert_path := "./sgp26/";
const charstring c_es2plus_cert_name_filter := "NIST";

/* Module Parameters */
modulepar {
    /* The SMDP server host name (FQDN) must match the host name of the SSL certificate of the server. To resolve the
     * server host name to an IP address, an entry in /etc/hosts is sufficient. It should also be pointed out that this
     * testsuite (libcurl) will also verify the presented server certificate against the related CA. To ensure that
     * the server certificate verification is possible, ensure that the related CA certificates are made available in
     * /etc/ssl/certs */
    charstring mp_es2plus_server_fqdn := "testsmdpplus1.example.com";

    /* Sets the server port of the ES2+ server (SM-DP+). */
    integer mp_es2plus_server_port := 8000;

    /* Sets the client certificate to be used to authenticate towards the ES2+ server (SM-DP+) */
    charstring mp_es2plus_client_cert_path := "./test_certs/CERT_MNO_ECDSA_NIST.pem";

    /* Sets the private key to be used to authenticate towards the ES2+ server (SM-DP+) */
    charstring mp_es2plus_client_key_path := "./test_certs/SK_MNO_ECDSA_NIST.pem";

    /* Sets the operator ID to be used on the ES2+ interface. (this parameter has no relation to SSL/TLS) */
    charstring mp_es2plus_operator_id := "test.operator.com";

    /* ES2+ normally uses SSL with client authentication, however for debug purposes it is possible to disable
     * mutual authentication. */
    boolean mp_es2plus_use_mutual_tls := true;

    /* Sets the server port of the ES9+ server (SM-DP+, NIST certificates) */
    integer mp_es9plus_server_port_nist := 8000;

    /* Sets the server port of the ES9+ server (SM-DP+, Brainpool certificates) */
    integer mp_es9plus_server_port_brp := 8001;
}

/* C++ handles only crypto, TTCN-3 handles ASN.1 encoding/decoding most of the time */

/* RSP Client Management */
external function ext_RSPClient_create(charstring serverUrl, integer serverPort,
                                      charstring certPath, charstring nameFilter) return integer;

external function ext_RSPClient_destroy(integer clientHandle) return integer;

external function ext_RSPClient_loadEUICCCertificate(integer clientHandle,
                                                    charstring euiccCertPath) return integer;

external function ext_RSPClient_loadEUICCKeyPair(integer clientHandle,
                                                charstring euiccPrivateKeyPath) return integer;

external function ext_RSPClient_loadEUMCertificate(integer clientHandle,
                                                  charstring eumCertPath) return integer;

external function ext_RSPClient_getEUMCertificate(integer clientHandle) return octetstring;

external function ext_RSPClient_getEUICCCertificate(integer clientHandle) return octetstring;

external function ext_RSPClient_getCICertificate(integer clientHandle) return octetstring;

external function ext_RSPClient_generateChallenge(integer clientHandle) return octetstring;

external function ext_RSPClient_signDataWithEUICC(integer clientHandle, octetstring dataToSign) return octetstring;

external function ext_RSPClient_verifyServerSignature(integer clientHandle, octetstring signedData,
                                          octetstring xsignature, octetstring serverCert) return boolean;

external function ext_RSPClient_generateEUICCOtpk(integer clientHandle) return octetstring;


external function ext_CertificateUtil_getEID(octetstring certData)return charstring;

external function ext_CertificateUtil_validateEIDRange(charstring eid, octetstring eumCertData)return boolean;

external function ext_CertificateUtil_hasRSPRole(octetstring certData, charstring roleOid) return boolean;

external function ext_CertificateUtil_getPermittedEINs(octetstring eumCertData) return charstring;

external function ext_CertificateUtil_verifyECDHCompatible(octetstring pubKey1, octetstring pubKey2) return boolean;

external function ext_CertificateUtil_verifyCertificateChainDynamic(octetstring cert,
                                                        charstring certPoolDir,
                                                         octetstring rootCA) return boolean;

external function ext_CertificateUtil_verifyCertificateChainWithIntermediate(octetstring cert,
                                                        octetstring intermediateCert,
                                                        octetstring rootCA) return boolean;

external function ext_RSPClient_getEUICCOtpk(integer clientHandle) return octetstring;

external function ext_RSPClient_computeSharedSecret(integer clientHandle, octetstring otherPublicKey) return octetstring;

external function ext_CertificateUtil_getCurveOID(octetstring certData) return charstring;

external function ext_RSPClient_setConfirmationCode(integer clientHandle,
                                                    charstring confirmationCode) return integer;

external function ext_RSPClient_setTransactionId(integer clientHandle,
                                                octetstring transactionId) return integer;

external function ext_RSPClient_getConfirmationCodeHash(integer clientHandle) return octetstring;

/* Utility Functions */
private function ext_base64Encode(octetstring data) return charstring  {return encode_base64(data)}
private function ext_base64Decode(charstring data) return octetstring {return decode_base64(data)}

private function ext_hexToBytes(charstring  data) return octetstring  {return hex2oct(str2hex(data))}
private function ext_bytesToHex(octetstring data) return charstring  {return hex2str(oct2hex(data))}

/* Logging */
external function ext_logInfo(charstring xmessage);
external function ext_logError(charstring xmessage);
external function ext_logDebug(charstring xmessage);

/* BSP Crypto Processing */
type record ProcessedBoundProfilePackage {
    octetstring configureIsdp,
    octetstring storeMetadata,
    boolean hasReplaceSessionKeys,
    octetstring profileData,
    octetstring ppkEnc optional,
    octetstring ppkMac optional,
    octetstring ppkInitialMCV optional
}

/* Parameters for AuthenticateClient success test cases */
type record AuthClientSuccessTestParams {
    charstring testName,
    charstring stepDescription,
    charstring matchingId optional,     /* omit for empty/null matchingId */
    boolean expectCcRequired optional,   /* omit if no CC validation needed */
    charstring successMessage
}

/* Parameters for AuthenticateClient error test cases */
type record AuthClientErrorTestParams {
    charstring testName,
    charstring stepDescription,
    charstring matchingId optional,
    octetstring transactionIdOverride optional,  /* For error injection */
    charstring expectedSubjectCode,
    charstring expectedReasonCode,
    charstring errorDescription
}

/* Unified parameters for AuthenticateClient test cases */
type record AuthClientTestParams {
    charstring testName,
    charstring stepDescription,
    charstring matchingId optional,
    octetstring transactionIdOverride optional,  /* For error injection */
    boolean expectError,
    /* Success case fields */
    boolean expectCcRequired optional,
    charstring successMessage optional,
    /* Error case fields */
    charstring expectedSubjectCode optional,
    charstring expectedReasonCode optional,
    charstring errorDescription optional
}

/* Test modes for GetBoundProfilePackage */
type enumerated GetBPPTestMode {
    BPP_NOMINAL,
    BPP_RETRY_SAME_OTPK,
    BPP_RETRY_DIFFERENT_OTPK,
    BPP_PREPARATION_ERROR,
    BPP_PPK_NO_CC,
    BPP_PPK_WITH_CC,
    BPP_PPK_METADATA_SPLIT
}

/* Retry OTPK handling modes */
type enumerated RetryOTPKMode {
    RETRY_REUSE_SAME_OTPK,      /* Reuse the same eUICC OTPK */
    RETRY_SEND_NEW_OTPK,        /* Send new eUICC OTPK (expect rejection) */
    RETRY_OMIT_OTPK             /* Omit eUICC OTPK (force server to generate new) */
}

/* Cancel session reason codes per SGP.22 */
type enumerated CancelSessionReason {
    CSR_END_USER_REJECTION (0),     /* End user rejected */
    CSR_END_USER_POSTPONED (1),     /* End user postponed */
    CSR_TIMEOUT (2),                /* Timeout occurred */
    CSR_PPR_NOT_ALLOWED (3),        /* PPR not allowed */
    CSR_METADATA_MISMATCH (4),      /* Metadata mismatch */
    CSR_LOAD_BPP_ERROR (5),         /* Load BPP execution error */
    CSR_UNDEFINED_REASON (127)      /* Undefined reason */
}

/* Parameters for GetBoundProfilePackage test cases */
type record GetBPPTestParams {
    charstring testName,
    GetBPPTestMode testMode,
    integer prepErrorCode optional  /* For BPP_PREPARATION_ERROR mode */
}

external function ext_BSP_processBoundProfilePackage(
    octetstring sharedSecret,
    integer keyType,
    integer keyLength,
    octetstring hostId,
    charstring eid,
    octetstring encodedBoundProfilePackage
) return ProcessedBoundProfilePackage;

/* HTTP Client Functions */
external function ext_RSPClient_sendHttpsPost(
    integer clientHandle,
    charstring endpoint,
    charstring body,
    integer dport,
    out integer statusCode
) return charstring;

external function ext_RSPClient_configureHttpClient(
    integer clientHandle,
    boolean useCustomTlsCert,
    charstring customTlsCertPath
) return integer;

external function ext_RSPClient_setAuthParams(
    integer clientHandle,
    boolean useMutualTLS,
    charstring clientCertPath,
    charstring clientKeyPath
) return integer;

external function ext_RSPClient_sendHttpsPostWithAuth(
    integer clientHandle,
    charstring endpoint,
    charstring body,
    integer dport,
    out integer statusCode
) return charstring;

external function ext_RSPClient_sendHttpsPostWithContentType(
    integer clientHandle,
    charstring endpoint,
    charstring body,
    integer dport,
    charstring contentType,
    out integer statusCode
) return charstring;

external function ext_RSPClient_sendHttpsPostBinary(
    integer clientHandle,
    charstring endpoint,
    octetstring body,
    integer dport,
    charstring contentType,
    out integer statusCode
) return octetstring;

/* RSP Protocol Constants */
const charstring c_oid_rspRole_dp_auth := "2.23.146.1.2.1.4";
const charstring c_oid_rspRole_dp_pb := "2.23.146.1.2.1.5";

/* Protocol Operation IDs */
const integer c_remoteOpId_installBoundProfilePackage := 1;

/* Cryptographic Constants */
const octetstring c_keyType_AES := '88'O;
const octetstring c_keyLen_16bytes := '10'O;
const octetstring c_ecPoint_uncompressed := '04'O;

/* Validation Limits */
const integer c_hostId_min_length := 4;
const integer c_hostId_max_length := 16;
const integer c_min_segment_length := 2;

// ensure canonical DER encoding, using a width 4 bitstring here leads to violations
const NotificationEvent c_notificationInstall := '1'B;  // Bit 0
const NotificationEvent c_notificationEnable := '10'B;   // Bit 1
const NotificationEvent c_notificationDisable := '100'B;  // Bit 2
const NotificationEvent c_notificationDelete := '1000'B;   // Bit 3

/* Error injection types for AuthenticateClient testing */
type union AuthClientErrorInjection {
    CertificateError cert_error,
    SignatureError sig_error,
    TransactionIdError trans_error,
    ServerChallengeError challenge_error,
    ContextParamError ctx_error
}

type record CertificateError {
    CertErrorType error_type,
    charstring cert_path optional
}

type enumerated CertErrorType {
    INVALID_EUM_SIGNATURE,
    INVALID_EUM_KEY_USAGE,
    EXPIRED_EUM,
    INVALID_EUICC_SIGNATURE,
    EXPIRED_EUICC,
    UNKNOWN_CI_KEY
}

type record SignatureError {
    boolean corrupt_signature
}

type record TransactionIdError {
    boolean in_json,  // true = error in JSON, false = error in ASN.1
    octetstring wrong_transaction_id optional
}

type record ServerChallengeError {
    octetstring wrong_challenge optional
}

type record ContextParamError {
    charstring wrong_matching_id optional,
    boolean omit_matching_id
}

/* Error injection types for GetBoundProfilePackage testing */
type union GetBppErrorInjection {
    SignatureError sig_error,
    TransactionIdError trans_error,
    ConfirmationCodeError cc_error
}

type record ConfirmationCodeError {
    boolean omit_cc,          /* true = omit confirmation code when required */
    boolean wrong_cc,         /* true = send wrong confirmation code */
    octetstring invalid_cc optional  /* specific wrong CC to use */
}

/* TTCN-3 COMPONENT TYPES */

type component MTC_CT {
	timer g_Tguard;
};

type component smdpp_ConnHdlr {
	var smdpp_ConnHdlrPars g_pars_smdpp;
	var template integer g_http_client_id_es9p := omit;
	var template integer g_http_client_id_es2p := omit;

	/* C++ RSP client handle */
	var integer g_rsp_client_handle_es9p := -1;
	var integer g_rsp_client_handle_es2p := -1;

	/* Session state */
	var octetstring g_transactionId := ''O;
	var octetstring g_euiccChallenge := ''O;
	var octetstring g_serverChallenge := ''O;
	var octetstring g_serverCert := ''O;
	var boolean g_authenticationComplete := false;

	/* HTTP Client state for new approach */
	var charstring g_last_es9p_endpoint := "";
	var charstring g_last_es9p_request := "";
};

type enumerated ES9EncodingMode {
	ES9_JSON,
	ES9_ASN1
}

type record smdpp_ConnHdlrPars {
	charstring smdp_server_fqdn,
	integer smdp_es9p_server_port,
	integer smdp_es2p_server_port,
	charstring cert_path,
	charstring cert_name_filter,
	charstring euicc_cert_path,
	charstring euicc_key_path,
	charstring confirmation_code optional,
	AuthClientErrorInjection err_injection optional,
	charstring test_name optional,
	charstring expected_subject_code optional,
	charstring expected_reason_code optional,
	GetBppErrorInjection gbpp_err_injection optional,
	boolean cc_required optional,
	boolean use_ppk optional,
	integer metadata_segments optional,
	ES9EncodingMode es9_encoding_mode optional
};

private function f_init_pars(boolean brainpool := false) runs on MTC_CT return smdpp_ConnHdlrPars {
	var smdpp_ConnHdlrPars pars := {
		/* Unfortunately the SMDP server FQDN cannot be made configurable via a module parameter since it always
		 * to match the FQDN in the test SSL certificates. To resolve the server FQDN to an IP address, an entry
		 * in /etc/hosts is sufficient. It should also be pointed out that this testsuite (libcurl) will also
		 * verify the presented server certificate against the related CA. To ensure that the server certificate
		 * verification is possible, ensure that the related CA certificates are made available in
		 * /etc/ssl/certs */
		smdp_server_fqdn := "testsmdpplus1.example.com",
		smdp_es2p_server_port := mp_es2plus_server_port,
		cert_path := "./sgp26/CertificateIssuer",
		confirmation_code := omit,  // No confirmation code by default
		err_injection := omit,
		test_name := omit,
		expected_subject_code := omit,
		expected_reason_code := omit,
		gbpp_err_injection := omit,
		cc_required := false,
		use_ppk := false,
		metadata_segments := 1,
		es9_encoding_mode := omit  /* Default to JSON mode */
	};

	/* GSMA SGP.22 specifies two different certificate curves, which require different default parameters */
	if (brainpool) {
		pars.smdp_es9p_server_port := mp_es9plus_server_port_brp;
		pars.cert_name_filter := "BRP";
		pars.euicc_cert_path := "./sgp26/eUICC/CERT_EUICC_ECDSA_BRP.der";
		pars.euicc_key_path := "./sgp26/eUICC/SK_EUICC_ECDSA_BRP.pem";
	} else {
		pars.smdp_es9p_server_port := mp_es9plus_server_port_nist;
		pars.cert_name_filter := "NIST";
		pars.euicc_cert_path := "./sgp26/eUICC/CERT_EUICC_ECDSA_NIST.der";
		pars.euicc_key_path := "./sgp26/eUICC/SK_EUICC_ECDSA_NIST.pem";
	}

	return pars;
}

private altstep as_Tguard() runs on MTC_CT {
	[] g_Tguard.timeout {
		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout");
	}
}

type function void_fn(charstring id) runs on smdpp_ConnHdlr;

private function f_init_handler(void_fn fn, charstring id, smdpp_ConnHdlrPars pars) runs on smdpp_ConnHdlr {
	g_pars_smdpp := pars;
	fn.apply(id);
}

private function f_start_handler(void_fn fn, smdpp_ConnHdlrPars pars)
runs on MTC_CT return smdpp_ConnHdlr {
	var smdpp_ConnHdlr vc_conn;
	var charstring id := testcasename();

	vc_conn := smdpp_ConnHdlr.create(id);


	vc_conn.start(f_init_handler(fn, id, pars));
	return vc_conn;
}

private function f_init(charstring id, float t_guard := 60.0) runs on MTC_CT {
	g_Tguard.start(t_guard);
	activate(as_Tguard());

}

/* RSP CLIENT WRAPPER FUNCTIONS */

// Initialize RSP client for ES2+
function f_init_es2plus() runs on smdpp_ConnHdlr {
    // Initialize RSP client using imported function from smdpp_Tests
    g_rsp_client_handle_es2p := smdpp_Tests.ext_RSPClient_create(
        mp_es2plus_server_fqdn,
        mp_es2plus_server_port,
	c_es2plus_cert_path,
	c_es2plus_cert_name_filter
    );

    if (g_rsp_client_handle_es2p < 0) {
        setverdict(fail, "Failed to initialize RSP client for ES2+");
        mtc.stop;
    }

    // Set authentication parameters once for all ES2+ operations
    var integer result := smdpp_Tests.ext_RSPClient_setAuthParams(
        g_rsp_client_handle_es2p,
        mp_es2plus_use_mutual_tls,
        mp_es2plus_client_cert_path,
        mp_es2plus_client_key_path
    );

    if (result != 0) {
        setverdict(fail, "Failed to set RSP client authentication parameters for ES2+");
        mtc.stop;
    }

    ext_logInfo("HTTP client (ES2+) configured");
}

// Initialize RSP client for ES9+
private function f_init_es9plus() runs on smdpp_ConnHdlr {
	ext_logInfo("Initializing RSP client");

	g_rsp_client_handle_es9p := ext_RSPClient_create(
		g_pars_smdpp.smdp_server_fqdn,
		g_pars_smdpp.smdp_es9p_server_port,
		g_pars_smdpp.cert_path,
		g_pars_smdpp.cert_name_filter
	);

	if (g_rsp_client_handle_es9p < 0) {
	        setverdict(fail, "Failed to initialize RSP client for ES9+");
		mtc.stop;
	}

	if (ext_RSPClient_loadEUICCCertificate(g_rsp_client_handle_es9p, g_pars_smdpp.euicc_cert_path) != 0) {
		ext_logError("Failed to load eUICC certificate for ES9+");
		f_rsp_client_cleanup();
		mtc.stop;
	}

	if (ext_RSPClient_loadEUICCKeyPair(g_rsp_client_handle_es9p, g_pars_smdpp.euicc_key_path) != 0) {
		ext_logError("Failed to load eUICC private key for ES9+");
		f_rsp_client_cleanup();
		mtc.stop;
	}

	// Configure HTTP client
	// The native rspclient cpp code (libcurl) recursively loads certs from the subdir (sgp26) and
	// automatically uses self signed certificates as root certificate.
	var integer result := ext_RSPClient_configureHttpClient(
		g_rsp_client_handle_es9p,
		true, // enable the usage of use custom TLS certificates
		"" // provede an empty certificate path, this means that the certificate pool is used.
	);

	if (result != 0) {
		ext_logError("Failed to configure HTTP client");
		f_rsp_client_cleanup();
		mtc.stop;
	}

	ext_logInfo("HTTP client (ES9+) configured");
}

private function f_rsp_client_cleanup() runs on smdpp_ConnHdlr {
	if (g_rsp_client_handle_es9p >= 0) {
		ext_RSPClient_destroy(g_rsp_client_handle_es9p);
		g_rsp_client_handle_es9p := -1;
	}
	if (g_rsp_client_handle_es2p >= 0) {
		ext_RSPClient_destroy(g_rsp_client_handle_es2p);
		g_rsp_client_handle_es2p := -1;
	}
}

/* HELPER FUNCTIONS FOR ES2+ DYNAMIC PROFILE PROVISIONING */

// Main ES2+ provisioning function - provisions a profile dynamically via ES2+
private function f_provision_profile_via_es2plus(
    charstring eid := "89049032123451234512345678901235",
    boolean with_confirmation_code := false,
    charstring profile_type := "Test",
    boolean release_flag := true
) runs on smdpp_ConnHdlr return charstring {

    // ES2+ constants
    const charstring c_es2plus_base_path := "/gsma/rsp2/es2plus";
    const charstring c_path_download_order := c_es2plus_base_path & "/downloadOrder";
    const charstring c_path_confirm_order := c_es2plus_base_path & "/confirmOrder";
    const charstring c_cert_path := "./test_certs/CERT_MNO_ECDSA_NIST.pem";
    const charstring c_key_path := "./test_certs/SK_MNO_ECDSA_NIST.pem";

    // Generate unique function call identifier
    var octetstring rnd_oct := f_rnd_octstring(4);
    var charstring func_call_id := "TTCN3-" & oct2str(rnd_oct);

    var integer result := smdpp_Tests.ext_RSPClient_setAuthParams(
        g_rsp_client_handle_es9p,
        true,  // useMutualTLS
        c_cert_path,
        c_key_path
    );

    if (result != 0) {
        setverdict(fail, "Failed to set authentication parameters");
        mtc.stop;
    }

    // Step 1: DownloadOrder to reserve ICCID
    var JSON_ES2p_Request dl_req := {
        downloadOrderRequest := {
            header := {
                functionRequesterIdentifier := mp_es2plus_operator_id,
                functionCallIdentifier := func_call_id & "-DL"
            },
            eid := eid,
            iccid := omit,
            profileType := profile_type
        }
    };

    var octetstring req_enc := enc_JSON_ES2p_Request(dl_req);
    var integer status_code;
    var charstring response := ext_RSPClient_sendHttpsPostWithAuth(
        g_rsp_client_handle_es2p,
        c_path_download_order,
        oct2char(req_enc),
        g_pars_smdpp.smdp_es2p_server_port,
        status_code
    );

    if (status_code != 200) {
        ext_logError("ES2+ DownloadOrder failed with status: " & int2str(status_code));
        return "";
    }

    var JSON_ES2p_Response dl_resp := dec_JSON_ES2p_Response(char2oct(response), "downloadOrder");
    if (dl_resp.downloadOrderResponse.header.functionExecutionStatus.status != "Executed-Success") {
        ext_logError("ES2+ DownloadOrder returned error");
        return "";
    }

    var charstring new_iccid := dl_resp.downloadOrderResponse.iccid;
    ext_logInfo("ES2+ provisioned ICCID: " & new_iccid);

    // Step 2: ConfirmOrder to create profile with matchingId
    var JSON_ES2p_Request conf_req := {
        confirmOrderRequest := {
            header := {
                functionRequesterIdentifier := mp_es2plus_operator_id,
                functionCallIdentifier := func_call_id & "-CF"
            },
            iccid := new_iccid,
            eid := omit,
            matchingId := omit,  // Let server generate
            confirmationCode :=  omit,
            smdsAddress := omit,
            releaseFlag := release_flag
        }
    };

    if (with_confirmation_code) {
        conf_req.confirmOrderRequest.confirmationCode := "12345678";
    }

    req_enc := enc_JSON_ES2p_Request(conf_req);
    response := ext_RSPClient_sendHttpsPostWithAuth(
        g_rsp_client_handle_es2p,
        c_path_confirm_order,
        oct2char(req_enc),
        g_pars_smdpp.smdp_es2p_server_port,
        status_code
    );

    if (status_code != 200) {
        ext_logError("ES2+ ConfirmOrder failed with status: " & int2str(status_code));
        return "";
    }

    var JSON_ES2p_Response conf_resp := dec_JSON_ES2p_Response(char2oct(response), "confirmOrder");
    if (conf_resp.confirmOrderResponse.header.functionExecutionStatus.status != "Executed-Success") {
        ext_logError("ES2+ ConfirmOrder returned error");
        return "";
    }

    var charstring matching_id := conf_resp.confirmOrderResponse.matchingId;
    ext_logInfo("ES2+ provisioned profile with matchingId: " & matching_id);

    // Store confirmation code if requested
    if (with_confirmation_code) {
        ext_logInfo("Profile provisioned with confirmation code required");
    }

    return matching_id;
}

// Simplified variant for basic profile provisioning
private function f_provision_simple_profile() runs on smdpp_ConnHdlr return charstring {
    return f_provision_profile_via_es2plus();
}

// Variant for profile with confirmation code
private function f_provision_profile_with_cc(charstring eid := "89049032123451234512345678901235") runs on smdpp_ConnHdlr return charstring {
    return f_provision_profile_via_es2plus(eid, true);
}

/* HELPER FUNCTIONS FOR CERTIFICATE PKID MANAGEMENT */
private function f_get_ci_pkids_list() runs on smdpp_ConnHdlr return RSPDefinitions.EUICCInfo2.euiccCiPKIdListForVerification {
	if (g_pars_smdpp.cert_name_filter == "BRP") {
		/* BRP CI certificate PKID */
		return { ext_hexToBytes("C0BC70BA36929D43B467FF57570530E57AB8FCD8") };
	} else {
		/* NIST CI certificate PKIDs */
		return {
			ext_hexToBytes("F54172BDF98A95D65CBEB88A38A1C11D800A85C3"),
			ext_hexToBytes("EE1F7178B70C23826CDCEA7BD28CEAB1874F552D")
		};
	}
}

/* Get CI PKIDs for verification based on certificate type */
private function f_get_ci_pkids_for_verification() runs on smdpp_ConnHdlr return RSPDefinitions.EUICCInfo2.euiccCiPKIdListForVerification {
	return f_get_ci_pkids_list();
}

/* Get CI PKIDs for signing based on certificate type */
private function f_get_ci_pkids_for_signing() runs on smdpp_ConnHdlr return RSPDefinitions.EUICCInfo1.euiccCiPKIdListForSigning {
	/* Currently same as verification PKIDs - rely on implicit type conversion */
	return f_get_ci_pkids_list();
}

/* RSP PROTOCOL IMPLEMENTATION */

/* SGP.22 version constant */
const octetstring c_SGP22_VERSION := '020200'O;  /* SGP.22 v2.2.0 */

private function f_create_initiate_authentication_request() runs on smdpp_ConnHdlr
return RemoteProfileProvisioningRequest {

	g_euiccChallenge := ext_RSPClient_generateChallenge(g_rsp_client_handle_es9p);
	ext_logInfo("Generated eUICC challenge: " & ext_bytesToHex(g_euiccChallenge));

	/* Create EUICC_INFO1 using TTCN-3 native types */
	var EUICCInfo1 euiccInfo1 := {
		svn := c_SGP22_VERSION,
		euiccCiPKIdListForVerification := f_get_ci_pkids_for_verification(),
		euiccCiPKIdListForSigning := f_get_ci_pkids_for_signing()
	};

	/* Create the request structure */
	var RemoteProfileProvisioningRequest request := {
		initiateAuthenticationRequest := {
			euiccChallenge := g_euiccChallenge,
			smdpAddress := g_pars_smdpp.smdp_server_fqdn,
			euiccInfo1 := euiccInfo1
		}
	};

	return request;
}

private function f_validate_initiate_authentication_response(RemoteProfileProvisioningResponse response)
runs on smdpp_ConnHdlr return boolean {

	if (not ispresent(response.initiateAuthenticationResponse)) {
		ext_logError("No initiateAuthenticationResponse in response");
		return false;
	}

	if (not ispresent(response.initiateAuthenticationResponse.initiateAuthenticationOk)) {
		ext_logError("Authentication failed - no OK response");
		return false;
	}

	var InitiateAuthenticationOkEs9 authOk := response.initiateAuthenticationResponse.initiateAuthenticationOk;

	/* Store session data */
	g_transactionId := authOk.transactionId;
	g_serverCert := enc_Certificate(authOk.serverCertificate);
	g_serverChallenge := authOk.serverSigned1.serverChallenge;

	ext_logInfo("Received transaction ID: " & ext_bytesToHex(g_transactionId));

	if (authOk.serverSigned1.transactionId != g_transactionId) {
		ext_logError("Transaction ID mismatch");
		return false;
	}

	if (authOk.serverSigned1.euiccChallenge != g_euiccChallenge) {
		ext_logError("eUICC challenge mismatch");
		return false;
	}

	if (not ext_RSPClient_verifyServerSignature(g_rsp_client_handle_es9p, enc_ServerSigned1(authOk.serverSigned1), authOk.serverSignature1, g_serverCert)) {
		ext_logError("Server signature validation failed");
		return false;
	}

	ext_logInfo("Authentication response validation successful");
	g_authenticationComplete := true;
	return true;
}

private function f_initiate_authentication_and_validate()
runs on smdpp_ConnHdlr return InitiateAuthenticationOkEs9 {
	ext_logInfo("Step: InitiateAuthentication");
	var RemoteProfileProvisioningRequest initReq := f_create_initiate_authentication_request();
	var RemoteProfileProvisioningResponse initResp := f_es9p_transceive_success(initReq);

	if (not f_validate_initiate_authentication_response(initResp)) {
		setverdict(fail, "InitiateAuthentication validation failed");
		f_rsp_client_cleanup();
		f_shutdown(__FILE__, __LINE__);
	}

	return initResp.initiateAuthenticationResponse.initiateAuthenticationOk;
}

private function f_create_get_bound_profile_package_request(octetstring smdpSignature2) runs on smdpp_ConnHdlr
return RemoteProfileProvisioningRequest {

	var octetstring euiccOtpk := ext_RSPClient_generateEUICCOtpk(g_rsp_client_handle_es9p);

	var EUICCSigned2 euiccSigned2 := {
		transactionId := g_transactionId,
		euiccOtpk := euiccOtpk,
		hashCc := omit
	};

	// Add confirmation code hash if required
	var octetstring ccHash := ext_RSPClient_getConfirmationCodeHash(g_rsp_client_handle_es9p);
	ext_logInfo("Checking confirmation code hash, length: " & int2str(lengthof(ccHash)));
	if (lengthof(ccHash) == 32) {
		euiccSigned2.hashCc := ccHash;
		ext_logInfo("Added confirmation code hash to PrepareDownloadRequest: " & oct2str(ccHash));
	} else if (lengthof(ccHash) > 0) {
		ext_logError("Invalid confirmation code hash length: " & int2str(lengthof(ccHash)));
	} else {
		ext_logInfo("No confirmation code hash available");
	}

	var octetstring euiccSigned2Data := enc_EUICCSigned2(euiccSigned2);
	var octetstring concatdata := euiccSigned2Data & smdpSignature2;
	var octetstring euiccSignature2 := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, concatdata);

	var PrepareDownloadResponse prepareDownloadResponse := {
		downloadResponseOk := {
			euiccSigned2 := euiccSigned2,
			euiccSignature2 := euiccSignature2
		}
	};

	var RemoteProfileProvisioningRequest request := {
		getBoundProfilePackageRequest := {
			transactionId := g_transactionId,
			prepareDownloadResponse := prepareDownloadResponse
		}
	};

	ext_logInfo("Created getBoundProfilePackage request");
	return request;
}

private function f_create_prepare_download_response_with_otpk(octetstring smdpSignature2, octetstring euicc_otpk) runs on smdpp_ConnHdlr return PrepareDownloadResponse {
	var EUICCSigned2 euiccSigned2 := {
		transactionId := g_transactionId,
		euiccOtpk := euicc_otpk,
		hashCc := omit  /* No confirmation code for nominal case */
	};

	var octetstring ccHash := ext_RSPClient_getConfirmationCodeHash(g_rsp_client_handle_es9p);
	if (lengthof(ccHash) == 32) {
		euiccSigned2.hashCc := ccHash;
		ext_logInfo("Added confirmation code hash to PrepareDownloadResponse: " & oct2str(ccHash));
	} else if (lengthof(ccHash) > 0) {
		ext_logError("Invalid confirmation code hash length: " & int2str(lengthof(ccHash)));
	}

	var octetstring euiccSigned2_raw := enc_EUICCSigned2(euiccSigned2);
	var octetstring concatdata := euiccSigned2_raw & smdpSignature2;
	var octetstring euiccSignature2 := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, concatdata);

	var PrepareDownloadResponse prepareDownloadResponse := {
		downloadResponseOk := {
			euiccSigned2 := euiccSigned2,
			euiccSignature2 := euiccSignature2
		}
	};

	return prepareDownloadResponse;
}

private function f_validate_get_bound_profile_package_response(RemoteProfileProvisioningResponse response)
runs on smdpp_ConnHdlr return boolean {

	if (not ispresent(response.getBoundProfilePackageResponse)) {
		ext_logError("No getBoundProfilePackageResponse in response");
		return false;
	}

	if (not ispresent(response.getBoundProfilePackageResponse.getBoundProfilePackageOk)) {
		ext_logError("getBoundProfilePackage failed - no OK response");
		return false;
	}

	var GetBoundProfilePackageOk packageOk := response.getBoundProfilePackageResponse.getBoundProfilePackageOk;

	if (packageOk.transactionId != g_transactionId or packageOk.boundProfilePackage.initialiseSecureChannelRequest.transactionId != g_transactionId) {
		ext_logError("Transaction ID mismatch in getBoundProfilePackage response");
		return false;
	}

	if (not ispresent(packageOk.boundProfilePackage)) {
		ext_logError("No boundProfilePackage in response");
		return false;
	}

	var BoundProfilePackage boundPackage := packageOk.boundProfilePackage;

	if (not ispresent(boundPackage.initialiseSecureChannelRequest)) {
		ext_logError("Missing initialiseSecureChannelRequest");
		return false;
	}

	if (not ispresent(boundPackage.firstSequenceOf87)) {
		ext_logError("Missing firstSequenceOf87");
		return false;
	}

	if (not ispresent(boundPackage.sequenceOf88)) {
		ext_logError("Missing sequenceOf88");
		return false;
	}

	if (not ispresent(boundPackage.sequenceOf86)) {
		ext_logError("Missing sequenceOf86");
		return false;
	}

	ext_logInfo("getBoundProfilePackage response validation successful");
	return true;
}

/* HTTP */

private function f_es9p_send_new(RemoteProfileProvisioningRequest es9p_req) runs on smdpp_ConnHdlr {
	var charstring es9p_req_enc;
	var charstring es9p_url;

	if (ispresent(es9p_req.initiateAuthenticationRequest)) {
		es9p_url := "/gsma/rsp2/es9plus/initiateAuthentication";
	} else if (ispresent(es9p_req.getBoundProfilePackageRequest)) {
		es9p_url := "/gsma/rsp2/es9plus/getBoundProfilePackage";
	} else if (ispresent(es9p_req.authenticateClientRequest)) {
		es9p_url := "/gsma/rsp2/es9plus/authenticateClient";
	} else if (ispresent(es9p_req.handleNotification)) {
		es9p_url := "/gsma/rsp2/es9plus/handleNotification";
	} else if (ispresent(es9p_req.cancelSessionRequestEs9)) {
		es9p_url := "/gsma/rsp2/es9plus/cancelSession";
	} else {
		setverdict(fail, "unknown JSON ES9+ function");
		return;
	}

	enc_RemoteProfileProvisioningRequest_to_JSON(es9p_req, es9p_req_enc);

	// Store for use in receive function
	g_last_es9p_endpoint := es9p_url;
	g_last_es9p_request := es9p_req_enc;
}

private function f_es9p_receive_new(template RemoteProfileProvisioningResponse expected_es9p_res := omit)
runs on smdpp_ConnHdlr return template RemoteProfileProvisioningResponse {
	var DecodedRPPReponse_Wrap resp;
	var integer http_status;

	var charstring response_body := ext_RSPClient_sendHttpsPost(
		g_rsp_client_handle_es9p,
		g_last_es9p_endpoint,
		g_last_es9p_request,
        g_pars_smdpp.smdp_es9p_server_port,
		http_status
	);

	if (http_status != 200) {
		setverdict(fail, "HTTP error response: " & int2str(http_status));
		return omit;
	}

	if (lengthof(response_body) == 0) {
		setverdict(fail, "Empty HTTP response body");
		return omit;
	}

	dec_RemoteProfileProvisioningResponse_from_JSON(response_body, resp);
	var RemoteProfileProvisioningResponse es9p_res;
	es9p_res := resp.asn1_pdu;

	if (not istemplatekind(expected_es9p_res, "omit")) {
		if (not match(es9p_res, expected_es9p_res)) {
			setverdict(fail, "unexpected response from SM-DP+ on ES9+");
		}
	}

	if (isvalue(es9p_res)) {
		return es9p_res;
	}
	return omit;
}

/* Perform one HTTP request/response cycle */
private function f_es9p_client_transceive_new(RemoteProfileProvisioningRequest es9p_req,
					      template RemoteProfileProvisioningResponse expected_es9p_res := omit)
runs on smdpp_ConnHdlr return template RemoteProfileProvisioningResponse {
	var template RemoteProfileProvisioningResponse es9p_res;
	f_es9p_send_new(es9p_req);
	es9p_res := f_es9p_receive_new(expected_es9p_res);
	return es9p_res;
}

private function f_es9p_transceive_wrap(RemoteProfileProvisioningRequest request)
runs on smdpp_ConnHdlr
return DecodedRPPReponse_Wrap {

	var ES9EncodingMode encoding_mode := ES9_JSON;
	if (ispresent(g_pars_smdpp.es9_encoding_mode)) {
		encoding_mode := g_pars_smdpp.es9_encoding_mode;
	}

	if (encoding_mode == ES9_ASN1) {
		return f_es9p_transceive_wrap_asn1(request);
	} else {
		f_es9p_send_new(request);

		var integer http_status;
		var charstring response_body := ext_RSPClient_sendHttpsPost(
			g_rsp_client_handle_es9p,
			g_last_es9p_endpoint,
			g_last_es9p_request,
			g_pars_smdpp.smdp_es9p_server_port,
			http_status
		);

		if (http_status != 200) {
			setverdict(fail, "HTTP error response: " & int2str(http_status));
			var DecodedRPPReponse_Wrap empty_response;
			return empty_response;
		}

		// Decode to wrapper type that handles both success and error
		var DecodedRPPReponse_Wrap response := {omit, omit};
		dec_RemoteProfileProvisioningResponse_from_JSON(response_body, response);

		return response;
	}
}

/* Pure ASN.1 mode transceive function */
private function f_es9p_transceive_wrap_asn1(RemoteProfileProvisioningRequest request)
runs on smdpp_ConnHdlr
return DecodedRPPReponse_Wrap {
	/* Encode the request as pure ASN.1 (already includes A2 tag) */
	var octetstring asn1_request := enc_RemoteProfileProvisioningRequest(request);

	ext_logInfo("ASN.1 request size: " & int2str(lengthof(asn1_request)) & " bytes");
	ext_logInfo("ASN.1 request first 50 bytes: " & oct2str(substr(asn1_request, 0, 50)));
	ext_logInfo("ASN.1 request full: " & oct2str(asn1_request));

	var integer http_status;
	ext_logInfo("Sending ASN.1 request to /gsma/rsp2/asn1 on port " & int2str(g_pars_smdpp.smdp_es9p_server_port));
	var octetstring response_body := ext_RSPClient_sendHttpsPostBinary(
		g_rsp_client_handle_es9p,
		"/gsma/rsp2/asn1",
		asn1_request,
		g_pars_smdpp.smdp_es9p_server_port,
		"application/x-gsma-rsp-asn1",
		http_status
	);
	ext_logInfo("Received HTTP status: " & int2str(http_status));

	if (http_status != 200) {
		setverdict(fail, "HTTP error response: " & int2str(http_status));
		var DecodedRPPReponse_Wrap empty_response;
		return empty_response;
	}

	/* Decode pure ASN.1 response (already includes A3 tag) */
	var RemoteProfileProvisioningResponse asn1_response := dec_RemoteProfileProvisioningResponse(response_body);

	/* Convert to DecodedRPPReponse_Wrap format for compatibility */
	var DecodedRPPReponse_Wrap wrap := {omit, omit};

	/* ASN.1 errors are encoded as specific CHOICE values */
	if (f_is_asn1_error_response(asn1_response)) {
		ext_logInfo("ASN.1 response detected as error, converting...");
		wrap.err := f_convert_asn1_error_to_json(asn1_response);
		ext_logInfo("Converted error: subject=" & wrap.err.subjectCode & ", reason=" & wrap.err.reasonCode);
	} else {
		/* Success response */
		wrap.asn1_pdu := asn1_response;
	}

	return wrap;
}

/* Helper to check if ASN.1 response is an error */
private function f_is_asn1_error_response(RemoteProfileProvisioningResponse resp) return boolean {
	if (ischosen(resp.authenticateClientResponseEs9)) {
		ext_logInfo("Response has authenticateClientResponseEs9");
		/* AuthenticateClientResponseEs9 is a CHOICE between authenticateClientOk and authenticateClientError */
		if (ischosen(resp.authenticateClientResponseEs9.authenticateClientError)) {
			return true;
		}
	} else if (ischosen(resp.getBoundProfilePackageResponse)) {
		/* GetBoundProfilePackageResponse is a CHOICE between getBoundProfilePackageOk and getBoundProfilePackageError */
		if (ischosen(resp.getBoundProfilePackageResponse.getBoundProfilePackageError)) {
			return true;
		}
	} else if (ischosen(resp.initiateAuthenticationResponse)) {
		/* InitiateAuthenticationResponse is a CHOICE between initiateAuthenticationOk and initiateAuthenticationError */
		if (ischosen(resp.initiateAuthenticationResponse.initiateAuthenticationError)) {
			return true;
		}
	} else if (ischosen(resp.cancelSessionResponseEs9)) {
		/* CancelSessionResponseEs9 is a CHOICE between cancelSessionOk and cancelSessionError */
		if (ischosen(resp.cancelSessionResponseEs9.cancelSessionError)) {
			return true;
		}
	}
	return false;
}

/* Helper to convert ASN.1 error to JSON error format */
private function f_convert_asn1_error_to_json(RemoteProfileProvisioningResponse resp)
return JSON_ESx_FunctionExecutionStatusCodeData {
	var JSON_ESx_FunctionExecutionStatusCodeData err := {
		subjectCode := "",
		reasonCode := "",
		subjectIdentifier := omit,
		message_ := ""
	};

	if (ischosen(resp.authenticateClientResponseEs9)) {
		if (ischosen(resp.authenticateClientResponseEs9.authenticateClientError)) {
			var integer errorCode := resp.authenticateClientResponseEs9.authenticateClientError;
			/* Map AuthenticateClient error codes per SGP.22 */
			if (errorCode == 1) {  /* eumCertificateInvalid */
				err.subjectCode := "8.1.1";
				err.reasonCode := "3.1";
				err.message_ := "EUM Certificate Invalid";
			} else if (errorCode == 2) {  /* eumCertificateExpired */
				err.subjectCode := "8.1.1";
				err.reasonCode := "3.2";
				err.message_ := "EUM Certificate Expired";
			} else if (errorCode == 3) {  /* euiccCertificateInvalid */
				err.subjectCode := "8.1.2";
				err.reasonCode := "3.1";
				err.message_ := "eUICC Certificate Invalid";
			} else if (errorCode == 4) {  /* euiccCertificateExpired */
				err.subjectCode := "8.1.2";
				err.reasonCode := "3.2";
				err.message_ := "eUICC Certificate Expired";
			} else if (errorCode == 5) {  /* euiccSignatureInvalid */
				err.subjectCode := "8.1.3";
				err.reasonCode := "3.1";
				err.message_ := "eUICC Signature Invalid";
			} else if (errorCode == 8) {  /* matchingIdRefused */
				err.subjectCode := "8.2.6";
				err.reasonCode := "3.1";
				err.message_ := "Matching ID Refused";
			} else if (errorCode == 127) {  /* undefinedError */
				err.subjectCode := "8.8.1";
				err.reasonCode := "5";
				err.message_ := "Undefined Error";
			}
		}
	} else if (ischosen(resp.getBoundProfilePackageResponse)) {
		if (ischosen(resp.getBoundProfilePackageResponse.getBoundProfilePackageError)) {
			var integer errorCode := resp.getBoundProfilePackageResponse.getBoundProfilePackageError;
			/* Map GetBoundProfilePackage error codes */
			if (errorCode == 1) {  /* euiccSignatureInvalid */
				err.subjectCode := "8.1.3";
				err.reasonCode := "3.1";
				err.message_ := "eUICC Signature Invalid";
			} else if (errorCode == 2) {  /* confirmationCodeMissing */
				err.subjectCode := "8.2.7";
				err.reasonCode := "3.7";
				err.message_ := "Confirmation Code Missing";
			} else if (errorCode == 3) {  /* confirmationCodeRefused */
				err.subjectCode := "8.2.7";
				err.reasonCode := "3.8";
				err.message_ := "Confirmation Code Refused";
			} else if (errorCode == 127) {  /* undefinedError */
				err.subjectCode := "8.8.1";
				err.reasonCode := "5";
				err.message_ := "Undefined Error";
			}
		}
	}

	/* Fallback for undefined or empty errors, tbd */
	if (err.subjectCode == "" or err.reasonCode == "") {
		err.subjectCode := "8.8.1";
		err.reasonCode := "5";
		err.message_ := "Undefined Error (Server Internal Error)";
		ext_logInfo("Using fallback error codes for undefined error");
	}

	return err;
}

private function f_es9p_transceive_success(RemoteProfileProvisioningRequest request)
runs on smdpp_ConnHdlr
return RemoteProfileProvisioningResponse {
	var DecodedRPPReponse_Wrap wrap := f_es9p_transceive_wrap(request);

	if (ispresent(wrap.asn1_pdu)) {
		return wrap.asn1_pdu;
	} else if (ispresent(wrap.err)) {
		setverdict(fail, "Expected success but got error: ",
		           wrap.err.subjectCode, "/", wrap.err.reasonCode,
		           " - ", wrap.err.message_);
		f_shutdown(__FILE__, __LINE__);
	}

	setverdict(fail, "Invalid response - neither success nor error");
	f_shutdown(__FILE__, __LINE__);
	var RemoteProfileProvisioningResponse dummy;
	return dummy;
}

private function f_es9p_transceive_error(RemoteProfileProvisioningRequest request)
runs on smdpp_ConnHdlr
return JSON_ESx_FunctionExecutionStatusCodeData {
	var DecodedRPPReponse_Wrap wrap := f_es9p_transceive_wrap(request);

	if (ispresent(wrap.err)) {
		return wrap.err;
	} else if (ispresent(wrap.asn1_pdu)) {
		setverdict(fail, "Expected error but got success response");
		f_shutdown(__FILE__, __LINE__);
	}

	setverdict(fail, "Invalid response - neither success nor error");
	f_shutdown(__FILE__, __LINE__);
	var JSON_ESx_FunctionExecutionStatusCodeData dummy;
	return dummy;
}

private function f_validate_error_response(
	JSON_ESx_FunctionExecutionStatusCodeData actual_error,
	charstring expected_subject_code,
	charstring expected_reason_code,
	charstring test_description := ""
) runs on smdpp_ConnHdlr {
	if (actual_error.subjectCode != expected_subject_code or
	    actual_error.reasonCode != expected_reason_code) {
		var charstring desc := "";
		if (lengthof(test_description) > 0) {
			desc := test_description & " - ";
		}
		setverdict(fail, desc,
		           "Expected error ", expected_subject_code, "/", expected_reason_code,
		           " but got ", actual_error.subjectCode, "/", actual_error.reasonCode);
		f_shutdown(__FILE__, __LINE__);
	}

	log("Error validation passed: ", expected_subject_code, "/", expected_reason_code,
	    " (", actual_error.message_, ")");
}

private function f_set_euicc_pkids(inout EUICCInfo2 euiccInfo2) runs on smdpp_ConnHdlr {
	euiccInfo2.euiccCiPKIdListForVerification := f_get_ci_pkids_for_verification();
	euiccInfo2.euiccCiPKIdListForSigning := f_get_ci_pkids_for_signing();
}

private function f_create_euicc_signed1(
	EUICCInfo2 euiccInfo2,
	CtxParams1 ctxParams
) runs on smdpp_ConnHdlr return EuiccSigned1 {
	return {
		transactionId := g_transactionId,
		serverAddress := g_pars_smdpp.smdp_server_fqdn,
		serverChallenge := g_serverChallenge,
		euiccInfo2 := euiccInfo2,
		ctxParams1 := ctxParams
	};
}

type record CertificatePair {
	Certificate euicc_cert,
	Certificate eum_cert
}

private function f_get_certificate_pair() runs on smdpp_ConnHdlr return CertificatePair {
	return {
		euicc_cert := dec_Certificate(ext_RSPClient_getEUICCCertificate(g_rsp_client_handle_es9p)),
		eum_cert := dec_Certificate(ext_RSPClient_getEUMCertificate(g_rsp_client_handle_es9p))
	};
}

private function f_sign_euicc_signed1(EuiccSigned1 euiccSigned1) runs on smdpp_ConnHdlr return octetstring {
    var octetstring euiccSigned1_raw := enc_EuiccSigned1(euiccSigned1);
    return ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, euiccSigned1_raw);
}

private function f_build_authenticate_client_request(
    EuiccSigned1 euiccSigned1,
    octetstring euiccSignature1
) runs on smdpp_ConnHdlr return RemoteProfileProvisioningRequest {
    var CertificatePair certs := f_get_certificate_pair();

    return {
        authenticateClientRequest := {
            transactionId := g_transactionId,
            authenticateServerResponse := {
                authenticateResponseOk := {
                    euiccSigned1 := euiccSigned1,
                    euiccSignature1 := euiccSignature1,
                    euiccCertificate := certs.euicc_cert,
                    eumCertificate := certs.eum_cert
                }
            }
        }
    };
}

private function f_perform_authenticate_client_standard(
    charstring matchingId := ""  /* Empty string will trigger dynamic provisioning */
) runs on smdpp_ConnHdlr return AuthenticateClientOk {
    /* Provision profile dynamically if matchingId not provided */
    if (matchingId == "") {
        matchingId := f_provision_simple_profile();
    }

    var EUICCInfo2 euiccInfo2 := valueof(ts_EUICCInfo2);
    f_set_euicc_pkids(euiccInfo2);

    var CtxParams1 ctxParams := valueof(ts_ctxParams1);
    ctxParams.ctxParamsForCommonAuthentication.matchingId := matchingId;

    var EuiccSigned1 euiccSigned1 := f_create_euicc_signed1(euiccInfo2, ctxParams);
    var octetstring euiccSignature1 := f_sign_euicc_signed1(euiccSigned1);

    var RemoteProfileProvisioningRequest authReq := f_build_authenticate_client_request(euiccSigned1, euiccSignature1);
    var RemoteProfileProvisioningResponse authResp := f_es9p_transceive_success(authReq);

    return authResp.authenticateClientResponseEs9.authenticateClientOk;
}

private function f_corrupt_signature(octetstring valid_sig) return octetstring {
    var octetstring corrupted := valid_sig;
    if (lengthof(corrupted) > 0) {
        /* Flip some bits in the first byte */
        corrupted[0] := int2oct((oct2int(corrupted[0]) + 1) mod 256, 1);
    }
    return corrupted;
}


private function f_generate_wrong_Generic() return octetstring {
    return f_rnd_octstring(16);
}

external function encode_DER_InitialiseSecureChannelRequest_ver(
  in InitialiseSecureChannelRequest_ver pdu
) return octetstring
with { extension "prototype(convert) encode(BER:BER_ENCODE_DER)" };

external function encode_DER_profileInstallationResultData(
  in ProfileInstallationResultData pdu
) return octetstring
with { extension "prototype(convert) encode(BER:BER_ENCODE_DER)" };

/* VALIDATION HELPERS */

private function f_validate_initialise_secure_channel_request(InitialiseSecureChannelRequest iscReq)
runs on smdpp_ConnHdlr return boolean {
    if (iscReq.remoteOpId != c_remoteOpId_installBoundProfilePackage) {
        ext_logError("Invalid remoteOpId, expected installBoundProfilePackage(" &
                    int2str(c_remoteOpId_installBoundProfilePackage) & ")");
        return false;
    }

    if (iscReq.controlRefTemplate.keyType != c_keyType_AES) {
        ext_logError("Invalid key type, expected AES (0x88)");
        return false;
    }

    if (iscReq.controlRefTemplate.keyLen != c_keyLen_16bytes) {
        ext_logError("Invalid key length, expected 16 bytes (0x10)");
        return false;
    }

    if (lengthof(iscReq.controlRefTemplate.hostId) < c_hostId_min_length or
        lengthof(iscReq.controlRefTemplate.hostId) > c_hostId_max_length) {
        ext_logError("Invalid hostId length (" & int2str(lengthof(iscReq.controlRefTemplate.hostId)) &
                    "), expected " & int2str(c_hostId_min_length) & "-" & int2str(c_hostId_max_length));
        return false;
    }

    if (not ispresent(iscReq.smdpOtpk) or lengthof(iscReq.smdpOtpk) == 0) {
        ext_logError("Missing or empty smdpOtpk");
        return false;
    }

    if (iscReq.smdpOtpk[0] != c_ecPoint_uncompressed) {
        ext_logError("smdpOtpk is not an uncompressed EC point");
        return false;
    }

    return true;
}

private function f_validate_ecdh_and_signature(InitialiseSecureChannelRequest iscReq,
                                             AuthenticateClientOk auok,
                                             RemoteProfileProvisioningRequest packageRequest)
runs on smdpp_ConnHdlr return boolean {
    var octetstring euiccOtpk := ext_RSPClient_getEUICCOtpk(g_rsp_client_handle_es9p);
    if (not ext_CertificateUtil_verifyECDHCompatible(euiccOtpk, iscReq.smdpOtpk)) {
        ext_logError("eUICC and SM-DP+ public keys are not ECDH compatible");
        return false;
    }

    var InitialiseSecureChannelRequest_ver toencsec := {
        remoteOpId := c_remoteOpId_installBoundProfilePackage,
        transactionId := g_transactionId,
        controlRefTemplate := iscReq.controlRefTemplate,
        smdpOtpk := iscReq.smdpOtpk,
        euiccOtpk := packageRequest.getBoundProfilePackageRequest.prepareDownloadResponse.downloadResponseOk.euiccSigned2.euiccOtpk
    };

    var octetstring encsecr := encode_DER_InitialiseSecureChannelRequest_ver(toencsec);
    var octetstring trunc_initsec := substr(encsecr, 4, lengthof(encsecr)-4);

    if (not ext_RSPClient_verifyServerSignature(g_rsp_client_handle_es9p, trunc_initsec,
                                               iscReq.smdpSign, enc_Certificate(auok.smdpCertificate))) {
        ext_logError("InitialiseSecureChannelRequest signature validation failed");
        return false;
    }

    return true;
}

private function f_fail_and_cleanup(charstring error_msg) runs on smdpp_ConnHdlr {
    ext_logError(error_msg);
    setverdict(fail, error_msg);
    f_rsp_client_cleanup();
}

private function f_validate_certificate_roles(RemoteProfileProvisioningResponse authResponse,
                                            AuthenticateClientOk auok) runs on smdpp_ConnHdlr
return boolean {
    ext_logInfo("=== Validating certificate roles ===");

    var octetstring dpAuthCert := enc_Certificate(authResponse.initiateAuthenticationResponse.initiateAuthenticationOk.serverCertificate);
    if (not ext_CertificateUtil_hasRSPRole(dpAuthCert, c_oid_rspRole_dp_auth)) {
        ext_logError("DPauth certificate missing authentication role OID");
        return false;
    }

    var octetstring dpPbCert := enc_Certificate(auok.smdpCertificate);
    if (not ext_CertificateUtil_hasRSPRole(dpPbCert, c_oid_rspRole_dp_pb)) {
        ext_logError("DPpb certificate missing profile binding role OID");
        return false;
    }

    return true;
}

private function f_validate_ein_permissions(charstring eid, octetstring eumCert) runs on smdpp_ConnHdlr
return boolean {
    ext_logInfo("=== Validating EUM certificate permissions ===");

    var charstring permittedEINs := ext_CertificateUtil_getPermittedEINs(eumCert);
    if (permittedEINs == "") {
        ext_logError("No permitted EINs found in EUM certificate");
        return false;
    }
    ext_logInfo("EUM permitted EINs: " & permittedEINs);

    var boolean ein_match := false;
    var charstring eid_upper := f_str_toupper(eid);

    // do we have comma-separated EINs? tbd.
    var integer ein_start := 0;
    for (var integer i := 0; i <= lengthof(permittedEINs); i := i + 1) {
        if (i == lengthof(permittedEINs) or permittedEINs[i] == ",") {
            var charstring ein := substr(permittedEINs, ein_start, i - ein_start);
            if (substr(eid_upper, 0, lengthof(ein)) == f_str_toupper(ein)) {
                ein_match := true;
                ext_logInfo("EID matches permitted EIN: " & ein);
                break;
            }
            ein_start := i + 1;
        }
    }

    if (not ein_match) {
        ext_logError("EID does not match any permitted EIN");
        return false;
    }

    return true;
}

private function f_validate_pkid_match(RemoteProfileProvisioningRequest authRequest,
                                     RemoteProfileProvisioningResponse authResponse)
runs on smdpp_ConnHdlr return boolean {
    var boolean pkid_found := false;
    var SubjectKeyIdentifier used_pkid :=
        authResponse.initiateAuthenticationResponse.initiateAuthenticationOk.euiccCiPKIdToBeUsed;

    for (var integer i := 0; i < lengthof(authRequest.initiateAuthenticationRequest.euiccInfo1.euiccCiPKIdListForSigning); i := i + 1) {
        if (used_pkid == authRequest.initiateAuthenticationRequest.euiccInfo1.euiccCiPKIdListForSigning[i]) {
            pkid_found := true;
            break;
        }
    }

    if (not pkid_found) {
        ext_logError("euiccCiPKIdToBeUsed not in requested list");
        return false;
    }

    return true;
}

private function f_es9p_handleNotification(JSON_ES9p_HandleNotification handleNotifReq)
runs on smdpp_ConnHdlr
return JSON_ES9p_EmptyResponse {
    var RemoteProfileProvisioningRequest asn1_req := {
        handleNotification := {
            pendingNotification := dec_PendingNotification(decode_base64(handleNotifReq.pendingNotification))
        }
    };

    f_es9p_send_new(asn1_req);

    var integer http_status;
    var charstring response_body := ext_RSPClient_sendHttpsPost(
        g_rsp_client_handle_es9p,
        g_last_es9p_endpoint,
        g_last_es9p_request,
        g_pars_smdpp.smdp_es9p_server_port,
        http_status
    );

    /* HandleNotification returns 204 No Content on success */
    if (http_status == 204) {
        var JSON_ES9p_EmptyResponse empty_resp := {
            header := {
                functionExecutionStatus := {
                    status := "Executed-Success",
                    statusCodeData := omit
                }
            }
        };
        return empty_resp;
    } else if (http_status != 200) {
        setverdict(fail, "HTTP error response: " & int2str(http_status));
        var JSON_ES9p_EmptyResponse empty;
        return empty;
    }

    /* For 200 response, decode JSON */
    var JSON_ES9p_RemoteProfileProvisioningResponse json_resp;
    json_resp := dec_JSON_ES9p_RemoteProfileProvisioningResponse(char2oct(response_body));

    if (ispresent(json_resp.emptyResponse)) {
        return json_resp.emptyResponse;
    } else {
        setverdict(fail, "Unexpected response type for HandleNotification");
        var JSON_ES9p_EmptyResponse empty;
        return empty;
    }
}

private function f_handleNotification_generic(PendingNotification pendingNotif) runs on smdpp_ConnHdlr {
    var octetstring pendingNotifData := enc_PendingNotification(pendingNotif);
    var charstring pendingNotifB64 := encode_base64(pendingNotifData);

    var JSON_ES9p_HandleNotification handleNotifReq := {
        header := {
            functionRequesterIdentifier := "TTCN3",
            functionCallIdentifier := "testsuite"
        },
        pendingNotification := pendingNotifB64
    };

    var JSON_ES9p_EmptyResponse emptyResp;
    emptyResp := f_es9p_handleNotification(handleNotifReq);

    /* HandleNotification should return empty response with header */
    if (ispresent(emptyResp.header)) {
        if (ispresent(emptyResp.header.functionExecutionStatus)) {
            if (ispresent(emptyResp.header.functionExecutionStatus.statusCodeData)) {
                setverdict(fail, "HandleNotification failed with error: ",
                          emptyResp.header.functionExecutionStatus.statusCodeData.subjectCode, "/",
                          emptyResp.header.functionExecutionStatus.statusCodeData.reasonCode);
                return;
            }
        }
        ext_logInfo("HandleNotification successful");
    } else {
        setverdict(fail, "HandleNotification response missing header");
    }
}

private function f_create_profile_installation_result(octetstring transactionId,
                                                    boolean success := true,
                                                    template (omit) Iccid iccid_val := omit,
                                                    integer errorReason := 1,
                                                    integer bppCommandId := 0)
runs on smdpp_ConnHdlr return ProfileInstallationResult {
    var NotificationMetadata notifMeta := {
        seqNumber := 1,
        profileManagementOperation := c_notificationInstall,
        notificationAddress := g_pars_smdpp.smdp_server_fqdn,
        iccid := omit
    };

    if (ispresent(iccid_val)) {
        notifMeta.iccid := valueof(iccid_val);
    }

    var ProfileInstallationResultData pirData := {
        transactionId := transactionId,
        notificationMetadata := notifMeta,
        smdpOid := objid { 2 999 10 } /* Test OID */
    };

    if (success) {
        pirData.finalResult := {
            successResult := {
                aid := 'A0000005591010FFFFFFFF8900001100'O, /* Test AID */
                simaResponse := '9000'O /* Success response */
            }
        };
    } else {
        pirData.finalResult := {
            errorResult := {
                bppCommandId := bppCommandId,
                errorReason := errorReason,
                simaResponse := '6A80'O /* Error response */
            }
        };
    }

    var octetstring full_encoded := encode_DER_profileInstallationResultData(pirData);
    var octetstring euiccSignPIR := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, full_encoded);

    var ProfileInstallationResult pir := {
        profileInstallationResultData := pirData,
        euiccSignPIR := euiccSignPIR
    };

    return pir;
}

private function f_create_profile_installation_result_error(octetstring transactionId,
                                                           integer errorReason)
runs on smdpp_ConnHdlr return ProfileInstallationResult {
    /* unified function with success=false */
    return f_create_profile_installation_result(transactionId, false, omit, errorReason);
}


private function f_performInitiateAuthentication() runs on smdpp_ConnHdlr return octetstring {
	var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();
	return authOk.serverSigned1.serverChallenge;
}

private function f_buildAuthenticateClientRequest_unified(
	octetstring serverChallenge,
	charstring matchingId := "",  /* Empty string will trigger dynamic provisioning */
	template (omit) EUICCInfo2 euiccInfo2 := omit,      // omit = create default
	template (omit) DeviceInfo deviceInfo := omit,       // omit = no device info
	template (omit) octetstring transactionIdOverride := omit,  // omit = use correct ID
	boolean setPkids := true                             // whether to set PKIDs
) runs on smdpp_ConnHdlr return RemoteProfileProvisioningRequest {

	var EUICCInfo2 actualEuiccInfo2;
	if (isvalue(euiccInfo2)) {
		actualEuiccInfo2 := valueof(euiccInfo2);
	} else {
		actualEuiccInfo2 := valueof(ts_EUICCInfo2);
	}

	if (setPkids) {
		f_set_euicc_pkids(actualEuiccInfo2);
	}

	var CtxParams1 ctxParams := valueof(ts_ctxParams1);
	/* matchingId:
	 * - "OMIT" -> field omitted from ASN.1 structure
	 * - "" -> triggers dynamic provisioning and uses the result
	 * - any other value -> field contains that value
	 */
	if (matchingId == "OMIT") {
		ctxParams.ctxParamsForCommonAuthentication.matchingId := omit;
	} else {
		/* Provision profile dynamically if matchingId empty */
		if (matchingId == "") {
			matchingId := f_provision_simple_profile();
		}
		ctxParams.ctxParamsForCommonAuthentication.matchingId := matchingId;
	}

	if (isvalue(deviceInfo)) {
		ctxParams.ctxParamsForCommonAuthentication.deviceInfo := valueof(deviceInfo);
	}

	var octetstring actualTransactionId := g_transactionId;
	if (isvalue(transactionIdOverride)) {
		actualTransactionId := valueof(transactionIdOverride);
	}

	var EuiccSigned1 euiccSigned1 := {
		transactionId := actualTransactionId,
		serverAddress := g_pars_smdpp.smdp_server_fqdn,
		serverChallenge := serverChallenge,
		euiccInfo2 := actualEuiccInfo2,
		ctxParams1 := ctxParams
	};

	var octetstring euiccSigned1_raw := enc_EuiccSigned1(euiccSigned1);
	var octetstring euiccSignature1 := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, euiccSigned1_raw);

	var Certificate g_euicc_cert := dec_Certificate(ext_RSPClient_getEUICCCertificate(g_rsp_client_handle_es9p));
	var Certificate g_eum_cert := dec_Certificate(ext_RSPClient_getEUMCertificate(g_rsp_client_handle_es9p));

	return {
		authenticateClientRequest := {
			transactionId := g_transactionId,
			authenticateServerResponse := {
				authenticateResponseOk := {
					euiccSigned1 := euiccSigned1,
					euiccSignature1 := euiccSignature1,
					euiccCertificate := g_euicc_cert,
					eumCertificate := g_eum_cert
				}
			}
		}
	};
}

private function f_buildAuthenticateClientRequest(
	octetstring serverChallenge,
	charstring matchingId := "",  /* Empty string will trigger dynamic provisioning */
	template (omit) octetstring transactionIdOverride := omit  // error injection - omit means correct ID
) runs on smdpp_ConnHdlr return RemoteProfileProvisioningRequest {
	return f_buildAuthenticateClientRequest_unified(
		serverChallenge,
		matchingId,
		omit,  // use default EUICCInfo2
		omit,  // no deviceInfo
		transactionIdOverride,
		true   // set PKIDs
	);
}


private function f_buildAuthenticateClientRequest_withEuiccInfo2(
	octetstring serverChallenge,
	charstring matchingId,
	EUICCInfo2 euiccInfo2
) runs on smdpp_ConnHdlr return RemoteProfileProvisioningRequest {
	return f_buildAuthenticateClientRequest_unified(
		serverChallenge,
		matchingId,
		euiccInfo2,
		omit,  // no deviceInfo
		omit,  // no transactionIdOverride
		false  // don't set PKIDs (assume caller did it)
	);
}


private function f_buildAuthenticateClientRequest_withDeviceInfo(
	octetstring serverChallenge,
	charstring matchingId,
	EUICCInfo2 euiccInfo2,
	DeviceInfo deviceInfo
) runs on smdpp_ConnHdlr return RemoteProfileProvisioningRequest {
	return f_buildAuthenticateClientRequest_unified(
		serverChallenge,
		matchingId,
		euiccInfo2,
		deviceInfo,
		omit,  // no transactionIdOverride
		false  // don't set PKIDs (assume caller did it)
	);
}


private function f_validateAuthenticateClientResponse(AuthenticateClientOk authClientOk) runs on smdpp_ConnHdlr {
	if (authClientOk.transactionId != g_transactionId) {
		setverdict(fail, "Transaction ID mismatch in response");
		f_shutdown(__FILE__, __LINE__);
	}
}


private function f_test_authenticateClient_unified(
    AuthClientTestParams params,
    charstring id
) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: " & params.testName & " ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var octetstring serverChallenge := f_performInitiateAuthentication();

    ext_logInfo("Step 2: " & params.stepDescription);

    var RemoteProfileProvisioningRequest authReq;
    if (ispresent(params.matchingId)) {
        if (ispresent(params.transactionIdOverride)) {
            authReq := f_buildAuthenticateClientRequest(serverChallenge, params.matchingId, params.transactionIdOverride);
        } else {
            authReq := f_buildAuthenticateClientRequest(serverChallenge, params.matchingId);
        }
    } else {
        if (ispresent(params.transactionIdOverride)) {
            authReq := f_buildAuthenticateClientRequest(serverChallenge, "OMIT", params.transactionIdOverride);
        } else {
            authReq := f_buildAuthenticateClientRequest(serverChallenge, "OMIT");
        }
    }

    if (params.expectError) {
        var JSON_ESx_FunctionExecutionStatusCodeData errorData := f_es9p_transceive_error(authReq);
        f_validate_error_response(errorData, params.expectedSubjectCode,
                                params.expectedReasonCode, params.errorDescription);

        ext_logInfo("Test passed - Correct error codes received for " & params.errorDescription);
    } else {
        var RemoteProfileProvisioningResponse authResp := f_es9p_transceive_success(authReq);
        var AuthenticateClientOk authClientOk := authResp.authenticateClientResponseEs9.authenticateClientOk;

        f_validateAuthenticateClientResponse(authClientOk);

        if (ispresent(params.expectCcRequired)) {
            if (params.expectCcRequired and not authClientOk.smdpSigned2.ccRequiredFlag) {
                setverdict(fail, "Expected ccRequiredFlag to be true but it was false");
                f_shutdown(__FILE__, __LINE__);
            } else if (not params.expectCcRequired and authClientOk.smdpSigned2.ccRequiredFlag) {
                setverdict(fail, "Expected ccRequiredFlag to be false but it was true");
                f_shutdown(__FILE__, __LINE__);
            }
        }

        ext_logInfo("Test passed - " & params.successMessage);
    }

    f_rsp_client_cleanup();
    setverdict(pass);
}

private function f_test_authenticateClient_success(
    AuthClientSuccessTestParams params,
    charstring id
) runs on smdpp_ConnHdlr {
    var AuthClientTestParams unifiedParams := {
        testName := params.testName,
        stepDescription := params.stepDescription,
        matchingId := params.matchingId,
        transactionIdOverride := omit,
        expectError := false,
        expectCcRequired := params.expectCcRequired,
        successMessage := params.successMessage,
        expectedSubjectCode := omit,
        expectedReasonCode := omit,
        errorDescription := omit
    };
    f_test_authenticateClient_unified(unifiedParams, id);
}


private function f_test_authenticateClient_error(
    AuthClientErrorTestParams params,
    charstring id
) runs on smdpp_ConnHdlr {
    var AuthClientTestParams unifiedParams := {
        testName := params.testName,
        stepDescription := params.stepDescription,
        matchingId := params.matchingId,
        transactionIdOverride := params.transactionIdOverride,
        expectError := true,
        expectCcRequired := omit,
        successMessage := omit,
        expectedSubjectCode := params.expectedSubjectCode,
        expectedReasonCode := params.expectedReasonCode,
        errorDescription := params.errorDescription
    };
    f_test_authenticateClient_unified(unifiedParams, id);
}

private function f_cancelSession(octetstring transactionId, objid smdpOid) runs on smdpp_ConnHdlr {
    var CancelSessionResponse cancelResp := {
        cancelSessionResponseOk := {
            euiccCancelSessionSigned := {
                transactionId := transactionId,
                smdpOid := smdpOid,
                reason := 0  /* endUserRejection */
            },
            euiccCancelSessionSignature := ''O
        }
    };

    var octetstring cancelSignedData := enc_EuiccCancelSessionSigned(cancelResp.cancelSessionResponseOk.euiccCancelSessionSigned);
    cancelResp.cancelSessionResponseOk.euiccCancelSessionSignature := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, cancelSignedData);

    var RemoteProfileProvisioningRequest cancelReq := {
        cancelSessionRequestEs9 := {
            transactionId := transactionId,
            cancelSessionResponse := cancelResp
        }
    };

    var DecodedRPPReponse_Wrap response := f_es9p_transceive_wrap(cancelReq);

    if (ispresent(response.err)) {
        setverdict(fail, "CancelSession failed with error");
    } else if (ispresent(response.asn1_pdu) and ispresent(response.asn1_pdu.cancelSessionResponseEs9)) {
        ext_logInfo("CancelSession successful - session terminated");
    } else {
        ext_logInfo("CancelSession successful - empty response received");
    }
}

private function f_create_authenticate_client_request(charstring matchingId := "") runs on smdpp_ConnHdlr return RemoteProfileProvisioningRequest {
	/* Provision profile dynamically if matchingId not provided */
	if (matchingId == "") {
		matchingId := f_provision_simple_profile();
	}

	var EUICCInfo2 euiccInfo2 := valueof(ts_EUICCInfo2);
	f_set_euicc_pkids(euiccInfo2);

	var CtxParams1 ctxParams := valueof(ts_ctxParams1);
	ctxParams.ctxParamsForCommonAuthentication.matchingId := matchingId;

	var EuiccSigned1 euiccSigned1 := f_create_euicc_signed1(euiccInfo2, ctxParams);

	var octetstring euiccSigned1_raw := enc_EuiccSigned1(euiccSigned1);
	var octetstring euiccSignature1 := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, euiccSigned1_raw);

	var Certificate g_euicc_cert := dec_Certificate(ext_RSPClient_getEUICCCertificate(g_rsp_client_handle_es9p));
	var Certificate g_eum_cert := dec_Certificate(ext_RSPClient_getEUMCertificate(g_rsp_client_handle_es9p));

	var RemoteProfileProvisioningRequest authReq := {
		authenticateClientRequest := {
			transactionId := g_transactionId,
			authenticateServerResponse := {
				authenticateResponseOk := {
					euiccSigned1 := euiccSigned1,
					euiccSignature1 := euiccSignature1,
					euiccCertificate := g_euicc_cert,
					eumCertificate := g_eum_cert
				}
			}
		}
	};

	return authReq;
}


private function f_create_prepare_download_response(octetstring smdpSignature2) runs on smdpp_ConnHdlr return PrepareDownloadResponse {
	var octetstring euicc_otpk := ext_RSPClient_generateEUICCOtpk(g_rsp_client_handle_es9p);

	var EUICCSigned2 euiccSigned2 := {
		transactionId := g_transactionId,
		euiccOtpk := euicc_otpk,
		hashCc := omit
	};

	var octetstring ccHash := ext_RSPClient_getConfirmationCodeHash(g_rsp_client_handle_es9p);
	if (lengthof(ccHash) == 32) {
		euiccSigned2.hashCc := ccHash;
		ext_logInfo("Added confirmation code hash to PrepareDownloadResponse: " & oct2str(ccHash));
	} else if (lengthof(ccHash) > 0) {
		ext_logError("Invalid confirmation code hash length: " & int2str(lengthof(ccHash)));
	}

	var octetstring euiccSigned2_raw := enc_EUICCSigned2(euiccSigned2);
	var octetstring concatdata := euiccSigned2_raw & smdpSignature2;
	var octetstring euiccSignature2 := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, concatdata);

	var PrepareDownloadResponse prepDownloadResp := {
		downloadResponseOk := {
			euiccSigned2 := euiccSigned2,
			euiccSignature2 := euiccSignature2
		}
	};

	return prepDownloadResp;
}


private function f_run_test_case(charstring tc_name, void_fn test_fn) runs on MTC_CT {
    var charstring id := tc_name;
    var smdpp_ConnHdlrPars pars := f_init_pars();
    var smdpp_ConnHdlr vc_conn;

    f_init(id);
    vc_conn := f_start_handler(test_fn, pars);
    vc_conn.done;
    setverdict(pass);
}

/* Test cases start here */

private function f_authenticateClient_error_generic(
    charstring test_name,
    charstring expected_subject_code,
    charstring expected_reason_code,
    AuthClientErrorInjection err_injection
) runs on smdpp_ConnHdlr {

    ext_logInfo("=== Testing AuthenticateClient Error: " & test_name & " ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    /* Step 1: InitiateAuthentication (normal) */
    var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();
    var octetstring transactionId := authOk.transactionId;
    var octetstring serverChallenge := authOk.serverSigned1.serverChallenge;

    /* Apply transaction ID error if specified */
    if (ischosen(err_injection.trans_error) and err_injection.trans_error.in_json) {
        if (ispresent(err_injection.trans_error.wrong_transaction_id)) {
            transactionId := err_injection.trans_error.wrong_transaction_id;
        } else {
            transactionId := f_generate_wrong_Generic();
        }
    }

    /* Build EUICCInfo2 */
    var EUICCInfo2 euiccInfo2 := valueof(ts_EUICCInfo2);
    f_set_euicc_pkids(euiccInfo2);

    /* Build CtxParams */
    var CtxParams1 ctxParams := valueof(ts_ctxParams1);

    /* Provision profile dynamically unless error injection overrides it */
    var charstring provisionedMatchingId := f_provision_simple_profile();
    ctxParams.ctxParamsForCommonAuthentication.matchingId := provisionedMatchingId;

    /* Apply context parameter errors if specified */
    if (ischosen(err_injection.ctx_error)) {
        if (ispresent(err_injection.ctx_error.wrong_matching_id)) {
            ctxParams.ctxParamsForCommonAuthentication.matchingId := err_injection.ctx_error.wrong_matching_id;
        }
        if (err_injection.ctx_error.omit_matching_id) {
            ctxParams.ctxParamsForCommonAuthentication.matchingId := omit;
        }
    }

    /* Build euiccSigned1 */
    var EuiccSigned1 euiccSigned1 := {
        transactionId := transactionId,
        serverAddress := g_pars_smdpp.smdp_server_fqdn,
        serverChallenge := serverChallenge,
        euiccInfo2 := euiccInfo2,
        ctxParams1 := ctxParams
    };

    /* Apply transaction ID error in ASN.1 if specified */
    if (ischosen(err_injection.trans_error) and not err_injection.trans_error.in_json) {
        if (ispresent(err_injection.trans_error.wrong_transaction_id)) {
            euiccSigned1.transactionId := err_injection.trans_error.wrong_transaction_id;
        } else {
            euiccSigned1.transactionId := f_generate_wrong_Generic();
        }
    }

    /* Apply server challenge error if specified */
    if (ischosen(err_injection.challenge_error)) {
        if (ispresent(err_injection.challenge_error.wrong_challenge)) {
            euiccSigned1.serverChallenge := err_injection.challenge_error.wrong_challenge;
        } else {
            euiccSigned1.serverChallenge := f_generate_wrong_Generic();
        }
    }

    /* Sign the data */
    var octetstring euiccSigned1_raw := enc_EuiccSigned1(euiccSigned1);
    var octetstring euiccSignature1 := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, euiccSigned1_raw);

    /* Apply signature error if specified */
    if (ischosen(err_injection.sig_error) and err_injection.sig_error.corrupt_signature) {
        euiccSignature1 := f_corrupt_signature(euiccSignature1);
    }

    /* Apply certificate error if specified */
    if (ischosen(err_injection.cert_error)) {
        select (err_injection.cert_error.error_type) {
        case (INVALID_EUM_SIGNATURE) {
            /* Load invalid (self-signed) EUM certificate */
            ext_RSPClient_loadEUMCertificate(g_rsp_client_handle_es9p, "./InvalidTestCases/CERT_EUM_ECDSA_NIST_INVALID.der");
        }
        case (EXPIRED_EUM) {
            /* Load expired EUM certificate */
            ext_RSPClient_loadEUMCertificate(g_rsp_client_handle_es9p, "./InvalidTestCases/CERT_EUM_ECDSA_NIST_EXPIRED.der");
        }
        case (INVALID_EUICC_SIGNATURE) {
            /* Load invalid (self-signed) eUICC certificate */
            ext_RSPClient_loadEUICCCertificate(g_rsp_client_handle_es9p, "./InvalidTestCases/CERT_EUICC_ECDSA_NIST_INVALID.der");
        }
        case (EXPIRED_EUICC) {
            /* Load expired eUICC certificate */
            ext_RSPClient_loadEUICCCertificate(g_rsp_client_handle_es9p, "./InvalidTestCases/CERT_EUICC_ECDSA_NIST_EXPIRED.der");
        }
        case (UNKNOWN_CI_KEY) {
            /* Load EUM certificate signed by unknown CI */
            ext_RSPClient_loadEUMCertificate(g_rsp_client_handle_es9p, "./InvalidTestCases/CERT_EUM_ECDSA_NIST_UNKNOWN_CI.der");
        }
        case else {
            setverdict(fail, "Unsupported certificate error type");
            f_shutdown(__FILE__, __LINE__);
        }
        }
    }

    /* Get certificates from RSP client */
    var Certificate g_euicc_cert := dec_Certificate(ext_RSPClient_getEUICCCertificate(g_rsp_client_handle_es9p));
    var Certificate g_eum_cert := dec_Certificate(ext_RSPClient_getEUMCertificate(g_rsp_client_handle_es9p));

    /* Build the request */
    var RemoteProfileProvisioningRequest authClientReq := {
        authenticateClientRequest := {
            transactionId := transactionId,
            authenticateServerResponse := {
                authenticateResponseOk := {
                    euiccSigned1 := euiccSigned1,
                    euiccSignature1 := euiccSignature1,
                    euiccCertificate := g_euicc_cert,
                    eumCertificate := g_eum_cert
                }
            }
        }
    };

    /* Send request and expect error */
    var JSON_ESx_FunctionExecutionStatusCodeData errorData := f_es9p_transceive_error(authClientReq);

    /* Validate error response */
    f_validate_error_response(errorData, expected_subject_code, expected_reason_code, test_name);

    ext_logInfo("Test passed - " & test_name);
    f_rsp_client_cleanup();
    setverdict(pass);
}


private function f_authenticateClient_error_wrapper(charstring id) runs on smdpp_ConnHdlr {
    f_authenticateClient_error_generic(
        g_pars_smdpp.test_name,
        g_pars_smdpp.expected_subject_code,
        g_pars_smdpp.expected_reason_code,
        g_pars_smdpp.err_injection
    );
}


private function f_getBoundProfilePackage_error_generic(
    charstring test_name,
    charstring expected_subject_code,
    charstring expected_reason_code,
    GetBppErrorInjection err_injection,
    boolean cc_required := false
) runs on smdpp_ConnHdlr {

    ext_logInfo("=== Testing GetBoundProfilePackage Error: " & test_name & " ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    /* Step 1: InitiateAuthentication */
    var InitiateAuthenticationOkEs9 initAuthOk;
    initAuthOk := f_initiate_authentication_and_validate();

    /* Step 2: AuthenticateClient with ccRequiredFlag if needed */
    var AuthenticateClientOk authClientOk;
    if (cc_required) {
        /* Use special matching ID to trigger ccRequiredFlag on server */
        authClientOk := f_perform_authenticate_client_standard("CC_REQUIRED_TEST");
    } else {
        authClientOk := f_perform_authenticate_client_standard();
    }

    /* Step 3: PrepareDownloadResponse with error injection */
    var octetstring smdpSignature2 := authClientOk.smdpSignature2;
    var octetstring euicc_otpk := ext_RSPClient_generateEUICCOtpk(g_rsp_client_handle_es9p);

    /* Build EUICCSigned2 */
    var EUICCSigned2 euiccSigned2 := {
        transactionId := g_transactionId,
        euiccOtpk := euicc_otpk,
        hashCc := omit  /* Default: no confirmation code */
    };

    /* Check if server requires confirmation code */
    var boolean server_requires_cc := authClientOk.smdpSigned2.ccRequiredFlag;

    /* If server requires CC and no cc_error injection, compute valid hash */
    if (server_requires_cc and not ischosen(err_injection.cc_error)) {
        /* Set confirmation code and get hash */
        var charstring confirmationCode := "12345678";  /* Default test code matching server */
        var integer result := ext_RSPClient_setConfirmationCode(g_rsp_client_handle_es9p, confirmationCode);
        if (result == 0) {
            euiccSigned2.hashCc := ext_RSPClient_getConfirmationCodeHash(g_rsp_client_handle_es9p);
            ext_logInfo("Using confirmation code hash: " & oct2str(euiccSigned2.hashCc));
        }
    }

    /* Apply error injections */
    var octetstring transactionId := g_transactionId;

    if (ischosen(err_injection.trans_error)) {
        if (err_injection.trans_error.in_json) {
            /* Error in JSON layer */
            if (ispresent(err_injection.trans_error.wrong_transaction_id)) {
                transactionId := err_injection.trans_error.wrong_transaction_id;
            } else {
                transactionId := f_generate_wrong_Generic();
            }
        } else {
            /* Error in ASN.1 */
            if (ispresent(err_injection.trans_error.wrong_transaction_id)) {
                euiccSigned2.transactionId := err_injection.trans_error.wrong_transaction_id;
            } else {
                euiccSigned2.transactionId := f_generate_wrong_Generic();
            }
        }
    }

    if (ischosen(err_injection.cc_error)) {
        if (server_requires_cc) {
            if (err_injection.cc_error.omit_cc) {
                /* Omit confirmation code when required */
                euiccSigned2.hashCc := omit;
            } else if (err_injection.cc_error.wrong_cc) {
                /* Send wrong confirmation code */
                if (ispresent(err_injection.cc_error.invalid_cc)) {
                    euiccSigned2.hashCc := err_injection.cc_error.invalid_cc;
                } else {
                    /* Generate random wrong CC hash */
                    euiccSigned2.hashCc := f_rnd_octstring(32);  /* SHA256 is 32 bytes */
                }
            }
        }
    }

    /* Sign EUICCSigned2 */
    var octetstring euiccSigned2_raw := enc_EUICCSigned2(euiccSigned2);
    var octetstring concatdata := euiccSigned2_raw & smdpSignature2;
    var octetstring euiccSignature2 := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, concatdata);

    /* Apply signature corruption if needed */
    if (ischosen(err_injection.sig_error) and err_injection.sig_error.corrupt_signature) {
        euiccSignature2 := f_corrupt_signature(euiccSignature2);
    }

    /* Create PrepareDownloadResponse */
    var PrepareDownloadResponse prepareDownloadResponse := {
        downloadResponseOk := {
            euiccSigned2 := euiccSigned2,
            euiccSignature2 := euiccSignature2
        }
    };

    /* Build the request */
    var RemoteProfileProvisioningRequest getBppReq := {
        getBoundProfilePackageRequest := {
            transactionId := transactionId,
            prepareDownloadResponse := prepareDownloadResponse
        }
    };

    /* Send request and expect error */
    var DecodedRPPReponse_Wrap wrap := f_es9p_transceive_wrap(getBppReq);

    /* Validate error response */
    if (not ispresent(wrap.err)) {
        setverdict(fail, "Expected error response but got success");
        return;
    }

    f_validate_error_response(wrap.err, expected_subject_code, expected_reason_code, test_name);

    setverdict(pass);
}


private function f_getBoundProfilePackage_error_wrapper(charstring id) runs on smdpp_ConnHdlr {
    f_getBoundProfilePackage_error_generic(
        g_pars_smdpp.test_name,
        g_pars_smdpp.expected_subject_code,
        g_pars_smdpp.expected_reason_code,
        g_pars_smdpp.gbpp_err_injection,
        g_pars_smdpp.cc_required
    );
}


private function f_initiateAuth_generic(charstring id, template (omit) octetstring version := omit, charstring testDescription, charstring successMessage, boolean checkPkid := false) runs on smdpp_ConnHdlr {
    ext_logInfo(testDescription);

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var RemoteProfileProvisioningRequest authRequest := f_create_initiate_authentication_request();

    authRequest.initiateAuthenticationRequest.euiccInfo1.svn := c_SGP22_VERSION;
    if (ispresent(version)) {
        authRequest.initiateAuthenticationRequest.euiccInfo1.svn := valueof(version);
    }

    var RemoteProfileProvisioningResponse authResponse := f_es9p_transceive_success(authRequest);
    var InitiateAuthenticationOkEs9 authOk := authResponse.initiateAuthenticationResponse.initiateAuthenticationOk;

    /* Verify transaction ID consistency */
    if (authOk.transactionId != authOk.serverSigned1.transactionId) {
        setverdict(fail, "Transaction ID mismatch between outer and inner structures");
        f_rsp_client_cleanup();
        return;
    }

    var octetstring serverCert := enc_Certificate(authOk.serverCertificate);
    if (not ext_RSPClient_verifyServerSignature(g_rsp_client_handle_es9p,
                                                enc_ServerSigned1(authOk.serverSigned1),
                                                authOk.serverSignature1,
                                                serverCert)) {
        setverdict(fail, "Server signature verification failed");
        f_rsp_client_cleanup();
        return;
    }

    /* Optional PKID verification */
    if (checkPkid) {
        var boolean pkid_found := false;
        for (var integer i := 0; i < lengthof(authRequest.initiateAuthenticationRequest.euiccInfo1.euiccCiPKIdListForSigning); i := i + 1) {
            if (authOk.euiccCiPKIdToBeUsed == authRequest.initiateAuthenticationRequest.euiccInfo1.euiccCiPKIdListForSigning[i]) {
                pkid_found := true;
                break;
            }
        }

        if (not pkid_found) {
            setverdict(fail, "euiccCiPKIdToBeUsed not in requested list");
            f_rsp_client_cleanup();
            return;
        }
    }

    ext_logInfo(successMessage);
    f_rsp_client_cleanup();
    setverdict(pass);
}

/* Test handler for TC_SM-DP+_ES9+.InitiateAuthenticationNIST - Test Sequence #01 Nominal */
private function f_TC_InitiateAuth_01_Nominal(charstring id) runs on smdpp_ConnHdlr {
	/* Use the generic function with PKID check enabled */
	f_initiateAuth_generic(id, '020201'O, "=== Test Case: InitiateAuthentication - Nominal ===",
	                      "Test passed - InitiateAuthentication nominal flow successful", true);
}

/* Test handler for TC_SM-DP+_ES9+.InitiateAuthenticationNIST - Test Sequence #02 Uniqueness */
private function f_TC_InitiateAuth_02_Uniqueness(charstring id) runs on smdpp_ConnHdlr {
	ext_logInfo("=== Test Case: InitiateAuthentication - Uniqueness of Transaction ID and Server Challenge ===");

	/* Initialize HTTP/TLS and RSP client */
	f_init_es9plus();

	/* Step 1: First InitiateAuthentication request */
	var RemoteProfileProvisioningRequest authRequest1 := f_create_initiate_authentication_request();
	var RemoteProfileProvisioningResponse authResponse1 := f_es9p_transceive_success(authRequest1);

	var InitiateAuthenticationOkEs9 authOk1 := authResponse1.initiateAuthenticationResponse.initiateAuthenticationOk;
	var octetstring transactionId1 := authOk1.transactionId;
	var octetstring serverChallenge1 := authOk1.serverSigned1.serverChallenge;

	ext_logInfo("First transaction ID: " & oct2str(transactionId1));
	ext_logInfo("First server challenge: " & oct2str(serverChallenge1));

	/* Step 2: Re-initialize TLS connection (simulated by re-init) */
	f_rsp_client_cleanup();
	f_init_es9plus();

	/* Step 3: Second InitiateAuthentication request */
	var RemoteProfileProvisioningRequest authRequest2 := f_create_initiate_authentication_request();
	var RemoteProfileProvisioningResponse authResponse2 := f_es9p_transceive_success(authRequest2);

	var InitiateAuthenticationOkEs9 authOk2 := authResponse2.initiateAuthenticationResponse.initiateAuthenticationOk;
	var octetstring transactionId2 := authOk2.transactionId;
	var octetstring serverChallenge2 := authOk2.serverSigned1.serverChallenge;

	ext_logInfo("Second transaction ID: " & oct2str(transactionId2));
	ext_logInfo("Second server challenge: " & oct2str(serverChallenge2));

	/* Verify uniqueness */
	if (transactionId1 == transactionId2) {
		setverdict(fail, "Transaction IDs are not unique");
		f_rsp_client_cleanup();
		return;
	}

	if (authOk1.serverSigned1.transactionId == authOk2.serverSigned1.transactionId) {
		setverdict(fail, "Signed transaction IDs are not unique");
		f_rsp_client_cleanup();
		return;
	}

	if (serverChallenge1 == serverChallenge2) {
		setverdict(fail, "Server challenges are not unique");
		f_rsp_client_cleanup();
		return;
	}

	ext_logInfo("Test passed - Transaction IDs and server challenges are unique");
	f_rsp_client_cleanup();
	setverdict(pass);
}

/* Test handler for TC_SM-DP+_ES9+.InitiateAuthenticationNIST - Test Sequence #03 Invalid Server Address */
private function f_TC_InitiateAuth_03_InvalidServerAddress(charstring id) runs on smdpp_ConnHdlr {
	ext_logInfo("=== Test Case: InitiateAuthentication - Invalid Server Address Error ===");

	/* Initialize HTTP/TLS and RSP client */
	f_init_es9plus();

	/* Create request with invalid server address */
	var RemoteProfileProvisioningRequest authRequest := f_create_initiate_authentication_request();
	authRequest.initiateAuthenticationRequest.smdpAddress := "unknown.server.invalid";

	/* Send request expecting an error response */
	var JSON_ESx_FunctionExecutionStatusCodeData errorData := f_es9p_transceive_error(authRequest);

	/* Verify error codes: Subject Code 8.8.1 Reason Code 3.8 */
	f_validate_error_response(errorData, "8.8.1", "3.8", "Invalid server address test");

	ext_logInfo("Test passed - Correct error codes received for invalid server address");
	ext_logInfo("Subject Code: " & errorData.subjectCode & ", Reason Code: " & errorData.reasonCode);
	ext_logInfo("Error message: " & errorData.message_);

	f_rsp_client_cleanup();
	setverdict(pass);
}

// TC_SM-DP+_ES9+.AuthenticateClientNIST_01_Nominal
private function f_TC_AuthenticateClient_01_Nominal(charstring id) runs on smdpp_ConnHdlr {
	var AuthClientSuccessTestParams params := {
		testName := "AuthenticateClient - Nominal",
		stepDescription := "AuthenticateClient",
		matchingId := omit,  /* Use default */
		expectCcRequired := false,
		successMessage := "AuthenticateClient nominal flow successful"
	};
	f_test_authenticateClient_success(params, id);
}

// TC_SM-DP+_ES9+.AuthenticateClientNIST_02_ConfirmationCode
private function f_TC_AuthenticateClient_02_ConfirmationCode(charstring id) runs on smdpp_ConnHdlr {
	var AuthClientSuccessTestParams params := {
		testName := "AuthenticateClient - Confirmation Code Required",
		stepDescription := "AuthenticateClient with CC_REQUIRED_TEST matchingId",
		matchingId := "CC_REQUIRED_TEST",
		expectCcRequired := true,
		successMessage := "Confirmation code required flag is set as expected"
	};
	f_test_authenticateClient_success(params, id);
}

// TC_SM-DP+_ES9+.AuthenticateClientNIST_03_Mismatched_Transaction_ID
private function f_TC_AuthenticateClient_03_Mismatched_Transaction_ID(charstring id) runs on smdpp_ConnHdlr {
	var octetstring wrongTransactionId := f_rnd_octstring(16);  /* Random wrong ID */
	var AuthClientErrorTestParams params := {
		testName := "AuthenticateClient - Mismatched Transaction ID",
		stepDescription := "AuthenticateClient with wrong transaction ID in signed data",
		matchingId := omit,  /* Will be provisioned dynamically */
		transactionIdOverride := wrongTransactionId,
		expectedSubjectCode := "8.10.1",
		expectedReasonCode := "3.9",
		errorDescription := "Unknown/Invalid Transaction ID"
	};
	f_test_authenticateClient_error(params, id);
}

private function f_test_getBoundProfilePackage_generic(
    GetBPPTestParams params,
    charstring id
) runs on smdpp_ConnHdlr {
    ext_logInfo(params.testName);

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    /* retry scenarios */
    var octetstring saved_euicc_otpk;
    var octetstring first_smdp_otpk;

    /* number of iterations based on test mode */
    var integer iterations := 1;
    if (params.testMode == BPP_RETRY_SAME_OTPK or params.testMode == BPP_RETRY_DIFFERENT_OTPK) {
        iterations := 2;
    }

    for (var integer iter := 0; iter < iterations; iter := iter + 1) {
        if (iter > 0) {
            ext_logInfo("=== Performing retry (iteration " & int2str(iter + 1) & ") ===");
        }

        /* Step 1: InitiateAuthentication */
        var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();

        /* Step 2: AuthenticateClient */
        ext_logInfo("Step 2: AuthenticateClient");
        var EUICCInfo2 euiccInfo2 := valueof(ts_EUICCInfo2);
        f_set_euicc_pkids(euiccInfo2);

        /* Provision profile dynamically */
        var charstring provisionedMatchingId := f_provision_simple_profile();

        var CtxParams1 ctxParams := valueof(ts_ctxParams1);
        ctxParams.ctxParamsForCommonAuthentication.matchingId := provisionedMatchingId;

        var EuiccSigned1 euiccSigned1 := f_create_euicc_signed1(euiccInfo2, ctxParams);
        var octetstring euiccSigned1_raw := enc_EuiccSigned1(euiccSigned1);
        var octetstring euiccSignature1 := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, euiccSigned1_raw);

        var Certificate g_euicc_cert := dec_Certificate(ext_RSPClient_getEUICCCertificate(g_rsp_client_handle_es9p));
        var Certificate g_eum_cert := dec_Certificate(ext_RSPClient_getEUMCertificate(g_rsp_client_handle_es9p));

        var RemoteProfileProvisioningRequest authReq := {
            authenticateClientRequest := {
                transactionId := g_transactionId,
                authenticateServerResponse := {
                    authenticateResponseOk := {
                        euiccSigned1 := euiccSigned1,
                        euiccSignature1 := euiccSignature1,
                        euiccCertificate := g_euicc_cert,
                        eumCertificate := g_eum_cert
                    }
                }
            }
        };

        var RemoteProfileProvisioningResponse authResp := f_es9p_transceive_success(authReq);
        var AuthenticateClientOk authClientOk := authResp.authenticateClientResponseEs9.authenticateClientOk;

        /* Step 3: GetBoundProfilePackage */
        ext_logInfo("Step 3: GetBoundProfilePackage");

        var RemoteProfileProvisioningRequest packageReq;
        var PrepareDownloadResponse prepDownloadResp;

        if (params.testMode == BPP_PREPARATION_ERROR) {
            prepDownloadResp := {
                downloadResponseError := {
                    transactionId := g_transactionId,
                    downloadErrorCode := params.prepErrorCode
                }
            };
        } else {
            var octetstring euicc_otpk;

            if (params.testMode == BPP_RETRY_SAME_OTPK and iter == 0) {
                /* First iteration: generate and save OTPK */
                euicc_otpk := ext_RSPClient_generateEUICCOtpk(g_rsp_client_handle_es9p);
                saved_euicc_otpk := euicc_otpk;
                ext_logInfo("Generated and saved eUICC OTPK: " & oct2str(euicc_otpk));
            } else if (params.testMode == BPP_RETRY_SAME_OTPK and iter == 1) {
                /* Second iteration: reuse saved OTPK */
                euicc_otpk := saved_euicc_otpk;
                ext_logInfo("Reusing saved eUICC OTPK: " & oct2str(euicc_otpk));
            } else {
                /* Generate new OTPK for all other cases */
                euicc_otpk := ext_RSPClient_generateEUICCOtpk(g_rsp_client_handle_es9p);
                if (params.testMode == BPP_RETRY_DIFFERENT_OTPK and iter == 1) {
                    ext_logInfo("Generated new eUICC OTPK for retry: " & oct2str(euicc_otpk));
                }
            }

            prepDownloadResp := f_create_prepare_download_response_with_otpk(
                authClientOk.smdpSignature2, euicc_otpk);
        }

        packageReq := {
            getBoundProfilePackageRequest := {
                transactionId := g_transactionId,
                prepareDownloadResponse := prepDownloadResp
            }
        };

        if (params.testMode == BPP_PREPARATION_ERROR) {
            var DecodedRPPReponse_Wrap response := f_es9p_transceive_wrap(packageReq);
            if (ispresent(response.err)) {
                var JSON_ESx_FunctionExecutionStatusCodeData errorData := response.err;
                ext_logInfo("Received expected error response");
                ext_logInfo("Subject Code: " & errorData.subjectCode);
                ext_logInfo("Reason Code: " & errorData.reasonCode);
                setverdict(pass, "Server correctly handled PrepareDownloadResponse error");
            } else {
                setverdict(fail, "Expected error response but got success response");
            }
            f_rsp_client_cleanup();
            return;
        } else {
            var RemoteProfileProvisioningResponse packageResp := f_es9p_transceive_success(packageReq);
            var GetBoundProfilePackageOk packageOk := packageResp.getBoundProfilePackageResponse.getBoundProfilePackageOk;

            if (packageOk.transactionId != g_transactionId) {
                setverdict(fail, "Transaction ID mismatch in GetBoundProfilePackage response");
                f_shutdown(__FILE__, __LINE__);
            }

            var BoundProfilePackage bpp := packageOk.boundProfilePackage;

            if (not ispresent(bpp.initialiseSecureChannelRequest)) {
                setverdict(fail, "Missing initialiseSecureChannelRequest in BoundProfilePackage");
                f_shutdown(__FILE__, __LINE__);
            }

            if (not ispresent(bpp.firstSequenceOf87) or lengthof(bpp.firstSequenceOf87) == 0) {
                setverdict(fail, "Missing or empty firstSequenceOf87 in BoundProfilePackage");
                f_shutdown(__FILE__, __LINE__);
            }

            /* OTPK for retry */
            var InitialiseSecureChannelRequest iscReq := bpp.initialiseSecureChannelRequest;
            var octetstring smdp_otpk := iscReq.smdpOtpk;

            if (iter == 0 and iterations == 2) {
                /* First iteration of retry test: save SM-DP+ OTPK */
                first_smdp_otpk := smdp_otpk;
                ext_logInfo("First SM-DP+ OTPK: " & oct2str(first_smdp_otpk));
                /* Simulate session cancellation */
                ext_logInfo("=== Simulating session cancellation ===");
            } else if (iter == 1) {
                /* Second iteration: compare SM-DP+ OTPK */
                ext_logInfo("Retry SM-DP+ OTPK: " & oct2str(smdp_otpk));

                if (params.testMode == BPP_RETRY_SAME_OTPK) {
                    if (smdp_otpk == first_smdp_otpk) {
                        ext_logInfo("PASS: SM-DP+ OTPK matches - retry with same challenge accepted");
                        setverdict(pass);
                    } else {
                        setverdict(fail, "SM-DP+ OTPK does not match - expected same value on retry");
                    }
                } else if (params.testMode == BPP_RETRY_DIFFERENT_OTPK) {
                    if (smdp_otpk != first_smdp_otpk) {
                        ext_logInfo("PASS: SM-DP+ OTPK is different - new session established");
                        setverdict(pass);
                    } else {
                        setverdict(fail, "SM-DP+ OTPK is the same - expected different value for new session");
                    }
                }
            } else if (params.testMode == BPP_NOMINAL) {
                /* Nominal case: just log success */
                ext_logInfo("Test passed - GetBoundProfilePackage nominal flow successful");
                ext_logInfo("BoundProfilePackage contains " & int2str(lengthof(bpp.firstSequenceOf87)) & " segments");
                setverdict(pass);
            }
        }
    }

    f_rsp_client_cleanup();
}

/* Test Cases for GetBoundProfilePackage Operation */

// TC_SM-DP+_ES9+.GetBoundProfilePackageNIST_01_Nominal
private function f_TC_GetBoundProfilePackage_01_Nominal(charstring id) runs on smdpp_ConnHdlr {
	var GetBPPTestParams params := {
		testName := "=== Test Case: GetBoundProfilePackage - Nominal ===",
		testMode := BPP_NOMINAL,
		prepErrorCode := omit
	};
	f_test_getBoundProfilePackage_generic(params, id);
}

/* GetBoundProfilePackage retry with same otPK.eUICC.ECKA // SGP.23 Section 4.3.13.2.4 Test Sequence #01 */
private function f_TC_GetBoundProfilePackage_02_Retry_Same_Challenge(charstring id) runs on smdpp_ConnHdlr {
	var GetBPPTestParams params := {
		testName := "=== Test Case: GetBoundProfilePackage - Retry with Same Challenge ===",
		testMode := BPP_RETRY_SAME_OTPK,
		prepErrorCode := omit
	};
	f_test_getBoundProfilePackage_generic(params, id);
}

/* GetBoundProfilePackage retry with different otPK.eUICC.ECKA // SGP.23 Section 4.3.13.2.7 Test Sequence #01 */
private function f_TC_GetBoundProfilePackage_03_Retry_Different_Challenge(charstring id) runs on smdpp_ConnHdlr {
	var GetBPPTestParams params := {
		testName := "=== Test Case: GetBoundProfilePackage - Retry with Different Challenge ===",
		testMode := BPP_RETRY_DIFFERENT_OTPK,
		prepErrorCode := omit
	};
	f_test_getBoundProfilePackage_generic(params, id);
}

/* GetBoundProfilePackage with preparation error //  SGP.23 GetBoundProfilePackage error cases */
private function f_TC_GetBoundProfilePackage_04_Preparation_Error(charstring id) runs on smdpp_ConnHdlr {
	var GetBPPTestParams params := {
		testName := "=== Test Case: GetBoundProfilePackage - Preparation Error ===",
		testMode := BPP_PREPARATION_ERROR,
		prepErrorCode := 127  /* undefinedError */
	};
	f_test_getBoundProfilePackage_generic(params, id);
}

private function f_test_getBoundProfilePackage_PPK_generic(
    charstring testName,
    boolean requireCC,
    boolean splitMetadata,
    charstring id
) runs on smdpp_ConnHdlr {
	ext_logInfo(testName);

	/* Initialize HTTP/TLS and RSP client */
	f_init_es9plus()

	if (requireCC) {
		g_pars_smdpp.cc_required := true;
	}
	if (splitMetadata) {
		g_pars_smdpp.metadata_segments := 2;
	}

	/* Step 1: InitiateAuthentication */
	var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();

	/* Step 2: AuthenticateClient */
	ext_logInfo("Step 2: AuthenticateClient");
	var AuthenticateClientOk authClientOk := f_perform_authenticate_client_standard();

	/* Step 3: GetBoundProfilePackage with PPK */
	ext_logInfo("Step 3: GetBoundProfilePackage with PPK");

	var RemoteProfileProvisioningRequest packageReq;

	if (requireCC) {
		var octetstring euiccOtpk := ext_RSPClient_generateEUICCOtpk(g_rsp_client_handle_es9p);

		var EUICCSigned2 euiccSigned2 := {
			transactionId := g_transactionId,
			euiccOtpk := euiccOtpk,
			hashCc := ext_RSPClient_getConfirmationCodeHash(g_rsp_client_handle_es9p)
		};

		var octetstring euiccSigned2Data := enc_EUICCSigned2(euiccSigned2);
		var octetstring concatdata := euiccSigned2Data & authClientOk.smdpSignature2;
		var octetstring euiccSignature2 := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, concatdata);

		var PrepareDownloadResponse prepDownloadResp := {
			downloadResponseOk := {
				euiccSigned2 := euiccSigned2,
				euiccSignature2 := euiccSignature2
			}
		};

		packageReq := {
			getBoundProfilePackageRequest := {
				transactionId := g_transactionId,
				prepareDownloadResponse := prepDownloadResp
			}
		};
	} else {
		packageReq := f_create_get_bound_profile_package_request(authClientOk.smdpSignature2);
	}

	var RemoteProfileProvisioningResponse packageResp := f_es9p_transceive_success(packageReq);

	var GetBoundProfilePackageOk packageOk := packageResp.getBoundProfilePackageResponse.getBoundProfilePackageOk;

	if (packageOk.transactionId != g_transactionId) {
		setverdict(fail, "Transaction ID mismatch in GetBoundProfilePackage response");
		f_shutdown(__FILE__, __LINE__);
	}

	var BoundProfilePackage bpp := packageOk.boundProfilePackage;

	if (not ispresent(bpp.initialiseSecureChannelRequest)) {
		setverdict(fail, "Missing initialiseSecureChannelRequest in BoundProfilePackage");
		f_shutdown(__FILE__, __LINE__);
	}

	if (not ispresent(bpp.firstSequenceOf87) or lengthof(bpp.firstSequenceOf87) == 0) {
		setverdict(fail, "Missing or empty firstSequenceOf87 in BoundProfilePackage");
		f_shutdown(__FILE__, __LINE__);
	}

	if (splitMetadata) {
		if (lengthof(bpp.sequenceOf88) < 2) {
			setverdict(fail, "Expected metadata split over 2 segments but got " & int2str(lengthof(bpp.sequenceOf88)));
			f_shutdown(__FILE__, __LINE__);
		}
		ext_logInfo("Metadata is split over " & int2str(lengthof(bpp.sequenceOf88)) & " segments");
	}

	/* Note: PPK verification would require BSP processing */
	if (requireCC) {
		ext_logInfo("PPK test with confirmation code completed successfully");
		ext_logInfo("Server accepted confirmation code and returned BoundProfilePackage");
	} else if (splitMetadata) {
		ext_logInfo("PPK test with metadata split completed successfully");
		ext_logInfo("Server returned BoundProfilePackage with metadata split over multiple segments");
	} else {
		ext_logInfo("PPK test scenario completed - server returned BoundProfilePackage");
		ext_logInfo("Note: Detailed PPK verification requires BSP segment processing");
	}

	ext_logInfo("Test passed - " & testName & " successful");

	f_rsp_client_cleanup();
	setverdict(pass);
}

/* GetBoundProfilePackage using PPK without Confirmation Code // SGP.23 Section 4.3.13.2.2 Test Sequence #03 */
private function f_TC_GetBoundProfilePackage_PPK_NoCC(charstring id) runs on smdpp_ConnHdlr {
	f_test_getBoundProfilePackage_PPK_generic(
		"=== Test Case: GetBoundProfilePackage - PPK without Confirmation Code ===",
		false,  /* requireCC */
		false,  /* splitMetadata */
		id
	);
}

/* GetBoundProfilePackage using PPK with Confirmation Code // SGP.23 Section 4.3.13.2.2 Test Sequence #04 */
private function f_TC_GetBoundProfilePackage_PPK_WithCC(charstring id) runs on smdpp_ConnHdlr {
	f_test_getBoundProfilePackage_PPK_generic(
		"=== Test Case: GetBoundProfilePackage - PPK with Confirmation Code ===",
		true,   /* requireCC */
		false,  /* splitMetadata */
		id
	);
}

/* GetBoundProfilePackage using PPK with Metadata split // SGP.23 Section 4.3.13.2.2 Test Sequence #06 */
private function f_TC_GetBoundProfilePackage_PPK_MetadataSplit(charstring id) runs on smdpp_ConnHdlr {
	f_test_getBoundProfilePackage_PPK_generic(
		"=== Test Case: GetBoundProfilePackage - PPK with Metadata Split ===",
		false,  /* requireCC */
		true,   /* splitMetadata */
		id
	);
}

private function f_TC_AuthenticateClient_RetryCases_Reuse_OTPK(charstring id) runs on smdpp_ConnHdlr {

    ext_logInfo("=== Testing AuthenticateClient Retry After Cancelled Session ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    /* Step 1: First session - will be cancelled */
    ext_logInfo("Step 1: Starting first session (to be cancelled)");

    var InitiateAuthenticationOkEs9 initAuthResp1;
    initAuthResp1 := f_initiate_authentication_and_validate();
    var octetstring transactionId1 := initAuthResp1.transactionId;
    ext_logInfo("First session transaction ID: " & oct2str(transactionId1));

    var AuthenticateClientOk authClientResp1;
    authClientResp1 := f_perform_authenticate_client_standard();

    ext_logInfo("Cancelling first session");
    f_cancelSession(transactionId1, objid { joint_iso_itu_t 999 10 });

    /* Step 2: Retry with new session */
    ext_logInfo("Step 2: Starting retry session");

    var InitiateAuthenticationOkEs9 initAuthResp2;
    initAuthResp2 := f_initiate_authentication_and_validate();
    var octetstring transactionId2 := initAuthResp2.transactionId;
    ext_logInfo("Retry session transaction ID: " & oct2str(transactionId2));

    if (transactionId1 == transactionId2) {
        setverdict(fail, "Expected different transaction ID for retry session");
        f_rsp_client_cleanup();
        return;
    }

    var AuthenticateClientOk authClientResp2;
    authClientResp2 := f_perform_authenticate_client_standard();

    if (not ispresent(authClientResp2.transactionId)) {
        setverdict(fail, "AuthenticateClient retry failed - no transaction ID");
        f_rsp_client_cleanup();
        return;
    }

    ext_logInfo("AuthenticateClient retry successful");

    ext_logInfo("Step 3: Testing GetBoundProfilePackage with OTPK reuse");

    /* simulate reuse from cancelled session */
    var octetstring euicc_otpk := ext_RSPClient_generateEUICCOtpk(g_rsp_client_handle_es9p);

    var octetstring smdpSignature2 := authClientResp2.smdpSignature2;
    var PrepareDownloadResponse prepDownloadResp := f_create_prepare_download_response_with_otpk(smdpSignature2, euicc_otpk);

    var RemoteProfileProvisioningRequest getBppReq := {
        getBoundProfilePackageRequest := {
            transactionId := g_transactionId,
            prepareDownloadResponse := prepDownloadResp
        }
    };

    var RemoteProfileProvisioningResponse resp := f_es9p_transceive_success(getBppReq);
    var GetBoundProfilePackageResponse getBppResp := resp.getBoundProfilePackageResponse;

    if (not ispresent(getBppResp.getBoundProfilePackageOk)) {
        setverdict(fail, "GetBoundProfilePackage failed in retry scenario");
        f_rsp_client_cleanup();
        return;
    }

    ext_logInfo("Complete retry flow successful");
    setverdict(pass);
    f_rsp_client_cleanup();
}

private function f_perform_session_through_getBoundProfilePackage(
    charstring matchingId := ""  /* Empty string will trigger dynamic provisioning */
) runs on smdpp_ConnHdlr return GetBoundProfilePackageOk {
    /* Provision profile dynamically if matchingId not provided */
    if (matchingId == "") {
        matchingId := f_provision_simple_profile();
    }

    var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();
    var RemoteProfileProvisioningRequest authClientReq := f_create_authenticate_client_request(matchingId);
    var RemoteProfileProvisioningResponse authClientResp := f_es9p_transceive_success(authClientReq);
    var AuthenticateClientOk authClientOk := authClientResp.authenticateClientResponseEs9.authenticateClientOk;

    var PrepareDownloadResponse prepDownloadResp := f_create_prepare_download_response(authClientOk.smdpSignature2);
    var RemoteProfileProvisioningRequest packageReq := {
        getBoundProfilePackageRequest := {
            transactionId := g_transactionId,
            prepareDownloadResponse := prepDownloadResp
        }
    };

    var RemoteProfileProvisioningResponse packageResp := f_es9p_transceive_success(packageReq);
    return packageResp.getBoundProfilePackageResponse.getBoundProfilePackageOk;
}

private function f_perform_initial_session_and_cancel(
    CancelSessionReason reason := CSR_END_USER_POSTPONED
) runs on smdpp_ConnHdlr return octetstring {
    /* Perform session setup through GetBoundProfilePackage */
    var GetBoundProfilePackageOk packageOk := f_perform_session_through_getBoundProfilePackage();
    var octetstring smdp_otpk := packageOk.boundProfilePackage.initialiseSecureChannelRequest.smdpOtpk;
    ext_logInfo("Initial SM-DP+ otPK: " & oct2str(smdp_otpk));

    /* Cancel the session */
    var CancelSessionResponse cancelResp := {
        cancelSessionResponseOk := {
            euiccCancelSessionSigned := {
                transactionId := g_transactionId,
                smdpOid := objid { 2 999 10 },
                reason := enum2int(reason)
            },
            euiccCancelSessionSignature := ''O
        }
    };

    var octetstring cancelSignedData := enc_EuiccCancelSessionSigned(cancelResp.cancelSessionResponseOk.euiccCancelSessionSigned);
    cancelResp.cancelSessionResponseOk.euiccCancelSessionSignature := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, cancelSignedData);

    var RemoteProfileProvisioningRequest cancelReq := {
        cancelSessionRequestEs9 := {
            transactionId := g_transactionId,
            cancelSessionResponse := cancelResp
        }
    };

    var DecodedRPPReponse_Wrap response := f_es9p_transceive_wrap(cancelReq);

    if (ispresent(response.err)) {
        setverdict(fail, "CancelSession failed unexpectedly");
    } else {
        ext_logInfo("Session cancelled successfully");
    }

    return smdp_otpk;
}

/* Unified function for all GetBoundProfilePackage retry test cases */
private function f_TC_GetBoundProfilePackage_Retry_Unified(
    charstring id,
    RetryOTPKMode otpk_mode,
    boolean use_ppk,
    boolean with_cc,
    charstring test_description
) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: GetBoundProfilePackage Retry - " & test_description & " ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    ext_logInfo("Step 1: Initial session and cancellation");
    var octetstring initial_smdp_otpk := f_perform_initial_session_and_cancel();

    ext_logInfo("Step 2: Starting retry flow");

    var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();
    var RemoteProfileProvisioningRequest authClientReq := f_create_authenticate_client_request();
    var RemoteProfileProvisioningResponse authClientResp := f_es9p_transceive_success(authClientReq);
    var AuthenticateClientOk authClientOk := authClientResp.authenticateClientResponseEs9.authenticateClientOk;

    if (use_ppk) {
        g_pars_smdpp.use_ppk := true;
    }

    if (with_cc) {
        ext_RSPClient_setConfirmationCode(g_rsp_client_handle_es9p, "12345678");
    }

    /* Step 3: Prepare retry based on OTPK mode */
    var PrepareDownloadResponse prepDownloadResp;
    var charstring otpk_description;

    if (otpk_mode == RETRY_REUSE_SAME_OTPK) {
        /* Reuse OTPK from cancelled session */
        var octetstring euicc_otpk := ext_RSPClient_getEUICCOtpk(g_rsp_client_handle_es9p);
        ext_logInfo("Step 3: GetBoundProfilePackage retry with SAME eUICC otPK");
        ext_logInfo("Reusing SAME eUICC otPK");
        prepDownloadResp := f_create_prepare_download_response_with_otpk(
            authClientOk.smdpSignature2, euicc_otpk);
        otpk_description := "same";
    } else if (otpk_mode == RETRY_SEND_NEW_OTPK) {
        /* Generate new OTPK to simulate eUICC rejection */
        var octetstring euicc_otpk := ext_RSPClient_generateEUICCOtpk(g_rsp_client_handle_es9p);
        ext_logInfo("Step 3: GetBoundProfilePackage retry with NEW eUICC otPK");
        ext_logInfo("Using NEW eUICC otPK");
        prepDownloadResp := f_create_prepare_download_response_with_otpk(
            authClientOk.smdpSignature2, euicc_otpk);
        otpk_description := "new";
    } else {  /* RETRY_OMIT_OTPK */
        /* Don't include otPK - let server generate new one */
        ext_logInfo("Step 3: GetBoundProfilePackage retry without otPK.eUICC.ECKA");
        prepDownloadResp := f_create_prepare_download_response(authClientOk.smdpSignature2);
        otpk_description := "omitted";
    }

    var RemoteProfileProvisioningRequest packageReq := {
        getBoundProfilePackageRequest := {
            transactionId := g_transactionId,
            prepareDownloadResponse := prepDownloadResp
        }
    };

    /* Step 4: Send request and verify response based on OTPK mode */
    if (otpk_mode == RETRY_SEND_NEW_OTPK) {
        /* When eUICC sends new otPK, server may reject or accept with different otPK */
        var DecodedRPPReponse_Wrap response := f_es9p_transceive_wrap(packageReq);

        if (ispresent(response.err)) {
            f_validate_error_response(response.err, "8.2", "3.7", "OTPK mismatch error");
            setverdict(pass, "Server correctly rejected new OTPK");
        } else if (ispresent(response.asn1_pdu)) {
            var GetBoundProfilePackageOk packageOk := response.asn1_pdu.getBoundProfilePackageResponse.getBoundProfilePackageOk;
            var octetstring new_smdp_otpk := packageOk.boundProfilePackage.initialiseSecureChannelRequest.smdpOtpk;

            if (new_smdp_otpk != initial_smdp_otpk) {
                ext_logInfo("Server accepted with DIFFERENT SM-DP+ otPK - correct behavior");
                setverdict(pass);
            } else {
                setverdict(fail, "Server incorrectly reused same SM-DP+ otPK with new eUICC otPK");
            }
        }
    } else {
        var RemoteProfileProvisioningResponse packageResp := f_es9p_transceive_success(packageReq);
        var GetBoundProfilePackageOk packageOk := packageResp.getBoundProfilePackageResponse.getBoundProfilePackageOk;
        var octetstring retry_smdp_otpk := packageOk.boundProfilePackage.initialiseSecureChannelRequest.smdpOtpk;

        if (otpk_mode == RETRY_REUSE_SAME_OTPK) {
            /* When reusing same eUICC otPK, server should reuse same SM-DP+ otPK */
            if (retry_smdp_otpk == initial_smdp_otpk) {
                ext_logInfo("Server correctly reused SAME SM-DP+ otPK");
                setverdict(pass);
            } else {
                setverdict(fail, "Server incorrectly used different SM-DP+ otPK");
            }
        } else {  /* RETRY_OMIT_OTPK */
            /* When omitting eUICC otPK, server should generate new SM-DP+ otPK */
            if (retry_smdp_otpk != initial_smdp_otpk) {
                ext_logInfo("Server correctly used DIFFERENT SM-DP+ otPK");
                setverdict(pass);
            } else {
                setverdict(fail, "Server incorrectly reused same SM-DP+ otPK");
            }
        }
    }

    f_rsp_client_cleanup();
}

private function f_TC_GetBoundProfilePackage_Retry_SameOTPK_Generic(
    charstring id,
    boolean use_ppk,
    boolean with_cc,
    boolean send_new_otpk,
    charstring test_description
) runs on smdpp_ConnHdlr {
    /* Delegate to unified function */
    var RetryOTPKMode otpk_mode;
    if (send_new_otpk) {
        otpk_mode := RETRY_SEND_NEW_OTPK;
    } else {
        otpk_mode := RETRY_REUSE_SAME_OTPK;
    }

    f_TC_GetBoundProfilePackage_Retry_Unified(id, otpk_mode, use_ppk, with_cc, test_description);
}

private function f_TC_GetBoundProfilePackage_Retry_DifferentOTPK_Generic(
    charstring id,
    boolean use_ppk,
    boolean with_cc,
    charstring test_description
) runs on smdpp_ConnHdlr {
    /* Delegate to unified function with RETRY_OMIT_OTPK mode */
    f_TC_GetBoundProfilePackage_Retry_Unified(id, RETRY_OMIT_OTPK, use_ppk, with_cc, test_description);
}

/* Test Sequence #01: Retry with same otPK using S-ENC/S-MAC without CC */
private function f_TC_GetBoundProfilePackage_Retry_01_SameOTPK_SENC_NoCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_SameOTPK_Generic(id, false, false, false,
        "Same OTPK with S-ENC/S-MAC without CC");
}

/* Test Sequence #02: Retry with same otPK using S-ENC/S-MAC with CC */
private function f_TC_GetBoundProfilePackage_Retry_02_SameOTPK_SENC_WithCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_SameOTPK_Generic(id, false, true, false,
        "Same OTPK with S-ENC/S-MAC with CC");
}

/* Test Sequence #03: Retry with same otPK using PPK-ENC/PPK-MAC without CC */
private function f_TC_GetBoundProfilePackage_Retry_03_SameOTPK_PPK_NoCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_SameOTPK_Generic(id, true, false, false,
        "Same OTPK with PPK-ENC/PPK-MAC without CC");
}

/* Test Sequence #04: Retry with same otPK using PPK-ENC/PPK-MAC with CC */
private function f_TC_GetBoundProfilePackage_Retry_04_SameOTPK_PPK_WithCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_SameOTPK_Generic(id, true, true, false,
        "Same OTPK with PPK-ENC/PPK-MAC with CC");
}

/* Test Sequence #05: eUICC rejects with new otPK, S-ENC/S-MAC without CC */
private function f_TC_GetBoundProfilePackage_Retry_05_NewOTPK_SENC_NoCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_SameOTPK_Generic(id, false, false, true,
        "New OTPK rejection with S-ENC/S-MAC without CC");
}

/* Test Sequence #06: eUICC rejects with new otPK, S-ENC/S-MAC with CC */
private function f_TC_GetBoundProfilePackage_Retry_06_NewOTPK_SENC_WithCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_SameOTPK_Generic(id, false, true, true,
        "New OTPK rejection with S-ENC/S-MAC with CC");
}

/* Test Sequence #07: eUICC rejects with new otPK, PPK-ENC/PPK-MAC without CC */
private function f_TC_GetBoundProfilePackage_Retry_07_NewOTPK_PPK_NoCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_SameOTPK_Generic(id, true, false, true,
        "New OTPK rejection with PPK-ENC/PPK-MAC without CC");
}

/* Test Sequence #08: eUICC rejects with new otPK, PPK-ENC/PPK-MAC with CC */
private function f_TC_GetBoundProfilePackage_Retry_08_NewOTPK_PPK_WithCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_SameOTPK_Generic(id, true, true, true,
        "New OTPK rejection with PPK-ENC/PPK-MAC with CC");
}

/* Test Sequence #09: Confirmation Code retry */
private function f_TC_GetBoundProfilePackage_Retry_09_ConfirmationCode(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: GetBoundProfilePackage - Confirmation Code Retry ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();
    var RemoteProfileProvisioningRequest authClientReq := f_create_authenticate_client_request("CC_REQUIRED_TEST");
    var RemoteProfileProvisioningResponse authClientResp := f_es9p_transceive_success(authClientReq);
    var AuthenticateClientOk authClientOk := authClientResp.authenticateClientResponseEs9.authenticateClientOk;

    /* duh */
    if (not authClientOk.smdpSigned2.ccRequiredFlag) {
        setverdict(fail, "Expected ccRequiredFlag to be true for CC_REQUIRED_TEST profile");
        f_rsp_client_cleanup();
        return;
    }

    /* Set transaction ID for confirmation code hash computation */
    ext_logInfo("Setting transaction ID: " & oct2str(g_transactionId));
    var integer result := ext_RSPClient_setTransactionId(g_rsp_client_handle_es9p, g_transactionId);
    if (result != 0) {
        setverdict(fail, "Failed to set transaction ID");
        f_rsp_client_cleanup();
        return;
    }

    /* First attempt with wrong confirmation code */
    ext_logInfo("First attempt with wrong confirmation code");
    ext_RSPClient_setConfirmationCode(g_rsp_client_handle_es9p, "00000000");  /* Wrong code */

    var PrepareDownloadResponse prepDownloadResp := f_create_prepare_download_response(authClientOk.smdpSignature2);
    var RemoteProfileProvisioningRequest packageReq := {
        getBoundProfilePackageRequest := {
            transactionId := g_transactionId,
            prepareDownloadResponse := prepDownloadResp
        }
    };

    var DecodedRPPReponse_Wrap response := f_es9p_transceive_wrap(packageReq);

    if (ispresent(response.err)) {
        f_validate_error_response(response.err, "8.2.7", "3.8", "Wrong confirmation code");
        ext_logInfo("First attempt correctly rejected");
    } else {
        setverdict(fail, "Server accepted wrong confirmation code");
        f_rsp_client_cleanup();
        return;
    }

    /* Second attempt with correct confirmation code */
    ext_logInfo("Second attempt with correct confirmation code");
    ext_RSPClient_setConfirmationCode(g_rsp_client_handle_es9p, "12345678");  /* Correct code */

    prepDownloadResp := f_create_prepare_download_response(authClientOk.smdpSignature2);
    packageReq.getBoundProfilePackageRequest.prepareDownloadResponse := prepDownloadResp;

    var RemoteProfileProvisioningResponse packageResp := f_es9p_transceive_success(packageReq);

    if (ispresent(packageResp.getBoundProfilePackageResponse.getBoundProfilePackageOk)) {
        ext_logInfo("Second attempt with correct CC succeeded");
        setverdict(pass);
    } else {
        setverdict(fail, "Server rejected correct confirmation code on retry");
    }

    f_rsp_client_cleanup();
}

/* Test Sequence #01: Retry without otPK using S-ENC/S-MAC without CC */
private function f_TC_GetBoundProfilePackage_Retry_10_DiffOTPK_SENC_NoCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_DifferentOTPK_Generic(id, false, false,
        "Different OTPK with S-ENC/S-MAC without CC");
}

/* Test Sequence #02: Retry without otPK using S-ENC/S-MAC with CC */
private function f_TC_GetBoundProfilePackage_Retry_11_DiffOTPK_SENC_WithCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_DifferentOTPK_Generic(id, false, true,
        "Different OTPK with S-ENC/S-MAC with CC");
}

/* Test Sequence #03: Retry without otPK using PPK-ENC/PPK-MAC without CC */
private function f_TC_GetBoundProfilePackage_Retry_12_DiffOTPK_PPK_NoCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_DifferentOTPK_Generic(id, true, false,
        "Different OTPK with PPK-ENC/PPK-MAC without CC");
}

/* Test Sequence #04: Retry without otPK using PPK-ENC/PPK-MAC with CC */
private function f_TC_GetBoundProfilePackage_Retry_13_DiffOTPK_PPK_WithCC(charstring id) runs on smdpp_ConnHdlr {
    f_TC_GetBoundProfilePackage_Retry_DifferentOTPK_Generic(id, true, true,
        "Different OTPK with PPK-ENC/PPK-MAC with CC");
}

private function f_TC_CancelSession_After_AuthenticateClient_Generic(
    charstring id,
    integer reason,
    charstring reason_name
) runs on smdpp_ConnHdlr {

	/* Initialize HTTP/TLS and RSP client */
	f_init_es9plus()

	var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();

	ext_logInfo("=== Step 2: AuthenticateClient ===");
	var RemoteProfileProvisioningRequest authClientReq := f_create_authenticate_client_request();
	var RemoteProfileProvisioningResponse authClientResp := f_es9p_transceive_success(authClientReq);

	if (not ischosen(authClientResp.authenticateClientResponseEs9.authenticateClientOk)) {
		setverdict(fail, "AuthenticateClient did not return success response");
		f_rsp_client_cleanup();
		return;
	}
	var AuthenticateClientOk authClientOk := authClientResp.authenticateClientResponseEs9.authenticateClientOk;

	ext_logInfo("=== Step 3: CancelSession - " & reason_name & " ===");

	var CancelSessionResponse cancelResp := {
		cancelSessionResponseOk := {
			euiccCancelSessionSigned := {
				transactionId := g_transactionId,
				smdpOid := objid { 2 999 10 },  /* SM-DP+ OID: 2.999.10 */
				reason := reason
			},
			euiccCancelSessionSignature := ''O
		}
	};

	var octetstring cancelSignedData := enc_EuiccCancelSessionSigned(cancelResp.cancelSessionResponseOk.euiccCancelSessionSigned);
	cancelResp.cancelSessionResponseOk.euiccCancelSessionSignature := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, cancelSignedData);

	var RemoteProfileProvisioningRequest cancelReq := {
		cancelSessionRequestEs9 := {
			transactionId := g_transactionId,
			cancelSessionResponse := cancelResp
		}
	};

	var DecodedRPPReponse_Wrap response := f_es9p_transceive_wrap(cancelReq);

	if (ispresent(response.err)) {
		setverdict(fail, "CancelSession failed with error");
	} else {
		ext_logInfo("CancelSession successful - " & reason_name & " - session terminated");
		setverdict(pass);
	}

	f_rsp_client_cleanup();
}

/* CancelSession after AuthenticateClient - End User Rejection // SGP.23 Section 4.3.16.2.1 Test Sequence #01 */
private function f_TC_CancelSession_After_AuthenticateClient_01_End_User_Rejection(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_AuthenticateClient_Generic(id, 0, "End User Rejection");
}

/* CancelSession after AuthenticateClient - End User Postponed // SGP.23 Section 4.3.16.2.1 Test Sequence #02 */
private function f_TC_CancelSession_After_AuthenticateClient_02_Postponed(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_AuthenticateClient_Generic(id, 1, "End User Postponed");
}

/* CancelSession after AuthenticateClient - Timeout // SGP.23 Section 4.3.16.2.1 Test Sequence #03 */
private function f_TC_CancelSession_After_AuthenticateClient_03_Timeout(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_AuthenticateClient_Generic(id, 2, "Timeout");
}

/* CancelSession after AuthenticateClient - PPR Not Allowed // SGP.23 Section 4.3.16.2.1 Test Sequence #04 */
private function f_TC_CancelSession_After_AuthenticateClient_04_PPR_Not_Allowed(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_AuthenticateClient_Generic(id, 3, "PPR Not Allowed");
}

/* CancelSession after AuthenticateClient - Undefined Reason // SGP.23 Section 4.3.16.2.1 Test Sequence #05 */
private function f_TC_CancelSession_After_AuthenticateClient_05_Undefined_Reason(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_AuthenticateClient_Generic(id, 127, "Undefined Reason");
}

private function f_TC_CancelSession_After_GetBoundProfilePackage_Generic(
    charstring id,
    CancelSessionReason reason
) runs on smdpp_ConnHdlr {

	/* Initialize HTTP/TLS and RSP client */
	f_init_es9plus()

	ext_logInfo("=== Steps 1-3: InitiateAuth, AuthenticateClient, GetBoundProfilePackage ===");
	var GetBoundProfilePackageOk packageOk := f_perform_session_through_getBoundProfilePackage();

	/* Get reason name for logging */
	var charstring reason_name;
	select (reason) {
		case (CSR_END_USER_REJECTION) { reason_name := "End User Rejection"; }
		case (CSR_END_USER_POSTPONED) { reason_name := "End User Postponed"; }
		case (CSR_TIMEOUT) { reason_name := "Timeout"; }
		case (CSR_PPR_NOT_ALLOWED) { reason_name := "PPR Not Allowed"; }
		case (CSR_METADATA_MISMATCH) { reason_name := "Metadata Mismatch"; }
		case (CSR_LOAD_BPP_ERROR) { reason_name := "Load BPP Execution Error"; }
		case (CSR_UNDEFINED_REASON) { reason_name := "Undefined Reason"; }
		case else { reason_name := "Unknown Reason"; }
	}

	ext_logInfo("=== Step 4: CancelSession after GetBoundProfilePackage - " & reason_name & " ===");

	var CancelSessionResponse cancelResp := {
		cancelSessionResponseOk := {
			euiccCancelSessionSigned := {
				transactionId := g_transactionId,
				smdpOid := objid { 2 999 10 },  /* SM-DP+ OID: 2.999.10 */
				reason := enum2int(reason)
			},
			euiccCancelSessionSignature := ''O
		}
	};

	var octetstring cancelSignedData := enc_EuiccCancelSessionSigned(cancelResp.cancelSessionResponseOk.euiccCancelSessionSigned);
	cancelResp.cancelSessionResponseOk.euiccCancelSessionSignature := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, cancelSignedData);

	var RemoteProfileProvisioningRequest cancelReq := {
		cancelSessionRequestEs9 := {
			transactionId := g_transactionId,
			cancelSessionResponse := cancelResp
		}
	};

	var DecodedRPPReponse_Wrap response := f_es9p_transceive_wrap(cancelReq);

	if (ispresent(response.err)) {
		setverdict(fail, "CancelSession failed with error");
	} else {
		ext_logInfo("CancelSession successful after GetBoundProfilePackage - " & reason_name);
		setverdict(pass);
	}

	f_rsp_client_cleanup();
}

/* CancelSession after GetBoundProfilePackage - End User Rejection // SGP.23 Section 4.3.16.2.2 Test Sequence #01 */
private function f_TC_CancelSession_After_GetBoundProfilePackage_01(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_GetBoundProfilePackage_Generic(id, CSR_END_USER_REJECTION);
}

/* CancelSession after GetBoundProfilePackage - End User Postponed // SGP.23 Section 4.3.16.2.2 Test Sequence #02 */
private function f_TC_CancelSession_After_GetBoundProfilePackage_02_Postponed(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_GetBoundProfilePackage_Generic(id, CSR_END_USER_POSTPONED);
}

/* CancelSession after GetBoundProfilePackage - Timeout // SGP.23 Section 4.3.16.2.2 Test Sequence #03 */
private function f_TC_CancelSession_After_GetBoundProfilePackage_03_Timeout(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_GetBoundProfilePackage_Generic(id, CSR_TIMEOUT);
}

/* CancelSession after GetBoundProfilePackage - PPR Not Allowed // SGP.23 Section 4.3.16.2.2 Test Sequence #04 */
private function f_TC_CancelSession_After_GetBoundProfilePackage_04_PPR_Not_Allowed(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_GetBoundProfilePackage_Generic(id, CSR_PPR_NOT_ALLOWED);
}

/* CancelSession after GetBoundProfilePackage - Metadata Mismatch // SGP.23 Section 4.3.16.2.2 Test Sequence #05 */
private function f_TC_CancelSession_After_GetBoundProfilePackage_05_Metadata_Mismatch(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_GetBoundProfilePackage_Generic(id, CSR_METADATA_MISMATCH);
}

/* CancelSession after GetBoundProfilePackage - Load BPP Execution Error // SGP.23 Section 4.3.16.2.2 Test Sequence #06 */
private function f_TC_CancelSession_After_GetBoundProfilePackage_06_Load_BPP_Error(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_GetBoundProfilePackage_Generic(id, CSR_LOAD_BPP_ERROR);
}

/* CancelSession after GetBoundProfilePackage - Undefined Reason // SGP.23 Section 4.3.16.2.2 Test Sequence #07 */
private function f_TC_CancelSession_After_GetBoundProfilePackage_07_Undefined_Reason(charstring id) runs on smdpp_ConnHdlr {
	f_TC_CancelSession_After_GetBoundProfilePackage_Generic(id, CSR_UNDEFINED_REASON);
}


type union CancelSessionErrorInjection {
	TransactionIdError trans_error,
	SignatureError sig_error,
	OidError oid_error
}

type record OidError {
	objid invalid_oid
}

private function f_TC_CancelSession_After_AuthenticateClient_Error_Generic(
    charstring id,
    charstring expected_subject_code,
    charstring expected_reason_code,
    CancelSessionErrorInjection err_injection,
    charstring test_description
) runs on smdpp_ConnHdlr {

	/* Initialize HTTP/TLS and RSP client */
	f_init_es9plus()

	var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();

	ext_logInfo("=== Step 2: AuthenticateClient ===");
	var RemoteProfileProvisioningRequest authClientReq := f_create_authenticate_client_request();
	var RemoteProfileProvisioningResponse authClientResp := f_es9p_transceive_success(authClientReq);
	var AuthenticateClientOk authClientOk := authClientResp.authenticateClientResponseEs9.authenticateClientOk;

	ext_logInfo("=== Step 3: CancelSession with " & test_description & " ===");

	var CancelSessionResponse cancelResp := {
		cancelSessionResponseOk := {
			euiccCancelSessionSigned := {
				transactionId := g_transactionId,
				smdpOid := objid { 2 999 10 },
				reason := 1  /* Postponed */
			},
			euiccCancelSessionSignature := ''O
		}
	};

	if (ischosen(err_injection.trans_error)) {
		if (not err_injection.trans_error.in_json) {
			/* Error in ASN.1 layer */
			if (ispresent(err_injection.trans_error.wrong_transaction_id)) {
				cancelResp.cancelSessionResponseOk.euiccCancelSessionSigned.transactionId := err_injection.trans_error.wrong_transaction_id;
			}
		}
	} else if (ischosen(err_injection.oid_error)) {
		cancelResp.cancelSessionResponseOk.euiccCancelSessionSigned.smdpOid := err_injection.oid_error.invalid_oid;
	}

	var octetstring cancelSignedData := enc_EuiccCancelSessionSigned(cancelResp.cancelSessionResponseOk.euiccCancelSessionSigned);
	cancelResp.cancelSessionResponseOk.euiccCancelSessionSignature := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, cancelSignedData);

	if (ischosen(err_injection.sig_error)) {
		if (err_injection.sig_error.corrupt_signature) {
			/* Corrupt the signature by modifying first few bytes */
			var octetstring sig := cancelResp.cancelSessionResponseOk.euiccCancelSessionSignature;
			if (lengthof(sig) > 0) {
				sig[0] := sig[0] xor4b 'FF'O;
				if (lengthof(sig) > 1) {
					sig[1] := sig[1] xor4b 'FF'O;
				}
				cancelResp.cancelSessionResponseOk.euiccCancelSessionSignature := sig;
			}
		}
	}

	var RemoteProfileProvisioningRequest cancelReq := {
		cancelSessionRequestEs9 := {
			transactionId := g_transactionId,
			cancelSessionResponse := cancelResp
		}
	};

	if (ischosen(err_injection.trans_error) and err_injection.trans_error.in_json) {
		if (ispresent(err_injection.trans_error.wrong_transaction_id)) {
			cancelReq.cancelSessionRequestEs9.transactionId := err_injection.trans_error.wrong_transaction_id;
		}
	}

	var DecodedRPPReponse_Wrap response := f_es9p_transceive_wrap(cancelReq);

	if (ispresent(response.err)) {
		f_validate_error_response(response.err, expected_subject_code, expected_reason_code, test_description);
		setverdict(pass, "CancelSession correctly failed with expected error");
	} else {
		setverdict(fail, "CancelSession succeeded when it should have failed");
	}

	f_rsp_client_cleanup();
}

private function f_TC_CancelSession_After_GetBoundProfilePackage_Error_Generic(
    charstring id,
    charstring expected_subject_code,
    charstring expected_reason_code,
    CancelSessionErrorInjection err_injection,
    charstring test_description
) runs on smdpp_ConnHdlr {

	/* Initialize HTTP/TLS and RSP client */
	f_init_es9plus()

	var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();

	ext_logInfo("=== Step 2: AuthenticateClient ===");
	var RemoteProfileProvisioningRequest authClientReq := f_create_authenticate_client_request();
	var RemoteProfileProvisioningResponse authClientResp := f_es9p_transceive_success(authClientReq);
	var AuthenticateClientOk authClientOk := authClientResp.authenticateClientResponseEs9.authenticateClientOk;

	ext_logInfo("=== Step 3: GetBoundProfilePackage ===");
	var PrepareDownloadResponse prepDownloadResp := f_create_prepare_download_response(authClientOk.smdpSignature2);
	var RemoteProfileProvisioningRequest packageReq := {
		getBoundProfilePackageRequest := {
			transactionId := g_transactionId,
			prepareDownloadResponse := prepDownloadResp
		}
	};

	var RemoteProfileProvisioningResponse packageResp := f_es9p_transceive_success(packageReq);
	var GetBoundProfilePackageOk packageOk := packageResp.getBoundProfilePackageResponse.getBoundProfilePackageOk;

	ext_logInfo("=== Step 4: CancelSession with " & test_description & " ===");

	var CancelSessionResponse cancelResp := {
		cancelSessionResponseOk := {
			euiccCancelSessionSigned := {
				transactionId := g_transactionId,
				smdpOid := objid { 2 999 10 },
				reason := 1  /* Postponed */
			},
			euiccCancelSessionSignature := ''O
		}
	};

	if (ischosen(err_injection.trans_error)) {
		if (not err_injection.trans_error.in_json) {
			/* Error in ASN.1 layer */
			if (ispresent(err_injection.trans_error.wrong_transaction_id)) {
				cancelResp.cancelSessionResponseOk.euiccCancelSessionSigned.transactionId := err_injection.trans_error.wrong_transaction_id;
			}
		}
	} else if (ischosen(err_injection.oid_error)) {
		cancelResp.cancelSessionResponseOk.euiccCancelSessionSigned.smdpOid := err_injection.oid_error.invalid_oid;
	}

	var octetstring cancelSignedData := enc_EuiccCancelSessionSigned(cancelResp.cancelSessionResponseOk.euiccCancelSessionSigned);
	cancelResp.cancelSessionResponseOk.euiccCancelSessionSignature := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, cancelSignedData);

	if (ischosen(err_injection.sig_error)) {
		if (err_injection.sig_error.corrupt_signature) {
			/* Corrupt the signature by modifying first few bytes */
			var octetstring sig := cancelResp.cancelSessionResponseOk.euiccCancelSessionSignature;
			if (lengthof(sig) > 0) {
				sig[0] := sig[0] xor4b 'FF'O;
				if (lengthof(sig) > 1) {
					sig[1] := sig[1] xor4b 'FF'O;
				}
				cancelResp.cancelSessionResponseOk.euiccCancelSessionSignature := sig;
			}
		}
	}

	var RemoteProfileProvisioningRequest cancelReq := {
		cancelSessionRequestEs9 := {
			transactionId := g_transactionId,
			cancelSessionResponse := cancelResp
		}
	};

	if (ischosen(err_injection.trans_error) and err_injection.trans_error.in_json) {
		if (ispresent(err_injection.trans_error.wrong_transaction_id)) {
			cancelReq.cancelSessionRequestEs9.transactionId := err_injection.trans_error.wrong_transaction_id;
		}
	}

	var DecodedRPPReponse_Wrap response := f_es9p_transceive_wrap(cancelReq);

	if (ispresent(response.err)) {
		f_validate_error_response(response.err, expected_subject_code, expected_reason_code, test_description);
		setverdict(pass, "CancelSession correctly failed with expected error");
	} else {
		setverdict(fail, "CancelSession succeeded when it should have failed");
	}

	f_rsp_client_cleanup();
}

/* Individual test functions for CancelSession errors after AuthenticateClient */

/* Unknown Transaction ID in JSON transport layer // SGP.23 Section 4.3.16.2.1 Test Sequence #06 */
private function f_TC_CancelSession_After_AuthenticateClient_Error_06_UnknownTransactionIdJSON(charstring id) runs on smdpp_ConnHdlr {
	var CancelSessionErrorInjection err_inj := {
		trans_error := {
			in_json := true,
			wrong_transaction_id := '00112233445566778899AABBCCDDEEFF'O
		}
	};
	f_TC_CancelSession_After_AuthenticateClient_Error_Generic(id, "8.10.1", "3.9", err_inj, "Unknown Transaction ID in JSON");
}

/* Unknown Transaction ID in ASN.1 CancelSessionResponse // SGP.23 Section 4.3.16.2.1 Test Sequence #07 */
private function f_TC_CancelSession_After_AuthenticateClient_Error_07_UnknownTransactionIdASN1(charstring id) runs on smdpp_ConnHdlr {
	var CancelSessionErrorInjection err_inj := {
		trans_error := {
			in_json := false,
			wrong_transaction_id := '00112233445566778899AABBCCDDEEFF'O
		}
	};
	f_TC_CancelSession_After_AuthenticateClient_Error_Generic(id, "8.10.1", "3.9", err_inj, "Unknown Transaction ID in ASN.1");
}

/* Invalid eUICC Signature // SGP.23 Section 4.3.16.2.1 Test Sequence #08 */
private function f_TC_CancelSession_After_AuthenticateClient_Error_08_InvalidSignature(charstring id) runs on smdpp_ConnHdlr {
	var CancelSessionErrorInjection err_inj := {
		sig_error := {
			corrupt_signature := true
		}
	};
	f_TC_CancelSession_After_AuthenticateClient_Error_Generic(id, "8.1", "6.1", err_inj, "Invalid eUICC Signature");
}

/* Invalid OID // SGP.23 Section 4.3.16.2.1 Test Sequence #09 */
private function f_TC_CancelSession_After_AuthenticateClient_Error_09_InvalidOID(charstring id) runs on smdpp_ConnHdlr {
	var CancelSessionErrorInjection err_inj := {
		oid_error := {
			invalid_oid := objid { 1 2 3 4 5 }  /* Wrong OID */
		}
	};
	f_TC_CancelSession_After_AuthenticateClient_Error_Generic(id, "8.8", "3.10", err_inj, "Invalid OID");
}

/* Individual test functions for CancelSession errors after GetBoundProfilePackage */

/* Unknown Transaction ID in JSON transport layer // SGP.23 Section 4.3.16.2.2 Test Sequence #08 */
private function f_TC_CancelSession_After_GetBoundProfilePackage_Error_08_UnknownTransactionIdJSON(charstring id) runs on smdpp_ConnHdlr {
	var CancelSessionErrorInjection err_inj := {
		trans_error := {
			in_json := true,
			wrong_transaction_id := '00112233445566778899AABBCCDDEEFF'O
		}
	};
	f_TC_CancelSession_After_GetBoundProfilePackage_Error_Generic(id, "8.10.1", "3.9", err_inj, "Unknown Transaction ID in JSON");
}

/* Unknown Transaction ID in ASN.1 CancelSessionResponse // SGP.23 Section 4.3.16.2.2 Test Sequence #09 */
private function f_TC_CancelSession_After_GetBoundProfilePackage_Error_09_UnknownTransactionIdASN1(charstring id) runs on smdpp_ConnHdlr {
	var CancelSessionErrorInjection err_inj := {
		trans_error := {
			in_json := false,
			wrong_transaction_id := '00112233445566778899AABBCCDDEEFF'O
		}
	};
	f_TC_CancelSession_After_GetBoundProfilePackage_Error_Generic(id, "8.10.1", "3.9", err_inj, "Unknown Transaction ID in ASN.1");
}

/* Invalid eUICC Signature // SGP.23 Section 4.3.16.2.2 Test Sequence #10 */
private function f_TC_CancelSession_After_GetBoundProfilePackage_Error_10_InvalidSignature(charstring id) runs on smdpp_ConnHdlr {
	var CancelSessionErrorInjection err_inj := {
		sig_error := {
			corrupt_signature := true
		}
	};
	f_TC_CancelSession_After_GetBoundProfilePackage_Error_Generic(id, "8.1", "6.1", err_inj, "Invalid eUICC Signature");
}

/* Invalid OID // SGP.23 Section 4.3.16.2.2 Test Sequence #11 */
private function f_TC_CancelSession_After_GetBoundProfilePackage_Error_11_InvalidOID(charstring id) runs on smdpp_ConnHdlr {
	var CancelSessionErrorInjection err_inj := {
		oid_error := {
			invalid_oid := objid { 1 2 3 4 5 }  /* Wrong OID */
		}
	};
	f_TC_CancelSession_After_GetBoundProfilePackage_Error_Generic(id, "8.8", "3.10", err_inj, "Invalid OID");
}

private function f_TC_rsp_complete_flow(charstring id) runs on smdpp_ConnHdlr {


	ext_logInfo("Starting complete RSP flow test");

	/* Initialize HTTP/TLS and RSP client */
	f_init_es9plus()

	ext_logInfo("=== Step 1: InitiateAuthentication ===");

	var RemoteProfileProvisioningRequest authRequest := f_create_initiate_authentication_request();
	var RemoteProfileProvisioningResponse authResponse := f_es9p_transceive_success(authRequest);

	if (not f_validate_initiate_authentication_response(authResponse)) {
		setverdict(fail, "InitiateAuthentication validation failed");
		f_rsp_client_cleanup();
		return;
	}


	var boolean pkid_found := false;
	for (var integer i := 0; i < lengthof(authRequest.initiateAuthenticationRequest.euiccInfo1.euiccCiPKIdListForSigning); i := i + 1) {
		if ( authResponse.initiateAuthenticationResponse.initiateAuthenticationOk.euiccCiPKIdToBeUsed == authRequest.initiateAuthenticationRequest.euiccInfo1.euiccCiPKIdListForSigning[i]) {
			pkid_found := true;
		}
	}
	if (not pkid_found) {
		setverdict(fail, "euiccCiPKIdToBeUsed not in requested list");
		return;
	}


	ext_logInfo("=== Step 2x: Authreq ===");

	var EUICCInfo2 euic2 := valueof(ts_EUICCInfo2);
	euic2.euiccCiPKIdListForVerification := f_get_ci_pkids_for_verification();
	euic2.euiccCiPKIdListForSigning := f_get_ci_pkids_for_signing();

	/* Provision profile dynamically */
	var charstring provisionedMatchingId := f_provision_simple_profile();

	var  CtxParams1 ctxpar := valueof(ts_ctxParams1);
	ctxpar.ctxParamsForCommonAuthentication.matchingId := provisionedMatchingId;

	var EuiccSigned1 euiccSig := {
		transactionId := g_transactionId,
		serverAddress := g_pars_smdpp.smdp_server_fqdn,
		serverChallenge := g_serverChallenge,
		euiccInfo2 := euic2,
		ctxParams1 := ctxpar
	}

	var octetstring enc_euicc_tosign := enc_EuiccSigned1(euiccSig);
	var octetstring euiccSignature1 := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, enc_euicc_tosign);
	var AuthenticateServerResponse authresp := {
		authenticateResponseOk := {
			euiccSigned1 := euiccSig,
			euiccSignature1 := euiccSignature1,
			euiccCertificate := dec_Certificate(ext_RSPClient_getEUICCCertificate(g_rsp_client_handle_es9p)),
			eumCertificate := dec_Certificate(ext_RSPClient_getEUMCertificate(g_rsp_client_handle_es9p))
		}
	}

	var RemoteProfileProvisioningRequest rrq := 	valueof(ts_authenticateClientRequest(transactionId := g_transactionId, authenticateServerResponse := authresp));
	var RemoteProfileProvisioningResponse rresp := valueof(f_es9p_client_transceive_new(rrq, tr_authenticateClientResponseEs9));
	var AuthenticateClientOk auok := rresp.authenticateClientResponseEs9.authenticateClientOk;

	if (auok.transactionId != g_transactionId or auok.smdpSigned2.transactionId != g_transactionId) {
		ext_logError("Transaction ID mismatch");
		setverdict(fail, "InitiateAuthentication validation failed");
		f_rsp_client_cleanup();
		return ;
	}

	var octetstring auresp_sigdata := enc_SmdpSigned2(auok.smdpSigned2) & '5f3740'O & euiccSignature1;
	if (not ext_RSPClient_verifyServerSignature( g_rsp_client_handle_es9p, auresp_sigdata, auok.smdpSignature2, enc_Certificate(auok.smdpCertificate))) {
		ext_logError("Server signature validation failed");
		setverdict(fail, "InitiateAuthentication validation failed");
		f_rsp_client_cleanup();
		return;
	}

	if (auok.smdpSigned2.ccRequiredFlag == true) {
		ext_logInfo("Confirmation code is required for this profile");

		ext_logInfo("Setting transaction ID: " & oct2str(auok.transactionId));
		var integer result := ext_RSPClient_setTransactionId(g_rsp_client_handle_es9p, auok.transactionId);
		if (result != 0) {
			ext_logError("Failed to set transaction ID");
		}

		var charstring confirmationCode := "12345678";  // Default test code
		if (ispresent(g_pars_smdpp.confirmation_code)) {
			confirmationCode := g_pars_smdpp.confirmation_code;
		}
		result := ext_RSPClient_setConfirmationCode(g_rsp_client_handle_es9p, confirmationCode);
		if (result != 0) {
			ext_logError("Failed to set confirmation code");
		}
		ext_logInfo("Set confirmation code: " & confirmationCode);

		var octetstring hashCheck := ext_RSPClient_getConfirmationCodeHash(g_rsp_client_handle_es9p);
		ext_logInfo("Confirmation code hash length: " & int2str(lengthof(hashCheck)));
		if (lengthof(hashCheck) == 32) {
			ext_logInfo("Confirmation code hash computed successfully: " & oct2str(hashCheck));
		} else {
			ext_logError("Failed to compute confirmation code hash");
		}
	} else {
		ext_logInfo("Confirmation code is NOT required for this profile");
	}

    var charstring eid := ext_CertificateUtil_getEID(ext_RSPClient_getEUICCCertificate(g_rsp_client_handle_es9p));
    var octetstring eumCert := ext_RSPClient_getEUMCertificate(g_rsp_client_handle_es9p);

    if (not ext_CertificateUtil_validateEIDRange(eid, eumCert)) {
        setverdict(fail, "EID is not within permitted range of EUM certificate");
        f_rsp_client_cleanup();
        return;
    }

	var octetstring dpAuthCert := enc_Certificate(authResponse.initiateAuthenticationResponse.initiateAuthenticationOk.serverCertificate);
	var octetstring dpPbCert := enc_Certificate(auok.smdpCertificate);
	if (not f_validate_certificate_roles(authResponse, auok)) {
		f_fail_and_cleanup("Certificate role validation failed");
		return;
	}

	/* Step 2: GetBoundProfilePackage */
	ext_logInfo("=== Step 2: GetBoundProfilePackage ===");

	var RemoteProfileProvisioningRequest packageRequest := f_create_get_bound_profile_package_request(auok.smdpSignature2);
	var RemoteProfileProvisioningResponse packageResponse := valueof(f_es9p_client_transceive_new(valueof(packageRequest), tr_getBoundProfilePackageResponse));
    var GetBoundProfilePackageOk packageOk := packageResponse.getBoundProfilePackageResponse.getBoundProfilePackageOk;
    var BoundProfilePackage bpp := packageOk.boundProfilePackage;
	var InitialiseSecureChannelRequest iscReq := bpp.initialiseSecureChannelRequest;

	if (not f_validate_get_bound_profile_package_response(packageResponse)) {
		f_fail_and_cleanup("GetBoundProfilePackage validation failed");
		return;
	}

	ext_logInfo("=== Validating BoundProfilePackage structure ===");

	if (not f_validate_initialise_secure_channel_request(iscReq)) {
		f_fail_and_cleanup("InitialiseSecureChannelRequest validation failed");
		return;
	}

	if (not f_validate_ecdh_and_signature(iscReq, auok, packageRequest)) {
		f_fail_and_cleanup("ECDH compatibility and signature validation failed");
		return;
	}

	if (not f_validate_ein_permissions(eid, eumCert)) {
		f_fail_and_cleanup("EIN permission validation failed");
		return;
	}

	ext_logInfo("=== Validating certificate chains ===");

	var octetstring ciCertificate := ext_RSPClient_getCICertificate(g_rsp_client_handle_es9p);

	var octetstring euiccCertDer := ext_RSPClient_getEUICCCertificate(g_rsp_client_handle_es9p);
	if (not ext_CertificateUtil_verifyCertificateChainWithIntermediate(euiccCertDer,
																	   eumCert,
																	   ciCertificate)) {
		setverdict(fail, "eUICC certificate chain validation failed");
		f_rsp_client_cleanup();
		return;
	}

	if (not ext_CertificateUtil_verifyCertificateChainDynamic(dpPbCert,
															g_pars_smdpp.cert_path,
															ciCertificate /* was ciPkid */)) {
		setverdict(fail, "DPpb certificate chain validation failed");
		f_rsp_client_cleanup();
		return;
	}

	ext_logInfo("=== Validating ECDH key agreement and session keys ===");

	var charstring euiccCurve := ext_CertificateUtil_getCurveOID(euiccCertDer);
	var charstring smdpCurve := ext_CertificateUtil_getCurveOID(dpPbCert);

	if (euiccCurve != smdpCurve) {
		setverdict(fail, "eUICC and SM-DP+ certificates use different curves");
		f_rsp_client_cleanup();
		return;
	}
	ext_logInfo("Both certificates use curve: " & euiccCurve);

	var octetstring sharedSecret := ext_RSPClient_computeSharedSecret(g_rsp_client_handle_es9p,
																	iscReq.smdpOtpk);
	if (lengthof(sharedSecret) == 0) {
		setverdict(fail, "Failed to compute ECDH shared secret");
		f_rsp_client_cleanup();
		return;
	}

	ext_logInfo("=== Processing BoundProfilePackage with BSP crypto ===");

	var octetstring encbpp := enc_BoundProfilePackage(bpp);
	var ProcessedBoundProfilePackage processed :=  ext_BSP_processBoundProfilePackage(
	sharedSecret,
	136,  // keyType: AES (0x88)
	16,   // keyLength: 16 bytes
	iscReq.controlRefTemplate.hostId,
	eid,  // Pass EID as string, C++ will convert it
    encbpp
	);

	if (lengthof(processed.configureIsdp) == 0) {
		f_fail_and_cleanup("Failed to decrypt ConfigureISDP");
		return;
	}
	ext_logInfo("ConfigureISDP decrypted successfully, length: " & int2str(lengthof(processed.configureIsdp)));

	if (lengthof(processed.storeMetadata) == 0) {
		f_fail_and_cleanup("Failed to verify StoreMetadata");
		return;
	}
	ext_logInfo("StoreMetadata verified successfully, length: " & int2str(lengthof(processed.storeMetadata)));

	if (lengthof(processed.profileData) == 0) {
		f_fail_and_cleanup("Failed to decrypt profile data");
		return;
	}
	ext_logInfo("Profile data decrypted successfully, length: " & int2str(lengthof(processed.profileData)));

	if (processed.hasReplaceSessionKeys) {
		ext_logInfo("ReplaceSessionKeys present - PPK used for profile decryption");
		if (ispresent(processed.ppkEnc)) {
			ext_logInfo("PPK-ENC: " & oct2str(processed.ppkEnc));
		}
	}

	ext_logInfo("=== Final certificate path validation ===");

	var boolean all_certs_valid := true;

	all_certs_valid := all_certs_valid and
		ext_CertificateUtil_verifyCertificateChainWithIntermediate(euiccCertDer, eumCert, ciCertificate);

	all_certs_valid := all_certs_valid and
		ext_CertificateUtil_verifyCertificateChainDynamic(dpAuthCert, g_pars_smdpp.cert_path, ciCertificate /* was ciPkid */);

	all_certs_valid := all_certs_valid and
		ext_CertificateUtil_verifyCertificateChainDynamic(dpPbCert, g_pars_smdpp.cert_path, ciCertificate /* was ciPkid */);

	if (not all_certs_valid) {
		setverdict(fail, "Complete certificate chain validation failed");
		f_rsp_client_cleanup();
		return;
	}

	ext_logInfo("All BoundProfilePackage validations passed successfully");

	ext_logInfo("Complete RSP flow successful");
	f_rsp_client_cleanup();
	setverdict(pass);
}

private function f_TC_HandleNotification_Generic(
    charstring id,
    boolean success,
    integer error_reason,
    charstring test_description
) runs on smdpp_ConnHdlr {
	ext_logInfo("=== Test Case: HandleNotification - " & test_description & " ===");

	/* Initialize HTTP/TLS and RSP client */
	f_init_es9plus();

	var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();

	ext_logInfo("=== Step 2: AuthenticateClient ===");
	var RemoteProfileProvisioningRequest authClientReq := f_create_authenticate_client_request();
	var RemoteProfileProvisioningResponse authClientResp := f_es9p_transceive_success(authClientReq);
	var AuthenticateClientOk authClientOk := authClientResp.authenticateClientResponseEs9.authenticateClientOk;

	ext_logInfo("=== Step 3: GetBoundProfilePackage ===");
	var PrepareDownloadResponse prepDownloadResp := f_create_prepare_download_response(authClientOk.smdpSignature2);
	var RemoteProfileProvisioningRequest packageRequest := {
		getBoundProfilePackageRequest := {
			transactionId := g_transactionId,
			prepareDownloadResponse := prepDownloadResp
		}
	};
	var RemoteProfileProvisioningResponse packageResponse := f_es9p_transceive_success(packageRequest);

	ext_logInfo("=== Step 4: HandleNotification - " & test_description & " ===");
	var Iccid testIccid := '8901000000123456789F'O;
	var ProfileInstallationResult pir;

	if (success) {
		pir := f_create_profile_installation_result(g_transactionId, true, testIccid);
	} else {
		pir := f_create_profile_installation_result_error(g_transactionId, error_reason);
	}

    var PendingNotification pendingNotif := {
        profileInstallationResult := pir
    };

    f_handleNotification_generic(pendingNotif);

	ext_logInfo("Test passed - HandleNotification " & test_description & " successful");
	f_rsp_client_cleanup();
	setverdict(pass);
}

/* Test HandleNotification - Nominal case */
private function f_TC_HandleNotification_01_Nominal(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, true, 0, "Nominal");
}

/* Test HandleNotification - PIR Error: Invalid Transaction ID */
private function f_TC_HandleNotification_Error_InvalidTransactionId(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 1, "Invalid Transaction ID");
}

/* Test HandleNotification - PIR Error: Incorrect Input Values */
private function f_TC_HandleNotification_Error_IncorrectInputValues(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 2, "Incorrect Input Values");
}

/* Test HandleNotification - PIR Error: Invalid Signature */
private function f_TC_HandleNotification_Error_InvalidSignature(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 3, "Invalid Signature");
}

/* Test HandleNotification - PIR Error: Unsupported CRT Values */
private function f_TC_HandleNotification_Error_UnsupportedCrtValues(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 4, "Unsupported CRT Values");
}

/* Test HandleNotification - PIR Error: Unsupported Remote Operation Type */
private function f_TC_HandleNotification_Error_UnsupportedRemoteOpType(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 5, "Unsupported Remote Operation Type");
}

/* Test HandleNotification - PIR Error: Unsupported Profile Class */
private function f_TC_HandleNotification_Error_UnsupportedProfileClass(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 6, "Unsupported Profile Class");
}

/* Test HandleNotification - PIR Error: SCP03t Structure Error */
private function f_TC_HandleNotification_Error_SCP03tStructureError(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 7, "SCP03t Structure Error");
}

/* Test HandleNotification - PIR Error: SCP03t Security Error */
private function f_TC_HandleNotification_Error_SCP03tSecurityError(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 8, "SCP03t Security Error");
}

/* Test HandleNotification - PIR Error: ICCID Already Exists */
private function f_TC_HandleNotification_Error_IccidAlreadyExists(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 9, "ICCID Already Exists");
}

/* Test HandleNotification - PIR Error: Insufficient Memory */
private function f_TC_HandleNotification_Error_InsufficientMemory(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 10, "Insufficient Memory");
}

/* Test HandleNotification - PIR Error: Install Failed Due To Interruption */
private function f_TC_HandleNotification_Error_InstallInterruption(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 11, "Install Failed Due To Interruption");
}

/* Test HandleNotification - PIR Error: PE Processing Error */
private function f_TC_HandleNotification_Error_PEProcessingError(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 12, "PE Processing Error");
}

/* Test HandleNotification - PIR Error: Data Mismatch */
private function f_TC_HandleNotification_Error_DataMismatch(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 13, "Data Mismatch");
}

/* Test HandleNotification - PIR Error: Invalid NAA Key */
private function f_TC_HandleNotification_Error_InvalidNaaKey(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 14, "Invalid NAA Key");
}

/* Test HandleNotification - PIR Error: PPR Not Allowed */
private function f_TC_HandleNotification_Error_PPRNotAllowed(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 15, "PPR Not Allowed");
}

/* Test HandleNotification - PIR Error: Unknown Error */
private function f_TC_HandleNotification_Error_UnknownError(charstring id) runs on smdpp_ConnHdlr {
	f_TC_HandleNotification_Generic(id, false, 16, "Unknown Error");
}

/* HandleNotification with OtherSignedNotification // SGP.23 Section 4.3.15.2.1 Test Sequence #02 */
private function f_TC_HandleNotification_02_OtherSignedNotification(charstring id) runs on smdpp_ConnHdlr {
	ext_logInfo("=== Test Case: HandleNotification - OtherSignedNotification ===");

	/* Initialize HTTP/TLS and RSP client */
	f_init_es9plus();

	var NotificationMetadata notifMeta := {
		seqNumber := 2,  /* Different sequence number from PIR */
		profileManagementOperation :=  c_notificationEnable,
		notificationAddress := g_pars_smdpp.smdp_server_fqdn,
		iccid := omit  /* No specific ICCID for this test */
	};

	var octetstring encoded := enc_NotificationMetadata(notifMeta);
	var octetstring euicc_signature := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, encoded);

	var OtherSignedNotification otherNotif := {
		tbsOtherNotification := notifMeta,
		euiccNotificationSignature := euicc_signature,
		euiccCertificate := dec_Certificate(ext_RSPClient_getEUICCCertificate(g_rsp_client_handle_es9p)),
		eumCertificate := dec_Certificate(ext_RSPClient_getEUMCertificate(g_rsp_client_handle_es9p))
	};

	var PendingNotification pendingNotif := {
		otherSignedNotification := otherNotif
	};

	f_handleNotification_generic(pendingNotif);
	setverdict(pass);

	f_rsp_client_cleanup();
}

private function f_TC_GetBoundProfilePackage_Error_Generic(
    charstring id,
    charstring expected_subject_code,
    charstring expected_reason_code,
    GetBppErrorInjection err_injection,
    charstring test_description
) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: GetBoundProfilePackage - " & test_description & " ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();
    var RemoteProfileProvisioningRequest authClientReq := f_create_authenticate_client_request();
    var RemoteProfileProvisioningResponse authClientResp := f_es9p_transceive_success(authClientReq);
    var AuthenticateClientOk authClientOk := authClientResp.authenticateClientResponseEs9.authenticateClientOk;

    ext_logInfo("=== Step 3: GetBoundProfilePackage with " & test_description & " ===");

    var octetstring smdpSignature2 := authClientOk.smdpSignature2;
    var octetstring euicc_otpk := ext_RSPClient_generateEUICCOtpk(g_rsp_client_handle_es9p);

    var EUICCSigned2 euiccSigned2 := {
        transactionId := g_transactionId,
        euiccOtpk := euicc_otpk,
        hashCc := omit
    };

    if (ischosen(err_injection.trans_error)) {
        if (not err_injection.trans_error.in_json) {
            /* Error in ASN.1 layer */
            if (ispresent(err_injection.trans_error.wrong_transaction_id)) {
                euiccSigned2.transactionId := err_injection.trans_error.wrong_transaction_id;
            }
        }
    }

    var octetstring euiccSigned2_raw := enc_EUICCSigned2(euiccSigned2);
    var octetstring concatdata := euiccSigned2_raw & smdpSignature2;
    var octetstring euiccSignature2 := ext_RSPClient_signDataWithEUICC(g_rsp_client_handle_es9p, concatdata);

    if (ischosen(err_injection.sig_error)) {
        if (err_injection.sig_error.corrupt_signature) {
            /* Corrupt the signature */
            if (lengthof(euiccSignature2) > 0) {
                euiccSignature2[0] := euiccSignature2[0] xor4b 'FF'O;
            }
        }
    }

    var PrepareDownloadResponse prepDownloadResp := {
        downloadResponseOk := {
            euiccSigned2 := euiccSigned2,
            euiccSignature2 := euiccSignature2
        }
    };

    var RemoteProfileProvisioningRequest packageReq := {
        getBoundProfilePackageRequest := {
            transactionId := g_transactionId,
            prepareDownloadResponse := prepDownloadResp
        }
    };

    if (ischosen(err_injection.trans_error) and err_injection.trans_error.in_json) {
        if (ispresent(err_injection.trans_error.wrong_transaction_id)) {
            packageReq.getBoundProfilePackageRequest.transactionId := err_injection.trans_error.wrong_transaction_id;
        }
    }

    var DecodedRPPReponse_Wrap response := f_es9p_transceive_wrap(packageReq);

    if (ispresent(response.err)) {
        f_validate_error_response(response.err, expected_subject_code, expected_reason_code, test_description);
        setverdict(pass, "GetBoundProfilePackage correctly failed with expected error");
    } else {
        setverdict(fail, "GetBoundProfilePackage succeeded when it should have failed");
    }

    f_rsp_client_cleanup();
}

/* GetBoundProfilePackage Invalid eUICC Signature // SGP.23 Section 4.3.13.2.10 Test Sequence #01 */
private function f_TC_GetBoundProfilePackage_Error_InvalidSignature(charstring id) runs on smdpp_ConnHdlr {
    var GetBppErrorInjection err_inj := {
        sig_error := { corrupt_signature := true }
    };
    f_TC_GetBoundProfilePackage_Error_Generic(id, "8.1", "6.1", err_inj, "Invalid eUICC Signature");
}

/* GetBoundProfilePackage Unknown Transaction ID in JSON // SGP.23 Section 4.3.13.2.10 Test Sequence #03 */
private function f_TC_GetBoundProfilePackage_Error_UnknownTransactionIdJSON(charstring id) runs on smdpp_ConnHdlr {
    var GetBppErrorInjection err_inj := {
        trans_error := {
            in_json := true,
            wrong_transaction_id := '00112233445566778899AABBCCDDEEFF'O
        }
    };
    f_TC_GetBoundProfilePackage_Error_Generic(id, "8.10.1", "3.9", err_inj, "Unknown Transaction ID in JSON");
}

/* GetBoundProfilePackage Unknown Transaction ID in ASN.1 // SGP.23 Section 4.3.13.2.10 Test Sequence #03 */
private function f_TC_GetBoundProfilePackage_Error_UnknownTransactionIdASN1(charstring id) runs on smdpp_ConnHdlr {
    var GetBppErrorInjection err_inj := {
        trans_error := {
            in_json := false,
            wrong_transaction_id := '00112233445566778899AABBCCDDEEFF'O
        }
    };
    f_TC_GetBoundProfilePackage_Error_Generic(id, "8.10.1", "3.9", err_inj, "Unknown Transaction ID in ASN.1");
}

/* GetBoundProfilePackage with S-ENC/S-MAC and Metadata Split // SGP.23 Section 4.3.13.2.1 Test Sequence #05 */
private function f_TC_GetBoundProfilePackage_05_Metadata_Split(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: GetBoundProfilePackage - S-ENC/S-MAC with Metadata Split ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    /* Perform standard flow up to GetBoundProfilePackage */
    var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();
    var RemoteProfileProvisioningRequest authClientReq := f_create_authenticate_client_request();
    var RemoteProfileProvisioningResponse authClientResp := f_es9p_transceive_success(authClientReq);
    var AuthenticateClientOk authClientOk := authClientResp.authenticateClientResponseEs9.authenticateClientOk;

    g_pars_smdpp.metadata_segments := 2;  /* Request metadata split */

    var PrepareDownloadResponse prepDownloadResp := f_create_prepare_download_response(authClientOk.smdpSignature2);
    var RemoteProfileProvisioningRequest packageReq := {
        getBoundProfilePackageRequest := {
            transactionId := g_transactionId,
            prepareDownloadResponse := prepDownloadResp
        }
    };

    var RemoteProfileProvisioningResponse packageResp := f_es9p_transceive_success(packageReq);
    var GetBoundProfilePackageOk packageOk := packageResp.getBoundProfilePackageResponse.getBoundProfilePackageOk;

    /* fixme: check for proper segment structure */
    if (ispresent(packageOk.boundProfilePackage)) {
        ext_logInfo("GetBoundProfilePackage with metadata split successful");
        setverdict(pass);
    } else {
        setverdict(fail, "Failed to get BoundProfilePackage with metadata split");
    }

    f_rsp_client_cleanup();
}

/* Test Case: TC_SM-DP+_ES9+.InitiateAuthenticationNIST - Test Sequence #04 Unsupported Public Key Identifiers */
private function f_TC_InitiateAuth_04_UnsupportedPKID(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: InitiateAuthentication - Unsupported Public Key Identifiers Error ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var RemoteProfileProvisioningRequest authRequest := f_create_initiate_authentication_request();
    /* unsupported PKIDs that server won't recognize */
    authRequest.initiateAuthenticationRequest.euiccInfo1.euiccCiPKIdListForVerification := { 'FFFF'O, 'FFFE'O };
    authRequest.initiateAuthenticationRequest.euiccInfo1.euiccCiPKIdListForSigning := { 'FFFF'O, 'FFFE'O };

    var JSON_ESx_FunctionExecutionStatusCodeData errorData := f_es9p_transceive_error(authRequest);
    f_validate_error_response(errorData, "8.8.2", "3.1", "Unsupported PKID test");

    ext_logInfo("Test passed - Correct error codes received for unsupported PKIDs");
    f_rsp_client_cleanup();
    setverdict(pass);
}

/* Test Case: TC_SM-DP+_ES9+.InitiateAuthenticationNIST - Test Sequence #05 Unsupported Specification Version */
private function f_TC_InitiateAuth_05_UnsupportedVersion(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: InitiateAuthentication - Unsupported Specification Version Error ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    /* version too low */
    ext_logInfo("Testing with SGP.22 version too low (v1.0.0)");
    var RemoteProfileProvisioningRequest authRequestLow := f_create_initiate_authentication_request();
    authRequestLow.initiateAuthenticationRequest.euiccInfo1.svn := '010000'O; /* v1.0.0 */

    var JSON_ESx_FunctionExecutionStatusCodeData errorDataLow := f_es9p_transceive_error(authRequestLow);
    f_validate_error_response(errorDataLow, "8.8.3", "3.1", "Unsupported version (too low) test");

    /* version too high */
    ext_logInfo("Testing with SGP.22 version too high (v3.0.0)");
    var RemoteProfileProvisioningRequest authRequestHigh := f_create_initiate_authentication_request();
    authRequestHigh.initiateAuthenticationRequest.euiccInfo1.svn := '030000'O; /* v3.0.0 */

    var JSON_ESx_FunctionExecutionStatusCodeData errorDataHigh := f_es9p_transceive_error(authRequestHigh);
    f_validate_error_response(errorDataHigh, "8.8.3", "3.1", "Unsupported version (too high) test");

    ext_logInfo("Test passed - Correct error codes received for unsupported versions");
    f_rsp_client_cleanup();
    setverdict(pass);
}

/* Test Case: TC_SM-DP+_ES9+.InitiateAuthenticationNIST - Test Sequence #06 Unavailable Server Auth Certificate */
private function f_TC_InitiateAuth_06_UnavailableServerAuthCert(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: InitiateAuthentication - Unavailable Server Auth Certificate Error ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var RemoteProfileProvisioningRequest authRequest := f_create_initiate_authentication_request();
    /* we need to:
     * 1. Pass the signing PKID check by using a valid NIST CI PKID
     * 2. Fail the verification PKID check by using a BRP CI PKID
     * This way the server recognizes both PKIDs as valid, but doesn't have a chain for verification */
    var octetstring nistCiPkid := ext_hexToBytes("F54172BDF98A95D65CBEB88A38A1C11D800A85C3");
    var octetstring brpCiPkid := ext_hexToBytes("C0BC70BA36929D43B467FF57570530E57AB8FCD8");

    authRequest.initiateAuthenticationRequest.euiccInfo1.euiccCiPKIdListForSigning := { nistCiPkid };
    authRequest.initiateAuthenticationRequest.euiccInfo1.euiccCiPKIdListForVerification := { brpCiPkid };

    var JSON_ESx_FunctionExecutionStatusCodeData errorData := f_es9p_transceive_error(authRequest);

    /* This test expects error 8.8.4/3.7 for "unavailable server auth certificate"
     * The NIST SM-DP+ server will pass the signing PKID check but fail the verification PKID check */

    if (errorData.subjectCode == "8.8.4" and errorData.reasonCode == "3.7") {
        ext_logInfo("Test passed - Received expected 8.8.4/3.7 (unavailable server auth certificate)");
        f_rsp_client_cleanup();
        setverdict(pass);
    } else {
        setverdict(fail, "Unexpected error codes - got " & errorData.subjectCode & "/" & errorData.reasonCode &
                   ", expected 8.8.4/3.7");
        f_rsp_client_cleanup();
    }
}



/* Test Case: TC_SM-DP+_ES9+.InitiateAuthenticationNIST - Test Sequence #07 Nominal eUICC v2.2.1 */
private function f_TC_InitiateAuth_07_Nominal_v221(charstring id) runs on smdpp_ConnHdlr {
    f_initiateAuth_generic(id, '020201'O, "=== Test Case: InitiateAuthentication - Nominal eUICC v2.2.1 ===", "Test passed - InitiateAuthentication successful with v2.2.1");
}

/* Test Case: TC_SM-DP+_ES9+.InitiateAuthenticationNIST - Test Sequence #08 Nominal eUICC v2.2.2 */
private function f_TC_InitiateAuth_08_Nominal_v222(charstring id) runs on smdpp_ConnHdlr {
    f_initiateAuth_generic(id, '020202'O, "=== Test Case: InitiateAuthentication - Nominal eUICC v2.2.2 ===", "Test passed - InitiateAuthentication successful with v2.2.2");
}

/* Test Case: TC_SM-DP+_ES9+.InitiateAuthenticationNIST - Test Sequence #09 Nominal eUICC v2.3 */
private function f_TC_InitiateAuth_09_Nominal_v230(charstring id) runs on smdpp_ConnHdlr {
    f_initiateAuth_generic(id, '020300'O, "=== Test Case: InitiateAuthentication - Nominal eUICC v2.3.0 ===", "Test passed - InitiateAuthentication successful with v2.3.0");
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Activation Code Use Case with CC // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #09 */
private function f_TC_AuthenticateClient_09_ActivationCode_WithCC(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_success({
        testName := "AuthenticateClient - Activation Code Use Case (With CC)",
        stepDescription := "AuthenticateClient with Activation Code use case and CC required",
        matchingId := "AC_WITH_CC",
        expectCcRequired := true,
        successMessage := "AuthenticateClient with activation code and CC requirement successful"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Activation Code Use Case // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #08 */
private function f_TC_AuthenticateClient_08_ActivationCode_NoCC(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_success({
        testName := "AuthenticateClient - Activation Code Use Case (No CC)",
        stepDescription := "AuthenticateClient with Activation Code use case",
        matchingId := "AC_NO_CC",
        expectCcRequired := false,
        successMessage := "AuthenticateClient with activation code successful"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - SM-DS Event No MatchingID // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #05 */
private function f_TC_AuthenticateClient_05_SMDS_NoMatchingID(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_success({
        testName := "AuthenticateClient - SM-DS Event No MatchingID",
        stepDescription := "AuthenticateClient with SM-DS event use case",
        matchingId := omit,  /* No matchingId for SM-DS use case */
        expectCcRequired := omit,
        successMessage := "AuthenticateClient with SM-DS event and no matchingID successful"
    }, id);
}


/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - SM-DS Event With MatchingID // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #06 */
private function f_TC_AuthenticateClient_06_SMDS_WithMatchingID(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_success({
        testName := "AuthenticateClient - SM-DS Event With MatchingID",
        stepDescription := "AuthenticateClient with SM-DS event use case and matchingID",
        matchingId := "EVENT_001",  /* SM-DS EventID (configured in Python server) */
        expectCcRequired := omit,
        successMessage := "AuthenticateClient with SM-DS event and matchingID successful"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Test Sequence #11 // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #11 */
private function f_TC_AuthenticateClient_11_ActivationCode_NotAssociated_NoCC(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_success({
        testName := "AuthenticateClient - Activation Code Not Associated to EID (No CC)",
        stepDescription := "AuthenticateClient with Activation Code not associated to specific EID",
        matchingId := "AC_NO_CC",  /* This profile has associated_eid = None in Python server */
        expectCcRequired := false,
        successMessage := "AuthenticateClient with activation code not associated to EID successful"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Test Sequence #12 // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #12 */
private function f_TC_AuthenticateClient_12_ActivationCode_NotAssociated_WithCC(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_success({
        testName := "AuthenticateClient - Activation Code Not Associated to EID (With CC)",
        stepDescription := "AuthenticateClient with Activation Code not associated to specific EID, CC required",
        matchingId := "AC_WITH_CC",  /* This profile has associated_eid = None in Python server */
        expectCcRequired := true,
        successMessage := "AuthenticateClient with activation code not associated to EID and CC requirement successful"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Test Sequence #14 // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #14 */
private function f_TC_AuthenticateClient_14_DefaultDP_MatchingIdOmitted(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_success({
        testName := "AuthenticateClient - Default SM-DP+ with MatchingId omitted",
        stepDescription := "AuthenticateClient for Default SM-DP+ use case with MatchingId field omitted",
        matchingId := "OMIT",  /* Special value to omit the field entirely */
        expectCcRequired := false,
        successMessage := "AuthenticateClient with omitted MatchingId successful"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Test Sequence #15 // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #15 */
private function f_TC_AuthenticateClient_15_SMDS_MatchingIdOmitted(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_success({
        testName := "AuthenticateClient - SM-DS with MatchingId omitted",
        stepDescription := "AuthenticateClient for SM-DS use case with MatchingId field omitted",
        matchingId := "OMIT",  /* Special value to omit the field entirely */
        expectCcRequired := false,
        successMessage := "AuthenticateClient SM-DS with omitted MatchingId successful"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Test Sequence #16 // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #16 */
private function f_TC_AuthenticateClient_16_SMDS_MatchingIdEmpty(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_success({
        testName := "AuthenticateClient - SM-DS with empty MatchingId",
        stepDescription := "AuthenticateClient for SM-DS use case with empty MatchingId field",
        matchingId := "",  /* Empty string - field present but empty */
        expectCcRequired := false,
        successMessage := "AuthenticateClient SM-DS with empty MatchingId successful"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Test Sequence #17 // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #17 */
private function f_TC_AuthenticateClient_17_ActivationCode_MatchingIdOmitted(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_success({
        testName := "AuthenticateClient - Activation Code with MatchingId omitted",
        stepDescription := "AuthenticateClient for Activation Code use case with MatchingId field omitted",
        matchingId := "OMIT",  /* Special value to omit the field entirely */
        expectCcRequired := false,
        successMessage := "AuthenticateClient Activation Code with omitted MatchingId successful"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Test Sequence #18 // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #18 */
private function f_TC_AuthenticateClient_18_ActivationCode_MatchingIdEmpty(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_success({
        testName := "AuthenticateClient - Activation Code with empty MatchingId",
        stepDescription := "AuthenticateClient for Activation Code use case with empty MatchingId field",
        matchingId := "",  /* Empty string - field present but empty */
        expectCcRequired := false,
        successMessage := "AuthenticateClient Activation Code with empty MatchingId successful"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Test Sequence #19 // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #19 */
private function f_TC_AuthenticateClient_19_Extended_UICC_Capability(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: AuthenticateClient - Extended UICC Capability ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var octetstring serverChallenge := f_performInitiateAuthentication();

    ext_logInfo("Step 2: AuthenticateClient with extended UICC Capability");

    var EUICCInfo2 euiccInfo2 := valueof(ts_EUICCInfo2);
    f_set_euicc_pkids(euiccInfo2);
    euiccInfo2.uiccCapability := '11111111111111111111111111111111'B;  /* totally extended to the max cap bits */

    var RemoteProfileProvisioningRequest authReq := f_buildAuthenticateClientRequest_withEuiccInfo2(
        serverChallenge,
        "OMIT",  /* Default SM-DP+ use case */
        euiccInfo2
    );

    var RemoteProfileProvisioningResponse authResp := f_es9p_transceive_success(authReq);
    var AuthenticateClientOk authClientOk := authResp.authenticateClientResponseEs9.authenticateClientOk;

    f_validateAuthenticateClientResponse(authClientOk);

    ext_logInfo("AuthenticateClient with extended UICC capability successful");
    setverdict(pass);
    f_rsp_client_cleanup();
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Test Sequence #20 // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #20 */
private function f_TC_AuthenticateClient_20_Extended_DeviceInfo(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: AuthenticateClient - Extended DeviceInfo ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var octetstring serverChallenge := f_performInitiateAuthentication();

    ext_logInfo("Step 2: AuthenticateClient with extended DeviceInfo");

    var EUICCInfo2 euiccInfo2 := valueof(ts_EUICCInfo2);
    f_set_euicc_pkids(euiccInfo2);

    var DeviceInfo deviceInfo := {
        tac := '12345678'O,
        deviceCapabilities := {
            gsmSupportedRelease := omit,
            utranSupportedRelease := omit,
            cdma2000onexSupportedRelease := omit,
            cdma2000hrpdSupportedRelease := omit,
            cdma2000ehrpdSupportedRelease := omit,
            eutranEpcSupportedRelease := omit,
            contactlessSupportedRelease := omit,
            rspCrlSupportedVersion := omit,
            nrEpcSupportedRelease := omit,
            nr5gcSupportedRelease := omit,
            eutran5gcSupportedRelease := omit,
            lpaSvn := omit,
            catSupportedClasses := omit,
            euiccFormFactorType := omit,
            deviceAdditionalFeatureSupport := omit
        },
        imei := omit
    };

    var RemoteProfileProvisioningRequest authReq := f_buildAuthenticateClientRequest_withDeviceInfo(
        serverChallenge,
        "OMIT",  /* Default SM-DP+ use case */
        euiccInfo2,
        deviceInfo
    );

    var RemoteProfileProvisioningResponse authResp := f_es9p_transceive_success(authReq);
    var AuthenticateClientOk authClientOk := authResp.authenticateClientResponseEs9.authenticateClientOk;

    f_validateAuthenticateClientResponse(authClientOk);

    ext_logInfo("AuthenticateClient with extended DeviceInfo successful");
    setverdict(pass);
    f_rsp_client_cleanup();
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Test Sequence #21 // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #21 */
private function f_TC_AuthenticateClient_21_Extended_eUICCInfo2(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: AuthenticateClient - Extended eUICCInfo2 ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var octetstring serverChallenge := f_performInitiateAuthentication();

    ext_logInfo("Step 2: AuthenticateClient with extended eUICCInfo2");

    var EUICCInfo2 euiccInfo2 := valueof(ts_EUICCInfo2);
    f_set_euicc_pkids(euiccInfo2);

    euiccInfo2.ts102241Version := '020100'O;  /* v2.1.0 */
    euiccInfo2.globalplatformVersion := '020303'O;  /* v2.3.3 */
    euiccInfo2.rspCapability := '11111111'B;  /* Extended RSP capabilities */
    euiccInfo2.euiccCategory := 1;  /* optional category */
    euiccInfo2.forbiddenProfilePolicyRules := '0001'B;  /* optional forbidden rules */
    euiccInfo2.ppVersion := '010203'O;  /* optional PP version */
    euiccInfo2.sasAcreditationNumber := "SAS123456";  /* optional SAS number */
    euiccInfo2.certificationDataObject := {
        platformLabel := "TestPlatform",
        discoveryBaseURL := "https://discovery.example.com"
    };
    euiccInfo2.treProperties := omit;  /* do we want this? */
    euiccInfo2.treProductReference := omit;  /* do we want this? */
    euiccInfo2.additionalEuiccProfilePackageVersions := omit;  /* do we want this? */

    var RemoteProfileProvisioningRequest authReq := f_buildAuthenticateClientRequest_withEuiccInfo2(
        serverChallenge,
        "OMIT",  /* Default SM-DP+ use case */
        euiccInfo2
    );

    var RemoteProfileProvisioningResponse authResp := f_es9p_transceive_success(authReq);
    var AuthenticateClientOk authClientOk := authResp.authenticateClientResponseEs9.authenticateClientOk;

    /* Validate response */
    f_validateAuthenticateClientResponse(authClientOk);

    ext_logInfo("AuthenticateClient with extended eUICCInfo2 successful");
    setverdict(pass);
    f_rsp_client_cleanup();
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #1 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #1 */
private function f_TC_AuthenticateClient_Error_01_InvalidEUMCert(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: AuthenticateClient - Error: Invalid EUM Certificate ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var octetstring serverChallenge := f_performInitiateAuthentication();

    var template (value) AuthClientErrorInjection err_injection := {
        cert_error := {
            error_type := INVALID_EUM_SIGNATURE,
            cert_path := omit
        }
    };

    g_pars_smdpp.test_name := "Invalid EUM Certificate";
    g_pars_smdpp.expected_subject_code := "8.1.2";
    g_pars_smdpp.expected_reason_code := "6.1";
    g_pars_smdpp.err_injection := valueof(err_injection);

    f_authenticateClient_error_wrapper(id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #2 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #2 */
private function f_TC_AuthenticateClient_Error_02_ExpiredEUMCert(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: AuthenticateClient - Error: Expired EUM Certificate ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var octetstring serverChallenge := f_performInitiateAuthentication();

    var template (value) AuthClientErrorInjection err_injection := {
        cert_error := {
            error_type := EXPIRED_EUM,
            cert_path := omit
        }
    };

    g_pars_smdpp.test_name := "Expired EUM Certificate";
    g_pars_smdpp.expected_subject_code := "8.1.2";
    g_pars_smdpp.expected_reason_code := "6.3";
    g_pars_smdpp.err_injection := valueof(err_injection);

    f_authenticateClient_error_wrapper(id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #3 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #3 */
private function f_TC_AuthenticateClient_Error_03_InvalidEUICCCert(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: AuthenticateClient - Error: Invalid eUICC Certificate ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var octetstring serverChallenge := f_performInitiateAuthentication();

    var template (value) AuthClientErrorInjection err_injection := {
        cert_error := {
            error_type := INVALID_EUICC_SIGNATURE,
            cert_path := omit
        }
    };

    g_pars_smdpp.test_name := "Invalid eUICC Certificate";
    g_pars_smdpp.expected_subject_code := "8.1.3";
    g_pars_smdpp.expected_reason_code := "6.1";
    g_pars_smdpp.err_injection := valueof(err_injection);

    f_authenticateClient_error_wrapper(id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #4 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #4 */
private function f_TC_AuthenticateClient_Error_04_ExpiredEUICCCert(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: AuthenticateClient - Error: Expired eUICC Certificate ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var octetstring serverChallenge := f_performInitiateAuthentication();

    var template (value) AuthClientErrorInjection err_injection := {
        cert_error := {
            error_type := EXPIRED_EUICC,
            cert_path := omit
        }
    };

    g_pars_smdpp.test_name := "Expired eUICC Certificate";
    g_pars_smdpp.expected_subject_code := "8.1.3";
    g_pars_smdpp.expected_reason_code := "6.3";
    g_pars_smdpp.err_injection := valueof(err_injection);

    f_authenticateClient_error_wrapper(id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #7 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #7 */
private function f_TC_AuthenticateClient_Error_07_UnknownCIKey(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: AuthenticateClient - Error: Unknown CI Public Key ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var octetstring serverChallenge := f_performInitiateAuthentication();

    var template (value) AuthClientErrorInjection err_injection := {
        cert_error := {
            error_type := UNKNOWN_CI_KEY,
            cert_path := omit
        }
    };

    g_pars_smdpp.test_name := "Unknown CI Public Key";
    g_pars_smdpp.expected_subject_code := "8.11.1";
    g_pars_smdpp.expected_reason_code := "3.9";
    g_pars_smdpp.err_injection := valueof(err_injection);

    f_authenticateClient_error_wrapper(id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #12 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #12 */
private function f_TC_AuthenticateClient_Error_12_InvalidMatchingID_ActivationCode(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_error({
        testName := "AuthenticateClient - Error: Invalid Matching ID for Activation Code",
        stepDescription := "AuthenticateClient with wrong matchingID for activation code use case",
        matchingId := "WRONG_AC_12345",  /* Invalid activation code */
        expectedSubjectCode := "8.2.6",
        expectedReasonCode := "3.8",
        errorDescription := "Invalid Matching ID for Activation Code test"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #13 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #13 */
private function f_TC_AuthenticateClient_Error_13_InvalidMatchingID_SMDS(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_error({
        testName := "AuthenticateClient - Error: Invalid Matching ID for SM-DS",
        stepDescription := "AuthenticateClient with wrong matchingID for SM-DS event use case",
        matchingId := "EVENT_INVALID_12345",  /* Invalid SM-DS event ID */
        expectedSubjectCode := "8.2.6",
        expectedReasonCode := "3.8",
        errorDescription := "Invalid Matching ID for SM-DS test"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #14 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #14 */
private function f_TC_AuthenticateClient_Error_14_UnmatchedEID_DefaultDP(charstring id) runs on smdpp_ConnHdlr {
    /* Test Sequence #14: Un-matched EID for Default SM-DP+ Address Use Case
     * This test uses a certificate with EID 89049032123451234512345678901299
     * which is
	 * - within the EUM's permitted range
	 * - not in the server's default_profiles.
     * Tests unknown EID tries to use the default SM-DP+ address (no matchingId).
     */

    /* Save original certificate path and use the UNMATCHED_EID certificate */
    var charstring original_cert_path := g_pars_smdpp.euicc_cert_path;
    var charstring original_key_path := g_pars_smdpp.euicc_key_path;
    g_pars_smdpp.euicc_cert_path := "./InvalidTestCases/CERT_EUICC_ECDSA_NIST_UNMATCHED_EID.der";
    /* uses the same private key as the regular NIST cert */
    g_pars_smdpp.euicc_key_path := "./sgp26/eUICC/SK_EUICC_ECDSA_NIST.pem";

    f_test_authenticateClient_error({
        testName := "AuthenticateClient - Error: Un-matched EID for Default SM-DP+",
        stepDescription := "AuthenticateClient with EID not associated with any default profile",
        matchingId := "OMIT",  /* Default SM-DP+ use case - no matchingId */
        expectedSubjectCode := "8.1.1",  /* EID - Per SGP.23 Test Sequence #14 */
        expectedReasonCode := "3.8",     /* Refused */
        errorDescription := "Un-matched EID for Default SM-DP+ test"
    }, id);

    /* Restore original certificate and key paths */
    g_pars_smdpp.euicc_cert_path := original_cert_path;
    g_pars_smdpp.euicc_key_path := original_key_path;
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #15 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #15 */
private function f_TC_AuthenticateClient_Error_15_NoEligibleProfile(charstring id) runs on smdpp_ConnHdlr {
    /* SGP.23 Section 4.3.14.2.2 Test Sequence #15
     * The profile has PPR1 set (disabling not allowed) but the eUICC reports PPR1 as forbidden
     * because an operational profile is already installed */

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    var InitiateAuthenticationOkEs9 authOk := f_initiate_authentication_and_validate();

    ext_logInfo("Step 2: AuthenticateClient with eUICC reporting forbidden PPR1");

    var EUICCInfo2 euiccInfo2 := valueof(ts_EUICCInfo2);
    f_set_euicc_pkids(euiccInfo2);
    /* Set forbiddenProfilePolicyRules to indicate PPR1 is forbidden
     * PPR1 (bit 1) = "Disabling of this Profile is not allowed"
     * This is forbidden when an operational profile is already installed */
    euiccInfo2.forbiddenProfilePolicyRules := '0100'B;  /* PPR1 is bit 1 */

    var CtxParams1 ctxParams := valueof(ts_ctxParams1);
    /* Use AC_PPR1 which has PPR1 set in the profile */
    ctxParams.ctxParamsForCommonAuthentication.matchingId := "AC_PPR1";

    var EuiccSigned1 euiccSigned1 := f_create_euicc_signed1(euiccInfo2, ctxParams);
    var octetstring euiccSignature1 := f_sign_euicc_signed1(euiccSigned1);

    var RemoteProfileProvisioningRequest authReq := f_build_authenticate_client_request(euiccSigned1, euiccSignature1);
    var JSON_ESx_FunctionExecutionStatusCodeData err := f_es9p_transceive_error(authReq);

    f_validate_error_response(err, "8.2.5", "4.3", "No eligible Profile for this eUICC/Device");
    setverdict(pass);

    f_rsp_client_cleanup();
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #16 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #16 */
private function f_TC_AuthenticateClient_Error_16_DownloadOrderExpired(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_error({
        testName := "AuthenticateClient - Error: Download Order Expired",
        stepDescription := "AuthenticateClient with expired download order",
        matchingId := "AC_EXPIRED",  /* Profile with expired download order */
        expectedSubjectCode := "8.8.5",
        expectedReasonCode := "4.10",
        errorDescription := "Download Order Expired test"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #17 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #17 */
private function f_TC_AuthenticateClient_Error_17_MaxRetriesExceeded(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_error({
        testName := "AuthenticateClient - Error: Max Retries Exceeded",
        stepDescription := "AuthenticateClient after maximum download attempts",
        matchingId := "AC_MAX_RETRIES",  /* Profile with exceeded retry count */
        expectedSubjectCode := "8.8.5",
        expectedReasonCode := "6.4",
        errorDescription := "Maximum retries exceeded test"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #19 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #19 */
private function f_TC_AuthenticateClient_Error_19_UnmatchedEID_SMDS(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_error({
        testName := "AuthenticateClient - Error: Un-matched EID for SM-DS",
        stepDescription := "AuthenticateClient with EID not allowed for SM-DS event",
        matchingId := "EVENT_RESTRICTED",  /* SM-DS event restricted to different EID */
        expectedSubjectCode := "8.1.1",
        expectedReasonCode := "3.8",
        errorDescription := "Un-matched EID for SM-DS test"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #20 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #20 */
private function f_TC_AuthenticateClient_Error_20_UnmatchedEID_ActivationCode(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_error({
        testName := "AuthenticateClient - Error: Un-matched EID for Activation Code",
        stepDescription := "AuthenticateClient with EID not allowed for activation code",
        matchingId := "AC_RESTRICTED_EID",  /* Activation code restricted to different EID */
        expectedSubjectCode := "8.1.1",
        expectedReasonCode := "3.8",
        errorDescription := "Un-matched EID for Activation Code test"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Error Test Sequence #21 // SGP.23 v1.15 section 4.3.14.2.2 Test Sequence #21 EID */
private function f_TC_AuthenticateClient_Error_21_InvalidMatchingID_NotAssociatedEID(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_error({
        testName := "AuthenticateClient - Error: Invalid MatchingId for AC not associated to EID",
        stepDescription := "AuthenticateClient with activation code exists but not for this EID",
        matchingId := "AC_OTHER_EID",  /* Valid activation code but for different EID */
        expectedSubjectCode := "8.1.1",  /* When EID mismatch is detected */
        expectedReasonCode := "3.8",
        errorDescription := "Invalid MatchingId for AC not associated to EID test"
    }, id);
}


/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Unmatched MatchingID // SGP.23 v1.15 section 4.3.14.2.2 Error Test Sequence #11 */
private function f_TC_AuthenticateClient_Error_UnmatchedMatchingID(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_error({
        testName := "AuthenticateClient - Error: Unmatched MatchingID",
        stepDescription := "AuthenticateClient with incorrect matchingID",
        matchingId := "WRONG-MATCHING-ID-12345",
        expectedSubjectCode := "8.2.6",
        expectedReasonCode := "3.8",
        errorDescription := "Unmatched MatchingID test"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Profile Not Released // SGP.23 v1.15 section 4.3.14.2.2 Error Test Sequence #8 */
private function f_TC_AuthenticateClient_Error_ProfileNotReleased(charstring id) runs on smdpp_ConnHdlr {
    f_test_authenticateClient_error({
        testName := "AuthenticateClient - Error: Profile Not Released",
        stepDescription := "AuthenticateClient for profile not in released state",
        matchingId := "AC_NOT_RELEASED",  /* Configured in Python server as not released */
        expectedSubjectCode := "8.2",
        expectedReasonCode := "1.2",
        errorDescription := "Profile not released test"
    }, id);
}

/* Test Case: TC_SM-DP+_ES9+.AuthenticateClientNIST - Test Sequence #03 // SGP.23 v1.15 section 4.3.14.2.1 Test Sequence #03 */
private function f_TC_AuthenticateClient_03_SecondAttempt_AfterInvalidMatchingID(charstring id) runs on smdpp_ConnHdlr {
    ext_logInfo("=== Test Case: AuthenticateClient - Second Attempt After Invalid MatchingID ===");

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();

    /* Step IC1: PROC_ES9+_AUTH_CLIENT_FAIL_DEF_DP_USE_CASE_INVALID_MATCHING_ID */
    ext_logInfo("Step IC1: First attempt with activation code matching ID (should fail)");

    var octetstring serverChallenge1 := f_performInitiateAuthentication();

    var RemoteProfileProvisioningRequest authReq1 := f_buildAuthenticateClientRequest(
        serverChallenge1,
        "INVALID-MATCHING-ID-12345"  /* Invalid matching ID that doesn't exist */
    );

    var JSON_ESx_FunctionExecutionStatusCodeData errorData := f_es9p_transceive_error(authReq1);
    f_validate_error_response(errorData, "8.2.6", "3.8", "Invalid MatchingID for default DP+ use case");
    ext_logInfo("First attempt failed as expected with invalid matching ID error");

    /* Step IC2-IC3: New TLS session and InitiateAuthentication */
    ext_logInfo("Step IC2-IC3: Starting new session for retry");

    var octetstring serverChallenge2 := f_performInitiateAuthentication();

    ext_logInfo("Step 1: Second AuthenticateClient with correct parameters (no matchingID)");

    var RemoteProfileProvisioningRequest authReq2 := f_buildAuthenticateClientRequest(
        serverChallenge2,
        "OMIT"  /* Omit matching ID for default DP+ use case */
    );

    var RemoteProfileProvisioningResponse authResp := f_es9p_transceive_success(authReq2);
    var AuthenticateClientOk authClientOk := authResp.authenticateClientResponseEs9.authenticateClientOk;

    f_validateAuthenticateClientResponse(authClientOk);

    ext_logInfo("Test passed - Second attempt succeeded after initial invalid matching ID error");
    f_rsp_client_cleanup();
    setverdict(pass);
}

testcase TC_SM_DP_ES9_InitiateAuthenticationNIST_01_Nominal() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_InitiateAuth_01_Nominal));
}

testcase TC_SM_DP_ES9_InitiateAuthenticationNIST_02_Uniqueness() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_InitiateAuth_02_Uniqueness));
}

testcase TC_SM_DP_ES9_InitiateAuthenticationNIST_03_InvalidServerAddress() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_InitiateAuth_03_InvalidServerAddress));
}

testcase TC_SM_DP_ES9_InitiateAuthenticationNIST_04_UnsupportedPKID() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_InitiateAuth_04_UnsupportedPKID));
}

testcase TC_SM_DP_ES9_InitiateAuthenticationNIST_05_UnsupportedVersion() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_InitiateAuth_05_UnsupportedVersion));
}

testcase TC_SM_DP_ES9_InitiateAuthenticationNIST_06_UnavailableServerAuthCert() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_InitiateAuth_06_UnavailableServerAuthCert));
}

testcase TC_SM_DP_ES9_InitiateAuthenticationNIST_07_Nominal_v221() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_InitiateAuth_07_Nominal_v221));
}

testcase TC_SM_DP_ES9_InitiateAuthenticationNIST_08_Nominal_v222() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_InitiateAuth_08_Nominal_v222));
}

testcase TC_SM_DP_ES9_InitiateAuthenticationNIST_09_Nominal_v230() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_InitiateAuth_09_Nominal_v230));
}

testcase TC_rsp_complete_flow() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_rsp_complete_flow));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_01_Nominal() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_01_Nominal));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_02_ConfirmationCode() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_02_ConfirmationCode));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_Mismatched_Transaction_ID() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_03_Mismatched_Transaction_ID));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_05_SMDS_NoMatchingID() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_05_SMDS_NoMatchingID));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_06_SMDS_WithMatchingID() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_06_SMDS_WithMatchingID));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_08_ActivationCode_NoCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_08_ActivationCode_NoCC));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_09_ActivationCode_WithCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_09_ActivationCode_WithCC));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_11_ActivationCode_NotAssociated_NoCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_11_ActivationCode_NotAssociated_NoCC));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_12_ActivationCode_NotAssociated_WithCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_12_ActivationCode_NotAssociated_WithCC));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_14_DefaultDP_MatchingIdOmitted() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_14_DefaultDP_MatchingIdOmitted));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_15_SMDS_MatchingIdOmitted() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_15_SMDS_MatchingIdOmitted));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_16_SMDS_MatchingIdEmpty() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_16_SMDS_MatchingIdEmpty));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_17_ActivationCode_MatchingIdOmitted() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_17_ActivationCode_MatchingIdOmitted));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_18_ActivationCode_MatchingIdEmpty() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_18_ActivationCode_MatchingIdEmpty));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_19_Extended_UICC_Capability() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_19_Extended_UICC_Capability));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_20_Extended_DeviceInfo() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_20_Extended_DeviceInfo));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_21_Extended_eUICCInfo2() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_21_Extended_eUICCInfo2));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_01_InvalidEUMCert() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_01_InvalidEUMCert));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_02_ExpiredEUMCert() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_02_ExpiredEUMCert));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_03_InvalidEUICCCert() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_03_InvalidEUICCCert));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_04_ExpiredEUICCCert() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_04_ExpiredEUICCCert));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_07_UnknownCIKey() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_07_UnknownCIKey));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_UnmatchedMatchingID() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_UnmatchedMatchingID));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_ProfileNotReleased() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_ProfileNotReleased));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_12_InvalidMatchingID_ActivationCode() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_12_InvalidMatchingID_ActivationCode));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_13_InvalidMatchingID_SMDS() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_13_InvalidMatchingID_SMDS));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_14_UnmatchedEID_DefaultDP() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_14_UnmatchedEID_DefaultDP));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_15_NoEligibleProfile() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_15_NoEligibleProfile));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_16_DownloadOrderExpired() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_16_DownloadOrderExpired));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_17_MaxRetriesExceeded() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_17_MaxRetriesExceeded));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_19_UnmatchedEID_SMDS() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_19_UnmatchedEID_SMDS));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_20_UnmatchedEID_ActivationCode() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_20_UnmatchedEID_ActivationCode));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_21_InvalidMatchingID_NotAssociatedEID() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_Error_21_InvalidMatchingID_NotAssociatedEID));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_03_SecondAttempt_AfterInvalidMatchingID() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_03_SecondAttempt_AfterInvalidMatchingID));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_01_Nominal() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_01_Nominal));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_02_Retry_Same_Challenge() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_02_Retry_Same_Challenge));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_03_Retry_Different_Challenge() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_03_Retry_Different_Challenge));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_04_Preparation_Error() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_04_Preparation_Error));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_InvalidSignature() runs on MTC_CT {
    var charstring id := testcasename();
    var smdpp_ConnHdlrPars pars;
    var smdpp_ConnHdlr vc_conn;

    f_init("Invalid eUICC Signature");
    pars := f_init_pars();
    pars.gbpp_err_injection := { sig_error := { corrupt_signature := true } };
    pars.test_name := "Invalid eUICC Signature";
    pars.expected_subject_code := "8.1";
    pars.expected_reason_code := "6.1";
    pars.cc_required := false;
    vc_conn := f_start_handler(refers(f_getBoundProfilePackage_error_wrapper), pars);
    vc_conn.done;
}

private function TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_UnknownTransactionId_Generic(charstring init_message, boolean in_json) runs on MTC_CT {
    var charstring id := testcasename();
    var smdpp_ConnHdlrPars pars;
    var smdpp_ConnHdlr vc_conn;

    f_init(init_message);
    pars := f_init_pars();
    pars.gbpp_err_injection := { trans_error := { in_json := in_json, wrong_transaction_id := omit } };
    pars.test_name := init_message;
    pars.expected_subject_code := "8.10.1";
    pars.expected_reason_code := "3.9";
    pars.cc_required := false;
    vc_conn := f_start_handler(refers(f_getBoundProfilePackage_error_wrapper), pars);
    vc_conn.done;
}

private function TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_Generic(charstring init_message, boolean omit_cc_, boolean wrong_cc_) runs on MTC_CT {
    var charstring id := testcasename();
    var smdpp_ConnHdlrPars pars;
    var smdpp_ConnHdlr vc_conn;

    f_init(init_message);
    pars := f_init_pars();
    pars.gbpp_err_injection := { cc_error := { omit_cc := omit_cc_, wrong_cc := wrong_cc_, invalid_cc := omit } };
    pars.test_name := init_message;
    pars.expected_subject_code := "8.2.7";
    /*
     * - Missing CC (omit_cc=true): 2.2 (Mandatory Element Missing)
     * - Refused CC (wrong_cc=true): 3.8 (Refused)
     */
    if (omit_cc_) {
        pars.expected_reason_code := "2.2";  /* Missing cc */
    } else if (wrong_cc_) {
        pars.expected_reason_code := "3.8";  /* Refused cc */
    } else {
        pars.expected_reason_code := "2.2";  /* Default */
    }
    /* For both missing CC and wrong CC tests server must require a cc */
    pars.cc_required := true;
    vc_conn := f_start_handler(refers(f_getBoundProfilePackage_error_wrapper), pars);
    vc_conn.done;
}

private function TC_SM_DP_ES9_AuthenticateClientNIST_Error_Generic(boolean in_json) runs on MTC_CT {
    var charstring id := testcasename();
    var smdpp_ConnHdlrPars pars := f_init_pars();
    var smdpp_ConnHdlr vc_conn;
    f_init(id);

    pars.err_injection := {
        trans_error := {
            in_json := in_json,
            wrong_transaction_id := omit
        }
    };
    pars.test_name := "Unknown Transaction ID";
    pars.expected_subject_code := "8.10.1";
    pars.expected_reason_code := "3.9";

    vc_conn := f_start_handler(refers(f_authenticateClient_error_wrapper), pars);
    vc_conn.done;
    setverdict(pass);
}

/* Test Case: Unknown Transaction ID in JSON */
testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_UnknownTransactionIdJSON() runs on MTC_CT {
    TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_UnknownTransactionId_Generic("Unknown Transaction ID in JSON", true);
}

/* Test Case: Unknown Transaction ID in ASN.1 */
testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_UnknownTransactionIdASN1() runs on MTC_CT {
    TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_UnknownTransactionId_Generic("Unknown Transaction ID in ASN.1", false);
}

/* Test Case: Missing Confirmation Code (8.2.7/2.2) */
testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_MissingConfirmationCode() runs on MTC_CT {
    TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_Generic("Missing Confirmation Code", true, false);
}

/* Test Case: Refused Confirmation Code (8.2.7/3.8) */
testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_RefusedConfirmationCode() runs on MTC_CT {
    TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_Generic("Refused Confirmation Code", false, true);
}

/* PPK (Profile Protection Key) GetBoundProfilePackage Test Cases */

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_PPK_NoCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_PPK_NoCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_PPK_WithCC() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars();
    pars.confirmation_code := "12345678";  /* Test confirmation code */
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_GetBoundProfilePackage_PPK_WithCC), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_PPK_MetadataSplit() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_PPK_MetadataSplit));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_01_SameOTPK_SENC_NoCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_01_SameOTPK_SENC_NoCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_02_SameOTPK_SENC_WithCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_02_SameOTPK_SENC_WithCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_03_SameOTPK_PPK_NoCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_03_SameOTPK_PPK_NoCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_04_SameOTPK_PPK_WithCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_04_SameOTPK_PPK_WithCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_05_NewOTPK_SENC_NoCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_05_NewOTPK_SENC_NoCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_06_NewOTPK_SENC_WithCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_06_NewOTPK_SENC_WithCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_07_NewOTPK_PPK_NoCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_07_NewOTPK_PPK_NoCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_08_NewOTPK_PPK_WithCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_08_NewOTPK_PPK_WithCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_09_ConfirmationCode() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_09_ConfirmationCode));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_10_DiffOTPK_SENC_NoCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_10_DiffOTPK_SENC_NoCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_11_DiffOTPK_SENC_WithCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_11_DiffOTPK_SENC_WithCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_12_DiffOTPK_PPK_NoCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_12_DiffOTPK_PPK_NoCC));
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_13_DiffOTPK_PPK_WithCC() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_GetBoundProfilePackage_Retry_13_DiffOTPK_PPK_WithCC));
}

testcase TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_AuthenticateClient_01_End_User_Rejection));
}

testcase TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Postponed() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_AuthenticateClient_02_Postponed));
}

testcase TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Timeout() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_AuthenticateClient_03_Timeout));
}

testcase TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_PPR_Not_Allowed() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_AuthenticateClient_04_PPR_Not_Allowed));
}

testcase TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Undefined_Reason() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_AuthenticateClient_05_Undefined_Reason));
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_GetBoundProfilePackage_01));
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Postponed() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_GetBoundProfilePackage_02_Postponed));
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Timeout() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_GetBoundProfilePackage_03_Timeout));
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_PPR_Not_Allowed() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_GetBoundProfilePackage_04_PPR_Not_Allowed));
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Metadata_Mismatch() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_GetBoundProfilePackage_05_Metadata_Mismatch));
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Load_BPP_Error() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_GetBoundProfilePackage_06_Load_BPP_Error));
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Undefined_Reason() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_GetBoundProfilePackage_07_Undefined_Reason));
}

testcase TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Error_UnknownTransactionIdJSON() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_AuthenticateClient_Error_06_UnknownTransactionIdJSON));
}

testcase TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Error_UnknownTransactionIdASN1() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_AuthenticateClient_Error_07_UnknownTransactionIdASN1));
}

testcase TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Error_InvalidSignature() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_AuthenticateClient_Error_08_InvalidSignature));
}

testcase TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Error_InvalidOID() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_AuthenticateClient_Error_09_InvalidOID));
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Error_UnknownTransactionIdJSON() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_GetBoundProfilePackage_Error_08_UnknownTransactionIdJSON));
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Error_UnknownTransactionIdASN1() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_GetBoundProfilePackage_Error_09_UnknownTransactionIdASN1));
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Error_InvalidSignature() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_GetBoundProfilePackage_Error_10_InvalidSignature));
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Error_InvalidOID() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_CancelSession_After_GetBoundProfilePackage_Error_11_InvalidOID));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_01_Nominal() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_01_Nominal));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_02_OtherSignedNotification() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_02_OtherSignedNotification));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_InvalidTransactionId() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_InvalidTransactionId));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_IncorrectInputValues() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_IncorrectInputValues));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_InvalidSignature() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_InvalidSignature));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_UnsupportedCrtValues() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_UnsupportedCrtValues));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_UnsupportedRemoteOpType() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_UnsupportedRemoteOpType));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_UnsupportedProfileClass() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_UnsupportedProfileClass));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_SCP03tStructureError() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_SCP03tStructureError));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_SCP03tSecurityError() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_SCP03tSecurityError));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_IccidAlreadyExists() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_IccidAlreadyExists));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_InsufficientMemory() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_InsufficientMemory));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_InstallInterruption() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_InstallInterruption));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_PEProcessingError() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_PEProcessingError));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_DataMismatch() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_DataMismatch));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_InvalidNaaKey() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_InvalidNaaKey));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_PPRNotAllowed() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_PPRNotAllowed));
}

testcase TC_SM_DP_ES9_HandleNotificationNIST_Error_UnknownError() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_HandleNotification_Error_UnknownError));
}

testcase TC_SM_DP_ES9_AuthenticateClient_RetryCases_Reuse_OTPK() runs on MTC_CT {
    f_run_test_case(testcasename(), refers(f_TC_AuthenticateClient_RetryCases_Reuse_OTPK));
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_InvalidSignature() runs on MTC_CT {
    var charstring id := testcasename();
    var smdpp_ConnHdlrPars pars := f_init_pars();
    var smdpp_ConnHdlr vc_conn;
    f_init(id);

    /* Run with signature corruption */
    pars.err_injection := {
        sig_error := { corrupt_signature := true }
    };
    pars.test_name := "Invalid eUICC Signature";
    pars.expected_subject_code := "8.1";
    pars.expected_reason_code := "6.1";

    vc_conn := f_start_handler(refers(f_authenticateClient_error_wrapper), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_UnknownTransactionId() runs on MTC_CT {
    TC_SM_DP_ES9_AuthenticateClientNIST_Error_Generic(true);
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_InvalidServerChallenge() runs on MTC_CT {
    var charstring id := testcasename();
    var smdpp_ConnHdlrPars pars := f_init_pars();
    var smdpp_ConnHdlr vc_conn;
    f_init(id);

    pars.err_injection := {
        challenge_error := {
            wrong_challenge := omit  /* Will generate random wrong challenge */
        }
    };
    pars.test_name := "Invalid Server Challenge";
    pars.expected_subject_code := "8.1";
    pars.expected_reason_code := "6.1";

    vc_conn := f_start_handler(refers(f_authenticateClient_error_wrapper), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_AuthenticateClientNIST_Error_TransactionIdMismatchASN1() runs on MTC_CT {
    TC_SM_DP_ES9_AuthenticateClientNIST_Error_Generic(false);
}


testcase TC_SM_DP_ES9_InitiateAuthenticationBRP_01_Nominal() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars(brainpool := true);
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_InitiateAuth_01_Nominal), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_AuthenticateClientBRP_01_Nominal() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars(brainpool := true);
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_AuthenticateClient_01_Nominal), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageBRP_01_Nominal() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars(brainpool := true);
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_GetBoundProfilePackage_01_Nominal), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_rsp_complete_flow_BRP() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars(brainpool := true);
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_rsp_complete_flow), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_HandleNotificationBRP() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars(brainpool := true);
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_HandleNotification_01_Nominal), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_CancelSession_After_AuthenticateClientBRP() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars(brainpool := true);
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_CancelSession_After_AuthenticateClient_01_End_User_Rejection), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageBRP() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars(brainpool := true);
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_CancelSession_After_GetBoundProfilePackage_01), pars);
    vc_conn.done;
    setverdict(pass);
}

/* ES2+/ES9+ Integration Test Case */
testcase TC_ES2Plus_ES9Plus_FullFlow() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars();
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_ES2Plus_ES9Plus_FullFlow), pars);
    vc_conn.done;
    setverdict(pass);
}

/* ES2+/ES9+ Integration Test Implementation */
private function f_TC_ES2Plus_ES9Plus_FullFlow(charstring id) runs on smdpp_ConnHdlr {
    // ES2+ constants
    const charstring c_es2plus_base_path := "/gsma/rsp2/es2plus";
    const charstring c_path_download_order := c_es2plus_base_path & "/downloadOrder";
    const charstring c_path_confirm_order := c_es2plus_base_path & "/confirmOrder";
    const charstring c_eid1 := "89049032123451234512345678901235";
    const charstring c_cert_path := "./test_certs/CERT_MNO_ECDSA_NIST.pem";
    const charstring c_key_path := "./test_certs/SK_MNO_ECDSA_NIST.pem";

    /* Initialize HTTP/TLS and RSP client */
    f_init_es9plus();
    f_init_es2plus();

    // Step 1: Order profile via ES2+

    // 1.1: dl req
    var JSON_ES2p_Request dl_req := {
        downloadOrderRequest := {
            header := {
                functionRequesterIdentifier := mp_es2plus_operator_id,
                functionCallIdentifier := "01234567890123456789012345678901"
            },
            eid := c_eid1,
            iccid := omit,
            profileType := "Test"
        }
    };

    var octetstring req_enc := enc_JSON_ES2p_Request(dl_req);
    var integer status_code;
    var charstring response := ext_RSPClient_sendHttpsPostWithAuth(
        g_rsp_client_handle_es2p,
        c_path_download_order,
        oct2char(req_enc),
        g_pars_smdpp.smdp_es2p_server_port,
        status_code
    );

    if (status_code != 200) {
        setverdict(fail, "DownloadOrder failed with status: ", status_code);
        f_rsp_client_cleanup();
        return;
    }

    var JSON_ES2p_Response dl_resp := dec_JSON_ES2p_Response(char2oct(response), "downloadOrder");
    if (dl_resp.downloadOrderResponse.header.functionExecutionStatus.status != "Executed-Success") {
        setverdict(fail, "DownloadOrder returned error");
        f_rsp_client_cleanup();
        return;
    }

    var charstring new_iccid := dl_resp.downloadOrderResponse.iccid;

    // 1.2: confirm
    var JSON_ES2p_Request conf_req := {
        confirmOrderRequest := {
            header := {
                functionRequesterIdentifier := mp_es2plus_operator_id,
                functionCallIdentifier := "02234567890123456789012345678901"
            },
            iccid := new_iccid,
            eid := omit,
            matchingId := omit,
            confirmationCode := omit,
            smdsAddress := omit,
            releaseFlag := true
        }
    };

    req_enc := enc_JSON_ES2p_Request(conf_req);
    response := ext_RSPClient_sendHttpsPostWithAuth(
        g_rsp_client_handle_es2p,
        c_path_confirm_order,
        oct2char(req_enc),
        g_pars_smdpp.smdp_es2p_server_port,
        status_code
    );

    if (status_code != 200) {
        setverdict(fail, "ConfirmOrder failed with status: ", status_code);
        f_rsp_client_cleanup();
        return;
    }

    var JSON_ES2p_Response conf_resp := dec_JSON_ES2p_Response(char2oct(response), "confirmOrder");
    if (conf_resp.confirmOrderResponse.header.functionExecutionStatus.status != "Executed-Success") {
        setverdict(fail, "ConfirmOrder returned error");
        f_rsp_client_cleanup();
        return;
    }

    var charstring matching_id := conf_resp.confirmOrderResponse.matchingId;

    // Step 2: Download profile via ES9+

    // Step 2.1: InitiateAuthentication
    var RemoteProfileProvisioningRequest initAuthReq := f_create_initiate_authentication_request();
    var RemoteProfileProvisioningResponse initAuthResp := f_es9p_transceive_success(initAuthReq);

    if (not f_validate_initiate_authentication_response(initAuthResp)) {
        setverdict(fail, "InitiateAuthentication validation failed");
        f_rsp_client_cleanup();
        return;
    }

    var InitiateAuthenticationOkEs9 initAuthOk := initAuthResp.initiateAuthenticationResponse.initiateAuthenticationOk;

    // Step 2.2: AuthenticateClient with ES2+ matchingId

    var RemoteProfileProvisioningRequest authClientReq := f_buildAuthenticateClientRequest(
        initAuthOk.serverSigned1.serverChallenge,
        matching_id  // Using the matchingId from ES2+ ConfirmOrder
    );

    var RemoteProfileProvisioningResponse authClientResp := f_es9p_transceive_success(authClientReq);
    var AuthenticateClientOk authClientOk := authClientResp.authenticateClientResponseEs9.authenticateClientOk;

    f_validateAuthenticateClientResponse(authClientOk);

    // Handle confirmation code if required
    var integer result;
    if (authClientOk.smdpSigned2.ccRequiredFlag == true) {
        log("Confirmation code is required for this profile");
        result := ext_RSPClient_setTransactionId(g_rsp_client_handle_es9p, authClientOk.transactionId);
        if (result != 0) {
            setverdict(fail, "Failed to set transaction ID");
            f_rsp_client_cleanup();
            return;
        }

        var charstring confirmationCode := "12345678";  // Default test code
        result := ext_RSPClient_setConfirmationCode(g_rsp_client_handle_es9p, confirmationCode);
        if (result != 0) {
            setverdict(fail, "Failed to set confirmation code");
            f_rsp_client_cleanup();
            return;
        }
        log("Set confirmation code: ", confirmationCode);
    }

    // Step 2.3: GetBoundProfilePackage

    var RemoteProfileProvisioningRequest packageReq := f_create_get_bound_profile_package_request(
        authClientOk.smdpSignature2
    );

    var RemoteProfileProvisioningResponse packageResp := f_es9p_transceive_success(packageReq);
    var GetBoundProfilePackageOk packageOk := packageResp.getBoundProfilePackageResponse.getBoundProfilePackageOk;

    f_validate_get_bound_profile_package_response(packageResp);

    f_rsp_client_cleanup();

    setverdict(pass);
}

/* ========================================================================
 * ASN.1 Mode Test Variants
 * These tests run the same logic as the NIST tests but use pure ASN.1
 * encoding instead of JSON for the ES9+ interface
 * ======================================================================== */

testcase TC_SM_DP_ES9_InitiateAuthenticationASN1_01_Nominal() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars();
    pars.es9_encoding_mode := ES9_ASN1;
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_InitiateAuth_01_Nominal), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_AuthenticateClientASN1_01_Nominal() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars();
    pars.es9_encoding_mode := ES9_ASN1;
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_AuthenticateClient_01_Nominal), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_GetBoundProfilePackageASN1_01_Nominal() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars();
    pars.es9_encoding_mode := ES9_ASN1;
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_GetBoundProfilePackage_01_Nominal), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_CancelSession_After_AuthenticateClientASN1_01_Nominal() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars();
    pars.es9_encoding_mode := ES9_ASN1;
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_CancelSession_After_AuthenticateClient_01_End_User_Rejection), pars);
    vc_conn.done;
    setverdict(pass);
}

testcase TC_SM_DP_ES9_HandleNotificationASN1_01_Nominal() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars := f_init_pars();
    pars.es9_encoding_mode := ES9_ASN1;
    var smdpp_ConnHdlr vc_conn;
    f_init(testcasename());
    vc_conn := f_start_handler(refers(f_TC_HandleNotification_01_Nominal), pars);
    vc_conn.done;
    setverdict(pass);
}

/* quick comparison */
testcase TC_ES9_Mode_Comparison() runs on MTC_CT {
    var smdpp_ConnHdlrPars pars_json := f_init_pars();
    pars_json.es9_encoding_mode := ES9_JSON;
    var smdpp_ConnHdlr vc_json;
    f_init(testcasename() & "_JSON");
    vc_json := f_start_handler(refers(f_TC_InitiateAuth_01_Nominal), pars_json);
    vc_json.done;

    var smdpp_ConnHdlrPars pars_asn1 := f_init_pars();
    pars_asn1.es9_encoding_mode := ES9_ASN1;
    var smdpp_ConnHdlr vc_asn1;
    f_init(testcasename() & "_ASN1");
    vc_asn1 := f_start_handler(refers(f_TC_InitiateAuth_01_Nominal), pars_asn1);
    vc_asn1.done;

    setverdict(pass);
}

control {
	execute(TC_rsp_complete_flow());

	/* InitiateAuthentication Tests */
	/* SGP.23 Section 4.3.12.2.1 Test Sequence #01 */
	execute(TC_SM_DP_ES9_InitiateAuthenticationNIST_01_Nominal());
	/* SGP.23 Section 4.3.12.2.1 Test Sequence #02 */
	execute(TC_SM_DP_ES9_InitiateAuthenticationNIST_02_Uniqueness());
	/* SGP.23 Section 4.3.12.2.1 Test Sequence #03 */
	execute(TC_SM_DP_ES9_InitiateAuthenticationNIST_03_InvalidServerAddress());
	/* SGP.23 Section 4.3.12.2.1 Test Sequence #04 */
	execute(TC_SM_DP_ES9_InitiateAuthenticationNIST_04_UnsupportedPKID());
	/* SGP.23 Section 4.3.12.2.1 Test Sequence #05 */
	execute(TC_SM_DP_ES9_InitiateAuthenticationNIST_05_UnsupportedVersion());
	/* SGP.23 Section 4.3.12.2.1 Test Sequence #06 */
	execute(TC_SM_DP_ES9_InitiateAuthenticationNIST_06_UnavailableServerAuthCert());
	/* SGP.23 Section 4.3.12.2.1 Test Sequence #07 */
	execute(TC_SM_DP_ES9_InitiateAuthenticationNIST_07_Nominal_v221());
	/* SGP.23 Section 4.3.12.2.1 Test Sequence #08 */
	execute(TC_SM_DP_ES9_InitiateAuthenticationNIST_08_Nominal_v222());
	/* SGP.23 Section 4.3.12.2.1 Test Sequence #09 */
	execute(TC_SM_DP_ES9_InitiateAuthenticationNIST_09_Nominal_v230());

	/* AuthenticateClient Tests */
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #01 */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_01_Nominal());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #02 */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_02_ConfirmationCode());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #03 - Second Attempt After Invalid MatchingID */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_03_SecondAttempt_AfterInvalidMatchingID());
	/* 04 VOID */
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #05 - SM-DS Event No MatchingID */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_05_SMDS_NoMatchingID());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #06 - SM-DS Event With MatchingID */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_06_SMDS_WithMatchingID());
 	/* 07 VOID */
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #08 - Activation Code Use Case */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_08_ActivationCode_NoCC());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #09 - Activation Code Use Case with CC */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_09_ActivationCode_WithCC());
	/* 10 VOID*/
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #11 - Activation Code not associated to EID (no CC) */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_11_ActivationCode_NotAssociated_NoCC());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #12 - Activation Code not associated to EID (with CC) */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_12_ActivationCode_NotAssociated_WithCC());
	/* 13 VOID */
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #14 - Default SM-DP+ with MatchingId omitted */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_14_DefaultDP_MatchingIdOmitted());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #15 - SM-DS with MatchingId omitted */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_15_SMDS_MatchingIdOmitted());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #16 - SM-DS with empty MatchingId */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_16_SMDS_MatchingIdEmpty());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #17 - Activation Code with MatchingId omitted */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_17_ActivationCode_MatchingIdOmitted());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #18 - Activation Code with empty MatchingId */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_18_ActivationCode_MatchingIdEmpty());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #19 - Extended UICC Capability */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_19_Extended_UICC_Capability());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #20 - Extended DeviceInfo */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_20_Extended_DeviceInfo());
	/* SGP.23 Section 4.3.14.2.1 Test Sequence #21 - Extended eUICCInfo2 */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_21_Extended_eUICCInfo2());


	/* AuthenticateClient Error Tests */

	/* Certificate Validation Error Tests */
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #1 - Invalid EUM Certificate */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_01_InvalidEUMCert());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #2 - Expired EUM Certificate */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_02_ExpiredEUMCert());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #3 - Invalid eUICC Certificate */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_03_InvalidEUICCCert());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #4 - Expired eUICC Certificate */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_04_ExpiredEUICCCert());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #7 - Unknown CI Public Key */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_07_UnknownCIKey());

	/* SGP.23 Section 4.3.14.2.2 Test Sequence #10 - Unknown Transaction ID in ASN.1 */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_Mismatched_Transaction_ID());

	/* SGP.23 Section 4.3.14.2.6 - Retry cases with reuse of OTPK */
	execute(TC_SM_DP_ES9_AuthenticateClient_RetryCases_Reuse_OTPK());


	/* SGP.23 Section 4.3.14.2.2 Test Sequence #5 - Invalid eUICC Signature */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_InvalidSignature());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #6 - Invalid Server Challenge */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_InvalidServerChallenge());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #8 - Profile Not Released */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_ProfileNotReleased());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #9 - Unknown Transaction ID in JSON */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_UnknownTransactionId());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #10 - Unknown Transaction ID in ASN.1 */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_TransactionIdMismatchASN1());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #11 - Invalid Matching ID for Default DP+ */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_UnmatchedMatchingID());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #12 - Invalid Matching ID for Activation Code */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_12_InvalidMatchingID_ActivationCode());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #13 - Invalid Matching ID for SM-DS */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_13_InvalidMatchingID_SMDS());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #14 - Un-matched EID for Default DP+ */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_14_UnmatchedEID_DefaultDP());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #15 - No Eligible Profile */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_15_NoEligibleProfile());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #16 - Download Order Expired */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_16_DownloadOrderExpired());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #17 - Max Retries Exceeded */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_17_MaxRetriesExceeded());
	/* Test Sequence #18 VOID */
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #19 - Un-matched EID for SM-DS */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_19_UnmatchedEID_SMDS());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #20 - Un-matched EID for Activation Code */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_20_UnmatchedEID_ActivationCode());
	/* SGP.23 Section 4.3.14.2.2 Test Sequence #21 - Invalid MatchingId for AC not associated to EID */
	execute(TC_SM_DP_ES9_AuthenticateClientNIST_Error_21_InvalidMatchingID_NotAssociatedEID());

	/* GetBoundProfilePackage Tests */
	/* SGP.23 Section 4.3.13.2.1 Test Sequence #01 */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_01_Nominal());
	/* SGP.23 Section 4.3.13.2.4 Test Sequence #01 - Retry with same otPK */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_02_Retry_Same_Challenge());
	/* SGP.23 Section 4.3.13.2.7 Test Sequence #01 - Retry with different otPK */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_03_Retry_Different_Challenge());
	/* SGP.23 Section 4.3.13.2.10 - Error cases */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_04_Preparation_Error());
	/* SGP.23 Section 4.3.13.2.10 - Individual error cases */
	/* Test Sequence #02: Error - Invalid eUICC Signature (8.1/6.1) */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_InvalidSignature());
	/* Test Sequence #03: Error - Unknown Transaction ID in JSON (8.10.1/3.9) */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_UnknownTransactionIdJSON());
	/* Test Sequence #03: Error - Unknown Transaction ID in ASN.1 (8.10.1/3.9) */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_UnknownTransactionIdASN1());
	/* Test Sequence #04: Error - Missing Confirmation Code (8.2.7/2.2) */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_MissingConfirmationCode());
	/* Test Sequence #05: Error - Refused Confirmation Code (8.2.7/3.8) */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Error_RefusedConfirmationCode());

	/* PPK (Profile Protection Key) Tests */
	/* SGP.23 Section 4.3.13.2.2 Test Sequence #03 - PPK without CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_PPK_NoCC());
	/* SGP.23 Section 4.3.13.2.2 Test Sequence #04 - PPK with CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_PPK_WithCC());
	/* SGP.23 Section 4.3.13.2.2 Test Sequence #06 - PPK with Metadata Split */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_PPK_MetadataSplit());

	/* GetBoundProfilePackage Retry Cases - Reuse OTPK */
	/* SGP.23 Section 4.3.13.2.4 - RetryCases_ReuseOTPK_NIST */
	/* Test Sequence #01: Retry with same otPK using S-ENC/S-MAC without CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_01_SameOTPK_SENC_NoCC());
	/* Test Sequence #02: Retry with same otPK using S-ENC/S-MAC with CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_02_SameOTPK_SENC_WithCC());
	/* Test Sequence #03: Retry with same otPK using PPK-ENC/PPK-MAC without CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_03_SameOTPK_PPK_NoCC());
	/* Test Sequence #04: Retry with same otPK using PPK-ENC/PPK-MAC with CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_04_SameOTPK_PPK_WithCC());
	/* Test Sequence #05: eUICC rejects with new otPK, S-ENC/S-MAC without CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_05_NewOTPK_SENC_NoCC());
	/* Test Sequence #06: eUICC rejects with new otPK, S-ENC/S-MAC with CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_06_NewOTPK_SENC_WithCC());
	/* Test Sequence #07: eUICC rejects with new otPK, PPK-ENC/PPK-MAC without CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_07_NewOTPK_PPK_NoCC());
	/* Test Sequence #08: eUICC rejects with new otPK, PPK-ENC/PPK-MAC with CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_08_NewOTPK_PPK_WithCC());
	/* Test Sequence #09: Confirmation Code retry */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_09_ConfirmationCode());

	/* GetBoundProfilePackage Retry Cases - Different OTPK */
	/* SGP.23 Section 4.3.13.2.7 - RetryCases_DifferentOTPK_NIST */
	/* Test Sequence #01: Retry without otPK using S-ENC/S-MAC without CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_10_DiffOTPK_SENC_NoCC());
	/* Test Sequence #02: Retry without otPK using S-ENC/S-MAC with CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_11_DiffOTPK_SENC_WithCC());
	/* Test Sequence #03: Retry without otPK using PPK-ENC/PPK-MAC without CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_12_DiffOTPK_PPK_NoCC());
	/* Test Sequence #04: Retry without otPK using PPK-ENC/PPK-MAC with CC */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageNIST_Retry_13_DiffOTPK_PPK_WithCC());

	/* CancelSession Tests */
	/* SGP.23 Section 4.3.16.2.1 - Cancel after AuthenticateClient */
	execute(TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST());
	/* SGP.23 Section 4.3.16.2.1 Test Sequence #02 - Postponed */
	execute(TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Postponed());
	/* SGP.23 Section 4.3.16.2.1 Test Sequence #03 - Timeout */
	execute(TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Timeout());
	/* SGP.23 Section 4.3.16.2.1 Test Sequence #04 - PPR Not Allowed */
	execute(TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_PPR_Not_Allowed());
	/* SGP.23 Section 4.3.16.2.1 Test Sequence #05 - Undefined Reason */
	execute(TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Undefined_Reason());

	/* SGP.23 Section 4.3.16.2.2 - Cancel after GetBoundProfilePackage */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST());
	/* SGP.23 Section 4.3.16.2.2 Test Sequence #02 - Postponed */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Postponed());
	/* SGP.23 Section 4.3.16.2.2 Test Sequence #03 - Timeout */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Timeout());
	/* SGP.23 Section 4.3.16.2.2 Test Sequence #04 - PPR Not Allowed */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_PPR_Not_Allowed());
	/* SGP.23 Section 4.3.16.2.2 Test Sequence #05 - Metadata Mismatch */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Metadata_Mismatch());
	/* SGP.23 Section 4.3.16.2.2 Test Sequence #06 - Load BPP Error */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Load_BPP_Error());
	/* SGP.23 Section 4.3.16.2.2 Test Sequence #07 - Undefined Reason */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Undefined_Reason());

	/* CancelSession Error Tests - After AuthenticateClient */
	/* SGP.23 Section 4.3.16.2.1 Test Sequence #06 - Unknown Transaction ID in JSON */
	execute(TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Error_UnknownTransactionIdJSON());
	/* SGP.23 Section 4.3.16.2.1 Test Sequence #07 - Unknown Transaction ID in ASN.1 */
	execute(TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Error_UnknownTransactionIdASN1());
	/* SGP.23 Section 4.3.16.2.1 Test Sequence #08 - Invalid eUICC Signature */
	execute(TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Error_InvalidSignature());
	/* SGP.23 Section 4.3.16.2.1 Test Sequence #09 - Invalid OID */
	execute(TC_SM_DP_ES9_CancelSession_After_AuthenticateClientNIST_Error_InvalidOID());

	/* CancelSession Error Tests - After GetBoundProfilePackage */
	/* SGP.23 Section 4.3.16.2.2 Test Sequence #08 - Unknown Transaction ID in JSON */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Error_UnknownTransactionIdJSON());
	/* SGP.23 Section 4.3.16.2.2 Test Sequence #09 - Unknown Transaction ID in ASN.1 */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Error_UnknownTransactionIdASN1());
	/* SGP.23 Section 4.3.16.2.2 Test Sequence #10 - Invalid eUICC Signature */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Error_InvalidSignature());
	/* SGP.23 Section 4.3.16.2.2 Test Sequence #11 - Invalid OID */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageNIST_Error_InvalidOID());

	/* HandleNotification Tests */
	/* SGP.23 Section 4.3.15.2.1 Test Sequence #01 */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_01_Nominal());
	/* SGP.23 Section 4.3.15.2.1 Test Sequence #02 - OtherSignedNotification */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_02_OtherSignedNotification());
	/* SGP.23 Section 4.3.15.2.1 PIR Error Tests */
	/* Test Sequence #03: Invalid Transaction ID */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_InvalidTransactionId());
	/* Test Sequence #04: Incorrect Input Values */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_IncorrectInputValues());
	/* Test Sequence #05: Invalid Signature */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_InvalidSignature());
	/* Test Sequence #06: Unsupported CRT Values */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_UnsupportedCrtValues());
	/* Test Sequence #07: Unsupported Remote Operation Type */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_UnsupportedRemoteOpType());
	/* Test Sequence #08: Unsupported Profile Class */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_UnsupportedProfileClass());
	/* Test Sequence #09: SCP03t Structure Error */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_SCP03tStructureError());
	/* Test Sequence #10: SCP03t Security Error */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_SCP03tSecurityError());
	/* Test Sequence #11: ICCID Already Exists */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_IccidAlreadyExists());
	/* Test Sequence #12: Insufficient Memory */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_InsufficientMemory());
	/* Test Sequence #13: Install Failed Due To Interruption */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_InstallInterruption());
	/* Test Sequence #14: PE Processing Error */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_PEProcessingError());
	/* Test Sequence #15: Data Mismatch */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_DataMismatch());
	/* Test Sequence #16: Invalid NAA Key */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_InvalidNaaKey());
	/* Test Sequence #17: PPR Not Allowed */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_PPRNotAllowed());
	/* Test Sequence #18: Unknown Error */
	execute(TC_SM_DP_ES9_HandleNotificationNIST_Error_UnknownError());

	/* BRP (Brainpool) Test Cases */
	/* SGP.23 Section 4.3.12.2.3 */
	execute(TC_SM_DP_ES9_InitiateAuthenticationBRP_01_Nominal());
	/* SGP.23 Section 4.3.14.2.5 */
	execute(TC_SM_DP_ES9_AuthenticateClientBRP_01_Nominal());
	/* SGP.23 Section 4.3.13.2.3 */
	execute(TC_SM_DP_ES9_GetBoundProfilePackageBRP_01_Nominal());
	/* SGP.23 Section 4.3.15.2.3 */
	execute(TC_SM_DP_ES9_HandleNotificationBRP());
	/* SGP.23 Section 4.3.16.2.5 */
	execute(TC_SM_DP_ES9_CancelSession_After_AuthenticateClientBRP());
	/* SGP.23 Section 4.3.16.2.6 */
	execute(TC_SM_DP_ES9_CancelSession_After_GetBoundProfilePackageBRP());
	/* Complete flow with BRP certificates */
	execute(TC_rsp_complete_flow_BRP());

	/* ES2+/ES9+ Integration Test */
	execute(TC_ES2Plus_ES9Plus_FullFlow());
}

}