diff options
Diffstat (limited to 'keystore')
4 files changed, 166 insertions, 19 deletions
diff --git a/keystore/java/android/security/LegacyVpnProfileStore.java b/keystore/java/android/security/LegacyVpnProfileStore.java new file mode 100644 index 000000000000..41cfb2707fcf --- /dev/null +++ b/keystore/java/android/security/LegacyVpnProfileStore.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2020 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.security; + +import android.annotation.NonNull; +import android.os.ServiceManager; +import android.os.ServiceSpecificException; +import android.security.keystore.AndroidKeyStoreProvider; +import android.security.vpnprofilestore.IVpnProfileStore; +import android.util.Log; + +/** + * @hide This class allows legacy VPN access to its profiles that were stored in Keystore. + * The storage of unstructured blobs in Android Keystore is going away, because there is no + * architectural or security benefit of storing profiles in keystore over storing them + * in the file system. This class allows access to the blobs that still exist in keystore. + * And it stores new blob in a database that is still owned by Android Keystore. + */ +public class LegacyVpnProfileStore { + private static final String TAG = "LegacyVpnProfileStore"; + + public static final int SYSTEM_ERROR = IVpnProfileStore.ERROR_SYSTEM_ERROR; + public static final int PROFILE_NOT_FOUND = IVpnProfileStore.ERROR_PROFILE_NOT_FOUND; + + private static final String VPN_PROFILE_STORE_SERVICE_NAME = "android.security.vpnprofilestore"; + + private static IVpnProfileStore getService() { + return IVpnProfileStore.Stub.asInterface( + ServiceManager.checkService(VPN_PROFILE_STORE_SERVICE_NAME)); + } + + /** + * Stores the profile under the alias in the profile database. Existing profiles by the + * same name will be replaced. + * @param alias The name of the profile + * @param profile The profile. + * @return true if the profile was successfully added. False otherwise. + * @hide + */ + public static boolean put(@NonNull String alias, @NonNull byte[] profile) { + try { + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + getService().put(alias, profile); + return true; + } else { + return KeyStore.getInstance().put( + alias, profile, KeyStore.UID_SELF, 0); + } + } catch (Exception e) { + Log.e(TAG, "Failed to put vpn profile.", e); + return false; + } + } + + /** + * Retrieves a profile by the name alias from the profile database. + * @param alias Name of the profile to retrieve. + * @return The unstructured blob, that is the profile that was stored using + * LegacyVpnProfileStore#put or with + * android.security.Keystore.put(Credentials.VPN + alias). + * Returns null if no profile was found. + * @hide + */ + public static byte[] get(@NonNull String alias) { + try { + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + return getService().get(alias); + } else { + return KeyStore.getInstance().get(alias, true /* suppressKeyNotFoundWarning */); + } + } catch (ServiceSpecificException e) { + if (e.errorCode != PROFILE_NOT_FOUND) { + Log.e(TAG, "Failed to get vpn profile.", e); + } + } catch (Exception e) { + Log.e(TAG, "Failed to get vpn profile.", e); + } + return null; + } + + /** + * Removes a profile by the name alias from the profile database. + * @param alias Name of the profile to be removed. + * @return True if a profile was removed. False if no such profile was found. + * @hide + */ + public static boolean remove(@NonNull String alias) { + try { + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + getService().remove(alias); + return true; + } else { + return KeyStore.getInstance().delete(alias); + } + } catch (ServiceSpecificException e) { + if (e.errorCode != PROFILE_NOT_FOUND) { + Log.e(TAG, "Failed to remove vpn profile.", e); + } + } catch (Exception e) { + Log.e(TAG, "Failed to remove vpn profile.", e); + } + return false; + } + + /** + * Lists the vpn profiles stored in the database. + * @return An array of strings representing the aliases stored in the profile database. + * The return value may be empty but never null. + * @hide + */ + public static @NonNull String[] list(@NonNull String prefix) { + try { + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + final String[] aliases = getService().list(prefix); + for (int i = 0; i < aliases.length; ++i) { + aliases[i] = aliases[i].substring(prefix.length()); + } + return aliases; + } else { + final String[] result = KeyStore.getInstance().list(prefix); + return result != null ? result : new String[0]; + } + } catch (Exception e) { + Log.e(TAG, "Failed to list vpn profiles.", e); + } + return new String[0]; + } +} diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 72735a787b7f..5cb2c3b41517 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -467,8 +467,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * * @return The numeric namespace as configured in the keystore2_key_contexts files of Android's * SEPolicy. - * TODO b/171806779 link to public Keystore 2.0 documentation. - * See bug for more details for now. + * See <a href="https://source.android.com/security/keystore#access-control"> + * Keystore 2.0 access control</a> * @hide */ @SystemApi @@ -1042,9 +1042,9 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * keys between system and vendor components, e.g., WIFI settings and WPA supplicant. * * @param namespace Numeric SELinux namespace as configured in keystore2_key_contexts - * of Android's SEPolicy. - * TODO b/171806779 link to public Keystore 2.0 documentation. - * See bug for more details for now. + * of Android's SEPolicy. + * See <a href="https://source.android.com/security/keystore#access-control"> + * Keystore 2.0 access control</a> * @return this Builder object. * * @hide diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java index d36695b9b410..fa852e33a1d8 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java @@ -340,11 +340,11 @@ public class AndroidKeyStoreProvider extends Provider { * @param keyStore The keystore2 backend. * @param alias The alias of the key in the Keystore database. * @param namespace The a Keystore namespace. This is used by system api only to request - * Android system specific keystore namespace, which can be configured - * in the device's SEPolicy. Third party apps and most system components - * set this parameter to -1 to indicate their application specific namespace. - * TODO b/171806779 link to public Keystore 2.0 documentation. - * See bug for more details for now. + * Android system specific keystore namespace, which can be configured + * in the device's SEPolicy. Third party apps and most system components + * set this parameter to -1 to indicate their application specific namespace. + * See <a href="https://source.android.com/security/keystore#access-control"> + * Keystore 2.0 access control</a> * @hide **/ @NonNull diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java index 992454285738..0006b92b1b9b 100644 --- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java +++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java @@ -18,6 +18,7 @@ package android.security.keystore2; import android.app.ActivityThread; import android.hardware.biometrics.BiometricManager; +import android.hardware.security.keymint.ErrorCode; import android.security.GateKeeper; import android.security.KeyStore; import android.security.KeyStoreException; @@ -183,15 +184,19 @@ abstract class KeyStoreCryptoOperationUtils { try { operation.abort(); } catch (KeyStoreException e) { - // We log this error, but we can afford to ignore it. Dropping the reference - // to the KeyStoreOperation is enough to clean up all related resources even - // in the Keystore daemon. We log it anyway, because it may indicate some - // underlying problem that is worth debugging. - Log.w( - "KeyStoreCryptoOperationUtils", - "Encountered error trying to abort a keystore operation.", - e - ); + // Invalid operation handle is very common at this point. It occurs every time + // an already finalized operation gets aborted. + if (e.getErrorCode() != ErrorCode.INVALID_OPERATION_HANDLE) { + // This error gets logged but ignored. Dropping the reference + // to the KeyStoreOperation is enough to clean up all related resources even + // in the Keystore daemon. It gets logged anyway, because it may indicate some + // underlying problem that is worth debugging. + Log.w( + "KeyStoreCryptoOperationUtils", + "Encountered error trying to abort a keystore operation.", + e + ); + } } } } |