/* JSON message definitions for ES9+
 *
 * Author: Philipp Maier <pmaier@sysmocom.de> / sysmocom - s.f.m.c. GmbH
 *
 * Released under the terms of GNU General Public License, Version 2 or
 * (at your option) any later version.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

module es9p_Types_JSON {

import from esx_header_Types_JSON 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;

/* GSMA SGP.22, section 6.5.2.6 */
type record JSON_ES9p_InitiateAuthenticationRequest {
	JSON_ESx_RequestHeader header,
	charstring euiccChallenge,
	charstring euiccInfo1,
	charstring smdpAddress
};
type record JSON_ES9p_InitiateAuthenticationResponse {
	JSON_ESx_ResponseHeader header,
	charstring transactionId,
	charstring serverSigned1,
	charstring serverSignature1,
	charstring euiccCiPKIdToBeUsed,
	charstring serverCertificate
};

/* GSMA SGP.22, section 6.5.2.7 */
type record JSON_ES9p_GetBoundProfilePackageRequest {
	JSON_ESx_RequestHeader header,
	charstring transactionId,
	charstring prepareDownloadResponse
};
type record JSON_ES9p_GetBoundProfilePackageResponse {
	JSON_ESx_ResponseHeader header,
	charstring transactionId,
	charstring boundProfilePackage
};

/* GSMA SGP.22, section 6.5.2.8 */
type record JSON_ES9p_AuthenticateClientRequest {
	JSON_ESx_RequestHeader header,
	charstring transactionId,
	charstring authenticateServerResponse
};
type record JSON_ES9p_AuthenticateClientResponseEs9 {
	JSON_ESx_ResponseHeader header,
	charstring transactionId,
	charstring profileMetadata,
	charstring smdpSigned2,
	charstring smdpSignature2,
	charstring smdpCertificate
};

/* GSMA SGP.22, section 6.5.2.9 */
type record JSON_ES9p_HandleNotification {
	JSON_ESx_RequestHeader header,
	charstring pendingNotification
};

/* GSMA SGP.22, section 6.5.2.10 */
type record JSON_ES9p_CancelSessionRequestEs9 {
	JSON_ESx_RequestHeader header,
	charstring transactionId,
	charstring cancelSessionResponse
};

/* An empty response that is used when the response only consists of a JSON header */
type record JSON_ES9p_EmptyResponse {
	JSON_ESx_ResponseHeader header
};


/* Definition for JSON ES9+ requests */
type union JSON_ES9p_RemoteProfileProvisioningRequest {
	JSON_ES9p_InitiateAuthenticationRequest initiateAuthenticationRequest,
	JSON_ES9p_GetBoundProfilePackageRequest getBoundProfilePackageRequest,
	JSON_ES9p_AuthenticateClientRequest authenticateClientRequest,
	JSON_ES9p_HandleNotification handleNotification,
	JSON_ES9p_CancelSessionRequestEs9 cancelSessionRequestEs9
} with {
	variant "JSON : as value"
}

external function enc_JSON_ES9p_RemoteProfileProvisioningRequest(in JSON_ES9p_RemoteProfileProvisioningRequest msg) return octetstring
with {
	extension "prototype (convert) encode(JSON)";
	extension "printing(pretty)";
	extension "errorbehavior(ALL:ERROR)"
}
external function dec_JSON_ES9p_RemoteProfileProvisioningRequest(in octetstring stream) return JSON_ES9p_RemoteProfileProvisioningRequest
with {
	extension "prototype (convert) decode(JSON)"
	extension "errorbehavior(ALL:ERROR)"
}


/* Definition for JSON ES9+ responses */
type union JSON_ES9p_RemoteProfileProvisioningResponse
{
	JSON_ES9p_InitiateAuthenticationResponse initiateAuthenticationResponse,
	JSON_ES9p_GetBoundProfilePackageResponse getBoundProfilePackageResponse,
	JSON_ES9p_AuthenticateClientResponseEs9 authenticateClientResponseEs9,
	JSON_ES9p_EmptyResponse emptyResponse
} with {
	variant "JSON : as value"
}

external function enc_JSON_ES9p_RemoteProfileProvisioningResponse(in JSON_ES9p_RemoteProfileProvisioningResponse msg) return octetstring
with {
	extension "prototype (convert) encode(JSON)";
	extension "printing(pretty)";
	extension "errorbehavior(ALL:ERROR)"
}
external function dec_JSON_ES9p_RemoteProfileProvisioningResponse(in octetstring stream) return JSON_ES9p_RemoteProfileProvisioningResponse
with {
	extension "prototype (convert) decode(JSON)"
	extension "errorbehavior(ALL:ERROR)"
}

