refactor: Trust SM-DP+ TLS certs based on euiccCiPKIdListForVerification
All checks were successful
/ build-debug (push) Successful in 4m39s

Unfortunately, because there is no way to access the certificate itself
from the eUICC, we have to hard-code known & supported certificates
still.

However, this approach makes sure that only those certificates listed by
the eUICC are trusted during their SM-DP+ sessions. Were these added
directly as part of the Android security config, then all certificates
would be blindly trusted for all SM-DP+ sessions (and even normal TLS
connections if the app were to make them).

As a result we can now trust more known certificates, including GSMA
Test CIs. These are hard-coded as a hash map.
This commit is contained in:
Peter Cai 2024-02-21 21:09:20 -05:00
parent 252000660a
commit c033ef5ba9
10 changed files with 219 additions and 30 deletions

View file

@ -6,8 +6,7 @@
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:networkSecurityConfig="@xml/network_security_config">
<application>
<activity
android:name="im.angry.openeuicc.ui.SettingsActivity"
android:label="@string/pref_settings" />

View file

@ -1,15 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICSTCCAe+gAwIBAgIQbmhWeneg7nyF7hg5Y9+qejAKBggqhkjOPQQDAjBEMRgw
FgYDVQQKEw9HU00gQXNzb2NpYXRpb24xKDAmBgNVBAMTH0dTTSBBc3NvY2lhdGlv
biAtIFJTUDIgUm9vdCBDSTEwIBcNMTcwMjIyMDAwMDAwWhgPMjA1MjAyMjEyMzU5
NTlaMEQxGDAWBgNVBAoTD0dTTSBBc3NvY2lhdGlvbjEoMCYGA1UEAxMfR1NNIEFz
c29jaWF0aW9uIC0gUlNQMiBSb290IENJMTBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABJ1qutL0HCMX52GJ6/jeibsAqZfULWj/X10p/Min6seZN+hf5llovbCNuB2n
unLz+O8UD0SUCBUVo8e6n9X1TuajgcAwgb0wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
EwEB/wQFMAMBAf8wEwYDVR0RBAwwCogIKwYBBAGC6WAwFwYDVR0gAQH/BA0wCzAJ
BgdngRIBAgEAME0GA1UdHwRGMEQwQqBAoD6GPGh0dHA6Ly9nc21hLWNybC5zeW1h
dXRoLmNvbS9vZmZsaW5lY2EvZ3NtYS1yc3AyLXJvb3QtY2kxLmNybDAdBgNVHQ4E
FgQUgTcPUSXQsdQI1MOyMubSXnlb6/swCgYIKoZIzj0EAwIDSAAwRQIgIJdYsOMF
WziPK7l8nh5mu0qiRiVf25oa9ullG/OIASwCIQDqCmDrYf+GziHXBOiwJwnBaeBO
aFsiLzIEOaUuZwdNUw==
-----END CERTIFICATE-----

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="@raw/symantec_gsma_rspv2_root_ci1"/>
<certificates src="system"/>
</trust-anchors>
</base-config>
</network-security-config>

View file

@ -9,4 +9,6 @@ data class EuiccInfo2(
val ppVersion: String,
val freeNvram: Int,
val freeRam: Int,
val euiccCiPKIdListForSigning: Array<String>,
val euiccCiPKIdListForVerification: Array<String>,
)

View file

@ -1,5 +1,7 @@
package net.typeblog.lpac_jni
import javax.net.ssl.TrustManager
/*
* Should reflect euicc_http_interface in lpac/euicc/interface.h
*/
@ -25,4 +27,8 @@ interface HttpInterface {
}
fun transmit(url: String, tx: ByteArray, headers: Array<String>): HttpResponse
// The LPA is supposed to pass in a list of pkIds supported by the eUICC.
// HttpInterface is responsible for providing TrustManager implementations that
// validate based on certificates corresponding to these pkIds
fun usePublicKeyIds(pkids: Array<String>)
}

View file

