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.net.Uri;
     21 import android.os.Bundle;
     22 import android.preference.PreferenceActivity;
     23 import android.provider.DocumentsContract;
     24 import android.security.Credentials;
     25 import android.security.KeyChain;
     26 import android.util.Log;
     27 import android.widget.Toast;
     28 
     29 import libcore.io.IoUtils;
     30 import libcore.io.Streams;
     31 
     32 import java.io.IOException;
     33 import java.io.InputStream;
     34 
     35 /**
     36  * The main class for installing certificates to the system keystore. It reacts
     37  * to the public {@link Credentials#INSTALL_ACTION} intent.
     38  */
     39 public class CertInstallerMain extends PreferenceActivity {
     40     private static final String TAG = "CertInstaller";
     41 
     42     private static final int REQUEST_INSTALL = 1;
     43     private static final int REQUEST_OPEN_DOCUMENT = 2;
     44 
     45     private static final String[] ACCEPT_MIME_TYPES = {
     46             "application/x-pkcs12",
     47             "application/x-x509-ca-cert",
     48             "application/x-x509-user-cert",
     49             "application/x-x509-server-cert",
     50             "application/x-pem-file",
     51             "application/pkix-cert"
     52     };
     53 
     54     @Override
     55     protected void onCreate(Bundle savedInstanceState) {
     56         super.onCreate(savedInstanceState);
     57 
     58         setResult(RESULT_CANCELED);
     59 
     60         final Intent intent = getIntent();
     61         final String action = intent.getAction();
     62 
     63         if (Credentials.INSTALL_ACTION.equals(action)
     64                 || Credentials.INSTALL_AS_USER_ACTION.equals(action)) {
     65             Bundle bundle = intent.getExtras();
     66 
     67             /*
     68              * There is a special INSTALL_AS_USER action that this activity is
     69              * aliased to, but you have to have a permission to call it. If the
     70              * caller got here any other way, remove the extra that we allow in
     71              * that INSTALL_AS_USER path.
     72              */
     73             if (bundle != null && !Credentials.INSTALL_AS_USER_ACTION.equals(action)) {
     74                 bundle.remove(Credentials.EXTRA_INSTALL_AS_UID);
     75             }
     76 
     77             // If bundle is empty of any actual credentials, ask user to open.
     78             // Otherwise, pass extras to CertInstaller to install those credentials.
     79             // Either way, we use KeyChain.EXTRA_NAME as the default name if available.
     80             if (bundle == null
     81                     || bundle.isEmpty()
     82                     || (bundle.size() == 1
     83                         && (bundle.containsKey(KeyChain.EXTRA_NAME)
     84                             || bundle.containsKey(Credentials.EXTRA_INSTALL_AS_UID)))) {
     85                 final Intent openIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
     86                 openIntent.setType("*/*");
     87                 openIntent.putExtra(Intent.EXTRA_MIME_TYPES, ACCEPT_MIME_TYPES);
     88                 openIntent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, true);
     89                 startActivityForResult(openIntent, REQUEST_OPEN_DOCUMENT);
     90             } else {
     91                 final Intent installIntent = new Intent(this, CertInstaller.class);
     92                 installIntent.putExtras(intent);
     93                 startActivityForResult(installIntent, REQUEST_INSTALL);
     94             }
     95         } else if (Intent.ACTION_VIEW.equals(action)) {
     96             startInstallActivity(intent.getType(), intent.getData());
     97         }
     98     }
     99 
    100     private void startInstallActivity(String mimeType, Uri uri) {
    101         if (mimeType == null) {
    102             mimeType = getContentResolver().getType(uri);
    103         }
    104 
    105         InputStream in = null;
    106         try {
    107             in = getContentResolver().openInputStream(uri);
    108 
    109             final byte[] raw = Streams.readFully(in);
    110             startInstallActivity(mimeType, raw);
    111 
    112         } catch (IOException e) {
    113             Log.e(TAG, "Failed to read certificate: " + e);
    114             Toast.makeText(this, R.string.cert_read_error, Toast.LENGTH_LONG).show();
    115         } finally {
    116             IoUtils.closeQuietly(in);
    117         }
    118     }
    119 
    120     private void startInstallActivity(String mimeType, byte[] value) {
    121         Intent intent = new Intent(this, CertInstaller.class);
    122         if ("application/x-pkcs12".equals(mimeType)) {
    123             intent.putExtra(KeyChain.EXTRA_PKCS12, value);
    124         } else if ("application/x-x509-ca-cert".equals(mimeType)
    125                 || "application/x-x509-user-cert".equals(mimeType)
    126                 || "application/x-x509-server-cert".equals(mimeType)
    127                 || "application/x-pem-file".equals(mimeType)
    128                 || "application/pkix-cert".equals(mimeType)) {
    129             intent.putExtra(KeyChain.EXTRA_CERTIFICATE, value);
    130         } else {
    131             throw new IllegalArgumentException("Unknown MIME type: " + mimeType);
    132         }
    133 
    134         startActivityForResult(intent, REQUEST_INSTALL);
    135     }
    136 
    137     @Override
    138     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    139         if (requestCode == REQUEST_OPEN_DOCUMENT) {
    140             if (resultCode == RESULT_OK) {
    141                 startInstallActivity(null, data.getData());
    142             } else {
    143                 finish();
    144             }
    145         } else if (requestCode == REQUEST_INSTALL) {
    146             setResult(resultCode);
    147             finish();
    148         } else {
    149             Log.w(TAG, "unknown request code: " + requestCode);
    150         }
    151     }
    152 }
    153