/* Converter function to decode a JSON formatted ES9+ request to its ASN.1 ES9+ record representation */
function dec_RemoteProfileProvisioningRequest_from_JSON(in charstring json_pdu_enc, out RemoteProfileProvisioningRequest asn1_pdu_dec) {
	var JSON_ES9p_RemoteProfileProvisioningRequest json_pdu;
	json_pdu := dec_JSON_ES9p_RemoteProfileProvisioningRequest(char2oct(json_pdu_enc));

	if (ispresent(json_pdu.initiateAuthenticationRequest)) {
		asn1_pdu_dec := valueof(ts_initiateAuthenticationRequest(
			decode_base64(json_pdu.initiateAuthenticationRequest.euiccChallenge),
			json_pdu.initiateAuthenticationRequest.smdpAddress,
			dec_EUICCInfo1(decode_base64(json_pdu.initiateAuthenticationRequest.euiccInfo1))));
	} else if (ispresent(json_pdu.getBoundProfilePackageRequest)) {
		asn1_pdu_dec := valueof(ts_getBoundProfilePackageRequest(
			str2oct(json_pdu.getBoundProfilePackageRequest.transactionId),
			dec_PrepareDownloadResponse(decode_base64(json_pdu.getBoundProfilePackageRequest.prepareDownloadResponse))));
	} else if (ispresent(json_pdu.authenticateClientRequest)) {
		asn1_pdu_dec := valueof(ts_authenticateClientRequest(
			str2oct(json_pdu.authenticateClientRequest.transactionId),
			dec_AuthenticateServerResponse(decode_base64(json_pdu.authenticateClientRequest.authenticateServerResponse))));
	} else if (ispresent(json_pdu.handleNotification)) {
		asn1_pdu_dec := valueof(ts_handleNotification(
			dec_PendingNotification(decode_base64(json_pdu.handleNotification.pendingNotification))));
	} else if (ispresent(json_pdu.cancelSessionRequestEs9)) {
		asn1_pdu_dec := valueof(ts_cancelSessionRequestEs9(
			str2oct(json_pdu.cancelSessionRequestEs9.transactionId),
			dec_CancelSessionResponse(decode_base64(json_pdu.cancelSessionRequestEs9.cancelSessionResponse))));
	} else {
		setverdict(fail, "decoder path not implemented for JSON ES9+ message");
	}
} with { extension "prototype(fast)" }

/* Converter function to encode an ASN.1 ES9+ request record to its JSON formatted ES9+ representation */
function enc_RemoteProfileProvisioningRequest_to_JSON(in RemoteProfileProvisioningRequest asn1_pdu_dec, out charstring json_pdu_enc) {
	var JSON_ES9p_RemoteProfileProvisioningRequest json_pdu;

	var charstring functionRequesterIdentifier := "TTCN3";
	var charstring functionCallIdentifier := "testsuite";

	if (ispresent(asn1_pdu_dec.initiateAuthenticationRequest)) {
		json_pdu.initiateAuthenticationRequest.header.functionRequesterIdentifier := functionRequesterIdentifier;
		json_pdu.initiateAuthenticationRequest.header.functionCallIdentifier := functionCallIdentifier;
		json_pdu.initiateAuthenticationRequest.euiccChallenge := encode_base64(asn1_pdu_dec.initiateAuthenticationRequest.euiccChallenge);
		json_pdu.initiateAuthenticationRequest.smdpAddress := unichar2char(asn1_pdu_dec.initiateAuthenticationRequest.smdpAddress);
		json_pdu.initiateAuthenticationRequest.euiccInfo1 := encode_base64(enc_EUICCInfo1(asn1_pdu_dec.initiateAuthenticationRequest.euiccInfo1));
		json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningRequest(json_pdu));
	} else if (ispresent(asn1_pdu_dec.getBoundProfilePackageRequest)) {
		json_pdu.getBoundProfilePackageRequest.header.functionRequesterIdentifier := functionRequesterIdentifier;
		json_pdu.getBoundProfilePackageRequest.header.functionCallIdentifier := functionCallIdentifier;
		json_pdu.getBoundProfilePackageRequest.transactionId := oct2str(asn1_pdu_dec.getBoundProfilePackageRequest.transactionId);
		json_pdu.getBoundProfilePackageRequest.prepareDownloadResponse :=
			encode_base64(enc_PrepareDownloadResponse(asn1_pdu_dec.getBoundProfilePackageRequest.prepareDownloadResponse));
		json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningRequest(json_pdu));
	} else if (ispresent(asn1_pdu_dec.authenticateClientRequest)) {
		json_pdu.authenticateClientRequest.header.functionRequesterIdentifier := functionRequesterIdentifier;
		json_pdu.authenticateClientRequest.header.functionCallIdentifier := functionCallIdentifier;
		json_pdu.authenticateClientRequest.transactionId := oct2str(asn1_pdu_dec.authenticateClientRequest.transactionId);
		json_pdu.authenticateClientRequest.authenticateServerResponse :=
			encode_base64(enc_AuthenticateServerResponse(asn1_pdu_dec.authenticateClientRequest.authenticateServerResponse))
		json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningRequest(json_pdu));
	} else if (ispresent(asn1_pdu_dec.handleNotification)) {
		json_pdu.handleNotification.header.functionRequesterIdentifier := functionRequesterIdentifier;
		json_pdu.handleNotification.header.functionCallIdentifier := functionCallIdentifier;
		json_pdu.handleNotification.pendingNotification :=
			encode_base64(enc_PendingNotification(asn1_pdu_dec.handleNotification.pendingNotification))
		json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningRequest(json_pdu));
	} else if (ispresent(asn1_pdu_dec.cancelSessionRequestEs9)) {
		json_pdu.cancelSessionRequestEs9.header.functionRequesterIdentifier := functionRequesterIdentifier;
		json_pdu.cancelSessionRequestEs9.header.functionCallIdentifier := functionCallIdentifier;
		json_pdu.cancelSessionRequestEs9.transactionId := oct2str(asn1_pdu_dec.cancelSessionRequestEs9.transactionId);
		json_pdu.cancelSessionRequestEs9.cancelSessionResponse :=
			encode_base64(enc_CancelSessionResponse(asn1_pdu_dec.cancelSessionRequestEs9.cancelSessionResponse))
		json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningRequest(json_pdu));
	} else {
		setverdict(fail, "encoder path not implemented for JSON ES9+ message");
	}
} with { extension "prototype(fast)" }

