1 /* 2 * Copyright (C) 2017 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.server.wifi.hotspot2; 18 19 import android.net.wifi.hotspot2.PasspointConfiguration; 20 import android.text.TextUtils; 21 22 import com.android.internal.util.XmlUtils; 23 import com.android.server.wifi.SIMAccessor; 24 import com.android.server.wifi.WifiConfigStore; 25 import com.android.server.wifi.WifiKeyStore; 26 import com.android.server.wifi.util.XmlUtil; 27 28 import org.xmlpull.v1.XmlPullParser; 29 import org.xmlpull.v1.XmlPullParserException; 30 import org.xmlpull.v1.XmlSerializer; 31 32 import java.io.IOException; 33 import java.util.ArrayList; 34 import java.util.List; 35 36 /** 37 * Responsible for Passpoint specific configuration store data. There are two types of 38 * configuration data, system wide and user specific. The system wide configurations are stored 39 * in the share store and user specific configurations are store in the user store. 40 * 41 * Below are the current configuration data for each respective store file, the list will 42 * probably grow in the future. 43 * 44 * Share Store (system wide configurations) 45 * - Current provider index - use for assigning provider ID during provider creation, to make 46 * sure each provider will have an unique ID across all users. 47 * 48 * User Store (user specific configurations) 49 * - Provider list - list of Passpoint provider configurations 50 * 51 */ 52 public class PasspointConfigStoreData implements WifiConfigStore.StoreData { 53 private static final String XML_TAG_SECTION_HEADER_PASSPOINT_CONFIG_DATA = 54 "PasspointConfigData"; 55 private static final String XML_TAG_SECTION_HEADER_PASSPOINT_PROVIDER_LIST = 56 "ProviderList"; 57 private static final String XML_TAG_SECTION_HEADER_PASSPOINT_PROVIDER = 58 "Provider"; 59 private static final String XML_TAG_SECTION_HEADER_PASSPOINT_CONFIGURATION = 60 "Configuration"; 61 62 private static final String XML_TAG_PROVIDER_ID = "ProviderID"; 63 private static final String XML_TAG_CREATOR_UID = "CreatorUID"; 64 private static final String XML_TAG_CA_CERTIFICATE_ALIAS = "CaCertificateAlias"; 65 private static final String XML_TAG_CLIENT_CERTIFICATE_ALIAS = "ClientCertificateAlias"; 66 private static final String XML_TAG_CLIENT_PRIVATE_KEY_ALIAS = "ClientPrivateKeyAlias"; 67 68 private static final String XML_TAG_PROVIDER_INDEX = "ProviderIndex"; 69 70 private final WifiKeyStore mKeyStore; 71 private final SIMAccessor mSimAccessor; 72 private final DataSource mDataSource; 73 74 /** 75 * Interface define the data source for the Passpoint configuration store data. 76 */ 77 public interface DataSource { 78 /** 79 * Retrieve the provider list from the data source. 80 * 81 * @return List of {@link PasspointProvider} 82 */ 83 List<PasspointProvider> getProviders(); 84 85 /** 86 * Set the provider list in the data source. 87 * 88 * @param providers The list of providers 89 */ 90 void setProviders(List<PasspointProvider> providers); 91 92 /** 93 * Retrieve the current provider index. 94 * 95 * @return long 96 */ 97 long getProviderIndex(); 98 99 /** 100 * Set the current provider index. 101 * 102 * @param providerIndex The provider index used for provider creation 103 */ 104 void setProviderIndex(long providerIndex); 105 } 106 107 PasspointConfigStoreData(WifiKeyStore keyStore, SIMAccessor simAccessor, 108 DataSource dataSource) { 109 mKeyStore = keyStore; 110 mSimAccessor = simAccessor; 111 mDataSource = dataSource; 112 } 113 114 @Override 115 public void serializeData(XmlSerializer out, boolean shared) 116 throws XmlPullParserException, IOException { 117 if (shared) { 118 serializeShareData(out); 119 } else { 120 serializeUserData(out); 121 } 122 } 123 124 @Override 125 public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared) 126 throws XmlPullParserException, IOException { 127 if (shared) { 128 deserializeShareData(in, outerTagDepth); 129 } else { 130 deserializeUserData(in, outerTagDepth); 131 } 132 } 133 134 @Override 135 public void resetData(boolean shared) { 136 if (shared) { 137 resetShareData(); 138 } else { 139 resetUserData(); 140 } 141 } 142 143 @Override 144 public String getName() { 145 return XML_TAG_SECTION_HEADER_PASSPOINT_CONFIG_DATA; 146 } 147 148 @Override 149 public boolean supportShareData() { 150 return true; 151 } 152 153 /** 154 * Serialize share data (system wide Passpoint configurations) to a XML block. 155 * 156 * @param out The output stream to serialize data to 157 * @throws XmlPullParserException 158 * @throws IOException 159 */ 160 private void serializeShareData(XmlSerializer out) throws XmlPullParserException, IOException { 161 XmlUtil.writeNextValue(out, XML_TAG_PROVIDER_INDEX, mDataSource.getProviderIndex()); 162 } 163 164 /** 165 * Serialize user data (user specific Passpoint configurations) to a XML block. 166 * 167 * @param out The output stream to serialize data to 168 * @throws XmlPullParserException 169 * @throws IOException 170 */ 171 private void serializeUserData(XmlSerializer out) throws XmlPullParserException, IOException { 172 serializeProviderList(out, mDataSource.getProviders()); 173 } 174 175 /** 176 * Serialize the list of Passpoint providers from the data source to a XML block. 177 * 178 * @param out The output stream to serialize data to 179 * @param providerList The list of providers to serialize 180 * @throws XmlPullParserException 181 * @throws IOException 182 */ 183 private void serializeProviderList(XmlSerializer out, List<PasspointProvider> providerList) 184 throws XmlPullParserException, IOException { 185 if (providerList == null) { 186 return; 187 } 188 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_PASSPOINT_PROVIDER_LIST); 189 for (PasspointProvider provider : providerList) { 190 serializeProvider(out, provider); 191 } 192 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_PASSPOINT_PROVIDER_LIST); 193 } 194 195 /** 196 * Serialize a Passpoint provider to a XML block. 197 * 198 * @param out The output stream to serialize data to 199 * @param provider The provider to serialize 200 * @throws XmlPullParserException 201 * @throws IOException 202 */ 203 private void serializeProvider(XmlSerializer out, PasspointProvider provider) 204 throws XmlPullParserException, IOException { 205 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_PASSPOINT_PROVIDER); 206 XmlUtil.writeNextValue(out, XML_TAG_PROVIDER_ID, provider.getProviderId()); 207 XmlUtil.writeNextValue(out, XML_TAG_CREATOR_UID, provider.getCreatorUid()); 208 XmlUtil.writeNextValue(out, XML_TAG_CA_CERTIFICATE_ALIAS, 209 provider.getCaCertificateAlias()); 210 XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CERTIFICATE_ALIAS, 211 provider.getClientCertificateAlias()); 212 XmlUtil.writeNextValue(out, XML_TAG_CLIENT_PRIVATE_KEY_ALIAS, 213 provider.getClientPrivateKeyAlias()); 214 if (provider.getConfig() != null) { 215 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_PASSPOINT_CONFIGURATION); 216 PasspointXmlUtils.serializePasspointConfiguration(out, provider.getConfig()); 217 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_PASSPOINT_CONFIGURATION); 218 } 219 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_PASSPOINT_PROVIDER); 220 } 221 222 /** 223 * Deserialize share data (system wide Passpoint configurations) from the input stream. 224 * 225 * @param in The input stream to read data from 226 * @param outerTagDepth The tag depth of the current XML section 227 * @throws XmlPullParserException 228 * @throws IOException 229 */ 230 private void deserializeShareData(XmlPullParser in, int outerTagDepth) 231 throws XmlPullParserException, IOException { 232 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 233 String[] valueName = new String[1]; 234 Object value = XmlUtil.readCurrentValue(in, valueName); 235 if (valueName[0] == null) { 236 throw new XmlPullParserException("Missing value name"); 237 } 238 switch (valueName[0]) { 239 case XML_TAG_PROVIDER_INDEX: 240 mDataSource.setProviderIndex((long) value); 241 break; 242 default: 243 throw new XmlPullParserException("Unknown value under share store data " 244 + valueName[0]); 245 } 246 } 247 } 248 249 /** 250 * Deserialize user data (user specific Passpoint configurations) from the input stream. 251 * 252 * @param in The input stream to read data from 253 * @param outerTagDepth The tag depth of the current XML section 254 * @throws XmlPullParserException 255 * @throws IOException 256 */ 257 private void deserializeUserData(XmlPullParser in, int outerTagDepth) 258 throws XmlPullParserException, IOException { 259 String[] headerName = new String[1]; 260 while (XmlUtil.gotoNextSectionOrEnd(in, headerName, outerTagDepth)) { 261 switch (headerName[0]) { 262 case XML_TAG_SECTION_HEADER_PASSPOINT_PROVIDER_LIST: 263 mDataSource.setProviders(deserializeProviderList(in, outerTagDepth + 1)); 264 break; 265 default: 266 throw new XmlPullParserException("Unknown Passpoint user store data " 267 + headerName[0]); 268 } 269 } 270 } 271 272 /** 273 * Deserialize a list of Passpoint providers from the input stream. 274 * 275 * @param in The input stream to read data form 276 * @param outerTagDepth The tag depth of the current XML section 277 * @return List of {@link PasspointProvider} 278 * @throws XmlPullParserException 279 * @throws IOException 280 */ 281 private List<PasspointProvider> deserializeProviderList(XmlPullParser in, int outerTagDepth) 282 throws XmlPullParserException, IOException { 283 List<PasspointProvider> providerList = new ArrayList<>(); 284 while (XmlUtil.gotoNextSectionWithNameOrEnd(in, XML_TAG_SECTION_HEADER_PASSPOINT_PROVIDER, 285 outerTagDepth)) { 286 providerList.add(deserializeProvider(in, outerTagDepth + 1)); 287 } 288 return providerList; 289 } 290 291 /** 292 * Deserialize a Passpoint provider from the input stream. 293 * 294 * @param in The input stream to read data from 295 * @param outerTagDepth The tag depth of the current XML section 296 * @return {@link PasspointProvider} 297 * @throws XmlPullParserException 298 * @throws IOException 299 */ 300 private PasspointProvider deserializeProvider(XmlPullParser in, int outerTagDepth) 301 throws XmlPullParserException, IOException { 302 long providerId = Long.MIN_VALUE; 303 int creatorUid = Integer.MIN_VALUE; 304 String caCertificateAlias = null; 305 String clientCertificateAlias = null; 306 String clientPrivateKeyAlias = null; 307 PasspointConfiguration config = null; 308 while (XmlUtils.nextElementWithin(in, outerTagDepth)) { 309 if (in.getAttributeValue(null, "name") != null) { 310 // Value elements. 311 String[] name = new String[1]; 312 Object value = XmlUtil.readCurrentValue(in, name); 313 switch (name[0]) { 314 case XML_TAG_PROVIDER_ID: 315 providerId = (long) value; 316 break; 317 case XML_TAG_CREATOR_UID: 318 creatorUid = (int) value; 319 break; 320 case XML_TAG_CA_CERTIFICATE_ALIAS: 321 caCertificateAlias = (String) value; 322 break; 323 case XML_TAG_CLIENT_CERTIFICATE_ALIAS: 324 clientCertificateAlias = (String) value; 325 break; 326 case XML_TAG_CLIENT_PRIVATE_KEY_ALIAS: 327 clientPrivateKeyAlias = (String) value; 328 break; 329 } 330 } else { 331 if (!TextUtils.equals(in.getName(), 332 XML_TAG_SECTION_HEADER_PASSPOINT_CONFIGURATION)) { 333 throw new XmlPullParserException("Unexpected section under Provider: " 334 + in.getName()); 335 } 336 config = PasspointXmlUtils.deserializePasspointConfiguration(in, 337 outerTagDepth + 1); 338 } 339 } 340 if (providerId == Long.MIN_VALUE) { 341 throw new XmlPullParserException("Missing provider ID"); 342 } 343 if (config == null) { 344 throw new XmlPullParserException("Missing Passpoint configuration"); 345 } 346 return new PasspointProvider(config, mKeyStore, mSimAccessor, providerId, creatorUid, 347 caCertificateAlias, clientCertificateAlias, clientPrivateKeyAlias); 348 } 349 350 /** 351 * Reset share data (system wide Passpoint configurations). 352 */ 353 private void resetShareData() { 354 mDataSource.setProviderIndex(0); 355 } 356 357 /** 358 * Reset user data (user specific Passpoint configurations). 359 */ 360 private void resetUserData() { 361 mDataSource.setProviders(new ArrayList<PasspointProvider>()); 362 } 363 } 364 365