• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 android.net.wifi;
18 
19 import static org.junit.Assert.assertArrayEquals;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertNotEquals;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertNull;
25 import static org.junit.Assert.assertThrows;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28 import static org.junit.Assume.assumeTrue;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.when;
31 
32 import android.net.wifi.WifiEnterpriseConfig.Eap;
33 import android.net.wifi.WifiEnterpriseConfig.Phase2;
34 import android.net.wifi.hotspot2.PasspointConfiguration;
35 import android.os.Bundle;
36 import android.os.Parcel;
37 import android.security.Credentials;
38 
39 import androidx.test.filters.SmallTest;
40 
41 import com.android.modules.utils.build.SdkLevel;
42 
43 import org.junit.Before;
44 import org.junit.Test;
45 
46 import java.security.PrivateKey;
47 import java.security.cert.X509Certificate;
48 import java.util.Arrays;
49 import java.util.HashMap;
50 import java.util.Map;
51 
52 /**
53  * Unit tests for {@link android.net.wifi.WifiEnterpriseConfig}.
54  */
55 @SmallTest
56 public class WifiEnterpriseConfigTest {
57     // Maintain a ground truth of the keystore uri prefix which is expected by wpa_supplicant.
58     public static final String KEYSTORE_URI = "keystore://";
59     public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
60     public static final String KEYSTORES_URI = "keystores://";
61     private static final String TEST_DOMAIN_SUFFIX_MATCH = "domainSuffixMatch";
62     private static final String TEST_ALT_SUBJECT_MATCH = "DNS:server.test.com";
63     private static final String TEST_DECORATED_IDENTITY_PREFIX = "androidwifi.dev!";
64     private static final long TEST_SELECTED_RCOI = 0xcafeL;
65 
66     private WifiEnterpriseConfig mEnterpriseConfig;
67 
68     @Before
setUp()69     public void setUp() throws Exception {
70         mEnterpriseConfig = new WifiEnterpriseConfig();
71     }
72 
73     @Test
testGetEmptyCaCertificate()74     public void testGetEmptyCaCertificate() {
75         // A newly-constructed WifiEnterpriseConfig object should have no CA certificate.
76         assertNull(mEnterpriseConfig.getCaCertificate());
77         assertNull(mEnterpriseConfig.getCaCertificates());
78         // Setting CA certificate to null explicitly.
79         mEnterpriseConfig.setCaCertificate(null);
80         assertNull(mEnterpriseConfig.getCaCertificate());
81         // Setting CA certificate to null using setCaCertificates().
82         mEnterpriseConfig.setCaCertificates(null);
83         assertNull(mEnterpriseConfig.getCaCertificates());
84         // Setting CA certificate to zero-length array.
85         mEnterpriseConfig.setCaCertificates(new X509Certificate[0]);
86         assertNull(mEnterpriseConfig.getCaCertificates());
87     }
88 
89     @Test
testSetGetSingleCaCertificate()90     public void testSetGetSingleCaCertificate() {
91         X509Certificate cert0 = FakeKeys.CA_CERT0;
92         mEnterpriseConfig.setCaCertificate(cert0);
93         assertEquals(mEnterpriseConfig.getCaCertificate(), cert0);
94     }
95 
96     @Test
testSetGetMultipleCaCertificates()97     public void testSetGetMultipleCaCertificates() {
98         X509Certificate cert0 = FakeKeys.CA_CERT0;
99         X509Certificate cert1 = FakeKeys.CA_CERT1;
100         mEnterpriseConfig.setCaCertificates(new X509Certificate[] {cert0, cert1});
101         X509Certificate[] result = mEnterpriseConfig.getCaCertificates();
102         assertEquals(result.length, 2);
103         assertTrue(result[0] == cert0 && result[1] == cert1);
104     }
105 
106     @Test
testSetGetInvalidNumberOfCaCertificates()107     public void testSetGetInvalidNumberOfCaCertificates() {
108         // Maximum number of CA certificates is 100.
109         X509Certificate[] invalidCaCertList = new X509Certificate[105];
110         Arrays.fill(invalidCaCertList, FakeKeys.CA_CERT0);
111         assertThrows(IllegalArgumentException.class, () -> {
112             mEnterpriseConfig.setCaCertificates(invalidCaCertList);
113         });
114         assertEquals(null, mEnterpriseConfig.getCaCertificates());
115     }
116 
117     @Test
testSetClientKeyEntryWithNull()118     public void testSetClientKeyEntryWithNull() {
119         mEnterpriseConfig.setClientKeyEntry(null, null);
120         assertNull(mEnterpriseConfig.getClientCertificateChain());
121         assertNull(mEnterpriseConfig.getClientCertificate());
122         mEnterpriseConfig.setClientKeyEntryWithCertificateChain(null, null);
123         assertNull(mEnterpriseConfig.getClientCertificateChain());
124         assertNull(mEnterpriseConfig.getClientCertificate());
125 
126         // Setting the client certificate to null should clear the existing chain.
127         PrivateKey clientKey = FakeKeys.RSA_KEY1;
128         X509Certificate clientCert0 = FakeKeys.CLIENT_CERT;
129         X509Certificate clientCert1 = FakeKeys.CA_CERT1;
130         mEnterpriseConfig.setClientKeyEntry(clientKey, clientCert0);
131         assertNotNull(mEnterpriseConfig.getClientCertificate());
132         mEnterpriseConfig.setClientKeyEntry(null, null);
133         assertNull(mEnterpriseConfig.getClientCertificate());
134         assertNull(mEnterpriseConfig.getClientCertificateChain());
135 
136         // Setting the chain to null should clear the existing chain.
137         X509Certificate[] clientChain = new X509Certificate[] {clientCert0, clientCert1};
138         mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain);
139         assertNotNull(mEnterpriseConfig.getClientCertificateChain());
140         mEnterpriseConfig.setClientKeyEntryWithCertificateChain(null, null);
141         assertNull(mEnterpriseConfig.getClientCertificate());
142         assertNull(mEnterpriseConfig.getClientCertificateChain());
143     }
144 
145     @Test
testSetClientCertificateChain()146     public void testSetClientCertificateChain() {
147         PrivateKey clientKey = FakeKeys.RSA_KEY1;
148         X509Certificate cert0 = FakeKeys.CLIENT_CERT;
149         X509Certificate cert1 = FakeKeys.CA_CERT1;
150         X509Certificate[] clientChain = new X509Certificate[] {cert0, cert1};
151         mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain);
152         X509Certificate[] result = mEnterpriseConfig.getClientCertificateChain();
153         assertEquals(result.length, 2);
154         assertTrue(result[0] == cert0 && result[1] == cert1);
155         assertTrue(mEnterpriseConfig.getClientCertificate() == cert0);
156     }
157 
158     @Test
testSetGetClientKeyPairAlias()159     public void testSetGetClientKeyPairAlias() {
160         assumeTrue(SdkLevel.isAtLeastS());
161 
162         final String alias = "alias";
163         mEnterpriseConfig.setClientKeyPairAlias(alias);
164         assertEquals(alias, mEnterpriseConfig.getClientKeyPairAlias());
165         assertEquals(alias, mEnterpriseConfig.getClientKeyPairAliasInternal());
166 
167         // Alias should have a maximum length of 256.
168         final String invalidAlias = "*".repeat(1000);
169         assertThrows(IllegalArgumentException.class, () -> {
170             mEnterpriseConfig.setClientKeyPairAlias(invalidAlias);
171         });
172     }
173 
isClientCertificateChainInvalid(X509Certificate[] clientChain)174     private boolean isClientCertificateChainInvalid(X509Certificate[] clientChain) {
175         boolean exceptionThrown = false;
176         try {
177             PrivateKey clientKey = FakeKeys.RSA_KEY1;
178             mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain);
179         } catch (IllegalArgumentException e) {
180             exceptionThrown = true;
181         }
182         return exceptionThrown;
183     }
184 
185     @Test
testSetInvalidClientCertificateChain()186     public void testSetInvalidClientCertificateChain() {
187         X509Certificate clientCert = FakeKeys.CLIENT_CERT;
188         X509Certificate caCert = FakeKeys.CA_CERT1;
189         assertTrue("Invalid client certificate",
190                 isClientCertificateChainInvalid(new X509Certificate[] {caCert, caCert}));
191         assertTrue("Invalid CA certificate",
192                 isClientCertificateChainInvalid(new X509Certificate[] {clientCert, clientCert}));
193         assertTrue("Both certificates invalid",
194                 isClientCertificateChainInvalid(new X509Certificate[] {caCert, clientCert}));
195         assertTrue("Certificate chain contains too many elements",
196                 isClientCertificateChainInvalid(new X509Certificate[] {
197                         clientCert, clientCert, clientCert, clientCert, caCert, caCert}));
198     }
199 
200     @Test
testSaveSingleCaCertificateAlias()201     public void testSaveSingleCaCertificateAlias() {
202         final String alias = "single_alias 0";
203         mEnterpriseConfig.setCaCertificateAliases(new String[] {alias});
204         assertEquals(getCaCertField(), CA_CERT_PREFIX + alias);
205     }
206 
207     @Test
testLoadSingleCaCertificateAlias()208     public void testLoadSingleCaCertificateAlias() {
209         final String alias = "single_alias 1";
210         setCaCertField(CA_CERT_PREFIX + alias);
211         String[] aliases = mEnterpriseConfig.getCaCertificateAliases();
212         assertEquals(aliases.length, 1);
213         assertEquals(aliases[0], alias);
214     }
215 
216     @Test
testSaveMultipleCaCertificates()217     public void testSaveMultipleCaCertificates() {
218         final String alias0 = "single_alias 0";
219         final String alias1 = "single_alias 1";
220         mEnterpriseConfig.setCaCertificateAliases(new String[] {alias0, alias1});
221         assertEquals(getCaCertField(), String.format("%s%s %s",
222                 KEYSTORES_URI,
223                 WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0),
224                 WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1)));
225     }
226 
227     @Test
testSetStrictConservativePeerMode()228     public void testSetStrictConservativePeerMode() {
229         assertFalse(mEnterpriseConfig.getStrictConservativePeerMode());
230 
231         mEnterpriseConfig.setStrictConservativePeerMode(true);
232 
233         assertTrue(mEnterpriseConfig.getStrictConservativePeerMode());
234     }
235 
236     @Test
testLoadMultipleCaCertificates()237     public void testLoadMultipleCaCertificates() {
238         final String alias0 = "single_alias 0";
239         final String alias1 = "single_alias 1";
240         setCaCertField(String.format("%s%s %s",
241                 KEYSTORES_URI,
242                 WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0),
243                 WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1)));
244         String[] aliases = mEnterpriseConfig.getCaCertificateAliases();
245         assertEquals(aliases.length, 2);
246         assertEquals(aliases[0], alias0);
247         assertEquals(aliases[1], alias1);
248     }
249 
getCaCertField()250     private String getCaCertField() {
251         return mEnterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY);
252     }
253 
setCaCertField(String value)254     private void setCaCertField(String value) {
255         mEnterpriseConfig.setFieldValue(WifiEnterpriseConfig.CA_CERT_KEY, value);
256     }
257 
258     // Retrieves the value for a specific key supplied to wpa_supplicant.
259     private class SupplicantConfigExtractor implements WifiEnterpriseConfig.SupplicantSaver {
260         private String mValue = null;
261         private String mKey;
262 
SupplicantConfigExtractor(String key)263         SupplicantConfigExtractor(String key) {
264             mKey = key;
265         }
266 
267         @Override
saveValue(String key, String value)268         public boolean saveValue(String key, String value) {
269             if (key.equals(mKey)) {
270                 mValue = value;
271             }
272             return true;
273         }
274 
getValue()275         public String getValue() {
276             return mValue;
277         }
278     }
279 
getSupplicantEapMethod()280     private String getSupplicantEapMethod() {
281         SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor(
282                 WifiEnterpriseConfig.EAP_KEY);
283         mEnterpriseConfig.saveToSupplicant(entryExtractor);
284         return entryExtractor.getValue();
285     }
286 
getSupplicantPhase2Method()287     private String getSupplicantPhase2Method() {
288         SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor(
289                 WifiEnterpriseConfig.PHASE2_KEY);
290         mEnterpriseConfig.saveToSupplicant(entryExtractor);
291         return entryExtractor.getValue();
292     }
293 
294     /** Verifies the default value for EAP outer and inner methods */
295     @Test
eapInnerDefault()296     public void eapInnerDefault() {
297         assertEquals(null, getSupplicantEapMethod());
298         assertEquals(null, getSupplicantPhase2Method());
299     }
300 
301     /** Verifies that the EAP inner method is reset when we switch to TLS */
302     @Test
eapPhase2MethodForTls()303     public void eapPhase2MethodForTls() {
304         // Initially select an EAP method that supports an phase2.
305         mEnterpriseConfig.setEapMethod(Eap.PEAP);
306         mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
307         assertEquals("PEAP", getSupplicantEapMethod());
308         assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
309 
310         // Change the EAP method to another type which supports a phase2.
311         mEnterpriseConfig.setEapMethod(Eap.TTLS);
312         assertEquals("TTLS", getSupplicantEapMethod());
313         assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
314 
315         // Change the EAP method to TLS which does not support a phase2.
316         mEnterpriseConfig.setEapMethod(Eap.TLS);
317         assertEquals(null, getSupplicantPhase2Method());
318     }
319 
320     /** Verfies that the EAP inner method is reset when we switch phase2 to NONE */
321     @Test
eapPhase2None()322     public void eapPhase2None() {
323         // Initially select an EAP method that supports an phase2.
324         mEnterpriseConfig.setEapMethod(Eap.PEAP);
325         mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
326         assertEquals("PEAP", getSupplicantEapMethod());
327         assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
328 
329         // Change the phase2 method to NONE and ensure the value is cleared.
330         mEnterpriseConfig.setPhase2Method(Phase2.NONE);
331         assertEquals(null, getSupplicantPhase2Method());
332     }
333 
334     /** Verfies that the correct "autheap" parameter is supplied for TTLS/GTC. */
335     @Test
peapGtcToTtls()336     public void peapGtcToTtls() {
337         mEnterpriseConfig.setEapMethod(Eap.PEAP);
338         mEnterpriseConfig.setPhase2Method(Phase2.GTC);
339         assertEquals("PEAP", getSupplicantEapMethod());
340         assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
341 
342         mEnterpriseConfig.setEapMethod(Eap.TTLS);
343         assertEquals("TTLS", getSupplicantEapMethod());
344         assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
345     }
346 
347     /** Verfies that the correct "auth" parameter is supplied for PEAP/GTC. */
348     @Test
ttlsGtcToPeap()349     public void ttlsGtcToPeap() {
350         mEnterpriseConfig.setEapMethod(Eap.TTLS);
351         mEnterpriseConfig.setPhase2Method(Phase2.GTC);
352         assertEquals("TTLS", getSupplicantEapMethod());
353         assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
354 
355         mEnterpriseConfig.setEapMethod(Eap.PEAP);
356         assertEquals("PEAP", getSupplicantEapMethod());
357         assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
358     }
359 
360     /** Verfies PEAP/SIM, PEAP/AKA, PEAP/AKA'. */
361     @Test
peapSimAkaAkaPrime()362     public void peapSimAkaAkaPrime() {
363         mEnterpriseConfig.setEapMethod(Eap.PEAP);
364         mEnterpriseConfig.setPhase2Method(Phase2.SIM);
365         assertEquals("PEAP", getSupplicantEapMethod());
366         assertEquals("\"auth=SIM\"", getSupplicantPhase2Method());
367 
368         mEnterpriseConfig.setPhase2Method(Phase2.AKA);
369         assertEquals("\"auth=AKA\"", getSupplicantPhase2Method());
370 
371         mEnterpriseConfig.setPhase2Method(Phase2.AKA_PRIME);
372         assertEquals("\"auth=AKA'\"", getSupplicantPhase2Method());
373     }
374 
375     /**
376      * Verifies that the copy constructor preseves both the masked password and inner method
377      * information.
378      */
379     @Test
copyConstructor()380     public void copyConstructor() {
381         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
382         enterpriseConfig.setPassword("*");
383         enterpriseConfig.setEapMethod(Eap.TTLS);
384         enterpriseConfig.setPhase2Method(Phase2.GTC);
385         mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
386         assertEquals("TTLS", getSupplicantEapMethod());
387         assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
388         assertEquals("*", mEnterpriseConfig.getPassword());
389     }
390 
391     /**
392      * Verifies that the copy from external ignores masked passwords and preserves the
393      * inner method information.
394      */
395     @Test
copyFromExternal()396     public void copyFromExternal() {
397         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
398         enterpriseConfig.setPassword("*");
399         enterpriseConfig.setEapMethod(Eap.TTLS);
400         enterpriseConfig.setPhase2Method(Phase2.GTC);
401         enterpriseConfig.setOcsp(WifiEnterpriseConfig.OCSP_REQUIRE_CERT_STATUS);
402         mEnterpriseConfig = new WifiEnterpriseConfig();
403         mEnterpriseConfig.copyFromExternal(enterpriseConfig, "*");
404         assertEquals("TTLS", getSupplicantEapMethod());
405         assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
406         assertNotEquals("*", mEnterpriseConfig.getPassword());
407         assertEquals(enterpriseConfig.getOcsp(), mEnterpriseConfig.getOcsp());
408     }
409 
410     /** Verfies that parceling a WifiEnterpriseConfig preseves method information. */
411     @Test
parcelConstructor()412     public void parcelConstructor() {
413         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
414         enterpriseConfig.setEapMethod(Eap.TTLS);
415         enterpriseConfig.setPhase2Method(Phase2.GTC);
416         Parcel parcel = Parcel.obtain();
417         enterpriseConfig.writeToParcel(parcel, 0);
418         parcel.setDataPosition(0);  // Allow parcel to be read from the beginning.
419         mEnterpriseConfig = WifiEnterpriseConfig.CREATOR.createFromParcel(parcel);
420         assertEquals("TTLS", getSupplicantEapMethod());
421         assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
422     }
423 
424     /**
425      * Verifies that parceling a WifiEnterpriseConfig preserves the key
426      * and certificates information.
427      */
428     @Test
parcelConfigWithKeyAndCerts()429     public void parcelConfigWithKeyAndCerts() throws Exception {
430         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
431         PrivateKey clientKey = FakeKeys.RSA_KEY1;
432         X509Certificate clientCert = FakeKeys.CLIENT_CERT;
433         X509Certificate[] caCerts = new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1};
434         enterpriseConfig.setClientKeyEntry(clientKey, clientCert);
435         enterpriseConfig.setCaCertificates(caCerts);
436         Parcel parcel = Parcel.obtain();
437         enterpriseConfig.writeToParcel(parcel, 0);
438 
439         parcel.setDataPosition(0);  // Allow parcel to be read from the beginning.
440         mEnterpriseConfig = WifiEnterpriseConfig.CREATOR.createFromParcel(parcel);
441         PrivateKey actualClientKey = mEnterpriseConfig.getClientPrivateKey();
442         X509Certificate actualClientCert = mEnterpriseConfig.getClientCertificate();
443         X509Certificate[] actualCaCerts = mEnterpriseConfig.getCaCertificates();
444 
445         /* Verify client private key. */
446         assertNotNull(actualClientKey);
447         assertEquals(clientKey.getAlgorithm(), actualClientKey.getAlgorithm());
448         assertArrayEquals(clientKey.getEncoded(), actualClientKey.getEncoded());
449 
450         /* Verify client certificate. */
451         assertNotNull(actualClientCert);
452         assertArrayEquals(clientCert.getEncoded(), actualClientCert.getEncoded());
453 
454         /* Verify CA certificates. */
455         assertNotNull(actualCaCerts);
456         assertEquals(caCerts.length, actualCaCerts.length);
457         for (int i = 0; i < caCerts.length; i++) {
458             assertNotNull(actualCaCerts[i]);
459             assertArrayEquals(caCerts[i].getEncoded(), actualCaCerts[i].getEncoded());
460         }
461     }
462 
463     /** Verifies proper operation of the getKeyId() method. */
464     @Test
getKeyId()465     public void getKeyId() {
466         assertEquals("NULL", mEnterpriseConfig.getKeyId(null));
467         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
468         enterpriseConfig.setEapMethod(Eap.TTLS);
469         enterpriseConfig.setPhase2Method(Phase2.GTC);
470         assertEquals("TTLS_GTC", mEnterpriseConfig.getKeyId(enterpriseConfig));
471         mEnterpriseConfig.setEapMethod(Eap.PEAP);
472         mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
473         assertEquals("PEAP_MSCHAPV2", mEnterpriseConfig.getKeyId(enterpriseConfig));
474     }
475 
476     /** Verifies that passwords are not displayed in toString. */
477     @Test
passwordNotInToString()478     public void passwordNotInToString() {
479         String password = "supersecret";
480         mEnterpriseConfig.setPassword(password);
481         assertFalse(mEnterpriseConfig.toString().contains(password));
482     }
483 
484     /** Verifies that certificate ownership flag is set correctly */
485     @Test
testIsAppInstalledDeviceKeyAndCert()486     public void testIsAppInstalledDeviceKeyAndCert() {
487         // First make sure that app didn't install anything
488         assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
489         assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
490 
491         // Then app loads keys via the enterprise config API
492         PrivateKey clientKey = FakeKeys.RSA_KEY1;
493         X509Certificate cert0 = FakeKeys.CLIENT_CERT;
494         X509Certificate cert1 = FakeKeys.CA_CERT1;
495         X509Certificate[] clientChain = new X509Certificate[] {cert0, cert1};
496         mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain);
497         X509Certificate[] result = mEnterpriseConfig.getClientCertificateChain();
498         assertEquals(result.length, 2);
499         assertTrue(result[0] == cert0 && result[1] == cert1);
500         assertTrue(mEnterpriseConfig.getClientCertificate() == cert0);
501 
502         // Make sure it is the owner now
503         assertTrue(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
504         assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
505     }
506 
507     /** Verifies that certificate ownership flag is set correctly */
508     @Test
testIsAppInstalledCaCert()509     public void testIsAppInstalledCaCert() {
510         // First make sure that app didn't install anything
511         assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
512         assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
513 
514         // Then app loads CA cert via the enterprise config API
515         X509Certificate cert = FakeKeys.CA_CERT1;
516         mEnterpriseConfig.setCaCertificate(cert);
517         X509Certificate result = mEnterpriseConfig.getCaCertificate();
518         assertTrue(result == cert);
519 
520         // Make sure it is the owner now
521         assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
522         assertTrue(mEnterpriseConfig.isAppInstalledCaCert());
523     }
524 
525     /** Verifies that certificate ownership flag is set correctly */
526     @Test
testIsAppInstalledCaCerts()527     public void testIsAppInstalledCaCerts() {
528         // First make sure that app didn't install anything
529         assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
530         assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
531 
532         // Then app loads CA cert via the enterprise config API
533         X509Certificate cert0 = FakeKeys.CA_CERT0;
534         X509Certificate cert1 = FakeKeys.CA_CERT1;
535         X509Certificate[] cert = new X509Certificate[] {cert0, cert1};
536 
537         mEnterpriseConfig.setCaCertificates(cert);
538         X509Certificate[] result = mEnterpriseConfig.getCaCertificates();
539         assertEquals(result.length, 2);
540         assertTrue(result[0] == cert0 && result[1] == cert1);
541 //        assertTrue(mEnterpriseConfig.getClientCertificate() == cert0);
542 
543         // Make sure it is the owner now
544         assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
545         assertTrue(mEnterpriseConfig.isAppInstalledCaCert());
546     }
547 
548     /** Verifies that OCSP value is set correctly. */
549     @Test
testOcspSetGet()550     public void testOcspSetGet() throws Exception {
551         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
552 
553         enterpriseConfig.setOcsp(WifiEnterpriseConfig.OCSP_NONE);
554         assertEquals(WifiEnterpriseConfig.OCSP_NONE, enterpriseConfig.getOcsp());
555 
556         enterpriseConfig.setOcsp(WifiEnterpriseConfig.OCSP_REQUIRE_CERT_STATUS);
557         assertEquals(WifiEnterpriseConfig.OCSP_REQUIRE_CERT_STATUS, enterpriseConfig.getOcsp());
558 
559         enterpriseConfig.setOcsp(WifiEnterpriseConfig.OCSP_REQUEST_CERT_STATUS);
560         assertEquals(WifiEnterpriseConfig.OCSP_REQUEST_CERT_STATUS, enterpriseConfig.getOcsp());
561 
562         enterpriseConfig.setOcsp(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS);
563         assertEquals(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS,
564                 enterpriseConfig.getOcsp());
565     }
566 
567     /** Verifies that an exception is thrown when invalid OCSP is set. */
568     @Test
testInvalidOcspValue()569     public void testInvalidOcspValue() {
570         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
571         try {
572             enterpriseConfig.setOcsp(-1);
573             fail("Should raise an IllegalArgumentException here.");
574         } catch (IllegalArgumentException e) {
575             // expected exception.
576         }
577     }
578 
579     /** Verifies that the EAP inner method is reset when we switch to Unauth-TLS */
580     @Test
eapPhase2MethodForUnauthTls()581     public void eapPhase2MethodForUnauthTls() {
582         // Initially select an EAP method that supports an phase2.
583         mEnterpriseConfig.setEapMethod(Eap.PEAP);
584         mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
585         assertEquals("PEAP", getSupplicantEapMethod());
586         assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
587 
588         // Change the EAP method to another type which supports a phase2.
589         mEnterpriseConfig.setEapMethod(Eap.TTLS);
590         assertEquals("TTLS", getSupplicantEapMethod());
591         assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
592 
593         // Change the EAP method to Unauth-TLS which does not support a phase2.
594         mEnterpriseConfig.setEapMethod(Eap.UNAUTH_TLS);
595         assertEquals(null, getSupplicantPhase2Method());
596     }
597 
598     @Test
testIsEnterpriseConfigServerCertNotEnabled()599     public void testIsEnterpriseConfigServerCertNotEnabled() {
600         WifiEnterpriseConfig baseConfig = new WifiEnterpriseConfig();
601         baseConfig.setEapMethod(Eap.PEAP);
602         baseConfig.setPhase2Method(Phase2.MSCHAPV2);
603         assertTrue(baseConfig.isEapMethodServerCertUsed());
604         assertFalse(baseConfig.isServerCertValidationEnabled());
605 
606         WifiEnterpriseConfig noMatchConfig = new WifiEnterpriseConfig(baseConfig);
607         noMatchConfig.setCaCertificate(FakeKeys.CA_CERT0);
608         // Missing match disables validation.
609         assertTrue(baseConfig.isEapMethodServerCertUsed());
610         assertFalse(baseConfig.isServerCertValidationEnabled());
611 
612         WifiEnterpriseConfig noCaConfig = new WifiEnterpriseConfig(baseConfig);
613         noCaConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
614         // Missing CA certificate disables validation.
615         assertTrue(baseConfig.isEapMethodServerCertUsed());
616         assertFalse(baseConfig.isServerCertValidationEnabled());
617 
618         WifiEnterpriseConfig noValidationConfig = new WifiEnterpriseConfig();
619         noValidationConfig.setEapMethod(Eap.AKA);
620         assertFalse(noValidationConfig.isEapMethodServerCertUsed());
621     }
622 
623     @Test
testIsEnterpriseConfigServerCertEnabledWithPeap()624     public void testIsEnterpriseConfigServerCertEnabledWithPeap() {
625         testIsEnterpriseConfigServerCertEnabled(Eap.PEAP);
626     }
627 
628     @Test
testIsEnterpriseConfigServerCertEnabledWithTls()629     public void testIsEnterpriseConfigServerCertEnabledWithTls() {
630         testIsEnterpriseConfigServerCertEnabled(Eap.TLS);
631     }
632 
633     @Test
testIsEnterpriseConfigServerCertEnabledWithTTLS()634     public void testIsEnterpriseConfigServerCertEnabledWithTTLS() {
635         testIsEnterpriseConfigServerCertEnabled(Eap.TTLS);
636     }
637 
638     @Test
testSetGetDecoratedIdentityPrefix()639     public void testSetGetDecoratedIdentityPrefix() {
640         assumeTrue(SdkLevel.isAtLeastS());
641         WifiEnterpriseConfig config = new WifiEnterpriseConfig();
642 
643         assertNull(config.getDecoratedIdentityPrefix());
644         config.setDecoratedIdentityPrefix(TEST_DECORATED_IDENTITY_PREFIX);
645         assertEquals(TEST_DECORATED_IDENTITY_PREFIX, config.getDecoratedIdentityPrefix());
646     }
647 
648     @Test
testTrustOnFirstUse()649     public void testTrustOnFirstUse() {
650         WifiEnterpriseConfig config = new WifiEnterpriseConfig();
651 
652         assertFalse(config.isTrustOnFirstUseEnabled());
653         config.enableTrustOnFirstUse(true);
654         assertTrue(config.isTrustOnFirstUseEnabled());
655         config.enableTrustOnFirstUse(false);
656         assertFalse(config.isTrustOnFirstUseEnabled());
657     }
658 
659     @Test
testHasCaCertificate()660     public void testHasCaCertificate() {
661         assumeTrue(SdkLevel.isAtLeastT());
662         WifiEnterpriseConfig config = new WifiEnterpriseConfig();
663         assertFalse(config.hasCaCertificate());
664         config.setCaPath("/tmp/testCa.cert");
665         assertTrue(config.hasCaCertificate());
666 
667         config = new WifiEnterpriseConfig();
668         assertFalse(config.hasCaCertificate());
669         config.setCaCertificate(FakeKeys.CA_CERT0);
670         assertTrue(config.hasCaCertificate());
671 
672         config = new WifiEnterpriseConfig();
673         assertFalse(config.hasCaCertificate());
674         config.setCaCertificateAliases(new String[] {"single_alias 0"});
675         assertTrue(config.hasCaCertificate());
676     }
677 
678     @Test
testUserApproveNoCaCert()679     public void testUserApproveNoCaCert() {
680         WifiEnterpriseConfig config = new WifiEnterpriseConfig();
681 
682         assertFalse(config.isUserApproveNoCaCert());
683         config.setUserApproveNoCaCert(true);
684         assertTrue(config.isUserApproveNoCaCert());
685         config.setUserApproveNoCaCert(false);
686         assertFalse(config.isUserApproveNoCaCert());
687     }
688 
689     /**
690      * Verify that the set decorated identity prefix doesn't accept a malformed input.
691      *
692      * @throws Exception
693      */
694     @Test (expected = IllegalArgumentException.class)
testSetDecoratedIdentityPrefixWithInvalidValue()695     public void testSetDecoratedIdentityPrefixWithInvalidValue() {
696         assumeTrue(SdkLevel.isAtLeastS());
697         PasspointConfiguration config = new PasspointConfiguration();
698 
699         config.setDecoratedIdentityPrefix(TEST_DECORATED_IDENTITY_PREFIX.replace('!', 'a'));
700     }
701 
702     @Test
testSetGetSelectedRcoi()703     public void testSetGetSelectedRcoi() {
704         WifiEnterpriseConfig config = new WifiEnterpriseConfig();
705 
706         assertEquals(0, config.getSelectedRcoi());
707         config.setSelectedRcoi(TEST_SELECTED_RCOI);
708         assertEquals(TEST_SELECTED_RCOI, config.getSelectedRcoi());
709     }
710 
testIsEnterpriseConfigServerCertEnabled(int eapMethod)711     private void testIsEnterpriseConfigServerCertEnabled(int eapMethod) {
712         WifiEnterpriseConfig configWithCertAndDomainSuffixMatch = createEnterpriseConfig(eapMethod,
713                 Phase2.NONE, FakeKeys.CA_CERT0, null, TEST_DOMAIN_SUFFIX_MATCH, null);
714         assertTrue(configWithCertAndDomainSuffixMatch.isEapMethodServerCertUsed());
715         assertTrue(configWithCertAndDomainSuffixMatch.isServerCertValidationEnabled());
716 
717         WifiEnterpriseConfig configWithCertAndAltSubjectMatch = createEnterpriseConfig(eapMethod,
718                 Phase2.NONE, FakeKeys.CA_CERT0, null, null, TEST_ALT_SUBJECT_MATCH);
719         assertTrue(configWithCertAndAltSubjectMatch.isEapMethodServerCertUsed());
720         assertTrue(configWithCertAndAltSubjectMatch.isServerCertValidationEnabled());
721 
722         WifiEnterpriseConfig configWithAliasAndDomainSuffixMatch = createEnterpriseConfig(eapMethod,
723                 Phase2.NONE, null, new String[]{"alias1", "alisa2"}, TEST_DOMAIN_SUFFIX_MATCH,
724                 null);
725         assertTrue(configWithAliasAndDomainSuffixMatch.isEapMethodServerCertUsed());
726         assertTrue(configWithAliasAndDomainSuffixMatch.isServerCertValidationEnabled());
727 
728         WifiEnterpriseConfig configWithAliasAndAltSubjectMatch = createEnterpriseConfig(eapMethod,
729                 Phase2.NONE, null, new String[]{"alias1", "alisa2"}, null, TEST_ALT_SUBJECT_MATCH);
730         assertTrue(configWithAliasAndAltSubjectMatch.isEapMethodServerCertUsed());
731         assertTrue(configWithAliasAndAltSubjectMatch.isServerCertValidationEnabled());
732     }
733 
createEnterpriseConfig(int eapMethod, int phase2Method, X509Certificate caCertificate, String[] aliases, String domainSuffixMatch, String altSubjectMatch)734     private WifiEnterpriseConfig createEnterpriseConfig(int eapMethod, int phase2Method,
735             X509Certificate caCertificate, String[] aliases, String domainSuffixMatch,
736             String altSubjectMatch) {
737         WifiEnterpriseConfig config = new WifiEnterpriseConfig();
738         config.setEapMethod(eapMethod);
739         config.setPhase2Method(phase2Method);
740         config.setCaCertificate(caCertificate);
741         config.setCaCertificateAliases(aliases);
742         config.setDomainSuffixMatch(domainSuffixMatch);
743         config.setAltSubjectMatch(altSubjectMatch);
744         return config;
745     }
746 
747     /**
748      * Verify that setCaCertificate() raises IllegalArgumentException
749      * for a self-signed certificate.
750      *
751      * @throws IllegalArgumentException
752      */
753     @Test (expected = IllegalArgumentException.class)
testSetCaCertificateExceptionWithSelfSignedCert()754     public void testSetCaCertificateExceptionWithSelfSignedCert() throws Exception {
755         X509Certificate mockCert = mock(X509Certificate.class);
756         when(mockCert.getBasicConstraints()).thenReturn(-1);
757 
758         mEnterpriseConfig.setCaCertificate(mockCert);
759     }
760 
761     /**
762      * Verify that setCaCertificateForTrustOnFirstUse sunny case.
763      */
764     @Test
testSetCaCertificateForTrustOnFirstUseSuccess()765     public void testSetCaCertificateForTrustOnFirstUseSuccess() throws Exception {
766         X509Certificate mockCert = mock(X509Certificate.class);
767         when(mockCert.getBasicConstraints()).thenReturn(-1);
768 
769         mEnterpriseConfig.enableTrustOnFirstUse(true);
770 
771         mEnterpriseConfig.setCaCertificateForTrustOnFirstUse(mockCert);
772         assertEquals(mEnterpriseConfig.getCaCertificate(), mockCert);
773     }
774 
775     /**
776      * Verify that setCaCertificateForTrustOnFirstUse() raises IllegalArgumentException
777      * when Trust on First Use is not enabled.
778      *
779      * @throws IllegalArgumentException
780      */
781     @Test (expected = IllegalArgumentException.class)
testSetCaCertificateForTrustOnFirstUseExceptionWithNoTofuEnabled()782     public void testSetCaCertificateForTrustOnFirstUseExceptionWithNoTofuEnabled()
783             throws Exception {
784         X509Certificate mockCert = mock(X509Certificate.class);
785         when(mockCert.getBasicConstraints()).thenReturn(-1);
786 
787         mEnterpriseConfig.enableTrustOnFirstUse(false);
788 
789         mEnterpriseConfig.setCaCertificateForTrustOnFirstUse(mockCert);
790     }
791 
792     /**
793      * Verify setMinimumTlsVersion sunny cases.
794      */
795     @Test
testSetMinimumTlsVersionWithValidValues()796     public void testSetMinimumTlsVersionWithValidValues() throws Exception {
797         for (int i = WifiEnterpriseConfig.TLS_VERSION_MIN;
798                 i <= WifiEnterpriseConfig.TLS_VERSION_MAX; i++) {
799             mEnterpriseConfig.setMinimumTlsVersion(i);
800             assertEquals(i, mEnterpriseConfig.getMinimumTlsVersion());
801         }
802     }
803 
804     /**
805      * Verify that setMinimumTlsVersion() raises IllegalArgumentException when
806      * an invalid TLS version is set.
807      *
808      * @throws IllegalArgumentException
809      */
810     @Test (expected = IllegalArgumentException.class)
testSetMinimumTlsVersionWithVersionLargerThanMaxVersion()811     public void testSetMinimumTlsVersionWithVersionLargerThanMaxVersion() throws Exception {
812         mEnterpriseConfig.setMinimumTlsVersion(WifiEnterpriseConfig.TLS_VERSION_MAX + 1);
813     }
814 
815     /**
816      * Verify that setMinimumTlsVersion() raises IllegalArgumentException when
817      * an invalid TLS version is set.
818      *
819      * @throws IllegalArgumentException
820      */
821     @Test (expected = IllegalArgumentException.class)
testSetMinimumTlsVersionWithVersionSmallerThanMinVersion()822     public void testSetMinimumTlsVersionWithVersionSmallerThanMinVersion() throws Exception {
823         mEnterpriseConfig.setMinimumTlsVersion(WifiEnterpriseConfig.TLS_VERSION_MIN - 1);
824     }
825 
826     /**
827      * Verify that fields with unsupported keys cannot be set or retrieved.
828      */
829     @Test
testCannotSetOrGetUnsupportedKeys()830     public void testCannotSetOrGetUnsupportedKeys() {
831         WifiEnterpriseConfig config = new WifiEnterpriseConfig();
832         String password = "somePassword";
833         config.setFieldValue(WifiEnterpriseConfig.PASSWORD_KEY, password);
834         assertEquals(password, config.getFieldValue(WifiEnterpriseConfig.PASSWORD_KEY));
835 
836         String invalidKey = "invalidKey";
837         String invalidValue = "invalidValue";
838         config.setFieldValue(invalidKey, invalidValue);
839         assertEquals("", config.getFieldValue(invalidKey));
840     }
841 
842     /**
843      * Construct a WifiEnterpriceConfig parcel using the provided fields map.
844      * Map is allowed to contain invalid keys.
845      */
constructParcelWithFieldsMap(Map<String, String> fieldsMap)846     private Parcel constructParcelWithFieldsMap(Map<String, String> fieldsMap) {
847         Parcel parcel = Parcel.obtain();
848         Bundle bundle = new Bundle();
849         for (Map.Entry<String, String> entry : fieldsMap.entrySet()) {
850             bundle.putString(entry.getKey(), entry.getValue());
851         }
852         parcel.writeBundle(bundle);
853 
854         // Use the default value for the remaining fields.
855         parcel.writeInt(Eap.NONE);
856         parcel.writeInt(Phase2.NONE);
857         parcel.writeInt(0); // numCaCertificates
858         parcel.writeString(null); // privateKey
859         parcel.writeInt(0); // numClientCertificates
860         parcel.writeString(""); // keyChainAlias
861         parcel.writeBoolean(false); // isAppInstalledDeviceKeyAndCert
862         parcel.writeBoolean(false); // isAppInstalledCaCert
863         parcel.writeInt(0); // OSCP
864         parcel.writeBoolean(false); // isTrustOnFirstUseEnabled
865         parcel.writeBoolean(false); // userApproveNoCaCert
866         parcel.writeInt(WifiEnterpriseConfig.TLS_V1_0);
867         return parcel;
868     }
869 
870     /**
871      * Verify that unsupported keys are ignored during unparceling.
872      */
873     @Test
testUnsupportedKeysIgnoredDuringUnparceling()874     public void testUnsupportedKeysIgnoredDuringUnparceling() {
875         Map<String, String> fieldsMap = new HashMap<>();
876         String password = "somePassword";
877         fieldsMap.put(WifiEnterpriseConfig.PASSWORD_KEY, password);
878 
879         String invalidKey = "invalidKey";
880         String invalidValue = "invalidValue";
881         fieldsMap.put(invalidKey, invalidValue);
882 
883         // Invalid field should be ignored during unparceling.
884         Parcel parcel = constructParcelWithFieldsMap(fieldsMap);
885         parcel.setDataPosition(0);
886         WifiEnterpriseConfig config = WifiEnterpriseConfig.CREATOR.createFromParcel(parcel);
887         assertEquals(password, config.getPassword());
888         assertEquals("", config.getFieldValue(invalidKey));
889     }
890 
891     /**
892      * Verify that fields with invalid field lengths cannot be set or retrieved.
893      */
894     @Test
testCannotSetOrGetFieldsWithInvalidLength()895     public void testCannotSetOrGetFieldsWithInvalidLength() {
896         WifiEnterpriseConfig config = new WifiEnterpriseConfig();
897         String password = "somePassword";
898         config.setFieldValue(WifiEnterpriseConfig.PASSWORD_KEY, password);
899         assertEquals(password, config.getFieldValue(WifiEnterpriseConfig.PASSWORD_KEY));
900 
901         // Value of OPP_KEY_CACHING is expected to have a length of 1.
902         String invalidValue = "invalidValue";
903         config.setFieldValue(WifiEnterpriseConfig.OPP_KEY_CACHING, invalidValue);
904         assertEquals("", config.getFieldValue(WifiEnterpriseConfig.OPP_KEY_CACHING));
905     }
906 
907     /**
908      * Verify that field values with invalid lengths are ignored during unparceling.
909      */
910     @Test
testFieldsWithInvalidLengthIgnoredDuringUnparceling()911     public void testFieldsWithInvalidLengthIgnoredDuringUnparceling() {
912         Map<String, String> fieldsMap = new HashMap<>();
913         String password = "somePassword";
914         fieldsMap.put(WifiEnterpriseConfig.PASSWORD_KEY, password);
915 
916         // Value of OPP_KEY_CACHING is expected to have a length of 1.
917         String invalidValue = "invalidValue";
918         fieldsMap.put(WifiEnterpriseConfig.OPP_KEY_CACHING, invalidValue);
919 
920         // Invalid field should be ignored during unparceling.
921         Parcel parcel = constructParcelWithFieldsMap(fieldsMap);
922         parcel.setDataPosition(0);
923         WifiEnterpriseConfig config = WifiEnterpriseConfig.CREATOR.createFromParcel(parcel);
924         assertEquals(password, config.getFieldValue(WifiEnterpriseConfig.PASSWORD_KEY));
925         assertEquals("", config.getFieldValue(WifiEnterpriseConfig.OPP_KEY_CACHING));
926     }
927 }
928