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