WifiCertManager.java revision 2bfc67c9893c0a525b224d68dd73a74212b0c29f
1/* 2 * Copyright (C) 2015 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 17package com.android.server.wifi; 18 19import android.app.admin.IDevicePolicyManager; 20import android.content.Context; 21import android.os.Environment; 22import android.os.ServiceManager; 23import android.os.UserHandle; 24import android.security.Credentials; 25import android.security.KeyStore; 26import android.text.TextUtils; 27import android.util.Log; 28 29import com.android.server.net.DelayedDiskWrite; 30 31import java.io.DataInputStream; 32import java.io.DataOutputStream; 33import java.io.File; 34import java.io.FileInputStream; 35import java.io.IOException; 36import java.nio.charset.StandardCharsets; 37import java.util.Arrays; 38import java.util.HashSet; 39import java.util.Set; 40 41/** 42 * Manager class for affiliated Wifi certificates. 43 */ 44public class WifiCertManager { 45 private static final String TAG = "WifiCertManager"; 46 private static final String SEP = "\n"; 47 48 private final Context mContext; 49 private Set<String> mAffiliatedUserOnlyCerts = new HashSet<String>(); 50 51 private static final String CONFIG_FILE = 52 Environment.getDataDirectory() + "/misc/wifi/affiliatedcerts.txt"; 53 54 private final DelayedDiskWrite mWriter = new DelayedDiskWrite(); 55 56 57 WifiCertManager(Context context) { 58 mContext = context; 59 final byte[] bytes = readConfigFile(); 60 if (bytes == null) { 61 // Config file does not exist or empty. 62 return; 63 } 64 65 String[] keys = new String(bytes, StandardCharsets.UTF_8).split(SEP); 66 for (String key : keys) { 67 mAffiliatedUserOnlyCerts.add(key); 68 } 69 70 // Remove keys that no longer exist in KeyStore. 71 if (mAffiliatedUserOnlyCerts.retainAll(Arrays.asList(listClientCertsForAllUsers()))) { 72 writeConfig(); 73 } 74 } 75 76 /** @param key Unprefixed cert key to hide from unaffiliated users. */ 77 public void hideCertFromUnaffiliatedUsers(String key) { 78 if (mAffiliatedUserOnlyCerts.add(Credentials.USER_PRIVATE_KEY + key)) { 79 writeConfig(); 80 } 81 } 82 83 /** @return Prefixed cert keys that are visible to the current user. */ 84 public String[] listClientCertsForCurrentUser() { 85 HashSet<String> results = new HashSet<String>(); 86 87 String[] keys = listClientCertsForAllUsers(); 88 if (isAffiliatedUser()) { 89 return keys; 90 } 91 92 for (String key : keys) { 93 if (!mAffiliatedUserOnlyCerts.contains(key)) { 94 results.add(key); 95 } 96 } 97 return results.toArray(new String[results.size()]); 98 } 99 100 private void writeConfig() { 101 String[] values = 102 mAffiliatedUserOnlyCerts.toArray(new String[mAffiliatedUserOnlyCerts.size()]); 103 String value = TextUtils.join(SEP, values); 104 writeConfigFile(value.getBytes(StandardCharsets.UTF_8)); 105 } 106 107 protected byte[] readConfigFile() { 108 byte[] bytes = null; 109 try { 110 final File file = new File(CONFIG_FILE); 111 final long fileSize = file.exists() ? file.length() : 0; 112 if (fileSize == 0 || fileSize >= Integer.MAX_VALUE) { 113 // Config file is empty/corrupted/non-existing. 114 return bytes; 115 } 116 117 bytes = new byte[(int) file.length()]; 118 final DataInputStream stream = new DataInputStream(new FileInputStream(file)); 119 stream.readFully(bytes); 120 } catch (IOException e) { 121 Log.e(TAG, "readConfigFile: failed to read " + e, e); 122 } finally { 123 return bytes; 124 } 125 } 126 127 protected void writeConfigFile(byte[] payload) { 128 final byte[] data = payload; 129 mWriter.write(CONFIG_FILE, new DelayedDiskWrite.Writer() { 130 public void onWriteCalled(DataOutputStream out) throws IOException { 131 out.write(data, 0, data.length); 132 } 133 }); 134 } 135 136 protected String[] listClientCertsForAllUsers() { 137 return KeyStore.getInstance().list(Credentials.USER_PRIVATE_KEY, UserHandle.myUserId()); 138 } 139 140 protected boolean isAffiliatedUser() { 141 IDevicePolicyManager pm = IDevicePolicyManager.Stub.asInterface( 142 ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)); 143 boolean result = false; 144 try { 145 result = pm.isAffiliatedUser(); 146 } catch (Exception e) { 147 Log.e(TAG, "failed to check user affiliation", e); 148 } 149 return result; 150 } 151} 152