Merge changes from topics "wifi-dpm-grant", "wifi-keychain" into sc-dev

* changes:
  Allow WiFi module to request grants from KeyChain
  DPM API to grant keys to Wifi
This commit is contained in:
Pavel Grafov
2021-03-06 12:12:14 +00:00
committed by Android (Google) Code Review
8 changed files with 188 additions and 6 deletions

View File

@@ -7121,6 +7121,7 @@ package android.app.admin {
method @NonNull public android.os.Bundle getUserRestrictions(@NonNull android.content.ComponentName);
method @Nullable public String getWifiMacAddress(@NonNull android.content.ComponentName);
method public boolean grantKeyPairToApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
method public boolean grantKeyPairToWifiAuth(@NonNull String);
method public boolean hasCaCertInstalled(@Nullable android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(@NonNull android.content.ComponentName, int);
method public boolean hasKeyPair(@NonNull String);
@@ -7143,6 +7144,7 @@ package android.app.admin {
method public boolean isDeviceIdAttestationSupported();
method public boolean isDeviceOwnerApp(String);
method public boolean isEphemeralUser(@NonNull android.content.ComponentName);
method public boolean isKeyPairGrantedToWifiAuth(@NonNull String);
method public boolean isLockTaskPermitted(String);
method public boolean isLogoutEnabled();
method public boolean isManagedProfile(@NonNull android.content.ComponentName);
@@ -7178,6 +7180,7 @@ package android.app.admin {
method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(@NonNull android.content.ComponentName);
method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(@NonNull android.content.ComponentName);
method public boolean revokeKeyPairFromApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
method public boolean revokeKeyPairFromWifiAuth(@NonNull String);
method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean);
method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;

View File

@@ -9198,6 +9198,15 @@ package android.se.omapi {
}
package android.security {
public final class KeyChain {
method @Nullable @WorkerThread public static String getWifiKeyGrantAsUser(@NonNull android.content.Context, @NonNull android.os.UserHandle, @NonNull String);
method @WorkerThread public static boolean hasWifiKeyGrantAsUser(@NonNull android.content.Context, @NonNull android.os.UserHandle, @NonNull String);
}
}
package android.security.keystore {
public class AndroidKeyStoreProvider extends java.security.Provider {

View File

@@ -6437,6 +6437,74 @@ public class DevicePolicyManager {
return false;
}
/**
* Called by a device or profile owner, or delegated certificate chooser (an app that has been
* delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to allow using a KeyChain key
* pair for authentication to Wifi networks. The key can then be used in configurations passed
* to {@link android.net.wifi.WifiManager#addNetwork}.
*
* @param alias The alias of the key pair.
* @return {@code true} if the operation was set successfully, {@code false} otherwise.
*
* @throws SecurityException if the caller is not a device owner, a profile owner or
* delegated certificate chooser.
* @see #revokeKeyPairFromWifiAuth
*/
public boolean grantKeyPairToWifiAuth(@NonNull String alias) {
throwIfParentInstance("grantKeyPairToWifiAuth");
try {
return mService.setKeyGrantToWifiAuth(mContext.getPackageName(), alias, true);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
return false;
}
/**
* Called by a device or profile owner, or delegated certificate chooser (an app that has been
* delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to deny using a KeyChain key
* pair for authentication to Wifi networks. Configured networks using this key won't be able to
* authenticate.
*
* @param alias The alias of the key pair.
* @return {@code true} if the operation was set successfully, {@code false} otherwise.
*
* @throws SecurityException if the caller is not a device owner, a profile owner or
* delegated certificate chooser.
* @see #grantKeyPairToWifiAuth
*/
public boolean revokeKeyPairFromWifiAuth(@NonNull String alias) {
throwIfParentInstance("revokeKeyPairFromWifiAuth");
try {
return mService.setKeyGrantToWifiAuth(mContext.getPackageName(), alias, false);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
return false;
}
/**
* Called by a device or profile owner, or delegated certificate chooser (an app that has been
* delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to query whether a KeyChain key
* pair can be used for authentication to Wifi networks.
*
* @param alias The alias of the key pair.
* @return {@code true} if the key pair can be used, {@code false} otherwise.
*
* @throws SecurityException if the caller is not a device owner, a profile owner or
* delegated certificate chooser.
* @see #grantKeyPairToWifiAuth
*/
public boolean isKeyPairGrantedToWifiAuth(@NonNull String alias) {
throwIfParentInstance("isKeyPairGrantedToWifiAuth");
try {
return mService.isKeyPairGrantedToWifiAuth(mContext.getPackageName(), alias);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
return false;
}
/**
* Returns {@code true} if the device supports attestation of device identifiers in addition
* to key attestation. See

View File

@@ -479,6 +479,8 @@ interface IDevicePolicyManager {
boolean setKeyGrantForApp(in ComponentName admin, String callerPackage, String alias, String packageName, boolean hasGrant);
List<String> getKeyPairGrants(in String callerPackage, in String alias);
boolean setKeyGrantToWifiAuth(String callerPackage, String alias, boolean hasGrant);
boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias);
void setUserControlDisabledPackages(in ComponentName admin, in List<String> packages);

View File

@@ -68,4 +68,7 @@ interface IKeyChainService {
// APIs used by KeyChainActivity
void setGrant(int uid, String alias, boolean value);
boolean hasGrant(int uid, String alias);
// API used by Wifi
String getWifiKeyGrantAsUser(String alias);
}

View File

@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
import android.app.Activity;
@@ -1012,6 +1013,54 @@ public final class KeyChain {
return bindAsUser(context, null, user);
}
/**
* Returns a persistable grant string that allows WiFi stack to access the key using Keystore
* SSL engine.
*
* @return grant string or null if key is not granted or doesn't exist.
*
* The key should be granted to Process.WIFI_UID.
* @hide
*/
@SystemApi
@Nullable
@WorkerThread
public static String getWifiKeyGrantAsUser(
@NonNull Context context, @NonNull UserHandle user, @NonNull String alias) {
try (KeyChainConnection keyChainConnection =
bindAsUser(context.getApplicationContext(), user)) {
return keyChainConnection.getService().getWifiKeyGrantAsUser(alias);
} catch (RemoteException | RuntimeException e) {
Log.i(LOG, "Couldn't get grant for wifi", e);
return null;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
Log.i(LOG, "Interrupted while getting grant for wifi", e);
return null;
}
}
/**
* Returns whether the key is granted to WiFi stack.
* @hide
*/
@SystemApi
@WorkerThread
public static boolean hasWifiKeyGrantAsUser(
@NonNull Context context, @NonNull UserHandle user, @NonNull String alias) {
try (KeyChainConnection keyChainConnection =
bindAsUser(context.getApplicationContext(), user)) {
return keyChainConnection.getService().hasGrant(Process.WIFI_UID, alias);
} catch (RemoteException | RuntimeException e) {
Log.i(LOG, "Couldn't query grant for wifi", e);
return false;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
Log.i(LOG, "Interrupted while querying grant for wifi", e);
return false;
}
}
/**
* Bind to KeyChainService in the target user.
* Caller should call unbindService on the result when finished.

View File

@@ -143,4 +143,14 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
return false;
}
@Override
public boolean setKeyGrantToWifiAuth(String callerPackage, String alias, boolean hasGrant) {
return false;
}
@Override
public boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias) {
return false;
}
}

View File

@@ -5460,6 +5460,42 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|| isCallerDelegate(caller, DELEGATION_CERT_INSTALL);
}
@Override
public boolean setKeyGrantToWifiAuth(String callerPackage, String alias, boolean hasGrant) {
Preconditions.checkStringNotEmpty(alias, "Alias to grant cannot be empty");
final CallerIdentity caller = getCallerIdentity(callerPackage);
Preconditions.checkCallAuthorization(canManageCertificates(caller));
return setKeyChainGrantInternal(alias, hasGrant, Process.WIFI_UID, caller.getUserHandle());
}
@Override
public boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias) {
Preconditions.checkStringNotEmpty(alias, "Alias to check cannot be empty");
final CallerIdentity caller = getCallerIdentity(callerPackage);
Preconditions.checkCallAuthorization(canManageCertificates(caller));
return mInjector.binderWithCleanCallingIdentity(() -> {
try (KeyChainConnection keyChainConnection =
KeyChain.bindAsUser(mContext, caller.getUserHandle())) {
final List<String> result = new ArrayList<>();
final int[] granteeUids = keyChainConnection.getService().getGrants(alias);
for (final int uid : granteeUids) {
if (uid == Process.WIFI_UID) {
return true;
}
}
return false;
} catch (RemoteException e) {
Log.e(LOG_TAG, "Querying grant to wifi auth. ", e);
return false;
}
});
}
@Override
public boolean setKeyGrantForApp(ComponentName who, String callerPackage, String alias,
String packageName, boolean hasGrant) {
@@ -5482,19 +5518,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
throw new IllegalStateException("Failure getting grantee uid", e);
}
return setKeyChainGrantInternal(alias, hasGrant, granteeUid, caller.getUserHandle());
}
private boolean setKeyChainGrantInternal(String alias, boolean hasGrant, int granteeUid,
UserHandle userHandle) {
final long id = mInjector.binderClearCallingIdentity();
try {
final KeyChainConnection keyChainConnection =
KeyChain.bindAsUser(mContext, caller.getUserHandle());
try {
try (KeyChainConnection keyChainConnection =
KeyChain.bindAsUser(mContext, userHandle)) {
IKeyChainService keyChain = keyChainConnection.getService();
keyChain.setGrant(granteeUid, alias, hasGrant);
return true;
} catch (RemoteException e) {
Log.e(LOG_TAG, "Setting grant for package.", e);
return false;
} finally {
keyChainConnection.close();
return false;
}
} catch (InterruptedException e) {
Log.w(LOG_TAG, "Interrupted while setting key grant", e);