MACAROON_API struct macaroon* macaroon_add_first_party_caveat(const struct macaroon* N, const unsigned char* predicate, size_t predicate_sz, enum macaroon_returncode* err) { unsigned char hash[MACAROON_HASH_BYTES]; size_t i; size_t sz; struct macaroon* M; unsigned char* ptr; assert(predicate_sz < MACAROON_MAX_STRLEN); if (N->num_caveats + 1 > MACAROON_MAX_CAVEATS) { *err = MACAROON_TOO_MANY_CAVEATS; return NULL; } if (!N->signature.data || N->signature.size != MACAROON_HASH_BYTES) { *err = MACAROON_INVALID; return NULL; } if (macaroon_hash1(N->signature.data, predicate, predicate_sz, hash) < 0) { *err = MACAROON_HASH_FAILED; return NULL; } sz = macaroon_body_size(N) + predicate_sz + MACAROON_HASH_BYTES; M = macaroon_malloc(N->num_caveats + 1, sz, &ptr); if (!M) { *err = MACAROON_OUT_OF_MEMORY; return NULL; } M->num_caveats = N->num_caveats + 1; ptr = copy_slice(&N->location, &M->location, ptr); ptr = copy_slice(&N->identifier, &M->identifier, ptr); for (i = 0; i < N->num_caveats; ++i) { ptr = copy_slice(&N->caveats[i].cid, &M->caveats[i].cid, ptr); ptr = copy_slice(&N->caveats[i].vid, &M->caveats[i].vid, ptr); ptr = copy_slice(&N->caveats[i].cl, &M->caveats[i].cl, ptr); } ptr = copy_to_slice(predicate, predicate_sz, &M->caveats[M->num_caveats - 1].cid, ptr); ptr = copy_to_slice(hash, MACAROON_HASH_BYTES, &M->signature, ptr); VALIDATE(M); return M; }
/* Insert slices into a goal branch. * The inserted slices are copies of the elements of prototypes). * Each slice is inserted at a position that corresponds to its predefined rank. * @param si identifies starting point of insertion * @param prototypes contains the prototypes whose copies are inserted * @param nr_prototypes number of elements of array prototypes */ static void goal_branch_insert_slices_nested(slice_index si, slice_index const prototypes[], unsigned int nr_prototypes) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParam("%u",nr_prototypes); TraceFunctionParamListEnd(); { slice_type const prototype_type = SLICE_TYPE(prototypes[0]); unsigned int prototype_rank = get_goal_slice_rank(prototype_type); if (prototype_rank==no_goal_slice_type) { if (nr_prototypes>1) goal_branch_insert_slices_nested(si,prototypes+1,nr_prototypes-1); } else do { slice_index const next = SLICE_NEXT1(si); if (SLICE_TYPE(next)==STProxy) si = next; else if (SLICE_TYPE(next)==STOr || SLICE_TYPE(next)==STAnd) { goal_branch_insert_slices_nested(SLICE_NEXT1(next), prototypes,nr_prototypes); goal_branch_insert_slices_nested(SLICE_NEXT2(next), prototypes,nr_prototypes); break; } else { unsigned int const rank_next = get_goal_slice_rank(SLICE_TYPE(next)); if (rank_next==no_goal_slice_type) break; else if (rank_next>prototype_rank) { slice_index const copy = copy_slice(prototypes[0]); pipe_append(si,copy); if (nr_prototypes>1) goal_branch_insert_slices_nested(copy,prototypes+1,nr_prototypes-1); break; } else si = next; } } while (prototype_type!=SLICE_TYPE(si)); } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Callback to stip_spin_off_testers * Spin a tester slice off a fork slice * @param si identifies the testing pipe slice * @param st address of structure representing traversal */ void stip_spin_off_testers_fork(slice_index si, stip_structure_traversal *st) { TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); SLICE_TESTER(si) = copy_slice(si); stip_traverse_structure_children(si,st); link_to_branch(SLICE_TESTER(si),SLICE_TESTER(SLICE_NEXT1(si))); SLICE_NEXT2(SLICE_TESTER(si)) = SLICE_TESTER(SLICE_NEXT2(si)); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* End copying on the visited slice, by moving it to the copy and linking it * to a proxy slice that takes its original place * @param si visited slice * @param st structure representing the copying traversal */ static void move_and_stop_copying(slice_index si, stip_structure_traversal *st) { stip_deep_copies_type * const copies = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); assert((*copies)[si]==no_slice); (*copies)[si] = copy_slice(si); pipe_substitute(si,alloc_proxy_slice()); link_to_branch((*copies)[si],si); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Create a shallow copy of the visited fork slice * @param si visited slice * @param st structure representing the copying traversal */ static void copy_shallow(slice_index si, stip_structure_traversal *st) { stip_deep_copies_type * const copies = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); assert((*copies)[si]==no_slice); (*copies)[si] = copy_slice(si); stip_traverse_structure_children_pipe(si,st); if (SLICE_NEXT1(si)!=no_slice) link_to_branch((*copies)[si],(*copies)[SLICE_NEXT1(si)]); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Add the copy of a slice into the set play branch * @param si slice index * @param st state of traversal */ static void copy_to_setplay(slice_index si, stip_structure_traversal *st) { spin_off_state_type * const state = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); stip_traverse_structure_children_pipe(si,st); TraceValue("%u",state->spun_off[SLICE_NEXT1(si)]); TraceEOL(); state->spun_off[si] = copy_slice(si); link_to_branch(state->spun_off[si],state->spun_off[SLICE_NEXT1(si)]); TraceValue("%u",state->spun_off[si]); TraceEOL(); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Shorten a help branch by 1 half move * @param identifies entry slice of branch to be shortened */ void help_branch_shorten(slice_index adapter) { slice_index const next = SLICE_NEXT1(adapter); TraceFunctionEntry(__func__); TraceFunctionParam("%u",adapter); TraceFunctionParamListEnd(); assert(SLICE_TYPE(adapter)==STHelpAdapter); { /* find the new spot for adapter by inserting a copy */ slice_index const prototype = copy_slice(adapter); help_branch_insert_slices(next,&prototype,1); } { /* move adapter to its new spot */ slice_index const copy = branch_find_slice(STHelpAdapter, next, stip_traversal_context_help); assert(copy!=no_slice); pipe_link(SLICE_PREV(adapter),next); pipe_append(copy,adapter); pipe_remove(copy); } /* adjust the length and min_length members */ --SLICE_U(adapter).branch.length; if (SLICE_U(adapter).branch.min_length<=0) increase_min_length(adapter); --SLICE_U(adapter).branch.min_length; branch_shorten_slices(next,STHelpAdapter,stip_traversal_context_help); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
/* Spin a copy off a conditional pipe to add it to the root or set play branch * @param si identifies (non-root) slice * @param st address of structure representing traversal */ void conditional_pipe_spin_off_copy(slice_index si, stip_structure_traversal *st) { spin_off_state_type * const state = st->param; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); state->spun_off[si] = copy_slice(si); stip_traverse_structure_children_pipe(si,st); if (state->spun_off[SLICE_NEXT1(si)]==no_slice) { dealloc_slice(state->spun_off[si]); state->spun_off[si] = no_slice; } else link_to_branch(state->spun_off[si],state->spun_off[SLICE_NEXT1(si)]); TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
MACAROON_API struct macaroon* macaroon_add_third_party_caveat_raw(const struct macaroon* N, const unsigned char* location, size_t location_sz, const unsigned char* key, size_t key_sz, const unsigned char* id, size_t id_sz, enum macaroon_returncode* err) { unsigned char new_sig[MACAROON_HASH_BYTES]; unsigned char enc_nonce[MACAROON_SECRET_NONCE_BYTES]; unsigned char enc_plaintext[MACAROON_SECRET_TEXT_ZERO_BYTES + MACAROON_HASH_BYTES]; unsigned char enc_ciphertext[MACAROON_SECRET_BOX_ZERO_BYTES + MACAROON_HASH_BYTES]; unsigned char vid[VID_NONCE_KEY_SZ]; size_t i; size_t sz; struct macaroon* M; unsigned char* ptr; assert(location_sz < MACAROON_MAX_STRLEN); assert(id_sz < MACAROON_MAX_STRLEN); assert(key_sz == MACAROON_SUGGESTED_SECRET_LENGTH); VALIDATE(N); if (N->num_caveats + 1 > MACAROON_MAX_CAVEATS) { *err = MACAROON_TOO_MANY_CAVEATS; return NULL; } /* * note that MACAROON_HASH_BYTES is necessarily the same as * MACAROON_SECRET_KEY_BYTES, so the signature is also good to use * as an encoding key */ if (!N->signature.data || N->signature.size != MACAROON_HASH_BYTES) { *err = MACAROON_INVALID; return NULL; } macaroon_randombytes(enc_nonce, sizeof(enc_nonce)); macaroon_memzero(enc_plaintext, sizeof(enc_plaintext)); macaroon_memzero(enc_ciphertext, sizeof(enc_ciphertext)); /* now encrypt the key to give us vid */ memmove(enc_plaintext + MACAROON_SECRET_TEXT_ZERO_BYTES, key, key_sz < MACAROON_HASH_BYTES ? key_sz : MACAROON_HASH_BYTES); if (macaroon_secretbox(N->signature.data, enc_nonce, enc_plaintext, MACAROON_SECRET_TEXT_ZERO_BYTES + MACAROON_HASH_BYTES, enc_ciphertext) < 0) { *err = MACAROON_HASH_FAILED; return NULL; } /* copy the (nonce, vid) pair into vid */ memmove(vid, enc_nonce, MACAROON_SECRET_NONCE_BYTES); memmove(vid + MACAROON_SECRET_NONCE_BYTES, enc_ciphertext + MACAROON_SECRET_BOX_ZERO_BYTES, VID_NONCE_KEY_SZ - MACAROON_SECRET_NONCE_BYTES); /* calculate the new signature */ if (macaroon_hash2(N->signature.data, vid, VID_NONCE_KEY_SZ, id, id_sz, new_sig) < 0) { *err = MACAROON_HASH_FAILED; return NULL; } sz = macaroon_body_size(N) + id_sz + VID_NONCE_KEY_SZ + location_sz + MACAROON_HASH_BYTES; M = macaroon_malloc(N->num_caveats + 1, sz, &ptr); if (!M) { *err = MACAROON_OUT_OF_MEMORY; return NULL; } M->num_caveats = N->num_caveats + 1; ptr = copy_slice(&N->location, &M->location, ptr); ptr = copy_slice(&N->identifier, &M->identifier, ptr); for (i = 0; i < N->num_caveats; ++i) { ptr = copy_slice(&N->caveats[i].cid, &M->caveats[i].cid, ptr); ptr = copy_slice(&N->caveats[i].vid, &M->caveats[i].vid, ptr); ptr = copy_slice(&N->caveats[i].cl, &M->caveats[i].cl, ptr); } ptr = copy_to_slice(id, id_sz, &M->caveats[M->num_caveats - 1].cid, ptr); ptr = copy_to_slice(vid, VID_NONCE_KEY_SZ, &M->caveats[M->num_caveats - 1].vid, ptr); ptr = copy_to_slice(location, location_sz, &M->caveats[M->num_caveats - 1].cl, ptr); ptr = copy_to_slice(new_sig, MACAROON_HASH_BYTES, &M->signature, ptr); VALIDATE(M); return M; }