KeyChainServiceTest.java revision 3e6251dedc92654476c70bdc413f24a4b31ce6a4
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 17package com.android.keychain.tests; 18 19import android.accounts.Account; 20import android.accounts.AccountManager; 21import android.accounts.AccountManagerFuture; 22import android.app.Service; 23import android.content.ComponentName; 24import android.content.Context; 25import android.content.Intent; 26import android.content.ServiceConnection; 27import android.os.Bundle; 28import android.os.IBinder; 29import android.security.Credentials; 30import android.security.IKeyChainService; 31import android.security.KeyChain; 32import android.security.KeyStore; 33import android.util.Log; 34import com.android.keychain.tests.support.IKeyChainServiceTestSupport; 35import java.security.KeyStore.PrivateKeyEntry; 36import java.security.cert.Certificate; 37import java.util.Arrays; 38import junit.framework.Assert; 39import libcore.java.security.TestKeyStore; 40 41public class KeyChainServiceTest extends Service { 42 43 private static final String TAG = "KeyChainServiceTest"; 44 45 private final Object mSupportLock = new Object(); 46 private IKeyChainServiceTestSupport mSupport; 47 private boolean mIsBoundSupport; 48 49 private final Object mServiceLock = new Object(); 50 private IKeyChainService mService; 51 private boolean mIsBoundService; 52 53 private ServiceConnection mSupportConnection = new ServiceConnection() { 54 @Override public void onServiceConnected(ComponentName name, IBinder service) { 55 synchronized (mSupportLock) { 56 mSupport = IKeyChainServiceTestSupport.Stub.asInterface(service); 57 mSupportLock.notifyAll(); 58 } 59 } 60 61 @Override public void onServiceDisconnected(ComponentName name) { 62 synchronized (mSupportLock) { 63 mSupport = null; 64 } 65 } 66 }; 67 68 private ServiceConnection mServiceConnection = new ServiceConnection() { 69 @Override public void onServiceConnected(ComponentName name, IBinder service) { 70 synchronized (mServiceLock) { 71 mService = IKeyChainService.Stub.asInterface(service); 72 mServiceLock.notifyAll(); 73 } 74 } 75 76 @Override public void onServiceDisconnected(ComponentName name) { 77 synchronized (mServiceLock) { 78 mService = null; 79 } 80 } 81 }; 82 83 private void bindSupport() { 84 mIsBoundSupport = bindService(new Intent(IKeyChainServiceTestSupport.class.getName()), 85 mSupportConnection, 86 Context.BIND_AUTO_CREATE); 87 } 88 89 private void bindService() { 90 mIsBoundService = bindService(new Intent(IKeyChainService.class.getName()), 91 mServiceConnection, 92 Context.BIND_AUTO_CREATE); 93 } 94 95 private void unbindServices() { 96 if (mIsBoundSupport) { 97 unbindService(mSupportConnection); 98 mIsBoundSupport = false; 99 } 100 if (mIsBoundService) { 101 unbindService(mServiceConnection); 102 mIsBoundService = false; 103 } 104 } 105 106 @Override public IBinder onBind(Intent intent) { 107 Log.d(TAG, "onBind"); 108 return null; 109 } 110 111 @Override public int onStartCommand(Intent intent, int flags, int startId) { 112 Log.d(TAG, "onStartCommand"); 113 new Thread(new Test(), TAG).start(); 114 return START_STICKY; 115 } 116 117 @Override public void onDestroy () { 118 Log.d(TAG, "onDestroy"); 119 unbindServices(); 120 } 121 122 private final class Test extends Assert implements Runnable { 123 124 @Override public void run() { 125 try { 126 test_KeyChainService(); 127 } catch (RuntimeException e) { 128 // rethrow RuntimeException without wrapping 129 throw e; 130 } catch (Exception e) { 131 throw new RuntimeException(e); 132 } finally { 133 stopSelf(); 134 } 135 } 136 137 public void test_KeyChainService() throws Exception { 138 Log.d(TAG, "test_KeyChainService uid=" + getApplicationInfo().uid); 139 140 Log.d(TAG, "test_KeyChainService bind support"); 141 bindSupport(); 142 assertTrue(mIsBoundSupport); 143 synchronized (mSupportLock) { 144 if (mSupport == null) { 145 mSupportLock.wait(10 * 1000); 146 } 147 } 148 assertNotNull(mSupport); 149 150 Log.d(TAG, "test_KeyChainService setup keystore and AccountManager"); 151 KeyStore keyStore = KeyStore.getInstance(); 152 assertTrue(mSupport.keystoreReset()); 153 assertTrue(mSupport.keystorePassword("ignored", "newpasswd")); 154 155 String intermediate = "-intermediate"; 156 String root = "-root"; 157 158 String alias1 = "client"; 159 String alias1Intermediate = alias1 + intermediate; 160 String alias1Root = alias1 + root; 161 byte[] alias1Pkey = (Credentials.USER_PRIVATE_KEY + alias1).getBytes(); 162 byte[] alias1Cert = (Credentials.USER_CERTIFICATE + alias1).getBytes(); 163 byte[] alias1ICert = (Credentials.CA_CERTIFICATE + alias1Intermediate).getBytes(); 164 byte[] alias1RCert = (Credentials.CA_CERTIFICATE + alias1Root).getBytes(); 165 PrivateKeyEntry pke1 = TestKeyStore.getClientCertificate().getPrivateKey("RSA", "RSA"); 166 Certificate intermediate1 = pke1.getCertificateChain()[1]; 167 Certificate root1 = TestKeyStore.getClientCertificate().getRootCertificate("RSA"); 168 169 final String alias2 = "server"; 170 String alias2Intermediate = alias2 + intermediate; 171 String alias2Root = alias2 + root; 172 byte[] alias2Pkey = (Credentials.USER_PRIVATE_KEY + alias2).getBytes(); 173 byte[] alias2Cert = (Credentials.USER_CERTIFICATE + alias2).getBytes(); 174 byte[] alias2ICert = (Credentials.CA_CERTIFICATE + alias2Intermediate).getBytes(); 175 byte[] alias2RCert = (Credentials.CA_CERTIFICATE + alias2Root).getBytes(); 176 PrivateKeyEntry pke2 = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); 177 Certificate intermediate2 = pke2.getCertificateChain()[1]; 178 Certificate root2 = TestKeyStore.getServer().getRootCertificate("RSA"); 179 180 assertTrue(mSupport.keystorePut(alias1Pkey, pke1.getPrivateKey().getEncoded())); 181 assertTrue(mSupport.keystorePut(alias1Cert, pke1.getCertificate().getEncoded())); 182 assertTrue(mSupport.keystorePut(alias1ICert, intermediate1.getEncoded())); 183 assertTrue(mSupport.keystorePut(alias1RCert, root1.getEncoded())); 184 assertTrue(mSupport.keystorePut(alias2Pkey, pke2.getPrivateKey().getEncoded())); 185 assertTrue(mSupport.keystorePut(alias2Cert, pke2.getCertificate().getEncoded())); 186 assertTrue(mSupport.keystorePut(alias2ICert, intermediate2.getEncoded())); 187 assertTrue(mSupport.keystorePut(alias2RCert, root2.getEncoded())); 188 189 assertEquals(KeyStore.NO_ERROR, keyStore.test()); 190 AccountManager accountManager = AccountManager.get(KeyChainServiceTest.this); 191 assertNotNull(accountManager); 192 for (Account account : accountManager.getAccountsByType(KeyChain.ACCOUNT_TYPE)) { 193 mSupport.revokeAppPermission(account, alias1, getApplicationInfo().uid); 194 mSupport.revokeAppPermission( 195 account, alias1Intermediate + KeyChain.CA_SUFFIX, getApplicationInfo().uid); 196 mSupport.revokeAppPermission( 197 account, alias1Root + KeyChain.CA_SUFFIX, getApplicationInfo().uid); 198 mSupport.revokeAppPermission(account, alias2, getApplicationInfo().uid); 199 mSupport.revokeAppPermission( 200 account, alias2Intermediate + KeyChain.CA_SUFFIX, getApplicationInfo().uid); 201 mSupport.revokeAppPermission( 202 account, alias2Root + KeyChain.CA_SUFFIX, getApplicationInfo().uid); 203 } 204 205 Log.d(TAG, "test_KeyChainService bind service"); 206 bindService(); 207 assertTrue(mIsBoundService); 208 synchronized (mServiceLock) { 209 if (mService == null) { 210 mServiceLock.wait(10 * 1000); 211 } 212 } 213 assertNotNull(mService); 214 215 Account[] accounts = accountManager.getAccountsByType(KeyChain.ACCOUNT_TYPE); 216 assertNotNull(accounts); 217 assertEquals(1, accounts.length); 218 Account account = accounts[0]; 219 Log.d(TAG, "test_KeyChainService getAuthTokenByFeatures for Intent"); 220 AccountManagerFuture<Bundle> accountManagerFutureFail 221 = accountManager.getAuthToken(account, alias1, false, null, null); 222 Bundle bundleFail = accountManagerFutureFail.getResult(); 223 assertNotNull(bundleFail); 224 Object intentObject = bundleFail.get(AccountManager.KEY_INTENT); 225 assertNotNull(intentObject); 226 assertTrue(Intent.class.isAssignableFrom(intentObject.getClass())); 227 Intent intent = (Intent) intentObject; 228 assertEquals("android", 229 intent.getComponent().getPackageName()); 230 assertEquals("android.accounts.GrantCredentialsPermissionActivity", 231 intent.getComponent().getClassName()); 232 233 mSupport.grantAppPermission(account, alias1, getApplicationInfo().uid); 234 // don't grant alias2, so it can be done manually with KeyChainTestActivity 235 Log.d(TAG, "test_KeyChainService getAuthTokenByFeatures for authtoken"); 236 AccountManagerFuture<Bundle> accountManagerFuture 237 = accountManager.getAuthToken(account, alias1, false, null, null); 238 Bundle bundle = accountManagerFuture.getResult(); 239 String accountName = bundle.getString(AccountManager.KEY_ACCOUNT_NAME); 240 assertNotNull(accountName); 241 String accountType = bundle.getString(AccountManager.KEY_ACCOUNT_TYPE); 242 assertEquals(KeyChain.ACCOUNT_TYPE, accountType); 243 String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN); 244 assertNotNull(authToken); 245 assertFalse(authToken.isEmpty()); 246 247 byte[] privateKey = mService.getPrivate(alias1, authToken); 248 assertNotNull(privateKey); 249 assertEquals(Arrays.toString(pke1.getPrivateKey().getEncoded()), 250 Arrays.toString(privateKey)); 251 252 byte[] certificate = mService.getCertificate(alias1, authToken); 253 assertNotNull(certificate); 254 assertEquals(Arrays.toString(pke1.getCertificate().getEncoded()), 255 Arrays.toString(certificate)); 256 257 String aliasI = mService.findIssuer(KeyChain.fromCertificate(pke1.getCertificate())); 258 assertNotNull(aliasI); 259 assertEquals(alias1Intermediate, aliasI); 260 261 String aliasR = mService.findIssuer(KeyChain.fromCertificate(intermediate1)); 262 assertNotNull(aliasR); 263 assertEquals(alias1Root, aliasR); 264 265 String aliasRR = mService.findIssuer(KeyChain.fromCertificate(intermediate1)); 266 assertNotNull(aliasRR); 267 assertEquals(alias1Root, aliasRR); 268 269 try { 270 mService.findIssuer(new Bundle()); 271 fail(); 272 } catch (IllegalArgumentException expected) { 273 } 274 try { 275 mService.findIssuer(null); 276 fail(); 277 } catch (NullPointerException expected) { 278 } 279 280 Log.d(TAG, "test_KeyChainService unbind"); 281 unbindServices(); 282 assertFalse(mIsBoundSupport); 283 assertFalse(mIsBoundService); 284 285 Log.d(TAG, "test_KeyChainService end"); 286 } 287 } 288} 289