diff options
author | Franklin Wei <me@fwei.tk> | 2018-06-25 11:02:19 -0400 |
---|---|---|
committer | Franklin Wei <me@fwei.tk> | 2018-06-25 11:02:19 -0400 |
commit | 91d71b86d0d93e49c610baf01df593ec21752048 (patch) | |
tree | e5fd5243c6e711c4b328b6969e6d41d77f0e72af | |
parent | 68932344b45fb8938e86513220eb39b3b7306c5b (diff) | |
download | csaa-91d71b86d0d93e49c610baf01df593ec21752048.zip csaa-91d71b86d0d93e49c610baf01df593ec21752048.tar.gz csaa-91d71b86d0d93e49c610baf01df593ec21752048.tar.bz2 csaa-91d71b86d0d93e49c610baf01df593ec21752048.tar.xz |
Update client; provide ACL in response; add encryption
Changed the command-line interface a bit to make it less sensitive to the
ordering of switches, though modifyacl still has its old behavior. The
client now supports the -e flag to encrypt the file with a random key.
-rw-r--r-- | client.c | 326 | ||||
-rw-r--r-- | crypto.c | 107 | ||||
-rw-r--r-- | crypto.h | 5 | ||||
-rw-r--r-- | helper.c | 3 | ||||
-rw-r--r-- | main.c | 5 | ||||
-rw-r--r-- | service_provider.c | 64 | ||||
-rw-r--r-- | service_provider.h | 9 |
7 files changed, 404 insertions, 115 deletions
@@ -3,14 +3,21 @@ /* Usage: * - * $ ./client [-s <SOCKET>] -k KEY -u USERID COMMAND [PARAMS] + * $ ./client [-s <SOCKET>] -u USERID -k USER_KEY COMMAND [PARAMS] * - * Where COMMAND and PARAMS is one of the following: + * Where COMMAND and PARAMS are one of the following: * create (takes no parameters) - * modifyacl fileidx user_1 acc_1 ... user_n acc_n - * modifyfile fileidx buildcode_file compose_file image_file [FILE_KEY] - * retrieveinfo fileidx version - * retrievefile fileidx version buildcode_out compose_out image_out [FILE_KEY] + * + * modifyacl -f FILEIDX USER_1 ACCESS_1 ... USER_n ACCESS_n + * - NOTE: there must be nothing following this command, as everything + * will be interpreted as part of the ACL list. + * + * modifyfile -f FILEIDX -i IMAGE_FILE [-ib buildcode_file] + * [-ic compose_file] [--encrypt, -e] + * + * retrieveinfo -f FILEIDX [-v VERSION] + * + * retrievefile -f FILEIDX [-v VERSION] -o IMAGE_OUT */ #define CLIENT @@ -60,14 +67,27 @@ static int ilog2(int n) void print_usage(const char *name) { - printf("Usage: %s [-s <SOCKET>] -k KEY -u USERID COMMAND [PARAMS]\n" + printf("Usage:\n" + "\n" + "$ ./client [-s <SOCKET>] -u USERID -k USER_KEY COMMAND [PARAMS]\n" "\n" "Where COMMAND and PARAMS are one of the following:\n" - " create (takes no parameters)\n" - " modifyacl fileidx USER_1 ACCESS_1 ... USER_n ACCESS_n\n" - " modifyfile fileidx buildcode_file compose_file image_file [FILE_KEY]\n" - " retrieveinfo fileidx version\n" - " retrievefile fileidx version buildcode_out compose_out image_out [FILE_KEY]\n", name); + " create (takes no parameters)\n" + "\n" + " modifyacl -f FILEIDX USER_1 ACCESS_1 ... USER_n ACCESS_n\n" + " - NOTE: there must be nothing following this command, as everything\n" + " will be interpreted as part of the ACL list.\n" + "\n" + " modifyfile -f FILEIDX -i IMAGE_FILE [-ib buildcode_file]\n" + " [-ic compose_file] [--encrypt, -e]\n" + "\n" + " retrieveinfo -f FILEIDX [-v VERSION]\n" + "\n" + " retrievefile -f FILEIDX [-v VERSION] -o IMAGE_OUT\n"); + for(int i = 0; i < 10; ++i) + { + printf("%d %d\n", i, ilog2(i)); + } } bool parse_args(int argc, char *argv[]) @@ -105,6 +125,63 @@ bool parse_args(int argc, char *argv[]) return false; } } + else if(!strcmp(arg, "-f")) + { + if(++i < argc) + cl_request.file_idx = atol(argv[i]); + else + { + parse_args_fail = "Expected file index"; + return false; + } + } + else if(!strcmp(arg, "-v")) + { + if(++i < argc) + cl_request.retrieve.version = atol(argv[i]); + else + { + parse_args_fail = "Expected version number"; + return false; + } + } + /* -i and -o are handled identically */ + else if(!strcmp(arg, "-i") || !strcmp(arg, "-o")) + { + if(++i < argc) + image_path = argv[i]; + else + { + parse_args_fail = "Expected image path"; + return false; + } + } + else if(!strcmp(arg, "-ib")) + { + if(++i < argc) + buildcode_path = argv[i]; + else + { + parse_args_fail = "Expected build code"; + return false; + } + } + else if(!strcmp(arg, "-ic")) + { + if(++i < argc) + compose_path = argv[i]; + else + { + parse_args_fail = "Expected compose file"; + return false; + } + } + else if(!strcmp(arg, "-e") || !strcmp(arg, "--encrypt")) + { + /* a random nonce will be generated along with this to + * form the key */ + file_key = "a"; + } else if(!strcmp(arg, "-h") || !strcmp(arg, "--help")) { print_usage(argv[0]); @@ -128,14 +205,6 @@ bool parse_args(int argc, char *argv[]) } cl_request.type = MODIFY_ACL; - if(++i < argc) - cl_request.modify_acl.file_idx = atol(argv[i]); - else - { - parse_args_fail = "Expected file idx"; - return false; - } - i++; size_t n = argc - i; @@ -153,12 +222,13 @@ bool parse_args(int argc, char *argv[]) /* sort ACL tuples by user id */ qsort(acl_tuples, n / 2, 2 * sizeof(uint64_t), compare_tuple); - size_t logleaves = ilog2(n); + size_t logleaves = ilog2(n / 2); /* round up if acl size is not an integer power of 2 */ - if((1 << logleaves) != n) + if((1 << logleaves) != n / 2) logleaves++; + printf("ACL logleaves = %d, count = %d, mt_leafcount = %d\n", logleaves, n, 1 << logleaves); new_acl = iomt_new(logleaves); /* now produce IOMT */ uint64_t first_idx = acl_tuples[0]; @@ -178,20 +248,6 @@ bool parse_args(int argc, char *argv[]) return false; } cl_request.type = MODIFY_FILE; - - if(++i < argc) - cl_request.modify_file.file_idx = atol(argv[i]); - else - { - parse_args_fail = "Expected file idx"; - return false; - } - - buildcode_path = argv[++i]; - compose_path = argv[++i]; - image_path = argv[++i]; - if(i + 1 < argc) - file_key = argv[++i]; } else if(!strcmp(arg, "retrieveinfo") || !strcmp(arg, "retrievefile")) { @@ -202,31 +258,9 @@ bool parse_args(int argc, char *argv[]) } cl_request.type = RETRIEVE_INFO; - if(++i < argc) - cl_request.retrieve.file_idx = atol(argv[i]); - else - { - parse_args_fail = "Expected file idx"; - return false; - } - - if(++i < argc) - cl_request.retrieve.version = atol(argv[i]); - else - { - parse_args_fail = "Expected file version"; - return false; - } - if(!strcmp(arg, "retrievefile")) { cl_request.type = RETRIEVE_FILE; - - buildcode_path = argv[++i]; - compose_path = argv[++i]; - image_path = argv[++i]; - if(i + 1 < argc) - file_key = argv[++i]; } } else @@ -236,7 +270,36 @@ bool parse_args(int argc, char *argv[]) } } if(cl_request.type != USERREQ_NONE && user_id != 0 && userkey != NULL) + { + if(cl_request.type > CREATE_FILE) + { + if(!cl_request.file_idx) + { + parse_args_fail = "No file index specified"; + return false; + } + } + else + { + if(cl_request.file_idx) + { + parse_args_fail = "Index specified for create"; + return false; + } + } + + if(cl_request.type == MODIFY_FILE || + cl_request.type == RETRIEVE_FILE) + { + if(!image_path) + { + parse_args_fail = "No image file specified"; + return false; + } + } + return true; + } else { parse_args_fail = "Missing required parameter (either command, user ID, or user key)"; @@ -283,7 +346,7 @@ static struct tm_request verify_and_sign(int fd, const struct user_request *req) break; } default: - break; + return req_null; } printf("Signing request\n"); @@ -367,28 +430,45 @@ bool exec_request(int fd, const struct user_request *req, if(hash_equals(hmac, hmac_sha256(&verinfo, sizeof(verinfo), user_key, keylen))) { + if(verinfo.idx != 0) + { + struct iomt *acl = iomt_deserialize(read_from_fd, &fd); + printf("ACL: "); + iomt_dump(acl); + iomt_free(acl); + } + *verinfo_out = verinfo; return true; } + return false; } case RETRIEVE_FILE: { - hash_t encrypted_secret; + hash_t encrypted_secret, kf; recv(fd, &encrypted_secret, sizeof(encrypted_secret), MSG_WAITALL); + recv(fd, &kf, sizeof(kf), MSG_WAITALL); - *secret_out = crypt_secret(encrypted_secret, - req->retrieve.file_idx, - req->retrieve.version, - user_key, keylen); + hash_t pad = hmac_sha256(&kf, sizeof(kf), + user_key, keylen); + *secret_out = hash_xor(encrypted_secret, pad); *buildcode = iomt_deserialize(read_from_fd, &fd); *composefile = iomt_deserialize(read_from_fd, &fd); recv(fd, file_len, sizeof(*file_len), MSG_WAITALL); - *file_contents_out = malloc(*file_len); - recv(fd, *file_contents_out, *file_len, MSG_WAITALL); + if(*file_len) + { + *file_contents_out = malloc(*file_len); + recv(fd, *file_contents_out, *file_len, MSG_WAITALL); + } + else + { + *file_contents_out = NULL; + return false; + } return true; } default: @@ -396,6 +476,38 @@ bool exec_request(int fd, const struct user_request *req, } } +/* set version = 0 to get latest version */ +struct version_info request_verinfo(int fd, uint64_t user_id, + const char *user_key, size_t keylen, + uint64_t file_idx, uint64_t version) + +{ + struct user_request req; + req.type = RETRIEVE_INFO; + req.user_id = user_id; + req.retrieve.file_idx = file_idx; + req.retrieve.version = version; + + struct version_info verinfo; + + bool rc = exec_request(fd, &req, + NULL, + NULL, + NULL, + NULL, 0, + NULL, + &verinfo, + user_key, keylen, + NULL, + NULL, + NULL, + NULL, + NULL); + if(rc) + return verinfo; + return verinfo_null; +} + int connect_to_service(const char *sockpath) { struct sockaddr_un addr; @@ -436,13 +548,16 @@ void *load_file(const char *path, size_t *len) void write_file(const char *path, const void *contents, size_t len) { - FILE *f = fopen(path, "w"); - fwrite(contents, 1, len, f); - fclose(f); + if(contents) + { + FILE *f = fopen(path, "w"); + fwrite(contents, 1, len, f); + fclose(f); + } } bool server_request(const char *sockpath, - const char *userkey, uint64_t user_id, + const char *user_key, uint64_t user_id, struct user_request req, struct iomt *new_acl, const char *buildcode_path, @@ -450,29 +565,66 @@ bool server_request(const char *sockpath, const char *image_path, const char *file_key) { - int fd = connect_to_service(sockpath); + struct iomt *buildcode = NULL, *composefile = NULL; + void *file_contents = NULL; + size_t file_len = 0; + hash_t secret = hash_null; + /* Fill in rest of request structure */ req.user_id = user_id; - struct iomt *buildcode = NULL, *composefile = NULL; if(req.type == MODIFY_FILE) { /* these can safely take NULLs */ buildcode = iomt_from_lines(buildcode_path); composefile = iomt_from_lines(compose_path); - } - void *file_contents = NULL; - size_t file_len = 0; - hash_t secret = hash_null; - if(image_path && req.type == MODIFY_FILE) - file_contents = load_file(image_path, &file_len); + if(image_path) + { + file_contents = load_file(image_path, &file_len); - /* TODO: encrypt file */ + /* Encrypt file and secret */ + if(file_key) + { + /* Get version */ + int fd = connect_to_service(sockpath); + struct version_info verinfo = request_verinfo(fd, user_id, + user_key, strlen(user_key), + req.modify_file.file_idx, + 0); + close(fd); + + /* failure */ + if(verinfo.idx == 0) + { + printf("Could not get version info.\n"); + return false; + } + + /* We use a block cipher in CTR mode and can thus + * avoid having to use an IV (as long as we never + * re-use keys) */ + hash_t nonce = generate_nonce(); + secret = derive_key(file_key, nonce); + + /* encrypt file (presumably a symmetric cipher) */ + crypt_bytes(file_contents, file_len, secret); + + printf("Derived file secret: %s\n", hash_format(secret, 4).str); + req.modify_file.kf = calc_kf(secret, req.modify_file.file_idx); + req.modify_file.encrypted_secret = crypt_secret(secret, + req.modify_file.file_idx, + verinfo.max_version + 1, + user_key, user_id); + } + } + } struct version_info verinfo; struct tm_request tmreq; + int fd = connect_to_service(sockpath); + bool success = exec_request(fd, &req, req.type == MODIFY_ACL ? new_acl : NULL, req.type == MODIFY_FILE ? buildcode : NULL, @@ -481,8 +633,8 @@ bool server_request(const char *sockpath, req.type == MODIFY_FILE ? file_len : 0, req.type <= MODIFY_ACL ? &tmreq : NULL, req.type == RETRIEVE_INFO ? &verinfo : NULL, - req.type >= RETRIEVE_INFO ? userkey : NULL, - req.type >= RETRIEVE_INFO ? strlen(userkey) : 0, + req.type >= RETRIEVE_INFO ? user_key : NULL, + req.type >= RETRIEVE_INFO ? strlen(user_key) : 0, req.type == RETRIEVE_FILE ? &buildcode : NULL, req.type == RETRIEVE_FILE ? &composefile : NULL, req.type == RETRIEVE_FILE ? &secret : NULL, @@ -509,11 +661,19 @@ bool server_request(const char *sockpath, case RETRIEVE_FILE: { hash_t gamma = sha256(file_contents, file_len); - hash_t lambda = calc_lambda(gamma, buildcode, composefile, req.modify_file.kf); + hash_t kf = calc_kf(secret, req.retrieve.file_idx); + + /* We should recalculate the roots of the two IOMTs ourselves + * to be sure */ + hash_t lambda = calc_lambda(gamma, buildcode, composefile, kf); + + printf("Decrypted file secret as %s\n", hash_format(secret, 4).str); printf("File lambda = %s\n", hash_format(lambda, 4).str); - /* TODO: decrypt file */ + if(!is_zero(kf)) + crypt_bytes(file_contents, file_len, secret); + printf("Writing image file to %s.\n", image_path); write_file(image_path, file_contents, file_len); /* What about build code? We only have the IOMT, not the actual contents. */ @@ -2,11 +2,15 @@ #include "trusted_module.h" #include "test.h" -#include <sys/socket.h> +#include <assert.h> #include <unistd.h> #include <string.h> +#include <sys/socket.h> + +#include <openssl/aes.h> #include <openssl/hmac.h> +#include <openssl/rand.h> #include <openssl/sha.h> /* return true iff [b, bprime] encloses a */ @@ -364,6 +368,8 @@ struct iomt *iomt_new(int logleaves) struct iomt *iomt_dup(const struct iomt *tree) { + if(!tree) + return NULL; struct iomt *newtree = calloc(1, sizeof(struct iomt)); newtree->mt_leafcount = tree->mt_leafcount; newtree->mt_logleaves = tree->mt_logleaves; @@ -395,6 +401,8 @@ void write_u64(void (*write_fn)(void *userdata, const void *data, size_t len), write_fn(userdata, &n, sizeof(n)); } +#define IOMT_EMPTY (uint64_t)0xFFFFFFFFFFFFFFFFUL + void iomt_serialize(const struct iomt *tree, void (*write_fn)(void *userdata, const void *data, size_t len), void *userdata) @@ -408,15 +416,17 @@ void iomt_serialize(const struct iomt *tree, write_fn(userdata, tree->mt_leaves, sizeof(struct iomt_node) * tree->mt_leafcount); } else - write_u64(write_fn, userdata, 0); + write_u64(write_fn, userdata, IOMT_EMPTY); } struct iomt *iomt_deserialize(int (*read_fn)(void *userdata, void *buf, size_t len), void *userdata) { uint64_t logleaves = read_u64(read_fn, userdata); - if(!logleaves) + + if(logleaves == IOMT_EMPTY) return NULL; + struct iomt *tree = iomt_new(logleaves); read_fn(userdata, tree->mt_nodes, sizeof(hash_t) * (2 * tree->mt_leafcount - 1)); @@ -500,14 +510,19 @@ struct hashstring hash_format(hash_t h, int n) void iomt_dump(const struct iomt *tree) { - for(int i = 0; i < tree->mt_leafcount; ++i) + if(tree) { - printf("(%lu, %s, %lu)%s", - tree->mt_leaves[i].idx, - hash_format(tree->mt_leaves[i].val, 4).str, - tree->mt_leaves[i].next_idx, - (i == tree->mt_leafcount - 1) ? "\n" : ", "); + for(int i = 0; i < tree->mt_leafcount; ++i) + { + printf("(%lu, %s, %lu)%s", + tree->mt_leaves[i].idx, + hash_format(tree->mt_leaves[i].val, 4).str, + tree->mt_leaves[i].next_idx, + (i == tree->mt_leafcount - 1) ? "\n" : ", "); + } } + else + printf("(empty IOMT)\n"); } /* convert the first 8 bytes (little endian) to a 64-bit int */ @@ -530,6 +545,12 @@ hash_t u64_to_hash(uint64_t n) return ret; } +hash_t hash_increment(hash_t h) +{ + /* incredibly inefficient... FIXME! */ + return u64_to_hash(hash_to_u64(h) + 1); +} + /* simple XOR cipher, so encryption and decryption are symmetric */ hash_t crypt_secret(hash_t encrypted_secret, uint64_t file_idx, uint64_t file_version, @@ -555,9 +576,6 @@ hash_t crypt_secret(hash_t encrypted_secret, * forgo any HMAC. */ hash_t calc_lambda(hash_t gamma, const struct iomt *buildcode, const struct iomt *composefile, hash_t kf) { - printf("calc_lambda: gamma = %s, buildcode = %s, compose = %s, kf = %s\n", - hash_format(gamma, 4).str, hash_format(buildcode->mt_nodes[0], 4).str, - hash_format(composefile->mt_nodes[0], 4).str, hash_format(kf, 4).str); hash_t buildcode_root = hash_null, composefile_root = hash_null; if(buildcode) buildcode_root = buildcode->mt_nodes[0]; @@ -576,9 +594,74 @@ hash_t calc_lambda(hash_t gamma, const struct iomt *buildcode, const struct iomt SHA256_Final(h.hash, &ctx); + printf("calc_lambda: gamma = %s, kf = %s, lambda = %s\n", + hash_format(gamma, 4).str, hash_format(kf, 4).str, + hash_format(h, 4).str); return h; } +hash_t generate_nonce(void) +{ + hash_t ret; + if(!RAND_bytes(ret.hash, sizeof(ret.hash))) + { + assert(!"Failed to generate nonce"); + } + return ret; +} + +/* Derive a fixed-length key from an arbitrary-length + * passphrase. TODO: replace with a real KDF (PBKDF2?) */ +hash_t derive_key(const char *passphrase, hash_t nonce) +{ + if(!passphrase || strlen(passphrase) == 0) + return hash_null; + return hmac_sha256(passphrase, strlen(passphrase), + &nonce, sizeof(nonce)); +} + +hash_t calc_kf(hash_t encryption_key, uint64_t file_idx) +{ + if(is_zero(encryption_key)) + return hash_null; + return hmac_sha256(&encryption_key, sizeof(encryption_key), + &file_idx, sizeof(file_idx)); +} + +void memxor(unsigned char *dest, const unsigned char *b, size_t len) +{ + while(len--) + *dest++ ^= *b++; +} + +/* symmetric: decryption and encryption are the same operation */ +void crypt_bytes(unsigned char *data, size_t len, hash_t key) +{ + /* We use AES256 in CTR mode with a hard-coded IV. We never reuse + * keys, as they are generated with a combination of the passphrase + * and a nonce. Therefore, it should be reasonably safe to + * hard-code the IV: */ + AES_KEY aes; + + AES_set_encrypt_key((void*)&key, 256, &aes); + unsigned char block[16]; + + /* We only use the first 16 bytes of the counter. */ + hash_t counter = u64_to_hash(0); + + size_t i; + for(i = 0; i < len; i += 16, data += 16) + { + AES_ecb_encrypt((void*)&counter, block, &aes, AES_ENCRYPT); + memxor(data, block, 16); + counter = hash_increment(counter); + } + + /* finish up */ + AES_ecb_encrypt((void*)&counter, block, &aes, AES_ENCRYPT); + memxor(data, block, len - i); +} + /* Generate a signed acknowledgement for successful completion of a * request. We append a zero byte to the user request and take the * HMAC. */ @@ -155,6 +155,11 @@ int read_from_fd(void *userdata, void *buf, size_t len); void dump_versioninfo(const struct version_info *verinfo); +void crypt_bytes(unsigned char *data, size_t len, hash_t key); +hash_t generate_nonce(void); +hash_t derive_key(const char *passphrase, hash_t nonce); +hash_t calc_kf(hash_t encryption_key, uint64_t file_idx); + /* self-test */ void crypto_test(void); #endif @@ -75,7 +75,8 @@ struct tm_cert cert_rv_by_idx(const struct trusted_module *tm, } else { - /* node does not exist */ + /* We have an encloser node, indicating that the requested + * node does not exist. */ cert_rv(tm, node, comp, orders, tree->mt_logleaves, @@ -46,7 +46,7 @@ void run_tests(void) int main() { - //run_tests(); + run_tests(); const char *socket_name = "socket"; int sockfd; @@ -56,11 +56,14 @@ int main() return 1; } + printf("Listening on '%s'\n", socket_name); + cleanup_socket = socket_name; atexit(cleanup); signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); + signal(SIGSEGV, signal_handler); sp_main(sockfd); } diff --git a/service_provider.c b/service_provider.c index 2ee4a12..86b4864 100644 --- a/service_provider.c +++ b/service_provider.c @@ -562,7 +562,8 @@ struct version_info sp_fileinfo(struct service_provider *sp, uint64_t user_id, uint64_t file_idx, uint64_t version, - hash_t *hmac) + hash_t *hmac, + struct iomt **acl_out) { struct file_record *rec = lookup_record(sp, file_idx); @@ -647,6 +648,9 @@ struct version_info sp_fileinfo(struct service_provider *sp, else ver = NULL; + if(acl_out) + *acl_out = iomt_dup(rec->acl); + return tm_verify_fileinfo(sp->tm, user_id, &rv1, rv1_hmac, @@ -658,25 +662,28 @@ struct version_info sp_fileinfo(struct service_provider *sp, /* This file retrieves the file given by file_idx for a given * user. *encrypted_secret will be set to the encryption key XOR'd - * with HMAC(f | c_f, K). The returned value is dynamically allocated - * and must be freed by the caller. This function returns NULL upon - * failure. An authenticated proof that the request cannot be - * satisfied can be obtained by calling sp_fileinfo. */ + * with HMAC(kf, K). kf will be returned via the *kf pointer. The + * returned value is dynamically allocated and must be freed by the + * caller. This function returns NULL upon failure. An authenticated + * proof that the request cannot be satisfied can be obtained by + * calling sp_fileinfo. */ void *sp_retrieve_file(struct service_provider *sp, uint64_t user_id, uint64_t file_idx, uint64_t version, hash_t *encrypted_secret, + hash_t *kf, struct iomt **buildcode, struct iomt **composefile, size_t *len) { struct file_record *rec = lookup_record(sp, file_idx); - if(!rec->nversions) + if(!rec || !rec->nversions) { /* Newly created file, no contents. We don't bother to set - * *encrypted_secret or *len. */ + * *encrypted_secret or *len. Or, file does not exist. */ + *len = 0; return NULL; } @@ -703,6 +710,9 @@ void *sp_retrieve_file(struct service_provider *sp, ver->encrypted_secret, ver->kf); } + if(kf) + *kf = ver->kf; + if(len) *len = ver->contents_len; @@ -755,6 +765,10 @@ static void sp_handle_client(struct service_provider *sp, int cl) { printf("Client: modify ACL\n"); struct iomt *acl = iomt_deserialize(read_from_fd, &cl); + + if(!acl) + return; + sp_modifyacl(sp, user_req.user_id, get_client_signature, @@ -801,37 +815,53 @@ static void sp_handle_client(struct service_provider *sp, int cl) case RETRIEVE_INFO: { printf("Client: retrieve info\n"); + struct iomt *acl = NULL; struct version_info verinfo = sp_fileinfo(sp, user_req.user_id, user_req.retrieve.file_idx, user_req.retrieve.version, - &ack_hmac); + &ack_hmac, + &acl); write(cl, &verinfo, sizeof(verinfo)); write(cl, &ack_hmac, sizeof(ack_hmac)); + + if(acl && verinfo.idx != 0) + { + iomt_serialize(acl, write_to_fd, &cl); + iomt_free(acl); + } + else + { + printf("failed: %s\n", tm_geterror()); + } + break; } case RETRIEVE_FILE: { printf("Client: retrieve file\n"); - hash_t encrypted_secret; - size_t len; + hash_t encrypted_secret = hash_null, kf = hash_null; + size_t len = 0; struct iomt *buildcode = NULL, *composefile = NULL; void *contents = sp_retrieve_file(sp, user_req.user_id, user_req.retrieve.file_idx, user_req.retrieve.version, &encrypted_secret, + &kf, &buildcode, &composefile, &len); /* write everything (no HMAC; the client should do a * RETRIEVE_INFO request separately) */ write(cl, &encrypted_secret, sizeof(encrypted_secret)); + write(cl, &kf, sizeof(kf)); iomt_serialize(buildcode, write_to_fd, &cl); iomt_serialize(composefile, write_to_fd, &cl); write(cl, &len, sizeof(len)); - write(cl, contents, len); + if(contents) + write(cl, contents, len); break; } @@ -921,11 +951,11 @@ void sp_test(void) hash_t hmac; /* check inside range, but empty slot */ - struct version_info vi = sp_fileinfo(sp, 1, 12, 1, &hmac); + struct version_info vi = sp_fileinfo(sp, 1, 12, 1, &hmac, NULL); check("Authenticated denial 1", hash_equals(hmac, hmac_sha256(&vi, sizeof(vi), "a", 1))); /* check outside range */ - vi = sp_fileinfo(sp, 1, (1 << sp->iomt->mt_logleaves) + 1, 1, &hmac); + vi = sp_fileinfo(sp, 1, (1 << sp->iomt->mt_logleaves) + 1, 1, &hmac, NULL); check("Authenticated denial 2", hash_equals(hmac, hmac_sha256(&vi, sizeof(vi), "a", 1))); /* check in range */ @@ -933,14 +963,17 @@ void sp_test(void) 1, /* user */ 1, /* file */ 1, /* version */ - &hmac); + &hmac, + NULL); check("File info retrieval 1", hash_equals(hmac, hmac_sha256(&vi, sizeof(vi), "a", 1))); hash_t gamma = sha256("contents", 8); hash_t kf = hash_null; hash_t lambda = calc_lambda(gamma, buildcode, NULL, kf); - struct version_info correct = { 1, N_MODIFY + 1, 1, N_MODIFY, lambda }; + struct iomt_node acl_node = { 1, 1, u64_to_hash(3) }; + + struct version_info correct = { 1, N_MODIFY + 1, 1, N_MODIFY, hash_node(&acl_node), lambda }; check("File info retrieval 2", !memcmp(&correct, &vi, sizeof(vi))); } @@ -955,6 +988,7 @@ void sp_test(void) &key, NULL, NULL, + NULL, &len); check("File retrieval 1", !memcmp(contents, "contents", 8) && len == 8); free(contents); diff --git a/service_provider.h b/service_provider.h index f5fd4bc..1150dad 100644 --- a/service_provider.h +++ b/service_provider.h @@ -35,6 +35,7 @@ struct user_request { enum { USERREQ_NONE = 0, CREATE_FILE, MODIFY_FILE, MODIFY_ACL, RETRIEVE_INFO, RETRIEVE_FILE } type; uint64_t user_id; union { + uint64_t file_idx; struct { uint64_t file_idx; /* ACL IOMT will follow */ @@ -57,8 +58,8 @@ struct user_request { /* same structure for retrieve file and retrieve info */ uint64_t file_idx, version; /* service will respond with either version_info struct, - * plus HMAC, or file contents and key (which the client - * can verify themselves) */ + * the serialized ACL, and an HMAC, or file contents and + * key (which the client can verify themselves) */ } retrieve; }; } __attribute__((packed)); @@ -110,7 +111,8 @@ struct tm_request sp_modifyfile(struct service_provider *sp, struct version_info sp_fileinfo(struct service_provider *sp, uint64_t user_id, uint64_t file_idx, uint64_t version, - hash_t *hmac); + hash_t *hmac, + struct iomt **acl_out); /* Again, version=0 selects the latest version. */ void *sp_retrieve_file(struct service_provider *sp, @@ -118,6 +120,7 @@ void *sp_retrieve_file(struct service_provider *sp, uint64_t file_idx, uint64_t version, hash_t *encrypted_secret, + hash_t *kf, struct iomt **buildcode, struct iomt **composefile, size_t *len); |