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