aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <me@fwei.tk>2018-07-06 22:34:04 -0400
committerFranklin Wei <me@fwei.tk>2018-07-06 22:34:04 -0400
commit3e7b74359f56c0518abcd420e85a5e3e778e8fd1 (patch)
tree26ace22aa872ffe4bc3fe26364991b04e1b104a8
parentfa2a0b2f0cf079695382020a8b418445dff0af97 (diff)
downloadcsaa-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.c11
-rw-r--r--crypto.c22
-rw-r--r--crypto.h11
-rw-r--r--iomt.c5
-rw-r--r--service_provider.c73
-rw-r--r--service_provider.h5
-rw-r--r--trusted_module.c38
-rw-r--r--trusted_module.h4
8 files changed, 89 insertions, 80 deletions
diff --git a/client.c b/client.c
index f6e0398..7df2868 100644
--- a/client.c
+++ b/client.c
@@ -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;
diff --git a/crypto.c b/crypto.c
index c965b1e..c8e2df7 100644
--- a/crypto.c
+++ b/crypto.c
@@ -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);
}
diff --git a/crypto.h b/crypto.h
index ed45730..2a6a0e0 100644
--- a/crypto.h
+++ b/crypto.h
@@ -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);
diff --git a/iomt.c b/iomt.c
index f79a0c4..d54102f 100644
--- a/iomt.c
+++ b/iomt.c
@@ -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);