@ -2,14 +2,20 @@ package net.typeblog.lpac_jni.impl
import android.util.Log
import net.typeblog.lpac_jni.HttpInterface
import java.net.HttpURLConnection
import java.net.URL
import java.security.SecureRandom
import javax.net.ssl.HttpsURLConnection
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.TrustManagerFactory
class HttpInterfaceImpl: HttpInterface {
companion object {
private const val TAG = "HttpInterfaceImpl"
}
private lateinit var trustManagers: Array<TrustManager>
override fun transmit(
url: String,
tx: ByteArray,
@ -17,8 +23,17 @@ class HttpInterfaceImpl: HttpInterface {
): HttpInterface.HttpResponse {
Log.d(TAG, "transmit(url = $url)")
val parsedUrl = URL(url)
if (parsedUrl.protocol != "https") {
throw IllegalArgumentException("SM-DP+ servers must use the HTTPS protocol")
}
try {
val conn = URL(url).openConnection() as HttpURLConnection
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, trustManagers, SecureRandom())
val conn = parsedUrl.openConnection() as HttpsURLConnection
conn.sslSocketFactory = sslContext.socketFactory
conn.requestMethod = "POST"
conn.doInput = true
conn.doOutput = true
@ -40,4 +55,11 @@ class HttpInterfaceImpl: HttpInterface {
throw e
}
}
override fun usePublicKeyIds(pkids: Array<String>) {
val trustManagerFactory = TrustManagerFactory.getInstance("PKIX").apply {
init(keyIdToKeystore(pkids))
}
trustManagers = trustManagerFactory.trustManagers
}
}

View file

@ -26,6 +26,9 @@ class LocalProfileAssistantImpl(
if (LpacJni.es10xInit(contextHandle) < 0) {
throw IllegalArgumentException("Failed to initialize LPA")
}
val pkids = euiccInfo2?.euiccCiPKIdListForVerification ?: arrayOf(DEFAULT_PKID_GSMA_RSP2_ROOT_CI1)
httpInterface.usePublicKeyIds(pkids)
}
private fun tryReconnect(timeoutMillis: Long) = runBlocking {

View file

@ -0,0 +1,148 @@
package net.typeblog.lpac_jni.impl
import java.io.ByteArrayInputStream
import java.security.KeyStore
import java.security.cert.CertificateException
import java.security.cert.CertificateFactory
const val DEFAULT_PKID_GSMA_RSP2_ROOT_CI1 = "81370f5125d0b1d408d4c3b232e6d25e795bebfb"
internal fun keyIdToKeystore(keyIds: Array<String>): KeyStore {
val ret = KeyStore.getInstance(KeyStore.getDefaultType())
ret.load(null, null)
keyIds.forEach {
if (it !in KNOWN_CI_CERTS) throw CertificateException("Unknown CI cert ID $it")
ByteArrayInputStream(KNOWN_CI_CERTS[it]!!.toByteArray()).use { stream ->
val cf = CertificateFactory.getInstance("X.509")
ret.setCertificateEntry(it, cf.generateCertificate(stream))
}
}
return ret
}
// ref: <https://euicc-manual.septs.app/docs/pki/ci/>
internal val KNOWN_CI_CERTS = hashMapOf(
// GSM Association - RSP2 Root CI1 (CA: DigiCert)
// Specs: SGP.21 and SGP.22 version 2 and version 3
"81370f5125d0b1d408d4c3b232e6d25e795bebfb" to """
-----BEGIN CERTIFICATE-----
MIICSTCCAe+gAwIBAgIQbmhWeneg7nyF7hg5Y9+qejAKBggqhkjOPQQDAjBEMRgw
FgYDVQQKEw9HU00gQXNzb2NpYXRpb24xKDAmBgNVBAMTH0dTTSBBc3NvY2lhdGlv
biAtIFJTUDIgUm9vdCBDSTEwIBcNMTcwMjIyMDAwMDAwWhgPMjA1MjAyMjEyMzU5
NTlaMEQxGDAWBgNVBAoTD0dTTSBBc3NvY2lhdGlvbjEoMCYGA1UEAxMfR1NNIEFz
c29jaWF0aW9uIC0gUlNQMiBSb290IENJMTBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABJ1qutL0HCMX52GJ6/jeibsAqZfULWj/X10p/Min6seZN+hf5llovbCNuB2n
unLz+O8UD0SUCBUVo8e6n9X1TuajgcAwgb0wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
EwEB/wQFMAMBAf8wEwYDVR0RBAwwCogIKwYBBAGC6WAwFwYDVR0gAQH/BA0wCzAJ
BgdngRIBAgEAME0GA1UdHwRGMEQwQqBAoD6GPGh0dHA6Ly9nc21hLWNybC5zeW1h
dXRoLmNvbS9vZmZsaW5lY2EvZ3NtYS1yc3AyLXJvb3QtY2kxLmNybDAdBgNVHQ4E
FgQUgTcPUSXQsdQI1MOyMubSXnlb6/swCgYIKoZIzj0EAwIDSAAwRQIgIJdYsOMF
WziPK7l8nh5mu0qiRiVf25oa9ullG/OIASwCIQDqCmDrYf+GziHXBOiwJwnBaeBO
aFsiLzIEOaUuZwdNUw==
-----END CERTIFICATE-----
""".trimIndent(),
// OISITE GSMA CI G1 (CA: WISeKey)
// Specs: SGP.21 and SGP.22 version 3
"4c27967ad20c14b391e9601e41e604ad57c0222f" to """
-----BEGIN CERTIFICATE-----
MIIB9zCCAZ2gAwIBAgIUSpBSCCDYPOEG/IFHUCKpZ2pIAQMwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5kYXRpb24xGTAXBgNV
BAMMEE9JU1RFIEdTTUEgQ0kgRzEwIBcNMjQwMTE2MjMxNzM5WhgPMjA1OTAxMDcy
MzE3MzhaMEMxCzAJBgNVBAYTAkNIMRkwFwYDVQQKDBBPSVNURSBGb3VuZGF0aW9u
MRkwFwYDVQQDDBBPSVNURSBHU01BIENJIEcxMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEvZ3s3PFC4NgrCcCMmHJ6DJ66uzAHuLcvjJnOn+TtBNThS7YHLDyHCa2v
7D+zTP+XTtgqgcLoB56Gha9EQQQ4xKNtMGswDwYDVR0TAQH/BAUwAwEB/zAQBgNV
HREECTAHiAVghXQFDjAXBgNVHSABAf8EDTALMAkGB2eBEgECAQAwHQYDVR0OBBYE
FEwnlnrSDBSzkelgHkHmBK1XwCIvMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQD
AgNIADBFAiBVcywTj017jKpAQ+gwy4MqK2hQvzve6lkvQkgSP6ykHwIhAI0KFwCD
jnPbmcJsG41hUrWNlf+IcrMvFuYii0DasBNi
-----END CERTIFICATE-----
""".trimIndent(),
// Symantec RSP Test Root CA (CA: DigiCert)
"665a1433d67c1a2c5db8b52c967f10a057ba5cb2" to """
-----BEGIN CERTIFICATE-----
MIICkDCCAjagAwIBAgIQPfCO5OYL+cdbbx2ETDO7DDAKBggqhkjOPQQDAjBoMR0w
GwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjFHMEUGA1UEAxM+U3ltYW50ZWMg
Q29ycG9yYXRpb24gUlNQIFRlc3QgUm9vdCBDQSAtIEZvciBUZXN0IFB1cnBvc2Vz
IE9ubHkwHhcNMTcwNzExMDAwMDAwWhcNNDkxMjMxMjM1OTU5WjBoMR0wGwYDVQQK
ExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjFHMEUGA1UEAxM+U3ltYW50ZWMgQ29ycG9y
YXRpb24gUlNQIFRlc3QgUm9vdCBDQSAtIEZvciBUZXN0IFB1cnBvc2VzIE9ubHkw
WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQlbEYt9PTmdWcaX5WC68SYTFyZcbBN
vFpJW6bZQpERlMIAuzEpgscbTDccHtNpDqJwMqZXCO7ebCmRLyI6jqe3o4HBMIG+
MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MBcGA1UdIAEB/wQNMAsw
CQYHZ4ESAQIBADBPBgNVHR8ESDBGMESgQqBAhj5odHRwOi8vcGtpLWNybC5zeW1h
dXRoLmNvbS9TeW1hbnRlY1JTUFRlc3RSb290Q0EvTGF0ZXN0Q1JMLmNybDASBgNV
HREECzAJiAcrBgEEAYMJMB0GA1UdDgQWBBRmWhQz1nwaLF24tSyWfxCgV7pcsjAK
BggqhkjOPQQDAgNIADBFAiAQ1quTqcexvDnKvmAkqoQP09QMXAXxlCyma82NtrYq
UQIhAP/W6pRamBGhSliV+EancgbZj+VoOkKdj0o7sP/cKdhZ
-----END CERTIFICATE-----
""".trimIndent(),
// GSMA Test CI
// Specs: SGP.26 v1
"f54172bdf98a95d65cbeb88a38a1c11d800a85c3" to """
-----BEGIN CERTIFICATE-----
MIICVjCCAfugAwIBAgIJALh086v6bETTMAoGCCqGSM49BAMCMEkxFTATBgNVBAMM
DEdTTUEgVGVzdCBDSTERMA8GA1UECwwIVEVTVENFUlQxEDAOBgNVBAoMB1JTUFRF
U1QxCzAJBgNVBAYTAklUMCAXDTE3MDIwMTE1Mzk0MloYDzIwNTIwMjAxMTUzOTQy
WjBJMRUwEwYDVQQDDAxHU01BIFRlc3QgQ0kxETAPBgNVBAsMCFRFU1RDRVJUMRAw
DgYDVQQKDAdSU1BURVNUMQswCQYDVQQGEwJJVDBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABJQGV6Zz3CiPidUuqKR3BJknkfnDSwA25jPi0MupRU1l2zLrF5gXmdLy
Q4juK5XBCUVGyXkBzq66llCRmi4g0imjgckwgcYwHQYDVR0OBBYEFPVBcr35ipXW
XL64ijihwR2ACoXDMA8GA1UdEwEB/wQFMAMBAf8wFwYDVR0gAQH/BA0wCzAJBgdn
gRIBAgEAMA4GA1UdDwEB/wQEAwIBBjAOBgNVHREEBzAFiAOINwEwWwYDVR0fBFQw
UjAnoCWgI4YhaHR0cDovL2NpLnRlc3QuZ3NtYS5jb20vQ1JMLUEuY3JsMCegJaAj
hiFodHRwOi8vY2kudGVzdC5nc21hLmNvbS9DUkwtQi5jcmwwCgYIKoZIzj0EAwID
SQAwRgIhAJHyUclxU7nPhTeadItXKkloUkVWxH8z62l7VZEswPLSAiEA3OSec/NJ
7NBZEO+d9raahnq/OJ3Ia4QRtN/hlpFQ9fk=
-----END CERTIFICATE-----
""".trimIndent(),
"c0bc70ba36929d43b467ff57570530e57ab8fcd8" to """
-----BEGIN CERTIFICATE-----
MIICVTCCAfygAwIBAgIJALh086v6bETTMAoGCCqGSM49BAMCMEkxFTATBgNVBAMM
DEdTTUEgVGVzdCBDSTERMA8GA1UECwwIVEVTVENFUlQxEDAOBgNVBAoMB1JTUFRF
U1QxCzAJBgNVBAYTAklUMCAXDTE3MDQxOTEwMzQzOFoYDzIwNTIwNDE4MTAzNDM4
WjBJMRUwEwYDVQQDDAxHU01BIFRlc3QgQ0kxETAPBgNVBAsMCFRFU1RDRVJUMRAw
DgYDVQQKDAdSU1BURVNUMQswCQYDVQQGEwJJVDBaMBQGByqGSM49AgEGCSskAwMC
CAEBBwNCAAQnh7TVbtgkqea+BOGIf2uYuv64x2P1KDf3ARPpNk7dvhObwMfefhaP
HlzQwYU0/FBk5k9obcUzJ8p/Hc6oWimUo4HJMIHGMB0GA1UdDgQWBBTAvHC6NpKd
Q7Rn/1dXBTDlerj82DAPBgNVHRMBAf8EBTADAQH/MBcGA1UdIAEB/wQNMAswCQYH
Z4ESAQIBADAOBgNVHQ8BAf8EBAMCAQYwDgYDVR0RBAcwBYgDiDcBMFsGA1UdHwRU
MFIwJ6AloCOGIWh0dHA6Ly9jaS50ZXN0LmdzbWEuY29tL0NSTC1BLmNybDAnoCWg
I4YhaHR0cDovL2NpLnRlc3QuZ3NtYS5jb20vQ1JMLUIuY3JsMAoGCCqGSM49BAMC
A0cAMEQCIAbGw59auXFdcsVl3PX/O/7z+3DvCuM6BzZmkTWG0O+SAiAWskTrRp8q
L1hrwcMgtLZDG4902UH38YMrQyVSsWHfog==
-----END CERTIFICATE-----
""".trimIndent(),
// Test CI
// Specs: SGP.26 v3
"34eecf13156518d48d30bdf06853404d115f955d" to """
-----BEGIN CERTIFICATE-----
MIIB4zCCAYqgAwIBAgIBADAKBggqhkjOPQQDAjBEMRAwDgYDVQQDDAdUZXN0IENJ
MREwDwYDVQQLDAhURVNUQ0VSVDEQMA4GA1UECgwHUlNQVEVTVDELMAkGA1UEBhMC
SVQwIBcNMjMwNTMxMTI1MDI4WhgPMjA1ODA1MzAxMjUwMjhaMEQxEDAOBgNVBAMM
B1Rlc3QgQ0kxETAPBgNVBAsMCFRFU1RDRVJUMRAwDgYDVQQKDAdSU1BURVNUMQsw
CQYDVQQGEwJJVDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLlQW4kHaMJSrAK4
nVKjGIgKWYxick+Y1x0MKO/Bsb3+KxMdnAObkPZjLosKlKCnH2bHUHhqRyDDSc2Y
9+wB6A6jazBpMB0GA1UdDgQWBBQ07s8TFWUY1I0wvfBoU0BNEV+VXTAOBgNVHQ8B
Af8EBAMCAQYwFwYDVR0gAQH/BA0wCzAJBgdngRIBAgEAMA8GA1UdEwEB/wQFMAMB
Af8wDgYDVR0RBAcwBYgDiDcBMAoGCCqGSM49BAMCA0cAMEQCIEuYVB+bwdn5Z6sL
eKFS07FnvHY03QqDm8XYxdjDAxZuAiBneNr+fBYeqDulQWfrGXFLDTbsFBENNdDj
jvcHgHpATQ==
-----END CERTIFICATE-----
""".trimIndent(),
"2209f61cd9ec5c9c854e787341ff83ecf9776a5b" to """
-----BEGIN CERTIFICATE-----
MIIB5DCCAYugAwIBAgIBADAKBggqhkjOPQQDAjBEMRAwDgYDVQQDDAdUZXN0IENJ
MREwDwYDVQQLDAhURVNUQ0VSVDEQMA4GA1UECgwHUlNQVEVTVDELMAkGA1UEBhMC
SVQwIBcNMjMwNjAyMTMwNTQzWhgPMjA1ODA2MDExMzA1NDNaMEQxEDAOBgNVBAMM
B1Rlc3QgQ0kxETAPBgNVBAsMCFRFU1RDRVJUMRAwDgYDVQQKDAdSU1BURVNUMQsw
CQYDVQQGEwJJVDBaMBQGByqGSM49AgEGCSskAwMCCAEBBwNCAASF7cCXanl/xSJe
PwIeEUeZk4zPPM3iE16JbpOWPqPXaJwGmMKvHwQlRxiLtPWrRBalgkzrr4RgYIqD
aTcnvxoFo2swaTAdBgNVHQ4EFgQUIgn2HNnsXJyFTnhzQf+D7Pl3alswDgYDVR0P
AQH/BAQDAgEGMBcGA1UdIAEB/wQNMAswCQYHZ4ESAQIBADAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdEQQHMAWIA4g3ATAKBggqhkjOPQQDAgNHADBEAiBLLHbhrIvy1Cue
7lDUlQZY2EOK7/I/o2CQO0pj76OqzQIgTQ+kE02RPbMuflDbXKRuVDKFvfZ/vHEW
QKvBPWehIXI=
-----END CERTIFICATE-----
""".trimIndent()
)

View file

@ -53,7 +53,7 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
euicc_info2_class = (*env)->FindClass(env, "net/typeblog/lpac_jni/EuiccInfo2");
euicc_info2_class = (*env)->NewGlobalRef(env, euicc_info2_class);
euicc_info2_constructor = (*env)->GetMethodID(env, euicc_info2_class, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)V");
euicc_info2_constructor = (*env)->GetMethodID(env, euicc_info2_class, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II[Ljava/lang/String;[Ljava/lang/String;)V");
const char _unused[1];
empty_string = (*env)->NewString(env, _unused, 0);
@ -262,12 +262,16 @@ JNIEXPORT jobject JNICALL
Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(JNIEnv *env, jobject thiz, jlong handle) {
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
struct es10cex_euiccinfo2 * info;
jobjectArray euiccCiPKIdListForVerification = NULL;
jobjectArray euiccCiPKIdListForSigning = NULL;
jstring sas_accreditation_number = NULL;
jstring global_platform_version = NULL;
jstring euicc_firmware_version = NULL;
jstring profile_version = NULL;
jstring pp_version = NULL;
jobject ret = NULL;
char **curr = NULL;
int count = 0;
if (es10cex_get_euiccinfo2(ctx, &info) < 0)
goto out;
@ -278,12 +282,26 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(JNIEnv *env, jobject th
sas_accreditation_number = toJString(env, info->sasAcreditationNumber);
pp_version = toJString(env, info->ppVersion);
count = LPAC_JNI_NULL_TERM_LIST_COUNT(info->euiccCiPKIdListForSigning, curr);
euiccCiPKIdListForSigning = (*env)->NewObjectArray(env, count, string_class, NULL);
LPAC_JNI_NULL_TERM_LIST_FOREACH(info->euiccCiPKIdListForSigning, curr, {
(*env)->SetObjectArrayElement(env, euiccCiPKIdListForSigning, i, toJString(env, *curr));
});
count = LPAC_JNI_NULL_TERM_LIST_COUNT(info->euiccCiPKIdListForVerification, curr);
euiccCiPKIdListForVerification = (*env)->NewObjectArray(env, count, string_class, NULL);
LPAC_JNI_NULL_TERM_LIST_FOREACH(info->euiccCiPKIdListForVerification, curr, {
(*env)->SetObjectArrayElement(env, euiccCiPKIdListForVerification, i, toJString(env, *curr));
});
ret = (*env)->NewObject(env, euicc_info2_class, euicc_info2_constructor,
profile_version, euicc_firmware_version,
global_platform_version,
sas_accreditation_number, pp_version,
info->extCardResource.freeNonVolatileMemory,
info->extCardResource.freeVolatileMemory);
info->extCardResource.freeVolatileMemory,
euiccCiPKIdListForSigning,
euiccCiPKIdListForVerification);
out:
(*env)->DeleteLocalRef(env, profile_version);

View file

@ -28,6 +28,21 @@ struct lpac_jni_ctx {
#define LPAC_JNI_LINKED_LIST_COUNT(list, curr) \
(__LPAC_JNI_LINKED_LIST_FOREACH(list, curr, {}, i))
#define __LPAC_JNI_NULL_TERM_LIST_FOREACH(list, curr, body, after) { \
int i = 0; \
curr = list; \
while (*curr != NULL) { \
body; \
curr++; \
i++; \
}; \
after; \
}
#define LPAC_JNI_NULL_TERM_LIST_FOREACH(list, curr, body) \
__LPAC_JNI_NULL_TERM_LIST_FOREACH(list, curr, body, {})
#define LPAC_JNI_NULL_TERM_LIST_COUNT(list, curr) \
(__LPAC_JNI_NULL_TERM_LIST_FOREACH(list, curr, {}, i))
extern JavaVM *jvm;
extern jclass string_class;