Install self-signed certificates no longer working in Android Q-ThrowExceptions

Exception or error:

I have generated a self-signed certificate which I tried to install on my phone running Android 10, but a snack appears telling me that Private key required to install certificate.

I have tried on a phone running Android 9 with the same certificate and it works as expected.

Any idea if there is any workaround to get the CA installed?

How to solve:

Here’s how I created a self-signed cert that will work with Android, iOS, and Chrome, from this answer:

openssl commands:

openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/C=US/ST=Oklahoma/L=Stillwater/O=My Company/OU=Engineering/CN=test.com" -keyout ca.key -out ca.crt
openssl genrsa -out "test.key" 2048
openssl req -new -key test.key -out test.csr -config openssl.cnf
openssl x509 -req -days 3650 -in test.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extensions v3_req -extfile openssl.cnf -out test.crt
openssl x509 -inform PEM -outform DER -in test.crt -out test.der.crt

Contents of openssl.cnf:

[req]
default_bits = 2048
encrypt_key  = no # Change to encrypt the private key using des3 or similar
default_md   = sha256
prompt       = no
utf8         = yes

# Specify the DN here so we aren't prompted (along with prompt = no above).

distinguished_name = req_distinguished_name

# Extensions for SAN IP and SAN DNS

req_extensions = v3_req

# Be sure to update the subject to match your organization.

[req_distinguished_name]
C  = US
ST = Oklahoma
L  = Stillwater
O  = My Company
OU = Engineering
CN = test.com

# Allow client and server auth. You may want to only allow server auth.
# Link to SAN names.

[v3_req]
basicConstraints     = CA:TRUE
subjectKeyIdentifier = hash
keyUsage             = digitalSignature, keyEncipherment
extendedKeyUsage     = clientAuth, serverAuth
subjectAltName       = @alt_names

# Alternative names are specified as IP.# and DNS.# for IP addresses and
# DNS accordingly.

[alt_names]
DNS.1 = test.com

After creating the certificates:

  1. Install the test.crt (not ca.crt at least in my case) to your server and restart it.
  2. Email the test.crt to your Gmail account, then log into Gmail in your
    Android device or simulator and tap to install it. (It will appear in the
    “USER” tab under Settings / Encryption & credentials / Trusted
    credentials.)

###

Building on @ScottyB’s answer:

openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/C=US/ST=Oklahoma/L=Stillwater/O=My Company/OU=Engineering/CN=test.com" -keyout ca.key -out ca.crt
openssl genrsa -out "test.key" 2048
openssl req -new -key test.key -out test.csr -config openssl.cnf
openssl x509 -req -days 3650 -in test.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extensions v3_req -extfile openssl.cnf -out test.crt

The error gives a hint on how to fix. If you combine the certificate and private key generated above into a single file, Android will accept it:

openssl pkcs12 -export -in test.crt -inkey test.key -out test-combined.p12

Transfer the .p12 file to your Android phone, then use Install From Device Storage. Give it a nice human-readable name and the CA certificate can now be used with services like web servers that use the ca.key & ca.crt.

Here’s an Nginx config snippet to refuse all connections except those that present a certificate signed by the above ca cert:

# within server block, eg. under the ssl_certificate config
    ssl_client_certificate /etc/ssl/ca/ca.crt;
    ssl_trusted_certificate /etc/ssl/ca/ca.crt;
    ssl_verify_client optional_no_ca;
    if ($ssl_client_verify != SUCCESS) { return 403; }

When your Android browser now visits this website, it will only let you in further if you present a signed certificate.

Leave a Reply

Your email address will not be published. Required fields are marked *