1/*
2 * Copyright (C) 2010, 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.connectivitymanagertest;
18
19import javax.xml.parsers.SAXParser;
20import javax.xml.parsers.SAXParserFactory;
21
22import org.xml.sax.Attributes;
23import org.xml.sax.SAXException;
24import org.xml.sax.helpers.DefaultHandler;
25
26import android.net.wifi.WifiConfiguration;
27import android.net.wifi.WifiConfiguration.AuthAlgorithm;
28import android.net.wifi.WifiConfiguration.IpAssignment;
29import android.net.wifi.WifiConfiguration.KeyMgmt;
30import android.net.wifi.WifiConfiguration.ProxySettings;
31import android.net.LinkAddress;
32import android.net.LinkProperties;
33import android.net.RouteInfo;
34import android.util.Log;
35
36import java.io.InputStream;
37import java.net.InetAddress;
38import java.net.UnknownHostException;
39import java.util.ArrayList;
40import java.util.HashMap;
41import java.util.List;
42
43
44/**
45 * Help class to process configurations of access points saved in an XML file.
46 * The configurations of an access point is included in tag
47 * <accesspoint></accesspoint>. The supported configuration includes: ssid,
48 * security, eap, phase2, identity, password, anonymousidentity, cacert, usercert,
49 * in which each is included in the corresponding tags. Static IP setting is also supported.
50 * Tags that can be used include: ip, gateway, networkprefixlength, dns1, dns2. All access points
51 * have to be enclosed in tags of <resources></resources>.
52 *
53 * The following is a sample configuration file for an access point using EAP-PEAP with MSCHAP2.
54 * <resources>
55 *   <accesspoint>
56 *   <ssid>testnet</ssid>
57 *   <security>EAP</security>
58 *   <eap>PEAP</eap>
59 *   <phase2>MSCHAP2</phase2>
60 *   <identity>donut</identity</identity>
61 *   <password>abcdefgh</password>
62 *   </accesspoint>
63 * </resources>
64 *
65 * Note:ssid and security have to be the first two tags
66 *      for static ip setting, tag "ip" should be listed before other fields: dns, gateway,
67 *      networkprefixlength.
68 */
69public class AccessPointParserHelper {
70    private static final String KEYSTORE_SPACE = "keystore://";
71    private static final String TAG = "AccessPointParserHelper";
72    static final int NONE = 0;
73    static final int WEP = 1;
74    static final int PSK = 2;
75    static final int EAP = 3;
76
77    List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
78
79    private int getSecurityType (String security) {
80        if (security.equalsIgnoreCase("NONE")) {
81            return NONE;
82        } else if (security.equalsIgnoreCase("WEP")) {
83            return WEP;
84        } else if (security.equalsIgnoreCase("PSK")) {
85            return PSK;
86        } else if (security.equalsIgnoreCase("EAP")) {
87            return EAP;
88        } else {
89            return -1;
90        }
91    }
92
93    private boolean validateEapValue(String value) {
94        if (value.equalsIgnoreCase("PEAP") ||
95                value.equalsIgnoreCase("TLS") ||
96                value.equalsIgnoreCase("TTLS")) {
97            return true;
98        } else {
99            return false;
100        }
101    }
102
103    DefaultHandler mHandler = new DefaultHandler() {
104
105        boolean ssid = false;
106        boolean security = false;
107        boolean password = false;
108        boolean ip = false;
109        boolean gateway = false;
110        boolean networkprefix = false;
111        boolean dns1 = false;
112        boolean dns2 = false;
113        boolean eap = false;
114        boolean phase2 = false;
115        boolean identity = false;
116        boolean anonymousidentity = false;
117        boolean cacert = false;
118        boolean usercert = false;
119        WifiConfiguration config = null;
120        int securityType = NONE;
121        LinkProperties mLinkProperties = null;
122        InetAddress mInetAddr = null;
123
124        @Override
125        public void startElement(String uri, String localName, String tagName,
126                Attributes attributes) throws SAXException {
127            if (tagName.equalsIgnoreCase("accesspoint")) {
128                config = new WifiConfiguration();
129            }
130            if (tagName.equalsIgnoreCase("ssid")) {
131                ssid = true;
132            }
133            if (tagName.equalsIgnoreCase("security")) {
134                security = true;
135            }
136            if (tagName.equalsIgnoreCase("password")) {
137                password = true;
138            }
139            if (tagName.equalsIgnoreCase("eap")) {
140                eap = true;
141            }
142            if (tagName.equalsIgnoreCase("phase2")) {
143                phase2 = true;
144            }
145            if (tagName.equalsIgnoreCase("identity")) {
146                identity = true;
147            }
148            if (tagName.equalsIgnoreCase("anonymousidentity")) {
149                anonymousidentity = true;
150            }
151            if (tagName.equalsIgnoreCase("cacert")) {
152                cacert = true;
153            }
154            if (tagName.equalsIgnoreCase("usercert")) {
155                usercert = true;
156            }
157            if (tagName.equalsIgnoreCase("ip")) {
158                mLinkProperties = new LinkProperties();
159                ip = true;
160            }
161            if (tagName.equalsIgnoreCase("gateway")) {
162                gateway = true;
163            }
164            if (tagName.equalsIgnoreCase("networkprefixlength")) {
165                networkprefix = true;
166            }
167            if (tagName.equalsIgnoreCase("dns1")) {
168                dns1 = true;
169            }
170            if (tagName.equalsIgnoreCase("dns2")) {
171                dns2 = true;
172            }
173        }
174
175        @Override
176        public void endElement(String uri, String localName, String tagName) throws SAXException {
177            if (tagName.equalsIgnoreCase("accesspoint")) {
178                if (mLinkProperties != null) {
179                    config.ipAssignment = IpAssignment.STATIC;
180                    config.linkProperties = mLinkProperties;
181                } else {
182                    config.ipAssignment = IpAssignment.DHCP;
183                }
184                config.proxySettings = ProxySettings.NONE;
185                networks.add(config);
186                mLinkProperties = null;
187            }
188        }
189
190        @Override
191        public void characters(char ch[], int start, int length) throws SAXException {
192            if (ssid) {
193                config.SSID = new String(ch, start, length);
194                ssid = false;
195            }
196            if (security) {
197                String securityStr = (new String(ch, start, length)).toUpperCase();
198                securityType = getSecurityType(securityStr);
199                switch (securityType) {
200                    case NONE:
201                        config.allowedKeyManagement.set(KeyMgmt.NONE);
202                        break;
203                    case WEP:
204                        config.allowedKeyManagement.set(KeyMgmt.NONE);
205                        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
206                        config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
207                        break;
208                    case PSK:
209                        config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
210                        break;
211                    case EAP:
212                        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
213                        config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
214                        // Initialize other fields.
215                        config.phase2.setValue("");
216                        config.ca_cert.setValue("");
217                        config.client_cert.setValue("");
218                        config.engine.setValue("");
219                        config.engine_id.setValue("");
220                        config.key_id.setValue("");
221                        config.identity.setValue("");
222                        config.anonymous_identity.setValue("");
223                        break;
224                    default:
225                        throw new SAXException();
226                }
227                security = false;
228            }
229            if (password) {
230                String passwordStr = new String(ch, start, length);
231                int len = passwordStr.length();
232                if (len == 0) {
233                    throw new SAXException();
234                }
235                if (securityType == WEP) {
236                    if ((len == 10 || len == 26 || len == 58) &&
237                            passwordStr.matches("[0-9A-Fa-f]*")) {
238                        config.wepKeys[0] = passwordStr;
239                    } else {
240                        config.wepKeys[0] = '"' + passwordStr + '"';
241                    }
242                } else if (securityType == PSK) {
243                    if (passwordStr.matches("[0-9A-Fa-f]{64}")) {
244                        config.preSharedKey = passwordStr;
245                    } else {
246                        config.preSharedKey = '"' + passwordStr + '"';
247                    }
248                } else if (securityType == EAP) {
249                    config.password.setValue(passwordStr);
250                } else {
251                    throw new SAXException();
252                }
253                password = false;
254            }
255            if (eap) {
256                String eapValue = new String(ch, start, length);
257                if (!validateEapValue(eapValue)) {
258                    throw new SAXException();
259                }
260                config.eap.setValue(eapValue);
261                eap = false;
262            }
263            if (phase2) {
264                String phase2Value = new String(ch, start, length);
265                config.phase2.setValue("auth=" + phase2Value);
266                phase2 = false;
267            }
268            if (identity) {
269                String identityValue = new String(ch, start, length);
270                config.identity.setValue(identityValue);
271                identity = false;
272            }
273            if (anonymousidentity) {
274                String anonyId = new String(ch, start, length);
275                config.anonymous_identity.setValue(anonyId);
276                anonymousidentity = false;
277            }
278            if (cacert) {
279                String cacertValue = new String(ch, start, length);
280                // need to install the credentail to "keystore://"
281                config.ca_cert.setValue(KEYSTORE_SPACE);
282                cacert = false;
283            }
284            if (usercert) {
285                String usercertValue = new String(ch, start, length);
286                config.client_cert.setValue(KEYSTORE_SPACE);
287                usercert = false;
288            }
289            if (ip) {
290                try {
291                    String ipAddr = new String(ch, start, length);
292                    if (!InetAddress.isNumeric(ipAddr)) {
293                        throw new SAXException();
294                    }
295                    mInetAddr = InetAddress.getByName(ipAddr);
296                } catch (UnknownHostException e) {
297                    throw new SAXException();
298                }
299                ip = false;
300            }
301            if (gateway) {
302                try {
303                    String gwAddr = new String(ch, start, length);
304                    if (!InetAddress.isNumeric(gwAddr)) {
305                        throw new SAXException();
306                    }
307                    mLinkProperties.addRoute(new RouteInfo(InetAddress.getByName(gwAddr)));
308                } catch (UnknownHostException e) {
309                    throw new SAXException();
310                }
311                gateway = false;
312            }
313            if (networkprefix) {
314                try {
315                    int nwPrefixLength = Integer.parseInt(new String(ch, start, length));
316                    if ((nwPrefixLength < 0) || (nwPrefixLength > 32)) {
317                        throw new SAXException();
318                    }
319                    mLinkProperties.addLinkAddress(new LinkAddress(mInetAddr, nwPrefixLength));
320                } catch (NumberFormatException e) {
321                    throw new SAXException();
322                }
323                networkprefix = false;
324            }
325            if (dns1) {
326                try {
327                    String dnsAddr = new String(ch, start, length);
328                    if (!InetAddress.isNumeric(dnsAddr)) {
329                        throw new SAXException();
330                    }
331                    mLinkProperties.addDns(InetAddress.getByName(dnsAddr));
332                } catch (UnknownHostException e) {
333                    throw new SAXException();
334                }
335                dns1 = false;
336            }
337            if (dns2) {
338                try {
339                    String dnsAddr = new String(ch, start, length);
340                    if (!InetAddress.isNumeric(dnsAddr)) {
341                        throw new SAXException();
342                    }
343                    mLinkProperties.addDns(InetAddress.getByName(dnsAddr));
344                } catch (UnknownHostException e) {
345                    throw new SAXException();
346                }
347                dns2 = false;
348            }
349        }
350    };
351
352    /**
353     * Process the InputStream in
354     * @param in is the InputStream that can be used for XML parsing
355     * @throws Exception
356     */
357    public AccessPointParserHelper(InputStream in) throws Exception {
358        SAXParserFactory factory = SAXParserFactory.newInstance();
359        SAXParser saxParser = factory.newSAXParser();
360        saxParser.parse(in, mHandler);
361    }
362
363    public List<WifiConfiguration> getNetworkConfigurations() throws Exception {
364        return networks;
365    }
366}
367