diff --git a/Android.mk b/Android.mk index 313f329f50af3..8a530eb479cc4 100644 --- a/Android.mk +++ b/Android.mk @@ -609,6 +609,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ 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 8a4ef23238f57..06e3867e4ee30 100644 --- a/wifi/java/android/net/wifi/aware/DiscoverySession.java +++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java @@ -342,8 +342,8 @@ public class DiscoverySession implements AutoCloseable { */ 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 @@ public class DiscoverySession implements AutoCloseable { @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 678d2e6459017..babbed02a11c9 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java @@ -269,9 +269,10 @@ public class WifiAwareSession implements AutoCloseable { 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 @@ public class WifiAwareSession implements AutoCloseable { 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 40833887c09e7..fda7a9abc3181 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 @@ public class WifiAwareUtils { ++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 694b911a51e5a..d9433c5a9d000 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.net.wifi.RttManager; 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 @@ public class WifiAwareManagerTest { 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 @@ public class WifiAwareManagerTest { 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 sessionCaptor = ArgumentCaptor.forClass( @@ -1070,4 +1071,162 @@ public class WifiAwareManagerTest { 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 sessionCaptor = ArgumentCaptor.forClass( + WifiAwareSession.class); + ArgumentCaptor clientProxyCallback = ArgumentCaptor + .forClass(IWifiAwareEventCallback.class); + ArgumentCaptor sessionProxyCallback = ArgumentCaptor + .forClass(IWifiAwareDiscoverySessionCallback.class); + ArgumentCaptor 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 sessionCaptor = ArgumentCaptor.forClass( + WifiAwareSession.class); + ArgumentCaptor 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); + } + } }