aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client.c326
-rw-r--r--crypto.c107
-rw-r--r--crypto.h5
-rw-r--r--helper.c3
-rw-r--r--main.c5
-rw-r--r--service_provider.c64
-rw-r--r--service_provider.h9
7 files changed, 404 insertions, 115 deletions
diff --git a/client.c b/client.c
index d7a9b9e..278c8d1 100644
--- a/client.c
+++ b/client.c
@@ -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. */
diff --git a/crypto.c b/crypto.c
index 4eb1cfa..d14e52e 100644
--- a/crypto.c
+++ b/crypto.c
@@ -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. */
diff --git a/crypto.h b/crypto.h
index 0cc0710..fafdf18 100644
--- a/crypto.h
+++ b/crypto.h
@@ -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
diff --git a/helper.c b/helper.c
index 7f2abd7..e34e515 100644
--- a/helper.c
+++ b/helper.c
@@ -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,
diff --git a/main.c b/main.c
index 4363592..4dc2d9e 100644
--- a/main.c
+++ b/main.c
@@ -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);