OpenEUICC doesn't seem to work with unknown CERT.CI.ECDSA on the eUICC for TLS cert verification #11

Open
opened 2024-02-16 20:24:30 +01:00 by laf0rge · 18 comments

I'm currently trying to install eSIM profiles using

I would have expected this to work, just like it works with the same eUICC and SM-DP+ using lpac on the command line and the eUICC in a PC/SC reader.

Looking at the android logs, it appears that the error is a TLS verification problem when connecting to the SM-DP+.

Sadly, even though the CERT.CI.ECDSA is stored on the eUICC, there is no way for an LPA to read it out from the eUICC. The eUICC only reveals the CERT.EUM.ECDSA and the CERT.EUICC.ECDSA.

So the best a LPA can do, from my point of view, is to

  • obtain the list of SubjectKeyIdentifier supported by the eUICC (part of GetEuiccInfo1/2)
  • establish a TLS connection to the SM-DP+
  • the SM-DP+ will provide its CERT.DP.TLS, which contains the X509v3 Authority Key Identifier
  • the LPA can then verify if there is a match between the AuthorityKeyIdentifier of the SM-DP+ and the list provided by the eUICC
  • the SM-DP+ should also include the CERT.CI.ECDSA (root CA Cert) during the TLS handshake
  • the LPA can then verify that the CERT.DP.TLS was really signed by the CERT.CI.ECDSA

In my opinion, this is the only way how any eUICC using any certificates (SGP.26, GSMA production or any other private / alternate root of trust) will work out of the box. It is not possible for a LPA to know of all the different root certificates out there, today and in the future. So including a list of certificates in the LPA is not possible.

Note: I haven't yet looked at the source code of OpenEUICC, the above is just based on observations of the alpha2 + alpha3 versions and looking at logs.

I'm currently trying to install eSIM profiles using * sysmoEUICC-C2T with SGP.26 derived certificates * SGP.26 certificates from smdpp.test.rsp.sysmocom.de (see https://test.rsp.sysmocom.de/) I would have expected this to work, just like it works with the same eUICC and SM-DP+ using lpac on the command line and the eUICC in a PC/SC reader. Looking at the android logs, it appears that the error is a TLS verification problem when connecting to the SM-DP+. Sadly, even though the CERT.CI.ECDSA is stored on the eUICC, there is no way for an LPA to read it out from the eUICC. The eUICC only reveals the CERT.EUM.ECDSA and the CERT.EUICC.ECDSA. So the best a LPA can do, from my point of view, is to * obtain the list of SubjectKeyIdentifier supported by the eUICC (part of GetEuiccInfo1/2) * establish a TLS connection to the SM-DP+ * the SM-DP+ will provide its CERT.DP.TLS, which contains the X509v3 Authority Key Identifier * the LPA can then verify if there is a match between the AuthorityKeyIdentifier of the SM-DP+ and the list provided by the eUICC * the SM-DP+ should also include the CERT.CI.ECDSA (root CA Cert) during the TLS handshake * the LPA can then verify that the CERT.DP.TLS was really signed by the CERT.CI.ECDSA In my opinion, this is the only way how any eUICC using any certificates (SGP.26, GSMA production or any other private / alternate root of trust) will work out of the box. It is not possible for a LPA to know of all the different root certificates out there, today and in the future. So including a list of certificates in the LPA is not possible. Note: I haven't yet looked at the source code of OpenEUICC, the above is just based on observations of the alpha2 + alpha3 versions and looking at logs.
Author

Ok, a quick look at the source code reveals:

  • OpenEUICC includes exactly only one root certificate, see app-common/src/main/res/raw/symantec_gsma_rspv2_root_ci1 and app-common/src/main/res/xml/network_security_config.xml referencing it.

So it will not care at all about the SubjectKeyIdentifier reported as supported by the eUICC, but simply ignore that and only accept production GSMA v2 certificates.

Ok, a quick look at the source code reveals: * OpenEUICC includes exactly only one root certificate, see `app-common/src/main/res/raw/symantec_gsma_rspv2_root_ci1` and `app-common/src/main/res/xml/network_security_config.xml` referencing it. So it will not care at all about the SubjectKeyIdentifier reported as supported by the eUICC, but simply ignore that and only accept production GSMA v2 certificates.
Author

Looking a bit at Android and Java APIs for this, I think the course of action would be to implement a custom X509TrustManager whose checkServerTrusted method would get all the certificates provided by the server (SM-DP+ here).

