Merge change 26794 into eclair
* changes: keystore: remove old implementation and test.
This commit is contained in:
@@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
**
|
|
||||||
** Copyright 2009, The Android Open Source Project
|
|
||||||
**
|
|
||||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
** you may not use this file except in compliance with the License.
|
|
||||||
** You may obtain a copy of the License at
|
|
||||||
**
|
|
||||||
** http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
**
|
|
||||||
** Unless required by applicable law or agreed to in writing, software
|
|
||||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
** See the License for the specific language governing permissions and
|
|
||||||
** limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __CERTTOOL_H__
|
|
||||||
#define __CERTTOOL_H__
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <cutils/sockets.h>
|
|
||||||
#include <cutils/log.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "netkeystore.h"
|
|
||||||
|
|
||||||
#define CERT_NAME_LEN (2 * MAX_KEY_NAME_LENGTH + 2)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The specific function 'get_cert' is used in daemons to get the key value
|
|
||||||
* from keystore. Caller should allocate the buffer and the length of the buffer
|
|
||||||
* should be MAX_KEY_VALUE_LENGTH.
|
|
||||||
*/
|
|
||||||
static inline int get_cert(const char *certname, unsigned char *value, int *size)
|
|
||||||
{
|
|
||||||
int count, fd, ret = -1;
|
|
||||||
LPC_MARSHAL cmd;
|
|
||||||
char delimiter[] = "_";
|
|
||||||
char *p = NULL;
|
|
||||||
char *context = NULL;
|
|
||||||
char *cname = (char*)cmd.data;
|
|
||||||
|
|
||||||
if ((certname == NULL) || (value == NULL)) {
|
|
||||||
LOGE("get_cert: certname or value is null\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlcpy(cname, certname, CERT_NAME_LEN) >= CERT_NAME_LEN) {
|
|
||||||
LOGE("get_cert: keyname is too long\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = socket_local_client(SOCKET_PATH,
|
|
||||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
|
||||||
SOCK_STREAM);
|
|
||||||
if (fd == -1) {
|
|
||||||
LOGE("Keystore service is not up and running.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.opcode = GET;
|
|
||||||
p = strstr(cname, delimiter);
|
|
||||||
cmd.len = strlen(certname) + 1;
|
|
||||||
if (p == NULL) goto err;
|
|
||||||
*p = 0; // replace the delimiter with \0 .
|
|
||||||
|
|
||||||
if (write_marshal(fd, &cmd)) {
|
|
||||||
LOGE("Incorrect command or command line is too long.\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (read_marshal(fd, &cmd)) {
|
|
||||||
LOGE("Failed to read the result.\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy the result if succeeded.
|
|
||||||
if (!cmd.retcode && cmd.len <= BUFFER_MAX) {
|
|
||||||
memcpy(value, cmd.data, cmd.len);
|
|
||||||
ret = 0;
|
|
||||||
*size = cmd.len;
|
|
||||||
}
|
|
||||||
err:
|
|
||||||
close(fd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
**
|
|
||||||
** Copyright 2009, The Android Open Source Project
|
|
||||||
**
|
|
||||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
** you may not use this file except in compliance with the License.
|
|
||||||
** You may obtain a copy of the License at
|
|
||||||
**
|
|
||||||
** http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
**
|
|
||||||
** Unless required by applicable law or agreed to in writing, software
|
|
||||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
** See the License for the specific language governing permissions and
|
|
||||||
** limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __COMMON_H__
|
|
||||||
#define __COMMON_H__
|
|
||||||
|
|
||||||
#define SOCKET_PATH "keystore"
|
|
||||||
#define KEYSTORE_DIR "/data/misc/keystore/"
|
|
||||||
|
|
||||||
#define READ_TIMEOUT 3
|
|
||||||
#define MAX_KEY_NAME_LENGTH 64
|
|
||||||
#define MAX_NAMESPACE_LENGTH MAX_KEY_NAME_LENGTH
|
|
||||||
#define MAX_KEY_VALUE_LENGTH 4096
|
|
||||||
|
|
||||||
#define BUFFER_MAX MAX_KEY_VALUE_LENGTH
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BOOTUP,
|
|
||||||
UNINITIALIZED,
|
|
||||||
LOCKED,
|
|
||||||
UNLOCKED,
|
|
||||||
} KEYSTORE_STATE;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
LOCK,
|
|
||||||
UNLOCK,
|
|
||||||
PASSWD,
|
|
||||||
GETSTATE,
|
|
||||||
LISTKEYS,
|
|
||||||
GET,
|
|
||||||
PUT,
|
|
||||||
REMOVE,
|
|
||||||
RESET,
|
|
||||||
MAX_OPCODE
|
|
||||||
} KEYSTORE_OPCODE;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t len;
|
|
||||||
union {
|
|
||||||
uint32_t opcode;
|
|
||||||
uint32_t retcode;
|
|
||||||
};
|
|
||||||
unsigned char data[BUFFER_MAX + 1];
|
|
||||||
} LPC_MARSHAL;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,421 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2009, The Android Open Source Project
|
|
||||||
**
|
|
||||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
** you may not use this file except in compliance with the License.
|
|
||||||
** You may obtain a copy of the License at
|
|
||||||
**
|
|
||||||
** http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
**
|
|
||||||
** Unless required by applicable law or agreed to in writing, software
|
|
||||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
** See the License for the specific language governing permissions and
|
|
||||||
** limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <openssl/aes.h>
|
|
||||||
#include <openssl/evp.h>
|
|
||||||
#include <cutils/log.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "keymgmt.h"
|
|
||||||
|
|
||||||
static int retry_count = 0;
|
|
||||||
static unsigned char iv[IV_LEN];
|
|
||||||
static KEYSTORE_STATE state = BOOTUP;
|
|
||||||
static AES_KEY encryptKey, decryptKey;
|
|
||||||
|
|
||||||
inline void unlock_keystore(unsigned char *master_key)
|
|
||||||
{
|
|
||||||
AES_set_encrypt_key(master_key, AES_KEY_LEN, &encryptKey);
|
|
||||||
AES_set_decrypt_key(master_key, AES_KEY_LEN, &decryptKey);
|
|
||||||
memset(master_key, 0, sizeof(master_key));
|
|
||||||
state = UNLOCKED;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void lock_keystore()
|
|
||||||
{
|
|
||||||
memset(&encryptKey, 0 , sizeof(AES_KEY));
|
|
||||||
memset(&decryptKey, 0 , sizeof(AES_KEY));
|
|
||||||
state = LOCKED;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void get_encrypt_key(char *passwd, AES_KEY *key)
|
|
||||||
{
|
|
||||||
unsigned char user_key[USER_KEY_LEN];
|
|
||||||
gen_key(passwd, user_key, USER_KEY_LEN);
|
|
||||||
AES_set_encrypt_key(user_key, AES_KEY_LEN, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void get_decrypt_key(char *passwd, AES_KEY *key)
|
|
||||||
{
|
|
||||||
unsigned char user_key[USER_KEY_LEN];
|
|
||||||
gen_key(passwd, user_key, USER_KEY_LEN);
|
|
||||||
AES_set_decrypt_key(user_key, AES_KEY_LEN, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gen_random_blob(unsigned char *key, int size)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
int fd = open("/dev/urandom", O_RDONLY);
|
|
||||||
if (fd == -1) return -1;
|
|
||||||
if (read(fd, key, size) != size) ret = -1;
|
|
||||||
close(fd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int encrypt_n_save(AES_KEY *enc_key, DATA_BLOB *blob,
|
|
||||||
const char *keyfile)
|
|
||||||
{
|
|
||||||
int size, fd, ret = -1;
|
|
||||||
unsigned char enc_blob[MAX_BLOB_LEN];
|
|
||||||
char tmpfile[KEYFILE_LEN];
|
|
||||||
|
|
||||||
if ((keyfile == NULL) || (strlen(keyfile) >= (KEYFILE_LEN - 4))) {
|
|
||||||
LOGE("keyfile name is too long or null");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
strcpy(tmpfile, keyfile);
|
|
||||||
strcat(tmpfile, ".tmp");
|
|
||||||
|
|
||||||
// prepare the blob
|
|
||||||
if (IV_LEN > USER_KEY_LEN) {
|
|
||||||
LOGE("iv length is too long.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memcpy(blob->iv, iv, IV_LEN);
|
|
||||||
blob->blob_size = get_blob_size(blob);
|
|
||||||
if (blob->blob_size > MAX_BLOB_LEN) {
|
|
||||||
LOGE("blob data size is too large.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memcpy(enc_blob, blob->blob, blob->blob_size);
|
|
||||||
AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char *)blob->blob,
|
|
||||||
blob->blob_size, enc_key, iv, AES_ENCRYPT);
|
|
||||||
// write to keyfile
|
|
||||||
size = data_blob_size(blob);
|
|
||||||
if ((fd = open(tmpfile, O_CREAT|O_RDWR)) == -1) return -1;
|
|
||||||
if (write(fd, blob, size) == size) ret = 0;
|
|
||||||
close(fd);
|
|
||||||
if (!ret) {
|
|
||||||
unlink(keyfile);
|
|
||||||
rename(tmpfile, keyfile);
|
|
||||||
chmod(keyfile, 0440);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int load_n_decrypt(const char *keyname, const char *keyfile,
|
|
||||||
AES_KEY *key, DATA_BLOB *blob)
|
|
||||||
{
|
|
||||||
int fd, ret = -1;
|
|
||||||
if ((fd = open(keyfile, O_RDONLY)) == -1) return -1;
|
|
||||||
// get the encrypted blob and iv
|
|
||||||
if ((read(fd, blob->iv, sizeof(blob->iv)) != sizeof(blob->iv)) ||
|
|
||||||
(read(fd, &blob->blob_size, sizeof(uint32_t)) != sizeof(uint32_t)) ||
|
|
||||||
(blob->blob_size > MAX_BLOB_LEN)) {
|
|
||||||
goto err;
|
|
||||||
} else {
|
|
||||||
unsigned char enc_blob[MAX_BLOB_LEN];
|
|
||||||
if (read(fd, enc_blob, blob->blob_size) !=
|
|
||||||
(int) blob->blob_size) goto err;
|
|
||||||
// decrypt the blob
|
|
||||||
AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char*)blob->blob,
|
|
||||||
blob->blob_size, key, blob->iv, AES_DECRYPT);
|
|
||||||
if (strcmp(keyname, (char*)blob->keyname) == 0) ret = 0;
|
|
||||||
}
|
|
||||||
err:
|
|
||||||
close(fd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int store_master_key(char *upasswd, unsigned char *master_key)
|
|
||||||
{
|
|
||||||
AES_KEY key;
|
|
||||||
DATA_BLOB blob;
|
|
||||||
|
|
||||||
// prepare the blob
|
|
||||||
if (strlen(MASTER_KEY_TAG) >= USER_KEY_LEN) return -1;
|
|
||||||
strlcpy(blob.keyname, MASTER_KEY_TAG, USER_KEY_LEN);
|
|
||||||
blob.value_size = USER_KEY_LEN;
|
|
||||||
if (USER_KEY_LEN > MAX_KEY_VALUE_LENGTH) {
|
|
||||||
LOGE("master_key length is too long.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memcpy((void*)blob.value, (const void*)master_key, USER_KEY_LEN);
|
|
||||||
|
|
||||||
// generate the encryption key
|
|
||||||
get_encrypt_key(upasswd, &key);
|
|
||||||
return encrypt_n_save(&key, &blob, MASTER_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_master_key(char *upasswd, unsigned char *master_key)
|
|
||||||
{
|
|
||||||
AES_KEY key;
|
|
||||||
int size, ret = 0;
|
|
||||||
DATA_BLOB blob;
|
|
||||||
|
|
||||||
get_decrypt_key(upasswd, &key);
|
|
||||||
ret = load_n_decrypt(MASTER_KEY_TAG, MASTER_KEY, &key, &blob);
|
|
||||||
if (blob.value_size > USER_KEY_LEN) {
|
|
||||||
LOGE("the blob's value size is too large");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!ret) memcpy(master_key, blob.value, blob.value_size);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int create_master_key(char *upasswd)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
unsigned char mpasswd[AES_KEY_LEN];
|
|
||||||
unsigned char master_key[USER_KEY_LEN];
|
|
||||||
|
|
||||||
gen_random_blob(mpasswd, AES_KEY_LEN);
|
|
||||||
gen_key((char*)mpasswd, master_key, USER_KEY_LEN);
|
|
||||||
if ((ret = store_master_key(upasswd, master_key)) == 0) {
|
|
||||||
unlock_keystore(master_key);
|
|
||||||
}
|
|
||||||
memset(master_key, 0, USER_KEY_LEN);
|
|
||||||
memset(mpasswd, 0, AES_KEY_LEN);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int change_passwd(char *old_pass, char *new_pass)
|
|
||||||
{
|
|
||||||
unsigned char master_key[USER_KEY_LEN];
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (state == UNINITIALIZED) return -1;
|
|
||||||
if ((strlen(old_pass) < MIN_PASSWD_LENGTH) ||
|
|
||||||
(strlen(new_pass) < MIN_PASSWD_LENGTH)) return -1;
|
|
||||||
|
|
||||||
if ((ret = get_master_key(old_pass, master_key)) == 0) {
|
|
||||||
ret = store_master_key(new_pass, master_key);
|
|
||||||
retry_count = 0;
|
|
||||||
} else {
|
|
||||||
ret = MAX_RETRY_COUNT - ++retry_count;
|
|
||||||
if (ret == 0) {
|
|
||||||
retry_count = 0;
|
|
||||||
LOGE("passwd:reach max retry count, reset the keystore now.");
|
|
||||||
reset_keystore();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int remove_key(const char *namespace, const char *keyname)
|
|
||||||
{
|
|
||||||
char keyfile[KEYFILE_LEN];
|
|
||||||
|
|
||||||
if (state != UNLOCKED) return -state;
|
|
||||||
if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
|
|
||||||
(strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
|
|
||||||
LOGE("keyname is too long.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
|
|
||||||
return unlink(keyfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
int put_key(const char *namespace, const char *keyname,
|
|
||||||
unsigned char *data, int size)
|
|
||||||
{
|
|
||||||
DATA_BLOB blob;
|
|
||||||
uint32_t real_size;
|
|
||||||
char keyfile[KEYFILE_LEN];
|
|
||||||
|
|
||||||
if (state != UNLOCKED) {
|
|
||||||
LOGE("Can not store key with current state %d\n", state);
|
|
||||||
return -state;
|
|
||||||
}
|
|
||||||
if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
|
|
||||||
(strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
|
|
||||||
LOGE("keyname is too long.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
|
|
||||||
strcpy(blob.keyname, keyname);
|
|
||||||
blob.value_size = size;
|
|
||||||
if (size > MAX_KEY_VALUE_LENGTH) {
|
|
||||||
LOGE("the data size is too large.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memcpy(blob.value, data, size);
|
|
||||||
return encrypt_n_save(&encryptKey, &blob, keyfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_key(const char *namespace, const char *keyname,
|
|
||||||
unsigned char *data, int *size)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
DATA_BLOB blob;
|
|
||||||
uint32_t blob_size;
|
|
||||||
char keyfile[KEYFILE_LEN];
|
|
||||||
|
|
||||||
if (state != UNLOCKED) {
|
|
||||||
LOGE("Can not retrieve key value with current state %d\n", state);
|
|
||||||
return -state;
|
|
||||||
}
|
|
||||||
if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
|
|
||||||
(strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
|
|
||||||
LOGE("keyname is too long.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
|
|
||||||
ret = load_n_decrypt(keyname, keyfile, &decryptKey, &blob);
|
|
||||||
if (!ret) {
|
|
||||||
if ((blob.value_size > MAX_KEY_VALUE_LENGTH)) {
|
|
||||||
LOGE("blob value size is too large.");
|
|
||||||
ret = -1;
|
|
||||||
} else {
|
|
||||||
*size = blob.value_size;
|
|
||||||
memcpy(data, blob.value, *size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int list_keys(const char *namespace, char reply[BUFFER_MAX])
|
|
||||||
{
|
|
||||||
DIR *d;
|
|
||||||
struct dirent *de;
|
|
||||||
|
|
||||||
if (state != UNLOCKED) {
|
|
||||||
LOGE("Can not list key with current state %d\n", state);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!namespace || ((d = opendir("."))) == NULL) {
|
|
||||||
LOGE("cannot open keystore dir or namespace is null\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(namespace) >= MAX_KEY_NAME_LENGTH) {
|
|
||||||
LOGE("namespace is too long.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
reply[0] = 0;
|
|
||||||
while ((de = readdir(d))) {
|
|
||||||
char *prefix, *name, *keyfile = de->d_name;
|
|
||||||
char *context = NULL;
|
|
||||||
|
|
||||||
if (de->d_type != DT_REG) continue;
|
|
||||||
if ((prefix = strtok_r(keyfile, NAME_DELIMITER, &context))
|
|
||||||
== NULL) continue;
|
|
||||||
if (strcmp(prefix, namespace)) continue;
|
|
||||||
if ((name = strtok_r(NULL, NAME_DELIMITER, &context)) == NULL) continue;
|
|
||||||
// append the key name into reply
|
|
||||||
if (reply[0] != 0) strlcat(reply, " ", BUFFER_MAX);
|
|
||||||
if (strlcat(reply, name, BUFFER_MAX) >= BUFFER_MAX) {
|
|
||||||
LOGE("too many files under keystore directory\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(d);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int new_passwd(char *password)
|
|
||||||
{
|
|
||||||
int passwdlen = strlen(password);
|
|
||||||
|
|
||||||
if ((state != UNINITIALIZED) || (passwdlen < MIN_PASSWD_LENGTH)) return -1;
|
|
||||||
return create_master_key(password);
|
|
||||||
}
|
|
||||||
|
|
||||||
int lock()
|
|
||||||
{
|
|
||||||
switch(state) {
|
|
||||||
case UNLOCKED:
|
|
||||||
lock_keystore();
|
|
||||||
case LOCKED:
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int unlock(char *passwd)
|
|
||||||
{
|
|
||||||
unsigned char master_key[USER_KEY_LEN];
|
|
||||||
int ret = get_master_key(passwd, master_key);
|
|
||||||
if (!ret) {
|
|
||||||
unlock_keystore(master_key);
|
|
||||||
retry_count = 0;
|
|
||||||
} else {
|
|
||||||
ret = MAX_RETRY_COUNT - ++retry_count;
|
|
||||||
if (ret == 0) {
|
|
||||||
retry_count = 0;
|
|
||||||
LOGE("unlock:reach max retry count, reset the keystore now.");
|
|
||||||
reset_keystore();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
KEYSTORE_STATE get_state()
|
|
||||||
{
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
int reset_keystore()
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
DIR *d;
|
|
||||||
struct dirent *de;
|
|
||||||
|
|
||||||
if ((d = opendir(".")) == NULL) {
|
|
||||||
LOGE("cannot open keystore dir\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
while ((de = readdir(d))) {
|
|
||||||
char *dirname = de->d_name;
|
|
||||||
if (strcmp(".", dirname) == 0) continue;
|
|
||||||
if (strcmp("..", dirname) == 0) continue;
|
|
||||||
if (unlink(dirname) != 0) ret = -1;
|
|
||||||
}
|
|
||||||
closedir(d);
|
|
||||||
state = UNINITIALIZED;
|
|
||||||
if (ret == 0) {
|
|
||||||
LOGI("keystore is reset.");
|
|
||||||
} else {
|
|
||||||
LOGI("keystore can not be cleaned up entirely.");
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_keystore(const char *dir)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (dir) mkdir(dir, 0770);
|
|
||||||
if (!dir || chdir(dir)) {
|
|
||||||
LOGE("Can not open/create the keystore directory %s\n",
|
|
||||||
dir ? dir : "(null)");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
gen_random_blob(iv, IV_LEN);
|
|
||||||
if ((fd = open(MASTER_KEY, O_RDONLY)) == -1) {
|
|
||||||
state = UNINITIALIZED;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
state = LOCKED;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2009, The Android Open Source Project
|
|
||||||
**
|
|
||||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
** you may not use this file except in compliance with the License.
|
|
||||||
** You may obtain a copy of the License at
|
|
||||||
**
|
|
||||||
** http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
**
|
|
||||||
** Unless required by applicable law or agreed to in writing, software
|
|
||||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
** See the License for the specific language governing permissions and
|
|
||||||
** limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __KEYMGMT_H__
|
|
||||||
#define __KEYMGMT_H__
|
|
||||||
|
|
||||||
#define MASTER_KEY_TAG "master_key"
|
|
||||||
#define MASTER_KEY ".keymaster"
|
|
||||||
#define MAX_PATH_LEN 128
|
|
||||||
#define SALT "Android Keystore 0.1"
|
|
||||||
#define NAME_DELIMITER "_"
|
|
||||||
#define KEYFILE_NAME "%s"NAME_DELIMITER"%s"
|
|
||||||
#define KEYGEN_ITER 1024
|
|
||||||
#define AES_KEY_LEN 128
|
|
||||||
#define USER_KEY_LEN (AES_KEY_LEN/8)
|
|
||||||
#define IV_LEN USER_KEY_LEN
|
|
||||||
#define MAX_RETRY_COUNT 6
|
|
||||||
#define MIN_PASSWD_LENGTH 8
|
|
||||||
|
|
||||||
#define gen_key(passwd, key, len) \
|
|
||||||
PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), \
|
|
||||||
(unsigned char*)SALT, \
|
|
||||||
strlen(SALT), KEYGEN_ITER, \
|
|
||||||
len, key)
|
|
||||||
|
|
||||||
#define KEYFILE_LEN MAX_NAMESPACE_LENGTH + MAX_KEY_NAME_LENGTH + 6
|
|
||||||
|
|
||||||
#define get_blob_size(blob) \
|
|
||||||
(((blob->value_size + sizeof(uint32_t) + MAX_KEY_NAME_LENGTH \
|
|
||||||
+ USER_KEY_LEN - 1) / USER_KEY_LEN) * USER_KEY_LEN)
|
|
||||||
|
|
||||||
#define MAX_BLOB_LEN ((MAX_KEY_VALUE_LENGTH + MAX_KEY_NAME_LENGTH + \
|
|
||||||
sizeof(uint32_t) + USER_KEY_LEN - 1) / USER_KEY_LEN)\
|
|
||||||
* USER_KEY_LEN
|
|
||||||
|
|
||||||
#define data_blob_size(blob) USER_KEY_LEN + sizeof(uint32_t) + blob->blob_size
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned char iv[USER_KEY_LEN];
|
|
||||||
uint32_t blob_size;
|
|
||||||
union {
|
|
||||||
unsigned char blob[1];
|
|
||||||
struct {
|
|
||||||
uint32_t value_size;
|
|
||||||
char keyname[MAX_KEY_NAME_LENGTH];
|
|
||||||
unsigned char value[MAX_KEY_VALUE_LENGTH];
|
|
||||||
} __attribute__((packed));
|
|
||||||
};
|
|
||||||
} DATA_BLOB;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char tag[USER_KEY_LEN];
|
|
||||||
unsigned char master_key[USER_KEY_LEN];
|
|
||||||
} MASTER_BLOB;
|
|
||||||
|
|
||||||
int put_key(const char *namespace, const char *keyname,
|
|
||||||
unsigned char *data, int size);
|
|
||||||
int get_key(const char *namespace, const char *keyname,
|
|
||||||
unsigned char *data, int *size);
|
|
||||||
int remove_key(const char *namespace, const char *keyname);
|
|
||||||
int list_keys(const char *namespace, char reply[BUFFER_MAX]);
|
|
||||||
int new_passwd(char *password);
|
|
||||||
int change_passwd(char *old_pass, char *new_pass);
|
|
||||||
int lock();
|
|
||||||
int unlock(char *passwd);
|
|
||||||
KEYSTORE_STATE get_state();
|
|
||||||
int reset_keystore();
|
|
||||||
int init_keystore(const char *dir);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,429 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2009, The Android Open Source Project
|
|
||||||
**
|
|
||||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
** you may not use this file except in compliance with the License.
|
|
||||||
** You may obtain a copy of the License at
|
|
||||||
**
|
|
||||||
** http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
**
|
|
||||||
** Unless required by applicable law or agreed to in writing, software
|
|
||||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
** See the License for the specific language governing permissions and
|
|
||||||
** limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <utime.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <private/android_filesystem_config.h>
|
|
||||||
|
|
||||||
#include <cutils/sockets.h>
|
|
||||||
#include <cutils/log.h>
|
|
||||||
#include <cutils/properties.h>
|
|
||||||
|
|
||||||
#include "netkeystore.h"
|
|
||||||
#include "keymgmt.h"
|
|
||||||
|
|
||||||
#define DBG 1
|
|
||||||
#define CMD_PUT_WITH_FILE "putfile"
|
|
||||||
|
|
||||||
typedef void CMD_FUNC(LPC_MARSHAL *cmd, LPC_MARSHAL *reply);
|
|
||||||
|
|
||||||
struct cmdinfo {
|
|
||||||
const char *name;
|
|
||||||
CMD_FUNC *func;
|
|
||||||
};
|
|
||||||
|
|
||||||
static CMD_FUNC do_lock;
|
|
||||||
static CMD_FUNC do_unlock;
|
|
||||||
static CMD_FUNC do_passwd;
|
|
||||||
static CMD_FUNC do_get_state;;
|
|
||||||
static CMD_FUNC do_listkeys;
|
|
||||||
static CMD_FUNC do_get_key;
|
|
||||||
static CMD_FUNC do_put_key;
|
|
||||||
static CMD_FUNC do_remove_key;
|
|
||||||
static CMD_FUNC do_reset_keystore;
|
|
||||||
|
|
||||||
#define str(x) #x
|
|
||||||
|
|
||||||
struct cmdinfo cmds[] = {
|
|
||||||
{ str(LOCK), do_lock },
|
|
||||||
{ str(UNLOCK), do_unlock },
|
|
||||||
{ str(PASSWD), do_passwd },
|
|
||||||
{ str(GETSTATE), do_get_state },
|
|
||||||
{ str(LISTKEYS), do_listkeys },
|
|
||||||
{ str(GET), do_get_key },
|
|
||||||
{ str(PUT), do_put_key },
|
|
||||||
{ str(REMOVE), do_remove_key },
|
|
||||||
{ str(RESET), do_reset_keystore },
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct ucred cr;
|
|
||||||
|
|
||||||
static int check_get_perm(int uid)
|
|
||||||
{
|
|
||||||
if (uid == AID_WIFI || uid == AID_VPN) return 0;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int check_reset_perm(int uid)
|
|
||||||
{
|
|
||||||
if (uid == AID_SYSTEM) return 0;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The function parse_strings() only handle two or three tokens just for
|
|
||||||
* keystore's need.
|
|
||||||
*/
|
|
||||||
static int parse_strings(char *data, int data_len, int ntokens, ...)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
va_list args;
|
|
||||||
char *p = data, **q;
|
|
||||||
|
|
||||||
va_start(args, ntokens);
|
|
||||||
q = va_arg(args, char**);
|
|
||||||
*q = p;
|
|
||||||
while (p < (data + data_len)) {
|
|
||||||
if (*(p++) == 0) {
|
|
||||||
if (++count == ntokens) break;
|
|
||||||
if ((q = va_arg(args, char**)) == NULL) break;
|
|
||||||
*q = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
va_end(args);
|
|
||||||
// the first two strings should be null-terminated and the third could
|
|
||||||
// ignore the delimiter.
|
|
||||||
if (count >= 2) {
|
|
||||||
if ((ntokens == 3) || ((ntokens == 2) && (p == (data + data_len)))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int is_alnum_string(char *s)
|
|
||||||
{
|
|
||||||
char *s0 = s;
|
|
||||||
while (*s != 0) {
|
|
||||||
if (!isalnum(*s++)) {
|
|
||||||
LOGE("The string '%s' is not an alphanumeric string\n", s0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// args of passwd():
|
|
||||||
// firstPassword - for the first time
|
|
||||||
// oldPassword newPassword - for changing the password
|
|
||||||
static void do_passwd(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
|
|
||||||
{
|
|
||||||
char *p1 = NULL, *p2 = NULL;
|
|
||||||
|
|
||||||
if (strlen((char*)cmd->data) == (cmd->len - 1)) {
|
|
||||||
reply->retcode = new_passwd((char*)cmd->data);
|
|
||||||
} else {
|
|
||||||
if (parse_strings((char *)cmd->data, cmd->len, 2, &p1, &p2) != 0) {
|
|
||||||
reply->retcode = -1;
|
|
||||||
} else {
|
|
||||||
reply->retcode = change_passwd(p1, p2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// args of lock():
|
|
||||||
// no argument
|
|
||||||
static void do_lock(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
|
|
||||||
{
|
|
||||||
reply->retcode = lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// args of unlock():
|
|
||||||
// password
|
|
||||||
static void do_unlock(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
|
|
||||||
{
|
|
||||||
reply->retcode = unlock((char*)cmd->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// args of get_state():
|
|
||||||
// no argument
|
|
||||||
static void do_get_state(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
|
|
||||||
{
|
|
||||||
int s = get_state();
|
|
||||||
if (DBG) LOGD("keystore state = %d\n", s);
|
|
||||||
reply->retcode = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// args of listkeys():
|
|
||||||
// namespace
|
|
||||||
static void do_listkeys(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
|
|
||||||
{
|
|
||||||
reply->retcode = list_keys((const char*)cmd->data, (char*)reply->data);
|
|
||||||
if (!reply->retcode) reply->len = strlen((char*)reply->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// args of get():
|
|
||||||
// namespace keyname
|
|
||||||
static void do_get_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
|
|
||||||
{
|
|
||||||
char *namespace = NULL, *keyname = NULL;
|
|
||||||
|
|
||||||
if (check_get_perm(cr.uid)) {
|
|
||||||
LOGE("uid %d doesn't have the permission to get key value\n", cr.uid);
|
|
||||||
reply->retcode = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parse_strings((char*)cmd->data, cmd->len, 2, &namespace, &keyname) ||
|
|
||||||
!is_alnum_string(namespace) || !is_alnum_string(keyname)) {
|
|
||||||
reply->retcode = -1;
|
|
||||||
} else {
|
|
||||||
reply->retcode = get_key(namespace, keyname, reply->data,
|
|
||||||
(int*)&reply->len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_value_index(LPC_MARSHAL *cmd)
|
|
||||||
{
|
|
||||||
uint32_t count = 0, i;
|
|
||||||
for (i = 0 ; i < cmd->len ; ++i) {
|
|
||||||
if (cmd->data[i] == ' ') {
|
|
||||||
if (++count == 2) return ++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// args of put():
|
|
||||||
// namespace keyname keyvalue
|
|
||||||
static void do_put_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
|
|
||||||
{
|
|
||||||
char *namespace = NULL, *keyname = NULL;
|
|
||||||
char *value = NULL;
|
|
||||||
|
|
||||||
if (parse_strings((char*)cmd->data, cmd->len, 3, &namespace, &keyname, &value) ||
|
|
||||||
!is_alnum_string(namespace) || !is_alnum_string(keyname)) {
|
|
||||||
reply->retcode = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int len = cmd->len - (value - namespace);
|
|
||||||
reply->retcode = put_key(namespace, keyname, (unsigned char *)value, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// args of remove_key():
|
|
||||||
// namespace keyname
|
|
||||||
static void do_remove_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
|
|
||||||
{
|
|
||||||
char *namespace = NULL, *keyname = NULL;
|
|
||||||
|
|
||||||
if (parse_strings((char*)cmd->data, cmd->len, 2, &namespace, &keyname) ||
|
|
||||||
!is_alnum_string(namespace) || !is_alnum_string(keyname)) {
|
|
||||||
reply->retcode = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reply->retcode = remove_key(namespace, keyname);
|
|
||||||
}
|
|
||||||
|
|
||||||
// args of reset_keystore():
|
|
||||||
// no argument
|
|
||||||
static void do_reset_keystore(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
|
|
||||||
{
|
|
||||||
if (check_reset_perm(cr.uid)) {
|
|
||||||
LOGE("uid %d doesn't have the permission to reset the keystore\n",
|
|
||||||
cr.uid);
|
|
||||||
reply->retcode = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reply->retcode = reset_keystore();
|
|
||||||
}
|
|
||||||
|
|
||||||
void execute(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
|
|
||||||
{
|
|
||||||
uint32_t cmd_max = sizeof(cmds)/sizeof(struct cmdinfo);
|
|
||||||
|
|
||||||
if (cmd->opcode >= cmd_max) {
|
|
||||||
LOGE("the opcode (%d) is not valid", cmd->opcode);
|
|
||||||
reply->retcode = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cmds[cmd->opcode].func(cmd, reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int set_read_timeout(int socket)
|
|
||||||
{
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = READ_TIMEOUT;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv))
|
|
||||||
{
|
|
||||||
LOGE("setsockopt failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int append_input_from_file(const char *filename, LPC_MARSHAL *cmd)
|
|
||||||
{
|
|
||||||
int fd, len, ret = 0;
|
|
||||||
|
|
||||||
// get opcode of the function put()
|
|
||||||
if ((fd = open(filename, O_RDONLY)) == -1) {
|
|
||||||
fprintf(stderr, "Can not open file %s\n", filename);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
len = read(fd, cmd->data + cmd->len, BUFFER_MAX - cmd->len);
|
|
||||||
if (len < 0 || (len == (int)(BUFFER_MAX - cmd->len))) {
|
|
||||||
ret = -1;
|
|
||||||
} else {
|
|
||||||
cmd->len += len;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int flatten_str_args(int argc, const char **argv, LPC_MARSHAL *cmd)
|
|
||||||
{
|
|
||||||
int i, len = 0;
|
|
||||||
char *buf = (char*)cmd->data;
|
|
||||||
buf[0] = 0;
|
|
||||||
for (i = 0 ; i < argc ; ++i) {
|
|
||||||
// we also include the \0 character in the input.
|
|
||||||
if (i == 0) {
|
|
||||||
len = (strlcpy(buf, argv[i], BUFFER_MAX) + 1);
|
|
||||||
} else {
|
|
||||||
len += (snprintf(buf + len, BUFFER_MAX - len, "%s", argv[i]) + 1);
|
|
||||||
}
|
|
||||||
if (len >= BUFFER_MAX) return -1;
|
|
||||||
}
|
|
||||||
if (len) cmd->len = len ;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int parse_cmd(int argc, const char **argv, LPC_MARSHAL *cmd)
|
|
||||||
{
|
|
||||||
uint32_t i, len = 0;
|
|
||||||
uint32_t cmd_max = sizeof(cmds)/sizeof(cmds[0]);
|
|
||||||
|
|
||||||
for (i = 0 ; i < cmd_max ; ++i) {
|
|
||||||
if (!strcasecmp(argv[0], cmds[i].name)) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == cmd_max) {
|
|
||||||
// check if this is a command to put the key value with a file.
|
|
||||||
if (strcmp(argv[0], CMD_PUT_WITH_FILE) != 0) return -1;
|
|
||||||
cmd->opcode = PUT;
|
|
||||||
if (argc != 4) {
|
|
||||||
fprintf(stderr, "%s args\n\tnamespace keyname filename\n",
|
|
||||||
argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (flatten_str_args(argc - 2, argv + 1, cmd)) return -1;
|
|
||||||
return append_input_from_file(argv[3], cmd);
|
|
||||||
} else {
|
|
||||||
cmd->opcode = i;
|
|
||||||
return flatten_str_args(argc - 1, argv + 1, cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int shell_command(const int argc, const char **argv)
|
|
||||||
{
|
|
||||||
int fd, i;
|
|
||||||
LPC_MARSHAL cmd;
|
|
||||||
|
|
||||||
if (parse_cmd(argc, argv, &cmd)) {
|
|
||||||
fprintf(stderr, "Incorrect command or command line is too long.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fd = socket_local_client(SOCKET_PATH,
|
|
||||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
|
||||||
SOCK_STREAM);
|
|
||||||
if (fd == -1) {
|
|
||||||
fprintf(stderr, "Keystore service is not up and running.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (write_marshal(fd, &cmd)) {
|
|
||||||
fprintf(stderr, "Incorrect command or command line is too long.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (read_marshal(fd, &cmd)) {
|
|
||||||
fprintf(stderr, "Failed to read the result.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
cmd.data[cmd.len] = 0;
|
|
||||||
fprintf(stdout, "%s\n", (cmd.retcode == 0) ? "Succeeded!" : "Failed!");
|
|
||||||
if (cmd.len) fprintf(stdout, "\t%s\n", (char*)cmd.data);
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int server_main(const int argc, const char *argv[])
|
|
||||||
{
|
|
||||||
struct sockaddr addr;
|
|
||||||
socklen_t alen;
|
|
||||||
int lsocket, s;
|
|
||||||
LPC_MARSHAL cmd, reply;
|
|
||||||
|
|
||||||
if (init_keystore(KEYSTORE_DIR)) {
|
|
||||||
LOGE("Can not initialize the keystore, the directory exist?\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
lsocket = android_get_control_socket(SOCKET_PATH);
|
|
||||||
if (lsocket < 0) {
|
|
||||||
LOGE("Failed to get socket from environment: %s\n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (listen(lsocket, 5)) {
|
|
||||||
LOGE("Listen on socket failed: %s\n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fcntl(lsocket, F_SETFD, FD_CLOEXEC);
|
|
||||||
memset(&reply, 0, sizeof(LPC_MARSHAL));
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
socklen_t cr_size = sizeof(cr);
|
|
||||||
alen = sizeof(addr);
|
|
||||||
s = accept(lsocket, &addr, &alen);
|
|
||||||
|
|
||||||
/* retrieve the caller info here */
|
|
||||||
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
|
|
||||||
close(s);
|
|
||||||
LOGE("Unable to recieve socket options\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s < 0) {
|
|
||||||
LOGE("Accept failed: %s\n", strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
fcntl(s, F_SETFD, FD_CLOEXEC);
|
|
||||||
if (set_read_timeout(s)) {
|
|
||||||
close(s);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read the command, execute and send the result back.
|
|
||||||
if(read_marshal(s, &cmd)) goto err;
|
|
||||||
execute(&cmd, &reply);
|
|
||||||
write_marshal(s, &reply);
|
|
||||||
err:
|
|
||||||
memset(&reply, 0, sizeof(LPC_MARSHAL));
|
|
||||||
close(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
/*
|
|
||||||
**
|
|
||||||
** Copyright 2009, The Android Open Source Project
|
|
||||||
**
|
|
||||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
** you may not use this file except in compliance with the License.
|
|
||||||
** You may obtain a copy of the License at
|
|
||||||
**
|
|
||||||
** http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
**
|
|
||||||
** Unless required by applicable law or agreed to in writing, software
|
|
||||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
** See the License for the specific language governing permissions and
|
|
||||||
** limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __NETKEYSTORE_H__
|
|
||||||
#define __NETKEYSTORE_H__
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <cutils/sockets.h>
|
|
||||||
#include <cutils/log.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
// for testing
|
|
||||||
int parse_cmd(int argc, const char **argv, LPC_MARSHAL *cmd);
|
|
||||||
void execute(LPC_MARSHAL *cmd, LPC_MARSHAL *reply);
|
|
||||||
|
|
||||||
static inline int readx(int s, void *_buf, int count)
|
|
||||||
{
|
|
||||||
char *buf = _buf;
|
|
||||||
int n = 0, r;
|
|
||||||
if (count < 0) return -1;
|
|
||||||
while (n < count) {
|
|
||||||
r = read(s, buf + n, count - n);
|
|
||||||
if (r < 0) {
|
|
||||||
if (errno == EINTR) continue;
|
|
||||||
LOGE("read error: %s\n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (r == 0) {
|
|
||||||
LOGE("eof\n");
|
|
||||||
return -1; /* EOF */
|
|
||||||
}
|
|
||||||
n += r;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int writex(int s, const void *_buf, int count)
|
|
||||||
{
|
|
||||||
const char *buf = _buf;
|
|
||||||
int n = 0, r;
|
|
||||||
if (count < 0) return -1;
|
|
||||||
while (n < count) {
|
|
||||||
r = write(s, buf + n, count - n);
|
|
||||||
if (r < 0) {
|
|
||||||
if (errno == EINTR) continue;
|
|
||||||
LOGE("write error: %s\n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
n += r;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int read_marshal(int s, LPC_MARSHAL *cmd)
|
|
||||||
{
|
|
||||||
if (readx(s, cmd, 2 * sizeof(uint32_t))) {
|
|
||||||
LOGE("failed to read header\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
cmd->len = ntohl(cmd->len);
|
|
||||||
cmd->opcode = ntohl(cmd->opcode);
|
|
||||||
if (cmd->len > BUFFER_MAX) {
|
|
||||||
LOGE("invalid size %d\n", cmd->len);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (readx(s, cmd->data, cmd->len)) {
|
|
||||||
LOGE("failed to read data\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
cmd->data[cmd->len] = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int write_marshal(int s, LPC_MARSHAL *cmd)
|
|
||||||
{
|
|
||||||
int len = cmd->len;
|
|
||||||
cmd->len = htonl(cmd->len);
|
|
||||||
cmd->opcode = htonl(cmd->opcode);
|
|
||||||
if (writex(s, cmd, 2 * sizeof(uint32_t))) {
|
|
||||||
LOGE("failed to write marshal header\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (writex(s, cmd->data, len)) {
|
|
||||||
LOGE("failed to write marshal data\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2009, The Android Open Source Project
|
|
||||||
**
|
|
||||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
** you may not use this file except in compliance with the License.
|
|
||||||
** You may obtain a copy of the License at
|
|
||||||
**
|
|
||||||
** http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
**
|
|
||||||
** Unless required by applicable law or agreed to in writing, software
|
|
||||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
** See the License for the specific language governing permissions and
|
|
||||||
** limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define LOG_TAG "keystore"
|
|
||||||
|
|
||||||
int shell_command(const int argc, const char **argv);
|
|
||||||
int server_main(const int argc, const char *argv[]);
|
|
||||||
|
|
||||||
int main(const int argc, const char *argv[])
|
|
||||||
{
|
|
||||||
if (argc > 1) {
|
|
||||||
return shell_command(argc - 1, argv + 1);
|
|
||||||
} else {
|
|
||||||
return server_main(argc, argv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Copyright (C) 2009 The Android Open Source Project
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
# define the KEYSTORE_TESTS environment variable to build the test programs
|
|
||||||
ifdef KEYSTORE_TESTS
|
|
||||||
LOCAL_PATH:= $(call my-dir)
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
LOCAL_SRC_FILES:= netkeystore_test.c ../keymgmt.c ../netkeystore.c
|
|
||||||
LOCAL_SHARED_LIBRARIES := libcutils libssl
|
|
||||||
LOCAL_MODULE:= netkeystore_test
|
|
||||||
LOCAL_MODULE_TAGS := optional
|
|
||||||
LOCAL_C_INCLUDES := external/openssl/include \
|
|
||||||
frameworks/base/cmds/keystore
|
|
||||||
EXTRA_CFLAGS := -g -O0 -DGTEST_OS_LINUX -DGTEST_HAS_STD_STRING
|
|
||||||
include $(BUILD_EXECUTABLE)
|
|
||||||
|
|
||||||
endif #KEYSTORE_TESTS
|
|
||||||
@@ -1,287 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 The Android Open Source Project
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in
|
|
||||||
* the documentation and/or other materials provided with the
|
|
||||||
* distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
||||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
||||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
||||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <cutils/log.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "keymgmt.h"
|
|
||||||
#include "netkeystore.h"
|
|
||||||
|
|
||||||
#define LOG_TAG "keystore_test"
|
|
||||||
|
|
||||||
typedef int FUNC_PTR();
|
|
||||||
typedef struct {
|
|
||||||
const char *name;
|
|
||||||
FUNC_PTR *func;
|
|
||||||
} TESTFUNC;
|
|
||||||
|
|
||||||
#define FUNC_NAME(x) { #x, test_##x }
|
|
||||||
#define FUNC_BODY(x) int test_##x()
|
|
||||||
|
|
||||||
#define TEST_PASSWD "12345678"
|
|
||||||
#define TEST_NPASSWD "hello world"
|
|
||||||
#define TEST_DIR "/data/local/tmp/keystore"
|
|
||||||
#define READONLY_DIR "/proc/keystore"
|
|
||||||
#define TEST_NAMESPACE "test"
|
|
||||||
#define TEST_KEYNAME "key"
|
|
||||||
#define TEST_KEYNAME2 "key2"
|
|
||||||
#define TEST_KEYVALUE "ANDROID"
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
if (init_keystore(TEST_DIR) != 0) {
|
|
||||||
fprintf(stderr, "Can not create the test directory %s\n", TEST_DIR);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void teardown()
|
|
||||||
{
|
|
||||||
if (reset_keystore() != 0) {
|
|
||||||
fprintf(stderr, "Can not reset the test directory %s\n", TEST_DIR);
|
|
||||||
}
|
|
||||||
rmdir(TEST_DIR);
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNC_BODY(init_keystore)
|
|
||||||
{
|
|
||||||
if (init_keystore(READONLY_DIR) == 0) return -1;
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNC_BODY(reset_keystore)
|
|
||||||
{
|
|
||||||
int ret = chdir("/proc");
|
|
||||||
if (reset_keystore() == 0) return -1;
|
|
||||||
chdir(TEST_DIR);
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNC_BODY(get_state)
|
|
||||||
{
|
|
||||||
if (get_state() != UNINITIALIZED) return -1;
|
|
||||||
new_passwd(TEST_PASSWD);
|
|
||||||
if (get_state() != UNLOCKED) return -1;
|
|
||||||
lock();
|
|
||||||
if (get_state() != LOCKED) return -1;
|
|
||||||
|
|
||||||
if (reset_keystore() != 0) return -1;
|
|
||||||
if (get_state() != UNINITIALIZED) return -1;
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNC_BODY(passwd)
|
|
||||||
{
|
|
||||||
char buf[512];
|
|
||||||
|
|
||||||
if (new_passwd("2d fsdf") == 0) return -1;
|
|
||||||
if (new_passwd("dsfsdf") == 0) return -1;
|
|
||||||
new_passwd(TEST_PASSWD);
|
|
||||||
lock();
|
|
||||||
if (unlock("55555555") == 0) return -1;
|
|
||||||
if (unlock(TEST_PASSWD) != 0) return -1;
|
|
||||||
|
|
||||||
// change the password
|
|
||||||
if (change_passwd("klfdjdsklfjg", "abcdefghi") == 0) return -1;
|
|
||||||
|
|
||||||
if (change_passwd(TEST_PASSWD, TEST_NPASSWD) != 0) return -1;
|
|
||||||
lock();
|
|
||||||
|
|
||||||
if (unlock(TEST_PASSWD) == 0) return -1;
|
|
||||||
if (unlock(TEST_NPASSWD) != 0) return -1;
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNC_BODY(lock)
|
|
||||||
{
|
|
||||||
if (lock() == 0) return -1;
|
|
||||||
new_passwd(TEST_PASSWD);
|
|
||||||
if (lock() != 0) return -1;
|
|
||||||
if (lock() != 0) return -1;
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNC_BODY(unlock)
|
|
||||||
{
|
|
||||||
int i = MAX_RETRY_COUNT;
|
|
||||||
new_passwd(TEST_PASSWD);
|
|
||||||
lock();
|
|
||||||
while (i > 1) {
|
|
||||||
if (unlock(TEST_NPASSWD) != --i) return -1;
|
|
||||||
}
|
|
||||||
if (unlock(TEST_NPASSWD) != -1) return -1;
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNC_BODY(put_key)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
char keyname[512];
|
|
||||||
|
|
||||||
if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
|
|
||||||
strlen(TEST_KEYVALUE)) == 0) return -1;
|
|
||||||
new_passwd(TEST_PASSWD);
|
|
||||||
if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
|
|
||||||
strlen(TEST_KEYVALUE)) != 0) return -1;
|
|
||||||
|
|
||||||
for(i = 0; i < 500; i++) keyname[i] = 'K';
|
|
||||||
keyname[i] = 0;
|
|
||||||
if (put_key(TEST_NAMESPACE, keyname, (unsigned char *)TEST_KEYVALUE,
|
|
||||||
strlen(TEST_KEYVALUE)) == 0) return -1;
|
|
||||||
if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
|
|
||||||
MAX_KEY_VALUE_LENGTH + 1) == 0) return -1;
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNC_BODY(get_key)
|
|
||||||
{
|
|
||||||
int size;
|
|
||||||
unsigned char data[MAX_KEY_VALUE_LENGTH];
|
|
||||||
|
|
||||||
if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) == 0) return -1;
|
|
||||||
|
|
||||||
new_passwd(TEST_PASSWD);
|
|
||||||
put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
|
|
||||||
strlen(TEST_KEYVALUE));
|
|
||||||
if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) != 0) return -1;
|
|
||||||
if (memcmp(data, TEST_KEYVALUE, size) != 0) return -1;
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNC_BODY(remove_key)
|
|
||||||
{
|
|
||||||
if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1;
|
|
||||||
|
|
||||||
new_passwd(TEST_PASSWD);
|
|
||||||
if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1;
|
|
||||||
|
|
||||||
put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
|
|
||||||
strlen(TEST_KEYVALUE));
|
|
||||||
if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) != 0) return -1;
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNC_BODY(list_keys)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char buf[128];
|
|
||||||
char reply[BUFFER_MAX];
|
|
||||||
|
|
||||||
for(i = 0; i < 100; i++) buf[i] = 'K';
|
|
||||||
buf[i] = 0;
|
|
||||||
|
|
||||||
if (list_keys(TEST_NAMESPACE, reply) == 0) return -1;
|
|
||||||
|
|
||||||
new_passwd(TEST_PASSWD);
|
|
||||||
if (list_keys(buf, reply) == 0) return -1;
|
|
||||||
|
|
||||||
if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
|
|
||||||
if (strcmp(reply, "") != 0) return -1;
|
|
||||||
|
|
||||||
put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
|
|
||||||
strlen(TEST_KEYVALUE));
|
|
||||||
if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
|
|
||||||
if (strcmp(reply, TEST_KEYNAME) != 0) return -1;
|
|
||||||
|
|
||||||
put_key(TEST_NAMESPACE, TEST_KEYNAME2, (unsigned char *)TEST_KEYVALUE,
|
|
||||||
strlen(TEST_KEYVALUE));
|
|
||||||
|
|
||||||
if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
|
|
||||||
sprintf(buf, "%s %s", TEST_KEYNAME2, TEST_KEYNAME);
|
|
||||||
if (strcmp(reply, buf) != 0) return -1;
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int execute_cmd(int argc, const char *argv[], LPC_MARSHAL *cmd,
|
|
||||||
LPC_MARSHAL *reply)
|
|
||||||
{
|
|
||||||
memset(cmd, 0, sizeof(LPC_MARSHAL));
|
|
||||||
memset(reply, 0, sizeof(LPC_MARSHAL));
|
|
||||||
if (parse_cmd(argc, argv, cmd)) return -1;
|
|
||||||
execute(cmd, reply);
|
|
||||||
return (reply->retcode ? -1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNC_BODY(client_passwd)
|
|
||||||
{
|
|
||||||
LPC_MARSHAL cmd, reply;
|
|
||||||
const char *set_passwd_cmds[2] = {"passwd", TEST_PASSWD};
|
|
||||||
const char *change_passwd_cmds[3] = {"passwd", TEST_PASSWD, TEST_NPASSWD};
|
|
||||||
|
|
||||||
if (execute_cmd(2, set_passwd_cmds, &cmd, &reply)) return -1;
|
|
||||||
|
|
||||||
lock();
|
|
||||||
if (unlock("55555555") == 0) return -1;
|
|
||||||
if (unlock(TEST_PASSWD) != 0) return -1;
|
|
||||||
|
|
||||||
if (execute_cmd(3, change_passwd_cmds, &cmd, &reply)) return -1;
|
|
||||||
|
|
||||||
lock();
|
|
||||||
if (unlock(TEST_PASSWD) == 0) return -1;
|
|
||||||
if (unlock(TEST_NPASSWD) != 0) return -1;
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
TESTFUNC all_tests[] = {
|
|
||||||
FUNC_NAME(init_keystore),
|
|
||||||
FUNC_NAME(reset_keystore),
|
|
||||||
FUNC_NAME(get_state),
|
|
||||||
FUNC_NAME(passwd),
|
|
||||||
FUNC_NAME(lock),
|
|
||||||
FUNC_NAME(unlock),
|
|
||||||
FUNC_NAME(put_key),
|
|
||||||
FUNC_NAME(get_key),
|
|
||||||
FUNC_NAME(remove_key),
|
|
||||||
FUNC_NAME(list_keys),
|
|
||||||
FUNC_NAME(client_passwd),
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
int i, ret;
|
|
||||||
for (i = 0 ; i < (int)(sizeof(all_tests)/sizeof(TESTFUNC)) ; ++i) {
|
|
||||||
LOGD("run %s...\n", all_tests[i].name);
|
|
||||||
setup();
|
|
||||||
if ((ret = all_tests[i].func()) != EXIT_SUCCESS) {
|
|
||||||
fprintf(stderr, "ERROR in function %s\n", all_tests[i].name);
|
|
||||||
return ret;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "function %s PASSED!\n", all_tests[i].name);
|
|
||||||
}
|
|
||||||
teardown();
|
|
||||||
}
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user