[AWARE] Add validity check on PMK/Passphrase lengths

Bug: 62376042
Test: unit tests + inegrated (sl4a) tests
Change-Id: Ib6383a0ba9ef61114eb72b9a04cc683792b8e89d
diff --git a/Android.mk b/Android.mk
index 313f329..8a530eb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -609,6 +609,7 @@
     android.hardware.usb-V1.1-java-constants             \
     android.hardware.vibrator-V1.0-java-constants        \
     android.hardware.vibrator-V1.1-java-constants        \
+    android.hardware.wifi-V1.0-java-constants            \
 
 # Loaded with System.loadLibrary by android.view.textclassifier
 LOCAL_REQUIRED_MODULES += libtextclassifier
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index 8a4ef23..06e3867 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -342,8 +342,8 @@
      */
     public NetworkSpecifier createNetworkSpecifierPassphrase(
             @Nullable PeerHandle peerHandle, @NonNull String passphrase) {
-        if (passphrase == null || passphrase.length() == 0) {
-            throw new IllegalArgumentException("Passphrase must not be null or empty");
+        if (!WifiAwareUtils.validatePassphrase(passphrase)) {
+            throw new IllegalArgumentException("Passphrase must meet length requirements");
         }
 
         if (mTerminated) {
@@ -405,8 +405,8 @@
     @SystemApi
     public NetworkSpecifier createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle,
             @NonNull byte[] pmk) {
-        if (pmk == null || pmk.length == 0) {
-            throw new IllegalArgumentException("PMK must not be null or empty");
+        if (!WifiAwareUtils.validatePmk(pmk)) {
+            throw new IllegalArgumentException("PMK must 32 bytes");
         }
 
         if (mTerminated) {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 678d2e6..babbed0 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -269,9 +269,10 @@
             Log.e(TAG, "createNetworkSpecifierPassphrase: called after termination");
             return null;
         }
-        if (passphrase == null || passphrase.length() == 0) {
-            throw new IllegalArgumentException("Passphrase must not be null or empty");
+        if (!WifiAwareUtils.validatePassphrase(passphrase)) {
+            throw new IllegalArgumentException("Passphrase must meet length requirements");
         }
+
         return mgr.createNetworkSpecifier(mClientId, role, peer, null, passphrase);
     }
 
@@ -319,8 +320,8 @@
             Log.e(TAG, "createNetworkSpecifierPmk: called after termination");
             return null;
         }
-        if (pmk == null || pmk.length == 0) {
-            throw new IllegalArgumentException("PMK must not be null or empty");
+        if (!WifiAwareUtils.validatePmk(pmk)) {
+            throw new IllegalArgumentException("PMK must 32 bytes");
         }
         return mgr.createNetworkSpecifier(mClientId, role, peer, pmk, null);
     }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareUtils.java b/wifi/java/android/net/wifi/aware/WifiAwareUtils.java
index 4083388..fda7a9a 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareUtils.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareUtils.java
@@ -16,6 +16,8 @@
 
 package android.net.wifi.aware;
 
+import android.hardware.wifi.V1_0.Constants;
+
 /**
  * Provides utilities for the Wifi Aware manager/service.
  *
@@ -51,4 +53,35 @@
             ++index;
         }
     }
+
+    /**
+     * Validates that the passphrase is a non-null string of the right size (per the HAL min/max
+     * length parameters).
+     *
+     * @param passphrase Passphrase to test
+     * @return true if passphrase is valid, false if not
+     */
+    public static boolean validatePassphrase(String passphrase) {
+        if (passphrase == null
+                || passphrase.length() < Constants.NanParamSizeLimits.MIN_PASSPHRASE_LENGTH
+                || passphrase.length() > Constants.NanParamSizeLimits.MAX_PASSPHRASE_LENGTH) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Validates that the PMK is a non-null byte array of the right size (32 bytes per spec).
+     *
+     * @param pmk PMK to test
+     * @return true if PMK is valid, false if not
+     */
+    public static boolean validatePmk(byte[] pmk) {
+        if (pmk == null || pmk.length != 32) {
+            return false;
+        }
+
+        return true;
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 694b911..d9433c5 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -32,6 +32,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcel;
+import android.os.RemoteException;
 import android.os.test.TestLooper;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -938,7 +939,7 @@
         final int sessionId = 123;
         final PeerHandle peerHandle = new PeerHandle(123412);
         final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
-        final byte[] pmk = "Some arbitrary byte array".getBytes();
+        final byte[] pmk = "01234567890123456789012345678901".getBytes();
         final String passphrase = "A really bad password";
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final PublishConfig publishConfig = new PublishConfig.Builder().build();
@@ -1019,7 +1020,7 @@
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final byte[] someMac = HexEncoding.decode("000102030405".toCharArray(), false);
         final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
-        final byte[] pmk = "Some arbitrary pmk data".getBytes();
+        final byte[] pmk = "01234567890123456789012345678901".getBytes();
         final String passphrase = "A really bad password";
 
         ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
@@ -1070,4 +1071,162 @@
         verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
                 mockPublishSession, mockRttListener);
     }
+
+    /**
+     * Validate that a null PMK triggers an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testNetworkSpecifierWithClientNullPmk() throws Exception {
+        executeNetworkSpecifierWithClient(true, null, null);
+    }
+
+    /**
+     * Validate that a non-32-bytes PMK triggers an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testNetworkSpecifierWithClientIncorrectLengthPmk() throws Exception {
+        executeNetworkSpecifierWithClient(true, "012".getBytes(), null);
+    }
+
+    /**
+     * Validate that a null Passphrase triggers an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testNetworkSpecifierWithClientNullPassphrase() throws Exception {
+        executeNetworkSpecifierWithClient(false, null, null);
+    }
+
+    /**
+     * Validate that a too short Passphrase triggers an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testNetworkSpecifierWithClientShortPassphrase() throws Exception {
+        executeNetworkSpecifierWithClient(false, null, "012");
+    }
+
+    /**
+     * Validate that a too long Passphrase triggers an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testNetworkSpecifierWithClientLongPassphrase() throws Exception {
+        executeNetworkSpecifierWithClient(false, null,
+                "0123456789012345678901234567890123456789012345678901234567890123456789");
+    }
+
+    private void executeNetworkSpecifierWithClient(boolean doPmk, byte[] pmk, String passphrase)
+            throws Exception {
+        final int clientId = 4565;
+        final int sessionId = 123;
+        final PeerHandle peerHandle = new PeerHandle(123412);
+        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
+        final PublishConfig publishConfig = new PublishConfig.Builder().build();
+
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+        ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareDiscoverySessionCallback.class);
+        ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(PublishDiscoverySession.class);
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession, mockRttListener);
+
+        // (1) connect successfully
+        mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+        WifiAwareSession session = sessionCaptor.getValue();
+
+        // (2) publish successfully
+        session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
+        inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
+                sessionProxyCallback.capture());
+        sessionProxyCallback.getValue().onSessionStarted(sessionId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
+
+        // (3) create network specifier
+        if (doPmk) {
+            publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk);
+        } else {
+            publishSession.getValue().createNetworkSpecifierPassphrase(peerHandle, passphrase);
+        }
+    }
+
+    /**
+     * Validate that a null PMK triggers an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testNetworkSpecifierDirectNullPmk() throws Exception {
+        executeNetworkSpecifierDirect(true, null, null);
+    }
+
+    /**
+     * Validate that a non-32-bytes PMK triggers an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testNetworkSpecifierDirectIncorrectLengthPmk() throws Exception {
+        executeNetworkSpecifierDirect(true, "012".getBytes(), null);
+    }
+
+    /**
+     * Validate that a null Passphrase triggers an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testNetworkSpecifierDirectNullPassphrase() throws Exception {
+        executeNetworkSpecifierDirect(false, null, null);
+    }
+
+    /**
+     * Validate that a too short Passphrase triggers an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testNetworkSpecifierDirectShortPassphrase() throws Exception {
+        executeNetworkSpecifierDirect(false, null, "012");
+    }
+
+    /**
+     * Validate that a too long Passphrase triggers an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testNetworkSpecifierDirectLongPassphrase() throws Exception {
+        executeNetworkSpecifierDirect(false, null,
+                "0123456789012345678901234567890123456789012345678901234567890123456789");
+    }
+
+    private void executeNetworkSpecifierDirect(boolean doPmk, byte[] pmk, String passphrase)
+            throws Exception {
+        final int clientId = 134;
+        final byte[] someMac = HexEncoding.decode("000102030405".toCharArray(), false);
+        final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
+        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
+
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession, mockRttListener);
+
+        // (1) connect successfully
+        mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+
+        // (2) create network specifier
+        if (doPmk) {
+            sessionCaptor.getValue().createNetworkSpecifierPmk(role, someMac, pmk);
+        } else {
+            sessionCaptor.getValue().createNetworkSpecifierPassphrase(role, someMac, passphrase);
+        }
+    }
 }