Question

I've managed to cross-compile OpenSSL for ARMv6 for use with the Android NDK and get it to run within my application. However, when attempting to establish an HTTPS connection to a well-known host (such as https://google.com), I always receive the error "The SSL certificate is invalid."

However, I have no difficulty displaying secure pages within any of my device's browsers (the stock browser, Chrome, Firefox, etc.). Therefore I can only assume OpenSSL isn't finding the root certificates stored on the device.

My question then breaks down into two very related sub-questions:

  • Where does Android store the root certificates on the device?
  • How can I point OpenSSL to them?
Was it helpful?

Solution

Where does Android store the root certificates on the device?

It moves around. With the advent of Ice Cream Sandwich (ICS), there are three stores used. The three stores are /data/misc/keychain (supplied by Android), /data/misc/keychain/cacerts-added (CAs added by users), and /data/misc/keychain/cacerts-removed (CAs removed by users or updates).

Prior to ICS, they used a BouncyCastle store located at /system/etc/security/cacerts.bks. It was a static store, and it could not be modified. If it needed to be changed, then you needed to update the firmware or image.

For an explanation of the stores, see ICS Trust Store Implementation. Its Nikolay Elenkov's blog, and he does a great job of discussing the system, and not just where the stores are located.


How can I point OpenSSL to them?

You can't really do it because what OpenSSL expects and what Android presents are two different presentation/storage formats. OpenSSL expects a collection of trust anchors in PEM format concatenated together. But an Android trust store is not in that format.

Often what happens is you download cacert.pem. Then, you load them with a call to SSL_CTX_load_verify_locations by specifying cacert.pem as the CAfile argument.

Even though you download cacert.pem from a trusted source, like Mozilla or cURL, you should still go through it and ensure you are satisfied with the collection of trust anchors. There are 155 potential trust anchors in the pack:

$ cat cacert.pem | grep BEGIN | wc -l
     155

But like I said in the comment, its implicitly using the Browser Security Model, and its not a particularly good way to do things in many instances.


when attempting to establish an HTTPS connection to a well-known host (such as https://google.com), I always receive the error "The SSL certificate is invalid."

To answer this, just use Google Internet Authority or GeoTrust Global CA with SSL_CTX_load_verify_locations. Its probably best to use Google Internet Authority because it limits the net cast.

Google Internet Authority:

-----BEGIN CERTIFICATE-----
MIID8DCCAtigAwIBAgIDAjp2MA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTYxMjMxMjM1OTU5WjBJMQswCQYDVQQG
EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB5zCB5DAfBgNVHSMEGDAWgBTAephojYn7
qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNQYDVR0fBC4wLDAqoCig
JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMC4GCCsGAQUF
BwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDovL2cuc3ltY2QuY29tMBcGA1UdIAQQ
MA4wDAYKKwYBBAHWeQIFATANBgkqhkiG9w0BAQUFAAOCAQEAJ4zP6cc7vsBv6JaE
+5xcXZDkd9uLMmCbZdiFJrW6nx7eZE4fxsggWwmfq6ngCTRFomUlNz1/Wm8gzPn6
8R2PEAwCOsTJAXaWvpv5Fdg50cUDR3a4iowx1mDV5I/b+jzG1Zgo+ByPF5E0y8tS
etH7OiDk4Yax2BgPvtaHZI3FCiVCUe+yOLjgHdDh/Ob0r0a678C/xbQF9ZR1DP6i
vgK66oZb+TWzZvXFjYWhGiN3GhkXVBNgnwvhtJwoKvmuAjRtJZOcgqgXe/GFsNMP
WOH7sf6coaPo/ck/9Ndx3L2MpBngISMjVROPpBYCCX65r+7bU2S9cS+5Oc4wt7S8
VOBHBw==
-----END CERTIFICATE-----

GeoTrust Global CA:

-----BEGIN CERTIFICATE-----
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
-----END CERTIFICATE-----

In the ideal world, you run a private PKI, and you only trust your PKI's root to certify sites and services. You don't confer trust a public CA to certify anything because they don't make any warranties to the relying party. Essentially, a public CA tells you their warez are no good, even for the purpose they are selling them to sites.

In the next best world, you only use the public CA that certified the site. That means you use Google Internet Authority or GeoTrust Global CA to certify Google properties; and not, say Diginotar.

There's other not-so-readily-apparent problems. The Google Internet Authority is an unconstrained subordinate CA certified by GeoTrust. Google is allowed to issue certificates for any site, and not just Google properties. Usually, this is caught by the RA, which is effectively an independent auditor that validates the signing request to the CA before issuance. But in this model, the organization making the request (Google) is the same organization that validates the request (Google), and the same organization that issues the certificate (Google). Browsers, CAs and PKI is the only instance I am aware the independent auditor was completely removed as a check-and-balance because it was too inconvenient.

If you think a subordinate would not do such a thing, then you'd be sadly mistaken. CNICC was just removed from a few browser trust stores because one of its unconstrained subordinates was caught issuing certificates for sites and services it was not authorized.

Where the browser security model really breaks down is ability for the wrong CA to certify a site. And it includes successful phishing attempts on the user. That is, a browser will happily allow a connection to be intercepted because a user was phished.

If you think the upcoming Public Key Pinning with Overrides will help, then you'd be sadly mistaken. Though they barely mention the overrides, an attacker can break a known good pinset. And worse, the reporting feature is disabled for a broken pinset with a MUST NOT Report, so the browser is complicit in the cover up.

There's a lot more reading available on the subject. For starters, try Peter Gutmann's Engineering Security and Audun Jøsang's Trust Extortion on the Internet.

OTHER TIPS

  • Where does android store the root certificates:

They move around from version to version and device to device according to loads of questions on adding certificates to the local keystore on different devices. Most of those require the device being rooted and later comments talk about the solution breaking because they moved or changed format on a particular device.

  • How can I point openssl to them:

I'm not sure there's a "good" way to do this right now. The best workaround I could find is this answer followed by shoveling those certificates into your own application specific store that openssl understands.

An imperfect solution, but one you might be able to use.

Where does android store the root certificates:

  • System certificates: These are stored in System/etc/security/cacerts.bks

  • ThirdParty certificates: These are stored in data/misc/keystore

How can I point openssl to them:

The android OS in conjunction with your openssl library will take care of this.You don't have to point it manually.

With the information you have given I am writing below.

Considering you are application is VPN or Cloud based application.

The issue might be due to Invalid SSL Root CA that you installed in device to inspect SSL traffic.

Hope this helps

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top