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