Support OWE in transition mode for devices with OWE support and devices without OWE support. Scan results will return a new type of network for OWE in transition networks on devices that support OWE, and Open for devices that don't support OWE. Handle the case where Open network is manually added to a device that supports OWE. Bug: 132139642 Test: Device with OWE: Connect to Open, OWE-Transition, OWE networks Test: Device without OWE: Connect to Open, OWE-Transition Test: Manually create Open network, connect to OWE-Transition Change-Id: I1a584ccbfec8507803c527ea13933cff6f699ccb
287 lines
12 KiB
Java
287 lines
12 KiB
Java
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.settings.wifi;
|
|
|
|
import android.app.admin.DevicePolicyManager;
|
|
import android.content.ComponentName;
|
|
import android.content.ContentResolver;
|
|
import android.content.Context;
|
|
import android.content.pm.PackageManager;
|
|
import android.net.NetworkCapabilities;
|
|
import android.net.wifi.ScanResult;
|
|
import android.net.wifi.WifiConfiguration;
|
|
import android.provider.Settings;
|
|
import android.text.TextUtils;
|
|
|
|
import com.android.settingslib.wifi.AccessPoint;
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
public class WifiUtils {
|
|
|
|
private static final int SSID_ASCII_MIN_LENGTH = 1;
|
|
private static final int SSID_ASCII_MAX_LENGTH = 32;
|
|
private static final int PASSWORD_MIN_LENGTH = 8;
|
|
private static final int PASSWORD_MAX_LENGTH = 63;
|
|
|
|
|
|
public static boolean isSSIDTooLong(String ssid) {
|
|
if (TextUtils.isEmpty(ssid)) {
|
|
return false;
|
|
}
|
|
return ssid.getBytes(StandardCharsets.UTF_8).length > SSID_ASCII_MAX_LENGTH;
|
|
}
|
|
|
|
public static boolean isSSIDTooShort(String ssid) {
|
|
if (TextUtils.isEmpty(ssid)) {
|
|
return true;
|
|
}
|
|
return ssid.length() < SSID_ASCII_MIN_LENGTH;
|
|
}
|
|
|
|
public static boolean isHotspotPasswordValid(String password) {
|
|
if (TextUtils.isEmpty(password)) {
|
|
return false;
|
|
}
|
|
|
|
final int length = password.length();
|
|
return length >= PASSWORD_MIN_LENGTH && length <= PASSWORD_MAX_LENGTH;
|
|
}
|
|
|
|
/**
|
|
* This method is a stripped and negated version of WifiConfigStore.canModifyNetwork.
|
|
*
|
|
* @param context Context of caller
|
|
* @param config The WiFi config.
|
|
* @return true if Settings cannot modify the config due to lockDown.
|
|
*/
|
|
public static boolean isNetworkLockedDown(Context context, WifiConfiguration config) {
|
|
if (config == null) {
|
|
return false;
|
|
}
|
|
|
|
final DevicePolicyManager dpm =
|
|
(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
|
|
final PackageManager pm = context.getPackageManager();
|
|
|
|
// Check if device has DPM capability. If it has and dpm is still null, then we
|
|
// treat this case with suspicion and bail out.
|
|
if (pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) && dpm == null) {
|
|
return true;
|
|
}
|
|
|
|
boolean isConfigEligibleForLockdown = false;
|
|
if (dpm != null) {
|
|
final ComponentName deviceOwner = dpm.getDeviceOwnerComponentOnAnyUser();
|
|
if (deviceOwner != null) {
|
|
final int deviceOwnerUserId = dpm.getDeviceOwnerUserId();
|
|
try {
|
|
final int deviceOwnerUid = pm.getPackageUidAsUser(deviceOwner.getPackageName(),
|
|
deviceOwnerUserId);
|
|
isConfigEligibleForLockdown = deviceOwnerUid == config.creatorUid;
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
// don't care
|
|
}
|
|
}
|
|
}
|
|
if (!isConfigEligibleForLockdown) {
|
|
return false;
|
|
}
|
|
|
|
final ContentResolver resolver = context.getContentResolver();
|
|
final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver,
|
|
Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0;
|
|
return isLockdownFeatureEnabled;
|
|
}
|
|
|
|
/** Returns true if the provided NetworkCapabilities indicate a captive portal network. */
|
|
public static boolean canSignIntoNetwork(NetworkCapabilities capabilities) {
|
|
return (capabilities != null
|
|
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL));
|
|
}
|
|
|
|
/**
|
|
* Provides a simple way to generate a new {@link WifiConfiguration} obj from
|
|
* {@link ScanResult} or {@link AccessPoint}. Either {@code accessPoint} or {@code scanResult
|
|
* } input should be not null for retrieving information, otherwise will throw
|
|
* IllegalArgumentException.
|
|
* This method prefers to take {@link AccessPoint} input in priority. Therefore this method
|
|
* will take {@link AccessPoint} input as preferred data extraction source when you input
|
|
* both {@link AccessPoint} and {@link ScanResult}, and ignore {@link ScanResult} input.
|
|
*
|
|
* Duplicated and simplified method from {@link WifiConfigController#getConfig()}.
|
|
* TODO(b/120827021): Should be removed if the there is have a common one in shared place (e.g.
|
|
* SettingsLib).
|
|
*
|
|
* @param accessPoint Input data for retrieving WifiConfiguration.
|
|
* @param scanResult Input data for retrieving WifiConfiguration.
|
|
* @return WifiConfiguration obj based on input.
|
|
*/
|
|
public static WifiConfiguration getWifiConfig(AccessPoint accessPoint, ScanResult scanResult,
|
|
String password) {
|
|
if (accessPoint == null && scanResult == null) {
|
|
throw new IllegalArgumentException(
|
|
"At least one of AccessPoint and ScanResult input is required.");
|
|
}
|
|
|
|
final WifiConfiguration config = new WifiConfiguration();
|
|
final int security;
|
|
|
|
if (accessPoint == null) {
|
|
config.SSID = AccessPoint.convertToQuotedString(scanResult.SSID);
|
|
security = getAccessPointSecurity(scanResult);
|
|
} else {
|
|
if (!accessPoint.isSaved()) {
|
|
config.SSID = AccessPoint.convertToQuotedString(
|
|
accessPoint.getSsidStr());
|
|
} else {
|
|
config.networkId = accessPoint.getConfig().networkId;
|
|
config.hiddenSSID = accessPoint.getConfig().hiddenSSID;
|
|
}
|
|
security = accessPoint.getSecurity();
|
|
}
|
|
|
|
switch (security) {
|
|
case AccessPoint.SECURITY_NONE:
|
|
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
|
|
break;
|
|
|
|
case AccessPoint.SECURITY_WEP:
|
|
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
|
|
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
|
|
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
|
|
if (!TextUtils.isEmpty(password)) {
|
|
int length = password.length();
|
|
// WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
|
|
if ((length == 10 || length == 26 || length == 58)
|
|
&& password.matches("[0-9A-Fa-f]*")) {
|
|
config.wepKeys[0] = password;
|
|
} else {
|
|
config.wepKeys[0] = '"' + password + '"';
|
|
}
|
|
}
|
|
break;
|
|
|
|
case AccessPoint.SECURITY_PSK:
|
|
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
|
|
if (!TextUtils.isEmpty(password)) {
|
|
if (password.matches("[0-9A-Fa-f]{64}")) {
|
|
config.preSharedKey = password;
|
|
} else {
|
|
config.preSharedKey = '"' + password + '"';
|
|
}
|
|
}
|
|
break;
|
|
|
|
case AccessPoint.SECURITY_EAP:
|
|
case AccessPoint.SECURITY_EAP_SUITE_B:
|
|
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
|
|
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
|
|
if (security == AccessPoint.SECURITY_EAP_SUITE_B) {
|
|
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
|
|
config.requirePMF = true;
|
|
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
|
|
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
|
|
config.allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher
|
|
.BIP_GMAC_256);
|
|
// allowedSuiteBCiphers will be set according to certificate type
|
|
}
|
|
|
|
if (!TextUtils.isEmpty(password)) {
|
|
config.enterpriseConfig.setPassword(password);
|
|
}
|
|
break;
|
|
case AccessPoint.SECURITY_SAE:
|
|
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
|
|
config.requirePMF = true;
|
|
if (!TextUtils.isEmpty(password)) {
|
|
config.preSharedKey = '"' + password + '"';
|
|
}
|
|
break;
|
|
|
|
case AccessPoint.SECURITY_OWE:
|
|
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
|
|
config.requirePMF = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return config;
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets security value from ScanResult.
|
|
*
|
|
* Duplicated method from {@link AccessPoint#getSecurity(ScanResult)}.
|
|
* TODO(b/120827021): Should be removed if the there is have a common one in shared place (e.g.
|
|
* SettingsLib).
|
|
*
|
|
* @param result ScanResult
|
|
* @return Related security value based on {@link AccessPoint}.
|
|
*/
|
|
public static int getAccessPointSecurity(ScanResult result) {
|
|
if (result.capabilities.contains("WEP")) {
|
|
return AccessPoint.SECURITY_WEP;
|
|
} else if (result.capabilities.contains("SAE")) {
|
|
return AccessPoint.SECURITY_SAE;
|
|
} else if (result.capabilities.contains("PSK")) {
|
|
return AccessPoint.SECURITY_PSK;
|
|
} else if (result.capabilities.contains("EAP_SUITE_B_192")) {
|
|
return AccessPoint.SECURITY_EAP_SUITE_B;
|
|
} else if (result.capabilities.contains("EAP")) {
|
|
return AccessPoint.SECURITY_EAP;
|
|
} else if (result.capabilities.contains("OWE")) {
|
|
return AccessPoint.SECURITY_OWE;
|
|
}
|
|
|
|
return AccessPoint.SECURITY_NONE;
|
|
}
|
|
|
|
|
|
public static final int CONNECT_TYPE_OTHERS = 0;
|
|
public static final int CONNECT_TYPE_OPEN_NETWORK = 1;
|
|
public static final int CONNECT_TYPE_SAVED_NETWORK = 2;
|
|
public static final int CONNECT_TYPE_OSU_PROVISION = 3;
|
|
|
|
/**
|
|
* Gets the connecting type of {@link AccessPoint}.
|
|
*/
|
|
public static int getConnectingType(AccessPoint accessPoint) {
|
|
final WifiConfiguration config = accessPoint.getConfig();
|
|
if (accessPoint.isOsuProvider()) {
|
|
return CONNECT_TYPE_OSU_PROVISION;
|
|
} else if ((accessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
|
|
(accessPoint.getSecurity() == AccessPoint.SECURITY_OWE) ||
|
|
(accessPoint.getSecurity() == AccessPoint.SECURITY_OWE_TRANSITION)) {
|
|
return CONNECT_TYPE_OPEN_NETWORK;
|
|
} else if (accessPoint.isSaved() && config != null
|
|
&& config.getNetworkSelectionStatus() != null
|
|
&& config.getNetworkSelectionStatus().getHasEverConnected()) {
|
|
return CONNECT_TYPE_SAVED_NETWORK;
|
|
} else if (accessPoint.isPasspoint()) {
|
|
// Access point provided by an installed Passpoint provider, connect using
|
|
// the associated config.
|
|
return CONNECT_TYPE_SAVED_NETWORK;
|
|
} else {
|
|
return CONNECT_TYPE_OTHERS;
|
|
}
|
|
}
|
|
}
|