1 /* 2 * Copyright (C) 2018 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.omadm; 18 19 import android.annotation.NonNull; 20 import android.content.Context; 21 import android.net.wifi.EAPConstants; 22 import android.telephony.SubscriptionManager; 23 import android.telephony.TelephonyManager; 24 import android.text.TextUtils; 25 import android.util.Log; 26 import android.util.Pair; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.server.wifi.hotspot2.SystemInfo; 30 31 import org.w3c.dom.Document; 32 import org.w3c.dom.Element; 33 34 import java.util.ArrayList; 35 import java.util.List; 36 37 import javax.xml.parsers.ParserConfigurationException; 38 39 /** 40 * Provides serialization API for DevDetail MO (Management Object). 41 */ 42 public class DevDetailMo { 43 private static final String TAG = "DevDetailMo"; 44 // Refer to 9.2 DevDetail MO vendor specific extensions 45 // in the Hotspot2.0 R2 Technical Specification document in detail 46 @VisibleForTesting 47 public static final String URN = "urn:oma:mo:oma-dm-devdetail:1.0"; 48 @VisibleForTesting 49 public static final String HS20_URN = "urn:wfa:mo-ext:hotspot2dot0-devdetail-ext:1.0"; 50 51 private static final String MO_NAME = "DevDetail"; 52 53 private static final String TAG_EXT = "ext"; 54 private static final String TAG_ORG_WIFI = "org.wi-fi"; 55 private static final String TAG_WIFI = "Wi-Fi"; 56 private static final String TAG_EAP_METHOD_LIST = "EAPMethodList"; //Required field 57 private static final String TAG_EAP_METHOD = "EAPMethod"; //Required field 58 private static final String TAG_EAP_TYPE = "EAPType"; //Required field 59 private static final String TAG_VENDOR_ID = "VendorId"; 60 private static final String TAG_VENDOR_TYPE = "VendorType"; 61 private static final String TAG_INNER_EAP_TYPE = "InnerEAPType"; 62 private static final String TAG_INNER_VENDOR_ID = "InnerVendorID"; 63 private static final String TAG_INNER_VENDOR_TYPE = "InnerVendorType"; 64 private static final String TAG_INNER_METHOD = "InnerMethod"; //Required field 65 66 // Mobile device information related to certificates provisioned by SPs 67 private static final String TAG_SP_CERTIFICATE = "SPCertificate"; 68 private static final String TAG_CERTIFICATE_ISSUER_NAME = "CertificateIssuerName"; 69 70 // Required if the mobile device is in possession of an IEEE 802.1ar-compliant 71 // manufacturing certificate and is authorized to use that certificate for 72 // mobile device AAA authentication 73 private static final String TAG_MANUFACTURING_CERT = "ManufacturingCertificate"; 74 // Required for a device having a SIM, but will not provide the IMSI to an SP that 75 // did not issue the IMSI. 76 private static final String TAG_IMSI = "IMSI"; 77 // Required for the device having a SIM. 78 private static final String TAG_IMEI_MEID = "IMEI_MEID"; 79 80 private static final String TAG_WIFI_MAC_ADDR = "Wi-FiMACAddress"; // Required field 81 82 // Required field 83 private static final String TAG_CLIENT_TRIGGER_REDIRECT_URI = "ClientTriggerRedirectURI"; 84 85 private static final String TAG_OPS = "Ops"; 86 private static final String TAG_LAUNCH_BROWSER_TO_URI = "launchBrowserToURI"; 87 private static final String TAG_NEGOTIATE_CLIENT_CERT_TLS = "negotiateClientCertTLS"; 88 private static final String TAG_GET_CERTIFICATE = "getCertificate"; 89 90 private static final List<String> sSupportedOps = new ArrayList<>(); 91 private static final String TAG_URI = "URI"; 92 private static final String TAG_MAX_DEPTH = "MaxDepth"; 93 private static final String TAG_MAX_TOT_LEN = "MaxTotLen"; 94 private static final String TAG_MAX_SEG_LEN = "MaxSegLen"; 95 private static final String TAG_OEM = "OEM"; 96 private static final String TAG_SW_VER = "SwV"; 97 private static final String TAG_LRG_ORJ = "LrgOrj"; 98 99 private static final String INNER_METHOD_PAP = "PAP"; 100 private static final String INNER_METHOD_MS_CHAP = "MS-CHAP"; 101 private static final String INNER_METHOD_MS_CHAP_V2 = "MS-CHAP-V2"; 102 103 private static final String IFNAME = "wlan0"; 104 105 private static final List<Pair<Integer, String>> sEapMethods = new ArrayList<>(); 106 static { Pair.create(EAPConstants.EAP_TTLS, INNER_METHOD_MS_CHAP_V2)107 sEapMethods.add(Pair.create(EAPConstants.EAP_TTLS, INNER_METHOD_MS_CHAP_V2)); Pair.create(EAPConstants.EAP_TTLS, INNER_METHOD_MS_CHAP)108 sEapMethods.add(Pair.create(EAPConstants.EAP_TTLS, INNER_METHOD_MS_CHAP)); Pair.create(EAPConstants.EAP_TTLS, INNER_METHOD_PAP)109 sEapMethods.add(Pair.create(EAPConstants.EAP_TTLS, INNER_METHOD_PAP)); 110 Pair.create(EAPConstants.EAP_TLS, null)111 sEapMethods.add(Pair.create(EAPConstants.EAP_TLS, null)); Pair.create(EAPConstants.EAP_SIM, null)112 sEapMethods.add(Pair.create(EAPConstants.EAP_SIM, null)); Pair.create(EAPConstants.EAP_AKA, null)113 sEapMethods.add(Pair.create(EAPConstants.EAP_AKA, null)); Pair.create(EAPConstants.EAP_AKA_PRIME, null)114 sEapMethods.add(Pair.create(EAPConstants.EAP_AKA_PRIME, null)); 115 116 sSupportedOps.add(TAG_LAUNCH_BROWSER_TO_URI); 117 } 118 119 // Whether to send IMSI and IMEI information or not during OSU provisioning flow; Mandatory (as 120 // per standard) for mobile devices possessing a SIM card. However, it is unclear why this is 121 // needed. Default to false due to privacy concerns. 122 private static boolean sAllowToSendImsiImeiInfo = false; 123 124 /** 125 * Allow or disallow to send IMSI and IMEI information during OSU provisioning flow. 126 * 127 * @param allowToSendImsiImeiInfo flag to allow/disallow to send IMSI and IMEI. 128 */ 129 @VisibleForTesting setAllowToSendImsiImeiInfo(boolean allowToSendImsiImeiInfo)130 public static void setAllowToSendImsiImeiInfo(boolean allowToSendImsiImeiInfo) { 131 sAllowToSendImsiImeiInfo = allowToSendImsiImeiInfo; 132 } 133 134 /** 135 * Make a format of XML based on the DDF(Data Definition Format) of DevDetail MO. 136 * 137 * expected_output : refer to Figure 73: example sppPostDevData SOAP message in Hotspot 2.0 138 * Rel 2.0 Specification document. 139 * @param context {@link Context} 140 * @param info {@link SystemInfo} 141 * @param redirectUri redirect uri that server uses as completion of subscription. 142 * @return the XML that has format of OMA DM DevDetail Management Object, <code>null</code> in 143 * case of any failure. 144 */ serializeToXml(@onNull Context context, @NonNull SystemInfo info, @NonNull String redirectUri)145 public static String serializeToXml(@NonNull Context context, @NonNull SystemInfo info, 146 @NonNull String redirectUri) { 147 String macAddress = info.getMacAddress(IFNAME); 148 if (macAddress != null) { 149 macAddress = macAddress.replace(":", ""); 150 } 151 if (TextUtils.isEmpty(macAddress)) { 152 Log.e(TAG, "mac address is empty"); 153 return null; 154 } 155 MoSerializer moSerializer; 156 try { 157 moSerializer = new MoSerializer(); 158 } catch (ParserConfigurationException e) { 159 Log.e(TAG, "failed to create the MoSerializer: " + e); 160 return null; 161 } 162 163 // Create the XML document for DevInfoMo 164 Document doc = moSerializer.createNewDocument(); 165 Element rootElement = moSerializer.createMgmtTree(doc); 166 rootElement.appendChild(moSerializer.writeVersion(doc)); 167 // <Node><NodeName>DevDetail</NodeName> 168 Element moNode = moSerializer.createNode(doc, MO_NAME); 169 170 171 moNode.appendChild(moSerializer.createNodeForUrn(doc, URN)); 172 // <Node><NodeName>Ext</NodeName> 173 Element extNode = moSerializer.createNode(doc, TAG_EXT); 174 // <Node><NodeName>org.wi-fi</NodeName> 175 Element orgNode = moSerializer.createNode(doc, TAG_ORG_WIFI); 176 orgNode.appendChild(moSerializer.createNodeForUrn(doc, HS20_URN)); 177 // <Node><NodeName>Wi-Fi</NodeName> 178 Element wifiNode = moSerializer.createNode(doc, TAG_WIFI); 179 // <Node><NodeName>EAPMethodList</NodeName> 180 Element eapMethodListNode = moSerializer.createNode(doc, TAG_EAP_METHOD_LIST); 181 182 String tagName; 183 Element eapMethodNode; 184 185 int i = 0; 186 for (Pair<Integer, String> entry : sEapMethods) { 187 tagName = String.format("%s%02d", TAG_EAP_METHOD, ++i); 188 eapMethodNode = moSerializer.createNode(doc, tagName); 189 eapMethodNode.appendChild( 190 moSerializer.createNodeForValue(doc, TAG_EAP_TYPE, entry.first.toString())); 191 if (entry.second != null) { 192 eapMethodNode.appendChild( 193 moSerializer.createNodeForValue(doc, TAG_INNER_METHOD, entry.second)); 194 } 195 eapMethodListNode.appendChild(eapMethodNode); 196 197 } 198 wifiNode.appendChild(eapMethodListNode); // TAG_EAP_METHOD_LIST 199 200 wifiNode.appendChild(moSerializer.createNodeForValue(doc, TAG_MANUFACTURING_CERT, "FALSE")); 201 wifiNode.appendChild(moSerializer.createNodeForValue(doc, TAG_CLIENT_TRIGGER_REDIRECT_URI, 202 redirectUri)); 203 wifiNode.appendChild(moSerializer.createNodeForValue(doc, TAG_WIFI_MAC_ADDR, macAddress)); 204 205 // TODO(b/132188983): Inject this using WifiInjector 206 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 207 String imsi = telephonyManager 208 .createForSubscriptionId(SubscriptionManager.getDefaultDataSubscriptionId()) 209 .getSubscriberId(); 210 if (imsi != null && sAllowToSendImsiImeiInfo) { 211 // Don't provide the IMSI to an SP that did not issue the IMSI 212 wifiNode.appendChild(moSerializer.createNodeForValue(doc, TAG_IMSI, imsi)); 213 wifiNode.appendChild( 214 moSerializer.createNodeForValue(doc, TAG_IMEI_MEID, info.getDeviceId())); 215 } 216 217 // <Node><NodeName>Ops</NodeName> 218 Element opsNode = moSerializer.createNode(doc, TAG_OPS); 219 for (String op: sSupportedOps) { 220 opsNode.appendChild(moSerializer.createNodeForValue(doc, op, "")); 221 } 222 wifiNode.appendChild(opsNode); // TAG_OPS 223 orgNode.appendChild(wifiNode); // TAG_WIFI 224 extNode.appendChild(orgNode); // TAG_ORG_WIFI 225 moNode.appendChild(extNode); // TAG_EXT 226 // <Node><NodeName>URI</NodeName> 227 Element uriNode = moSerializer.createNode(doc, TAG_URI); 228 229 uriNode.appendChild(moSerializer.createNodeForValue(doc, TAG_MAX_DEPTH, "32")); 230 uriNode.appendChild(moSerializer.createNodeForValue(doc, TAG_MAX_TOT_LEN, "2048")); 231 uriNode.appendChild(moSerializer.createNodeForValue(doc, TAG_MAX_SEG_LEN, "64")); 232 moNode.appendChild(uriNode); // TAG_URI 233 234 moNode.appendChild( 235 moSerializer.createNodeForValue(doc, TAG_OEM, info.getDeviceManufacturer())); 236 moNode.appendChild( 237 moSerializer.createNodeForValue(doc, TAG_SW_VER, info.getSoftwareVersion())); 238 moNode.appendChild(moSerializer.createNodeForValue(doc, TAG_LRG_ORJ, "TRUE")); 239 rootElement.appendChild(moNode); // TAG_DEVDETAIL 240 241 return moSerializer.serialize(doc); 242 } 243 } 244