See for example https://stackoverflow.com/questions/72234590/android-how-do-i-programmatically-download-an-ssl-certificate-from-a-provided-h

Once the certificate chain has been downloaded from the server this way, OpenEUICC can check

  • verify that both CERT.DP.TLS and CERT.CI.ECDSA are included
  • verify that the CERT.DP.TLS was really signed by the CERT.CI.ECDSA
  • verify that the CERT.DP.TLS AuthorityKeyIdentiifer matches any of the SubjectKeyIdentifier reported in eUICCInfo1/2
Looking a bit at Android and Java APIs for this, I think the course of action would be to implement a custom `X509TrustManager` whose `checkServerTrusted` method would get all the certificates provided by the server (SM-DP+ here). See for example https://stackoverflow.com/questions/72234590/android-how-do-i-programmatically-download-an-ssl-certificate-from-a-provided-h Once the certificate chain has been downloaded from the server this way, OpenEUICC can check * verify that both CERT.DP.TLS and CERT.CI.ECDSA are included * verify that the CERT.DP.TLS was really signed by the CERT.CI.ECDSA * verify that the CERT.DP.TLS AuthorityKeyIdentiifer matches any of the SubjectKeyIdentifier reported in eUICCInfo1/2
Author

by the way: In case you're interested: I can send you free samples of such an eUICC with SGP.26 test certificates. Or I can even create completely custom/private CI and then personalize eUICCs within such a private CI.

by the way: In case you're interested: I can send you free samples of such an eUICC with SGP.26 test certificates. Or I can even create completely custom/private CI and then personalize eUICCs within such a private CI.
Owner

An interim solution that can be implemented a bit faster would be an option that allows the user to supply a custom CI public key, or an option to disable the check on the TLS side altogether.

An interim solution that can be implemented a bit faster would be an option that allows the user to supply a custom CI public key, or an option to disable the check on the TLS side altogether.
Owner

But I agree checking with GetEuiccInfo1/2 would be the best course of action to support non production CIs

But I agree checking with GetEuiccInfo1/2 would be the best course of action to support non production CIs
Owner

It looks like many production SM-DP+ servers do not actually send the full certificate chain, and therefore we cannot verify CERT.DP.TLS against CERT.CI.ECDSA without hard-coding the CI cert. The LPA will need to have a mapping from AuthorityKeyIdentifier to the actual cert in order to perform the verification, which defeats the purpose.

It looks like many production SM-DP+ servers do not actually send the full certificate chain, and therefore we cannot verify CERT.DP.TLS against CERT.CI.ECDSA without hard-coding the CI cert. The LPA will need to have a mapping from AuthorityKeyIdentifier to the actual cert in order to perform the verification, which defeats the purpose.
Owner

I now wonder if it is even necessary for the LPA to verify the TLS cert at all, given that the eUICC is not supposed to accept arbitrary BPP anyway.

I now wonder if it is even necessary for the LPA to verify the TLS cert at all, given that the eUICC is not supposed to accept arbitrary BPP anyway.
Author

An interim solution that can be implemented a bit faster would be an option that allows the user to supply a custom CI public key, or an option to disable the check on the TLS side altogether.

That would work, yes. It's not very elegant, but I understand the advantage of a simple solution.

> An interim solution that can be implemented a bit faster would be an option that allows the user to supply a custom CI public key, or an option to disable the check on the TLS side altogether. That would work, yes. It's not very elegant, but I understand the advantage of a simple solution.
Author

It looks like many production SM-DP+ servers do not actually send the full certificate chain, and therefore we cannot verify CERT.DP.TLS against CERT.CI.ECDSA without hard-coding the CI cert. The LPA will need to have a mapping from AuthorityKeyIdentifier to the actual cert in order to perform the verification, which defeats the purpose.

That's sad. However, I still think it would be good to support a SM-DP+ that includes the CERT.CI.ECDSA, as it is a way how somebody can set up SM-DP+ that would "automagically" work.

I think the root cause here is actually that the SGP.22 specifications do not have a way how the eUICC would provide the CERT.CI.ECDSA to the LPA. The eUICC has to contain that certificate - but yet at the same time there is no way to extract it. In my opinion it is a specification oversight. I will report this to the GSMA. IT wouldn't change much as even if they added such a mechanism, it would take many yars to propagate into practical deployments.

So in the end, EasyEUICC could have a combination of

  • its own certificate store with GSMA root certificate (for v2 and v3?) pre-installed
  • ability for users to add their own additional root certificates
  • auto-discovery mechanism as I described. will only work with SM-DP+ that include the root cert
