OpenEUICC doesn't seem to work with unknown CERT.CI.ECDSA on the eUICC for TLS cert verification #11
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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
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.
Ok, a quick look at the source code reveals:
app-common/src/main/res/raw/symantec_gsma_rspv2_root_ci1
andapp-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.
Looking a bit at Android and Java APIs for this, I think the course of action would be to implement a custom
X509TrustManager
whosecheckServerTrusted
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
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.
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.
But I agree checking with GetEuiccInfo1/2 would be the best course of action to support non production CIs
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.
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.
That would work, yes. It's not very elegant, but I understand the advantage of a simple solution.
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
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.
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.
Although I guess I could also piggyback on lpac's
derutil.c
here from JNI.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.
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.
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:
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.
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.
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 initialf5
There could be a bug in lpac that stripped that initial byte from the response.
There's a mode to ignore certs across the board now.