diff --git a/app-common/src/main/AndroidManifest.xml b/app-common/src/main/AndroidManifest.xml index a9c61d3..be37bf4 100644 --- a/app-common/src/main/AndroidManifest.xml +++ b/app-common/src/main/AndroidManifest.xml @@ -6,8 +6,7 @@ - + diff --git a/app-common/src/main/res/raw/symantec_gsma_rspv2_root_ci1 b/app-common/src/main/res/raw/symantec_gsma_rspv2_root_ci1 deleted file mode 100644 index d9b7113..0000000 --- a/app-common/src/main/res/raw/symantec_gsma_rspv2_root_ci1 +++ /dev/null @@ -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----- diff --git a/app-common/src/main/res/xml/network_security_config.xml b/app-common/src/main/res/xml/network_security_config.xml deleted file mode 100644 index 2d4e014..0000000 --- a/app-common/src/main/res/xml/network_security_config.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccInfo2.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccInfo2.kt index b7769e7..e69c7ff 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccInfo2.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccInfo2.kt @@ -9,4 +9,6 @@ data class EuiccInfo2( val ppVersion: String, val freeNvram: Int, val freeRam: Int, + val euiccCiPKIdListForSigning: Array, + val euiccCiPKIdListForVerification: Array, ) \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/HttpInterface.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/HttpInterface.kt index f693374..49d6cc0 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/HttpInterface.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/HttpInterface.kt @@ -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): 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) } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/HttpInterfaceImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/HttpInterfaceImpl.kt index d84ae95..bfad50c 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/HttpInterfaceImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/HttpInterfaceImpl.kt @@ -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 + 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) { + val trustManagerFactory = TrustManagerFactory.getInstance("PKIX").apply { + init(keyIdToKeystore(pkids)) + } + trustManagers = trustManagerFactory.trustManagers + } } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 5dabf28..7412f00 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -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 { diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/RootCertificates.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/RootCertificates.kt new file mode 100644 index 0000000..ec094aa --- /dev/null +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/RootCertificates.kt @@ -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): 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: +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() +) \ No newline at end of file diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c index 44f5e93..4c3393a 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c @@ -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, "", "(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, "", "(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); diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h index e0e2109..e60c465 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h @@ -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;