> It looks like many production SM-DP+ servers do not actually send the full certificate chain, and therefore we cannot verify CERT.DP.TLS against CERT.CI.ECDSA without hard-coding the CI cert. The LPA will need to have a mapping from AuthorityKeyIdentifier to the actual cert in order to perform the verification, which defeats the purpose. That's sad. However, I still think it would be good to support a SM-DP+ that includes the CERT.CI.ECDSA, as it is a way how somebody can set up SM-DP+ that would "automagically" work. I think the root cause here is actually that the SGP.22 specifications do not have a way how the eUICC would provide the CERT.CI.ECDSA to the LPA. The eUICC has to contain that certificate - but yet at the same time there is no way to extract it. In my opinion it is a specification oversight. I will report this to the GSMA. IT wouldn't change much as even if they added such a mechanism, it would take many yars to propagate into practical deployments. So in the end, EasyEUICC could have a combination of * its own certificate store with GSMA root certificate (for v2 and v3?) pre-installed * ability for users to add their own additional root certificates * auto-discovery mechanism as I described. will only work with SM-DP+ that include the root cert
Author

I now wonder if it is even necessary for the LPA to verify the TLS cert at all, given that the eUICC is not supposed to accept arbitrary BPP anyway.

I think it's mostly about privacy / information leakage. If you do not verify the TLS certificate, you are opening up vulnerabilities where an attacker performs an impersonation of the SM-DP+ hostname or IP address and then learns the EID and other details about the users phone - basically everything contained in the initialAuthRequest.

Also, you are opening the attack surface of the LPA (ES9+) and eUICC (ES8+) to any random attacker out there. So any implementation flaws discovered can suddenly be accessed by virtually any attacker - while at the moment such flaws in LPA/eUICC are only accessible to operators of SM-DP+.

I'd strongly recommend against disabling certificate verification for the above reasons.

> I now wonder if it is even necessary for the LPA to verify the TLS cert at all, given that the eUICC is not supposed to accept arbitrary BPP anyway. I think it's mostly about privacy / information leakage. If you do not verify the TLS certificate, you are opening up vulnerabilities where an attacker performs an impersonation of the SM-DP+ hostname or IP address and then learns the EID and other details about the users phone - basically everything contained in the initialAuthRequest. Also, you are opening the attack surface of the LPA (ES9+) and eUICC (ES8+) to any random attacker out there. So any implementation flaws discovered can suddenly be accessed by virtually any attacker - while at the moment such flaws in LPA/eUICC are only accessible to operators of SM-DP+. I'd strongly recommend against disabling certificate verification for the above reasons.
Owner

Even without considering support for test CIs, I think implementing the certificate check as part of the initial handshake is also advantageous over just installing the cert and trusting it across the board in the app, since really these CI certs should only be trusted during SM-DP+ sessions.

I think we can have a default mapping from AuthorityKeyIdentifiers to known CI certs, and for everything outside of those we assume the SM-DP+ should be sending the full chain (and we can verify AKIs against the public keys if I am not mistaken).

