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
17package android.security;
18
19import android.net.LocalSocketAddress;
20import android.net.LocalSocket;
21
22import java.io.InputStream;
23import java.io.IOException;
24import java.io.OutputStream;
25import java.io.UnsupportedEncodingException;
26import java.nio.charset.Charsets;
27import java.util.ArrayList;
28
29/**
30 * @hide This should not be made public in its present form because it
31 * assumes that private and secret key bytes are available and would
32 * preclude the use of hardware crypto.
33 */
34public class KeyStore {
35
36    // ResponseCodes
37    public static final int NO_ERROR = 1;
38    public static final int LOCKED = 2;
39    public static final int UNINITIALIZED = 3;
40    public static final int SYSTEM_ERROR = 4;
41    public static final int PROTOCOL_ERROR = 5;
42    public static final int PERMISSION_DENIED = 6;
43    public static final int KEY_NOT_FOUND = 7;
44    public static final int VALUE_CORRUPTED = 8;
45    public static final int UNDEFINED_ACTION = 9;
46    public static final int WRONG_PASSWORD = 10;
47
48    // States
49    public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
50
51    private static final LocalSocketAddress sAddress = new LocalSocketAddress(
52            "keystore", LocalSocketAddress.Namespace.RESERVED);
53
54    private int mError = NO_ERROR;
55
56    private KeyStore() {}
57
58    public static KeyStore getInstance() {
59        return new KeyStore();
60    }
61
62    public State state() {
63        execute('t');
64        switch (mError) {
65            case NO_ERROR: return State.UNLOCKED;
66            case LOCKED: return State.LOCKED;
67            case UNINITIALIZED: return State.UNINITIALIZED;
68            default: throw new AssertionError(mError);
69        }
70    }
71
72    private byte[] get(byte[] key) {
73        ArrayList<byte[]> values = execute('g', key);
74        return (values == null || values.isEmpty()) ? null : values.get(0);
75    }
76
77    public byte[] get(String key) {
78        return get(getBytes(key));
79    }
80
81    private boolean put(byte[] key, byte[] value) {
82        execute('i', key, value);
83        return mError == NO_ERROR;
84    }
85
86    public boolean put(String key, byte[] value) {
87        return put(getBytes(key), value);
88    }
89
90    private boolean delete(byte[] key) {
91        execute('d', key);
92        return mError == NO_ERROR;
93    }
94
95    public boolean delete(String key) {
96        return delete(getBytes(key));
97    }
98
99    private boolean contains(byte[] key) {
100        execute('e', key);
101        return mError == NO_ERROR;
102    }
103
104    public boolean contains(String key) {
105        return contains(getBytes(key));
106    }
107
108    public byte[][] saw(byte[] prefix) {
109        ArrayList<byte[]> values = execute('s', prefix);
110        return (values == null) ? null : values.toArray(new byte[values.size()][]);
111    }
112
113    public String[] saw(String prefix) {
114        byte[][] values = saw(getBytes(prefix));
115        if (values == null) {
116            return null;
117        }
118        String[] strings = new String[values.length];
119        for (int i = 0; i < values.length; ++i) {
120            strings[i] = toString(values[i]);
121        }
122        return strings;
123    }
124
125    public boolean reset() {
126        execute('r');
127        return mError == NO_ERROR;
128    }
129
130    private boolean password(byte[] password) {
131        execute('p', password);
132        return mError == NO_ERROR;
133    }
134
135    public boolean password(String password) {
136        return password(getBytes(password));
137    }
138
139    public boolean lock() {
140        execute('l');
141        return mError == NO_ERROR;
142    }
143
144    private boolean unlock(byte[] password) {
145        execute('u', password);
146        return mError == NO_ERROR;
147    }
148
149    public boolean unlock(String password) {
150        return unlock(getBytes(password));
151    }
152
153    public boolean isEmpty() {
154        execute('z');
155        return mError == KEY_NOT_FOUND;
156    }
157
158    private boolean generate(byte[] key) {
159        execute('a', key);
160        return mError == NO_ERROR;
161    }
162
163    public boolean generate(String key) {
164        return generate(getBytes(key));
165    }
166
167    private boolean importKey(byte[] keyName, byte[] key) {
168        execute('m', keyName, key);
169        return mError == NO_ERROR;
170    }
171
172    public boolean importKey(String keyName, byte[] key) {
173        return importKey(getBytes(keyName), key);
174    }
175
176    private byte[] getPubkey(byte[] key) {
177        ArrayList<byte[]> values = execute('b', key);
178        return (values == null || values.isEmpty()) ? null : values.get(0);
179    }
180
181    public byte[] getPubkey(String key) {
182        return getPubkey(getBytes(key));
183    }
184
185    private boolean delKey(byte[] key) {
186        execute('k', key);
187        return mError == NO_ERROR;
188    }
189
190    public boolean delKey(String key) {
191        return delKey(getBytes(key));
192    }
193
194    private byte[] sign(byte[] keyName, byte[] data) {
195        final ArrayList<byte[]> values = execute('n', keyName, data);
196        return (values == null || values.isEmpty()) ? null : values.get(0);
197    }
198
199    public byte[] sign(String key, byte[] data) {
200        return sign(getBytes(key), data);
201    }
202
203    private boolean verify(byte[] keyName, byte[] data, byte[] signature) {
204        execute('v', keyName, data, signature);
205        return mError == NO_ERROR;
206    }
207
208    public boolean verify(String key, byte[] data, byte[] signature) {
209        return verify(getBytes(key), data, signature);
210    }
211
212    private boolean grant(byte[] key, byte[] uid) {
213        execute('x', key, uid);
214        return mError == NO_ERROR;
215    }
216
217    public boolean grant(String key, int uid) {
218        return grant(getBytes(key), Integer.toString(uid).getBytes());
219    }
220
221    private boolean ungrant(byte[] key, byte[] uid) {
222        execute('y', key, uid);
223        return mError == NO_ERROR;
224    }
225
226    public boolean ungrant(String key, int uid) {
227        return ungrant(getBytes(key), Integer.toString(uid).getBytes());
228    }
229
230    public int getLastError() {
231        return mError;
232    }
233
234    private ArrayList<byte[]> execute(int code, byte[]... parameters) {
235        mError = PROTOCOL_ERROR;
236
237        for (byte[] parameter : parameters) {
238            if (parameter == null || parameter.length > 65535) {
239                return null;
240            }
241        }
242
243        LocalSocket socket = new LocalSocket();
244        try {
245            socket.connect(sAddress);
246
247            OutputStream out = socket.getOutputStream();
248            out.write(code);
249            for (byte[] parameter : parameters) {
250                out.write(parameter.length >> 8);
251                out.write(parameter.length);
252                out.write(parameter);
253            }
254            out.flush();
255            socket.shutdownOutput();
256
257            InputStream in = socket.getInputStream();
258            if ((code = in.read()) != NO_ERROR) {
259                if (code != -1) {
260                    mError = code;
261                }
262                return null;
263            }
264
265            ArrayList<byte[]> values = new ArrayList<byte[]>();
266            while (true) {
267                int i, j;
268                if ((i = in.read()) == -1) {
269                    break;
270                }
271                if ((j = in.read()) == -1) {
272                    return null;
273                }
274                byte[] value = new byte[i << 8 | j];
275                for (i = 0; i < value.length; i += j) {
276                    if ((j = in.read(value, i, value.length - i)) == -1) {
277                        return null;
278                    }
279                }
280                values.add(value);
281            }
282            mError = NO_ERROR;
283            return values;
284        } catch (IOException e) {
285            // ignore
286        } finally {
287            try {
288                socket.close();
289            } catch (IOException e) {}
290        }
291        return null;
292    }
293
294    private static byte[] getBytes(String string) {
295        return string.getBytes(Charsets.UTF_8);
296    }
297
298    private static String toString(byte[] bytes) {
299        return new String(bytes, Charsets.UTF_8);
300    }
301}
302