236 lines
7.3 KiB
C
236 lines
7.3 KiB
C
|
|
#include "amduat/bytestore.h"
|
||
|
|
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
static const char k_amduat_bytestore_domain_sep[] = "CAS:OBJ\0";
|
||
|
|
|
||
|
|
static bool amduat_bytestore_trim_trailing_slash(const char *input,
|
||
|
|
size_t *out_len) {
|
||
|
|
size_t len;
|
||
|
|
|
||
|
|
if (input == NULL || out_len == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
len = strlen(input);
|
||
|
|
while (len > 1u && input[len - 1u] == '/') {
|
||
|
|
len--;
|
||
|
|
}
|
||
|
|
*out_len = len;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool amduat_bytestore_path_is_prefix(const char *parent,
|
||
|
|
size_t parent_len,
|
||
|
|
const char *child,
|
||
|
|
size_t child_len) {
|
||
|
|
if (parent_len == 0u || child_len == 0u) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (child_len < parent_len) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (memcmp(parent, child, parent_len) != 0) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (child_len == parent_len) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return child[parent_len] == '/';
|
||
|
|
}
|
||
|
|
|
||
|
|
void amduat_bytestore_init(amduat_bytestore_t *store,
|
||
|
|
amduat_bytestore_config_t config,
|
||
|
|
amduat_bytestore_ops_t ops,
|
||
|
|
void *ctx) {
|
||
|
|
if (store == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
store->config = config;
|
||
|
|
store->ops = ops;
|
||
|
|
store->ctx = ctx;
|
||
|
|
}
|
||
|
|
|
||
|
|
amduat_bytestore_error_t amduat_bytestore_put(amduat_bytestore_t *store,
|
||
|
|
amduat_octets_t payload,
|
||
|
|
amduat_reference_t *out_cid) {
|
||
|
|
if (store == NULL || store->ops.put == NULL) {
|
||
|
|
return AMDUAT_BYTESTORE_ERR_UNSUPPORTED;
|
||
|
|
}
|
||
|
|
return store->ops.put(store->ctx, payload, out_cid);
|
||
|
|
}
|
||
|
|
|
||
|
|
amduat_bytestore_error_t amduat_bytestore_put_stream(
|
||
|
|
amduat_bytestore_t *store,
|
||
|
|
amduat_bytestore_stream_t stream,
|
||
|
|
amduat_reference_t *out_cid) {
|
||
|
|
if (store == NULL || store->ops.put_stream == NULL) {
|
||
|
|
return AMDUAT_BYTESTORE_ERR_UNSUPPORTED;
|
||
|
|
}
|
||
|
|
return store->ops.put_stream(store->ctx, stream, out_cid);
|
||
|
|
}
|
||
|
|
|
||
|
|
amduat_bytestore_error_t amduat_bytestore_import_cor(
|
||
|
|
amduat_bytestore_t *store,
|
||
|
|
amduat_octets_t envelope,
|
||
|
|
amduat_reference_t *out_cid) {
|
||
|
|
if (store == NULL || store->ops.import_cor == NULL) {
|
||
|
|
return AMDUAT_BYTESTORE_ERR_UNSUPPORTED;
|
||
|
|
}
|
||
|
|
return store->ops.import_cor(store->ctx, envelope, out_cid);
|
||
|
|
}
|
||
|
|
|
||
|
|
amduat_bytestore_error_t amduat_bytestore_export_cor(
|
||
|
|
amduat_bytestore_t *store,
|
||
|
|
amduat_reference_t cid,
|
||
|
|
amduat_octets_t *out_envelope) {
|
||
|
|
if (store == NULL || store->ops.export_cor == NULL) {
|
||
|
|
return AMDUAT_BYTESTORE_ERR_UNSUPPORTED;
|
||
|
|
}
|
||
|
|
return store->ops.export_cor(store->ctx, cid, out_envelope);
|
||
|
|
}
|
||
|
|
|
||
|
|
amduat_bytestore_error_t amduat_bytestore_get(amduat_bytestore_t *store,
|
||
|
|
amduat_reference_t cid,
|
||
|
|
amduat_octets_t *out_bytes) {
|
||
|
|
if (store == NULL || store->ops.get == NULL) {
|
||
|
|
return AMDUAT_BYTESTORE_ERR_UNSUPPORTED;
|
||
|
|
}
|
||
|
|
return store->ops.get(store->ctx, cid, out_bytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
amduat_bytestore_error_t amduat_bytestore_stat(
|
||
|
|
amduat_bytestore_t *store,
|
||
|
|
amduat_reference_t cid,
|
||
|
|
amduat_bytestore_stat_t *out_stat) {
|
||
|
|
if (store == NULL || store->ops.stat == NULL) {
|
||
|
|
return AMDUAT_BYTESTORE_ERR_UNSUPPORTED;
|
||
|
|
}
|
||
|
|
return store->ops.stat(store->ctx, cid, out_stat);
|
||
|
|
}
|
||
|
|
|
||
|
|
amduat_bytestore_error_t amduat_bytestore_assert_area_isolation(
|
||
|
|
amduat_bytestore_t *store,
|
||
|
|
const char *public_root,
|
||
|
|
const char *secure_root) {
|
||
|
|
size_t public_len;
|
||
|
|
size_t secure_len;
|
||
|
|
|
||
|
|
if (store != NULL && store->ops.assert_area_isolation != NULL) {
|
||
|
|
return store->ops.assert_area_isolation(store->ctx, public_root,
|
||
|
|
secure_root);
|
||
|
|
}
|
||
|
|
if (!amduat_bytestore_trim_trailing_slash(public_root, &public_len) ||
|
||
|
|
!amduat_bytestore_trim_trailing_slash(secure_root, &secure_len)) {
|
||
|
|
return AMDUAT_BYTESTORE_ERR_INVALID;
|
||
|
|
}
|
||
|
|
if (public_len == 0u || secure_len == 0u) {
|
||
|
|
return AMDUAT_BYTESTORE_ERR_INVALID;
|
||
|
|
}
|
||
|
|
if (public_len == secure_len &&
|
||
|
|
memcmp(public_root, secure_root, public_len) == 0) {
|
||
|
|
return AMDUAT_BYTESTORE_ERR_AREA_VIOLATION;
|
||
|
|
}
|
||
|
|
if (amduat_bytestore_path_is_prefix(public_root, public_len, secure_root,
|
||
|
|
secure_len)) {
|
||
|
|
return AMDUAT_BYTESTORE_ERR_AREA_VIOLATION;
|
||
|
|
}
|
||
|
|
if (amduat_bytestore_path_is_prefix(secure_root, secure_len, public_root,
|
||
|
|
public_len)) {
|
||
|
|
return AMDUAT_BYTESTORE_ERR_AREA_VIOLATION;
|
||
|
|
}
|
||
|
|
return AMDUAT_BYTESTORE_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool amduat_bytestore_cid_for_payload(amduat_hash_id_t hash_id,
|
||
|
|
amduat_octets_t payload,
|
||
|
|
amduat_reference_t *out_cid) {
|
||
|
|
const amduat_hash_asl1_desc_t *desc;
|
||
|
|
uint8_t *digest;
|
||
|
|
amduat_octets_t domain_sep;
|
||
|
|
|
||
|
|
if (out_cid == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
*out_cid = amduat_reference(0, amduat_octets(NULL, 0u));
|
||
|
|
desc = amduat_hash_asl1_desc_lookup(hash_id);
|
||
|
|
if (desc == NULL || desc->digest_len == 0u) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
digest = (uint8_t *)malloc(desc->digest_len);
|
||
|
|
if (digest == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
domain_sep = amduat_octets(k_amduat_bytestore_domain_sep,
|
||
|
|
sizeof(k_amduat_bytestore_domain_sep) - 1u);
|
||
|
|
if (!amduat_hash_asl1_digest_domain(hash_id, domain_sep, payload, digest,
|
||
|
|
desc->digest_len)) {
|
||
|
|
free(digest);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
*out_cid = amduat_reference(hash_id, amduat_octets(digest, desc->digest_len));
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool amduat_bytestore_cid_for_stream(amduat_hash_id_t hash_id,
|
||
|
|
amduat_bytestore_stream_t stream,
|
||
|
|
amduat_reference_t *out_cid) {
|
||
|
|
amduat_hash_asl1_stream_t hasher;
|
||
|
|
const amduat_hash_asl1_desc_t *desc;
|
||
|
|
uint8_t *digest;
|
||
|
|
amduat_octets_t domain_sep;
|
||
|
|
amduat_octets_t chunk;
|
||
|
|
int next_status;
|
||
|
|
|
||
|
|
if (out_cid == NULL || stream.next == NULL) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
*out_cid = amduat_reference(0, amduat_octets(NULL, 0u));
|
||
|
|
desc = amduat_hash_asl1_desc_lookup(hash_id);
|
||
|
|
if (desc == NULL || desc->digest_len == 0u) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (!amduat_hash_asl1_stream_init(hash_id, &hasher)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
domain_sep = amduat_octets(k_amduat_bytestore_domain_sep,
|
||
|
|
sizeof(k_amduat_bytestore_domain_sep) - 1u);
|
||
|
|
if (!amduat_hash_asl1_stream_update(&hasher, domain_sep)) {
|
||
|
|
amduat_hash_asl1_stream_destroy(&hasher);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
while (true) {
|
||
|
|
chunk = amduat_octets(NULL, 0u);
|
||
|
|
next_status = stream.next(stream.ctx, &chunk);
|
||
|
|
if (next_status == 0) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (next_status < 0) {
|
||
|
|
amduat_hash_asl1_stream_destroy(&hasher);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (chunk.len != 0u && chunk.data == NULL) {
|
||
|
|
amduat_hash_asl1_stream_destroy(&hasher);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (chunk.len != 0u &&
|
||
|
|
!amduat_hash_asl1_stream_update(&hasher, chunk)) {
|
||
|
|
amduat_hash_asl1_stream_destroy(&hasher);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
digest = (uint8_t *)malloc(desc->digest_len);
|
||
|
|
if (digest == NULL) {
|
||
|
|
amduat_hash_asl1_stream_destroy(&hasher);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (!amduat_hash_asl1_stream_final(&hasher, digest, desc->digest_len)) {
|
||
|
|
free(digest);
|
||
|
|
amduat_hash_asl1_stream_destroy(&hasher);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
amduat_hash_asl1_stream_destroy(&hasher);
|
||
|
|
*out_cid = amduat_reference(hash_id, amduat_octets(digest, desc->digest_len));
|
||
|
|
return true;
|
||
|
|
}
|