My last concern about this approach is that Java does not seem to include a default implementation of ASN.1 parsers (or at least not one I can use to parse AuthorityKeyIdentifiers), so I either have to include Bounty Castle (which I don't want to and in fact just got rid of a few months ago), or I have to implement one just enough to parse these ASN.1 sequences myself.

Even without considering support for test CIs, I think implementing the certificate check as part of the initial handshake is also advantageous over just installing the cert and trusting it across the board in the app, since really these CI certs should only be trusted during SM-DP+ sessions. I think we can have a default mapping from AuthorityKeyIdentifiers to known CI certs, and for everything outside of those we assume the SM-DP+ should be sending the full chain (and we can verify AKIs against the public keys if I am not mistaken). My last concern about this approach is that Java does not seem to include a default implementation of ASN.1 parsers (or at least not one I can use to parse AuthorityKeyIdentifiers), so I either have to include Bounty Castle (which I don't want to and in fact just got rid of a few months ago), or I have to implement one just enough to parse these ASN.1 sequences myself.
Owner

Although I guess I could also piggyback on lpac's derutil.c here from JNI.

Although I guess I could also piggyback on lpac's `derutil.c` here from JNI.
Owner

auto-discovery mechanism as I described. will only work with SM-DP+ that include the root cert

Also note that the Subject Key Identifier of the CI cert can be an arbitrary string dictated by the creator of the cert. Unless SGP standards mandated a way to derive the SKI, there is no way for us to be sure that the CI cert is genuine.

> auto-discovery mechanism as I described. will only work with SM-DP+ that include the root cert Also note that the Subject Key Identifier of the CI cert can be an arbitrary string dictated by the creator of the cert. Unless SGP standards mandated a way to derive the SKI, there is no way for us to be sure that the CI cert is genuine.
Owner

Ok, this has now been implemented but with the caveat that we still have to hard-code a mapping between known PKIDs and their public certificates. However, compared to just adding the certificates to Android's security config, this has the benefit of only trusting those PKIDs listed by the eUICC, instead of blindly trusting all known CIs for every eUICC. This means we can now safely add any known certificates to the hard-coded hashmap, including test CIs or even China CIs.

I have added a list of known CIs based on Sept's manual at https://euicc-manual.septs.app/docs/pki/ci/. You can find a debug build from the Actions tab.

Ok, this has now been implemented but with the caveat that we still have to hard-code a mapping between known PKIDs and their public certificates. However, compared to just adding the certificates to Android's security config, this has the benefit of only trusting those PKIDs listed by the eUICC, instead of blindly trusting all known CIs for every eUICC. This means we can now safely add **any** known certificates to the hard-coded hashmap, including test CIs or even China CIs. I have added a list of known CIs based on Sept's manual at https://euicc-manual.septs.app/docs/pki/ci/. You can find a debug build from the Actions tab.
Author

First of all: Thanks a lot for your effort!

I didn't have a chance to test it until today. However, it doesn't appear to be working, sorry.

I configured smdpp.test.rsp.sysmocom.de to provide both the SM-DP+ certificate and the GSMA test root cert. There are no intermediate certs. I can verify this using openssl s_client -showcerts smdpp.test.rsp.sysmocom.de:443 and I can see that both certificates (CA root + SM-DP+) are contained.

However, when using the EasyEUICC beta1 apk file on a UE, it still fails with the following log:

03-10 17:27:41.802 15985 31402 D HttpInterfaceImpl: transmit(url = https://smdpp.test.rsp.sysmocom.de/gsma/rsp2/es9plus/initiateAuthentication)
03-10 17:27:41.808 15985 31402 I System.out: (HTTPLog)-Static: isSBSettingEnabled false
03-10 17:27:41.808 15985 31402 I System.out: (HTTPLog)-Static: isSBSettingEnabled false
03-10 17:27:41.964 15985 31402 E CONSCRYPT: ------------------Untrusted chain: ----------------------
03-10 17:27:41.964 15985 31402 E CONSCRYPT: == Chain0 == 
03-10 17:27:41.964 15985 31402 E CONSCRYPT:  Version:   3
03-10 17:27:41.964 15985 31402 E CONSCRYPT:  AuthorityKeyIdentifier:   41830168014f54172bdf98a95d65cbeb88a38a1c11d800a85c3
03-10 17:27:41.964 15985 31402 E CONSCRYPT:  SubjectKeyIdentifier:   41604147514dd865c38ca68a235c68e66a975086dc0d8be
03-10 17:27:41.964 15985 31402 E CONSCRYPT:  Serial Number:   17
03-10 17:27:41.969 15985 31402 E CONSCRYPT:  SubjectDN:   CN=smdpp.test.rsp.sysmocom.de, O=sysmocom
03-10 17:27:41.970 15985 31402 E CONSCRYPT:  IssuerDN:   C=IT, O=RSPTEST, OU=TESTCERT, CN=Test CI
03-10 17:27:41.971 15985 31402 E CONSCRYPT:  Get not before:   Thu Jan 25 21:07:13 GMT+01:00 2024
03-10 17:27:41.971 15985 31402 E CONSCRYPT:  Get not after:   Wed Feb 26 21:07:13 GMT+01:00 2025
03-10 17:27:41.972 15985 31402 E CONSCRYPT:  Sig ALG name:   SHA256withECDSA
03-10 17:27:41.972 15985 31402 E CONSCRYPT:  Signature:   3045022100af8e941c969949124f5456da060993f4873b51ed70452a4078da2b2de8e817dc02205035137e74c5f33af8f3daee42770a8ca9bdea40961205f24eba4d9fed9a3846
03-10 17:27:41.976 15985 31402 E CONSCRYPT:  Public key:
03-10 17:27:41.976 15985 31402 E CONSCRYPT:  
03-10 17:27:41.976 15985 31402 E CONSCRYPT:  30 59 30 13 06 07 2a 86 48 ce 3d 02 01 06 08 2a 86 48 ce 3d
03-10 17:27:41.976 15985 31402 E CONSCRYPT:  03 01 07 03 42 00 04 c0 1e ac ee aa 6f 7c 0c d7 40 d0 6b b3
03-10 17:27:41.976 15985 31402 E CONSCRYPT:  a6 ce 65 4c e2 40 65 c4 34 1c c3 d6 11 48 0c 59 f3 23 54 92
03-10 17:27:41.976 15985 31402 E CONSCRYPT:  c9 80 44 7a 48 ca 73 d1 e7 18 10 e1 90 b5 49 ab a2 df ab b2
03-10 17:27:41.976 15985 31402 E CONSCRYPT:  b4 25 91 42 0d 7b 7f 5a 73 cd 59
03-10 17:27:41.976 15985 31402 E CONSCRYPT: == Chain1 == 
03-10 17:27:41.976 15985 31402 E CONSCRYPT:  Version:   3
03-10 17:27:41.977 15985 31402 E CONSCRYPT:  SubjectKeyIdentifier:   4160414f54172bdf98a95d65cbeb88a38a1c11d800a85c3
03-10 17:27:41.977 15985 31402 E CONSCRYPT:  Serial Number:   b874f3abfa6c44d3
03-10 17:27:41.977 15985 31402 E CONSCRYPT:  SubjectDN:   C=IT, O=RSPTEST, OU=TESTCERT, CN=Test CI
03-10 17:27:41.978 15985 31402 E CONSCRYPT:  IssuerDN:   C=IT, O=RSPTEST, OU=TESTCERT, CN=Test CI
03-10 17:27:41.978 15985 31402 E CONSCRYPT:  Get not before:   Wed Apr 01 10:27:51 GMT+02:00 2020
03-10 17:27:41.978 15985 31402 E CONSCRYPT:  Get not after:   Thu Apr 01 09:27:51 GMT+01:00 2055
03-10 17:27:41.978 15985 31402 E CONSCRYPT:  Sig ALG name:   SHA256withECDSA
03-10 17:27:41.978 15985 31402 E CONSCRYPT:  Signature:   3044022052756aafc2020a6cecbf2e5f3c20892510ff29751d298bd3b015d9605a4fe67d022057982836e4d205ddd2e6c3c1b455937f6b6e493b602fd1b66c357489a935f76b
03-10 17:27:41.982 15985 31402 E CONSCRYPT:  Public key:
03-10 17:27:41.982 15985 31402 E CONSCRYPT:  
03-10 17:27:41.982 15985 31402 E CONSCRYPT:  30 59 30 13 06 07 2a 86 48 ce 3d 02 01 06 08 2a 86 48 ce 3d
03-10 17:27:41.982 15985 31402 E CONSCRYPT:  03 01 07 03 42 00 04 94 06 57 a6 73 dc 28 8f 89 d5 2e a8 a4
03-10 17:27:41.982 15985 31402 E CONSCRYPT:  77 04 99 27 91 f9 c3 4b 00 36 e6 33 e2 d0 cb a9 45 4d 65 db
03-10 17:27:41.982 15985 31402 E CONSCRYPT:  32 eb 17 98 17 99 d2 f2 43 88 ee 2b 95 c1 09 45 46 c9 79 01
03-10 17:27:41.982 15985 31402 E CONSCRYPT:  ce ae ba 96 50 91 9a 2e 20 d2 29
03-10 17:27:41.995 15985 31402 W System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
03-10 17:27:41.996 15985 31402 W System.err:    at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:239)
03-10 17:27:41.996 15985 31402 W System.err:    at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:1471)
03-10 17:27:41.996 15985 31402 W System.err:    at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:1415)
03-10 17:27:41.996 15985 31402 W System.err:    at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:1359)
03-10 17:27:41.996 15985 31402 W System.err:    at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:221)
03-10 17:27:41.996 15985 31402 W System.err:    at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:144)
03-10 17:27:41.996 15985 31402 W System.err:    at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:106)
03-10 17:27:41.996 15985 31402 W System.err:    at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:400)
03-10 17:27:41.997 15985 31402 W System.err:    at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:333)
03-10 17:27:41.997 15985 31402 W System.err:    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:483)
03-10 17:27:41.997 15985 31402 W System.err:    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:135)
03-10 17:27:41.997 15985 31402 W System.err:    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:266)
03-10 17:27:41.997 15985 31402 W System.err:    at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:219)
03-10 17:27:41.997 15985 31402 W System.err:    at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:30)
03-10 17:27:41.997 15985 31402 W System.err:    at net.typeblog.lpac_jni.impl.HttpInterfaceImpl.transmit(HttpInterfaceImpl.kt:46)
03-10 17:27:41.997 15985 31402 W System.err:    at net.typeblog.lpac_jni.LpacJni.downloadProfile(Native Method)
03-10 17:27:41.997 15985 31402 W System.err:    at net.typeblog.lpac_jni.impl.LocalProfileAssistantImpl.downloadProfile(LocalProfileAssistantImpl.kt:121)
03-10 17:27:41.997 15985 31402 W System.err:    at im.angry.openeuicc.ui.ProfileDownloadFragment$doDownloadProfile$2.invokeSuspend(ProfileDownloadFragment.kt:193)
03-10 17:27:41.997 15985 31402 W System.err:    at im.angry.openeuicc.ui.ProfileDownloadFragment$doDownloadProfile$2.invoke(Unknown Source:8)
03-10 17:27:41.997 15985 31402 W System.err:    at im.angry.openeuicc.ui.ProfileDownloadFragment$doDownloadProfile$2.invoke(Unknown Source:4)
03-10 17:27:41.997 15985 31402 W System.err:    at net.typeblog.lpac_jni.LocalProfileAssistant$beginOperation$2.invokeSuspend(LocalProfileAssistant.kt:48)
03-10 17:27:41.997 15985 31402 W System.err:    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
03-10 17:27:41.997 15985 31402 W System.err:    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
03-10 17:27:41.997 15985 31402 W System.err:    at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
03-10 17:27:41.997 15985 31402 W System.err:    at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
03-10 17:27:41.997 15985 31402 W System.err:    at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
03-10 17:27:41.997 15985 31402 W System.err:    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
03-10 17:27:41.997 15985 31402 W System.err:    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
03-10 17:27:41.997 15985 31402 W System.err:    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

