Change the keystore APIs.

1. simplify the keypair selection in UI.
2. add the user certificate and key into the keystore for keygen feature.
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 @@
     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 @@
     }
     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 @@
     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 @@
     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;
     }
-    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);
-    strlcat(dstfile, "/", KEYNAME_LENGTH);
-    if (strlcat(dstfile, keyfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
-        LOGE("keyname is too long '%s'\n", keyfile);
+    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 (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 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 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);
 }
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 int do_list_certs(char **arg, char reply[REPLY_MAX])
+static inline int has_whitespace(char *name)
 {
-    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 {
     const char *name;
     unsigned numargs;
@@ -55,12 +107,19 @@
 
 
 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 @@
     /* 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 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 @@
         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 @@
         return new FileKeystore();
     }
 
+    // for compatiblity, start from here
     /**
      */
     public abstract String getUserkey(String key);
@@ -46,6 +47,34 @@
      */
     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 @@
 
     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 @@
             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 @@
             }
         }
 
-        /**
-         * 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 @@
             }
         }
 
+        // 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 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;
+        }
+
     }
 }