1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.certinstaller; 18 19 import android.content.Intent; 20 import android.os.Bundle; 21 import android.os.Environment; 22 import android.preference.PreferenceActivity; 23 import android.security.Credentials; 24 import android.security.KeyChain; 25 import android.util.Log; 26 import android.widget.Toast; 27 28 import java.io.File; 29 import java.io.FileFilter; 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.List; 33 34 /** 35 * Base class that deals with certificate files on the SD card. 36 */ 37 public class CertFile extends PreferenceActivity implements FileFilter { 38 static final int CERT_READ_ERROR = R.string.cert_read_error; 39 static final int CERT_TOO_LARGE_ERROR = R.string.cert_too_large_error; 40 static final int CERT_FILE_MISSING_ERROR = R.string.cert_missing_error; 41 42 static final String DOWNLOAD_DIR = "download"; 43 44 private static final String TAG = "CertFile"; 45 46 private static final String CERT_FILE_KEY = "cf"; 47 private static final int MAX_FILE_SIZE = 1000000; 48 protected static final int REQUEST_INSTALL_CODE = 1; 49 50 private File mCertFile; 51 52 @Override 53 protected void onSaveInstanceState(Bundle outStates) { 54 super.onSaveInstanceState(outStates); 55 if (mCertFile != null) { 56 outStates.putString(CERT_FILE_KEY, mCertFile.getAbsolutePath()); 57 } 58 } 59 60 @Override 61 protected void onRestoreInstanceState(Bundle savedStates) { 62 super.onRestoreInstanceState(savedStates); 63 String path = savedStates.getString(CERT_FILE_KEY); 64 if (path != null) { 65 mCertFile = new File(path); 66 } 67 } 68 69 @Override 70 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 71 if (requestCode == REQUEST_INSTALL_CODE) { 72 boolean success = (resultCode == RESULT_OK 73 && (mCertFile == null || Util.deleteFile(mCertFile))); 74 onInstallationDone(success); 75 mCertFile = null; 76 } else { 77 Log.w(TAG, "unknown request code: " + requestCode); 78 } 79 } 80 81 /** 82 * Called when installation is done. 83 * 84 * @param success true if installation is done successfully 85 */ 86 protected void onInstallationDone(boolean success) { 87 if (success) { 88 setResult(RESULT_OK); 89 } 90 } 91 92 /** 93 * Called when an error occurs when reading a certificate file. 94 * 95 * @param errorId one of {@link #CERT_READ_ERROR}, 96 * {@link #CERT_TOO_LARGE_ERROR} and {@link #CERT_FILE_MISSING_ERROR} 97 */ 98 protected void onError(int errorId) { 99 } 100 101 /** 102 * Returns a list of certificate files found on the SD card. 103 */ 104 protected List<File> getAllCertFiles() { 105 List<File> allFiles = new ArrayList<File>(); 106 File root = Environment.getExternalStorageDirectory(); 107 108 File download = new File(root, DOWNLOAD_DIR); 109 if (download != null) { 110 File[] files = download.listFiles(this); 111 if (files != null) { 112 Collections.addAll(allFiles, files); 113 } 114 } 115 116 File[] files = root.listFiles(this); 117 if (files != null) { 118 Collections.addAll(allFiles, files); 119 } 120 121 return allFiles; 122 } 123 124 /** 125 * Invokes {@link CertInstaller} to install the certificate(s) in the file. 126 * 127 * @param file the certificate file 128 */ 129 protected void installFromFile(File file) { 130 Log.d(TAG, "install cert from " + file); 131 132 String fileName = file.getName(); 133 Bundle bundle = getIntent().getExtras(); 134 String name = ((bundle == null) 135 ? fileName 136 : bundle.getString(KeyChain.EXTRA_NAME, fileName)); 137 if (file.exists()) { 138 if (file.length() < MAX_FILE_SIZE) { 139 byte[] data = Util.readFile(file); 140 if (data == null) { 141 toastError(CERT_READ_ERROR); 142 onError(CERT_READ_ERROR); 143 return; 144 } 145 mCertFile = file; 146 install(fileName, name, data); 147 } else { 148 Log.w(TAG, "cert file is too large: " + file.length()); 149 toastError(CERT_TOO_LARGE_ERROR); 150 onError(CERT_TOO_LARGE_ERROR); 151 } 152 } else { 153 Log.w(TAG, "cert file does not exist"); 154 toastError(CERT_FILE_MISSING_ERROR); 155 onError(CERT_FILE_MISSING_ERROR); 156 } 157 } 158 159 @Override public boolean accept(File file) { 160 if (!file.isDirectory()) { 161 return isFileAcceptable(file.getPath()); 162 } else { 163 return false; 164 } 165 } 166 167 protected boolean isFileAcceptable(String path) { 168 return (path.endsWith(Credentials.EXTENSION_CRT) || 169 path.endsWith(Credentials.EXTENSION_P12) || 170 path.endsWith(Credentials.EXTENSION_CER) || 171 path.endsWith(Credentials.EXTENSION_PFX)); 172 } 173 174 protected boolean isSdCardPresent() { 175 return Environment.getExternalStorageState().equals( 176 Environment.MEDIA_MOUNTED); 177 } 178 179 private void install(String fileName, String name, byte[] value) { 180 Intent intent = new Intent(this, CertInstaller.class); 181 intent.putExtra(KeyChain.EXTRA_NAME, name); 182 if (fileName.endsWith(Credentials.EXTENSION_PFX) 183 || fileName.endsWith(Credentials.EXTENSION_P12)) { 184 intent.putExtra(KeyChain.EXTRA_PKCS12, value); 185 } else if (fileName.endsWith(Credentials.EXTENSION_CER) 186 || fileName.endsWith(Credentials.EXTENSION_CRT)) { 187 intent.putExtra(KeyChain.EXTRA_CERTIFICATE, value); 188 } else { 189 throw new AssertionError(fileName); 190 } 191 startActivityForResult(intent, REQUEST_INSTALL_CODE); 192 } 193 194 private void toastError(int msgId) { 195 Toast.makeText(this, msgId, Toast.LENGTH_LONG).show(); 196 } 197 } 198