1 /* 2 * Copyright (C) 2011 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.keychain.tests.support; 18 19 import android.app.Service; 20 import android.content.Intent; 21 import android.os.IBinder; 22 import android.os.RemoteException; 23 import android.security.IKeyChainService; 24 import android.security.KeyChain; 25 import android.security.KeyStore; 26 import android.security.keystore.ParcelableKeyGenParameterSpec; 27 import android.util.Log; 28 29 public class KeyChainServiceTestSupport extends Service { 30 private static final String TAG = "KeyChainServiceTest"; 31 32 private final IKeyChainServiceTestSupport.Stub mIKeyChainServiceTestSupport 33 = new IKeyChainServiceTestSupport.Stub() { 34 @Override public void revokeAppPermission(final int uid, final String alias) 35 throws RemoteException { 36 Log.d(TAG, "revokeAppPermission"); 37 blockingSetGrantPermission(uid, alias, false); 38 } 39 40 @Override public void grantAppPermission(final int uid, final String alias) 41 throws RemoteException { 42 Log.d(TAG, "grantAppPermission"); 43 blockingSetGrantPermission(uid, alias, true); 44 } 45 46 @Override public boolean installKeyPair( 47 byte[] privateKey, byte[] userCert, byte[] certChain, String alias) 48 throws RemoteException { 49 Log.d(TAG, "installKeyPair"); 50 return performBlockingKeyChainCall(keyChainService -> { 51 return keyChainService.installKeyPair( 52 privateKey, userCert, certChain, alias, KeyStore.UID_SELF); 53 }); 54 } 55 56 @Override public boolean removeKeyPair(String alias) throws RemoteException { 57 Log.d(TAG, "removeKeyPair"); 58 return performBlockingKeyChainCall(keyChainService -> { 59 return keyChainService.removeKeyPair(alias); 60 }); 61 } 62 63 @Override public void setUserSelectable(String alias, boolean isUserSelectable) 64 throws RemoteException { 65 Log.d(TAG, "setUserSelectable"); 66 KeyChainAction<Void> action = service -> { 67 service.setUserSelectable(alias, isUserSelectable); 68 return null; 69 }; 70 performBlockingKeyChainCall(action); 71 } 72 73 @Override public int generateKeyPair(String algorithm, ParcelableKeyGenParameterSpec spec) 74 throws RemoteException { 75 return performBlockingKeyChainCall(keyChainService -> { 76 return keyChainService.generateKeyPair(algorithm, spec); 77 }); 78 } 79 80 @Override public boolean setKeyPairCertificate(String alias, byte[] userCertificate, 81 byte[] userCertificateChain) throws RemoteException { 82 return performBlockingKeyChainCall(keyChainService -> { 83 return keyChainService.setKeyPairCertificate(alias, userCertificate, 84 userCertificateChain); 85 }); 86 } 87 88 /** 89 * Binds to the KeyChainService and requests that permission for the sender to 90 * access the specified alias is granted/revoked. 91 * This method blocks so it must not be called from the UI thread. 92 * @param senderUid 93 * @param alias 94 */ 95 private void blockingSetGrantPermission(int senderUid, String alias, boolean value) 96 throws RemoteException { 97 KeyChainAction<Void> action = new KeyChainAction<Void>() { 98 public Void run(IKeyChainService service) throws RemoteException { 99 service.setGrant(senderUid, alias, value); 100 return null; 101 }; 102 }; 103 performBlockingKeyChainCall(action); 104 } 105 }; 106 onBind(Intent intent)107 @Override public IBinder onBind(Intent intent) { 108 return mIKeyChainServiceTestSupport; 109 } 110 111 public interface KeyChainAction<T> { run(IKeyChainService service)112 T run(IKeyChainService service) throws RemoteException; 113 } 114 performBlockingKeyChainCall(KeyChainAction<T> action)115 private <T> T performBlockingKeyChainCall(KeyChainAction<T> action) throws RemoteException { 116 try (KeyChain.KeyChainConnection connection = 117 KeyChain.bind(KeyChainServiceTestSupport.this)) { 118 return action.run(connection.getService()); 119 } catch (InterruptedException e) { 120 // should never happen. 121 Log.e(TAG, "interrupted while running action"); 122 Thread.currentThread().interrupt(); 123 } 124 return null; 125 } 126 } 127