Rating: Medium
Description:
Certificate or public key pinning is when an app communicates with entites with specific TLS Certificates/Public Key. Any other communication is denied by the app, even if the TLS Certificate is signed by a trusted CA. This provides extra protection against Man in the Middle (MitM) attacks.
iOS app does not implement this secure measure, and this increases the possibility of a MitM attack.
Internal Tracking ID: EXPOSUREAPP-2517
HI @BSI-TF-CWA thanks for sharing this security attack vector.
The certificate pinning functionality using a controlled intermediate certificate is in develop. As a result I am closing this issue.
Best regards,
Chris
Rating: Medium
Description:
The iOS app now implements public key pinning. However, the distribution
backend is explicitly whitelisted from public key pinning. As the application
data received from the distribution backend is signed, an attacker in a MitM
position cannot tamper with this data. However, they could still observe and
modify this traffic.
Proof of Concept:
The exception is configured in the following file: https://github.com/corona-warn-app/cwa-app-ios/blob/development/src/xcode/ENA/ENA/Resources/HostWhitelist.plist
I don鈥檛 see how observing the traffic between the CDN and the app poses any risk, because all app instances download the same data from the CDN, right?
The one thing a MITM attacker could do, is to replay old versions of (correctly signed) App Configuration Data or Diagnosis Key sets, and by doing this modify the risk score result of the user.
Not even sure if that will work --> "Return data needs to be signed and will contain a timestamp [...]" here
@haxxbard Do you want this timestamp to checked? Or the signature to contain an expiration timestamp? I didn't find either in the current source code, could you maybe please point me to that, or to the exact specification of the requirement?
@mh- for my understanding only the last 14 days of diagnosis keys will be relevant for any risk calculation, see here. Nevertheless the configuration data might be able to be replayed, that's something we need to investigate on and track it in a separate issue (For tracking purposes: #434).
@haxxbard I agree. And also a MITM attacker (e.g. in a hotel network) could on purpose replay too old packets that will automatically yield _no_ exposure risk, to give the user a false sense of safety, while the app and the API assume that they did their work correctly.
I wonder if setting an expiration date on the signatures is feasible and would help against this.
Planned for Version 1.1 (31.07.2020)
The iOS app now implements public key pinning for all backends. However, there seems to be an anomaly which negatively impacts the pinning measure at app start up. When the app is first started, two subsequent requests to /app_config seem to be sent from the device. The headers in these requests seem to slightly differ. When certificate pinning is explicitly disabled, both of these requests can be seen in an interception proxy that is set up in a MitM position. With certificate pinning enabled (i.e., the unmodified version of the app), one of these requests can still be observed, meaning that the rogue MitM certificate does not seem to be checked for this request.
It is interesting to note that this only occurs on app start up. Any subsequent requests to the distribution backend (and especially to the /app_config endpoint) are covered by the certificate pinning and do not come in pairs.
The following screenshots shows the two requests as well as their request headers, that can be observed when certificate pinning is disabled:

The implementation of the initial app configuration retrieval seems to be flawed. The app is sending two requests where only one request is needed. This additional, unneeded request seems to be the one that is missing the proper public key pinning. This issue could be fixed by identifying the reason for the additional request and removing this request.
@BSI-TF-CWA thanks for sharing your observations. The first call is made during application start to check if the device is online. Since the call is made by a library we can't enforce certificate pinning here. (the lib doesn't allow that)
Since we are only using the information (response received: yes, no) we not see any attack vector with MiM here.
In the subsequent releases we plan to retire the library and the call will disappear.
Nevertheless for the entire RiskScore calculation the certificate pinning is implemented which you see in the request chain.
We agree that a large part of the certificate pinning is implemented and the remaining open point only refers to a "response received" information. Nevertheless, we are of the opinion that the feature is not yet fully implemented and therefore we want to keep this issue open. However, the criticality of is reduced to low.
Hi @BSI-TF-CWA , thanks for sharing your content. I will keep this point to discuss this internally with our development team and come back to you as soon as possible.
Thanks,
MP
Corona-Warn-App Open Source Team
Internal Tracking ID: EXPOSUREAPP-2517
Hello @BSI-TF-CWA,
this issue has been marked as completed and will be closed now.
If you have additional questions, please feel free to reach out.
Thanks,
LMM
Corona-Warn-App Open Source Team
Most helpful comment
@haxxbard I agree. And also a MITM attacker (e.g. in a hotel network) could on purpose replay too old packets that will automatically yield _no_ exposure risk, to give the user a false sense of safety, while the app and the API assume that they did their work correctly.
I wonder if setting an expiration date on the signatures is feasible and would help against this.