Home | History | Annotate | Download | only in security
      1 /*
      2  * Copyright (C) 2009 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 android.security;
     18 
     19 import com.android.org.conscrypt.NativeCrypto;
     20 
     21 import android.os.RemoteException;
     22 import android.os.ServiceManager;
     23 import android.util.Log;
     24 
     25 import java.util.Locale;
     26 
     27 /**
     28  * @hide This should not be made public in its present form because it
     29  * assumes that private and secret key bytes are available and would
     30  * preclude the use of hardware crypto.
     31  */
     32 public class KeyStore {
     33     private static final String TAG = "KeyStore";
     34 
     35     // ResponseCodes
     36     public static final int NO_ERROR = 1;
     37     public static final int LOCKED = 2;
     38     public static final int UNINITIALIZED = 3;
     39     public static final int SYSTEM_ERROR = 4;
     40     public static final int PROTOCOL_ERROR = 5;
     41     public static final int PERMISSION_DENIED = 6;
     42     public static final int KEY_NOT_FOUND = 7;
     43     public static final int VALUE_CORRUPTED = 8;
     44     public static final int UNDEFINED_ACTION = 9;
     45     public static final int WRONG_PASSWORD = 10;
     46 
     47     // Used for UID field to indicate the calling UID.
     48     public static final int UID_SELF = -1;
     49 
     50     // Flags for "put" "import" and "generate"
     51     public static final int FLAG_NONE = 0;
     52     public static final int FLAG_ENCRYPTED = 1;
     53 
     54     // States
     55     public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
     56 
     57     private int mError = NO_ERROR;
     58 
     59     private final IKeystoreService mBinder;
     60 
     61     private KeyStore(IKeystoreService binder) {
     62         mBinder = binder;
     63     }
     64 
     65     public static KeyStore getInstance() {
     66         IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
     67                 .getService("android.security.keystore"));
     68         return new KeyStore(keystore);
     69     }
     70 
     71     static int getKeyTypeForAlgorithm(String keyType) throws IllegalArgumentException {
     72         if ("RSA".equalsIgnoreCase(keyType)) {
     73             return NativeCrypto.EVP_PKEY_RSA;
     74         } else if ("DSA".equalsIgnoreCase(keyType)) {
     75             return NativeCrypto.EVP_PKEY_DSA;
     76         } else if ("EC".equalsIgnoreCase(keyType)) {
     77             return NativeCrypto.EVP_PKEY_EC;
     78         } else {
     79             throw new IllegalArgumentException("Unsupported key type: " + keyType);
     80         }
     81     }
     82 
     83     public State state() {
     84         final int ret;
     85         try {
     86             ret = mBinder.test();
     87         } catch (RemoteException e) {
     88             Log.w(TAG, "Cannot connect to keystore", e);
     89             throw new AssertionError(e);
     90         }
     91 
     92         switch (ret) {
     93             case NO_ERROR: return State.UNLOCKED;
     94             case LOCKED: return State.LOCKED;
     95             case UNINITIALIZED: return State.UNINITIALIZED;
     96             default: throw new AssertionError(mError);
     97         }
     98     }
     99 
    100     public boolean isUnlocked() {
    101         return state() == State.UNLOCKED;
    102     }
    103 
    104     public byte[] get(String key) {
    105         try {
    106             return mBinder.get(key);
    107         } catch (RemoteException e) {
    108             Log.w(TAG, "Cannot connect to keystore", e);
    109             return null;
    110         }
    111     }
    112 
    113     public boolean put(String key, byte[] value, int uid, int flags) {
    114         try {
    115             return mBinder.insert(key, value, uid, flags) == NO_ERROR;
    116         } catch (RemoteException e) {
    117             Log.w(TAG, "Cannot connect to keystore", e);
    118             return false;
    119         }
    120     }
    121 
    122     public boolean delete(String key, int uid) {
    123         try {
    124             return mBinder.del(key, uid) == NO_ERROR;
    125         } catch (RemoteException e) {
    126             Log.w(TAG, "Cannot connect to keystore", e);
    127             return false;
    128         }
    129     }
    130 
    131     public boolean delete(String key) {
    132         return delete(key, UID_SELF);
    133     }
    134 
    135     public boolean contains(String key, int uid) {
    136         try {
    137             return mBinder.exist(key, uid) == NO_ERROR;
    138         } catch (RemoteException e) {
    139             Log.w(TAG, "Cannot connect to keystore", e);
    140             return false;
    141         }
    142     }
    143 
    144     public boolean contains(String key) {
    145         return contains(key, UID_SELF);
    146     }
    147 
    148     public String[] saw(String prefix, int uid) {
    149         try {
    150             return mBinder.saw(prefix, uid);
    151         } catch (RemoteException e) {
    152             Log.w(TAG, "Cannot connect to keystore", e);
    153             return null;
    154         }
    155     }
    156 
    157     public String[] saw(String prefix) {
    158         return saw(prefix, UID_SELF);
    159     }
    160 
    161     public boolean reset() {
    162         try {
    163             return mBinder.reset() == NO_ERROR;
    164         } catch (RemoteException e) {
    165             Log.w(TAG, "Cannot connect to keystore", e);
    166             return false;
    167         }
    168     }
    169 
    170     public boolean password(String password) {
    171         try {
    172             return mBinder.password(password) == NO_ERROR;
    173         } catch (RemoteException e) {
    174             Log.w(TAG, "Cannot connect to keystore", e);
    175             return false;
    176         }
    177     }
    178 
    179     public boolean lock() {
    180         try {
    181             return mBinder.lock() == NO_ERROR;
    182         } catch (RemoteException e) {
    183             Log.w(TAG, "Cannot connect to keystore", e);
    184             return false;
    185         }
    186     }
    187 
    188     public boolean unlock(String password) {
    189         try {
    190             mError = mBinder.unlock(password);
    191             return mError == NO_ERROR;
    192         } catch (RemoteException e) {
    193             Log.w(TAG, "Cannot connect to keystore", e);
    194             return false;
    195         }
    196     }
    197 
    198     public boolean isEmpty() {
    199         try {
    200             return mBinder.zero() == KEY_NOT_FOUND;
    201         } catch (RemoteException e) {
    202             Log.w(TAG, "Cannot connect to keystore", e);
    203             return false;
    204         }
    205     }
    206 
    207     public boolean generate(String key, int uid, int keyType, int keySize, int flags,
    208             byte[][] args) {
    209         try {
    210             return mBinder.generate(key, uid, keyType, keySize, flags, args) == NO_ERROR;
    211         } catch (RemoteException e) {
    212             Log.w(TAG, "Cannot connect to keystore", e);
    213             return false;
    214         }
    215     }
    216 
    217     public boolean importKey(String keyName, byte[] key, int uid, int flags) {
    218         try {
    219             return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
    220         } catch (RemoteException e) {
    221             Log.w(TAG, "Cannot connect to keystore", e);
    222             return false;
    223         }
    224     }
    225 
    226     public byte[] getPubkey(String key) {
    227         try {
    228             return mBinder.get_pubkey(key);
    229         } catch (RemoteException e) {
    230             Log.w(TAG, "Cannot connect to keystore", e);
    231             return null;
    232         }
    233     }
    234 
    235     public boolean delKey(String key, int uid) {
    236         try {
    237             return mBinder.del_key(key, uid) == NO_ERROR;
    238         } catch (RemoteException e) {
    239             Log.w(TAG, "Cannot connect to keystore", e);
    240             return false;
    241         }
    242     }
    243 
    244     public boolean delKey(String key) {
    245         return delKey(key, UID_SELF);
    246     }
    247 
    248     public byte[] sign(String key, byte[] data) {
    249         try {
    250             return mBinder.sign(key, data);
    251         } catch (RemoteException e) {
    252             Log.w(TAG, "Cannot connect to keystore", e);
    253             return null;
    254         }
    255     }
    256 
    257     public boolean verify(String key, byte[] data, byte[] signature) {
    258         try {
    259             return mBinder.verify(key, data, signature) == NO_ERROR;
    260         } catch (RemoteException e) {
    261             Log.w(TAG, "Cannot connect to keystore", e);
    262             return false;
    263         }
    264     }
    265 
    266     public boolean grant(String key, int uid) {
    267         try {
    268             return mBinder.grant(key, uid) == NO_ERROR;
    269         } catch (RemoteException e) {
    270             Log.w(TAG, "Cannot connect to keystore", e);
    271             return false;
    272         }
    273     }
    274 
    275     public boolean ungrant(String key, int uid) {
    276         try {
    277             return mBinder.ungrant(key, uid) == NO_ERROR;
    278         } catch (RemoteException e) {
    279             Log.w(TAG, "Cannot connect to keystore", e);
    280             return false;
    281         }
    282     }
    283 
    284     /**
    285      * Returns the last modification time of the key in milliseconds since the
    286      * epoch. Will return -1L if the key could not be found or other error.
    287      */
    288     public long getmtime(String key) {
    289         try {
    290             final long millis = mBinder.getmtime(key);
    291             if (millis == -1L) {
    292                 return -1L;
    293             }
    294 
    295             return millis * 1000L;
    296         } catch (RemoteException e) {
    297             Log.w(TAG, "Cannot connect to keystore", e);
    298             return -1L;
    299         }
    300     }
    301 
    302     public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) {
    303         try {
    304             return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR;
    305         } catch (RemoteException e) {
    306             Log.w(TAG, "Cannot connect to keystore", e);
    307             return false;
    308         }
    309     }
    310 
    311     // TODO remove this when it's removed from Settings
    312     public boolean isHardwareBacked() {
    313         return isHardwareBacked("RSA");
    314     }
    315 
    316     public boolean isHardwareBacked(String keyType) {
    317         try {
    318             return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
    319         } catch (RemoteException e) {
    320             Log.w(TAG, "Cannot connect to keystore", e);
    321             return false;
    322         }
    323     }
    324 
    325     public boolean clearUid(int uid) {
    326         try {
    327             return mBinder.clear_uid(uid) == NO_ERROR;
    328         } catch (RemoteException e) {
    329             Log.w(TAG, "Cannot connect to keystore", e);
    330             return false;
    331         }
    332     }
    333 
    334     public boolean resetUid(int uid) {
    335         try {
    336             mError = mBinder.reset_uid(uid);
    337             return mError == NO_ERROR;
    338         } catch (RemoteException e) {
    339             Log.w(TAG, "Cannot connect to keystore", e);
    340             return false;
    341         }
    342     }
    343 
    344     public boolean syncUid(int sourceUid, int targetUid) {
    345         try {
    346             mError = mBinder.sync_uid(sourceUid, targetUid);
    347             return mError == NO_ERROR;
    348         } catch (RemoteException e) {
    349             Log.w(TAG, "Cannot connect to keystore", e);
    350             return false;
    351         }
    352     }
    353 
    354     public boolean passwordUid(String password, int uid) {
    355         try {
    356             mError = mBinder.password_uid(password, uid);
    357             return mError == NO_ERROR;
    358         } catch (RemoteException e) {
    359             Log.w(TAG, "Cannot connect to keystore", e);
    360             return false;
    361         }
    362     }
    363 
    364     public int getLastError() {
    365         return mError;
    366     }
    367 }
    368