diff options
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | client.c | 184 | ||||
-rw-r--r-- | crypto.c | 79 | ||||
-rw-r--r-- | crypto.h | 17 | ||||
-rw-r--r-- | helper.c | 18 | ||||
-rw-r--r-- | helper.h | 42 | ||||
-rw-r--r-- | main.c | 65 | ||||
-rw-r--r-- | service_provider.c | 184 | ||||
-rw-r--r-- | service_provider.h | 97 | ||||
-rw-r--r-- | test.c | 9 | ||||
-rw-r--r-- | test.h | 3 | ||||
-rw-r--r-- | trusted_module.c | 33 | ||||
-rw-r--r-- | trusted_module.h | 15 |
13 files changed, 628 insertions, 127 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9016ba1 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +all: client server Makefile +CFLAGS = -g -Wall + +client: client.o crypto.o test.o + cc -o $@ $^ -lcrypto $(CFLAGS) +server: service_provider.o crypto.o helper.o trusted_module.o main.o test.o + cc -o $@ $^ -lcrypto $(CFLAGS) +clean: + rm -f *.o a.out client server diff --git a/client.c b/client.c new file mode 100644 index 0000000..ba6066e --- /dev/null +++ b/client.c @@ -0,0 +1,184 @@ +/* Taken from + * https://github.com/troydhanson/network/blob/master/unixdomain/01.basic/cli.c */ + +#define CLIENT +#include "crypto.h" +#include "service_provider.h" +#include "trusted_module.h" +#include "test.h" + +#include <sys/socket.h> +#include <sys/un.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <assert.h> + +char *socket_path = "socket"; + +static bool need_sign(int reqtype) +{ + return reqtype == CREATE_FILE || reqtype == MODIFY_FILE || reqtype == MODIFY_ACL; +} + +static struct tm_request verify_and_sign(int fd, const struct user_request *req) +{ + struct tm_request tmr = req_null; + if(read(fd, &tmr, sizeof(tmr)) != sizeof(tmr)) + { + perror("read"); + exit(1); + } + + assert(tmr.type != REQ_NONE); + + switch(req->type) + { + case CREATE_FILE: + { + /* check request values to make sure they actually do what we + * want */ + struct iomt_node acl_node = { req->create.user_id, req->create.user_id, u64_to_hash(3) }; + if(tmr.type != ACL_UPDATE || + tmr.idx == 0 || + tmr.counter != 0 || + !hash_equals(hash_node(&acl_node), tmr.val)) + return req_null; + break; + } + case MODIFY_FILE: + { + /* TODO */ + break; + } + case MODIFY_ACL: + { + /* TODO */ + break; + } + } + + hash_t hmac = hmac_sha256(&tmr, sizeof(tmr), "a", 1); + write(fd, &hmac, sizeof(hmac)); + + return tmr; +} + +static bool verify_sp_ack(int fd, const struct tm_request *tmr) +{ + hash_t hmac = hash_null; + if(read(fd, &hmac, sizeof(hmac)) != sizeof(hmac)) + { + perror("read 2"); + exit(2); + } + + return ack_verify(tmr, "a", 1, hmac); +} + +void write_fd(void *userdata, const void *data, size_t len) +{ + int *fdptr = userdata; + write(*fdptr, data, len); +} + +bool exec_request(int fd, const struct user_request *req, + const struct iomt *new_acl, + const struct iomt *new_buildcode, + const struct iomt *new_composefile, + const void *file_contents, size_t len) +{ + write(fd, req, sizeof(*req)); + /* write additional data */ + switch(req->type) + { + case MODIFY_ACL: + /* send ACL */ + iomt_serialize(new_acl, write_fd, &fd); + break; + case MODIFY_FILE: + /* send build code, compose file, and file contents */ + iomt_serialize(new_buildcode, write_fd, &fd); + iomt_serialize(new_composefile, write_fd, &fd); + + /* prefix file with size */ + write(fd, &len, sizeof(len)); + write(fd, file_contents, len); + break; + case CREATE_FILE: + case RETRIEVE_INFO: + case RETRIEVE_FILE: + /* no additional data needed, fall through */ + default: + break; + } + + struct tm_request tmr; + + /* sign request */ + if(need_sign(req->type)) + { + /* read a tm_request from the file descriptor, and verify that + * it carries out the requested action, and then sign */ + tmr = verify_and_sign(fd, req); + } + + /* verify acknowledgement */ + return verify_sp_ack(fd, &tmr); +} + +int connect_to_service(const char *sockpath) +{ + struct sockaddr_un addr; + int fd; + + if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("socket error"); + exit(-1); + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + if (*socket_path == '\0') { + *addr.sun_path = '\0'; + strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2); + } else { + strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1); + } + + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + perror("connect error"); + exit(-1); + } + + return fd; +} + +int main(int argc, char *argv[]) { + char buf[100]; + int fd,rc; + + if (argc > 1) socket_path=argv[1]; + + fd = connect_to_service(socket_path); + + struct user_request req; + req.type = CREATE_FILE; + req.create.user_id = 1; + + check("Client file creation", exec_request(fd, &req, NULL, NULL, NULL, NULL, 0)); + close(fd); + fd = connect_to_service(socket_path); + + req.type = MODIFY_FILE; + req.modify_file.user_id = 1; + req.modify_file.file_idx = 1; + req.modify_file.encrypted_secret = hash_null; + req.modify_file.kf = hash_null; + + check("Client file modification", exec_request(fd, &req, NULL, NULL, NULL, "contents", 8)); + close(fd); + + return 0; +} @@ -1,4 +1,5 @@ #include "crypto.h" +#include "trusted_module.h" #include "test.h" #include <string.h> @@ -374,6 +375,51 @@ struct iomt *iomt_dup(const struct iomt *tree) return newtree; } +/* TODO: error checking */ +uint64_t read_u64(int (*read_fn)(void *userdata, void *buf, size_t len), void *userdata) +{ + uint64_t n; + read_fn(userdata, &n, sizeof(n)); + return n; +} + +void write_u64(void (*write_fn)(void *userdata, const void *data, size_t len), + void *userdata, uint64_t n) +{ + write_fn(userdata, &n, sizeof(n)); +} + + +void iomt_serialize(const struct iomt *tree, + void (*write_fn)(void *userdata, const void *data, size_t len), + void *userdata) +{ + /* leafcount isn't needed */ + if(tree) + { + write_u64(write_fn, userdata, tree->mt_logleaves); + + write_fn(userdata, tree->mt_nodes, sizeof(hash_t) * (2 * tree->mt_leafcount - 1)); + write_fn(userdata, tree->mt_leaves, sizeof(struct iomt_node) * tree->mt_leafcount); + } + else + write_u64(write_fn, userdata, 0); +} + +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) + return NULL; + struct iomt *tree = iomt_new(logleaves); + + read_fn(userdata, tree->mt_nodes, sizeof(hash_t) * (2 * tree->mt_leafcount - 1)); + read_fn(userdata, tree->mt_leaves, sizeof(struct iomt_node) * tree->mt_leafcount); + + return tree; +} + void iomt_free(struct iomt *tree) { if(tree) @@ -522,8 +568,40 @@ hash_t calc_lambda(hash_t gamma, const struct iomt *buildcode, const struct iomt return h; } +/* Generate a signed acknowledgement for successful completion of a + * request. We append a zero byte to the user request and take the + * HMAC. */ +hash_t ack_sign(const struct tm_request *req, int nzeros, const void *key, size_t keylen) +{ + HMAC_CTX *ctx = HMAC_CTX_new(); + HMAC_Init_ex(ctx, + key, keylen, + EVP_sha256(), NULL); + + HMAC_Update(ctx, (const unsigned char*)req, sizeof(*req)); + + unsigned char zero = 0; + for(int i = 0; i < nzeros; ++i) + HMAC_Update(ctx, &zero, 1); + + hash_t hmac; + HMAC_Final(ctx, hmac.hash, NULL); + HMAC_CTX_free(ctx); + + return hmac; +} + +bool ack_verify(const struct tm_request *req, + const void *secret, size_t secret_len, + hash_t hmac) +{ + hash_t correct = ack_sign(req, 1, secret, secret_len); + return hash_equals(hmac, correct); +} + void crypto_test(void) { +#if 1 int *orders; int *comp = bintree_complement(6, 4, &orders); int correct[] = { 22, 9, 3, 2 }; @@ -570,4 +648,5 @@ void crypto_test(void) //dump_hash(root2); check("Merkle compute", hash_equals(root1, root2)); } +#endif } @@ -4,6 +4,8 @@ #include <stddef.h> #include <stdint.h> +struct tm_request; + /* Various useful cryptographic functions; shared between TM and SP. */ /* we use SHA256 for h() */ @@ -105,6 +107,13 @@ void iomt_update_leaf_hash(struct iomt *tree, uint64_t leafidx, /* Create an IOMT where the leaves are the hash of file lines */ struct iomt *iomt_from_lines(const char *filename); +void iomt_serialize(const struct iomt *tree, + void (*write_fn)(void *userdata, const void *data, size_t len), + void *userdata); + +struct iomt *iomt_deserialize(int (*read_fn)(void *userdata, void *buf, size_t len), + void *userdata); + void iomt_fill(struct iomt *tree); void iomt_dump(const struct iomt *tree); @@ -132,6 +141,14 @@ hash_t crypt_secret(hash_t encrypted_secret, hash_t calc_lambda(hash_t gamma, const struct iomt *buildcode, const struct iomt *composefile, hash_t kf); +/* Generate a signed acknowledgement for successful completion of a + * request. We append a zero byte to the user request and take the + * HMAC. */ +hash_t ack_sign(const struct tm_request *req, int nzeros, const void *key, size_t keylen); +bool ack_verify(const struct tm_request *req, + const void *secret, size_t secret_len, + hash_t hmac); + /* self-test */ void crypto_test(void); #endif @@ -90,16 +90,16 @@ struct tm_cert cert_rv_by_idx(const struct trusted_module *tm, return cert; } -/* Fill out a user_request struct to create a file with the index +/* Fill out a tm_request struct to create a file with the index * given in file_node->idx with the user added with level 3 access in * the ACL. */ -struct user_request req_filecreate(const struct trusted_module *tm, +struct tm_request req_filecreate(const struct trusted_module *tm, uint64_t user_id, const struct iomt_node *file_node, const hash_t *file_comp, const int *file_orders, size_t file_n) { /* construct a request to create a file */ - struct user_request req = req_null; + struct tm_request req = req_null; req.idx = file_node->idx; req.user_id = user_id; req.type = ACL_UPDATE; @@ -127,10 +127,10 @@ struct user_request req_filecreate(const struct trusted_module *tm, return req; } -/* Fill out a user_request struct to modify an existing file's +/* Fill out a tm_request struct to modify an existing file's * contents, given the previously generated FR certificate, and the * ACL node giving the user's access rights. */ -struct user_request req_filemodify(const struct trusted_module *tm, +struct tm_request req_filemodify(const struct trusted_module *tm, const struct tm_cert *fr_cert, hash_t fr_hmac, const struct iomt_node *file_node, const hash_t *file_comp, const int *file_orders, size_t file_n, @@ -139,7 +139,7 @@ struct user_request req_filemodify(const struct trusted_module *tm, hash_t fileval) { /* modification */ - struct user_request req = req_null; + struct tm_request req = req_null; req.type = FILE_UPDATE; req.idx = file_node->idx; @@ -166,10 +166,10 @@ struct user_request req_filemodify(const struct trusted_module *tm, return req; } -/* Fill out a user_request struct to modify a file's ACL. Same +/* Fill out a tm_request struct to modify a file's ACL. Same * parameters as req_filemodify(), except the hash is the root of the * new ACL. */ -struct user_request req_aclmodify(const struct trusted_module *tm, +struct tm_request req_aclmodify(const struct trusted_module *tm, const struct tm_cert *fr_cert, hash_t fr_hmac, const struct iomt_node *file_node, const hash_t *file_comp, const int *file_orders, size_t file_n, @@ -177,7 +177,7 @@ struct user_request req_aclmodify(const struct trusted_module *tm, const hash_t *oldacl_comp, const int *oldacl_orders, size_t oldacl_n, hash_t newacl_root) { - struct user_request req = req_null; + struct tm_request req = req_null; req.type = ACL_UPDATE; req.idx = file_node->idx; @@ -21,32 +21,32 @@ struct tm_cert cert_rv_by_idx(const struct trusted_module *tm, uint64_t idx, hash_t *hmac_out); -/* Fill out a user_request struct to create a file with the index +/* Fill out a tm_request struct to create a file with the index * given in file_node->idx with the user added with level 3 access in * the ACL. */ -struct user_request req_filecreate(const struct trusted_module *tm, - uint64_t user_id, - const struct iomt_node *file_node, - const hash_t *file_comp, const int *file_orders, size_t file_n); +struct tm_request req_filecreate(const struct trusted_module *tm, + uint64_t user_id, + const struct iomt_node *file_node, + const hash_t *file_comp, const int *file_orders, size_t file_n); -/* Fill out a user_request struct to modify an existing file's +/* Fill out a tm_request struct to modify an existing file's * contents, given the previously generated FR certificate, and the * ACL node giving the user's access rights. */ -struct user_request req_filemodify(const struct trusted_module *tm, - const struct tm_cert *fr_cert, hash_t fr_hmac, - const struct iomt_node *file_node, - const hash_t *file_comp, const int *file_orders, size_t file_n, - const struct iomt_node *acl_node, - const hash_t *acl_comp, const int *acl_orders, size_t acl_n, - hash_t fileval); +struct tm_request req_filemodify(const struct trusted_module *tm, + const struct tm_cert *fr_cert, hash_t fr_hmac, + const struct iomt_node *file_node, + const hash_t *file_comp, const int *file_orders, size_t file_n, + const struct iomt_node *acl_node, + const hash_t *acl_comp, const int *acl_orders, size_t acl_n, + hash_t fileval); -/* Fill out a user_request struct to modify a file's ACL. Same +/* Fill out a tm_request struct to modify a file's ACL. Same * parameters as req_filemodify(), except the hash is the root of the * new ACL. */ -struct user_request req_aclmodify(const struct trusted_module *tm, - const struct tm_cert *fr_cert, hash_t fr_hmac, - const struct iomt_node *file_node, - const hash_t *file_comp, const int *file_orders, size_t file_n, - const struct iomt_node *oldacl_node, - const hash_t *oldacl_comp, const int *oldacl_orders, size_t oldacl_n, - hash_t newacl_root); +struct tm_request req_aclmodify(const struct trusted_module *tm, + const struct tm_cert *fr_cert, hash_t fr_hmac, + const struct iomt_node *file_node, + const hash_t *file_comp, const int *file_orders, size_t file_n, + const struct iomt_node *oldacl_node, + const hash_t *oldacl_comp, const int *oldacl_orders, size_t oldacl_n, + hash_t newacl_root); @@ -0,0 +1,65 @@ +#include "service_provider.h" +#include "test.h" + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +int bind_unix_socket(const char *fname) +{ + int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, fname, sizeof(addr.sun_path) - 1); + if(bind(sockfd, (struct sockaddr*) &addr, sizeof(addr)) < 0) + return -1; + + return sockfd; +} + +static const char *cleanup_socket = NULL; +void cleanup(void) +{ + if(cleanup_socket) + unlink(cleanup_socket); +} + +void sigint(int sig) +{ + cleanup(); + exit(1); +} + +void run_tests(void) +{ + crypto_test(); + tm_test(); + sp_test(); +} + +int main() +{ + run_tests(); + + const char *socket_name = "socket"; + int sockfd; + if((sockfd = bind_unix_socket(socket_name)) < 0) + { + perror("bind"); + return 1; + } + + cleanup_socket = socket_name; + + atexit(cleanup); + signal(SIGINT, sigint); + + sp_main(sockfd); +} diff --git a/service_provider.c b/service_provider.c index 421d377..5dc033b 100644 --- a/service_provider.c +++ b/service_provider.c @@ -5,6 +5,10 @@ #include <stdlib.h> #include <string.h> #include <stdio.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/socket.h> #include "crypto.h" #include "helper.h" @@ -237,7 +241,7 @@ static void append_version(struct file_record *rec, const struct file_version *v } /* This does the majority of the work that actually modifies or - * creates a file. It expects a filled and signed user_request + * creates a file. It expects a filled and signed tm_request * structure, req, and will return the resulting FR certificate and * its signature in *hmac_out. Additionally, the module's * authenticated acknowledgement (equal to HMAC(req | 0), where | @@ -254,7 +258,7 @@ static void append_version(struct file_record *rec, const struct file_version *v * is essentially an ACL update), the ACL will be set to * new_acl. `new_acl' must be in persistent storage. */ struct tm_cert sp_request(struct service_provider *sp, - const struct user_request *req, hash_t req_hmac, + const struct tm_request *req, hash_t req_hmac, hash_t *hmac_out, struct tm_cert *vr_out, hash_t *vr_hmac_out, hash_t *ack_hmac_out, @@ -368,9 +372,11 @@ struct tm_cert sp_request(struct service_provider *sp, return fr; } -struct user_request sp_createfile(struct service_provider *sp, - uint64_t user_id, const void *key, size_t keylen, - hash_t *ack_hmac) +struct tm_request sp_createfile(struct service_provider *sp, + uint64_t user_id, + hash_t (*sign_request)(void *userdata, const struct tm_request *req), + void *userdata, + hash_t *ack_hmac) { int i; @@ -395,12 +401,12 @@ struct user_request sp_createfile(struct service_provider *sp, 0, user_id, user_id, u64_to_hash(3)); - struct user_request req = req_filecreate(sp->tm, + struct tm_request req = req_filecreate(sp->tm, i + 1, sp->iomt->mt_leaves + i, file_comp, file_orders, sp->iomt->mt_logleaves); - hash_t req_hmac = hmac_sha256(&req, sizeof(req), key, keylen); + hash_t req_hmac = sign_request(userdata, &req); hash_t fr_hmac; struct tm_cert fr_cert = sp_request(sp, @@ -424,11 +430,13 @@ struct user_request sp_createfile(struct service_provider *sp, } /* Expects ACL root to already be calculated */ -struct user_request sp_modifyacl(struct service_provider *sp, - uint64_t user_id, const void *key, size_t keylen, - uint64_t file_idx, - struct iomt *new_acl, - hash_t *ack_hmac) +struct tm_request sp_modifyacl(struct service_provider *sp, + uint64_t user_id, + hash_t (*sign_request)(void *userdata, const struct tm_request *req), + void *userdata, + uint64_t file_idx, + struct iomt *new_acl, + hash_t *ack_hmac) { /* modification */ struct file_record *rec = lookup_record(sp, file_idx); @@ -447,7 +455,7 @@ struct user_request sp_modifyacl(struct service_provider *sp, acl_node - rec->acl->mt_leaves, &acl_orders); - struct user_request req = req_aclmodify(sp->tm, + struct tm_request req = req_aclmodify(sp->tm, &rec->fr_cert, rec->fr_hmac, file_node, file_comp, file_orders, sp->iomt->mt_logleaves, @@ -460,7 +468,7 @@ struct user_request sp_modifyacl(struct service_provider *sp, free(acl_comp); free(acl_orders); - hash_t req_hmac = hmac_sha256(&req, sizeof(req), key, keylen); + hash_t req_hmac = sign_request(userdata, &req); struct tm_cert new_fr = sp_request(sp, &req, req_hmac, @@ -477,13 +485,15 @@ struct user_request sp_modifyacl(struct service_provider *sp, return req_null; } -struct user_request sp_modifyfile(struct service_provider *sp, - uint64_t user_id, const void *key, size_t keylen, - uint64_t file_idx, - hash_t encrypted_secret, hash_t kf, - const struct iomt *buildcode, const struct iomt *composefile, - const void *encrypted_file, size_t filelen, - hash_t *ack_hmac) +struct tm_request sp_modifyfile(struct service_provider *sp, + uint64_t user_id, + hash_t (*sign_request)(void *userdata, const struct tm_request *req), + void *userdata, + uint64_t file_idx, + hash_t encrypted_secret, hash_t kf, + const struct iomt *buildcode, const struct iomt *composefile, + const void *encrypted_file, size_t filelen, + hash_t *ack_hmac) { /* modification */ struct file_record *rec = lookup_record(sp, file_idx); @@ -505,7 +515,7 @@ struct user_request sp_modifyfile(struct service_provider *sp, hash_t gamma = sha256(encrypted_file, filelen); hash_t lambda = calc_lambda(gamma, buildcode, composefile, kf); - struct user_request req = req_filemodify(sp->tm, + struct tm_request req = req_filemodify(sp->tm, &rec->fr_cert, rec->fr_hmac, file_node, file_comp, file_orders, sp->iomt->mt_logleaves, @@ -517,7 +527,7 @@ struct user_request sp_modifyfile(struct service_provider *sp, free(file_orders); free(acl_orders); - hash_t req_hmac = hmac_sha256(&req, sizeof(req), key, keylen); + hash_t req_hmac = sign_request(userdata, &req); struct tm_cert vr; hash_t vr_hmac, fr_hmac; @@ -539,14 +549,6 @@ struct user_request sp_modifyfile(struct service_provider *sp, return req_null; } -static bool ack_verify(const struct user_request *req, - const void *secret, size_t secret_len, - hash_t hmac) -{ - hash_t correct = ack_sign(req, 1, secret, secret_len); - return hash_equals(hmac, correct); -} - /* Retrieve authenticated information (using the user's secret as the * key) on a version of a file; if version is zero, default to the * latest version. If the file does not exist, the function will still @@ -701,8 +703,113 @@ void *sp_retrieve_file(struct service_provider *sp, return ret; } +static hash_t get_client_signature(void *userdata, const struct tm_request *req) +{ + int *fd = userdata; + write(*fd, req, sizeof(*req)); + + hash_t hmac; + read(*fd, &hmac, sizeof(hmac)); + return hmac; +} + +int read_fd(void *userdata, void *buf, size_t len) +{ + int *fdptr = userdata; + return read(*fdptr, buf, len); +} + +static void sp_handle_client(struct service_provider *sp, int cl) +{ + /* We should probably fork() here to avoid blocking */ + struct user_request user_req; + if(read(cl, &user_req, sizeof(user_req)) != sizeof(user_req)) + return; + + hash_t ack_hmac = hash_null; + + switch(user_req.type) + { + case CREATE_FILE: + sp_createfile(sp, user_req.create.user_id, get_client_signature, &cl, &ack_hmac); + break; + case MODIFY_ACL: + { + struct iomt *acl = iomt_deserialize(read_fd, &cl); + sp_modifyacl(sp, + user_req.modify_acl.user_id, + get_client_signature, + &cl, + user_req.modify_acl.file_idx, + acl, + &ack_hmac); + iomt_free(acl); + break; + } + case MODIFY_FILE: + { + struct iomt *buildcode = iomt_deserialize(read_fd, &cl); + struct iomt *composefile = iomt_deserialize(read_fd, &cl); + size_t filelen; + read(cl, &filelen, sizeof(filelen)); + void *filebuf = malloc(filelen); + read(cl, filebuf, filelen); + + sp_modifyfile(sp, + user_req.modify_file.user_id, + get_client_signature, + &cl, + user_req.modify_file.file_idx, + user_req.modify_file.encrypted_secret, + user_req.modify_file.kf, + buildcode, + composefile, + filebuf, filelen, + &ack_hmac); + iomt_free(buildcode); + iomt_free(composefile); + } + } + + write(cl, &ack_hmac, sizeof(ack_hmac)); +} + +int sp_main(int sockfd) +{ +#define BACKLOG 10 + + if(listen(sockfd, BACKLOG) < 0) + { + perror("listen"); + return 1; + } + + int logleaves = 8; + struct service_provider *sp = sp_new("a", 1, logleaves); + + while(1) + { + int cl; + + if((cl = accept(sockfd, NULL, NULL)) < 0) + { + perror("accept"); + return 1; + } + + sp_handle_client(sp, cl); + close(cl); + } +} + #include <time.h> +static hash_t test_sign_request(void *userdata, const struct tm_request *req) +{ + const char *str = userdata; + return hmac_sha256(req, sizeof(*req), str, strlen(str)); +} + void sp_test(void) { int logleaves = 5; @@ -717,7 +824,7 @@ void sp_test(void) { hash_t ack_hmac; - struct user_request req = sp_createfile(sp, 1, "a", 1, &ack_hmac); + struct tm_request req = sp_createfile(sp, 1, test_sign_request, "a", &ack_hmac); check("File creation", ack_verify(&req, "a", 1, ack_hmac)); @@ -734,7 +841,7 @@ void sp_test(void) #define N_MODIFY 100 start = clock(); for(int i = 0; i < N_MODIFY; ++i) - req = sp_modifyfile(sp, 1, "a", 1, 1, hash_null, hash_null, buildcode, NULL, "contents", 8, &ack_hmac); + req = sp_modifyfile(sp, 1, test_sign_request, "a", 1, hash_null, hash_null, buildcode, NULL, "contents", 8, &ack_hmac); stop = clock(); printf("%.1f modifications per second\n", (double)N_MODIFY * CLOCKS_PER_SEC / (stop - start)); @@ -792,11 +899,12 @@ void sp_test(void) #define N_ACLMODIFY 100 for(int i = 0; i < 100; ++i) { - struct user_request req = sp_modifyacl(sp, - 1, "a", 1, - 1, - newacl, - &ack); + struct tm_request req = sp_modifyacl(sp, + 1, + test_sign_request, "a", + 1, + newacl, + &ack); success &= ack_verify(&req, "a", 1, ack); } diff --git a/service_provider.h b/service_provider.h index 3399cb4..b55285c 100644 --- a/service_provider.h +++ b/service_provider.h @@ -9,12 +9,64 @@ struct service_provider; +/* Client-service protocol: */ + +/* 1. Client sends user_request to service. + * + * 2. Client sends additional data to service, if needed. + * + * 3. Service sends filled tm_request to client for signature. + * + * 4. Client verifies that the tm_request is appropriate. + * + * 5. Client sends HMAC(tm_request, user key) to service. + * + * 6. Service performs action. + * + * 7. Service sends module's authenticated acknowledgement (and + * response, in the case of RETRIEVE_INFO) to client. + * + * 8. Client verifies acknowledgement against earlier tm_request or + * response. + */ + +/* request from the client to the service */ +struct user_request { + enum { CREATE_FILE, MODIFY_FILE, MODIFY_ACL, RETRIEVE_INFO, RETRIEVE_FILE } type; + union { + struct { + uint64_t user_id; + } create; + struct { + uint64_t user_id, file_idx; + /* ACL IOMT will follow */ + } modify_acl; + struct { + uint64_t user_id, file_idx; + hash_t encrypted_secret, kf; + /* file contents, build code IOMT, and compose file IOMT + * will follow */ + + /* will respond with module's HMAC of tm_request struct + * plus a zero byte */ + } modify_file; + struct { + /* same structure for retrieve file and retrieve info */ + uint64_t user_id, file_idx, version; + /* will respond with either version_info struct, plus + * HMAC, or file contents and key (which the client can + * verify themselves) */ + } retrieve; + }; +} __attribute__((packed)); + +#ifndef CLIENT struct service_provider *sp_new(const void *key, size_t keylen, int logleaves); void sp_free(struct service_provider *sp); /* see .c file for documentation */ struct tm_cert sp_request(struct service_provider *sp, - const struct user_request *req, hash_t req_hmac, + const struct tm_request *req, hash_t req_hmac, hash_t *hmac_out, struct tm_cert *vr_out, hash_t *vr_hmac_out, hash_t *ack_hmac_out, @@ -26,23 +78,29 @@ struct tm_cert sp_request(struct service_provider *sp, /* Reserve a new file index with user_id added to the ACL. Returns * cert on failure. Authenticated with ack_hmac, which is the returned * request with a zero byte appended, signed by the module. */ -struct user_request sp_createfile(struct service_provider *sp, - uint64_t user_id, const void *key, size_t keylen, - hash_t *ack_hmac); - -struct user_request sp_modifyacl(struct service_provider *sp, - uint64_t user_id, const void *key, size_t keylen, - uint64_t file_idx, - struct iomt *new_acl, - hash_t *ack_hmac); - -struct user_request sp_modifyfile(struct service_provider *sp, - uint64_t user_id, const void *key, size_t keylen, - uint64_t file_idx, - hash_t encrypted_secret, hash_t kf, - const struct iomt *buildcode, const struct iomt *composefile, - const void *encrypted_file, size_t filelen, - hash_t *ack_hmac); +struct tm_request sp_createfile(struct service_provider *sp, + uint64_t user_id, + hash_t (*sign_request)(void *userdata, const struct tm_request *req), + void *userdata, + hash_t *ack_hmac); + +struct tm_request sp_modifyacl(struct service_provider *sp, + uint64_t user_id, + hash_t (*sign_request)(void *userdata, const struct tm_request *req), + void *userdata, + uint64_t file_idx, + struct iomt *new_acl, + hash_t *ack_hmac); + +struct tm_request sp_modifyfile(struct service_provider *sp, + uint64_t user_id, + hash_t (*sign_request)(void *userdata, const struct tm_request *req), + void *userdata, + uint64_t file_idx, + hash_t encrypted_secret, hash_t kf, + const struct iomt *buildcode, const struct iomt *composefile, + const void *encrypted_file, size_t filelen, + hash_t *ack_hmac); /* Retrieve authenticated information on a version of a file; if * version is zero, default to the latest version. */ @@ -59,6 +117,9 @@ void *sp_retrieve_file(struct service_provider *sp, hash_t *encrypted_secret, size_t *len); +int sp_main(int sockfd); + void sp_test(void); +#endif #endif @@ -6,16 +6,11 @@ void check(const char *name, int condition) { printf("%s: %s", name, condition ? "\033[32;1mPASS\033[0m\n" : "\033[31;1mFAIL\033[0m\n"); +#if 0 if(!condition) { printf("%s\n", tm_geterror()); tm_seterror(NULL); } -} - -int main() -{ - crypto_test(); - tm_test(); - sp_test(); +#endif } @@ -1,2 +1,5 @@ /* testing */ void check(const char *name, int condition); + +/* in main.c */ +void run_tests(void); diff --git a/trusted_module.c b/trusted_module.c index 7ebd716..2c021e3 100644 --- a/trusted_module.c +++ b/trusted_module.c @@ -386,13 +386,13 @@ bool tm_set_equiv_root(struct trusted_module *tm, } /* user id is 1-indexed */ -static hash_t req_sign(const struct trusted_module *tm, const struct user_request *req, int id) +static hash_t req_sign(const struct trusted_module *tm, const struct tm_request *req, int id) { return hmac_sha256(req, sizeof(*req), tm->user_keys[id - 1].key, tm->user_keys[id - 1].len); } /* verify HMAC of user request */ -static bool req_verify(const struct trusted_module *tm, const struct user_request *req, uint64_t id, hash_t hmac) +static bool req_verify(const struct trusted_module *tm, const struct tm_request *req, uint64_t id, hash_t hmac) { if(id < 1 || id >= tm->n_users + 1) return false; @@ -400,30 +400,7 @@ static bool req_verify(const struct trusted_module *tm, const struct user_reques return hash_equals(calculated, hmac); } -/* Generate a signed acknowledgement for successful completion of a - * request. We append a zero byte to the user request and take the - * HMAC. */ -hash_t ack_sign(const struct user_request *req, int nzeros, const void *key, size_t keylen) -{ - HMAC_CTX *ctx = HMAC_CTX_new(); - HMAC_Init_ex(ctx, - key, keylen, - EVP_sha256(), NULL); - - HMAC_Update(ctx, (const unsigned char*)req, sizeof(*req)); - - unsigned char zero = 0; - for(int i = 0; i < nzeros; ++i) - HMAC_Update(ctx, &zero, 1); - - hash_t hmac; - HMAC_Final(ctx, hmac.hash, NULL); - HMAC_CTX_free(ctx); - - return hmac; -} - -static hash_t req_ack(const struct trusted_module *tm, const struct user_request *req) +static hash_t req_ack(const struct trusted_module *tm, const struct tm_request *req) { return ack_sign(req, 1, @@ -435,7 +412,7 @@ static hash_t req_ack(const struct trusted_module *tm, const struct user_request /* * This function handles all transformations on the IOMT except * inserting a placeholder (handled above). The function takes its - * parameter in the form of a user_request struct, which must be + * parameter in the form of a tm_request struct, which must be * authenticated or else the function will fail. When a request is * successfully completed, *ack_hmac will be updated to the value * HMAC(<request> + 1, K), where + denotes concatenation, and K is the @@ -483,7 +460,7 @@ static hash_t req_ack(const struct trusted_module *tm, const struct user_request * be updated to reflect the incremented file counter. */ struct tm_cert tm_request(struct trusted_module *tm, - const struct user_request *req, hash_t req_hmac, + const struct tm_request *req, hash_t req_hmac, hash_t *hmac_out, struct tm_cert *vr_out, hash_t *vr_hmac, hash_t *hmac_ack) diff --git a/trusted_module.h b/trusted_module.h index f78d5f2..7e1cd4b 100644 --- a/trusted_module.h +++ b/trusted_module.h @@ -8,7 +8,7 @@ #include "crypto.h" struct trusted_module; -struct user_request; +struct tm_request; struct tm_cert { enum { CERT_NONE = 0, NU, EQ, RV, RU, FR, VR } type; @@ -50,7 +50,7 @@ struct tm_cert { }; }; -struct user_request { +struct tm_request { uint64_t idx; /* file index */ uint64_t user_id; /* user id */ enum { REQ_NONE = 0, ACL_UPDATE, FILE_UPDATE } type; @@ -94,10 +94,12 @@ struct version_info { hash_t lambda; /* equal to HMAC(h(encrypted_contents), key=HMAC(key, file_idx)) */ }; -static const struct user_request req_null = { REQ_NONE }; +static const struct tm_request req_null = { REQ_NONE }; static const struct tm_cert cert_null = { CERT_NONE }; static const struct version_info verinfo_null = { 0 }; +#ifndef CLIENT + /* creates 1 user with given shared secret */ struct trusted_module *tm_new(const void *key, size_t keylen); void tm_free(struct trusted_module *tm); @@ -164,7 +166,7 @@ bool tm_set_equiv_root(struct trusted_module *tm, /* process a user's request to transform the IOMT in some way */ struct tm_cert tm_request(struct trusted_module *tm, - const struct user_request *req, hash_t req_hmac, + const struct tm_request *req, hash_t req_hmac, hash_t *hmac_out, struct tm_cert *vr_out, hash_t *vr_hmac, hash_t *ack_hmac); @@ -203,9 +205,10 @@ struct version_info tm_verify_file(const struct trusted_module *tm, const struct tm_cert *vr, hash_t vr_hmac, hash_t *response_hmac); -hash_t ack_sign(const struct user_request *req, int nzeros, const void *key, size_t keylen); - const char *tm_geterror(void); void tm_seterror(const char *error); + +#endif + #endif |