18

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?

Dorinel Panaite
  • 492
  • 1
  • 6
  • 15

3 Answers3

15

Great! My problem was solved with this code:

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

After this, I managed to import the test-combined.p12 certificate normally to my Android 10.

Thank you!

Aman Srivastava
  • 1,007
  • 1
  • 13
  • 25
  • 10
    How can I get the private keys of the third party server? and why android Q have this kind of feature? any explanation from android – Prabhakaran Jul 24 '20 at 02:49
  • 4
    I'm curious as well. It makes zero sense for an app or OS to ask for a private key, it defeats the purpose of using a certificate in the first place. – tresf Mar 25 '21 at 14:32
  • I think this is for adding a pkcs12 certificate which contains your __personal__ private key and certificate authority signed __personal__ certificate (generated by the ca using the certificate request you provided them). One use case I found for this feature is for accessing a VPN. If you need to access an https server from your phone, you don't need to do the command above. You only need to install the ca's x509 certificate (not their pkcs12 certificate) that was used to generate the https server's certificate. I'm not a security expert so please take this with a grain of salt. – bmdelacruz Feb 09 '22 at 18:59
  • That makes no sense. You imported private key of what I presume is your CA. This is exactly what you should never do. In case of your organization, IT will never give you a CA's private key. If it's your personal CA, well, then you provided google or samsung or whatever with your absolutely un-disclosable key they have no business knowing. – galets Jun 21 '22 at 00:54
  • 2
    A private key is NOT required to install self-signed certificates on Android. What is required is that the certificate be a CA certificate. That means that the x.509 'Basic Constraints' extension MUST have the code "CA:true" present in the certificate AFTER it is generated. If this isn't present in the certificate, it won't install on Android. In my case it was a Samsung S9+ that gave me THE COMPLETELY MISLEADING MESSAGE "Private key required". A PRIVATE KEY ISN'T REQUIRED. What is required is that the certificate contain "CA:true". – Bill Vallance Aug 15 '22 at 15:13
12

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.)
ScottyB
  • 2,167
  • 1
  • 30
  • 46
  • 2
    send me your https://beerpay.io/ link or whatever you happen to use! You, my friend, deserve a beer or two! Two days I have been working on this and finally put in the right google search to land here. – Michael Hobbs Jan 05 '20 at 17:18
  • Glad it helped. I’ll be posting a better answer to https://stackoverflow.com/q/57565665/1161573 soon that’s much simpler – ScottyB Jan 05 '20 at 20:48
  • 1
    The `CA:TRUE` constraint seems to be what's missing for most people, I initially thought (silly me!) that your answer was very similar to what I was doing and skipped it, but a minimal example worked for me in https://android.stackexchange.com/questions/237141/how-to-get-android-11-to-trust-a-user-root-ca-without-a-private-key/238859#238859 with that flag. – F.X. Jun 18 '21 at 20:32
  • @F.X. Thanks for pointing out, I was missing the same 'CA:TRUE' – avinash Oct 13 '22 at 17:48
4

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.