diff options
-rw-r--r-- | cmds/keystore/commands.c | 170 | ||||
-rw-r--r-- | cmds/keystore/keystore.c | 100 | ||||
-rw-r--r-- | cmds/keystore/keystore.h | 37 | ||||
-rw-r--r-- | keystore/java/android/security/Keystore.java | 120 |
4 files changed, 341 insertions, 86 deletions
diff --git a/cmds/keystore/commands.c b/cmds/keystore/commands.c index e53cece..17dd060 100644 --- a/cmds/keystore/commands.c +++ b/cmds/keystore/commands.c @@ -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"); ** 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; } -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; DIR *d; @@ -39,7 +40,9 @@ static int list_files(const char *dir, char reply[REPLY_MAX]) { } reply[0]=0; 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 (strlcat(reply, de->d_name, REPLY_MAX) >= REPLY_MAX) { LOGE("reply is too long(too many files under '%s'\n", dir); @@ -50,31 +53,25 @@ static int list_files(const char *dir, char reply[REPLY_MAX]) { return 0; } -static int copy_keyfile(const char *keystore, const char *srcfile) { - int srcfd, dstfd; - int length; - char buf[2048]; - char dstfile[KEYNAME_LENGTH]; - const char *filename = strrchr(srcfile, '/'); +static int copy_keyfile(const char *src, int src_type, const char *dstfile) { + int srcfd = -1, dstfd; + char buf[REPLY_MAX]; - strlcpy(dstfile, keystore, KEYNAME_LENGTH); - strlcat(dstfile, "/", KEYNAME_LENGTH); - 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); + if ((src_type == IS_FILE) && (srcfd = open(src, O_RDONLY)) == -1) { + LOGE("Cannot open the original file '%s'\n", src); return -1; } if ((dstfd = open(dstfile, O_CREAT|O_RDWR)) == -1) { LOGE("Cannot open the destination file '%s'\n", dstfile); return -1; } - while((length = read(srcfd, buf, 2048)) > 0) { - write(dstfd, buf, length); + if (src_type == IS_FILE) { + int length; + while((length = read(srcfd, buf, REPLY_MAX)) > 0) { + write(dstfd, buf, length); + } + } else { + write(dstfd, src, strlen(src)); } close(srcfd); close(dstfd); @@ -82,60 +79,149 @@ static int copy_keyfile(const char *keystore, const char *srcfile) { 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; + char fullpath[KEYNAME_LENGTH]; 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; + } + + 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(dir, keyfile); + 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]) +{ + struct dirent *de; + char filename[KEYNAME_LENGTH]; + int fd; + + if (snprintf(filename, sizeof(filename), "%s/%s/%s", path, keyname, file) + >= KEYNAME_LENGTH) { + LOGE("cert name '%s' is too long.\n", keyname); + return -1; + } + + 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++; + } - strlcpy(dstfile, dir, KEYNAME_LENGTH); - strlcat(dstfile, "/", KEYNAME_LENGTH); - if (strlcat(dstfile, keyfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) { - LOGE("keyname is too long '%s'\n", keyfile); + if (count == 0) { + LOGE("can not clean up '%s' keys or not exist\n", key); return -1; } - if (unlink(dstfile)) { - LOGE("cannot delete '%s': %s\n", dstfile, strerror(errno)); + + snprintf(dstfile, KEYNAME_LENGTH, "%s/%s", dir, key); + if (rmdir(dstfile)) { + LOGE("can not clean up '%s' directory\n", key); return -1; } return 0; } -int list_certs(char reply[REPLY_MAX]) +int list_user_certs(char reply[REPLY_MAX]) { 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 install_p12_cert(const char *keyname, const char *certfile) +{ + return install_key(CERTS_DIR, keyname, certfile, IS_FILE, USER_P12_CERT); +} + +int add_ca_cert(const char *keyname, const char *certificate) +{ + 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_cert(const char *certfile) +int remove_user_cert(const char *key) { - return remove_key(CERTS_DIR, certfile); + return remove_key(CERTS_DIR, key); } -int remove_userkey(const char *keyfile) +int remove_ca_cert(const char *key) { - return remove_key(USERKEYS_DIR, keyfile); + return remove_key(CACERTS_DIR, key); } diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c index 5193b3d..df8d832 100644 --- a/cmds/keystore/keystore.c +++ b/cmds/keystore/keystore.c @@ -16,37 +16,89 @@ #include "keystore.h" +static inline int has_whitespace(char *name) +{ + if((strrchr(name, ' ') != NULL)) { + LOGE("'%s' contains whitespace character\n", name); + return 1; + } + return 0; +} + +static int do_list_user_certs(char **arg, char reply[REPLY_MAX]) +{ + return list_user_certs(reply); +} + +static int do_list_ca_certs(char **arg, char reply[REPLY_MAX]) +{ + return list_ca_certs(reply); +} + +static int do_install_user_cert(char **arg, char reply[REPLY_MAX]) +{ + 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_list_certs(char **arg, char reply[REPLY_MAX]) +static int do_install_p12_cert(char **arg, char reply[REPLY_MAX]) { - return list_certs(reply); + if (has_whitespace(arg[0])) return -1; + return install_p12_cert(arg[0], arg[1]); } -static int do_list_userkeys(char **arg, char reply[REPLY_MAX]) +static int do_install_ca_cert(char **arg, char reply[REPLY_MAX]) { - return list_userkeys(reply); + 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_install_cert(char **arg, char reply[REPLY_MAX]) +static int do_add_ca_cert(char **arg, char reply[REPLY_MAX]) { - return install_cert(arg[0]); /* move the certificate to keystore */ + if (has_whitespace(arg[0])) return -1; + return add_ca_cert(arg[0], arg[1]); } -static int do_remove_cert(char **arg, char reply[REPLY_MAX]) +static int do_add_user_cert(char **arg, char reply[REPLY_MAX]) { - return remove_cert(arg[0]); /* certificate */ + if (has_whitespace(arg[0])) return -1; + return add_user_cert(arg[0], arg[1]); } -static int do_install_userkey(char **arg, char reply[REPLY_MAX]) +static int do_add_user_key(char **arg, char reply[REPLY_MAX]) { - return install_userkey(arg[0]); /* move the certificate to keystore */ + if (has_whitespace(arg[0])) return -1; + return add_user_key(arg[0], arg[1]); } -static int do_remove_userkey(char **arg, char reply[REPLY_MAX]) +static int do_get_ca_cert(char **arg, char reply[REPLY_MAX]) { - return remove_userkey(arg[0]); /* userkey */ + 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 { const char *name; unsigned numargs; @@ -55,12 +107,19 @@ struct cmdinfo { struct cmdinfo cmds[] = { - { "listcerts", 0, do_list_certs }, - { "listuserkeys", 0, do_list_userkeys }, - { "installcert", 1, do_install_cert }, - { "removecert", 1, do_remove_cert }, - { "installuserkey", 1, do_install_userkey }, - { "removeuserkey", 1, do_remove_userkey }, + { "listcacerts", 0, do_list_ca_certs }, + { "listusercerts", 0, do_list_user_certs }, + { "installusercert", 3, do_install_user_cert }, + { "installcacert", 2, do_install_ca_cert }, + { "installp12cert", 2, do_install_p12_cert }, + { "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) @@ -121,7 +180,7 @@ static int execute(int s, char cmd[BUFFER_MAX]) /* n is number of args (not counting arg[0]) */ arg[0] = cmd; while (*cmd) { - if (isspace(*cmd)) { + if (*cmd == CMD_DELIMITER) { *cmd++ = 0; n++; arg[n] = cmd; @@ -167,6 +226,7 @@ int shell_command(const int argc, const char **argv) int fd, i; short ret; unsigned short count; + char delimiter[2] = { CMD_DELIMITER, 0 }; char buf[BUFFER_MAX]=""; fd = socket_local_client(SOCKET_PATH, @@ -177,7 +237,7 @@ int shell_command(const int argc, const char **argv) exit(1); } 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) { fprintf(stderr, "Arguments are too long\n"); exit(1); diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h index 35acf0b9..b9cb185 100644 --- a/cmds/keystore/keystore.h +++ b/cmds/keystore/keystore.h @@ -40,18 +40,35 @@ /* path of the keystore */ #define KEYSTORE_DIR_PREFIX "/data/misc/keystore" -#define CERTS_DIR KEYSTORE_DIR_PREFIX "/certs" -#define USERKEYS_DIR KEYSTORE_DIR_PREFIX "/userkeys" +#define CERTS_DIR KEYSTORE_DIR_PREFIX "/keys" +#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 REPLY_MAX 1024 /* largest reply allowed */ +#define REPLY_MAX 4096 /* largest reply allowed */ +#define CMD_DELIMITER '\t' #define KEYNAME_LENGTH 128 +#define IS_CONTENT 0 +#define IS_FILE 1 + /* commands.c */ -int list_certs(char reply[REPLY_MAX]); -int list_userkeys(char reply[REPLY_MAX]); -int install_cert(const char *certfile); -int install_userkey(const char *keyfile); -int remove_cert(const char *certfile); -int remove_userkey(const char *keyfile); +int list_ca_certs(char reply[REPLY_MAX]); +int list_user_certs(char reply[REPLY_MAX]); +int install_user_cert(const char *certname, const char *cert, const char *key); +int install_ca_cert(const char *certname, const char *cert); +int install_p12_cert(const char *certname, const char *cert); +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); diff --git a/keystore/java/android/security/Keystore.java b/keystore/java/android/security/Keystore.java index 71c1cf4..ce3fa88 100644 --- a/keystore/java/android/security/Keystore.java +++ b/keystore/java/android/security/Keystore.java @@ -30,6 +30,7 @@ public abstract class Keystore { return new FileKeystore(); } + // for compatiblity, start from here /** */ public abstract String getUserkey(String key); @@ -46,6 +47,34 @@ public abstract class Keystore { */ 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(); /** @@ -63,13 +92,25 @@ public abstract class Keystore { private static class FileKeystore extends 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_USERKEYS = "listuserkeys"; private static final String PATH = "/data/misc/keystore/"; private static final String USERKEY_PATH = PATH + "userkeys/"; private static final String CERT_PATH = PATH + "certs/"; - private static final ServiceCommand mServiceCommand = - new ServiceCommand(SERVICE_NAME); @Override public String getUserkey(String key) { @@ -81,12 +122,6 @@ public abstract class Keystore { 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 public String[] getAllCertificateKeys() { 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 public String[] getAllUserkeyKeys() { 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 public String[] getSupportedKeyStrenghs() { // TODO: real implementation @@ -149,5 +220,26 @@ public abstract class Keystore { public void addCertificate(String cert) { // 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; + } + } } |