Home | History | Annotate | Download | only in certinstaller
      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