I somehow have the feeling it is a matter of certificate ordering? However, I cannot change the order of certificates in nginx, as the first certificate in file must match the private key; so any intermediate or root CA certificates will always follow after the server cert.

First of all: Thanks a lot for your effort! I didn't have a chance to test it until today. However, it doesn't appear to be working, sorry. I configured smdpp.test.rsp.sysmocom.de to provide both the SM-DP+ certificate and the GSMA test root cert. There are no intermediate certs. I can verify this using `openssl s_client -showcerts smdpp.test.rsp.sysmocom.de:443` and I can see that both certificates (CA root + SM-DP+) are contained. However, when using the EasyEUICC beta1 apk file on a UE, it still fails with the following log: ``` 03-10 17:27:41.802 15985 31402 D HttpInterfaceImpl: transmit(url = https://smdpp.test.rsp.sysmocom.de/gsma/rsp2/es9plus/initiateAuthentication) 03-10 17:27:41.808 15985 31402 I System.out: (HTTPLog)-Static: isSBSettingEnabled false 03-10 17:27:41.808 15985 31402 I System.out: (HTTPLog)-Static: isSBSettingEnabled false 03-10 17:27:41.964 15985 31402 E CONSCRYPT: ------------------Untrusted chain: ---------------------- 03-10 17:27:41.964 15985 31402 E CONSCRYPT: == Chain0 == 03-10 17:27:41.964 15985 31402 E CONSCRYPT: Version: 3 03-10 17:27:41.964 15985 31402 E CONSCRYPT: AuthorityKeyIdentifier: 41830168014f54172bdf98a95d65cbeb88a38a1c11d800a85c3 03-10 17:27:41.964 15985 31402 E CONSCRYPT: SubjectKeyIdentifier: 41604147514dd865c38ca68a235c68e66a975086dc0d8be 03-10 17:27:41.964 15985 31402 E CONSCRYPT: Serial Number: 17 03-10 17:27:41.969 15985 31402 E CONSCRYPT: SubjectDN: CN=smdpp.test.rsp.sysmocom.de, O=sysmocom 03-10 17:27:41.970 15985 31402 E CONSCRYPT: IssuerDN: C=IT, O=RSPTEST, OU=TESTCERT, CN=Test CI 03-10 17:27:41.971 15985 31402 E CONSCRYPT: Get not before: Thu Jan 25 21:07:13 GMT+01:00 2024 03-10 17:27:41.971 15985 31402 E CONSCRYPT: Get not after: Wed Feb 26 21:07:13 GMT+01:00 2025 03-10 17:27:41.972 15985 31402 E CONSCRYPT: Sig ALG name: SHA256withECDSA 03-10 17:27:41.972 15985 31402 E CONSCRYPT: Signature: 3045022100af8e941c969949124f5456da060993f4873b51ed70452a4078da2b2de8e817dc02205035137e74c5f33af8f3daee42770a8ca9bdea40961205f24eba4d9fed9a3846 03-10 17:27:41.976 15985 31402 E CONSCRYPT: Public key: 03-10 17:27:41.976 15985 31402 E CONSCRYPT: 03-10 17:27:41.976 15985 31402 E CONSCRYPT: 30 59 30 13 06 07 2a 86 48 ce 3d 02 01 06 08 2a 86 48 ce 3d 03-10 17:27:41.976 15985 31402 E CONSCRYPT: 03 01 07 03 42 00 04 c0 1e ac ee aa 6f 7c 0c d7 40 d0 6b b3 03-10 17:27:41.976 15985 31402 E CONSCRYPT: a6 ce 65 4c e2 40 65 c4 34 1c c3 d6 11 48 0c 59 f3 23 54 92 03-10 17:27:41.976 15985 31402 E CONSCRYPT: c9 80 44 7a 48 ca 73 d1 e7 18 10 e1 90 b5 49 ab a2 df ab b2 03-10 17:27:41.976 15985 31402 E CONSCRYPT: b4 25 91 42 0d 7b 7f 5a 73 cd 59 03-10 17:27:41.976 15985 31402 E CONSCRYPT: == Chain1 == 03-10 17:27:41.976 15985 31402 E CONSCRYPT: Version: 3 03-10 17:27:41.977 15985 31402 E CONSCRYPT: SubjectKeyIdentifier: 4160414f54172bdf98a95d65cbeb88a38a1c11d800a85c3 03-10 17:27:41.977 15985 31402 E CONSCRYPT: Serial Number: b874f3abfa6c44d3 03-10 17:27:41.977 15985 31402 E CONSCRYPT: SubjectDN: C=IT, O=RSPTEST, OU=TESTCERT, CN=Test CI 03-10 17:27:41.978 15985 31402 E CONSCRYPT: IssuerDN: C=IT, O=RSPTEST, OU=TESTCERT, CN=Test CI 03-10 17:27:41.978 15985 31402 E CONSCRYPT: Get not before: Wed Apr 01 10:27:51 GMT+02:00 2020 03-10 17:27:41.978 15985 31402 E CONSCRYPT: Get not after: Thu Apr 01 09:27:51 GMT+01:00 2055 03-10 17:27:41.978 15985 31402 E CONSCRYPT: Sig ALG name: SHA256withECDSA 03-10 17:27:41.978 15985 31402 E CONSCRYPT: Signature: 3044022052756aafc2020a6cecbf2e5f3c20892510ff29751d298bd3b015d9605a4fe67d022057982836e4d205ddd2e6c3c1b455937f6b6e493b602fd1b66c357489a935f76b 03-10 17:27:41.982 15985 31402 E CONSCRYPT: Public key: 03-10 17:27:41.982 15985 31402 E CONSCRYPT: 03-10 17:27:41.982 15985 31402 E CONSCRYPT: 30 59 30 13 06 07 2a 86 48 ce 3d 02 01 06 08 2a 86 48 ce 3d 03-10 17:27:41.982 15985 31402 E CONSCRYPT: 03 01 07 03 42 00 04 94 06 57 a6 73 dc 28 8f 89 d5 2e a8 a4 03-10 17:27:41.982 15985 31402 E CONSCRYPT: 77 04 99 27 91 f9 c3 4b 00 36 e6 33 e2 d0 cb a9 45 4d 65 db 03-10 17:27:41.982 15985 31402 E CONSCRYPT: 32 eb 17 98 17 99 d2 f2 43 88 ee 2b 95 c1 09 45 46 c9 79 01 03-10 17:27:41.982 15985 31402 E CONSCRYPT: ce ae ba 96 50 91 9a 2e 20 d2 29 03-10 17:27:41.995 15985 31402 W System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. 03-10 17:27:41.996 15985 31402 W System.err: at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:239) 03-10 17:27:41.996 15985 31402 W System.err: at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:1471) 03-10 17:27:41.996 15985 31402 W System.err: at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:1415) 03-10 17:27:41.996 15985 31402 W System.err: at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:1359) 03-10 17:27:41.996 15985 31402 W System.err: at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:221) 03-10 17:27:41.996 15985 31402 W System.err: at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:144) 03-10 17:27:41.996 15985 31402 W System.err: at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:106) 03-10 17:27:41.996 15985 31402 W System.err: at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:400) 03-10 17:27:41.997 15985 31402 W System.err: at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:333) 03-10 17:27:41.997 15985 31402 W System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:483) 03-10 17:27:41.997 15985 31402 W System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:135) 03-10 17:27:41.997 15985 31402 W System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:266) 03-10 17:27:41.997 15985 31402 W System.err: at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:219) 03-10 17:27:41.997 15985 31402 W System.err: at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:30) 03-10 17:27:41.997 15985 31402 W System.err: at net.typeblog.lpac_jni.impl.HttpInterfaceImpl.transmit(HttpInterfaceImpl.kt:46) 03-10 17:27:41.997 15985 31402 W System.err: at net.typeblog.lpac_jni.LpacJni.downloadProfile(Native Method) 03-10 17:27:41.997 15985 31402 W System.err: at net.typeblog.lpac_jni.impl.LocalProfileAssistantImpl.downloadProfile(LocalProfileAssistantImpl.kt:121) 03-10 17:27:41.997 15985 31402 W System.err: at im.angry.openeuicc.ui.ProfileDownloadFragment$doDownloadProfile$2.invokeSuspend(ProfileDownloadFragment.kt:193) 03-10 17:27:41.997 15985 31402 W System.err: at im.angry.openeuicc.ui.ProfileDownloadFragment$doDownloadProfile$2.invoke(Unknown Source:8) 03-10 17:27:41.997 15985 31402 W System.err: at im.angry.openeuicc.ui.ProfileDownloadFragment$doDownloadProfile$2.invoke(Unknown Source:4) 03-10 17:27:41.997 15985 31402 W System.err: at net.typeblog.lpac_jni.LocalProfileAssistant$beginOperation$2.invokeSuspend(LocalProfileAssistant.kt:48) 03-10 17:27:41.997 15985 31402 W System.err: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) 03-10 17:27:41.997 15985 31402 W System.err: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) 03-10 17:27:41.997 15985 31402 W System.err: at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42) 03-10 17:27:41.997 15985 31402 W System.err: at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95) 03-10 17:27:41.997 15985 31402 W System.err: at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570) 03-10 17:27:41.997 15985 31402 W System.err: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750) 03-10 17:27:41.997 15985 31402 W System.err: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677) 03-10 17:27:41.997 15985 31402 W System.err: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664) ``` I somehow have the feeling it is a matter of certificate ordering? However, I cannot change the order of certificates in nginx, as the first certificate in file must match the private key; so any intermediate or root CA certificates will always follow after the server cert.
Author

