#include "euicc.private.h" #include "es10b.h" #include "derutil.h" #include "hexutil.h" #include "base64.h" #include "sha256.h" #include #include #include #include #include int es10b_prepare_download_r(struct euicc_ctx *ctx, char **b64_PrepareDownloadResponse, struct es10b_prepare_download_param *param, struct es10b_prepare_download_param_user *param_user) { int fret = 0; uint8_t *reqbuf = NULL; uint32_t reqlen; uint8_t *respbuf = NULL; unsigned resplen; EUICC_SHA256_CTX sha256ctx; uint8_t hashCC[SHA256_BLOCK_SIZE]; uint8_t *smdpSigned2 = NULL, *smdpSignature2 = NULL, *smdpCertificate = NULL; int smdpSigned2_len, smdpSignature2_len, smdpCertificate_len; struct euicc_derutil_node n_request, n_smdpSigned2, n_smdpSignature2, n_smdpCertificate, n_hashCc, n_transactionId, n_ccRequiredFlag; *b64_PrepareDownloadResponse = NULL; memset(&n_request, 0, sizeof(n_request)); memset(&n_smdpSigned2, 0, sizeof(n_smdpSigned2)); memset(&n_smdpSignature2, 0, sizeof(n_smdpSignature2)); memset(&n_smdpCertificate, 0, sizeof(n_smdpCertificate)); memset(&n_hashCc, 0, sizeof(n_hashCc)); smdpSigned2 = malloc(euicc_base64_decode_len(param->b64_smdpSigned2)); if (!smdpSigned2) { goto err; } smdpSignature2 = malloc(euicc_base64_decode_len(param->b64_smdpSignature2)); if (!smdpSignature2) { goto err; } smdpCertificate = malloc(euicc_base64_decode_len(param->b64_smdpCertificate)); if (!smdpCertificate) { goto err; } if ((smdpSigned2_len = euicc_base64_decode(smdpSigned2, param->b64_smdpSigned2)) < 0) { goto err; } if ((smdpSignature2_len = euicc_base64_decode(smdpSignature2, param->b64_smdpSignature2)) < 0) { goto err; } if ((smdpCertificate_len = euicc_base64_decode(smdpCertificate, param->b64_smdpCertificate)) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_smdpSigned2, 0x30, smdpSigned2, smdpSigned2_len) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_smdpSignature2, 0x5F37, smdpSignature2, smdpSignature2_len) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_smdpCertificate, 0x30, smdpCertificate, smdpCertificate_len) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_transactionId, 0x80, n_smdpSigned2.value, n_smdpSigned2.length) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_ccRequiredFlag, 0x01, n_smdpSigned2.value, n_smdpSigned2.length) < 0) { goto err; } n_request.tag = 0xBF21; n_request.pack.child = &n_smdpSigned2; n_smdpSigned2.pack.next = &n_smdpSignature2; if (euicc_derutil_convert_bin2long(n_ccRequiredFlag.value, n_ccRequiredFlag.length)) { if ((!param_user->confirmationCode) || (strlen(param_user->confirmationCode) == 0)) { goto err; } memset(&sha256ctx, 0, sizeof(sha256ctx)); euicc_sha256_init(&sha256ctx); euicc_sha256_update(&sha256ctx, (const uint8_t *)param_user->confirmationCode, strlen(param_user->confirmationCode)); euicc_sha256_final(&sha256ctx, hashCC); memset(&sha256ctx, 0, sizeof(sha256ctx)); euicc_sha256_init(&sha256ctx); euicc_sha256_update(&sha256ctx, hashCC, sizeof(hashCC)); euicc_sha256_update(&sha256ctx, n_transactionId.value, n_transactionId.length); euicc_sha256_final(&sha256ctx, hashCC); n_hashCc.tag = 0x04; n_hashCc.value = hashCC; n_hashCc.length = sizeof(hashCC); n_smdpSignature2.pack.next = &n_hashCc; n_hashCc.pack.next = &n_smdpCertificate; } else { n_smdpSignature2.pack.next = &n_smdpCertificate; } if (euicc_derutil_pack_alloc(&reqbuf, &reqlen, &n_request) < 0) { goto err; } free(smdpSigned2); smdpSigned2 = NULL; free(smdpSignature2); smdpSignature2 = NULL; free(smdpCertificate); smdpCertificate = NULL; if (es10x_command(ctx, &respbuf, &resplen, reqbuf, reqlen) < 0) { goto err; } free(reqbuf); reqbuf = NULL; *b64_PrepareDownloadResponse = malloc(euicc_base64_encode_len(resplen)); if (!(*b64_PrepareDownloadResponse)) { goto err; } if (euicc_base64_encode(*b64_PrepareDownloadResponse, respbuf, resplen) < 0) { goto err; } fret = 0; goto exit; err: fret = -1; free(*b64_PrepareDownloadResponse); *b64_PrepareDownloadResponse = NULL; exit: free(smdpSigned2); smdpSigned2 = NULL; free(smdpSignature2); smdpSignature2 = NULL; free(smdpCertificate); smdpCertificate = NULL; free(reqbuf); reqbuf = NULL; free(respbuf); respbuf = NULL; return fret; } static int es10b_load_bound_profile_package_tx(struct euicc_ctx *ctx, struct es10b_load_bound_profile_package_result *result, const uint8_t *reqbuf, int reqbuf_len) { int fret = 0; uint8_t *respbuf = NULL; unsigned resplen; result->bppCommandId = ES10B_BPP_COMMAND_ID_UNDEFINED; result->errorReason = ES10B_ERROR_REASON_UNDEFINED; if (es10x_command(ctx, &respbuf, &resplen, reqbuf, reqbuf_len) < 0) { goto err; } if (resplen > 0) { struct euicc_derutil_node tmpnode, n_finalResult; if (euicc_derutil_unpack_find_tag(&tmpnode, 0xBF37, respbuf, resplen) < 0) // ProfileInstallationResult { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, 0xBF27, tmpnode.value, tmpnode.length) < 0) // ProfileInstallationResultData { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, 0xA2, tmpnode.value, tmpnode.length) < 0) // finalResult { goto err; } if (euicc_derutil_unpack_first(&n_finalResult, tmpnode.value, tmpnode.length) < 0) { goto err; } switch (n_finalResult.tag) { case 0xA0: // SuccessResult break; case 0xA1: // ErrorResult tmpnode.self.ptr = n_finalResult.value; tmpnode.self.length = 0; while (euicc_derutil_unpack_next(&tmpnode, &tmpnode, n_finalResult.value, n_finalResult.length) == 0) { int tmpint; switch (tmpnode.tag) { case 0x80: tmpint = euicc_derutil_convert_bin2long(tmpnode.value, tmpnode.length); switch (tmpint) { case ES10B_BPP_COMMAND_ID_INITIALISE_SECURE_CHANNEL: case ES10B_BPP_COMMAND_ID_CONFIGURE_ISDP: case ES10B_BPP_COMMAND_ID_STORE_METADATA: case ES10B_BPP_COMMAND_ID_STORE_METADATA2: case ES10B_BPP_COMMAND_ID_REPLACE_SESSION_KEYS: case ES10B_BPP_COMMAND_ID_LOAD_PROFILE_ELEMENTS: result->bppCommandId = tmpint; break; default: result->bppCommandId = ES10B_BPP_COMMAND_ID_UNDEFINED; break; } break; case 0x81: tmpint = euicc_derutil_convert_bin2long(tmpnode.value, tmpnode.length); switch (tmpint) { case ES10B_ERROR_REASON_INCORRECT_INPUT_VALUES: case ES10B_ERROR_REASON_INVALID_SIGNATURE: case ES10B_ERROR_REASON_INVALID_TRANSACTION_ID: case ES10B_ERROR_REASON_UNSUPPORTED_CRT_VALUES: case ES10B_ERROR_REASON_UNSUPPORTED_REMOTE_OPERATION_TYPE: case ES10B_ERROR_REASON_UNSUPPORTED_PROFILE_CLASS: case ES10B_ERROR_REASON_SCP03T_STRUCTURE_ERROR: case ES10B_ERROR_REASON_SCP03T_SECURITY_ERROR: case ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_ALREADY_EXISTS_ON_EUICC: case ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INSUFFICIENT_MEMORY_FOR_PROFILE: case ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INTERRUPTION: case ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_PE_PROCESSING_ERROR: case ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_MISMATCH: case ES10B_ERROR_REASON_TEST_PROFILE_INSTALL_FAILED_DUE_TO_INVALID_NAA_KEY: case ES10B_ERROR_REASON_PPR_NOT_ALLOWED: case ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_UNKNOWN_ERROR: result->errorReason = tmpint; break; default: result->errorReason = ES10B_ERROR_REASON_UNDEFINED; break; } break; } } goto err; default: goto err; } } fret = 0; goto exit; err: fret = -1; exit: free(respbuf); respbuf = NULL; return fret; } int es10b_load_bound_profile_package_r(struct euicc_ctx *ctx, struct es10b_load_bound_profile_package_result *result, const char *b64_BoundProfilePackage) { int fret = 0; uint8_t *bpp = NULL; int bpp_len; const uint8_t *reqbuf; int reqbuf_len; struct euicc_derutil_node tmpnode, tmpchildnode, n_BoundProfilePackage; bpp = malloc(euicc_base64_decode_len(b64_BoundProfilePackage)); if (!bpp) { goto err; } if ((bpp_len = euicc_base64_decode(bpp, b64_BoundProfilePackage)) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_BoundProfilePackage, 0xBF36, bpp, bpp_len) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, 0xBF23, n_BoundProfilePackage.value, n_BoundProfilePackage.length) < 0) { goto err; } reqbuf = n_BoundProfilePackage.self.ptr; reqbuf_len = tmpnode.self.ptr - n_BoundProfilePackage.self.ptr + tmpnode.self.length; if (es10b_load_bound_profile_package_tx(ctx, result, reqbuf, reqbuf_len) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, 0xA0, n_BoundProfilePackage.value, n_BoundProfilePackage.length) < 0) { goto err; } reqbuf = tmpnode.self.ptr; reqbuf_len = tmpnode.self.length; if (es10b_load_bound_profile_package_tx(ctx, result, reqbuf, reqbuf_len) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, 0xA1, n_BoundProfilePackage.value, n_BoundProfilePackage.length) < 0) { goto err; } reqbuf = tmpnode.self.ptr; reqbuf_len = tmpnode.value - tmpnode.self.ptr; if (es10b_load_bound_profile_package_tx(ctx, result, reqbuf, reqbuf_len) < 0) { goto err; } tmpchildnode.self.ptr = tmpnode.value; tmpchildnode.self.length = 0; while (euicc_derutil_unpack_next(&tmpchildnode, &tmpchildnode, tmpnode.value, tmpnode.length) == 0) { reqbuf = tmpchildnode.self.ptr; reqbuf_len = tmpchildnode.self.length; if (es10b_load_bound_profile_package_tx(ctx, result, reqbuf, reqbuf_len) < 0) { goto err; } } if (euicc_derutil_unpack_find_tag(&tmpnode, 0xA2, n_BoundProfilePackage.value, n_BoundProfilePackage.length) == 0) { reqbuf = tmpnode.self.ptr; reqbuf_len = tmpnode.self.length; if (es10b_load_bound_profile_package_tx(ctx, result, reqbuf, reqbuf_len) < 0) { goto err; } } if (euicc_derutil_unpack_find_tag(&tmpnode, 0xA3, n_BoundProfilePackage.value, n_BoundProfilePackage.length) < 0) { goto err; } reqbuf = tmpnode.self.ptr; reqbuf_len = tmpnode.value - tmpnode.self.ptr; if (es10b_load_bound_profile_package_tx(ctx, result, reqbuf, reqbuf_len) < 0) { goto err; } tmpchildnode.self.ptr = tmpnode.value; tmpchildnode.self.length = 0; while (euicc_derutil_unpack_next(&tmpchildnode, &tmpchildnode, tmpnode.value, tmpnode.length) == 0) { reqbuf = tmpchildnode.self.ptr; reqbuf_len = tmpchildnode.self.length; if (es10b_load_bound_profile_package_tx(ctx, result, reqbuf, reqbuf_len) < 0) { goto err; } } goto exit; err: fret = -1; exit: free(bpp); bpp = NULL; return fret; } int es10b_get_euicc_challenge_r(struct euicc_ctx *ctx, char **b64_euiccChallenge) { int fret = 0; struct euicc_derutil_node n_request = { .tag = 0xBF2E, // GetEuiccDataRequest }; uint32_t reqlen; uint8_t *respbuf = NULL; unsigned resplen; struct euicc_derutil_node tmpnode; reqlen = sizeof(ctx->apdu._internal.request_buffer.body); if (euicc_derutil_pack(ctx->apdu._internal.request_buffer.body, &reqlen, &n_request)) { goto err; } if (es10x_command(ctx, &respbuf, &resplen, ctx->apdu._internal.request_buffer.body, reqlen) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, n_request.tag, respbuf, resplen)) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, 0x80, tmpnode.value, tmpnode.length)) { goto err; } *b64_euiccChallenge = malloc(euicc_base64_encode_len(tmpnode.length)); if (!(*b64_euiccChallenge)) { goto err; } if (euicc_base64_encode(*b64_euiccChallenge, tmpnode.value, tmpnode.length) < 0) { goto err; } goto exit; err: fret = -1; free(*b64_euiccChallenge); *b64_euiccChallenge = NULL; exit: free(respbuf); respbuf = NULL; return fret; } int es10b_get_euicc_info_r(struct euicc_ctx *ctx, char **b64_EUICCInfo1) { int fret = 0; struct euicc_derutil_node n_request = { .tag = 0xBF20, // GetEuiccInfo1Request }; uint32_t reqlen; uint8_t *respbuf = NULL; unsigned resplen; struct euicc_derutil_node tmpnode; reqlen = sizeof(ctx->apdu._internal.request_buffer.body); if (euicc_derutil_pack(ctx->apdu._internal.request_buffer.body, &reqlen, &n_request)) { goto err; } if (es10x_command(ctx, &respbuf, &resplen, ctx->apdu._internal.request_buffer.body, reqlen) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, n_request.tag, respbuf, resplen)) { goto err; } *b64_EUICCInfo1 = malloc(euicc_base64_encode_len(tmpnode.self.length)); if (!(*b64_EUICCInfo1)) { goto err; } if (euicc_base64_encode(*b64_EUICCInfo1, tmpnode.self.ptr, tmpnode.self.length) < 0) { goto err; } goto exit; err: fret = -1; free(*b64_EUICCInfo1); *b64_EUICCInfo1 = NULL; exit: free(respbuf); respbuf = NULL; return fret; } int es10b_authenticate_server_r(struct euicc_ctx *ctx, uint8_t **transaction_id, uint32_t *transaction_id_len, char **b64_AuthenticateServerResponse, struct es10b_authenticate_server_param *param, struct es10b_authenticate_server_param_user *param_user) { int fret = 0; uint8_t *reqbuf = NULL; uint32_t reqlen; uint8_t *respbuf = NULL; unsigned resplen; uint8_t imei[8]; uint8_t *serverSigned1 = NULL, *serverSignature1 = NULL, *euiccCiPKIdToBeUsed = NULL, *serverCertificate = NULL; int serverSigned1_len, serverSignature1_len, euiccCiPKIdToBeUsed_len, serverCertificate_len; struct euicc_derutil_node n_request, n_serverSigned1, n_transactionId, n_serverSignature1, n_euiccCiPKIdToBeUsed, n_serverCertificate, n_CtxParams1, n_matchingId, n_deviceInfo, n_tac, n_deviceCapabilities, n_imei; *transaction_id = NULL; *transaction_id_len = 0; *b64_AuthenticateServerResponse = NULL; memset(&n_request, 0, sizeof(n_request)); memset(&n_serverSigned1, 0, sizeof(n_serverSigned1)); memset(&n_serverSignature1, 0, sizeof(n_serverSignature1)); memset(&n_euiccCiPKIdToBeUsed, 0, sizeof(n_euiccCiPKIdToBeUsed)); memset(&n_serverCertificate, 0, sizeof(n_serverCertificate)); memset(&n_CtxParams1, 0, sizeof(n_CtxParams1)); memset(&n_matchingId, 0, sizeof(n_matchingId)); memset(&n_deviceInfo, 0, sizeof(n_deviceInfo)); memset(&n_tac, 0, sizeof(n_tac)); memset(&n_deviceCapabilities, 0, sizeof(n_deviceCapabilities)); memset(&n_imei, 0, sizeof(n_imei)); serverSigned1 = malloc(euicc_base64_decode_len(param->b64_serverSigned1)); if (!serverSigned1) { goto err; } serverSignature1 = malloc(euicc_base64_decode_len(param->b64_serverSignature1)); if (!serverSignature1) { goto err; } euiccCiPKIdToBeUsed = malloc(euicc_base64_decode_len(param->b64_euiccCiPKIdToBeUsed)); if (!euiccCiPKIdToBeUsed) { goto err; } serverCertificate = malloc(euicc_base64_decode_len(param->b64_serverCertificate)); if (!serverCertificate) { goto err; } if ((serverSigned1_len = euicc_base64_decode(serverSigned1, param->b64_serverSigned1)) < 0) { goto err; } if ((serverSignature1_len = euicc_base64_decode(serverSignature1, param->b64_serverSignature1)) < 0) { goto err; } if ((euiccCiPKIdToBeUsed_len = euicc_base64_decode(euiccCiPKIdToBeUsed, param->b64_euiccCiPKIdToBeUsed)) < 0) { goto err; } if ((serverCertificate_len = euicc_base64_decode(serverCertificate, param->b64_serverCertificate)) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_serverSigned1, 0x30, serverSigned1, serverSigned1_len) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_transactionId, 0x80, n_serverSigned1.value, n_serverSigned1.length) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_serverSignature1, 0x5F37, serverSignature1, serverSignature1_len) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_euiccCiPKIdToBeUsed, 0x04, euiccCiPKIdToBeUsed, euiccCiPKIdToBeUsed_len) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_serverCertificate, 0x30, serverCertificate, serverCertificate_len) < 0) { goto err; } *transaction_id_len = n_transactionId.length; *transaction_id = malloc(n_transactionId.length); if (!(*transaction_id)) { goto err; } memcpy(*transaction_id, n_transactionId.value, n_transactionId.length); n_request.tag = 0xBF38; n_request.pack.child = &n_serverSigned1; n_serverSigned1.pack.next = &n_serverSignature1; n_serverSignature1.pack.next = &n_euiccCiPKIdToBeUsed; n_euiccCiPKIdToBeUsed.pack.next = &n_serverCertificate; n_serverCertificate.pack.next = &n_CtxParams1; n_CtxParams1.tag = 0xA0; n_deviceInfo.tag = 0xA1; n_deviceInfo.pack.child = &n_tac; n_tac.tag = 0x80; n_tac.value = imei; n_tac.length = 4; n_tac.pack.next = &n_deviceCapabilities; n_deviceCapabilities.tag = 0xA1; if (param_user->imei) { int imei_len; imei_len = euicc_hexutil_gsmbcd2bin(imei, sizeof(imei), param_user->imei, 0); if (imei_len < 0) { goto err; } n_deviceCapabilities.pack.next = &n_imei; n_imei.tag = 0x82; n_imei.value = imei; n_imei.length = imei_len; } else { memcpy(imei, (uint8_t[]){0x35, 0x29, 0x06, 0x11}, 4); } if (param_user->matchingId) { n_CtxParams1.pack.child = &n_matchingId; n_matchingId.tag = 0x80; n_matchingId.value = (const uint8_t *)param_user->matchingId; n_matchingId.length = strlen(param_user->matchingId); n_matchingId.pack.next = &n_deviceInfo; } else { n_CtxParams1.pack.child = &n_deviceInfo; } if (euicc_derutil_pack_alloc(&reqbuf, &reqlen, &n_request) < 0) { goto err; } free(serverSigned1); serverSigned1 = NULL; free(serverSignature1); serverSignature1 = NULL; free(euiccCiPKIdToBeUsed); euiccCiPKIdToBeUsed = NULL; free(serverCertificate); serverCertificate = NULL; if (es10x_command(ctx, &respbuf, &resplen, reqbuf, reqlen) < 0) { goto err; } free(reqbuf); reqbuf = NULL; *b64_AuthenticateServerResponse = malloc(euicc_base64_encode_len(resplen)); if (!(*b64_AuthenticateServerResponse)) { goto err; } if (euicc_base64_encode(*b64_AuthenticateServerResponse, respbuf, resplen) < 0) { goto err; } fret = 0; goto exit; err: fret = -1; free(*transaction_id); *transaction_id = NULL; *transaction_id_len = 0; free(*b64_AuthenticateServerResponse); *b64_AuthenticateServerResponse = NULL; exit: free(serverSigned1); serverSigned1 = NULL; free(serverSignature1); serverSignature1 = NULL; free(euiccCiPKIdToBeUsed); euiccCiPKIdToBeUsed = NULL; free(serverCertificate); serverCertificate = NULL; free(reqbuf); reqbuf = NULL; free(respbuf); respbuf = NULL; return fret; } int es10b_cancel_session_r(struct euicc_ctx *ctx, char **b64_CancelSessionResponse, struct es10b_cancel_session_param *param) { int fret = 0; struct euicc_derutil_node n_request, n_transactionId, n_reason; uint8_t reason_buf[sizeof(enum es10b_cancel_session_reason)]; uint32_t reason_buf_len; uint32_t reqlen; uint8_t *respbuf = NULL; unsigned resplen; struct euicc_derutil_node tmpnode; if (euicc_derutil_convert_long2bin(reason_buf, &reason_buf_len, param->reason) < 0) { goto err; } memset(&n_request, 0, sizeof(n_request)); memset(&n_transactionId, 0, sizeof(n_transactionId)); memset(&n_reason, 0, sizeof(n_reason)); n_request.tag = 0xBF41; // CancelSessionRequest n_request.pack.child = &n_transactionId; n_transactionId.tag = 0x80; n_transactionId.value = (const uint8_t *)param->transactionId; n_transactionId.length = param->transactionIdLen; n_reason.tag = 0x81; n_reason.value = reason_buf; n_reason.length = reason_buf_len; reqlen = sizeof(ctx->apdu._internal.request_buffer.body); if (euicc_derutil_pack(ctx->apdu._internal.request_buffer.body, &reqlen, &n_request)) { goto err; } if (es10x_command(ctx, &respbuf, &resplen, ctx->apdu._internal.request_buffer.body, reqlen) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, n_request.tag, respbuf, resplen)) { goto err; } *b64_CancelSessionResponse = malloc(euicc_base64_encode_len(tmpnode.self.length)); if (!(*b64_CancelSessionResponse)) { goto err; } if (euicc_base64_encode(*b64_CancelSessionResponse, tmpnode.self.ptr, tmpnode.self.length) < 0) { goto err; } goto exit; err: fret = -1; free(*b64_CancelSessionResponse); *b64_CancelSessionResponse = NULL; exit: free(respbuf); respbuf = NULL; return fret; } void es10b_prepare_download_param_free(struct es10b_prepare_download_param *param) { if (!param) { return; } free(param->b64_profileMetadata); free(param->b64_smdpCertificate); free(param->b64_smdpSignature2); free(param->b64_smdpSigned2); memset(param, 0x00, sizeof(*param)); } void es10b_authenticate_server_param_free(struct es10b_authenticate_server_param *param) { if (!param) { return; } free(param->b64_euiccCiPKIdToBeUsed); free(param->b64_serverCertificate); free(param->b64_serverSignature1); free(param->b64_serverSigned1); memset(param, 0x00, sizeof(*param)); } int es10b_prepare_download(struct euicc_ctx *ctx, const char *confirmationCode) { int fret; struct es10b_prepare_download_param_user param_user = { .confirmationCode = confirmationCode, }; if (ctx->http._internal.b64_prepare_download_response) { return -1; } if (ctx->http._internal.prepare_download_param == NULL) { return -1; } fret = es10b_prepare_download_r(ctx, &ctx->http._internal.b64_prepare_download_response, ctx->http._internal.prepare_download_param, ¶m_user); if (fret < 0) { ctx->http._internal.b64_prepare_download_response = NULL; return fret; } es10b_prepare_download_param_free(ctx->http._internal.prepare_download_param); free(ctx->http._internal.prepare_download_param); ctx->http._internal.prepare_download_param = NULL; return fret; } int es10b_load_bound_profile_package(struct euicc_ctx *ctx, struct es10b_load_bound_profile_package_result *result) { int fret; if (ctx->http._internal.b64_bound_profile_package == NULL) { return -1; } fret = es10b_load_bound_profile_package_r(ctx, result, ctx->http._internal.b64_bound_profile_package); if (fret < 0) { return fret; } free(ctx->http._internal.b64_bound_profile_package); ctx->http._internal.b64_bound_profile_package = NULL; return fret; } int es10b_get_euicc_challenge_and_info(struct euicc_ctx *ctx) { int fret; if (ctx->http._internal.b64_euicc_challenge) { return -1; } if (ctx->http._internal.b64_euicc_info_1) { return -1; } fret = es10b_get_euicc_challenge_r(ctx, &ctx->http._internal.b64_euicc_challenge); if (fret < 0) { goto err; } fret = es10b_get_euicc_info_r(ctx, &ctx->http._internal.b64_euicc_info_1); if (fret < 0) { goto err; } return fret; err: free(ctx->http._internal.b64_euicc_challenge); ctx->http._internal.b64_euicc_challenge = NULL; free(ctx->http._internal.b64_euicc_info_1); ctx->http._internal.b64_euicc_info_1 = NULL; return -1; } int es10b_authenticate_server(struct euicc_ctx *ctx, const char *matchingId, const char *imei) { int fret; struct es10b_authenticate_server_param_user param_user = { .matchingId = matchingId, .imei = imei, }; if (ctx->http._internal.b64_authenticate_server_response) { return -1; } if (ctx->http._internal.authenticate_server_param == NULL) { return -1; } fret = es10b_authenticate_server_r(ctx, &ctx->http._internal.transaction_id_bin, &ctx->http._internal.transaction_id_bin_len, &ctx->http._internal.b64_authenticate_server_response, ctx->http._internal.authenticate_server_param, ¶m_user); if (fret < 0) { ctx->http._internal.b64_authenticate_server_response = NULL; return fret; } es10b_authenticate_server_param_free(ctx->http._internal.authenticate_server_param); free(ctx->http._internal.authenticate_server_param); ctx->http._internal.authenticate_server_param = NULL; return fret; } int es10b_cancel_session(struct euicc_ctx *ctx, enum es10b_cancel_session_reason reason) { int fret; struct es10b_cancel_session_param param = { .transactionId = ctx->http._internal.transaction_id_bin, .transactionIdLen = ctx->http._internal.transaction_id_bin_len, .reason = reason, }; if (ctx->http._internal.transaction_id_bin == NULL) { return -1; } if (ctx->http._internal.transaction_id_bin_len == 0) { return -1; } if (ctx->http._internal.b64_cancel_session_response) { return -1; } fret = es10b_cancel_session_r(ctx, &ctx->http._internal.b64_cancel_session_response, ¶m); if (fret < 0) { ctx->http._internal.b64_cancel_session_response = NULL; } return fret; } int es10b_list_notification(struct euicc_ctx *ctx, struct es10b_notification_metadata_list **notificationMetadataList) { int fret = 0; struct euicc_derutil_node n_request = { .tag = 0xBF28, // ListNotificationRequest }; uint32_t reqlen; uint8_t *respbuf = NULL; unsigned resplen; struct euicc_derutil_node tmpnode, n_notificationMetadataList, n_NotificationMetadata; struct es10b_notification_metadata_list *list_wptr = NULL; *notificationMetadataList = NULL; reqlen = sizeof(ctx->apdu._internal.request_buffer.body); if (euicc_derutil_pack(ctx->apdu._internal.request_buffer.body, &reqlen, &n_request)) { goto err; } if (es10x_command(ctx, &respbuf, &resplen, ctx->apdu._internal.request_buffer.body, reqlen) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, n_request.tag, respbuf, resplen) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_notificationMetadataList, 0xA0, tmpnode.value, tmpnode.length) < 0) { goto err; } n_NotificationMetadata.self.ptr = n_notificationMetadataList.value; n_NotificationMetadata.self.length = 0; while (euicc_derutil_unpack_next(&n_NotificationMetadata, &n_NotificationMetadata, n_notificationMetadataList.value, n_notificationMetadataList.length) == 0) { struct es10b_notification_metadata_list *p; if (n_NotificationMetadata.tag != 0xBF2F) { continue; } p = malloc(sizeof(struct es10b_notification_metadata_list)); if (!p) { goto err; } memset(p, 0, sizeof(*p)); tmpnode.self.ptr = n_NotificationMetadata.value; tmpnode.self.length = 0; p->profileManagementOperation = ES10B_PROFILE_MANAGEMENT_OPERATION_NULL; while (euicc_derutil_unpack_next(&tmpnode, &tmpnode, n_NotificationMetadata.value, n_NotificationMetadata.length) == 0) { switch (tmpnode.tag) { case 0x80: p->seqNumber = euicc_derutil_convert_bin2long(tmpnode.value, tmpnode.length); break; case 0x81: if (tmpnode.length >= 2) { switch (tmpnode.value[1]) { case ES10B_PROFILE_MANAGEMENT_OPERATION_INSTALL: case ES10B_PROFILE_MANAGEMENT_OPERATION_ENABLE: case ES10B_PROFILE_MANAGEMENT_OPERATION_DISABLE: case ES10B_PROFILE_MANAGEMENT_OPERATION_DELETE: p->profileManagementOperation = tmpnode.value[1]; break; default: p->profileManagementOperation = ES10B_PROFILE_MANAGEMENT_OPERATION_UNDEFINED; break; } } break; case 0x0C: p->notificationAddress = malloc(tmpnode.length + 1); if (p->notificationAddress) { memcpy(p->notificationAddress, tmpnode.value, tmpnode.length); p->notificationAddress[tmpnode.length] = '\0'; } break; case 0x5A: p->iccid = malloc((tmpnode.length * 2) + 1); if (p->iccid) { if (euicc_hexutil_bin2gsmbcd(p->iccid, (tmpnode.length * 2) + 1, tmpnode.value, tmpnode.length) < 0) { free(p->iccid); p->iccid = NULL; } } break; } } if (*notificationMetadataList == NULL) { *notificationMetadataList = p; } else { list_wptr->next = p; } list_wptr = p; } goto exit; err: fret = -1; es10b_notification_metadata_list_free_all(*notificationMetadataList); exit: free(respbuf); respbuf = NULL; return fret; } int es10b_retrieve_notifications_list(struct euicc_ctx *ctx, struct es10b_pending_notification *PendingNotification, unsigned long seqNumber) { int fret = 0; uint8_t seqNumber_buf[sizeof(seqNumber)]; uint32_t seqNumber_buf_len = sizeof(seqNumber_buf); struct euicc_derutil_node n_request, n_searchCriteria, n_seqNumber; uint32_t reqlen; uint8_t *respbuf = NULL; unsigned resplen; struct euicc_derutil_node tmpnode, n_PendingNotification, n_NotificationMetadata; memset(PendingNotification, 0, sizeof(struct es10b_pending_notification)); if (euicc_derutil_convert_long2bin(seqNumber_buf, &seqNumber_buf_len, seqNumber) < 0) { goto err; } memset(&n_request, 0, sizeof(n_request)); memset(&n_searchCriteria, 0, sizeof(n_searchCriteria)); memset(&n_seqNumber, 0, sizeof(n_seqNumber)); n_request.tag = 0xBF2B; // RetrieveNotificationsListRequest n_request.pack.child = &n_searchCriteria; n_searchCriteria.tag = 0xA0; // searchCriteria n_searchCriteria.pack.child = &n_seqNumber; n_seqNumber.tag = 0x80; // seqNumber n_seqNumber.length = seqNumber_buf_len; n_seqNumber.value = seqNumber_buf; reqlen = sizeof(ctx->apdu._internal.request_buffer.body); if (euicc_derutil_pack(ctx->apdu._internal.request_buffer.body, &reqlen, &n_request)) { goto err; } if (es10x_command(ctx, &respbuf, &resplen, ctx->apdu._internal.request_buffer.body, reqlen) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, n_request.tag, respbuf, resplen) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, 0xA0, tmpnode.value, tmpnode.length) < 0) { goto err; } if (euicc_derutil_unpack_find_alias_tags(&n_PendingNotification, (uint16_t[]){0xBF37, 0x30}, 2, tmpnode.value, tmpnode.length) < 0) { goto err; } switch (n_PendingNotification.tag) { case 0xBF37: // profileInstallationResult if (euicc_derutil_unpack_find_tag(&tmpnode, 0xBF27, n_PendingNotification.value, n_PendingNotification.length) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&n_NotificationMetadata, 0xBF2F, tmpnode.value, tmpnode.length) < 0) { goto err; } break; case 0x30: // otherSignedNotification if (euicc_derutil_unpack_find_tag(&n_NotificationMetadata, 0xBF2F, n_PendingNotification.value, n_PendingNotification.length) < 0) { goto err; } break; } if (euicc_derutil_unpack_find_tag(&tmpnode, 0x0C, n_NotificationMetadata.value, n_NotificationMetadata.length) < 0) { goto err; } PendingNotification->notificationAddress = malloc(tmpnode.length + 1); if (!PendingNotification->notificationAddress) { goto err; } memcpy(PendingNotification->notificationAddress, tmpnode.value, tmpnode.length); PendingNotification->notificationAddress[tmpnode.length] = '\0'; PendingNotification->b64_PendingNotification = malloc(euicc_base64_encode_len(n_PendingNotification.self.length)); if (!PendingNotification->b64_PendingNotification) { goto err; } if (euicc_base64_encode(PendingNotification->b64_PendingNotification, n_PendingNotification.self.ptr, n_PendingNotification.self.length) < 0) { goto err; } fret = 0; goto exit; err: fret = -1; es10b_pending_notification_free(PendingNotification); exit: free(respbuf); respbuf = NULL; return fret; } int es10b_remove_notification_from_list(struct euicc_ctx *ctx, unsigned long seqNumber) { int fret = 0; uint8_t seqNumber_buf[sizeof(seqNumber)]; uint32_t seqNumber_buf_len = sizeof(seqNumber_buf); struct euicc_derutil_node n_request, n_seqNumber; uint32_t reqlen; uint8_t *respbuf = NULL; unsigned resplen; struct euicc_derutil_node tmpnode; if (euicc_derutil_convert_long2bin(seqNumber_buf, &seqNumber_buf_len, seqNumber) < 0) { goto err; } memset(&n_request, 0, sizeof(n_request)); memset(&n_seqNumber, 0, sizeof(n_seqNumber)); n_request.tag = 0xBF30; // NotificationSentRequest n_request.pack.child = &n_seqNumber; n_seqNumber.tag = 0x80; // seqNumber n_seqNumber.length = seqNumber_buf_len; n_seqNumber.value = seqNumber_buf; reqlen = sizeof(ctx->apdu._internal.request_buffer.body); if (euicc_derutil_pack(ctx->apdu._internal.request_buffer.body, &reqlen, &n_request)) { goto err; } if (es10x_command(ctx, &respbuf, &resplen, ctx->apdu._internal.request_buffer.body, reqlen) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, n_request.tag, respbuf, resplen) < 0) { goto err; } if (euicc_derutil_unpack_find_tag(&tmpnode, 0x80, tmpnode.value, tmpnode.length) < 0) { goto err; } fret = euicc_derutil_convert_bin2long(tmpnode.value, tmpnode.length); goto exit; err: fret = -1; exit: free(respbuf); respbuf = NULL; return fret; } void es10b_notification_metadata_list_free_all(struct es10b_notification_metadata_list *notificationMetadataList) { while (notificationMetadataList) { struct es10b_notification_metadata_list *next = notificationMetadataList->next; free(notificationMetadataList->notificationAddress); free(notificationMetadataList->iccid); free(notificationMetadataList); notificationMetadataList = next; } } void es10b_pending_notification_free(struct es10b_pending_notification *PendingNotification) { free(PendingNotification->notificationAddress); free(PendingNotification->b64_PendingNotification); memset(PendingNotification, 0, sizeof(struct es10b_pending_notification)); } int es10b_get_rat(struct euicc_ctx *ctx, struct es10b_rat **ratList) { int fret; struct euicc_derutil_node n_request = { .tag = 0xBF43, // GetRatRequest }; uint32_t reqlen; uint8_t *respbuf = NULL; unsigned resplen; struct es10b_rat *rat; struct euicc_derutil_node tmpnode, tmpchildnode, n_profile; *ratList = NULL; reqlen = sizeof(ctx->apdu._internal.request_buffer.body); if (euicc_derutil_pack(ctx->apdu._internal.request_buffer.body, &reqlen, &n_request)) { goto err; } if (es10x_command(ctx, &respbuf, &resplen, ctx->apdu._internal.request_buffer.body, reqlen) < 0) { goto err; } if (resplen == 0) { goto err; } // GetRatResponse if (euicc_derutil_unpack_find_tag(&tmpnode, 0xBF43, respbuf, resplen) < 0) { goto err; } // RulesAuthorisationTable if (euicc_derutil_unpack_find_tag(&tmpnode, 0xA0, tmpnode.value, tmpnode.length) < 0) { goto err; } n_profile.self.ptr = tmpnode.value; n_profile.self.length = 0; // ProfilePolicyAuthorisationRule while (euicc_derutil_unpack_next(&n_profile, &n_profile, tmpnode.value, tmpnode.length) == 0) { tmpchildnode.self.ptr = n_profile.value; tmpchildnode.self.length = 0; rat = malloc(sizeof(struct es10b_rat)); if (!rat) { goto err; } memset(rat, 0, sizeof(*rat)); while (euicc_derutil_unpack_next(&tmpchildnode, &tmpchildnode, n_profile.value, n_profile.length) == 0) { switch (tmpchildnode.tag) { case 0x80: // ppr ids { static const char *desc[] = {"pprUpdateControl", "ppr1", "ppr2", "ppr3", NULL}; if (euicc_derutil_convert_bin2bits_str(&rat->pprIds, tmpchildnode.value, tmpchildnode.length, desc)) { goto err; } } break; case 0xA1: // allowed operators { struct euicc_derutil_node n_allowed_operator, n_operator; struct es10b_operation_id *operations_wptr = NULL; struct es10b_operation_id *p; n_allowed_operator.self.ptr = tmpchildnode.value; n_allowed_operator.self.length = 0; while (euicc_derutil_unpack_next(&n_allowed_operator, &n_allowed_operator, tmpchildnode.value, tmpchildnode.length) == 0) { p = malloc(sizeof(struct es10b_operation_id)); if (!p) { goto err; } memset(p, 0, sizeof(*p)); n_operator.self.ptr = n_allowed_operator.value; n_operator.self.length = 0; while (euicc_derutil_unpack_next(&n_operator, &n_operator, n_allowed_operator.value, n_allowed_operator.length) == 0) { if (n_operator.length == 0) { continue; } switch (n_operator.tag) { case 0x80: // mcc_mnc p->plmn = malloc((n_operator.length * 2) + 1); euicc_hexutil_bin2hex(p->plmn, sizeof(p->plmn), n_operator.value, n_operator.length); break; case 0x81: // gid1 p->gid1 = malloc((n_operator.length * 2) + 1); euicc_hexutil_bin2hex(p->gid1, sizeof(p->gid1), n_operator.value, n_operator.length); break; case 0x82: // gid2 p->gid2 = malloc((n_operator.length * 2) + 1); euicc_hexutil_bin2hex(p->gid2, sizeof(p->gid2), n_operator.value, n_operator.length); break; } } if (operations_wptr == NULL) { operations_wptr = p; } else { operations_wptr->next = p; } } rat->allowedOperators = operations_wptr; } break; case 0x82: // ppr flags { static const char *desc[] = {"consentRequired", NULL}; if (euicc_derutil_convert_bin2bits_str(&rat->pprFlags, tmpchildnode.value, tmpchildnode.length, desc)) { goto err; } } break; } } if (*ratList == NULL) { *ratList = rat; } else { (*ratList)->next = rat; } } fret = 0; goto exit; err: fret = -1; es10b_rat_list_free_all(*ratList); *ratList = NULL; exit: free(respbuf); respbuf = NULL; return fret; } void es10b_rat_list_free_all(struct es10b_rat *ratList) { struct es10b_rat *next_rat; struct es10b_operation_id *next_operation_id; while (ratList) { next_rat = ratList->next; free(ratList->pprIds); while (ratList->allowedOperators) { next_operation_id = ratList->allowedOperators->next; free(ratList->allowedOperators->plmn); free(ratList->allowedOperators->gid1); free(ratList->allowedOperators->gid2); free(ratList->allowedOperators); ratList->allowedOperators = next_operation_id; } free(ratList->pprFlags); free(ratList); ratList = next_rat; } }