Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d531bf0 authored by Chung-yih Wang's avatar Chung-yih Wang
Browse files

Change the keystore APIs.

1. simplify the keypair selection in UI.
2. add the user certificate and key into the keystore for keygen feature.
parent 653349fe
Loading
Loading
Loading
Loading
+128 −42
Original line number Diff line number Diff line
/*
** 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,92 +53,175 @@ 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) {
    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);
    chmod(dstfile, 0440);
    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])
{
    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(CACERTS_DIR, reply);
}

int install_user_cert(const char *keyname, const char *cert, const char *key)
{
    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_ca_cert(const char *keyname, const char *certfile)
{
    return install_key(CACERTS_DIR, keyname, certfile, IS_FILE, CA_CERTIFICATE);
}

int install_p12_cert(const char *keyname, const char *certfile)
{
    return list_files(USERKEYS_DIR, reply);
    return install_key(CERTS_DIR, keyname, certfile, IS_FILE, USER_P12_CERT);
}

int install_cert(const char *certfile)
int add_ca_cert(const char *keyname, const char *certificate)
{
    return install_key(CERTS_DIR, certfile);
    return install_key(CACERTS_DIR, keyname, certificate, IS_CONTENT,
            CA_CERTIFICATE);
}

int install_userkey(const char *keyfile)
int add_user_cert(const char *keyname, const char *certificate)
{
    return install_key(USERKEYS_DIR, keyfile);
    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);
}
+80 −20
Original line number Diff line number Diff line
@@ -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);
+27 −10
Original line number Diff line number Diff line
@@ -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);
+106 −14
Original line number Diff line number Diff line
@@ -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;
        }

    }
}