• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
18 
19 import android.app.Service;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.ServiceConnection;
24 import android.os.IBinder;
25 import android.security.Credentials;
26 import android.security.IKeyChainService;
27 import android.security.KeyStore;
28 import android.util.Log;
29 import com.android.keychain.tests.support.IKeyChainServiceTestSupport;
30 import java.security.KeyStore.PrivateKeyEntry;
31 import java.security.cert.Certificate;
32 import java.util.Arrays;
33 import junit.framework.Assert;
34 import libcore.java.security.TestKeyStore;
35 
36 public class KeyChainServiceTest extends Service {
37 
38     private static final String TAG = "KeyChainServiceTest";
39 
40     private final Object mSupportLock = new Object();
41     private IKeyChainServiceTestSupport mSupport;
42     private boolean mIsBoundSupport;
43 
44     private final Object mServiceLock = new Object();
45     private IKeyChainService mService;
46     private boolean mIsBoundService;
47 
48     private ServiceConnection mSupportConnection = new ServiceConnection() {
49         @Override public void onServiceConnected(ComponentName name, IBinder service) {
50             synchronized (mSupportLock) {
51                 mSupport = IKeyChainServiceTestSupport.Stub.asInterface(service);
52                 mSupportLock.notifyAll();
53             }
54         }
55 
56         @Override public void onServiceDisconnected(ComponentName name) {
57             synchronized (mSupportLock) {
58                 mSupport = null;
59             }
60         }
61     };
62 
63     private ServiceConnection mServiceConnection = new ServiceConnection() {
64         @Override public void onServiceConnected(ComponentName name, IBinder service) {
65             synchronized (mServiceLock) {
66                 mService = IKeyChainService.Stub.asInterface(service);
67                 mServiceLock.notifyAll();
68             }
69         }
70 
71         @Override public void onServiceDisconnected(ComponentName name) {
72             synchronized (mServiceLock) {
73                 mService = null;
74             }
75         }
76     };
77 
bindSupport()78     private void bindSupport() {
79         mIsBoundSupport = bindService(new Intent(IKeyChainServiceTestSupport.class.getName()),
80                                       mSupportConnection,
81                                       Context.BIND_AUTO_CREATE);
82     }
83 
bindService()84     private void bindService() {
85         mIsBoundService = bindService(new Intent(IKeyChainService.class.getName()),
86                                       mServiceConnection,
87                                       Context.BIND_AUTO_CREATE);
88     }
89 
unbindServices()90     private void unbindServices() {
91         if (mIsBoundSupport) {
92             unbindService(mSupportConnection);
93             mIsBoundSupport = false;
94         }
95         if (mIsBoundService) {
96             unbindService(mServiceConnection);
97             mIsBoundService = false;
98         }
99     }
100 
onBind(Intent intent)101     @Override public IBinder onBind(Intent intent) {
102         Log.d(TAG, "onBind");
103         return null;
104     }
105 
onStartCommand(Intent intent, int flags, int startId)106     @Override public int onStartCommand(Intent intent, int flags, int startId) {
107         Log.d(TAG, "onStartCommand");
108         new Thread(new Test(), TAG).start();
109         return START_STICKY;
110     }
111 
onDestroy()112     @Override public void onDestroy () {
113         Log.d(TAG, "onDestroy");
114         unbindServices();
115     }
116 
117     private final class Test extends Assert implements Runnable {
118 
run()119         @Override public void run() {
120             try {
121                 test_KeyChainService();
122             } catch (RuntimeException e) {
123                 // rethrow RuntimeException without wrapping
124                 throw e;
125             } catch (Exception e) {
126                 throw new RuntimeException(e);
127             } finally {
128                 stopSelf();
129             }
130         }
131 
test_KeyChainService()132         public void test_KeyChainService() throws Exception {
133             Log.d(TAG, "test_KeyChainService uid=" + getApplicationInfo().uid);
134 
135             Log.d(TAG, "test_KeyChainService bind support");
136             bindSupport();
137             assertTrue(mIsBoundSupport);
138             synchronized (mSupportLock) {
139                 if (mSupport == null) {
140                     mSupportLock.wait(10 * 1000);
141                 }
142             }
143             assertNotNull(mSupport);
144 
145             Log.d(TAG, "test_KeyChainService setup keystore");
146             KeyStore keyStore = KeyStore.getInstance();
147             assertTrue(mSupport.keystoreReset());
148             assertTrue(mSupport.keystorePassword("newpasswd"));
149 
150             String intermediate = "-intermediate";
151             String root = "-root";
152 
153             String alias1 = "client";
154             String alias1Intermediate = alias1 + intermediate;
155             String alias1Root = alias1 + root;
156             String alias1Pkey = (Credentials.USER_PRIVATE_KEY + alias1);
157             String alias1Cert = (Credentials.USER_CERTIFICATE + alias1);
158             String alias1ICert = (Credentials.CA_CERTIFICATE + alias1Intermediate);
159             String alias1RCert = (Credentials.CA_CERTIFICATE + alias1Root);
160             PrivateKeyEntry pke1 = TestKeyStore.getClientCertificate().getPrivateKey("RSA", "RSA");
161             Certificate intermediate1 = pke1.getCertificateChain()[1];
162             Certificate root1 = TestKeyStore.getClientCertificate().getRootCertificate("RSA");
163 
164             final String alias2 = "server";
165             String alias2Intermediate = alias2 + intermediate;
166             String alias2Root = alias2 + root;
167             String alias2Pkey = (Credentials.USER_PRIVATE_KEY + alias2);
168             String alias2Cert = (Credentials.USER_CERTIFICATE + alias2);
169             String alias2ICert = (Credentials.CA_CERTIFICATE + alias2Intermediate);
170             String alias2RCert = (Credentials.CA_CERTIFICATE + alias2Root);
171             PrivateKeyEntry pke2 = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
172             Certificate intermediate2 = pke2.getCertificateChain()[1];
173             Certificate root2 = TestKeyStore.getServer().getRootCertificate("RSA");
174 
175             assertTrue(mSupport.keystoreImportKey(alias1Pkey,
176                                            pke1.getPrivateKey().getEncoded()));
177             assertTrue(mSupport.keystorePut(alias1Cert,
178                                             Credentials.convertToPem(pke1.getCertificate())));
179             assertTrue(mSupport.keystorePut(alias1ICert,
180                                             Credentials.convertToPem(intermediate1)));
181             assertTrue(mSupport.keystorePut(alias1RCert,
182                                             Credentials.convertToPem(root1)));
183             assertTrue(mSupport.keystoreImportKey(alias2Pkey,
184                                             pke2.getPrivateKey().getEncoded()));
185             assertTrue(mSupport.keystorePut(alias2Cert,
186                                             Credentials.convertToPem(pke2.getCertificate())));
187             assertTrue(mSupport.keystorePut(alias2ICert,
188                                             Credentials.convertToPem(intermediate2)));
189             assertTrue(mSupport.keystorePut(alias2RCert,
190                                             Credentials.convertToPem(root2)));
191 
192             assertEquals(KeyStore.State.UNLOCKED, keyStore.state());
193 
194             Log.d(TAG, "test_KeyChainService bind service");
195             bindService();
196             assertTrue(mIsBoundService);
197             synchronized (mServiceLock) {
198                 if (mService == null) {
199                     mServiceLock.wait(10 * 1000);
200                 }
201             }
202             assertNotNull(mService);
203 
204             mSupport.grantAppPermission(getApplicationInfo().uid, alias1);
205             // don't grant alias2, so it can be done manually with KeyChainTestActivity
206             Log.d(TAG, "test_KeyChainService positive testing");
207             assertNotNull("Requesting private key should succeed",
208                     mService.requestPrivateKey(alias1));
209 
210             byte[] certificate = mService.getCertificate(alias1);
211             assertNotNull(certificate);
212             assertEquals(Arrays.toString(Credentials.convertToPem(pke1.getCertificate())),
213                          Arrays.toString(certificate));
214 
215             Log.d(TAG, "test_KeyChainService negative testing");
216             mSupport.revokeAppPermission(getApplicationInfo().uid, alias2);
217             try {
218                 mService.requestPrivateKey(alias2);
219                 fail();
220             } catch (IllegalStateException expected) {
221             }
222 
223             try {
224                 mService.getCertificate(alias2);
225                 fail();
226             } catch (IllegalStateException expected) {
227             }
228 
229             Log.d(TAG, "test_KeyChainService unbind");
230             unbindServices();
231             assertFalse(mIsBoundSupport);
232             assertFalse(mIsBoundService);
233 
234             Log.d(TAG, "test_KeyChainService end");
235         }
236     }
237 }
238