Merge change 4337 into donut

* changes:
  Change the keystore APIs.
This commit is contained in:
Android (Google) Code Review
2009-06-16 23:35:57 -07:00
4 changed files with 343 additions and 88 deletions

View File

@@ -1,5 +1,5 @@
/* /*
** Copyright 2008, The Android Open Source Project ** Copyright 2009, The Android Open Source Project
** **
** Licensed under the Apache License, Version 2.0 (the "License"); ** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License. ** you may not use this file except in compliance with the License.
@@ -30,7 +30,8 @@ static DIR *open_keystore(const char *dir)
return d; return d;
} }
static int list_files(const char *dir, char reply[REPLY_MAX]) { static int list_files(const char *dir, char reply[REPLY_MAX])
{
struct dirent *de; struct dirent *de;
DIR *d; DIR *d;
@@ -39,7 +40,9 @@ static int list_files(const char *dir, char reply[REPLY_MAX]) {
} }
reply[0]=0; reply[0]=0;
while ((de = readdir(d))) { while ((de = readdir(d))) {
if (de->d_type != DT_REG) continue; if (de->d_type != DT_DIR) continue;
if ((strcmp(DOT, de->d_name) == 0) ||
(strcmp(DOTDOT, de->d_name) == 0)) continue;
if (reply[0] != 0) strlcat(reply, " ", REPLY_MAX); if (reply[0] != 0) strlcat(reply, " ", REPLY_MAX);
if (strlcat(reply, de->d_name, REPLY_MAX) >= REPLY_MAX) { if (strlcat(reply, de->d_name, REPLY_MAX) >= REPLY_MAX) {
LOGE("reply is too long(too many files under '%s'\n", dir); LOGE("reply is too long(too many files under '%s'\n", dir);
@@ -50,92 +53,175 @@ static int list_files(const char *dir, char reply[REPLY_MAX]) {
return 0; return 0;
} }
static int copy_keyfile(const char *keystore, const char *srcfile) { static int copy_keyfile(const char *src, int src_type, const char *dstfile) {
int srcfd, dstfd; int srcfd = -1, dstfd;
int length; char buf[REPLY_MAX];
char buf[2048];
char dstfile[KEYNAME_LENGTH];
const char *filename = strrchr(srcfile, '/');
strlcpy(dstfile, keystore, KEYNAME_LENGTH); if ((src_type == IS_FILE) && (srcfd = open(src, O_RDONLY)) == -1) {
strlcat(dstfile, "/", KEYNAME_LENGTH); LOGE("Cannot open the original file '%s'\n", src);
if (strlcat(dstfile, filename ? filename + 1 : srcfile,
KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
LOGE("keyname is too long '%s'\n", srcfile);
return -1;
}
if ((srcfd = open(srcfile, O_RDONLY)) == -1) {
LOGE("Cannot open the original file '%s'\n", srcfile);
return -1; return -1;
} }
if ((dstfd = open(dstfile, O_CREAT|O_RDWR)) == -1) { if ((dstfd = open(dstfile, O_CREAT|O_RDWR)) == -1) {
LOGE("Cannot open the destination file '%s'\n", dstfile); LOGE("Cannot open the destination file '%s'\n", dstfile);
return -1; return -1;
} }
while((length = read(srcfd, buf, 2048)) > 0) { if (src_type == IS_FILE) {
int length;
while((length = read(srcfd, buf, REPLY_MAX)) > 0) {
write(dstfd, buf, length); write(dstfd, buf, length);
} }
} else {
write(dstfd, src, strlen(src));
}
close(srcfd); close(srcfd);
close(dstfd); close(dstfd);
chmod(dstfile, 0440); chmod(dstfile, 0440);
return 0; return 0;
} }
static int install_key(const char *dir, const char *keyfile) static int install_key(const char *path, const char *certname, const char *src,
int src_is_file, char *dstfile)
{ {
struct dirent *de; struct dirent *de;
char fullpath[KEYNAME_LENGTH];
DIR *d; DIR *d;
if ((d = open_keystore(dir)) == NULL) { if (snprintf(fullpath, sizeof(fullpath), "%s/%s/", path, certname)
>= KEYNAME_LENGTH) {
LOGE("cert name '%s' is too long.\n", certname);
return -1; return -1;
} }
return copy_keyfile(dir, keyfile);
if ((d = open_keystore(fullpath)) == NULL) {
LOGE("Can not open the keystore '%s'\n", fullpath);
return -1;
}
closedir(d);
if (strlcat(fullpath, dstfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
LOGE("cert name '%s' is too long.\n", certname);
return -1;
}
return copy_keyfile(src, src_is_file, fullpath);
} }
static int remove_key(const char *dir, const char *keyfile) static int get_key(const char *path, const char *keyname, const char *file,
char reply[REPLY_MAX])
{ {
char dstfile[KEYNAME_LENGTH]; struct dirent *de;
char filename[KEYNAME_LENGTH];
int fd;
strlcpy(dstfile, dir, KEYNAME_LENGTH); if (snprintf(filename, sizeof(filename), "%s/%s/%s", path, keyname, file)
strlcat(dstfile, "/", KEYNAME_LENGTH); >= KEYNAME_LENGTH) {
if (strlcat(dstfile, keyfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) { LOGE("cert name '%s' is too long.\n", keyname);
LOGE("keyname is too long '%s'\n", keyfile);
return -1; return -1;
} }
if (unlink(dstfile)) {
LOGE("cannot delete '%s': %s\n", dstfile, strerror(errno)); if ((fd = open(filename, O_RDONLY)) == -1) {
return -1;
}
close(fd);
strlcpy(reply, filename, REPLY_MAX);
return 0;
}
static int remove_key(const char *dir, const char *key)
{
char dstfile[KEYNAME_LENGTH];
char *keyfile[4] = { USER_KEY, USER_P12_CERT, USER_CERTIFICATE,
CA_CERTIFICATE };
int i, count = 0;
for ( i = 0 ; i < 4 ; i++) {
if (snprintf(dstfile, KEYNAME_LENGTH, "%s/%s/%s", dir, key, keyfile[i])
>= KEYNAME_LENGTH) {
LOGE("keyname is too long '%s'\n", key);
return -1;
}
if (unlink(dstfile) == 0) count++;
}
if (count == 0) {
LOGE("can not clean up '%s' keys or not exist\n", key);
return -1;
}
snprintf(dstfile, KEYNAME_LENGTH, "%s/%s", dir, key);
if (rmdir(dstfile)) {
LOGE("can not clean up '%s' directory\n", key);
return -1; return -1;
} }
return 0; return 0;
} }
int list_certs(char reply[REPLY_MAX]) int list_user_certs(char reply[REPLY_MAX])
{ {
return list_files(CERTS_DIR, reply); return list_files(CERTS_DIR, reply);
} }
int list_userkeys(char reply[REPLY_MAX]) int list_ca_certs(char reply[REPLY_MAX])
{ {
return list_files(USERKEYS_DIR, reply); return list_files(CACERTS_DIR, reply);
} }
int install_cert(const char *certfile) int install_user_cert(const char *keyname, const char *cert, const char *key)
{ {
return install_key(CERTS_DIR, certfile); if (install_key(CERTS_DIR, keyname, cert, IS_FILE, USER_CERTIFICATE) == 0) {
return install_key(CERTS_DIR, keyname, key, IS_FILE, USER_KEY);
}
return -1;
} }
int install_userkey(const char *keyfile) int install_ca_cert(const char *keyname, const char *certfile)
{ {
return install_key(USERKEYS_DIR, keyfile); return install_key(CACERTS_DIR, keyname, certfile, IS_FILE, CA_CERTIFICATE);
} }
int remove_cert(const char *certfile) int install_p12_cert(const char *keyname, const char *certfile)
{ {
return remove_key(CERTS_DIR, certfile); return install_key(CERTS_DIR, keyname, certfile, IS_FILE, USER_P12_CERT);
} }
int remove_userkey(const char *keyfile) int add_ca_cert(const char *keyname, const char *certificate)
{ {
return remove_key(USERKEYS_DIR, keyfile); return install_key(CACERTS_DIR, keyname, certificate, IS_CONTENT,
CA_CERTIFICATE);
}
int add_user_cert(const char *keyname, const char *certificate)
{
return install_key(CERTS_DIR, keyname, certificate, IS_CONTENT,
USER_CERTIFICATE);
}
int add_user_key(const char *keyname, const char *key)
{
return install_key(CERTS_DIR, keyname, key, IS_CONTENT, USER_KEY);
}
int get_ca_cert(const char *keyname, char reply[REPLY_MAX])
{
return get_key(CACERTS_DIR, keyname, CA_CERTIFICATE, reply);
}
int get_user_cert(const char *keyname, char reply[REPLY_MAX])
{
return get_key(CERTS_DIR, keyname, USER_CERTIFICATE, reply);
}
int get_user_key(const char *keyname, char reply[REPLY_MAX])
{
if(get_key(CERTS_DIR, keyname, USER_KEY, reply))
return get_key(CERTS_DIR, keyname, USER_P12_CERT, reply);
return 0;
}
int remove_user_cert(const char *key)
{
return remove_key(CERTS_DIR, key);
}
int remove_ca_cert(const char *key)
{
return remove_key(CACERTS_DIR, key);
} }

View File

@@ -16,37 +16,89 @@
#include "keystore.h" #include "keystore.h"
static inline int has_whitespace(char *name)
static int do_list_certs(char **arg, char reply[REPLY_MAX])
{ {
return list_certs(reply); if((strrchr(name, ' ') != NULL)) {
LOGE("'%s' contains whitespace character\n", name);
return 1;
}
return 0;
} }
static int do_list_userkeys(char **arg, char reply[REPLY_MAX]) static int do_list_user_certs(char **arg, char reply[REPLY_MAX])
{ {
return list_userkeys(reply); return list_user_certs(reply);
} }
static int do_install_cert(char **arg, char reply[REPLY_MAX]) static int do_list_ca_certs(char **arg, char reply[REPLY_MAX])
{ {
return install_cert(arg[0]); /* move the certificate to keystore */ return list_ca_certs(reply);
} }
static int do_remove_cert(char **arg, char reply[REPLY_MAX]) static int do_install_user_cert(char **arg, char reply[REPLY_MAX])
{ {
return remove_cert(arg[0]); /* certificate */ if (has_whitespace(arg[0])) return -1;
/* copy the certificate and key to keystore */
return install_user_cert(arg[0], arg[1], arg[2]);
} }
static int do_install_userkey(char **arg, char reply[REPLY_MAX]) static int do_install_p12_cert(char **arg, char reply[REPLY_MAX])
{ {
return install_userkey(arg[0]); /* move the certificate to keystore */ if (has_whitespace(arg[0])) return -1;
return install_p12_cert(arg[0], arg[1]);
} }
static int do_remove_userkey(char **arg, char reply[REPLY_MAX]) static int do_install_ca_cert(char **arg, char reply[REPLY_MAX])
{ {
return remove_userkey(arg[0]); /* userkey */ if (has_whitespace(arg[0])) return -1;
/* copy the certificate and key to keystore */
return install_ca_cert(arg[0], arg[1]);
} }
static int do_add_ca_cert(char **arg, char reply[REPLY_MAX])
{
if (has_whitespace(arg[0])) return -1;
return add_ca_cert(arg[0], arg[1]);
}
static int do_add_user_cert(char **arg, char reply[REPLY_MAX])
{
if (has_whitespace(arg[0])) return -1;
return add_user_cert(arg[0], arg[1]);
}
static int do_add_user_key(char **arg, char reply[REPLY_MAX])
{
if (has_whitespace(arg[0])) return -1;
return add_user_key(arg[0], arg[1]);
}
static int do_get_ca_cert(char **arg, char reply[REPLY_MAX])
{
return get_ca_cert(arg[0], reply);
}
static int do_get_user_cert(char **arg, char reply[REPLY_MAX])
{
return get_user_cert(arg[0], reply);
}
static int do_get_user_key(char **arg, char reply[REPLY_MAX])
{
return get_user_key(arg[0], reply);
}
static int do_remove_user_cert(char **arg, char reply[REPLY_MAX])
{
return remove_user_cert(arg[0]);
}
static int do_remove_ca_cert(char **arg, char reply[REPLY_MAX])
{
return remove_ca_cert(arg[0]);
}
struct cmdinfo { struct cmdinfo {
const char *name; const char *name;
unsigned numargs; unsigned numargs;
@@ -55,12 +107,19 @@ struct cmdinfo {
struct cmdinfo cmds[] = { struct cmdinfo cmds[] = {
{ "listcerts", 0, do_list_certs }, { "listcacerts", 0, do_list_ca_certs },
{ "listuserkeys", 0, do_list_userkeys }, { "listusercerts", 0, do_list_user_certs },
{ "installcert", 1, do_install_cert }, { "installusercert", 3, do_install_user_cert },
{ "removecert", 1, do_remove_cert }, { "installcacert", 2, do_install_ca_cert },
{ "installuserkey", 1, do_install_userkey }, { "installp12cert", 2, do_install_p12_cert },
{ "removeuserkey", 1, do_remove_userkey }, { "addusercert", 2, do_add_user_cert },
{ "adduserkey", 2, do_add_user_key },
{ "addcacert", 2, do_add_ca_cert },
{ "getusercert", 1, do_get_user_cert },
{ "getuserkey", 1, do_get_user_key },
{ "getcacert", 1, do_get_ca_cert },
{ "removecacert", 1, do_remove_ca_cert },
{ "removeusercert", 1, do_remove_user_cert },
}; };
static int readx(int s, void *_buf, int count) static int readx(int s, void *_buf, int count)
@@ -121,7 +180,7 @@ static int execute(int s, char cmd[BUFFER_MAX])
/* n is number of args (not counting arg[0]) */ /* n is number of args (not counting arg[0]) */
arg[0] = cmd; arg[0] = cmd;
while (*cmd) { while (*cmd) {
if (isspace(*cmd)) { if (*cmd == CMD_DELIMITER) {
*cmd++ = 0; *cmd++ = 0;
n++; n++;
arg[n] = cmd; arg[n] = cmd;
@@ -167,6 +226,7 @@ int shell_command(const int argc, const char **argv)
int fd, i; int fd, i;
short ret; short ret;
unsigned short count; unsigned short count;
char delimiter[2] = { CMD_DELIMITER, 0 };
char buf[BUFFER_MAX]=""; char buf[BUFFER_MAX]="";
fd = socket_local_client(SOCKET_PATH, fd = socket_local_client(SOCKET_PATH,
@@ -177,7 +237,7 @@ int shell_command(const int argc, const char **argv)
exit(1); exit(1);
} }
for(i = 0; i < argc; i++) { for(i = 0; i < argc; i++) {
if (i > 0) strlcat(buf, " ", BUFFER_MAX); if (i > 0) strlcat(buf, delimiter, BUFFER_MAX);
if(strlcat(buf, argv[i], BUFFER_MAX) >= BUFFER_MAX) { if(strlcat(buf, argv[i], BUFFER_MAX) >= BUFFER_MAX) {
fprintf(stderr, "Arguments are too long\n"); fprintf(stderr, "Arguments are too long\n");
exit(1); exit(1);

View File

@@ -40,18 +40,35 @@
/* path of the keystore */ /* path of the keystore */
#define KEYSTORE_DIR_PREFIX "/data/misc/keystore" #define KEYSTORE_DIR_PREFIX "/data/misc/keystore"
#define CERTS_DIR KEYSTORE_DIR_PREFIX "/certs" #define CERTS_DIR KEYSTORE_DIR_PREFIX "/keys"
#define USERKEYS_DIR KEYSTORE_DIR_PREFIX "/userkeys" #define CACERTS_DIR KEYSTORE_DIR_PREFIX "/cacerts"
#define CA_CERTIFICATE "ca.crt"
#define USER_CERTIFICATE "user.crt"
#define USER_P12_CERT "user.p12"
#define USER_KEY "user.key"
#define DOT "."
#define DOTDOT ".."
#define BUFFER_MAX 1024 /* input buffer for commands */ #define BUFFER_MAX 4096 /* input buffer for commands */
#define TOKEN_MAX 8 /* max number of arguments in buffer */ #define TOKEN_MAX 8 /* max number of arguments in buffer */
#define REPLY_MAX 1024 /* largest reply allowed */ #define REPLY_MAX 4096 /* largest reply allowed */
#define CMD_DELIMITER '\t'
#define KEYNAME_LENGTH 128 #define KEYNAME_LENGTH 128
#define IS_CONTENT 0
#define IS_FILE 1
/* commands.c */ /* commands.c */
int list_certs(char reply[REPLY_MAX]); int list_ca_certs(char reply[REPLY_MAX]);
int list_userkeys(char reply[REPLY_MAX]); int list_user_certs(char reply[REPLY_MAX]);
int install_cert(const char *certfile); int install_user_cert(const char *certname, const char *cert, const char *key);
int install_userkey(const char *keyfile); int install_ca_cert(const char *certname, const char *cert);
int remove_cert(const char *certfile); int install_p12_cert(const char *certname, const char *cert);
int remove_userkey(const char *keyfile); int add_ca_cert(const char *certname, const char *content);
int add_user_cert(const char *certname, const char *content);
int add_user_key(const char *keyname, const char *content);
int get_ca_cert(const char *keyname, char reply[REPLY_MAX]);
int get_user_cert(const char *keyname, char reply[REPLY_MAX]);
int get_user_key(const char *keyname, char reply[REPLY_MAX]);
int remove_user_cert(const char *certname);
int remove_ca_cert(const char *certname);

View File

@@ -30,6 +30,7 @@ public abstract class Keystore {
return new FileKeystore(); return new FileKeystore();
} }
// for compatiblity, start from here
/** /**
*/ */
public abstract String getUserkey(String key); public abstract String getUserkey(String key);
@@ -46,6 +47,34 @@ public abstract class Keystore {
*/ */
public abstract String[] getAllUserkeyKeys(); public abstract String[] getAllUserkeyKeys();
// to here
/**
*/
public abstract String getCaCertificate(String key);
/**
*/
public abstract String getUserCertificate(String key);
/**
*/
public abstract String getUserPrivateKey(String key);
/**
* Returns the array of the certificate keynames in keystore if successful.
* Or return an empty array if error.
*
* @return array of the certificate keynames
*/
public abstract String[] getAllUserCertificateKeys();
/**
*/
public abstract String[] getAllCaCertificateKeys();
/**
*/
public abstract String[] getSupportedKeyStrenghs(); public abstract String[] getSupportedKeyStrenghs();
/** /**
@@ -63,13 +92,25 @@ public abstract class Keystore {
private static class FileKeystore extends Keystore { private static class FileKeystore extends Keystore {
private static final String SERVICE_NAME = "keystore"; private static final String SERVICE_NAME = "keystore";
private static final String LIST_CA_CERTIFICATES = "listcacerts";
private static final String LIST_USER_CERTIFICATES = "listusercerts";
private static final String GET_CA_CERTIFICATE = "getcacert";
private static final String GET_USER_CERTIFICATE = "getusercert";
private static final String GET_USER_KEY = "getuserkey";
private static final String ADD_CA_CERTIFICATE = "addcacert";
private static final String ADD_USER_CERTIFICATE = "addusercert";
private static final String ADD_USER_KEY = "adduserkey";
private static final String COMMAND_DELIMITER = "\t";
private static final ServiceCommand mServiceCommand =
new ServiceCommand(SERVICE_NAME);
// for compatiblity, start from here
private static final String LIST_CERTIFICATES = "listcerts"; private static final String LIST_CERTIFICATES = "listcerts";
private static final String LIST_USERKEYS = "listuserkeys"; private static final String LIST_USERKEYS = "listuserkeys";
private static final String PATH = "/data/misc/keystore/"; private static final String PATH = "/data/misc/keystore/";
private static final String USERKEY_PATH = PATH + "userkeys/"; private static final String USERKEY_PATH = PATH + "userkeys/";
private static final String CERT_PATH = PATH + "certs/"; private static final String CERT_PATH = PATH + "certs/";
private static final ServiceCommand mServiceCommand =
new ServiceCommand(SERVICE_NAME);
@Override @Override
public String getUserkey(String key) { public String getUserkey(String key) {
@@ -81,12 +122,6 @@ public abstract class Keystore {
return CERT_PATH + key; return CERT_PATH + key;
} }
/**
* Returns the array of the certificate names in keystore if successful.
* Or return an empty array if error.
*
* @return array of the certificates
*/
@Override @Override
public String[] getAllCertificateKeys() { public String[] getAllCertificateKeys() {
try { try {
@@ -98,12 +133,6 @@ public abstract class Keystore {
} }
} }
/**
* Returns the array of the names of private keys in keystore if successful.
* Or return an empty array if errors.
*
* @return array of the user keys
*/
@Override @Override
public String[] getAllUserkeyKeys() { public String[] getAllUserkeyKeys() {
try { try {
@@ -115,6 +144,48 @@ public abstract class Keystore {
} }
} }
// to here
@Override
public String getUserPrivateKey(String key) {
return mServiceCommand.execute(
GET_USER_KEY + COMMAND_DELIMITER + key);
}
@Override
public String getUserCertificate(String key) {
return mServiceCommand.execute(
GET_USER_CERTIFICATE + COMMAND_DELIMITER + key);
}
@Override
public String getCaCertificate(String key) {
return mServiceCommand.execute(
GET_CA_CERTIFICATE + COMMAND_DELIMITER + key);
}
@Override
public String[] getAllUserCertificateKeys() {
try {
String result = mServiceCommand.execute(LIST_USER_CERTIFICATES);
if (result != null) return result.split("\\s+");
return NOTFOUND;
} catch (NumberFormatException ex) {
return NOTFOUND;
}
}
@Override
public String[] getAllCaCertificateKeys() {
try {
String result = mServiceCommand.execute(LIST_CA_CERTIFICATES);
if (result != null) return result.split("\\s+");
return NOTFOUND;
} catch (NumberFormatException ex) {
return NOTFOUND;
}
}
@Override @Override
public String[] getSupportedKeyStrenghs() { public String[] getSupportedKeyStrenghs() {
// TODO: real implementation // TODO: real implementation
@@ -149,5 +220,26 @@ public abstract class Keystore {
public void addCertificate(String cert) { public void addCertificate(String cert) {
// TODO: real implementation // TODO: real implementation
} }
private boolean addUserCertificate(String key, String certificate,
String privateKey) {
if(mServiceCommand.execute(ADD_USER_CERTIFICATE + COMMAND_DELIMITER
+ key + COMMAND_DELIMITER + certificate) != null) {
if (mServiceCommand.execute(ADD_USER_KEY + COMMAND_DELIMITER
+ key + COMMAND_DELIMITER + privateKey) != null) {
return true;
}
}
return false;
}
private boolean addCaCertificate(String key, String content) {
if (mServiceCommand.execute(ADD_CA_CERTIFICATE + COMMAND_DELIMITER
+ key + COMMAND_DELIMITER + content) != null) {
return true;
}
return false;
}
} }
} }