Apps | Hardware | Setup | Network | Hacking | Wishlist | Top |
A number of Android users, myself included, have posted forum complaints that they cannot read or send mail, or do other internet activities such as XMPP/Jabber, that involve SSL/TLS to a server whose X.509 host certificate is signed by a trust vendor or other origin of trust that is not in Android's certificate storage area. Here is the procedure to add your preferred X.509 root certificate, or to delete a certificate which you object to on political grounds.
If a reader has gotten to this page he/she probably is fully aware of the issues, but they should be repeated: you should only believe in a root certificate if you have obtained it from a trusted source, e.g. from the hand of a trusted system administrator or over an internal LAN on which the enemy is not likely to be operating, and if you trust the person who can wield its secret key to only certify hosts or persons whose hat color matches yours.
These instructions are for Android 1.5 Cupcake
, but are likely
to be fairly stable on back or future versions.
To add (or delete) a root certificate:
Make sure that the Java package on your development machine includes
keytool; look for /usr/bin/keytool
. My distro (OpenSuSE 11.1)
provides java-1_6_0-sun-1.6.0.u13 which provides this program symlinked through
/etc/alternatives/keytool
).
Make sure OpenSSL is installed. Look for the command
/usr/bin/openssl
.
Obtain and install the Android SDK (software development kit). It is not necessary to have a functioning Eclipse setup for this, but you will be using adb.
Check out a copy of the sources. See the
Get Source page for
how to do this. For these examples full path names in the source code
are shown beginning with
~/android
; modify to match where you put the sources. In many
cases files and directories can be adjusted and may possibly change in future
versions of Android.
Change directory to
~/android/dalvik/libcore/security/src/main/files
Download the BouncyCastle provider JAR file from http://www.bouncycastle.org/latest_releases.html. This JAR file is not included with Android, though the contents are in the distro; nonetheless I was not able to make the procedure work using the unpacked native source code. I planted the JAR file in the current directory, purely for convenience.
In this directory is a subdirectory called cacerts
, which
contains authority root certificates. You need to add your own root
certificate to the directory, or delete the politically poisonous one. The
certificates are in PEM
format: view the file and look for -----BEGIN CERTIFICATE-----
, a lot of
base64 encoded stuff, down to -----END CERTIFICATE-----
. A text
description may come before or after the boundary lines; it will be ignored.
The certificate files are named after their subject hashes. The naming is
unimportant, but you should import only one copy of each certificate; the
typical subject hash links used in OpenSSL will confuse the script and would
have to be excluded one way or another, if present.
To display a certificate:
openssl x509 -in cacerts/e4a7f639.0 -noout -text
To determine the subject hash (append .0 in the likely case of no duplicates):
openssl x509 -in example-com.pem -noout -subject_hash
You will find ./cacerts.bks
which is the pre-built
certificate store. It will end up as
/system/etc/security/cacerts.bks
and is bit-for-bit identical to
this file (before hacking). The scripts assume that this file may be removed
at the start, being created anew by keytool.
You will also find ./certimport.sh
which is a wrapper that
calls keytool. However, the needed JAR
file is not present and some of the other pathnames and options do not seem to
be functional. Likely this is the script that one of the real
developers used, at some time in the past, to create
./cacerts.bks
. We're going to need to update this script.
The attached file
is the updated script.
It wants on the command line the names of the keystore file and of the
certificates to put in it; if a directory is found all the files in it are
added. For the Android source situation call it like this (assuming the script
and the JAR file were deposited in
the current directory):
certimportJ
./certimportJ cacerts.bks cacerts
The key item in this script is that it calls keytool with the following
parameters for each certificate. Bash syntax is used to pipe the output of
openssl into keytool. Each parameter is shown on a separate line to make it
more readable. In the filenames I am assuming that the script is executed in
the
directory.
files
COUNTER=0
keytool \
-importcert \
-v \
-noprompt \
-trustcacerts \
-alias cert$((COUNTER++)) \
-file <(openssl x509 -in $cert -outform DER) \
-keystore ./cacerts.bks \
-storetype BKS \
-storepass SillyNoKeysHere \
-provider org.bouncycastle.jce.provider.BouncyCastleProvider \
-providerpath $PWD/bcprov-jdk16-143.jar
Notes on the parameters:
$certrepresents the filename of the PEM format certificate.
Now you have a keystore file that includes your root certificate. Here is how to get it onto your phone.
adb push ./cacerts.bks /sdcard/cacerts.bks
adb shell
su root
/system
partition in read-write mode. It
should be sufficient to do (on the host system) adb
remount
, but I'm getting a permission problem, so here is
how to do it by hand. cat /proc/mounts
; look for
/dev/block/mtdblock3 /system yaffs2 ro 0 0
(in the unlikely
event of future alterations to the partitioning, adjust
the following mount command to match what's actually in
/proc/mounts
).
mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system
cat /proc/mounts
again and make sure /system
now has
the rwoption.
cd /system/etc/security
ls -l
; you should see cacerts.bks
,
mode 644, owner root:root. If you're not too familiar with
UNIX, the mode code will be shown as -rw-r--r--.
mv cacerts.bks cacerts.bks.orig
; you're saving
the original keystore in case of problems. Of course, skip this step
if you've already saved the original version.
cp(copy) command? Use whichever of these command lines is going to work for you, to bring in the new keystore from where you left it on the SD card. Note the dot representing the current directory, as the destination of
cp.
cp /sdcard/cacerts.bks .
dd if=/sdcard/cacerts.bks of=./cacerts.bks
chmod 644 cacerts.bks
; the file's mode comes out
wrong, most likely because the shell's umask is not set, and you need
to fix it. Afterward do ls -l
and compare to the
result seen previously.
/system
read-only by
repeating the above remount steps interchanging roand
rw, but you're just going to reboot your phone, so don't bother.
exittwice) and disconnect the USB cable.
Now you should be able to connect to your SSL/TLS servers without being hassled about certificates issued by an untrusted origin of trust.
This issue has been posted on Android's bug system as issue 3237. It has been merged into an earlier similar thread, Android bug 1016.
Apps | Hardware | Setup | Network | Hacking | Wishlist | Top |