Actually the standard mandates that the first TLS certificate sent is the sender (server) certificate, followed by any other crtificates. See: https://www.rfc-editor.org/rfc/rfc5246#section-7.4.2

btw: If you want some sysmoEUICC1-C2T samples: I'm happy to send you some, if you're interested. Contact me with your mailing address in that case.

Actually the standard mandates that the first TLS certificate sent is the sender (server) certificate, followed by any other crtificates. See: https://www.rfc-editor.org/rfc/rfc5246#section-7.4.2 btw: If you want some sysmoEUICC1-C2T samples: I'm happy to send you some, if you're interested. Contact me with your mailing address in that case.
laf0rge reopened this issue 2024-03-10 17:52:28 +01:00
Author

what's odd is that the authoritkeyidentifier / subjectkeyidentifier of the SGP.26 v1 NIST CI certificate i s f54172bdf98a95d65cbeb88a38a1c11d800a85c3 (also in your RootCertificates.kt file) - but the log file output of EasyEUICC is missing the initial f5

what's odd is that the authoritkeyidentifier / subjectkeyidentifier of the SGP.26 v1 NIST CI certificate i s `f54172bdf98a95d65cbeb88a38a1c11d800a85c3` (also in your RootCertificates.kt file) - but the log file output of EasyEUICC is missing the initial `f5`
Owner

There could be a bug in lpac that stripped that initial byte from the response.

There could be a bug in lpac that stripped that initial byte from the response.
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: PeterCxy/OpenEUICC#11
No description provided.