Compare commits
1 commit
4989b1eec7
...
9cd866f464
Author | SHA1 | Date | |
---|---|---|---|
9cd866f464 |
9 changed files with 218 additions and 13 deletions
|
@ -1,9 +1,11 @@
|
|||
package im.angry.openeuicc.core
|
||||
|
||||
import net.typeblog.lpac_jni.EuiccConfiguredAddresses
|
||||
import net.typeblog.lpac_jni.EuiccInfo2
|
||||
import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||
import net.typeblog.lpac_jni.LocalProfileInfo
|
||||
import net.typeblog.lpac_jni.LocalProfileNotification
|
||||
import net.typeblog.lpac_jni.ProfileDiscoveryCallback
|
||||
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
||||
|
||||
class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) :
|
||||
|
@ -32,6 +34,9 @@ class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) :
|
|||
|
||||
override fun setEs10xMss(mss: Byte) = lpa.setEs10xMss(mss)
|
||||
|
||||
override fun getEuiccConfiguredAddresses(): EuiccConfiguredAddresses =
|
||||
lpa.getEuiccConfiguredAddresses()
|
||||
|
||||
override fun enableProfile(iccid: String, refresh: Boolean): Boolean =
|
||||
lpa.enableProfile(iccid, refresh)
|
||||
|
||||
|
@ -48,6 +53,9 @@ class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) :
|
|||
callback: ProfileDownloadCallback
|
||||
) = lpa.downloadProfile(smdp, matchingId, imei, confirmationCode, callback)
|
||||
|
||||
override fun discoveryProfile(smds: String, imei: String?, callback: ProfileDiscoveryCallback) =
|
||||
lpa.discoveryProfile(smds, imei, callback)
|
||||
|
||||
override fun deleteNotification(seqNumber: Long): Boolean = lpa.deleteNotification(seqNumber)
|
||||
|
||||
override fun handleNotification(seqNumber: Long): Boolean = lpa.handleNotification(seqNumber)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package net.typeblog.lpac_jni
|
||||
|
||||
import android.util.Patterns
|
||||
|
||||
// example address in GSMA SGP.26, some chips use addresses like this
|
||||
@Suppress("SpellCheckingInspection")
|
||||
val invalidDPAddresses = setOf(
|
||||
"testrootsmds.gsma.com",
|
||||
"testrootsmds.example.com",
|
||||
)
|
||||
|
||||
class EuiccConfiguredAddresses(defaultDPAddress: String?, rootDSAddress: String?) {
|
||||
val defaultDPAddress: String? = defaultDPAddress.takeUnless(::isInvalidDPAddress)
|
||||
val rootDSAddress = rootDSAddress.takeUnless(::isInvalidDSAddress)
|
||||
|
||||
val discoverable: Boolean
|
||||
get() = !defaultDPAddress.isNullOrBlank() || !rootDSAddress.isNullOrBlank()
|
||||
}
|
||||
|
||||
private fun isInvalidDPAddress(address: String?): Boolean {
|
||||
if (address.isNullOrBlank()) return true
|
||||
return !Patterns.DOMAIN_NAME.matcher(address).matches()
|
||||
}
|
||||
|
||||
private fun isInvalidDSAddress(address: String?): Boolean {
|
||||
if (address.isNullOrBlank()) return true
|
||||
if (address in invalidDPAddresses) return true
|
||||
return !Patterns.DOMAIN_NAME.matcher(address).matches()
|
||||
}
|
|
@ -12,6 +12,15 @@ interface LocalProfileAssistant {
|
|||
val lastApduException: Exception?,
|
||||
) : Exception("Failed to download profile")
|
||||
|
||||
@Suppress("ArrayInDataClass")
|
||||
data class ProfileDiscoveryException(
|
||||
val lpaErrorReason: String,
|
||||
val lastHttpResponse: HttpResponse?,
|
||||
val lastHttpException: Exception?,
|
||||
val lastApduResponse: ByteArray?,
|
||||
val lastApduException: Exception?,
|
||||
) : Exception("Failed to discovery profile")
|
||||
|
||||
class ProfileRenameException() : Exception("Failed to rename profile")
|
||||
class ProfileNameTooLongException() : Exception("Profile name too long")
|
||||
class ProfileNameIsInvalidUTF8Exception() : Exception("Profile name is invalid UTF-8")
|
||||
|
@ -30,6 +39,9 @@ interface LocalProfileAssistant {
|
|||
*/
|
||||
fun setEs10xMss(mss: Byte)
|
||||
|
||||
// es10a
|
||||
fun getEuiccConfiguredAddresses(): EuiccConfiguredAddresses
|
||||
|
||||
// All blocking functions in this class assume that they are executed on non-Main threads
|
||||
// The IO context in Kotlin's coroutine library is recommended.
|
||||
fun enableProfile(iccid: String, refresh: Boolean = true): Boolean
|
||||
|
@ -38,6 +50,7 @@ interface LocalProfileAssistant {
|
|||
|
||||
fun downloadProfile(smdp: String, matchingId: String?, imei: String?,
|
||||
confirmationCode: String?, callback: ProfileDownloadCallback)
|
||||
fun discoveryProfile(smds: String, imei: String?, callback: ProfileDiscoveryCallback)
|
||||
|
||||
fun deleteNotification(seqNumber: Long): Boolean
|
||||
fun handleNotification(seqNumber: Long): Boolean
|
||||
|
|
|
@ -29,6 +29,12 @@ internal object LpacJni {
|
|||
external fun es10bListNotification(handle: Long): Long // A native pointer to a linked list. Handle with linked list-related methods below. May be 0 (null)
|
||||
external fun es10bDeleteNotification(handle: Long, seqNumber: Long): Int
|
||||
|
||||
// es10a
|
||||
external fun es10aGetEuiccConfiguredAddresses(handle: Long): EuiccConfiguredAddresses
|
||||
|
||||
// es9p + es11
|
||||
external fun discoveryProfile(handle: Long, address: String, imei: String?, callback: ProfileDiscoveryCallback): Int
|
||||
|
||||
// es9p + es10b
|
||||
// We do not expose all of the functions because of tediousness :)
|
||||
external fun downloadProfile(handle: Long, smdp: String, matchingId: String?, imei: String?,
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package net.typeblog.lpac_jni
|
||||
|
||||
interface ProfileDiscoveryCallback {
|
||||
fun onDiscovered(hosts: Array<String>)
|
||||
}
|
|
@ -9,6 +9,7 @@ import net.typeblog.lpac_jni.HttpInterface.HttpResponse
|
|||
import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||
import net.typeblog.lpac_jni.LocalProfileInfo
|
||||
import net.typeblog.lpac_jni.LocalProfileNotification
|
||||
import net.typeblog.lpac_jni.ProfileDiscoveryCallback
|
||||
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
||||
import net.typeblog.lpac_jni.Version
|
||||
|
||||
|
@ -93,6 +94,9 @@ class LocalProfileAssistantImpl(
|
|||
LpacJni.euiccSetMss(contextHandle, mss)
|
||||
}
|
||||
|
||||
override fun getEuiccConfiguredAddresses() =
|
||||
LpacJni.es10aGetEuiccConfiguredAddresses(contextHandle)
|
||||
|
||||
override val valid: Boolean
|
||||
get() = !finalized && apduInterface.valid && try {
|
||||
// If we can read both eID and euiccInfo2 properly, we are likely looking at
|
||||
|
@ -212,7 +216,7 @@ class LocalProfileAssistantImpl(
|
|||
callback
|
||||
)
|
||||
|
||||
if (res != 0) {
|
||||
if (res == 0) return
|
||||
// Construct the error now to store any error information we _can_ access
|
||||
val err = LocalProfileAssistant.ProfileDownloadException(
|
||||
lpaErrorReason = LpacJni.downloadErrCodeToString(-res),
|
||||
|
@ -227,6 +231,17 @@ class LocalProfileAssistantImpl(
|
|||
|
||||
throw err
|
||||
}
|
||||
|
||||
override fun discoveryProfile(smds: String, imei: String?, callback: ProfileDiscoveryCallback) {
|
||||
val res = LpacJni.discoveryProfile(contextHandle, smds, imei, callback)
|
||||
if (res == 0) return
|
||||
throw LocalProfileAssistant.ProfileDiscoveryException(
|
||||
lpaErrorReason = LpacJni.downloadErrCodeToString(-res),
|
||||
httpInterface.lastHttpResponse,
|
||||
httpInterface.lastHttpException,
|
||||
apduInterface.lastApduResponse,
|
||||
apduInterface.lastApduException,
|
||||
)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
|
121
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.c
Normal file
121
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
#include "lpac-notifications.h"
|
||||
#include <euicc/es10a.h>
|
||||
#include <euicc/es10b.h>
|
||||
#include <euicc/es9p.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#define EUICC_CONFIGURED_ADDRESSES_CLASS "net/typeblog/lpac_jni/EuiccConfiguredAddresses"
|
||||
|
||||
jclass euicc_configured_addresses_class;
|
||||
jmethodID euicc_configured_addresses_constructor;
|
||||
|
||||
jmethodID on_state_update;
|
||||
|
||||
#define DISCOVERY_CALLBACK_CLASS "net/typeblog/lpac_jni/ProfileDiscoveryCallback"
|
||||
#define STRING_CLASS "java/lang/String"
|
||||
|
||||
void lpac_discovery_init() {
|
||||
LPAC_JNI_SETUP_ENV;
|
||||
|
||||
jclass download_callback_class = (*env)->FindClass(env, DISCOVERY_CALLBACK_CLASS);
|
||||
on_state_update = (*env)->GetMethodID(env, download_callback_class, "onDiscovered",
|
||||
"([L" STRING_CLASS ";)V");
|
||||
|
||||
euicc_configured_addresses_class = (*env)->FindClass(env, EUICC_CONFIGURED_ADDRESSES_CLASS);
|
||||
euicc_configured_addresses_class = (*env)->NewGlobalRef(env, euicc_configured_addresses_class);
|
||||
euicc_configured_addresses_constructor = (*env)->GetMethodID(
|
||||
env, euicc_configured_addresses_class, "<init>",
|
||||
"(L" STRING_CLASS ";L" STRING_CLASS ";)V");
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_net_typeblog_lpac_1jni_LpacJni_es10aGetEuiccConfiguredAddresses(
|
||||
JNIEnv *env,
|
||||
__attribute__((unused)) jobject thiz,
|
||||
jlong handle
|
||||
) {
|
||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||
struct es10a_euicc_configured_addresses addresses;
|
||||
jobject ret = NULL;
|
||||
if (es10a_get_euicc_configured_addresses(ctx, &addresses) == 0) {
|
||||
jstring default_dp_address = toJString(env, addresses.defaultDpAddress);
|
||||
jstring root_ds_address = toJString(env, addresses.rootDsAddress);
|
||||
ret = (*env)->NewObject(env, euicc_configured_addresses_class,
|
||||
euicc_configured_addresses_constructor,
|
||||
default_dp_address, root_ds_address);
|
||||
}
|
||||
es10a_euicc_configured_addresses_free(&addresses);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_net_typeblog_lpac_1jni_LpacJni_discoveryProfile(
|
||||
JNIEnv *env,
|
||||
__attribute__((unused)) jobject thiz,
|
||||
jlong handle,
|
||||
jstring address,
|
||||
jstring imei,
|
||||
jobject callback
|
||||
) {
|
||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||
|
||||
const char *_address = (*env)->GetStringUTFChars(env, address, NULL);
|
||||
const char *_imei = NULL;
|
||||
|
||||
if (imei != NULL) {
|
||||
_imei = (*env)->GetStringUTFChars(env, address, NULL);
|
||||
}
|
||||
|
||||
ctx->http.server_address = _address;
|
||||
|
||||
char **smdp_list = NULL;
|
||||
jobjectArray addresses = NULL;
|
||||
int ret = -1;
|
||||
|
||||
ret = es10b_get_euicc_challenge_and_info(ctx);
|
||||
syslog(LOG_INFO, "es10b_get_euicc_challenge_and_info %d", ret);
|
||||
if (ret < 0) {
|
||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = es9p_initiate_authentication(ctx);
|
||||
syslog(LOG_INFO, "es9p_initiate_authentication %d", ret);
|
||||
if (ret < 0) {
|
||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = es10b_authenticate_server(ctx, NULL, _imei);
|
||||
syslog(LOG_INFO, "es10b_authenticate_server %d", ret);
|
||||
if (ret < 0) {
|
||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = es11_authenticate_client(ctx, &smdp_list);
|
||||
if (ret < 0) {
|
||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
jsize n = 0;
|
||||
for (n = 0; smdp_list[n] != NULL; n++) continue;
|
||||
|
||||
addresses = (*env)->NewObjectArray(env, n, string_class, NULL);
|
||||
|
||||
for (jsize index = 0; index < n; index++) {
|
||||
jstring element = toJString(env, smdp_list[index]);
|
||||
(*env)->SetObjectArrayElement(env, addresses, index, element);
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(env, callback, on_state_update, addresses);
|
||||
|
||||
out:
|
||||
if (_imei != NULL) (*env)->ReleaseStringUTFChars(env, imei, _imei);
|
||||
(*env)->ReleaseStringUTFChars(env, address, _address);
|
||||
es11_smdp_list_free_all(smdp_list);
|
||||
return ret;
|
||||
}
|
6
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.h
Normal file
6
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <jni.h>
|
||||
#include "lpac-jni.h"
|
||||
|
||||
void lpac_discovery_init();
|
|
@ -8,6 +8,7 @@
|
|||
#include "lpac-jni.h"
|
||||
#include "lpac-download.h"
|
||||
#include "lpac-notifications.h"
|
||||
#include "lpac-discovery.h"
|
||||
#include "interface-wrapper.h"
|
||||
|
||||
JavaVM *jvm = NULL;
|
||||
|
@ -21,6 +22,7 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||
jvm = vm;
|
||||
interface_wrapper_init();
|
||||
lpac_download_init();
|
||||
lpac_discovery_init();
|
||||
|
||||
LPAC_JNI_SETUP_ENV;
|
||||
string_class = (*env)->FindClass(env, "java/lang/String");
|
||||
|
|
Loading…
Add table
Reference in a new issue