softap: Add SAE and SAE transition mode in configuration

Bug: 142752869
Test: atest frameworks/base/wifi/tests/
Change-Id: I2eac1b7291554cd69db9833d494ba741a65d86c3
This commit is contained in:
lesl
2019-12-27 18:26:07 +08:00
committed by Les Lee
parent 005c68cf66
commit 3562952f83
4 changed files with 223 additions and 39 deletions

View File

@@ -5739,6 +5739,7 @@ package android.net.wifi {
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApCapability> CREATOR;
field public static final int SOFTAP_FEATURE_ACS_OFFLOAD = 1; // 0x1
field public static final int SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 2; // 0x2
field public static final int SOFTAP_FEATURE_WPA3_SAE = 4; // 0x4
}
public final class SoftApConfiguration implements android.os.Parcelable {
@@ -5747,6 +5748,7 @@ package android.net.wifi {
method @Nullable public android.net.MacAddress getBssid();
method public int getChannel();
method public int getMaxNumberOfClients();
method @Nullable public String getPassphrase();
method public int getSecurityType();
method @Nullable public String getSsid();
method @Nullable public String getWpa2Passphrase();
@@ -5759,6 +5761,8 @@ package android.net.wifi {
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApConfiguration> CREATOR;
field public static final int SECURITY_TYPE_OPEN = 0; // 0x0
field public static final int SECURITY_TYPE_WPA2_PSK = 1; // 0x1
field public static final int SECURITY_TYPE_WPA3_SAE = 3; // 0x3
field public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2; // 0x2
}
public static final class SoftApConfiguration.Builder {
@@ -5770,6 +5774,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setWpa2Passphrase(@Nullable String);
}

View File

@@ -61,11 +61,20 @@ public final class SoftApCapability implements Parcelable {
*/
public static final int SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 1 << 1;
/**
* Support for WPA3 Simultaneous Authentication of Equals (WPA3-SAE).
*
* flag when {@link config_wifi_softap_sae_supported)} is true.
*/
public static final int SOFTAP_FEATURE_WPA3_SAE = 1 << 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "SOFTAP_FEATURE_" }, value = {
SOFTAP_FEATURE_ACS_OFFLOAD,
SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT,
SOFTAP_FEATURE_WPA3_SAE,
})
public @interface HotspotFeatures {}

View File

@@ -25,6 +25,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
@@ -55,6 +56,11 @@ import java.util.concurrent.Executor;
@SystemApi
public final class SoftApConfiguration implements Parcelable {
@VisibleForTesting
static final int PSK_MIN_LEN = 8;
@VisibleForTesting
static final int PSK_MAX_LEN = 63;
/**
* 2GHz band.
* @hide
@@ -142,9 +148,10 @@ public final class SoftApConfiguration implements Parcelable {
private final @Nullable MacAddress mBssid;
/**
* Pre-shared key for WPA2-PSK encryption (non-null enables WPA2-PSK).
* Pre-shared key for WPA2-PSK or WPA3-SAE-Transition or WPA3-SAE encryption which depends on
* the security type.
*/
private final @Nullable String mWpa2Passphrase;
private final @Nullable String mPassphrase;
/**
* This is a network that does not broadcast its SSID, so an
@@ -185,21 +192,31 @@ public final class SoftApConfiguration implements Parcelable {
@SystemApi
public static final int SECURITY_TYPE_WPA2_PSK = 1;
/** @hide */
@SystemApi
public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2;
/** @hide */
@SystemApi
public static final int SECURITY_TYPE_WPA3_SAE = 3;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "SECURITY_TYPE" }, value = {
@IntDef(prefix = { "SECURITY_TYPE_" }, value = {
SECURITY_TYPE_OPEN,
SECURITY_TYPE_WPA2_PSK,
SECURITY_TYPE_WPA3_SAE_TRANSITION,
SECURITY_TYPE_WPA3_SAE,
})
public @interface SecurityType {}
/** Private constructor for Builder and Parcelable implementation. */
private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
@Nullable String wpa2Passphrase, boolean hiddenSsid, @BandType int band, int channel,
@Nullable String passphrase, boolean hiddenSsid, @BandType int band, int channel,
@SecurityType int securityType, int maxNumberOfClients) {
mSsid = ssid;
mBssid = bssid;
mWpa2Passphrase = wpa2Passphrase;
mPassphrase = passphrase;
mHiddenSsid = hiddenSsid;
mBand = band;
mChannel = channel;
@@ -218,7 +235,7 @@ public final class SoftApConfiguration implements Parcelable {
SoftApConfiguration other = (SoftApConfiguration) otherObj;
return Objects.equals(mSsid, other.mSsid)
&& Objects.equals(mBssid, other.mBssid)
&& Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase)
&& Objects.equals(mPassphrase, other.mPassphrase)
&& mHiddenSsid == other.mHiddenSsid
&& mBand == other.mBand
&& mChannel == other.mChannel
@@ -228,7 +245,7 @@ public final class SoftApConfiguration implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(mSsid, mBssid, mWpa2Passphrase, mHiddenSsid,
return Objects.hash(mSsid, mBssid, mPassphrase, mHiddenSsid,
mBand, mChannel, mSecurityType, mMaxNumberOfClients);
}
@@ -237,8 +254,8 @@ public final class SoftApConfiguration implements Parcelable {
StringBuilder sbuf = new StringBuilder();
sbuf.append("ssid=").append(mSsid);
if (mBssid != null) sbuf.append(" \n bssid=").append(mBssid.toString());
sbuf.append(" \n Wpa2Passphrase =").append(
TextUtils.isEmpty(mWpa2Passphrase) ? "<empty>" : "<non-empty>");
sbuf.append(" \n Passphrase =").append(
TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>");
sbuf.append(" \n HiddenSsid =").append(mHiddenSsid);
sbuf.append(" \n Band =").append(mBand);
sbuf.append(" \n Channel =").append(mChannel);
@@ -251,7 +268,7 @@ public final class SoftApConfiguration implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mSsid);
dest.writeParcelable(mBssid, flags);
dest.writeString(mWpa2Passphrase);
dest.writeString(mPassphrase);
dest.writeBoolean(mHiddenSsid);
dest.writeInt(mBand);
dest.writeInt(mChannel);
@@ -299,13 +316,26 @@ public final class SoftApConfiguration implements Parcelable {
return mBssid;
}
// TODO: Remove it after update the caller
/**
* Returns String set to be passphrase for the WPA2-PSK AP.
* {@link Builder#setWpa2Passphrase(String)}.
* {@link #setWpa2Passphrase(String)}.
*/
@Nullable
public String getWpa2Passphrase() {
return mWpa2Passphrase;
if (mSecurityType == SECURITY_TYPE_WPA2_PSK) {
return mPassphrase;
}
return null;
}
/**
* Returns String set to be passphrase for current AP.
* {@link #setPassphrase(String, @SecurityType int)}.
*/
@Nullable
public String getPassphrase() {
return mPassphrase;
}
/**
@@ -360,23 +390,12 @@ public final class SoftApConfiguration implements Parcelable {
public static final class Builder {
private String mSsid;
private MacAddress mBssid;
private String mWpa2Passphrase;
private String mPassphrase;
private boolean mHiddenSsid;
private int mBand;
private int mChannel;
private int mMaxNumberOfClients;
private int setSecurityType() {
int securityType = SECURITY_TYPE_OPEN;
if (!TextUtils.isEmpty(mWpa2Passphrase)) { // WPA2-PSK network.
securityType = SECURITY_TYPE_WPA2_PSK;
}
return securityType;
}
private void clearAllPassphrase() {
mWpa2Passphrase = null;
}
private int mSecurityType;
/**
* Constructs a Builder with default values (see {@link Builder}).
@@ -384,11 +403,12 @@ public final class SoftApConfiguration implements Parcelable {
public Builder() {
mSsid = null;
mBssid = null;
mWpa2Passphrase = null;
mPassphrase = null;
mHiddenSsid = false;
mBand = BAND_2GHZ;
mChannel = 0;
mMaxNumberOfClients = 0;
mSecurityType = SECURITY_TYPE_OPEN;
}
/**
@@ -399,11 +419,12 @@ public final class SoftApConfiguration implements Parcelable {
mSsid = other.mSsid;
mBssid = other.mBssid;
mWpa2Passphrase = other.mWpa2Passphrase;
mPassphrase = other.mPassphrase;
mHiddenSsid = other.mHiddenSsid;
mBand = other.mBand;
mChannel = other.mChannel;
mMaxNumberOfClients = other.mMaxNumberOfClients;
mSecurityType = other.mSecurityType;
}
/**
@@ -413,8 +434,8 @@ public final class SoftApConfiguration implements Parcelable {
*/
@NonNull
public SoftApConfiguration build() {
return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase,
mHiddenSsid, mBand, mChannel, setSecurityType(), mMaxNumberOfClients);
return new SoftApConfiguration(mSsid, mBssid, mPassphrase,
mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients);
}
/**
@@ -461,6 +482,7 @@ public final class SoftApConfiguration implements Parcelable {
return this;
}
// TODO: Remove it after update the caller
/**
* Specifies that this AP should use WPA2-PSK with the given ASCII WPA2 passphrase.
* When set to null, an open network is created.
@@ -473,15 +495,47 @@ public final class SoftApConfiguration implements Parcelable {
*/
@NonNull
public Builder setWpa2Passphrase(@Nullable String passphrase) {
if (passphrase != null) {
return setPassphrase(passphrase, SECURITY_TYPE_WPA2_PSK);
}
/**
* Specifies that this AP should use specific security type with the given ASCII passphrase.
*
* @param securityType one of the security types from {@link @SecurityType}.
* @param passphrase The passphrase to use for sepcific {@link @SecurityType} configuration
* or null with {@link @SecurityType#SECURITY_TYPE_OPEN}.
*
* @return Builder for chaining.
* @throws IllegalArgumentException when the passphrase length is invalid and
* {@code securityType} is not {@link @SecurityType#SECURITY_TYPE_OPEN}
* or non-null passphrase and {@code securityType} is
* {@link @SecurityType#SECURITY_TYPE_OPEN}.
*/
@NonNull
public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) {
if (securityType == SECURITY_TYPE_OPEN) {
if (passphrase != null) {
throw new IllegalArgumentException(
"passphrase should be null when security type is open");
}
} else {
Preconditions.checkStringNotEmpty(passphrase);
final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
if (!asciiEncoder.canEncode(passphrase)) {
throw new IllegalArgumentException("passphrase not ASCII encodable");
}
Preconditions.checkStringNotEmpty(passphrase);
if (securityType == SECURITY_TYPE_WPA2_PSK
|| securityType == SECURITY_TYPE_WPA3_SAE_TRANSITION) {
if (passphrase.length() < PSK_MIN_LEN || passphrase.length() > PSK_MAX_LEN) {
throw new IllegalArgumentException(
"Password size must be at least " + PSK_MIN_LEN
+ " and no more than " + PSK_MAX_LEN
+ " for WPA2_PSK and WPA3_SAE_TRANSITION Mode");
}
}
}
clearAllPassphrase();
mWpa2Passphrase = passphrase;
mSecurityType = securityType;
mPassphrase = passphrase;
return this;
}

View File

@@ -25,8 +25,12 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
import java.util.Random;
@SmallTest
public class SoftApConfigurationTest {
private static final String TEST_CHAR_SET_AS_STRING = "abcdefghijklmnopqrstuvwxyz0123456789";
private SoftApConfiguration parcelUnparcel(SoftApConfiguration configIn) {
Parcel parcel = Parcel.obtain();
parcel.writeParcelable(configIn, 0);
@@ -37,6 +41,25 @@ public class SoftApConfigurationTest {
return configOut;
}
/**
* Helper method to generate random string.
*
* Note: this method has limited use as a random string generator.
* The characters used in this method do no not cover all valid inputs.
* @param length number of characters to generate for the string
* @return String generated string of random characters
*/
private String generateRandomString(int length) {
Random random = new Random();
StringBuilder stringBuilder = new StringBuilder(length);
int index = -1;
while (stringBuilder.length() < length) {
index = random.nextInt(TEST_CHAR_SET_AS_STRING.length());
stringBuilder.append(TEST_CHAR_SET_AS_STRING.charAt(index));
}
return stringBuilder.toString();
}
@Test
public void testBasicSettings() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
@@ -45,7 +68,7 @@ public class SoftApConfigurationTest {
.build();
assertThat(original.getSsid()).isEqualTo("ssid");
assertThat(original.getBssid()).isEqualTo(MacAddress.fromString("11:22:33:44:55:66"));
assertThat(original.getWpa2Passphrase()).isNull();
assertThat(original.getPassphrase()).isNull();
assertThat(original.getSecurityType()).isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
assertThat(original.getChannel()).isEqualTo(0);
@@ -66,9 +89,9 @@ public class SoftApConfigurationTest {
@Test
public void testWpa2() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
.setWpa2Passphrase("secretsecret")
.setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
.build();
assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
assertThat(original.getPassphrase()).isEqualTo("secretsecret");
assertThat(original.getSecurityType()).isEqualTo(
SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
@@ -90,13 +113,12 @@ public class SoftApConfigurationTest {
@Test
public void testWpa2WithAllFieldCustomized() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
.setWpa2Passphrase("secretsecret")
.setBand(SoftApConfiguration.BAND_ANY)
.setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
.setChannel(149, SoftApConfiguration.BAND_5GHZ)
.setHiddenSsid(true)
.setMaxNumberOfClients(10)
.build();
assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
assertThat(original.getPassphrase()).isEqualTo("secretsecret");
assertThat(original.getSecurityType()).isEqualTo(
SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
@@ -114,4 +136,98 @@ public class SoftApConfigurationTest {
assertThat(copy).isEqualTo(original);
assertThat(copy.hashCode()).isEqualTo(original.hashCode());
}
@Test
public void testWpa3Sae() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
.setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)
.setChannel(149, SoftApConfiguration.BAND_5GHZ)
.setHiddenSsid(true)
.build();
assertThat(original.getPassphrase()).isEqualTo("secretsecret");
assertThat(original.getSecurityType()).isEqualTo(
SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
assertThat(original.getChannel()).isEqualTo(149);
assertThat(original.isHiddenSsid()).isEqualTo(true);
SoftApConfiguration unparceled = parcelUnparcel(original);
assertThat(unparceled).isNotSameAs(original);
assertThat(unparceled).isEqualTo(original);
assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
assertThat(copy).isNotSameAs(original);
assertThat(copy).isEqualTo(original);
assertThat(copy.hashCode()).isEqualTo(original.hashCode());
}
@Test
public void testWpa3SaeTransition() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
.setPassphrase("secretsecret",
SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
.setChannel(149, SoftApConfiguration.BAND_5GHZ)
.setHiddenSsid(true)
.build();
assertThat(original.getSecurityType()).isEqualTo(
SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
assertThat(original.getPassphrase()).isEqualTo("secretsecret");
assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
assertThat(original.getChannel()).isEqualTo(149);
assertThat(original.isHiddenSsid()).isEqualTo(true);
SoftApConfiguration unparceled = parcelUnparcel(original);
assertThat(unparceled).isNotSameAs(original);
assertThat(unparceled).isEqualTo(original);
assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
assertThat(copy).isNotSameAs(original);
assertThat(copy).isEqualTo(original);
assertThat(copy.hashCode()).isEqualTo(original.hashCode());
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidShortPasswordLengthForWpa2() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
.setPassphrase(generateRandomString(SoftApConfiguration.PSK_MIN_LEN - 1),
SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
.setChannel(149, SoftApConfiguration.BAND_5GHZ)
.setHiddenSsid(true)
.build();
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidLongPasswordLengthForWpa2() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
.setPassphrase(generateRandomString(SoftApConfiguration.PSK_MAX_LEN + 1),
SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
.setChannel(149, SoftApConfiguration.BAND_5GHZ)
.setHiddenSsid(true)
.build();
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidShortPasswordLengthForWpa3SaeTransition() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
.setPassphrase(generateRandomString(SoftApConfiguration.PSK_MIN_LEN - 1),
SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
.setChannel(149, SoftApConfiguration.BAND_5GHZ)
.setHiddenSsid(true)
.build();
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidLongPasswordLengthForWpa3SaeTransition() {
SoftApConfiguration original = new SoftApConfiguration.Builder()
.setPassphrase(generateRandomString(SoftApConfiguration.PSK_MAX_LEN + 1),
SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
.setChannel(149, SoftApConfiguration.BAND_5GHZ)
.setHiddenSsid(true)
.build();
}
}