blob: e4102a920e27558d68c3bca6a48570ccaef7c747 [file] [log] [blame]
Chung-yih Wangc186c662009-06-29 03:12:56 +08001/*
2** Copyright 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
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <ctype.h>
23#include <fcntl.h>
24#include <dirent.h>
25#include <errno.h>
26#include <openssl/aes.h>
27#include <openssl/evp.h>
28#include <cutils/log.h>
29
30#include "common.h"
31#include "keymgmt.h"
32
33static int retry_count = 0;
34static unsigned char iv[IV_LEN];
35static KEYSTORE_STATE state = BOOTUP;
36static AES_KEY encryptKey, decryptKey;
37
38inline void unlock_keystore(unsigned char *master_key)
39{
40 AES_set_encrypt_key(master_key, AES_KEY_LEN, &encryptKey);
41 AES_set_decrypt_key(master_key, AES_KEY_LEN, &decryptKey);
42 memset(master_key, 0, sizeof(master_key));
43 state = UNLOCKED;
44}
45
46inline void lock_keystore()
47{
48 memset(&encryptKey, 0 , sizeof(AES_KEY));
49 memset(&decryptKey, 0 , sizeof(AES_KEY));
50 state = LOCKED;
51}
52
53inline void get_encrypt_key(char *passwd, AES_KEY *key)
54{
55 unsigned char user_key[USER_KEY_LEN];
56 gen_key(passwd, user_key, USER_KEY_LEN);
57 AES_set_encrypt_key(user_key, AES_KEY_LEN, key);
58}
59
60inline void get_decrypt_key(char *passwd, AES_KEY *key)
61{
62 unsigned char user_key[USER_KEY_LEN];
63 gen_key(passwd, user_key, USER_KEY_LEN);
64 AES_set_decrypt_key(user_key, AES_KEY_LEN, key);
65}
66
67static int gen_random_blob(unsigned char *key, int size)
68{
69 int ret = 0;
70 int fd = open("/dev/urandom", O_RDONLY);
71 if (fd == -1) return -1;
72 if (read(fd, key, size) != size) ret = -1;
73 close(fd);
74 return ret;
75}
76
77static int encrypt_n_save(AES_KEY *enc_key, DATA_BLOB *blob,
78 const char *keyfile)
79{
80 int size, fd, ret = -1;
81 unsigned char enc_blob[MAX_BLOB_LEN];
82
83 char tmpfile[KEYFILE_LEN];
84 strcpy(tmpfile, keyfile);
85 strcat(tmpfile, ".tmp");
86
87 // prepare the blob
88 memcpy(blob->iv, iv, IV_LEN);
89 blob->blob_size = get_blob_size(blob);
90 memcpy(enc_blob, blob->blob, blob->blob_size);
91 AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char *)blob->blob,
92 blob->blob_size, enc_key, iv, AES_ENCRYPT);
93 // write to keyfile
94 size = data_blob_size(blob);
95 if ((fd = open(tmpfile, O_CREAT|O_RDWR)) == -1) return -1;
96 if (write(fd, blob, size) == size) ret = 0;
97 close(fd);
98 if (!ret) {
99 unlink(keyfile);
100 rename(tmpfile, keyfile);
101 chmod(keyfile, 0440);
102 }
103 return ret;
104}
105
106static int load_n_decrypt(const char *keyname, const char *keyfile,
107 AES_KEY *key, DATA_BLOB *blob)
108{
109 int fd, ret = -1;
110 if ((fd = open(keyfile, O_RDONLY)) == -1) return -1;
111 // get the encrypted blob and iv
112 if ((read(fd, blob->iv, sizeof(blob->iv)) != sizeof(blob->iv)) ||
113 (read(fd, &blob->blob_size, sizeof(uint32_t)) != sizeof(uint32_t)) ||
114 (blob->blob_size > MAX_BLOB_LEN)) {
115 goto err;
116 } else {
117 unsigned char enc_blob[MAX_BLOB_LEN];
118 if (read(fd, enc_blob, blob->blob_size) !=
119 (int) blob->blob_size) goto err;
120 // decrypt the blob
121 AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char*)blob->blob,
122 blob->blob_size, key, blob->iv, AES_DECRYPT);
123 if (strcmp(keyname, (char*)blob->keyname) == 0) ret = 0;
124 }
125err:
126 close(fd);
127 return ret;
128}
129
130static int store_master_key(char *upasswd, unsigned char *master_key)
131{
132 AES_KEY key;
133 DATA_BLOB blob;
134
135 // prepare the blob
136 strlcpy(blob.keyname, MASTER_KEY_TAG, USER_KEY_LEN);
137 blob.value_size = USER_KEY_LEN;
138 memcpy((void*)blob.value, (const void*)master_key, USER_KEY_LEN);
139
140 // generate the encryption key
141 get_encrypt_key(upasswd, &key);
142 return encrypt_n_save(&key, &blob, MASTER_KEY);
143}
144
145static int get_master_key(char *upasswd, unsigned char *master_key)
146{
147 AES_KEY key;
148 int size, ret = 0;
149 DATA_BLOB blob;
150
151 get_decrypt_key(upasswd, &key);
152 ret = load_n_decrypt(MASTER_KEY_TAG, MASTER_KEY, &key, &blob);
153 if (!ret) memcpy(master_key, blob.value, blob.value_size);
154 return ret;
155}
156
157static int create_master_key(char *upasswd)
158{
159 int ret;
160 unsigned char mpasswd[AES_KEY_LEN];
161 unsigned char master_key[USER_KEY_LEN];
162
163 gen_random_blob(mpasswd, AES_KEY_LEN);
164 gen_key((char*)mpasswd, master_key, USER_KEY_LEN);
165 if ((ret = store_master_key(upasswd, master_key)) == 0) {
166 unlock_keystore(master_key);
167 }
168 memset(master_key, 0, USER_KEY_LEN);
169 memset(mpasswd, 0, AES_KEY_LEN);
170
171 return ret;
172}
173
174static int change_passwd(char *data)
175{
176 unsigned char master_key[USER_KEY_LEN];
177 char *old_pass, *new_pass = NULL, *p, *delimiter=" ";
178 int ret, count = 0;
179 char *context = NULL;
180
181 old_pass = p = strtok_r(data, delimiter, &context);
182 while (p != NULL) {
183 count++;
184 new_pass = p;
185 p = strtok_r(NULL, delimiter, &context);
186 }
187 if (count != 2) return -1;
188 if ((ret = get_master_key(old_pass, master_key)) == 0) {
189 ret = store_master_key(new_pass, master_key);
190 retry_count = 0;
191 } else {
192 ret = MAX_RETRY_COUNT - ++retry_count;
193 if (ret == 0) {
194 retry_count = 0;
195 LOGE("passwd:reach max retry count, reset the keystore now.");
196 reset_keystore();
197 return -1;
198 }
199
200 }
201 return ret;
202}
203
204int remove_key(const char *namespace, const char *keyname)
205{
206 char keyfile[KEYFILE_LEN];
207
208 if (state != UNLOCKED) return -state;
209 sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
210 return unlink(keyfile);
211}
212
213int put_key(const char *namespace, const char *keyname,
214 unsigned char *data, int size)
215{
216 DATA_BLOB blob;
217 uint32_t real_size;
218 char keyfile[KEYFILE_LEN];
219
220 if (state != UNLOCKED) {
221 LOGE("Can not store key with current state %d\n", state);
222 return -state;
223 }
224 sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
225 // flatten the args
226 strcpy(blob.keyname, keyname);
227 blob.value_size = size;
228 memcpy(blob.value, data, size);
229 return encrypt_n_save(&encryptKey, &blob, keyfile);
230}
231
232int get_key(const char *namespace, const char *keyname,
233 unsigned char *data, int *size)
234{
235 int ret;
236 DATA_BLOB blob;
237 uint32_t blob_size;
238 char keyfile[KEYFILE_LEN];
239
240 if (state != UNLOCKED) {
241 LOGE("Can not retrieve key value with current state %d\n", state);
242 return -state;
243 }
244 sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
245 ret = load_n_decrypt(keyname, keyfile, &decryptKey, &blob);
246 if (!ret) {
247 if ((blob.value_size > MAX_KEY_VALUE_LENGTH)) {
248 ret = -1;
249 } else {
250 *size = blob.value_size;
251 memcpy(data, blob.value, *size);
252 }
253 }
254 return ret;
255}
256
257int list_keys(const char *namespace, char reply[BUFFER_MAX])
258{
259 DIR *d;
260 struct dirent *de;
261
262 if (!namespace || ((d = opendir("."))) == NULL) {
263 LOGE("cannot open keystore dir or namespace is null\n");
264 return -1;
265 }
266 while ((de = readdir(d))) {
267 char *prefix, *name, *keyfile = de->d_name;
268 char *context = NULL;
269
270 if (de->d_type != DT_REG) continue;
271 if ((prefix = strtok_r(keyfile, NAME_DELIMITER, &context))
272 == NULL) continue;
273 if (strcmp(prefix, namespace)) continue;
274 if ((name = strtok_r(NULL, NAME_DELIMITER, &context)) == NULL) continue;
275 // append the key name into reply
276 if (reply[0] != 0) strlcat(reply, " ", BUFFER_MAX);
277 if (strlcat(reply, name, BUFFER_MAX) >= BUFFER_MAX) {
278 LOGE("too many files under keystore directory\n");
279 return -1;
280 }
281 }
282 closedir(d);
283 return 0;
284}
285
286int passwd(char *data)
287{
288 if (state == UNINITIALIZED) {
289 if (strchr(data, ' ')) return -1;
290 return create_master_key(data);
291 }
292 return change_passwd(data);
293}
294
295int lock()
296{
297 switch(state) {
298 case UNLOCKED:
299 lock_keystore();
300 case LOCKED:
301 return 0;
302 default:
303 return -1;
304 }
305}
306
307int unlock(char *passwd)
308{
309 unsigned char master_key[USER_KEY_LEN];
310 int ret = get_master_key(passwd, master_key);
311 if (!ret) {
312 unlock_keystore(master_key);
313 retry_count = 0;
314 } else {
315 ret = MAX_RETRY_COUNT - ++retry_count;
316 if (ret == 0) {
317 retry_count = 0;
318 LOGE("unlock:reach max retry count, reset the keystore now.");
319 reset_keystore();
320 return -1;
321 }
322 }
323 return ret;
324}
325
326KEYSTORE_STATE get_state()
327{
328 return state;
329}
330
331int reset_keystore()
332{
333 DIR *d;
334 struct dirent *de;
335
336 if ((d = opendir(".")) == NULL) {
337 LOGE("cannot open keystore dir\n");
338 return -1;
339 }
340 while ((de = readdir(d))) unlink(de->d_name);
341 closedir(d);
342 state = UNINITIALIZED;
343 LOGI("keystore is reset.");
344 return 0;
345}
346
347int init_keystore(const char *dir)
348{
349 int fd;
350
351 if (!dir) mkdir(dir, 0770);
352 if (!dir || chdir(dir)) {
353 LOGE("Can not open/create the keystore directory %s\n",
354 dir ? dir : "(null)");
355 return -1;
356 }
357 gen_random_blob(iv, IV_LEN);
358 if ((fd = open(MASTER_KEY, O_RDONLY)) == -1) {
359 state = UNINITIALIZED;
360 return 0;
361 }
362 close(fd);
363 state = LOCKED;
364 return 0;
365}