Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0aa66c58 authored by Gabriel Biren's avatar Gabriel Biren Committed by Android (Google) Code Review
Browse files

Merge "Use ConnectivityBlobStore as the main storage mechanism in WifiKeystore." into main

parents 79c910f8 bf26b946
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 android.net.wifi;

import com.android.internal.net.ConnectivityBlobStore;

/**
 * Database blob store for Wifi.
 * @hide
 */
public class WifiBlobStore extends ConnectivityBlobStore {
    private static final String DB_NAME = "WifiBlobStore.db";
    private static WifiBlobStore sInstance;
    private WifiBlobStore() {
        super(DB_NAME);
    }

    /** Returns an instance of WifiBlobStore. */
    public static WifiBlobStore getInstance() {
        if (sInstance == null) {
            sInstance = new WifiBlobStore();
        }
        return sInstance;
    }
}
+51 −13
Original line number Diff line number Diff line
@@ -18,12 +18,17 @@ package android.net.wifi;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.os.Binder;
import android.os.Process;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.security.legacykeystore.ILegacyKeystore;
import android.util.Log;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * This class allows the storage and retrieval of non-standard Wifi certificate blobs.
 * @hide
@@ -34,7 +39,7 @@ public final class WifiKeystore {
    private static final String TAG = "WifiKeystore";
    private static final String LEGACY_KEYSTORE_SERVICE_NAME = "android.security.legacykeystore";

    private static ILegacyKeystore getService() {
    private static ILegacyKeystore getLegacyKeystore() {
        return ILegacyKeystore.Stub.asInterface(
                ServiceManager.checkService(LEGACY_KEYSTORE_SERVICE_NAME));
    }
@@ -54,13 +59,18 @@ public final class WifiKeystore {
    @SystemApi
    @SuppressLint("UnflaggedApi")
    public static boolean put(@NonNull String alias, @NonNull byte[] blob) {
        // ConnectivityBlobStore uses the calling uid as a key into the DB.
        // Clear identity to ensure that callers from system apps and the Wifi framework
        // are able to access the same values.
        final long identity = Binder.clearCallingIdentity();
        try {
            Log.i(TAG, "put blob. alias " + alias);
            getService().put(alias, Process.WIFI_UID, blob);
            return true;
            return WifiBlobStore.getInstance().put(alias, blob);
        } catch (Exception e) {
            Log.e(TAG, "Failed to put blob.", e);
            return false;
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

@@ -69,23 +79,31 @@ public final class WifiKeystore {
     * @param alias Name of the blob to retrieve.
     * @return The unstructured blob, that is the blob that was stored using
     *         {@link android.net.wifi.WifiKeystore#put}.
     *         Returns null if no blob was found.
     *         Returns empty byte[] if no blob was found.
     * @hide
     */
    @SystemApi
    @SuppressLint("UnflaggedApi")
    public static @NonNull byte[] get(@NonNull String alias) {
        final long identity = Binder.clearCallingIdentity();
        try {
            Log.i(TAG, "get blob. alias " + alias);
            return getService().get(alias, Process.WIFI_UID);
            byte[] blob = WifiBlobStore.getInstance().get(alias);
            if (blob != null) {
                return blob;
            }
            Log.i(TAG, "Searching for blob in Legacy Keystore");
            return getLegacyKeystore().get(alias, Process.WIFI_UID);
        } catch (ServiceSpecificException e) {
            if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) {
                Log.e(TAG, "Failed to get blob.", e);
            }
        } catch (Exception e) {
            Log.e(TAG, "Failed to get blob.", e);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
        return null;
        return new byte[0];
    }

    /**
@@ -97,17 +115,27 @@ public final class WifiKeystore {
    @SystemApi
    @SuppressLint("UnflaggedApi")
    public static boolean remove(@NonNull String alias) {
        boolean blobStoreSuccess = false;
        boolean legacyKsSuccess = false;
        final long identity = Binder.clearCallingIdentity();
        try {
            getService().remove(alias, Process.WIFI_UID);
            return true;
            Log.i(TAG, "remove blob. alias " + alias);
            blobStoreSuccess = WifiBlobStore.getInstance().remove(alias);
            // Legacy Keystore will throw an exception if the alias is not found.
            getLegacyKeystore().remove(alias, Process.WIFI_UID);
            legacyKsSuccess = true;
        } catch (ServiceSpecificException e) {
            if (e.errorCode != ILegacyKeystore.ERROR_ENTRY_NOT_FOUND) {
                Log.e(TAG, "Failed to remove blob.", e);
            }
        } catch (Exception e) {
            Log.e(TAG, "Failed to remove blob.", e);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
        return false;
        Log.i(TAG, "Removal status: wifiBlobStore=" + blobStoreSuccess
                + ", legacyKeystore=" + legacyKsSuccess);
        return blobStoreSuccess || legacyKsSuccess;
    }

    /**
@@ -119,14 +147,24 @@ public final class WifiKeystore {
    @SystemApi
    @SuppressLint("UnflaggedApi")
    public static @NonNull String[] list(@NonNull String prefix) {
        final long identity = Binder.clearCallingIdentity();
        try {
            final String[] aliases = getService().list(prefix, Process.WIFI_UID);
            for (int i = 0; i < aliases.length; ++i) {
                aliases[i] = aliases[i].substring(prefix.length());
            // Aliases from WifiBlobStore will be pre-trimmed.
            final String[] blobStoreAliases = WifiBlobStore.getInstance().list(prefix);
            final String[] legacyAliases = getLegacyKeystore().list(prefix, Process.WIFI_UID);
            for (int i = 0; i < legacyAliases.length; ++i) {
                legacyAliases[i] = legacyAliases[i].substring(prefix.length());
            }
            return aliases;
            // Deduplicate aliases before returning.
            Set<String> uniqueAliases = new HashSet<>();
            uniqueAliases.addAll(Arrays.asList(blobStoreAliases));
            uniqueAliases.addAll(Arrays.asList(legacyAliases));
            String[] uniqueAliasArray = new String[uniqueAliases.size()];
            return uniqueAliases.toArray(uniqueAliasArray);
        } catch (Exception e) {
            Log.e(TAG, "Failed to list blobs.", e);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
        return new String[0];
    }