Skip to content

Instantly share code, notes, and snippets.

@ByteHamster
Last active June 25, 2022 21:47
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ByteHamster/f488f9993eeb6679c2b5f0180615d518 to your computer and use it in GitHub Desktop.
Save ByteHamster/f488f9993eeb6679c2b5f0180615d518 to your computer and use it in GitHub Desktop.
ConscryptProviderInstaller Proof-Of-Concept
/*
* This class would be distributed as a small library to be included in apps.
* The library does NOT need the (large) Conscrypt dependency.
*/
package de.danoeh.antennapod.core;
import android.content.Context;
import android.content.pm.PackageManager;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ConscryptProviderInstaller {
private static boolean installed = false;
public static void installIfNeeded(Context context) {
if (installed) {
return;
}
try {
Context targetContext = context.createPackageContext("com.bytehamster.providerinstaller",
Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
ClassLoader classLoader = targetContext.getClassLoader();
Class installClass = classLoader.loadClass("com.bytehamster.providerinstaller.ProviderInstallerImpl");
Method installMethod = installClass.getMethod("install", new Class[]{ });
installMethod.invoke(null);
installed = true;
} catch (PackageManager.NameNotFoundException | ClassNotFoundException
| NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
/*
* This class is located in another apk that needs to be installed separately.
* Its code and Conscrypt library can be shared with other apps.
* This apk (com.bytehamster.providerinstaller) needs the (large) Conscrypt dependency.
*/
package com.bytehamster.providerinstaller;
import android.util.Log;
import org.conscrypt.Conscrypt;
import java.security.Security;
public class ProviderInstallerImpl {
private static final String TAG = "ProviderInstallerImpl";
public static void install() {
Log.d(TAG, "Installing provider...");
Security.insertProviderAt(Conscrypt.newProvider(), 1);
Log.d(TAG, "Provider installed successfully.");
}
}
@Slinger
Copy link

Slinger commented Sep 19, 2020

For context, this might have useful information: Conscrypt Bundling Example

After inserting a new version of conscrypt (through this method or by bundling it directly with an app) it is still necessary to do some more work to fully utilize it and increase security, like disabling old insecure protocols (SSLv3) and enable new (TLSv1.3).

@eighthave
Copy link

Very nice! I think microG contains some version of this idea, where it can act as a central TLS provider.

@Slinger
Copy link

Slinger commented Dec 1, 2021

Sorry for writing so much! Hans, you got me thinking about this again. I think we all talked about this idea a while ago on the F-Droid forum. I've been meaning to get the discussion going again, I got some ideas I want to share but have never gotten around to actually posting. This all got started because AntennaPod was having problems downloading content on old devices and bundling Conscrypt directly was an easy (but ugly) solution. A solution that provides (and updates) a single copy of Conscrypt to all apps would be better.

I do have some concerns about using hard-coded public/private keys to secure this sort of transaction. And if I'm not mistaken microg requires apps to be built against the proprietary GMS libraries. And actually using microg requires a rom with signature spoofing (so no stock, and even lineageos typically don't support it by default).

My dream would be to solve this by having the user simply install a ("system app"?) zip in rescue, similar to the F-Droid privilege extension. Perhaps it would be possible to add a new security provider directly to the built-in ones in the OS, making it a global and automatic solution for all apps (or otherwise maybe offer the provider to apps in a way a regular non-system app can't fake?). I've been digging through the android source to see how feasible it would be. And there is already a similar idea for doing this through a magisk module (I can't find it right now, but I can look if you like).

Oh, and I believe a project of yours, NetCipher, supports bundling Conscrypt with apps? A thought I've had is that (if apps would need to explicitly request the new conscrypt) this "client-side" functionality would fit really well with the existing features of NetCipher (since it covers the necessary configuration necessary to fully utilize the new security provider).

@eighthave
Copy link

eighthave commented Dec 2, 2021 via email

@Slinger
Copy link

Slinger commented Dec 2, 2021

Oh, don't get me wrong. I just meant the practical requirements of using microG as-is. A purpose-built solution for this specific problem wouldn't need exactly those requirements. But it would still need some way of ensuring/verifying that no malicious app poses as the expected one and provides a tampered security provider (or just generally exploits the possibility of arbitrary code execution).

An idea of using private-public keys to verify the authenticity was mentioned before (and it's indirectly how the microG/GMS approach works), but I have strong concerns about it (I can go into details about it, but I don't want to make this post too long) and ideally I would like to find some other solution. IMO the best case would be to insert the provider into the set of OS-provided ones (through a recover zip), to globally upgrade the security of all apps automatically. But when I was looking into doing that, it was hard to figure out how (the android source is a bit of a mess...). But I still think it's possible. And if so, maybe the functionality could even be added to the F-Droid privilege extension (that way the F-Droid client could be privileged keep the new security provider up-to-date)?

@evermind-zz
Copy link

Did anyone implemented ByteHamsters proof of concept anywhere? I would like to use that approach. If nothing is there yet I may build it myself.

@Slinger
Copy link

Slinger commented Mar 10, 2022

I don't believe so, and keep in mind that using this approach would also require all apps to be modified to benefit. But if your goal is just to use a modern conscrypt version in a few apps, maybe try bundling conscrypt directly with those apps? It's very easy, I wrote a guide here: https://github.com/Slinger/Conscrypt-Bundling-Example

As for this proof-of-concept, as the name implies it's just to demonstrate the idea. It's actually based on an idea I proposed in a PR when I bundled conscrypt with antennapod (see here for more info and the talk about this idea starts around here).

Sadly I don't think I nor ByteHamster will have the time to implement this for real. Also I think we disagree on one implementation detail: my goal is to (in best case) insert the new conscrypt globally in the OS so it will automatically upgrade all apps, or (if not possible) find a way which doesn't require all apps to use a hard-coded signature (something I suspect will cause a lot of issues in the future).

@evermind-zz
Copy link

Thx for replying. Yeah I read most of your comments and I bundled Conscrypt into some apps which works great.

Sadly I don't think I nor ByteHamster will have the time to implement this for real. Also I think we disagree on one implementation detail: my goal is to (in best case) insert the new conscrypt globally in the OS so it will automatically upgrade all apps, or (if not possible) find a way which doesn't require all apps to use a hard-coded signature (something I suspect will cause a lot of issues in the future).

With hard-coded signature you meant the java signature eg. com.something.nice or something the signature of the apk?

Having an apk approach seems easier for the average user, than relying on a zip file using recovery.
But as f-droid does no longer support older than Android 5.1 Lollipop (API 22) the distribution might be not as easy as it could be.

@Slinger
Copy link

Slinger commented Mar 10, 2022

I'm glad to hear it was useful! Regarding the f-droid client, you can find more info on older versions which supports old devices here: https://gitlab.com/fdroid/wiki/-/wikis/Running-on-old-Androids I'm still using an old version on my kitkat device with no problems.

Now, about signatures: if you look at this proof-of-concept, a malicious app could pretend to be "com.bytehamster.providerinstaller", and provide a tampered version of conscrypt (spying, or causing code execution) in all apps that requests it. The obvious solution is to rely on a public&private key pair, so only the version signed by the real developer will be accepted by the apps. But doing this can cause much problems, not the least that old versions of android has flaws that allows spoofing signatures... but there are other big problems, some I've written (too) much about here https://forum.f-droid.org/t/lack-of-tls-1-2-breaking-apps-in-older-androids/9823/14

In short, using a private key will lead to a form a tiivoization: it will be hard for anyone else to build/update/replace the app, they would need to rebuild all other apps against the new signature... if the signature is lost, all apps needs to be rebuilt... if the signature leaks, it's a big security problem and all apps will need to be updated ASAP... if some user i using an old version of some app, they will probably not receive this rebuilt version... and if we want to archive and maintain a "time capsule" of old apps, then not having the private key could be a problem in the future... and so on...

So it's a matter of weighing user/developer convenience against security: if the user instead has to install a zip through recovery, they will at least have full control and there's no way a malicious app can bypass it. It will also make it possible to replace it (for development/experiment and everything I mentioned above) - without having to modify all installed apps. Ideally, this zip would insert something in the OS which inserts the new conscrypt version in the global list (or in worst case, this system-level app could provide an API to the apps which no user-level app could fake?). And ideally the conscrypt version would be updated by the f-droid client, so this is a one-time installation on the device.

I've also seen an idea of creating a magisk/xposed module for this idea. Similar idea, and it might have some extra benefits, but it also feels like even more work for the user.

@ByteHamster
Copy link
Author

At the RC3 Congress there seemed to be the consensus that using Google's system component as a provider would be the most feasible option. It has a signature that will likely not change in the near future and the same provider+signature is installed on devices running MicroG.

@Slinger
Copy link

Slinger commented Mar 12, 2022

Interesting. I don't have time to look at the recordings (if there are any), but does this mean redistributing a prebuilt (and signed) security provider binary built by Google? (libconscrypt_gmscore_jni.so?)

I'm a bit concerned about this way of depending directly on google. But if it's agreed on by all the F-Droid developers I guess it's the most pragmatic approach.

@ByteHamster
Copy link
Author

I don't have time to look at the recordings (if there are any)

There are no recordings unfortunately

But if it's agreed on by all the F-Droid developers

Only some of the developers attended the meeting. I remember eighthave and uniqx

does this mean redistributing a prebuilt (and signed) security provider binary built by Google?

No, it means calling the ones from Google (with the technique above) without having to ship it in every app. It would basically be an open-source re-implementation of Google's ProviderInstaller client library, calling the same system components

@Slinger
Copy link

Slinger commented Mar 13, 2022

Ah, I wish I had known and been around. I hope it was fun!

No, it means calling the ones from Google (with the technique above) without having to ship it in every app. It would basically be an open-source re-implementation of Google's ProviderInstaller client library, calling the same system components

Hmm... that would require that user has installed GMS (which not everyone wants), or MicroG which requires signature spoofing - something (for example) the official builds of LineageOS does not allow (see here)... so there seems to be details needing further discussion here. Do you know if there's any active talk about this (e.g. on the f-droid forum)?

@ByteHamster
Copy link
Author

Hmm... that would require that user has installed GMS (which not everyone wants), or MicroG which requires signature spoofing - something (for example) the official builds of LineageOS does not allow

Yes. I do think we need to be realistic, though - most users use GMS and do not know what a "security provider" even is. Using the system provided one therefore probably fixes things for more users than having an independent app and at the same time solves the signature problem.

Do you know if there's any active talk about this (e.g. on the f-droid forum)?

I don't know of any discussion

@Slinger
Copy link

Slinger commented Mar 13, 2022

[...]most users use GMS and do not know what a "security provider" even is.[...]

And those users most likely installs AntennaPod from the google play store, which uses the security provider from GMS already.

The problem to solve is for the users who installs AntennaPod (or some other app) from f-droid instead of the play store. And I'd bet those users are generally more technically savvy and doesn't necessarily want GMS. And also not all of them will even be able to install microG (unless they have a rom that supports signature spoofing, which most don't). In fact (if I understand correctly) this approach wouldn't add anything compared to just building the apps against the gms client libs (or reverse-engineered open counterparts) and simply have the apps load it directly from GMS/microG - it just introduces another middleman and the complexities it brings, but I might have misunderstood.

If anyone implements this I really don't mind, but If what you describe is accurate and I understand it correctly... then sadly I don't see this being a solution for everyone affected (for me and other FLOSS fans who doesn't want GMS and can't/wont install microG). And if apps like AntennaPod switches from bundling conscrypt to requiring the user to install GMS/microG then it will again stop working for users in my situation.

No offense, but I guess I feel a bit left out of the conversation. I mean technically I suggested the idea (after ironing out the details of bundling conscrypt with AntennaPod), but my involvement was barely mentioned (and originally not at all) in the f-droid blog post, and when I've tried bringing up points for/against certain details it seems to just falls on deaf ears. I really do hope someone implements some good solution to this problem, but for now I'm happy with a specific AntennaPod version I've pinned on my device, and I can settle for just keeping that version. I'm not feeling much motivation to contribute to this, it seems like my suggestions or work will not matter.

@ByteHamster
Copy link
Author

I mean technically I suggested the idea (after ironing out the details of bundling conscrypt with AntennaPod), but my involvement was barely mentioned (and originally not at all) in the f-droid blog post

I'm sorry. It was not my intention to "steal" the idea from you.

I don't see this being a solution for everyone affected (for me and other FLOSS fans who doesn't want GMS and can't/wont install microG)

I mean, a library could do both - take the one from MicroG/Google if it is available and ask for installing the external app if it isn't. Then most users would get working apps without having to do anything and people who use a custom ROM can install the provider. To get around the signature issue, apps could just ask users. Something like "Do you want XY to become your security provider?"

@Slinger
Copy link

Slinger commented Mar 30, 2022

I mean, the idea itself is nothing special. I just felt a bit left out from the conversation(s) around it. Also I was sad to have missed the congress, it sounds like it was fun. But I'm not sure I'd been able to attend anyway, I'm very busy right now. Speaking of which, sorry for replying so late. I didn't mean to be rude and keep you hanging for so long. If I was pedantic about being credited I would be more concerned about not being credited in the antennapod release notes.

And sure, I think we can agree that the client library (that part the normal apps use) should be able to fetch conscrypt from microG/GMS if it's available, and do it directly (oh, to clarify: when you wrote "(with the technique above)" I thought you suggested the part in ProviderInstallerImpl.java would fetch conscrypt from GMS/microG and then pass it along to the apps, which would have been weird... sorry for the confusion 😅).

But this still leaves the part I'm interested in; a way to distribute conscrypt without relying on GMS/microG. For short while I got hopeful: I got the impression the conscrypt prebuilt&signed files could be copied from GMS (this seems to be what microG is doing, the files are included prebuilt from GMS) and then sent directly to the apps (so they can verify the google signature and somehow link against them at runtime), but that might not be possible with google's version of java (plus I'd imagine every app having a copy would eat more memory). In any way I hope it's possible to avoid a hard-coded signature check of some random developer (for reasons I've previously tried to explain).

Edit: just to clarify why/what I meant by: "not being credited in the antennapod release notes". It's not related to this discussion, I've just been chasing a regression that appeared (for me) around the 2.0 release. It happens rarely, so I've been lazy and just slowly stepping backwards in versions using the apk:s on the github release page (instead of doing bisections and building it myself). I was worried that it might be one of my changes (especially the conscrypt bundling), but then I noticed none of my changes were mentioned in any of the release version details, which I found a bit odd. But I've been able to determine which build has/hasn't conscrypt bundled, based on the file size.

@mendhak
Copy link

mendhak commented Jun 25, 2022

Hi all thanks for your efforts on the gist and discussions around it and the blog post. FWIW I decided to take the an easy approach for myself, which is creating a Conscrypt Provider, I'm going to be using it from another app of mine because I wanted to provide TLS 1.3 capabilities to old Android devices.

In theory anyone could call from their own app. I've included instructions on including it from another app including how to check for my signature or F-Droid's signature.

I've also submitted an app inclusion request on F-Droid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment