blob: c45b53caac70ad66a4d8f57ff5f6b6c346e9a80c [file] [log] [blame]
Chung-yih Wang70246eb2009-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];
Chung-yih Wang70246eb2009-06-29 03:12:56 +080082 char tmpfile[KEYFILE_LEN];
Chung-yih Wang75b68162009-07-23 07:23:24 +080083
84 if ((keyfile == NULL) || (strlen(keyfile) >= (KEYFILE_LEN - 4))) {
85 LOGE("keyfile name is too long or null");
86 return -1;
87 }
Chung-yih Wang70246eb2009-06-29 03:12:56 +080088 strcpy(tmpfile, keyfile);
89 strcat(tmpfile, ".tmp");
90
91 // prepare the blob
Chung-yih Wang75b68162009-07-23 07:23:24 +080092 if (IV_LEN > USER_KEY_LEN) {
93 LOGE("iv length is too long.");
94 return -1;
95 }
Chung-yih Wang70246eb2009-06-29 03:12:56 +080096 memcpy(blob->iv, iv, IV_LEN);
97 blob->blob_size = get_blob_size(blob);
Chung-yih Wang75b68162009-07-23 07:23:24 +080098 if (blob->blob_size > MAX_BLOB_LEN) {
99 LOGE("blob data size is too large.");
100 return -1;
101 }
Chung-yih Wang70246eb2009-06-29 03:12:56 +0800102 memcpy(enc_blob, blob->blob, blob->blob_size);
103 AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char *)blob->blob,
104 blob->blob_size, enc_key, iv, AES_ENCRYPT);
105 // write to keyfile
106 size = data_blob_size(blob);
107 if ((fd = open(tmpfile, O_CREAT|O_RDWR)) == -1) return -1;
108 if (write(fd, blob, size) == size) ret = 0;
109 close(fd);
110 if (!ret) {
111 unlink(keyfile);
112 rename(tmpfile, keyfile);
113 chmod(keyfile, 0440);
114 }
115 return ret;
116}
117
118static int load_n_decrypt(const char *keyname, const char *keyfile,
119 AES_KEY *key, DATA_BLOB *blob)
120{
121 int fd, ret = -1;
122 if ((fd = open(keyfile, O_RDONLY)) == -1) return -1;
123 // get the encrypted blob and iv
124 if ((read(fd, blob->iv, sizeof(blob->iv)) != sizeof(blob->iv)) ||
125 (read(fd, &blob->blob_size, sizeof(uint32_t)) != sizeof(uint32_t)) ||
126 (blob->blob_size > MAX_BLOB_LEN)) {
127 goto err;
128 } else {
129 unsigned char enc_blob[MAX_BLOB_LEN];
130 if (read(fd, enc_blob, blob->blob_size) !=
131 (int) blob->blob_size) goto err;
132 // decrypt the blob
133 AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char*)blob->blob,
134 blob->blob_size, key, blob->iv, AES_DECRYPT);
135 if (strcmp(keyname, (char*)blob->keyname) == 0) ret = 0;
136 }
137err:
138 close(fd);
139 return ret;
140}
141
142static int store_master_key(char *upasswd, unsigned char *master_key)
143{
144 AES_KEY key;
145 DATA_BLOB blob;
146
147 // prepare the blob
Chung-yih Wang75b68162009-07-23 07:23:24 +0800148 if (strlen(MASTER_KEY_TAG) >= USER_KEY_LEN) return -1;
Chung-yih Wang70246eb2009-06-29 03:12:56 +0800149 strlcpy(blob.keyname, MASTER_KEY_TAG, USER_KEY_LEN);
150 blob.value_size = USER_KEY_LEN;
Chung-yih Wang75b68162009-07-23 07:23:24 +0800151 if (USER_KEY_LEN > MAX_KEY_VALUE_LENGTH) {
152 LOGE("master_key length is too long.");
153 return -1;
154 }
Chung-yih Wang70246eb2009-06-29 03:12:56 +0800155 memcpy((void*)blob.value, (const void*)master_key, USER_KEY_LEN);
156
157 // generate the encryption key
158 get_encrypt_key(upasswd, &key);
159 return encrypt_n_save(&key, &blob, MASTER_KEY);
160}
161
162static int get_master_key(char *upasswd, unsigned char *master_key)
163{
164 AES_KEY key;
165 int size, ret = 0;
166 DATA_BLOB blob;
167
168 get_decrypt_key(upasswd, &key);
169 ret = load_n_decrypt(MASTER_KEY_TAG, MASTER_KEY, &key, &blob);
Chung-yih Wang75b68162009-07-23 07:23:24 +0800170 if (blob.value_size > USER_KEY_LEN) {
171 LOGE("the blob's value size is too large");
172 return -1;
173 }
Chung-yih Wang70246eb2009-06-29 03:12:56 +0800174 if (!ret) memcpy(master_key, blob.value, blob.value_size);
175 return ret;
176}
177
178static int create_master_key(char *upasswd)
179{
180 int ret;
181 unsigned char mpasswd[AES_KEY_LEN];
182 unsigned char master_key[USER_KEY_LEN];
183
184 gen_random_blob(mpasswd, AES_KEY_LEN);
185 gen_key((char*)mpasswd, master_key, USER_KEY_LEN);
186 if ((ret = store_master_key(upasswd, master_key)) == 0) {
187 unlock_keystore(master_key);
188 }
189 memset(master_key, 0, USER_KEY_LEN);
190 memset(mpasswd, 0, AES_KEY_LEN);
191
192 return ret;
193}
194
195static int change_passwd(char *data)
196{
197 unsigned char master_key[USER_KEY_LEN];
198 char *old_pass, *new_pass = NULL, *p, *delimiter=" ";
199 int ret, count = 0;
200 char *context = NULL;
201
202 old_pass = p = strtok_r(data, delimiter, &context);
203 while (p != NULL) {
204 count++;
205 new_pass = p;
206 p = strtok_r(NULL, delimiter, &context);
207 }
208 if (count != 2) return -1;
Chung-yih Wanga7342072009-07-03 12:09:52 +0800209 if (strlen(new_pass) < MIN_PASSWD_LENGTH) return -1;
Chung-yih Wang70246eb2009-06-29 03:12:56 +0800210 if ((ret = get_master_key(old_pass, master_key)) == 0) {
211 ret = store_master_key(new_pass, master_key);
212 retry_count = 0;
213 } else {
214 ret = MAX_RETRY_COUNT - ++retry_count;
215 if (ret == 0) {
216 retry_count = 0;
217 LOGE("passwd:reach max retry count, reset the keystore now.");
218 reset_keystore();
219 return -1;
220 }
221
222 }
223 return ret;
224}
225
226int remove_key(const char *namespace, const char *keyname)
227{
228 char keyfile[KEYFILE_LEN];
229
230 if (state != UNLOCKED) return -state;
231 sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
232 return unlink(keyfile);
233}
234
235int put_key(const char *namespace, const char *keyname,
236 unsigned char *data, int size)
237{
238 DATA_BLOB blob;
239 uint32_t real_size;
240 char keyfile[KEYFILE_LEN];
241
242 if (state != UNLOCKED) {
243 LOGE("Can not store key with current state %d\n", state);
244 return -state;
245 }
246 sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
247 // flatten the args
Chung-yih Wang75b68162009-07-23 07:23:24 +0800248 if (strlen(keyname) >= MAX_KEY_NAME_LENGTH) {
249 LOGE("keyname is too long.");
250 return -1;
251 }
Chung-yih Wang70246eb2009-06-29 03:12:56 +0800252 strcpy(blob.keyname, keyname);
253 blob.value_size = size;
Chung-yih Wang75b68162009-07-23 07:23:24 +0800254 if (size > MAX_KEY_VALUE_LENGTH) {
255 LOGE("the data size is too large.");
256 return -1;
257 }
Chung-yih Wang70246eb2009-06-29 03:12:56 +0800258 memcpy(blob.value, data, size);
259 return encrypt_n_save(&encryptKey, &blob, keyfile);
260}
261
262int get_key(const char *namespace, const char *keyname,
263 unsigned char *data, int *size)
264{
265 int ret;
266 DATA_BLOB blob;
267 uint32_t blob_size;
268 char keyfile[KEYFILE_LEN];
269
270 if (state != UNLOCKED) {
271 LOGE("Can not retrieve key value with current state %d\n", state);
272 return -state;
273 }
274 sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
275 ret = load_n_decrypt(keyname, keyfile, &decryptKey, &blob);
276 if (!ret) {
277 if ((blob.value_size > MAX_KEY_VALUE_LENGTH)) {
Chung-yih Wang75b68162009-07-23 07:23:24 +0800278 LOGE("blob value size is too large.");
Chung-yih Wang70246eb2009-06-29 03:12:56 +0800279 ret = -1;
280 } else {
281 *size = blob.value_size;
282 memcpy(data, blob.value, *size);
283 }
284 }
285 return ret;
286}
287
288int list_keys(const char *namespace, char reply[BUFFER_MAX])
289{
290 DIR *d;
291 struct dirent *de;
292
Chung-yih Wanga7342072009-07-03 12:09:52 +0800293 if (state != UNLOCKED) {
294 LOGE("Can not list key with current state %d\n", state);
295 return -1;
296 }
297
Chung-yih Wang70246eb2009-06-29 03:12:56 +0800298 if (!namespace || ((d = opendir("."))) == NULL) {
299 LOGE("cannot open keystore dir or namespace is null\n");
300 return -1;
301 }
302 while ((de = readdir(d))) {
303 char *prefix, *name, *keyfile = de->d_name;
304 char *context = NULL;
305
306 if (de->d_type != DT_REG) continue;
307 if ((prefix = strtok_r(keyfile, NAME_DELIMITER, &context))
308 == NULL) continue;
309 if (strcmp(prefix, namespace)) continue;
310 if ((name = strtok_r(NULL, NAME_DELIMITER, &context)) == NULL) continue;
311 // append the key name into reply
312 if (reply[0] != 0) strlcat(reply, " ", BUFFER_MAX);
313 if (strlcat(reply, name, BUFFER_MAX) >= BUFFER_MAX) {
314 LOGE("too many files under keystore directory\n");
315 return -1;
316 }
317 }
318 closedir(d);
319 return 0;
320}
321
322int passwd(char *data)
323{
324 if (state == UNINITIALIZED) {
325 if (strchr(data, ' ')) return -1;
Chung-yih Wanga7342072009-07-03 12:09:52 +0800326 if (strlen(data) < MIN_PASSWD_LENGTH) return -1;
Chung-yih Wang70246eb2009-06-29 03:12:56 +0800327 return create_master_key(data);
328 }
329 return change_passwd(data);
330}
331
332int lock()
333{
334 switch(state) {
335 case UNLOCKED:
336 lock_keystore();
337 case LOCKED:
338 return 0;
339 default:
340 return -1;
341 }
342}
343
344int unlock(char *passwd)
345{
346 unsigned char master_key[USER_KEY_LEN];
347 int ret = get_master_key(passwd, master_key);
348 if (!ret) {
349 unlock_keystore(master_key);
350 retry_count = 0;
351 } else {
352 ret = MAX_RETRY_COUNT - ++retry_count;
353 if (ret == 0) {
354 retry_count = 0;
355 LOGE("unlock:reach max retry count, reset the keystore now.");
356 reset_keystore();
357 return -1;
358 }
359 }
360 return ret;
361}
362
363KEYSTORE_STATE get_state()
364{
365 return state;
366}
367
368int reset_keystore()
369{
370 DIR *d;
371 struct dirent *de;
372
373 if ((d = opendir(".")) == NULL) {
374 LOGE("cannot open keystore dir\n");
375 return -1;
376 }
377 while ((de = readdir(d))) unlink(de->d_name);
378 closedir(d);
379 state = UNINITIALIZED;
380 LOGI("keystore is reset.");
381 return 0;
382}
383
384int init_keystore(const char *dir)
385{
386 int fd;
387
388 if (!dir) mkdir(dir, 0770);
389 if (!dir || chdir(dir)) {
390 LOGE("Can not open/create the keystore directory %s\n",
391 dir ? dir : "(null)");
392 return -1;
393 }
394 gen_random_blob(iv, IV_LEN);
395 if ((fd = open(MASTER_KEY, O_RDONLY)) == -1) {
396 state = UNINITIALIZED;
397 return 0;
398 }
399 close(fd);
400 state = LOCKED;
401 return 0;
402}