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 if (file.exists()) { 133 if (file.length() < MAX_FILE_SIZE) { 134 byte[] data = Util.readFile(file); 135 if (data == null) { 136 toastError(CERT_READ_ERROR); 137 onError(CERT_READ_ERROR); 138 return; 139 } 140 mCertFile = file; 141 install(file.getName(), data); 142 } else { 143 Log.w(TAG, "cert file is too large: " + file.length()); 144 toastError(CERT_TOO_LARGE_ERROR); 145 onError(CERT_TOO_LARGE_ERROR); 146 } 147 } else { 148 Log.w(TAG, "cert file does not exist"); 149 toastError(CERT_FILE_MISSING_ERROR); 150 onError(CERT_FILE_MISSING_ERROR); 151 } 152 } 153 154 @Override public boolean accept(File file) { 155 if (!file.isDirectory()) { 156 return isFileAcceptable(file.getPath()); 157 } else { 158 return false; 159 } 160 } 161 162 protected boolean isFileAcceptable(String path) { 163 return (path.endsWith(Credentials.EXTENSION_CRT) || 164 path.endsWith(Credentials.EXTENSION_P12) || 165 path.endsWith(Credentials.EXTENSION_CER) || 166 path.endsWith(Credentials.EXTENSION_PFX)); 167 } 168 169 protected boolean isSdCardPresent() { 170 return Environment.getExternalStorageState().equals( 171 Environment.MEDIA_MOUNTED); 172 } 173 174 private void install(String fileName, byte[] value) { 175 Intent intent = new Intent(this, CertInstaller.class); 176 intent.putExtra(CredentialHelper.CERT_NAME_KEY, fileName); 177 if (fileName.endsWith(Credentials.EXTENSION_PFX) 178 || fileName.endsWith(Credentials.EXTENSION_P12)) { 179 intent.putExtra(KeyChain.EXTRA_PKCS12, value); 180 } else if (fileName.endsWith(Credentials.EXTENSION_CER) 181 || fileName.endsWith(Credentials.EXTENSION_CRT)) { 182 intent.putExtra(KeyChain.EXTRA_CERTIFICATE, value); 183 } else { 184 throw new AssertionError(fileName); 185 } 186 startActivityForResult(intent, REQUEST_INSTALL_CODE); 187 } 188 189 private void toastError(int msgId) { 190 Toast.makeText(this, msgId, Toast.LENGTH_LONG).show(); 191 } 192 } 193