13e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan/* 23e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * Copyright (C) 2009 The Android Open Source Project 33e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * 43e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * Licensed under the Apache License, Version 2.0 (the "License"); 53e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * you may not use this file except in compliance with the License. 63e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * You may obtain a copy of the License at 73e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * 83e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * http://www.apache.org/licenses/LICENSE-2.0 93e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * 103e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * Unless required by applicable law or agreed to in writing, software 113e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * distributed under the License is distributed on an "AS IS" BASIS, 123e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * See the License for the specific language governing permissions and 143e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * limitations under the License. 153e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan */ 163e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 173e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanpackage com.android.certinstaller; 183e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 193e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport android.content.Intent; 203e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport android.os.Bundle; 213e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport android.os.Environment; 223e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport android.preference.PreferenceActivity; 233e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport android.security.Credentials; 2400736f76392c742e9c72c51f158ad7020f22524cBrian Carlstromimport android.security.KeyChain; 253e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport android.util.Log; 263e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport android.widget.Toast; 273e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 283e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport java.io.File; 293e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport java.io.FileFilter; 303e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport java.util.ArrayList; 313e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport java.util.Collections; 323e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanimport java.util.List; 333e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 343e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan/** 353e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * Base class that deals with certificate files on the SD card. 363e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan */ 373e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyanpublic class CertFile extends PreferenceActivity implements FileFilter { 383e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan static final int CERT_READ_ERROR = R.string.cert_read_error; 393e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan static final int CERT_TOO_LARGE_ERROR = R.string.cert_too_large_error; 403e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan static final int CERT_FILE_MISSING_ERROR = R.string.cert_missing_error; 413e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 423e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan static final String DOWNLOAD_DIR = "download"; 433e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 443e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan private static final String TAG = "CertFile"; 453e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 463e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan private static final String CERT_FILE_KEY = "cf"; 473e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan private static final int MAX_FILE_SIZE = 1000000; 4830389d0148993679892385e007596a56ed46b6acBrian Carlstrom protected static final int REQUEST_INSTALL_CODE = 1; 493e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 503e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan private File mCertFile; 513e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 523e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan @Override 533e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan protected void onSaveInstanceState(Bundle outStates) { 543e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan super.onSaveInstanceState(outStates); 553e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan if (mCertFile != null) { 563e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan outStates.putString(CERT_FILE_KEY, mCertFile.getAbsolutePath()); 573e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 583e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 593e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 603e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan @Override 613e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan protected void onRestoreInstanceState(Bundle savedStates) { 623e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan super.onRestoreInstanceState(savedStates); 633e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan String path = savedStates.getString(CERT_FILE_KEY); 6430389d0148993679892385e007596a56ed46b6acBrian Carlstrom if (path != null) { 6530389d0148993679892385e007596a56ed46b6acBrian Carlstrom mCertFile = new File(path); 6630389d0148993679892385e007596a56ed46b6acBrian Carlstrom } 673e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 683e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 693e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan @Override 703e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan protected void onActivityResult(int requestCode, int resultCode, Intent data) { 713e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan if (requestCode == REQUEST_INSTALL_CODE) { 7230389d0148993679892385e007596a56ed46b6acBrian Carlstrom boolean success = (resultCode == RESULT_OK 73a921a7f6b86e2564f70e841c0b10b368f6b8d495Brian Carlstrom && (mCertFile == null || Util.deleteFile(mCertFile))); 7430389d0148993679892385e007596a56ed46b6acBrian Carlstrom onInstallationDone(success); 753e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan mCertFile = null; 763e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } else { 773e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan Log.w(TAG, "unknown request code: " + requestCode); 783e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 793e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 803e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 813e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan /** 823e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * Called when installation is done. 833e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * 843e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * @param success true if installation is done successfully 853e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan */ 863e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan protected void onInstallationDone(boolean success) { 8730389d0148993679892385e007596a56ed46b6acBrian Carlstrom if (success) { 8830389d0148993679892385e007596a56ed46b6acBrian Carlstrom setResult(RESULT_OK); 8930389d0148993679892385e007596a56ed46b6acBrian Carlstrom } 903e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 913e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 923e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan /** 933e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * Called when an error occurs when reading a certificate file. 943e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * 953e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * @param errorId one of {@link #CERT_READ_ERROR}, 963e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * {@link #CERT_TOO_LARGE_ERROR} and {@link #CERT_FILE_MISSING_ERROR} 973e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan */ 983e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan protected void onError(int errorId) { 993e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 1003e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 1013e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan /** 1023e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * Returns a list of certificate files found on the SD card. 1033e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan */ 1043e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan protected List<File> getAllCertFiles() { 1053e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan List<File> allFiles = new ArrayList<File>(); 1063e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan File root = Environment.getExternalStorageDirectory(); 107832878cac1a136b1952de51cc2417d4e18188403Hung-ying Tyan 1083e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan File download = new File(root, DOWNLOAD_DIR); 109832878cac1a136b1952de51cc2417d4e18188403Hung-ying Tyan if (download != null) { 110832878cac1a136b1952de51cc2417d4e18188403Hung-ying Tyan File[] files = download.listFiles(this); 111a921a7f6b86e2564f70e841c0b10b368f6b8d495Brian Carlstrom if (files != null) { 112a921a7f6b86e2564f70e841c0b10b368f6b8d495Brian Carlstrom Collections.addAll(allFiles, files); 113a921a7f6b86e2564f70e841c0b10b368f6b8d495Brian Carlstrom } 114832878cac1a136b1952de51cc2417d4e18188403Hung-ying Tyan } 115832878cac1a136b1952de51cc2417d4e18188403Hung-ying Tyan 116832878cac1a136b1952de51cc2417d4e18188403Hung-ying Tyan File[] files = root.listFiles(this); 117a921a7f6b86e2564f70e841c0b10b368f6b8d495Brian Carlstrom if (files != null) { 118a921a7f6b86e2564f70e841c0b10b368f6b8d495Brian Carlstrom Collections.addAll(allFiles, files); 119a921a7f6b86e2564f70e841c0b10b368f6b8d495Brian Carlstrom } 120832878cac1a136b1952de51cc2417d4e18188403Hung-ying Tyan 1213e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan return allFiles; 1223e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 1233e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 1243e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan /** 1253e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * Invokes {@link CertInstaller} to install the certificate(s) in the file. 1263e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * 1273e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan * @param file the certificate file 1283e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan */ 1293e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan protected void installFromFile(File file) { 1303e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan Log.d(TAG, "install cert from " + file); 1313e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 132f4616bf8c0b3bff8863d627c3c003fa9234cb225Brian Carlstrom String fileName = file.getName(); 133f4616bf8c0b3bff8863d627c3c003fa9234cb225Brian Carlstrom Bundle bundle = getIntent().getExtras(); 134f4616bf8c0b3bff8863d627c3c003fa9234cb225Brian Carlstrom String name = ((bundle == null) 135f4616bf8c0b3bff8863d627c3c003fa9234cb225Brian Carlstrom ? fileName 136f4616bf8c0b3bff8863d627c3c003fa9234cb225Brian Carlstrom : bundle.getString(KeyChain.EXTRA_NAME, fileName)); 1373e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan if (file.exists()) { 1383e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan if (file.length() < MAX_FILE_SIZE) { 1393e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan byte[] data = Util.readFile(file); 1403e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan if (data == null) { 1413e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan toastError(CERT_READ_ERROR); 1423e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan onError(CERT_READ_ERROR); 1433e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan return; 1443e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 1453e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan mCertFile = file; 146f4616bf8c0b3bff8863d627c3c003fa9234cb225Brian Carlstrom install(fileName, name, data); 1473e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } else { 1483e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan Log.w(TAG, "cert file is too large: " + file.length()); 1493e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan toastError(CERT_TOO_LARGE_ERROR); 1503e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan onError(CERT_TOO_LARGE_ERROR); 1513e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 1523e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } else { 1533e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan Log.w(TAG, "cert file does not exist"); 1543e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan toastError(CERT_FILE_MISSING_ERROR); 1553e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan onError(CERT_FILE_MISSING_ERROR); 1563e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 1573e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 1583e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 159a921a7f6b86e2564f70e841c0b10b368f6b8d495Brian Carlstrom @Override public boolean accept(File file) { 1603e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan if (!file.isDirectory()) { 1617b4cee910e1e755d2f0468a5f79aaa97e926a3a9Hung-ying Tyan return isFileAcceptable(file.getPath()); 1623e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } else { 1633e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan return false; 1643e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 1653e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 1663e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 1677b4cee910e1e755d2f0468a5f79aaa97e926a3a9Hung-ying Tyan protected boolean isFileAcceptable(String path) { 168fcd5fb26acec88e98c3bedb41d4510888f7890cdBrian Carlstrom return (path.endsWith(Credentials.EXTENSION_CRT) || 169fcd5fb26acec88e98c3bedb41d4510888f7890cdBrian Carlstrom path.endsWith(Credentials.EXTENSION_P12) || 170fcd5fb26acec88e98c3bedb41d4510888f7890cdBrian Carlstrom path.endsWith(Credentials.EXTENSION_CER) || 171fcd5fb26acec88e98c3bedb41d4510888f7890cdBrian Carlstrom path.endsWith(Credentials.EXTENSION_PFX)); 1727b4cee910e1e755d2f0468a5f79aaa97e926a3a9Hung-ying Tyan } 1737b4cee910e1e755d2f0468a5f79aaa97e926a3a9Hung-ying Tyan 174d674440a49f278793aa2a2bb01c231f8cea7f8c0Hung-ying Tyan protected boolean isSdCardPresent() { 175d674440a49f278793aa2a2bb01c231f8cea7f8c0Hung-ying Tyan return Environment.getExternalStorageState().equals( 176d674440a49f278793aa2a2bb01c231f8cea7f8c0Hung-ying Tyan Environment.MEDIA_MOUNTED); 177d674440a49f278793aa2a2bb01c231f8cea7f8c0Hung-ying Tyan } 178d674440a49f278793aa2a2bb01c231f8cea7f8c0Hung-ying Tyan 179f4616bf8c0b3bff8863d627c3c003fa9234cb225Brian Carlstrom private void install(String fileName, String name, byte[] value) { 1803e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan Intent intent = new Intent(this, CertInstaller.class); 181f4616bf8c0b3bff8863d627c3c003fa9234cb225Brian Carlstrom intent.putExtra(KeyChain.EXTRA_NAME, name); 182fcd5fb26acec88e98c3bedb41d4510888f7890cdBrian Carlstrom if (fileName.endsWith(Credentials.EXTENSION_PFX) 183fcd5fb26acec88e98c3bedb41d4510888f7890cdBrian Carlstrom || fileName.endsWith(Credentials.EXTENSION_P12)) { 18400736f76392c742e9c72c51f158ad7020f22524cBrian Carlstrom intent.putExtra(KeyChain.EXTRA_PKCS12, value); 185fcd5fb26acec88e98c3bedb41d4510888f7890cdBrian Carlstrom } else if (fileName.endsWith(Credentials.EXTENSION_CER) 186fcd5fb26acec88e98c3bedb41d4510888f7890cdBrian Carlstrom || fileName.endsWith(Credentials.EXTENSION_CRT)) { 18700736f76392c742e9c72c51f158ad7020f22524cBrian Carlstrom intent.putExtra(KeyChain.EXTRA_CERTIFICATE, value); 188f3ece3c05b05b6780d9bee0dd90de0df891207e0Brian Carlstrom } else { 189f3ece3c05b05b6780d9bee0dd90de0df891207e0Brian Carlstrom throw new AssertionError(fileName); 1907b4cee910e1e755d2f0468a5f79aaa97e926a3a9Hung-ying Tyan } 1913e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan startActivityForResult(intent, REQUEST_INSTALL_CODE); 1923e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 1933e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan 1943e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan private void toastError(int msgId) { 1953e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan Toast.makeText(this, msgId, Toast.LENGTH_LONG).show(); 1963e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan } 1973e722cadf66802194267460fe5de77e6c18530ebHung-ying Tyan} 198