Android: RIP self-signed certificates

i want to replace HttpUrlConnection in android app with okhttp3, because it makes for much cleaner code, doesn’t depend on platform implementation that much, and I already use it anyway so having two http client libraries annoys me.

this brings me to self signed certificates, i.e. allowing to trust any certificate. this was implemented long before letsencrypt became a thing and we were generally all MITMed less. nowadays i think having this option is harmful because it provides an illusion of security to people who don’t know better, and in my experience, people generally don’t know better.

it’s been a while since i tried, but i think installing your own CA certificates is still a thing on android, if you don’t want to use letsencrypt or other platform-trusted SSL certificate vendor.

therefore, i want to remove this whole trusting anything thing for the okhttp rewrite. comments?

oh and before anyone asks, i think installing your own certificates in the app is redundant and it’s not going to happen.

Will that in any way effect connecting to a hidden/onion-site?

Any chance of getting a proxy configuration settings with the rewrite?

this strikes me as redundant too tbh.

e: app-specific proxy settings that is

that depends on whether your site has a self-signed certificate, i guess

I think leaving support for self signed is OK, if you did it differently, like firefox does. no check box in settings but on first access warn the user about possible security issue and if they accept, allow the site.

I don’t use a standard port and also have all access protected via basic auth. At one point lets encrypt only supported 80/443 as ports. also they didn’t work with my dynamic dns provider.

i want to remove bloat, not add to it. i wouldn’t even merge a PR for this.

this, and other similar issues, should be solved by having a custom CA, with certificate installed in the phone.

unless, of course, google managed to remove this already for our collective “safety” or w/e.

That is only needed for the challenge process, and there are other ways to answer the challenge. Once you have the certificate you can use it just like any certificate.

good point, there’s dns challenge now that you must use anyway instead of http for wildcard certificates

fox: that is what I will do. the capability appears to still be there.

randompherret: I did know that, but thanks for the assist.

I’ve switched to certbot rfc 2136 long ago

So just out of curiosity: how would the setup look like, if I just wanted to set up in my own lan environment, no access from outside.

Is there even any other way than using a self signed certificate?
Also, any “normal” certificate would not work anyway (I assume) since Android cant resolve .local addresses due to mDNS.
So I have to use the IP to connect to my tt-rss instance and I wont be able to get a cert on an IP.

So if the Android app cant connect to tt-rss via IP, then I would not be able to use it.

You use something like GitHub - OpenVPN/easy-rsa: easy-rsa - Simple shell based CA utility and import the ca cert into Android. Settings->security->encryption & credentials-> install from storage.

You can use self signed certs, you just have to tell Android to trust them.

I use a LetsEncrypt cert for locally hosted services by keeping a domain that doesn’t point anywhere, obtaining the cert using DNS challenges, and using a rewrite rule in my local DNS server to point that domain to the local server (I use Adguard for this, but pi-hole or any other will work, too). That gives me a cert that Android trusts, without having to import anything or expose anything to the big bad internet.

This is what I do and it works fine. I’m using iOS versus Android but after installing the root CA everything just works for all my self-hosted domains (both local and remote).

The .local thing sort of depends on your network; I don’t really bother with it myself and just use IPs. If you’re using a certificate signed by your own CA you can use an IP address, you just have to specify it in the SAN (subject alt. name) as IP:192.168.0.101 when you’re creating the certificate. If you’re using the EasyRSA scripts it can handle all that for you via command line options.

I wanted to try out the Android app for tt-rss which is hosted on a free cloud server. I do not have any domain names for the server, I just use the IP address. Previously, as I was setting up the server, I followed the instructions here so that I could use encrypted communications between my web browser (Firefox) and the server running tt-rss.

I knew next to nothing about all the options related to certificates. When I tried to load the self signed certificate generated by the commands in the link above into my Android phone, I could not get the app to connect to tt-rss, I was getting certificate errors. After a number of trials and errors, I could get the app to talk to the server. I believe the key options that made the difference in certificate creation were 1) specifying the subject alt name (thanks to the hint from JustAMacUser), 2) making sure the certificate has CA:True set. I am sharing the settings that I used below, it could be useful to others who run into a similar issue.


This is the command I used to create the certificate on the server:
sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -config trial.cnf -keyout /etc/ssl/private/apache-selfsigned.key -out /etc/ssl/certs/apache-selfsigned.crt

Here are the contents of trial.cnf configuration file, you should modify the parts highlighted with <...>:

[req]
default_bits  = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_req
prompt = no

[req_distinguished_name]
countryName = <FILL>
stateOrProvinceName = <FILL>
localityName = <FILL>
organizationName = <FILL>
organizationalUnitName = <FILL>
commonName = <PUT IP HERE, e.g., 1.1.1.1>
emailAddress = <FILL>

[req_ext]
basicConstraints = CA:TRUE
subjectAltName = @alt_names

[v3_req]
basicConstraints = CA:TRUE
subjectAltName = @alt_names

[alt_names]
IP.1 = <PUT IP HERE, e.g., 1.1.1.1>

After creating the new certificate, restart apache by: (if you are using a different server, the command would be different)

sudo service apache2 restart

I then downloaded the certificate to my local computer by visiting the tt-rss server from Firefox, add a security exception, click the security icon to the left of the server address, click more Information, view Certificate, then click Download PEM (chain).

The certificate now needs to be converted into a format that Android understands. The following command does the conversion.

openssl x509 -inform PEM -outform DER -in <DOWNLOADED_FILENAME>.pem -out self_signed.crt

Finally, copy the certificate to your Android phone. I used adb but any other way would be fine.

adb push self_signed.crt /storage/self/primary/Download/self_signed.crt

Now, selecting Security settings, Install from SD Card then choosing self_signed.crt results in the certificate installation into Android (you need to have lock screen password enabled, I believe). You can check to see if you have a CA certificate by going to Trusted Credentials (under Security settings) and verifying that the certificate shows up under the User tab.

Lastly, I had to grant API access to the app to get it to connect to the server.


There are probably better ways to get the self signed certificate to work with Android, I have very little experience with such settings. There might be serious security issues with the implementation above, if so, please let me know.