type record DecodedRPPReponse_Wrap {
    RemoteProfileProvisioningResponse asn1_pdu optional,
    JSON_ESx_FunctionExecutionStatusCodeData err optional
}

/* Converter function to decode a JSON formatted ES9+ response to its ASN.1 ES9+ record representation */
function dec_RemoteProfileProvisioningResponse_from_JSON(in charstring json_pdu_enc, out DecodedRPPReponse_Wrap wrapped_resp) {
	var JSON_ES9p_RemoteProfileProvisioningResponse json_pdu;
	json_pdu := dec_JSON_ES9p_RemoteProfileProvisioningResponse(char2oct(json_pdu_enc));

	if (ispresent(json_pdu.initiateAuthenticationResponse)) {
		if (not match(json_pdu.initiateAuthenticationResponse.header, ts_responseHeader)) {
			setverdict(fail, "unsuccessful request");
		}
		wrapped_resp.asn1_pdu := valueof(ts_initiateAuthenticationResponse(
			str2oct(json_pdu.initiateAuthenticationResponse.transactionId),
			dec_ServerSigned1(decode_base64(json_pdu.initiateAuthenticationResponse.serverSigned1)),
			decode_base64(json_pdu.initiateAuthenticationResponse.serverSignature1),
			dec_SubjectKeyIdentifier(decode_base64(json_pdu.initiateAuthenticationResponse.euiccCiPKIdToBeUsed)),
			dec_Certificate(decode_base64(json_pdu.initiateAuthenticationResponse.serverCertificate))));
	} else if (ispresent(json_pdu.getBoundProfilePackageResponse)) {
		if (not match(json_pdu.getBoundProfilePackageResponse.header, ts_responseHeader)) {
			setverdict(fail, "unsuccessful request");
		}
		wrapped_resp.asn1_pdu := valueof(ts_getBoundProfilePackageResponse(
			str2oct(json_pdu.getBoundProfilePackageResponse.transactionId),
			dec_BoundProfilePackage(decode_base64(json_pdu.getBoundProfilePackageResponse.boundProfilePackage))));
	} else if (ispresent(json_pdu.authenticateClientResponseEs9)) {
		if (not match(json_pdu.authenticateClientResponseEs9.header, ts_responseHeader)) {
			setverdict(fail, "unsuccessful request");
		}
		wrapped_resp.asn1_pdu := valueof(ts_authenticateClientResponseEs9(
			str2oct(json_pdu.authenticateClientResponseEs9.transactionId),
			dec_StoreMetadataRequest(decode_base64(json_pdu.authenticateClientResponseEs9.profileMetadata)),
			dec_SmdpSigned2(decode_base64(json_pdu.authenticateClientResponseEs9.smdpSigned2)),
			decode_base64(json_pdu.authenticateClientResponseEs9.smdpSignature2),
			dec_Certificate(decode_base64(json_pdu.authenticateClientResponseEs9.smdpCertificate))));
	} else if (ispresent(json_pdu.emptyResponse)) {
		if (not match(json_pdu.emptyResponse.header, ts_responseHeader)) {
			wrapped_resp.err := json_pdu.emptyResponse.header.functionExecutionStatus.statusCodeData;
		} else {
			/* Success case for empty response - initialize optional fields */
			wrapped_resp.asn1_pdu := omit;
			wrapped_resp.err := omit;
		}
	} else {
		setverdict(fail, "decoder path not implemented for JSON ES9+ message");
	}
} with { extension "prototype(fast)" }

/* Converter function to encode an ASN.1 ES9+ response record to its JSON formatted ES9+ representation */
function enc_RemoteProfileProvisioningResponse_to_JSON(in RemoteProfileProvisioningResponse asn1_pdu_dec, out charstring json_pdu_enc) {
	var JSON_ES9p_RemoteProfileProvisioningResponse json_pdu;

	if (ispresent(asn1_pdu_dec.initiateAuthenticationResponse)) {
		json_pdu.initiateAuthenticationResponse.header.functionExecutionStatus.status := "Executed-Success";
		json_pdu.initiateAuthenticationResponse.transactionId :=
			oct2str(asn1_pdu_dec.initiateAuthenticationResponse.initiateAuthenticationOk.transactionId);
		json_pdu.initiateAuthenticationResponse.serverSigned1 :=
			encode_base64(enc_ServerSigned1(asn1_pdu_dec.initiateAuthenticationResponse.initiateAuthenticationOk.serverSigned1));
		json_pdu.initiateAuthenticationResponse.serverSignature1 :=
			encode_base64(asn1_pdu_dec.initiateAuthenticationResponse.initiateAuthenticationOk.serverSignature1);
		json_pdu.initiateAuthenticationResponse.euiccCiPKIdToBeUsed :=
			encode_base64(enc_SubjectKeyIdentifier(asn1_pdu_dec.initiateAuthenticationResponse.initiateAuthenticationOk.euiccCiPKIdToBeUsed));
		json_pdu.initiateAuthenticationResponse.serverCertificate :=
			encode_base64(enc_Certificate(asn1_pdu_dec.initiateAuthenticationResponse.initiateAuthenticationOk.serverCertificate));
		json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningResponse(json_pdu));
	} else if (ispresent(asn1_pdu_dec.getBoundProfilePackageResponse)) {
		json_pdu.getBoundProfilePackageResponse.header.functionExecutionStatus.status := "Executed-Success";
		json_pdu.getBoundProfilePackageResponse.transactionId :=
			oct2str(asn1_pdu_dec.getBoundProfilePackageResponse.getBoundProfilePackageOk.transactionId);
		json_pdu.getBoundProfilePackageResponse.boundProfilePackage :=
			encode_base64(enc_BoundProfilePackage(asn1_pdu_dec.getBoundProfilePackageResponse.getBoundProfilePackageOk.boundProfilePackage));
		json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningResponse(json_pdu));
	} else if (ispresent(asn1_pdu_dec.authenticateClientResponseEs9)) {
		json_pdu.authenticateClientResponseEs9.header.functionExecutionStatus.status := "Executed-Success";
		json_pdu.authenticateClientResponseEs9.transactionId :=
			oct2str(asn1_pdu_dec.authenticateClientResponseEs9.authenticateClientOk.transactionId);
		json_pdu.authenticateClientResponseEs9.profileMetadata :=
			encode_base64(enc_StoreMetadataRequest(asn1_pdu_dec.authenticateClientResponseEs9.authenticateClientOk.profileMetaData));
		json_pdu.authenticateClientResponseEs9.smdpSigned2 :=
			encode_base64(enc_SmdpSigned2(asn1_pdu_dec.authenticateClientResponseEs9.authenticateClientOk.smdpSigned2));
		json_pdu.authenticateClientResponseEs9.smdpSignature2 :=
			encode_base64(asn1_pdu_dec.authenticateClientResponseEs9.authenticateClientOk.smdpSignature2);
		json_pdu.authenticateClientResponseEs9.smdpCertificate :=
			encode_base64(enc_Certificate(asn1_pdu_dec.authenticateClientResponseEs9.authenticateClientOk.smdpCertificate));
		json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningResponse(json_pdu));
	} else if (ispresent(asn1_pdu_dec.cancelSessionResponseEs9)) {
		/* This message has no JSON body, see also GSMA SGP.22, section 6.5.2.10 */
		json_pdu.emptyResponse.header.functionExecutionStatus.status := "Executed-Success";
		json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningResponse(json_pdu));
	} else if (ispresent(asn1_pdu_dec.authenticateClientResponseEs11)) {
		setverdict(fail, "encoder path not implemented for JSON ES9+ message AuthenticateClientResponseEs11");
	} else {
		json_pdu.emptyResponse.header.functionExecutionStatus.status := "Executed-Success";
		json_pdu_enc := oct2char(enc_JSON_ES9p_RemoteProfileProvisioningResponse(json_pdu));
	}
} with { extension "prototype(fast)" }

} with {
	encode "JSON";
}





