On 2025-01-15 12:47, Michael Rogers via anti-censorship-team wrote:
On 14/01/2025 18:47, cohosh--- via anti-censorship-team wrote:
Hi Michael,
We addressed the original problem in Snowflake a while ago by pinning the ISRG Root X1 cert[0], and I wrote a quick patch for Lyrebird[1] that does the same. Although, indeed, it looks like the cert we've pinned[2] has expired, and we need to update that.
Thanks, good to know. The Moat library used by OnionShare Android doesn't use Lyrebird for its Moat connection but it looks like that's our best path forward.
This won't work quite yet without that above patch merged and also updated to use an up-to-date root cert. Is OnionShare using the original meek client[3]? If so, we can also work on adding cert pinning support there.
[0] https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowf... [1] https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyreb... [2] https://crt.sh/?id=3958242236 [3] https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/meek/
Hi cohosh,
Thanks for following up on this.
I made a mistake about OnionShare's use of Moat. It *does* use obfs4proxy for the meek connection (and will use Lyrebird in the next release), but then the HTTPS request through the meek tunnel fails on Android < 7.1.1 because bridges.torproject.org also uses a Let's Encrypt certificate. To fix that, I need to investigate whether we can get the libraries we're using for HTTPS (OkHttp and Conscrypt) to trust a pinned certificate.
Another thing I need to investigate is a difference in failure modes between Lyrebird 0.5.0 and obfs4proxy 0.0.14 on Android 7.0.
On Android 7.1.1, both versions of the transport are able to make meek connections via CDN77 and Azure and then connect to bridges.torproject.org through the tunnel.
On Android 7.0, both versions of the transport are able to make meek connections to Azure. (They then fail to connect to bridges.torproject.org through the tunnel as I mentioned above, but that's a separate issue.)
But on Android 7.0, obfs4proxy 0.0.14 can make a meek connection to CDN77 before failing to connect through the tunnel, whereas Lyrebird 0.5.0 fails with a timeout error instead.
When I first read your message I thought, "Aha, the out-of-date certificate pin is causing the meek connection to CDN77 to fail, that's why we see a timeout with Lyrebird but not with obfs4proxy." But now I have a doubt. If there's an out-of-date pin then shouldn't Lyrebird + CDN77 also fail on Android 7.1.1? Or is the pin only consulted if the platform's certificate store fails to validate the certificate (which would be the case for Android 7.0 + CDN77 + Lyrebird, but not for any other combination)?
Well, we never shipped the pin for Lyrebird. That was a trial patch I discarded because it didn't solve the problem we were seeing. Your last guess is correct. What we're doing in Snowflake isn't restrictively pinning certs. We're just appending the Let's Encrypt root cert to the root CA pool[0]. So if a platform, like Android 7.1.1 and above, already has a working cert in it's store, it doesn't need the pinned cert and just ignores it.
I am curious about the CDN77 meek connection working while the internal tunnelled connection fails on < Android 7.1.1. This sounds like exactly the issue we've been trying to debug with Tor Browser[1], when domain fronting stopped working with Fastly, which wasn't using Let's Encrypt. It didn't occur to me to think about certificate validation in the tunnelled connection... I guess I assumed that the application would do the right thing with the expired cross-signed root cert. But maybe the libraries used by Tor Browser and OnionShare are similar to the Go library in this way, and actually are enforcing the expiration date.
[0] https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowf... [1] https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyreb...