WifiConfigManager: Separate validation criteria for update

For network config updates, the WifiConfiguration is expected to be a
sparse object with only the fields being updated being filled in. So,
separate out the network config validation criterions for the 2 cases.

Current special cases for update are:
1. SSID's are allowed to be null (because it may not be updated).
2. preSharedKey are allowed to be "*" (This is apps screwing up and sending
back the masked password back to us in an update).

Bug: 62955649
Test: Unit tests
Change-Id: I0c77af06503548f0887c41b02777f288f8a9d013
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 3c81922..67583a3 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -947,6 +947,10 @@
         WifiConfiguration existingInternalConfig = getInternalConfiguredNetwork(config);
         // No existing network found. So, potentially a network add.
         if (existingInternalConfig == null) {
+            if (!WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)) {
+                Log.e(TAG, "Cannot add network with invalid config");
+                return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
+            }
             newInternalConfig = createNewInternalWifiConfigurationFromExternal(config, uid);
             // Since the original config provided may have had an empty
             // {@link WifiConfiguration#allowedKeyMgmt} field, check again if we already have a
@@ -955,6 +959,11 @@
         }
         // Existing network found. So, a network update.
         if (existingInternalConfig != null) {
+            if (!WifiConfigurationUtil.validate(
+                    config, WifiConfigurationUtil.VALIDATE_FOR_UPDATE)) {
+                Log.e(TAG, "Cannot update network with invalid config");
+                return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
+            }
             // Check for the app's permission before we let it update this network.
             if (!canModifyNetwork(existingInternalConfig, uid, DISALLOW_LOCKDOWN_CHECK_BYPASS)) {
                 Log.e(TAG, "UID " + uid + " does not have permission to update configuration "
@@ -1046,8 +1055,8 @@
             Log.e(TAG, "UID " + uid + " not visible to the current user");
             return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
         }
-        if (!WifiConfigurationUtil.validate(config)) {
-            Log.e(TAG, "Cannot add/update network with invalid config");
+        if (config == null) {
+            Log.e(TAG, "Cannot add/update network with null config");
             return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
         }
         if (mPendingStoreRead) {
diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
index 3ff4d73..a7a527b 100644
--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java
+++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
@@ -254,10 +254,17 @@
         return false;
     }
 
-    private static boolean validateSsid(String ssid) {
-        if (ssid == null) {
-            Log.e(TAG, "validateSsid failed: null string");
-            return false;
+    private static boolean validateSsid(String ssid, boolean isAdd) {
+        if (isAdd) {
+            if (ssid == null) {
+                Log.e(TAG, "validateSsid : null string");
+                return false;
+            }
+        } else {
+            if (ssid == null) {
+                // This is an update, so the SSID can be null if that is not being changed.
+                return true;
+            }
         }
         if (ssid.isEmpty()) {
             Log.e(TAG, "validateSsid failed: empty string");
@@ -293,19 +300,26 @@
         return true;
     }
 
-    private static boolean validatePsk(String psk) {
-        if (psk == null) {
-            Log.e(TAG, "validatePsk failed: null string");
-            return false;
+    private static boolean validatePsk(String psk, boolean isAdd) {
+        if (isAdd) {
+            if (psk == null) {
+                Log.e(TAG, "validatePsk: null string");
+                return false;
+            }
+        } else {
+            if (psk == null) {
+                // This is an update, so the psk can be null if that is not being changed.
+                return true;
+            } else if (psk.equals(PASSWORD_MASK)) {
+                // This is an update, so the app might have returned back the masked password, let
+                // it thru. WifiConfigManager will handle it.
+                return true;
+            }
         }
         if (psk.isEmpty()) {
             Log.e(TAG, "validatePsk failed: empty string");
             return false;
         }
-        // The app returned back the masked password, let it thru. WifiConfigManager will handle it.
-        if (psk.equals(PASSWORD_MASK)) {
-            return true;
-        }
         if (psk.startsWith("\"")) {
             // ASCII PSK string
             if (psk.length() < PSK_ASCII_MIN_LEN) {
@@ -375,6 +389,12 @@
     }
 
     /**
+     * Enums to specify if the provided config is being validated for add or update.
+     */
+    public static final boolean VALIDATE_FOR_ADD = true;
+    public static final boolean VALIDATE_FOR_UPDATE = false;
+
+    /**
      * Validate the configuration received from an external application.
      *
      * This method checks for the following parameters:
@@ -382,22 +402,23 @@
      * 2. {@link WifiConfiguration#preSharedKey}
      * 3. {@link WifiConfiguration#allowedKeyManagement}
      * 4. {@link WifiConfiguration#getIpConfiguration()}
+     *
      * @param config {@link WifiConfiguration} received from an external application.
+     * @param isAdd {@link #VALIDATE_FOR_ADD} to indicate a network config received for an add,
+     *              {@link #VALIDATE_FOR_UPDATE} for a network config received for an update.
+     *              These 2 cases need to be handled differently because the config received for an
+     *              update could contain only the fields that are being changed.
      * @return true if the parameters are valid, false otherwise.
      */
-    public static boolean validate(WifiConfiguration config) {
-        if (config == null) {
-            Log.e(TAG, "validate failed: null WifiConfiguration");
-            return false;
-        }
-        if (!validateSsid(config.SSID)) {
+    public static boolean validate(WifiConfiguration config, boolean isAdd) {
+        if (!validateSsid(config.SSID, isAdd)) {
             return false;
         }
         if (!validateKeyMgmt(config.allowedKeyManagement)) {
             return false;
         }
         if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
-                && !validatePsk(config.preSharedKey)) {
+                && !validatePsk(config.preSharedKey, isAdd)) {
             return false;
         }
         if (!validateIpConfiguration(config.getIpConfiguration())) {
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
index 40e7d4f..cc3f709 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
@@ -195,10 +195,18 @@
      */
     @Test
     public void testValidatePositiveCases_Ascii() {
-        assertTrue(WifiConfigurationUtil.validate(WifiConfigurationTestUtil.createOpenNetwork()));
-        assertTrue(WifiConfigurationUtil.validate(WifiConfigurationTestUtil.createPskNetwork()));
-        assertTrue(WifiConfigurationUtil.validate(WifiConfigurationTestUtil.createWepNetwork()));
-        assertTrue(WifiConfigurationUtil.validate(WifiConfigurationTestUtil.createEapNetwork()));
+        assertTrue(WifiConfigurationUtil.validate(
+                WifiConfigurationTestUtil.createOpenNetwork(),
+                WifiConfigurationUtil.VALIDATE_FOR_ADD));
+        assertTrue(WifiConfigurationUtil.validate(
+                WifiConfigurationTestUtil.createPskNetwork(),
+                WifiConfigurationUtil.VALIDATE_FOR_ADD));
+        assertTrue(WifiConfigurationUtil.validate(
+                WifiConfigurationTestUtil.createWepNetwork(),
+                WifiConfigurationUtil.VALIDATE_FOR_ADD));
+        assertTrue(WifiConfigurationUtil.validate(
+                WifiConfigurationTestUtil.createEapNetwork(),
+                WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -211,19 +219,34 @@
         config.SSID = "abcd1234555a";
         config.preSharedKey = "abcd1234551512345567889900345566673323456673223445566767432334454"
                 + "abcd12345515123455678899003455666733234566732234455667674323344";
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
-     * Verify that the validate method validates WifiConfiguration with masked psk string.
+     * Verify that the validate method validates WifiConfiguration with masked psk string only for
+     * an update.
      */
     @Test
     public void testValidatePositiveCases_MaskedPskString() {
         WifiConfiguration config = WifiConfigurationTestUtil.createPskNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.preSharedKey = WifiConfigurationUtil.PASSWORD_MASK;
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
+        assertTrue(WifiConfigurationUtil.validate(
+                config, WifiConfigurationUtil.VALIDATE_FOR_UPDATE));
+    }
+
+    /**
+     * Verify that the validate method validates WifiConfiguration with null ssid only for an
+     * update.
+     */
+    @Test
+    public void testValidatePositiveCases_OnlyUpdateIgnoresNullSsid() {
+        WifiConfiguration config = new WifiConfiguration();
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
+        assertTrue(WifiConfigurationUtil.validate(
+                config, WifiConfigurationUtil.VALIDATE_FOR_UPDATE));
     }
 
     /**
@@ -232,12 +255,12 @@
     @Test
     public void testValidateNegativeCases_BadAsciiSsidLength() {
         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.SSID = "\"abcdfefeeretretyetretetetetetrertertrsreqwrwe\"";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
         config.SSID = "\"\"";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -247,10 +270,10 @@
     @Test
     public void testValidateNegativeCases_MalformedAsciiSsidString() {
         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.SSID = "\"ab";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -259,12 +282,12 @@
     @Test
     public void testValidateNegativeCases_BadHexSsidLength() {
         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.SSID = "abcdfe012345632423343543453456464545656464545646454ace34534545634535";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
         config.SSID = "";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -274,10 +297,10 @@
     @Test
     public void testValidateNegativeCases_MalformedHexSsidString() {
         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.SSID = "hello";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -286,13 +309,13 @@
     @Test
     public void testValidateNegativeCases_BadAsciiPskLength() {
         WifiConfiguration config = WifiConfigurationTestUtil.createPskNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.preSharedKey = "\"abcdffeeretretyetreteteteabe34tetrertertrsraaaaaaaaaaa345eqwrweewq"
                 + "weqe\"";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
         config.preSharedKey = "\"454\"";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -302,10 +325,10 @@
     @Test
     public void testValidateNegativeCases_MalformedAsciiPskString() {
         WifiConfiguration config = WifiConfigurationTestUtil.createPskNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.preSharedKey = "\"abcdfefeeretrety";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -314,12 +337,12 @@
     @Test
     public void testValidateNegativeCases_BadHexPskLength() {
         WifiConfiguration config = WifiConfigurationTestUtil.createPskNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.preSharedKey = "abcd123456788990013453445345465465476546";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
         config.preSharedKey = "";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -329,10 +352,10 @@
     @Test
     public void testValidateNegativeCases_MalformedHexPskString() {
         WifiConfiguration config = WifiConfigurationTestUtil.createPskNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.preSharedKey = "adbdfgretrtyrtyrty";
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -341,10 +364,10 @@
     @Test
     public void testValidateNegativeCases_BadKeyMgmtPskEap() {
         WifiConfiguration config = WifiConfigurationTestUtil.createPskNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -353,10 +376,10 @@
     @Test
     public void testValidateNegativeCases_BadKeyMgmtOpenPsk() {
         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -365,10 +388,10 @@
     @Test
     public void testValidateNegativeCases_BadKeyMgmt() {
         WifiConfiguration config = WifiConfigurationTestUtil.createPskNetwork();
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**
@@ -381,11 +404,11 @@
         IpConfiguration ipConfig =
                 WifiConfigurationTestUtil.createStaticIpConfigurationWithPacProxy();
         config.setIpConfiguration(ipConfig);
-        assertTrue(WifiConfigurationUtil.validate(config));
+        assertTrue(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
 
         ipConfig.setStaticIpConfiguration(null);
         config.setIpConfiguration(ipConfig);
-        assertFalse(WifiConfigurationUtil.validate(config));
+        assertFalse(WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD));
     }
 
     /**