• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.locksettings.recoverablekeystore.storage;
18 
19 import static android.security.keystore.recovery.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR;
20 
21 import android.annotation.Nullable;
22 import android.os.ServiceSpecificException;
23 import android.security.Credentials;
24 import android.security.keystore.KeyProperties;
25 import android.security.keystore.KeyProtection;
26 import android.security.KeyStore;
27 import android.util.Log;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.server.locksettings.recoverablekeystore.KeyStoreProxy;
31 import com.android.server.locksettings.recoverablekeystore.KeyStoreProxyImpl;
32 
33 import java.security.KeyStore.SecretKeyEntry;
34 import java.security.KeyStoreException;
35 import java.util.Locale;
36 
37 import javax.crypto.spec.SecretKeySpec;
38 
39 /**
40  * Storage for Application keys in LockSettings service KeyStore namespace.
41  *
42  * <p> Uses KeyStore's grant mechanism to make keys usable by application process without
43  * revealing key material
44  */
45 public class ApplicationKeyStorage {
46     private static final String TAG = "RecoverableAppKeyStore";
47 
48     private static final String APPLICATION_KEY_ALIAS_PREFIX =
49             "com.android.server.locksettings.recoverablekeystore/application/";
50 
51     private final KeyStoreProxy mKeyStore;
52     private final KeyStore mKeystoreService;
53 
getInstance(KeyStore keystoreService)54     public static ApplicationKeyStorage getInstance(KeyStore keystoreService)
55             throws KeyStoreException {
56         return new ApplicationKeyStorage(
57                 new KeyStoreProxyImpl(KeyStoreProxyImpl.getAndLoadAndroidKeyStore()),
58                 keystoreService);
59     }
60 
61     @VisibleForTesting
ApplicationKeyStorage(KeyStoreProxy keyStore, KeyStore keystoreService)62     ApplicationKeyStorage(KeyStoreProxy keyStore, KeyStore keystoreService) {
63         mKeyStore = keyStore;
64         mKeystoreService = keystoreService;
65     }
66 
67     /**
68      * Returns grant alias, valid in Applications namespace.
69      */
getGrantAlias(int userId, int uid, String alias)70     public @Nullable String getGrantAlias(int userId, int uid, String alias) {
71         // Aliases used by {@link KeyStore} are different than used by public API.
72         // {@code USER_PRIVATE_KEY} prefix is used secret keys.
73         Log.i(TAG, String.format(Locale.US, "Get %d/%d/%s", userId, uid, alias));
74         String keystoreAlias = Credentials.USER_PRIVATE_KEY + getInternalAlias(userId, uid, alias);
75         return mKeystoreService.grant(keystoreAlias, uid);
76     }
77 
setSymmetricKeyEntry(int userId, int uid, String alias, byte[] secretKey)78     public void setSymmetricKeyEntry(int userId, int uid, String alias, byte[] secretKey)
79             throws KeyStoreException {
80         Log.i(TAG, String.format(Locale.US, "Set %d/%d/%s: %d bytes of key material",
81                 userId, uid, alias, secretKey.length));
82         try {
83             mKeyStore.setEntry(
84                 getInternalAlias(userId, uid, alias),
85                 new SecretKeyEntry(
86                     new SecretKeySpec(secretKey, KeyProperties.KEY_ALGORITHM_AES)),
87                 new KeyProtection.Builder(
88                         KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
89                     .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
90                     .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
91                     .build());
92         } catch (KeyStoreException e) {
93             throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
94         }
95     }
96 
deleteEntry(int userId, int uid, String alias)97     public void deleteEntry(int userId, int uid, String alias) {
98         Log.i(TAG, String.format(Locale.US, "Del %d/%d/%s", userId, uid, alias));
99         try {
100             mKeyStore.deleteEntry(getInternalAlias(userId, uid, alias));
101         } catch (KeyStoreException e) {
102             throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
103         }
104     }
105 
106     /**
107      * Returns the alias in locksettins service's KeyStore namespace used for given application key.
108      *
109      * <p>These IDs look as follows:
110      * {@code com.security.recoverablekeystore/application/<userId>/<uid>/<alias>}
111      *
112      * @param userId The ID of the user
113      * @param uid The uid
114      * @param alias - alias in application's namespace
115      * @return The alias.
116      */
getInternalAlias(int userId, int uid, String alias)117     private String getInternalAlias(int userId, int uid, String alias) {
118         return APPLICATION_KEY_ALIAS_PREFIX + userId + "/" + uid + "/" + alias;
119     }
120 }
121