diff options
author | Franklin Wei <me@fwei.tk> | 2018-07-06 22:34:04 -0400 |
---|---|---|
committer | Franklin Wei <me@fwei.tk> | 2018-07-06 22:34:04 -0400 |
commit | 3e7b74359f56c0518abcd420e85a5e3e778e8fd1 (patch) | |
tree | 26ace22aa872ffe4bc3fe26364991b04e1b104a8 | |
parent | fa2a0b2f0cf079695382020a8b418445dff0af97 (diff) | |
download | csaa-3e7b74359f56c0518abcd420e85a5e3e778e8fd1.zip csaa-3e7b74359f56c0518abcd420e85a5e3e778e8fd1.tar.gz csaa-3e7b74359f56c0518abcd420e85a5e3e778e8fd1.tar.bz2 csaa-3e7b74359f56c0518abcd420e85a5e3e778e8fd1.tar.xz |
Add nonce to version info response (to prevent replay); various code cleanup
Diffstat (limited to '')
-rw-r--r-- | client.c | 11 | ||||
-rw-r--r-- | crypto.c | 22 | ||||
-rw-r--r-- | crypto.h | 11 | ||||
-rw-r--r-- | iomt.c | 5 | ||||
-rw-r--r-- | service_provider.c | 73 | ||||
-rw-r--r-- | service_provider.h | 5 | ||||
-rw-r--r-- | trusted_module.c | 38 | ||||
-rw-r--r-- | trusted_module.h | 4 |
8 files changed, 89 insertions, 80 deletions
@@ -332,6 +332,8 @@ static struct tm_request verify_and_sign(int fd, const struct user_request *req, } break; } + /* TODO: check indices to prevent replay of old request and + * response (will require file info first) */ case MODIFY_FILE: { if(tmr.type != FILE_UPDATE || @@ -367,7 +369,7 @@ static bool verify_sp_ack(int fd, const struct tm_request *tmr) if(recv(fd, &hmac, sizeof(hmac), MSG_WAITALL) != sizeof(hmac)) return false; - return ack_verify(tmr, userkey, strlen(userkey), hmac); + return verify_ack(tmr, userkey, strlen(userkey), hmac); } /* In case of modifcation or file creation, returns true on successful @@ -445,7 +447,7 @@ bool exec_request(int fd, const struct user_request *req, recv(fd, &verinfo, sizeof(verinfo), MSG_WAITALL); recv(fd, &hmac, sizeof(hmac), MSG_WAITALL); - if(hash_equals(hmac, hmac_sha256(&verinfo, sizeof(verinfo), user_key, keylen))) + if(verify_verinfo(&verinfo, user_key, keylen, req->retrieve.nonce, hmac)) { if(verinfo.idx != 0) { @@ -641,6 +643,11 @@ bool server_request(const char *sockpath, } } } + else if(req.type == RETRIEVE_INFO) + { + /* RETRIEVE_FILE does not need a nonce */ + req.retrieve.nonce = generate_nonce(); + } struct version_info verinfo; struct tm_request tmreq; @@ -120,7 +120,7 @@ hash_t merkle_compute(hash_t node, const hash_t *comp, const int *orders, size_t * representation of a binary tree. */ uint64_t bintree_parent(uint64_t idx) { - return (idx - ((idx & 1) ? 1 : 2)) / 2; + return (idx - 1) / 2; } uint64_t bintree_sibling(uint64_t idx) @@ -399,7 +399,7 @@ void crypt_bytes(unsigned char *data, size_t len, hash_t key) /* 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) +hash_t sign_ack(const struct tm_request *req, int nzeros, const void *key, size_t keylen) { HMAC_CTX *ctx = HMAC_CTX_new(); #if OPENSSL_VERSION_NUMBER < 0x10100000L @@ -425,11 +425,25 @@ hash_t ack_sign(const struct tm_request *req, int nzeros, const void *key, size_ return hmac; } -bool ack_verify(const struct tm_request *req, +bool verify_ack(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); + hash_t correct = sign_ack(req, 1, secret, secret_len); + return hash_equals(hmac, correct); +} + +hash_t sign_verinfo(const struct version_info *verinfo, const void *key, size_t len) +{ + return hmac_sha256(verinfo, sizeof(*verinfo), key, len); +} + +bool verify_verinfo(const struct version_info *verinfo, const void *key, size_t len, hash_t nonce, hash_t hmac) +{ + if(!hash_equals(nonce, verinfo->nonce)) + return false; + + hash_t correct = sign_verinfo(verinfo, key, len); return hash_equals(hmac, correct); } @@ -72,16 +72,19 @@ hash_t calc_lambda(hash_t gamma, const struct iomt *buildcode, const struct iomt /* 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, +hash_t sign_ack(const struct tm_request *req, int nzeros, const void *key, size_t keylen); +bool verify_ack(const struct tm_request *req, const void *secret, size_t secret_len, hash_t hmac); -void write_to_fd(void *userdata, const void *data, size_t len); -int read_from_fd(void *userdata, void *buf, size_t len); +hash_t sign_verinfo(const struct version_info *verinfo, const void *key, size_t len); +bool verify_verinfo(const struct version_info *verinfo, const void *key, size_t len, hash_t nonce, hash_t hmac); void dump_versioninfo(const struct version_info *verinfo); +void write_to_fd(void *userdata, const void *data, size_t len); +int read_from_fd(void *userdata, void *buf, size_t len); + 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); @@ -11,7 +11,10 @@ hash_t hash_node(const struct iomt_node node) { - return sha256(&node, sizeof(node)); + if(node.idx != 0) + return sha256(&node, sizeof(node)); + else + return hash_null; } static void reset_and_bind(const struct iomt *tree, sqlite3_stmt *st) diff --git a/service_provider.c b/service_provider.c index d31e833..3bca02f 100644 --- a/service_provider.c +++ b/service_provider.c @@ -985,75 +985,33 @@ struct version_info sp_fileinfo(struct service_provider *sp, uint64_t user_id, uint64_t file_idx, uint64_t version, + hash_t nonce, hash_t *hmac, struct iomt **acl_out) { struct file_record *rec = lookup_record(sp, file_idx); + /* RV1 indicates counter */ + hash_t rv1_hmac; + struct tm_cert rv1 = cert_rv_by_idx(sp->tm, + sp->iomt, + file_idx, + &rv1_hmac); + /* Produce an authenticated denial proving that no file exists * with the given index. */ if(!rec) { - /* In theory, we would have to perform a linear search now to - * either find a placeholder node for this file index, or an - * enclosing node, both of which would prove that no file with - * the given index exists. However, we can cheat since we know - * that our IOMT is initialized with all the node indices - * falling densely into the range [1,2^logleaves]. If the - * index falls into this range, we can generate a RV - * certificate indicating that it has a zero counter value - * (and hence no associated file), or if it falls outside this - * range, by generating an RV certificate indicating the - * nonexistence of this node index. */ - struct tm_cert rv1; - hash_t rv1_hmac; - - if(1 <= file_idx && file_idx <= sp->iomt->mt_leafcount) - { - int *orders; - hash_t *comp = merkle_complement(sp->iomt, file_idx - 1, &orders); - - /* Placeholder exists. */ - rv1 = cert_rv(sp->tm, - iomt_getleaf(sp->iomt, file_idx - 1), - comp, orders, sp->iomt->mt_logleaves, - &rv1_hmac, - 0, NULL, NULL); - free(comp); - free(orders); - } - else - { - /* Use last node as encloser */ - int *orders; - hash_t *comp = merkle_complement(sp->iomt, sp->iomt->mt_leafcount - 1, &orders); - - cert_rv(sp->tm, - iomt_getleaf(sp->iomt, sp->iomt->mt_leafcount - 1), - comp, orders, sp->iomt->mt_logleaves, - NULL, - file_idx, &rv1, &rv1_hmac); - - free(comp); - free(orders); - } - return tm_verify_fileinfo(sp->tm, user_id, &rv1, rv1_hmac, NULL, hash_null, NULL, hash_null, NULL, hash_null, + nonce, hmac); } - /* RV1 indicates counter */ - hash_t rv1_hmac; - struct tm_cert rv1 = cert_rv_by_idx(sp->tm, - sp->iomt, - file_idx, - &rv1_hmac); - /* RV2 indicates access rights */ hash_t rv2_hmac; struct tm_cert rv2 = cert_rv_by_idx(sp->tm, @@ -1072,6 +1030,7 @@ struct version_info sp_fileinfo(struct service_provider *sp, &rv2, rv2_hmac, &rec->fr_cert, rec->fr_hmac, ver ? &ver->vr_cert : NULL, ver ? ver->vr_hmac : hash_null, + nonce, hmac); free_record(rec); free_version(ver); @@ -1253,6 +1212,7 @@ static void sp_handle_client(struct service_provider *sp, int cl) user_req.user_id, user_req.retrieve.file_idx, user_req.retrieve.version, + user_req.retrieve.nonce, &ack_hmac, &acl); write(cl, &verinfo, sizeof(verinfo)); @@ -1371,7 +1331,7 @@ void sp_test(void) hash_t 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)); + check("File creation", verify_ack(&req, "a", 1, ack_hmac)); /* IOMT generation from file */ struct iomt *buildcode = iomt_from_lines("container1/Dockerfile"); @@ -1391,15 +1351,15 @@ void sp_test(void) stop = clock(); printf("%.1f modifications per second\n", (double)N_MODIFY * CLOCKS_PER_SEC / (stop - start)); - check("File modification", ack_verify(&req, "a", 1, ack_hmac)); + check("File modification", verify_ack(&req, "a", 1, ack_hmac)); hash_t hmac; /* check inside range, but empty slot */ - struct version_info vi = sp_fileinfo(sp, 1, 12, 1, &hmac, NULL); + struct version_info vi = sp_fileinfo(sp, 1, 12, 1, hash_null, &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, NULL); + vi = sp_fileinfo(sp, 1, (1 << sp->iomt->mt_logleaves) + 1, 1, hash_null, &hmac, NULL); check("Authenticated denial 2", hash_equals(hmac, hmac_sha256(&vi, sizeof(vi), "a", 1))); /* check in range */ @@ -1407,6 +1367,7 @@ void sp_test(void) 1, /* user */ 1, /* file */ 1, /* version */ + hash_null, &hmac, NULL); check("File info retrieval 1", hash_equals(hmac, hmac_sha256(&vi, sizeof(vi), "a", 1))); @@ -1457,7 +1418,7 @@ void sp_test(void) newacl, &ack); - success &= ack_verify(&req, "a", 1, ack); + success &= verify_ack(&req, "a", 1, ack); } check("ACL modification 1", success); diff --git a/service_provider.h b/service_provider.h index 4dcb109..b64bc82 100644 --- a/service_provider.h +++ b/service_provider.h @@ -57,6 +57,10 @@ struct user_request { struct { /* same structure for retrieve file and retrieve info */ uint64_t file_idx, version; + + /* used only for RETRIEVE_INFO */ + hash_t nonce; + /* service will respond with either version_info struct, * the serialized ACL, and an HMAC, or file contents and * key (which the client can verify themselves) */ @@ -116,6 +120,7 @@ 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 nonce, hash_t *hmac, struct iomt **acl_out); diff --git a/trusted_module.c b/trusted_module.c index 2a5c61d..c59beb1 100644 --- a/trusted_module.c +++ b/trusted_module.c @@ -447,7 +447,7 @@ static bool req_verify(const struct trusted_module *tm, const struct tm_request static hash_t req_ack(const struct trusted_module *tm, const struct tm_request *req) { - return ack_sign(req, + return sign_ack(req, 1, tm->user_keys[req->user_id - 1].key, tm->user_keys[req->user_id - 1].len); @@ -841,13 +841,13 @@ hash_t tm_retrieve_secret(const struct trusted_module *tm, return hash_xor(secret, pad); } -static hash_t sign_verinfo(const struct trusted_module *tm, - const struct version_info *ver, - uint64_t user_id) +static hash_t tm_sign_verinfo(const struct trusted_module *tm, + const struct version_info *ver, + uint64_t user_id) { - return hmac_sha256(ver, sizeof(*ver), - tm->user_keys[user_id - 1].key, - tm->user_keys[user_id - 1].len); + return sign_verinfo(ver, + tm->user_keys[user_id - 1].key, + tm->user_keys[user_id - 1].len); } /* Verify the integrity of file information passed in the four @@ -867,10 +867,9 @@ struct version_info tm_verify_fileinfo(const struct trusted_module *tm, const struct tm_cert *rv2, hash_t rv2_hmac, const struct tm_cert *fr, hash_t fr_hmac, const struct tm_cert *vr, hash_t vr_hmac, + hash_t nonce, hash_t *response_hmac) { - struct version_info verinfo = verinfo_null; - /* No authenticated response if the parameters are incorrect or * improperly signed; it is the service provider's responsibility * to make sure these are correct, because if they are not, the @@ -903,8 +902,11 @@ struct version_info tm_verify_fileinfo(const struct trusted_module *tm, /* File does not exist; issue authenticated denial. */ if(is_zero(rv1->rv.val)) { + struct version_info verinfo = verinfo_null; + verinfo.nonce = nonce; + verinfo.idx = rv1->rv.idx; - *response_hmac = sign_verinfo(tm, &verinfo, user_id); + *response_hmac = tm_sign_verinfo(tm, &verinfo, user_id); return verinfo; } @@ -967,8 +969,12 @@ struct version_info tm_verify_fileinfo(const struct trusted_module *tm, /* insufficient access level; produce an authenticated denial * (which is indistinguishable from the response when a file * does not exist) */ + + struct version_info verinfo = verinfo_null; + verinfo.nonce = nonce; + verinfo.idx = fr->fr.idx; - *response_hmac = sign_verinfo(tm, &verinfo, user_id); + *response_hmac = tm_sign_verinfo(tm, &verinfo, user_id); return verinfo; } @@ -979,6 +985,9 @@ struct version_info tm_verify_fileinfo(const struct trusted_module *tm, { /* File has been created, but has no contents (and hence * no versions). We issue a response to this effect. */ + struct version_info verinfo; + verinfo.nonce = nonce; + verinfo.idx = fr->fr.idx; verinfo.counter = fr->fr.counter; verinfo.max_version = fr->fr.version; @@ -986,7 +995,7 @@ struct version_info tm_verify_fileinfo(const struct trusted_module *tm, verinfo.current_acl = fr->fr.acl; verinfo.lambda = hash_null; - *response_hmac = sign_verinfo(tm, &verinfo, user_id); + *response_hmac = tm_sign_verinfo(tm, &verinfo, user_id); return verinfo; } tm_seterror("null VR even though maxversion > 0"); @@ -1013,6 +1022,9 @@ struct version_info tm_verify_fileinfo(const struct trusted_module *tm, /* We have verified that this file version exists and can * authenticate its record. */ + struct version_info verinfo; + verinfo.nonce = nonce; + verinfo.idx = fr->fr.idx; verinfo.counter = fr->fr.counter; verinfo.max_version = fr->fr.version; @@ -1020,7 +1032,7 @@ struct version_info tm_verify_fileinfo(const struct trusted_module *tm, verinfo.current_acl = fr->fr.acl; verinfo.lambda = vr->vr.hash; - *response_hmac = sign_verinfo(tm, &verinfo, user_id); + *response_hmac = tm_sign_verinfo(tm, &verinfo, user_id); return verinfo; } diff --git a/trusted_module.h b/trusted_module.h index fe4fbc1..5a07c47 100644 --- a/trusted_module.h +++ b/trusted_module.h @@ -94,6 +94,9 @@ struct version_info { uint64_t version, max_version; hash_t current_acl; /* not version ACL */ hash_t lambda; /* equal to HMAC(h(encrypted_contents), key=HMAC(key, file_idx)) */ + + /* to prevent a replay attack */ + hash_t nonce; }; static const struct tm_request req_null = { REQ_NONE }; @@ -208,6 +211,7 @@ struct version_info tm_verify_fileinfo(const struct trusted_module *tm, const struct tm_cert *rv2, hash_t rv2_hmac, const struct tm_cert *fr, hash_t fr_hmac, const struct tm_cert *vr, hash_t vr_hmac, + hash_t nonce, hash_t *response_hmac); const char *tm_geterror(void); |