mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-04-07 19:14:17 +00:00
Rewrite bundle author authentication
Replaced 'int has_author' manifest element with new 'enum authorship' element to record the result of author authentication, to avoid repeating expensive crypto operations. Separated the handling of bundle secret arguments from author lookup and authentication. The new rhizome_apply_bundle_secret(m,bsk) is now called at the top level to set the manifest secret key (if it validates), and thereafter there is no need to pass the 'bsk' argument to any other functions, as they can simply check the 'haveSecret' field of the manifest. Removed rhizome_extract_privatekey() which combined author lookup and bundle secret validation, and replaced it with functions that only deal with the author: rhizome_lookup_author() and rhizome_authenticate_author(). Renamed other functions to make their purpose and effect clearer. Formalised the semantics of only storing AUTHENTICATED author SIDs in the 'author' column of the MANIFESTS table, which necessitated a change to a 'rhizomeops' test case: when adding a file using a BK-less manifest, the author column is set to null, so the Rhizome list output does not show the bundle as ".fromhere" and does not give an author for that bundle.
This commit is contained in:
parent
4aea05f445
commit
45442d3eb4
@ -1358,20 +1358,20 @@ int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_context *co
|
||||
|
||||
if (journal && !m->is_journal)
|
||||
return WHY("Existing manifest is not a journal");
|
||||
|
||||
if (!journal && m->is_journal)
|
||||
return WHY("Existing manifest is a journal");
|
||||
|
||||
if (bskhex)
|
||||
rhizome_apply_bundle_secret(m, &bsk);
|
||||
if (m->service == NULL)
|
||||
rhizome_manifest_set_service(m, RHIZOME_SERVICE_FILE);
|
||||
|
||||
if (rhizome_fill_manifest(m, filepath, *authorSidHex ? &authorSid : NULL, bskhex ? &bsk : NULL)){
|
||||
if (rhizome_fill_manifest(m, filepath, *authorSidHex ? &authorSid : NULL)) {
|
||||
rhizome_manifest_free(m);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (journal){
|
||||
if (rhizome_append_journal_file(m, bskhex?&bsk:NULL, 0, filepath)){
|
||||
if (rhizome_append_journal_file(m, 0, filepath)){
|
||||
rhizome_manifest_free(m);
|
||||
return -1;
|
||||
}
|
||||
@ -1406,15 +1406,17 @@ int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_context *co
|
||||
cli_field_name(context, "manifestid", ":");
|
||||
cli_put_string(context, alloca_tohex_rhizome_bid_t(mout->cryptoSignPublic), "\n");
|
||||
}
|
||||
assert(m->haveSecret);
|
||||
{
|
||||
char secret[RHIZOME_BUNDLE_KEY_STRLEN + 1];
|
||||
rhizome_bytes_to_hex_upper(mout->cryptoSignSecret, secret, RHIZOME_BUNDLE_KEY_BYTES);
|
||||
cli_field_name(context, ".secret", ":");
|
||||
cli_put_string(context, secret, "\n");
|
||||
}
|
||||
if (m->has_author) {
|
||||
assert(mout->authorship != AUTHOR_LOCAL);
|
||||
if (mout->authorship == AUTHOR_AUTHENTIC) {
|
||||
cli_field_name(context, ".author", ":");
|
||||
cli_put_string(context, alloca_tohex_sid_t(m->author), "\n");
|
||||
cli_put_string(context, alloca_tohex_sid_t(mout->author), "\n");
|
||||
}
|
||||
if (mout->has_bundle_key) {
|
||||
cli_field_name(context, "BK", ":");
|
||||
@ -1670,8 +1672,9 @@ int app_rhizome_extract(const struct cli_parsed *parsed, struct cli_context *con
|
||||
ret = rhizome_retrieve_manifest(&bid, m);
|
||||
|
||||
if (ret==0){
|
||||
// ignore errors
|
||||
rhizome_extract_privatekey(m, bskhex ? &bsk : NULL);
|
||||
if (bskhex)
|
||||
rhizome_apply_bundle_secret(m, &bsk);
|
||||
rhizome_authenticate_author(m);
|
||||
|
||||
if (m->service) {
|
||||
cli_field_name(context, "service", ":");
|
||||
@ -1684,6 +1687,9 @@ int app_rhizome_extract(const struct cli_parsed *parsed, struct cli_context *con
|
||||
rhizome_bytes_to_hex_upper(m->cryptoSignSecret, secret, RHIZOME_BUNDLE_KEY_BYTES);
|
||||
cli_field_name(context, ".secret", ":");
|
||||
cli_put_string(context, secret, "\n");
|
||||
}
|
||||
assert(m->authorship != AUTHOR_LOCAL);
|
||||
if (m->authorship == AUTHOR_AUTHENTIC) {
|
||||
cli_field_name(context, ".author", ":");
|
||||
cli_put_string(context, alloca_tohex_sid_t(m->author), "\n");
|
||||
}
|
||||
@ -1707,8 +1713,7 @@ int app_rhizome_extract(const struct cli_parsed *parsed, struct cli_context *con
|
||||
if (ret==0 && m->filesize != 0 && filepath && *filepath){
|
||||
if (extract){
|
||||
// Save the file, implicitly decrypting if required.
|
||||
// TODO, this may cause us to search for an author a second time if the above call to rhizome_extract_privatekey failed
|
||||
retfile = rhizome_extract_file(m, filepath, bskhex?&bsk:NULL);
|
||||
retfile = rhizome_extract_file(m, filepath);
|
||||
}else{
|
||||
// Save the file without attempting to decrypt
|
||||
int64_t length;
|
||||
|
@ -88,5 +88,6 @@ void dump_stack(int log_level);
|
||||
#define OUT() fd_func_exit(__HERE__, &_this_call)
|
||||
#define RETURN(X) do { OUT(); return (X); } while (0);
|
||||
#define RETURNNULL do { OUT(); return (NULL); } while (0);
|
||||
#define RETURNVOID do { OUT(); return; } while (0);
|
||||
|
||||
#endif // __SERVALDNA__FDQUEUE_H
|
||||
|
@ -1504,7 +1504,7 @@ unsigned char *keyring_find_sas_private(keyring_file *k, const sid_t *sidp, unsi
|
||||
k->contexts[cn]->identities[in]->keypairs[kp]->private_key;
|
||||
unsigned char *sas_public=
|
||||
k->contexts[cn]->identities[in]->keypairs[kp]->public_key;
|
||||
if (rhizome_verify_bundle_privatekey(NULL,sas_private,sas_public))
|
||||
if (!rhizome_verify_bundle_privatekey(sas_private, sas_public))
|
||||
{
|
||||
/* SAS key is invalid (perhaps because it was a pre 0.90 format one),
|
||||
so replace it */
|
||||
|
30
meshms.c
30
meshms.c
@ -87,7 +87,7 @@ static int get_my_conversation_bundle(const sid_t *my_sidp, rhizome_manifest *m)
|
||||
assert(m->haveSecret);
|
||||
if (m->haveSecret == NEW_BUNDLE_ID) {
|
||||
rhizome_manifest_set_service(m, RHIZOME_SERVICE_FILE);
|
||||
if (rhizome_fill_manifest(m, NULL, my_sidp, NULL) == -1)
|
||||
if (rhizome_fill_manifest(m, NULL, my_sidp) == -1)
|
||||
return WHY("Invalid manifest");
|
||||
if (config.debug.meshms) {
|
||||
char secret[RHIZOME_BUNDLE_KEY_STRLEN + 1];
|
||||
@ -218,8 +218,9 @@ static int create_ply(const sid_t *my_sid, struct conversations *conv, rhizome_m
|
||||
rhizome_manifest_set_recipient(m, &conv->them);
|
||||
rhizome_manifest_set_filesize(m, 0);
|
||||
rhizome_manifest_set_tail(m, 0);
|
||||
if (rhizome_fill_manifest(m, NULL, my_sid, NULL))
|
||||
if (rhizome_fill_manifest(m, NULL, my_sid))
|
||||
return -1;
|
||||
assert(m->haveSecret);
|
||||
assert(m->payloadEncryption == PAYLOAD_ENCRYPTED);
|
||||
conv->my_ply.bundle_id = m->cryptoSignPublic;
|
||||
conv->found_my_ply = 1;
|
||||
@ -239,7 +240,7 @@ static int ply_read_open(struct ply_read *ply, const rhizome_bid_t *bid, rhizome
|
||||
DEBUGF("Opening ply %s", alloca_tohex_rhizome_bid_t(*bid));
|
||||
if (rhizome_retrieve_manifest(bid, m))
|
||||
return -1;
|
||||
int ret = rhizome_open_decrypt_read(m, NULL, &ply->read);
|
||||
int ret = rhizome_open_decrypt_read(m, &ply->read);
|
||||
if (ret == 1)
|
||||
WARNF("Payload was not found for manifest %s, %"PRId64, alloca_tohex_rhizome_bid_t(m->cryptoSignPublic), m->version);
|
||||
if (ret != 0)
|
||||
@ -317,7 +318,8 @@ static int ply_find_next(struct ply_read *ply, char type){
|
||||
}
|
||||
}
|
||||
|
||||
static int append_meshms_buffer(const sid_t *my_sid, struct conversations *conv, unsigned char *buffer, int len){
|
||||
static int append_meshms_buffer(const sid_t *my_sid, struct conversations *conv, unsigned char *buffer, int len)
|
||||
{
|
||||
int ret=-1;
|
||||
rhizome_manifest *mout = NULL;
|
||||
rhizome_manifest *m = rhizome_new_manifest();
|
||||
@ -327,14 +329,17 @@ static int append_meshms_buffer(const sid_t *my_sid, struct conversations *conv,
|
||||
if (conv->found_my_ply){
|
||||
if (rhizome_retrieve_manifest(&conv->my_ply.bundle_id, m))
|
||||
goto end;
|
||||
if (rhizome_find_bundle_author(m))
|
||||
rhizome_authenticate_author(m);
|
||||
if (!m->haveSecret || m->authorship != AUTHOR_AUTHENTIC)
|
||||
goto end;
|
||||
}else{
|
||||
if (create_ply(my_sid, conv, m))
|
||||
goto end;
|
||||
}
|
||||
assert(m->haveSecret);
|
||||
assert(m->authorship == AUTHOR_AUTHENTIC);
|
||||
|
||||
if (rhizome_append_journal_buffer(m, NULL, 0, buffer, len))
|
||||
if (rhizome_append_journal_buffer(m, 0, buffer, len))
|
||||
goto end;
|
||||
|
||||
if (rhizome_manifest_finalise(m, &mout, 1))
|
||||
@ -493,7 +498,7 @@ static int read_known_conversations(rhizome_manifest *m, const sid_t *their_sid,
|
||||
struct rhizome_read_buffer buff;
|
||||
bzero(&buff, sizeof(buff));
|
||||
|
||||
int ret = rhizome_open_decrypt_read(m, NULL, &read);
|
||||
int ret = rhizome_open_decrypt_read(m, &read);
|
||||
if (ret == -1)
|
||||
goto end;
|
||||
|
||||
@ -713,7 +718,8 @@ int app_meshms_conversations(const struct cli_parsed *parsed, struct cli_context
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_meshms_send_message(const struct cli_parsed *parsed, struct cli_context *context){
|
||||
int app_meshms_send_message(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
{
|
||||
const char *my_sidhex, *their_sidhex, *message;
|
||||
if (cli_arg(parsed, "sender_sid", &my_sidhex, str_is_subscriber_id, "") == -1
|
||||
|| cli_arg(parsed, "recipient_sid", &their_sidhex, str_is_subscriber_id, "") == -1
|
||||
@ -728,9 +734,11 @@ int app_meshms_send_message(const struct cli_parsed *parsed, struct cli_context
|
||||
return -1;
|
||||
|
||||
sid_t my_sid, their_sid;
|
||||
fromhex(my_sid.binary, my_sidhex, sizeof(my_sid.binary));
|
||||
fromhex(their_sid.binary, their_sidhex, sizeof(their_sid.binary));
|
||||
struct conversations *conv=find_or_create_conv(&my_sid, &their_sid);
|
||||
if (str_to_sid_t(&my_sid, my_sidhex) == -1)
|
||||
return WHY("invalid sender SID");
|
||||
if (str_to_sid_t(&their_sid, their_sidhex) == -1)
|
||||
return WHY("invalid recipient SID");
|
||||
struct conversations *conv = find_or_create_conv(&my_sid, &their_sid);
|
||||
if (!conv)
|
||||
return -1;
|
||||
|
||||
|
102
rhizome.c
102
rhizome.c
@ -184,44 +184,74 @@ int rhizome_manifest_check_sanity(rhizome_manifest *m)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
A bundle can either be an ordinary manifest-payload pair, or a group description.
|
||||
|
||||
- Group descriptions are manifests with no payload that have the "isagroup" variable set. They
|
||||
get stored in the manifests table AND a reference is added to the grouplist table. Any
|
||||
manifest, including any group manifest, may be a member of zero or one group. This allows a
|
||||
nested, i.e., multi-level group hierarchy where sub-groups will only typically be discovered
|
||||
by joining the parent group.
|
||||
*/
|
||||
|
||||
int rhizome_manifest_bind_id(rhizome_manifest *m)
|
||||
/* Sets the bundle key "BK" field of a manifest. Returns 1 if the field was set, 0 if not.
|
||||
*
|
||||
* This function must not be called unless the bundle secret is known.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int rhizome_manifest_add_bundle_key(rhizome_manifest *m)
|
||||
{
|
||||
if (rhizome_manifest_createid(m) == -1)
|
||||
return -1;
|
||||
/* The ID is implicit in transit, but we need to store it in the file, so that reimporting
|
||||
manifests on receiver nodes works easily. We might implement something that strips the id
|
||||
variable out of the manifest when sending it, or some other scheme to avoid sending all the
|
||||
extra bytes. */
|
||||
if (m->has_author) {
|
||||
/* Set the BK using the provided authorship information.
|
||||
Serval Security Framework defines BK as being:
|
||||
BK = privateKey XOR sha512(RS##BID), where BID = cryptoSignPublic,
|
||||
and RS is the rhizome secret for the specified author.
|
||||
The nice thing about this specification is that:
|
||||
privateKey = BK XOR sha512(RS##BID), so the same function can be used
|
||||
to encrypt and decrypt the BK field. */
|
||||
const unsigned char *rs;
|
||||
int rs_len=0;
|
||||
if (rhizome_find_secret(&m->author, &rs_len, &rs))
|
||||
return WHYF("Failed to obtain RS for %s to calculate BK", alloca_tohex_sid_t(m->author));
|
||||
rhizome_bk_t bkey;
|
||||
if (!rhizome_secret2bk(&m->cryptoSignPublic, rs, rs_len, bkey.binary, m->cryptoSignSecret))
|
||||
rhizome_manifest_set_bundle_key(m, &bkey);
|
||||
else
|
||||
return WHY("Failed to set BK");
|
||||
IN();
|
||||
assert(m->haveSecret);
|
||||
switch (m->authorship) {
|
||||
case ANONYMOUS: // there can be no BK field without an author
|
||||
case AUTHOR_UNKNOWN: // we already know the author is not in the keyring
|
||||
case AUTHENTICATION_ERROR: // already tried and failed to get Rhizome Secret
|
||||
break;
|
||||
case AUTHOR_NOT_CHECKED:
|
||||
case AUTHOR_LOCAL:
|
||||
case AUTHOR_AUTHENTIC:
|
||||
case AUTHOR_IMPOSTOR: {
|
||||
/* Set the BK using the provided author. Serval Security Framework defines BK as being:
|
||||
* BK = privateKey XOR sha512(RS##BID)
|
||||
* where BID = cryptoSignPublic,
|
||||
* RS is the rhizome secret for the specified author.
|
||||
* The nice thing about this specification is that:
|
||||
* privateKey = BK XOR sha512(RS##BID)
|
||||
* so the same function can be used to encrypt and decrypt the BK field.
|
||||
*/
|
||||
const unsigned char *rs;
|
||||
size_t rs_len = 0;
|
||||
enum rhizome_secret_disposition d = find_rhizome_secret(&m->author, &rs_len, &rs);
|
||||
switch (d) {
|
||||
case FOUND_RHIZOME_SECRET: {
|
||||
rhizome_bk_t bkey;
|
||||
if (rhizome_secret2bk(&m->cryptoSignPublic, rs, rs_len, bkey.binary, m->cryptoSignSecret) == 0) {
|
||||
rhizome_manifest_set_bundle_key(m, &bkey);
|
||||
m->authorship = AUTHOR_AUTHENTIC;
|
||||
RETURN(1);
|
||||
} else
|
||||
m->authorship = AUTHENTICATION_ERROR;
|
||||
}
|
||||
break;
|
||||
case IDENTITY_NOT_FOUND:
|
||||
m->authorship = AUTHOR_UNKNOWN;
|
||||
break;
|
||||
case IDENTITY_HAS_NO_RHIZOME_SECRET:
|
||||
m->authorship = AUTHENTICATION_ERROR;
|
||||
break;
|
||||
default:
|
||||
FATALF("find_rhizome_secret() returned unknown code %d", (int)d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FATALF("m->authorship = %d", (int)m->authorship);
|
||||
}
|
||||
return 0;
|
||||
rhizome_manifest_del_bundle_key(m);
|
||||
switch (m->authorship) {
|
||||
case AUTHOR_UNKNOWN:
|
||||
WHYF("Cannot set BK because author=%s is not in keyring", alloca_tohex_sid_t(m->author));
|
||||
break;
|
||||
case AUTHENTICATION_ERROR:
|
||||
WHY("Cannot set BK due to error");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
int rhizome_add_manifest(rhizome_manifest *m, int ttl)
|
||||
|
96
rhizome.h
96
rhizome.h
@ -238,16 +238,13 @@ typedef struct rhizome_manifest
|
||||
bool_t has_sender;
|
||||
bool_t has_recipient;
|
||||
|
||||
/* Set if the 'author' element is valid, ie, a SID has been assigned.
|
||||
*/
|
||||
bool_t has_author;
|
||||
|
||||
/* Local authorship. Useful for dividing bundle lists between "sent" and
|
||||
* "inbox" views.
|
||||
*/
|
||||
enum rhizome_bundle_authorship {
|
||||
AUTHOR_NOT_CHECKED = 0,
|
||||
AUTHOR_ERROR, // author check failed, don't try again
|
||||
ANONYMOUS = 0, // 'author' element is not valid
|
||||
AUTHOR_NOT_CHECKED, // 'author' element is valid but not checked
|
||||
AUTHENTICATION_ERROR, // author check failed, don't try again
|
||||
AUTHOR_UNKNOWN, // author is not a local identity
|
||||
AUTHOR_LOCAL, // author is in keyring (unlocked) but not verified
|
||||
AUTHOR_IMPOSTOR, // author is a local identity but fails verification
|
||||
@ -295,7 +292,8 @@ typedef struct rhizome_manifest
|
||||
sid_t recipient;
|
||||
|
||||
/* Local data, not encapsulated in the bundle. The system time of the most
|
||||
* recent INSERT or UPDATE of the manifest into the store.
|
||||
* recent INSERT or UPDATE of the manifest into the store. Zero if the manifest
|
||||
* has not been stored yet.
|
||||
*/
|
||||
time_ms_t inserttime;
|
||||
|
||||
@ -326,19 +324,27 @@ typedef struct rhizome_manifest
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
#define rhizome_manifest_set_id(m,v) _rhizome_manifest_set_id(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_version(m,v) _rhizome_manifest_set_version(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_filesize(m,v) _rhizome_manifest_set_filesize(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_filehash(m,v) _rhizome_manifest_set_filehash(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_tail(m,v) _rhizome_manifest_set_tail(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_bundle_key(m,v) _rhizome_manifest_set_bundle_key(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_service(m,v) _rhizome_manifest_set_service(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_name(m,v) _rhizome_manifest_set_name(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_date(m,v) _rhizome_manifest_set_date(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_sender(m,v) _rhizome_manifest_set_sender(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_recipient(m,v) _rhizome_manifest_set_recipient(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_crypt(m,v) _rhizome_manifest_set_crypt(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_author(m,v) _rhizome_manifest_set_author(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_id(m,v) _rhizome_manifest_set_id(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_version(m,v) _rhizome_manifest_set_version(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_filesize(m,v) _rhizome_manifest_set_filesize(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_filehash(m,v) _rhizome_manifest_set_filehash(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_tail(m,v) _rhizome_manifest_set_tail(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_bundle_key(m,v) _rhizome_manifest_set_bundle_key(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_del_bundle_key(m) _rhizome_manifest_del_bundle_key(__WHENCE__,(m))
|
||||
#define rhizome_manifest_set_service(m,v) _rhizome_manifest_set_service(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_del_service(m) _rhizome_manifest_del_service(__WHENCE__,(m))
|
||||
#define rhizome_manifest_set_name(m,v) _rhizome_manifest_set_name(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_del_name(m) _rhizome_manifest_del_name(__WHENCE__,(m))
|
||||
#define rhizome_manifest_set_date(m,v) _rhizome_manifest_set_date(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_del_date(m) _rhizome_manifest_del_date(__WHENCE__,(m))
|
||||
#define rhizome_manifest_set_sender(m,v) _rhizome_manifest_set_sender(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_del_sender(m) _rhizome_manifest_del_sender(__WHENCE__,(m))
|
||||
#define rhizome_manifest_set_recipient(m,v) _rhizome_manifest_set_recipient(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_del_recipient(m) _rhizome_manifest_del_recipient(__WHENCE__,(m))
|
||||
#define rhizome_manifest_set_crypt(m,v) _rhizome_manifest_set_crypt(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_inserttime(m,v) _rhizome_manifest_set_inserttime(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_set_author(m,v) _rhizome_manifest_set_author(__WHENCE__,(m),(v))
|
||||
#define rhizome_manifest_del_author(m) _rhizome_manifest_del_author(__WHENCE__,(m))
|
||||
|
||||
void _rhizome_manifest_set_id(struct __sourceloc, rhizome_manifest *, const rhizome_bid_t *);
|
||||
void _rhizome_manifest_set_version(struct __sourceloc, rhizome_manifest *, int64_t); // TODO change to uint64_t
|
||||
@ -346,13 +352,21 @@ void _rhizome_manifest_set_filesize(struct __sourceloc, rhizome_manifest *, uint
|
||||
void _rhizome_manifest_set_filehash(struct __sourceloc, rhizome_manifest *, const rhizome_filehash_t *);
|
||||
void _rhizome_manifest_set_tail(struct __sourceloc, rhizome_manifest *, uint64_t);
|
||||
void _rhizome_manifest_set_bundle_key(struct __sourceloc, rhizome_manifest *, const rhizome_bk_t *);
|
||||
void _rhizome_manifest_del_bundle_key(struct __sourceloc, rhizome_manifest *);
|
||||
void _rhizome_manifest_set_service(struct __sourceloc, rhizome_manifest *, const char *);
|
||||
void _rhizome_manifest_del_service(struct __sourceloc, rhizome_manifest *);
|
||||
void _rhizome_manifest_set_name(struct __sourceloc, rhizome_manifest *, const char *);
|
||||
void _rhizome_manifest_del_name(struct __sourceloc, rhizome_manifest *);
|
||||
void _rhizome_manifest_set_date(struct __sourceloc, rhizome_manifest *, time_ms_t);
|
||||
void _rhizome_manifest_del_date(struct __sourceloc, rhizome_manifest *);
|
||||
void _rhizome_manifest_set_sender(struct __sourceloc, rhizome_manifest *, const sid_t *);
|
||||
void _rhizome_manifest_del_sender(struct __sourceloc, rhizome_manifest *);
|
||||
void _rhizome_manifest_set_recipient(struct __sourceloc, rhizome_manifest *, const sid_t *);
|
||||
void _rhizome_manifest_del_recipient(struct __sourceloc, rhizome_manifest *);
|
||||
void _rhizome_manifest_set_crypt(struct __sourceloc, rhizome_manifest *, enum rhizome_manifest_crypt);
|
||||
void _rhizome_manifest_set_inserttime(struct __sourceloc, rhizome_manifest *, time_ms_t);
|
||||
void _rhizome_manifest_set_author(struct __sourceloc, rhizome_manifest *, const sid_t *);
|
||||
void _rhizome_manifest_del_author(struct __sourceloc, rhizome_manifest *);
|
||||
|
||||
/* Supported service identifiers. These go in the 'service' field of every
|
||||
* manifest, and indicate which application must be used to process the bundle
|
||||
@ -439,17 +453,21 @@ rhizome_manifest *_rhizome_new_manifest(struct __sourceloc __whence);
|
||||
int rhizome_manifest_pack_variables(rhizome_manifest *m);
|
||||
int rhizome_store_bundle(rhizome_manifest *m);
|
||||
int rhizome_remove_file_datainvalid(sqlite_retry_state *retry, const rhizome_filehash_t *hashp);
|
||||
int rhizome_manifest_add_group(rhizome_manifest *m,char *groupid);
|
||||
int rhizome_clean_payload(const char *fileidhex);
|
||||
int rhizome_store_file(rhizome_manifest *m,const unsigned char *key);
|
||||
int rhizome_bundle_import_files(rhizome_manifest *m, const char *manifest_path, const char *filepath);
|
||||
int rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t *authorSidp, rhizome_bk_t *bsk);
|
||||
|
||||
int rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t *authorSidp);
|
||||
|
||||
int rhizome_apply_bundle_secret(rhizome_manifest *, const rhizome_bk_t *);
|
||||
int rhizome_manifest_add_bundle_key(rhizome_manifest *);
|
||||
|
||||
void rhizome_find_bundle_author_and_secret(rhizome_manifest *m);
|
||||
int rhizome_lookup_author(rhizome_manifest *m);
|
||||
void rhizome_authenticate_author(rhizome_manifest *m);
|
||||
|
||||
int rhizome_manifest_verify(rhizome_manifest *m);
|
||||
int rhizome_manifest_check_sanity(rhizome_manifest *m_in);
|
||||
|
||||
int rhizome_manifest_bind_id(rhizome_manifest *m_in);
|
||||
int rhizome_manifest_finalise(rhizome_manifest *m, rhizome_manifest **mout, int deduplicate);
|
||||
int rhizome_add_manifest(rhizome_manifest *m_in,int ttl);
|
||||
|
||||
@ -546,9 +564,9 @@ int64_t rhizome_bar_version(const unsigned char *bar);
|
||||
uint64_t rhizome_bar_bidprefix_ll(unsigned char *bar);
|
||||
int rhizome_is_bar_interesting(unsigned char *bar);
|
||||
int rhizome_is_manifest_interesting(rhizome_manifest *m);
|
||||
int rhizome_list_manifests(struct cli_context *context, const char *service, const char *name,
|
||||
const char *sender_sid, const char *recipient_sid,
|
||||
int limit, int offset, char count_rows);
|
||||
int rhizome_list_manifests(struct cli_context *context, const char *service, const char *name,
|
||||
const char *sender_sid, const char *recipient_sid,
|
||||
size_t rowlimit, size_t rowoffset, char count_rows);
|
||||
int rhizome_retrieve_manifest(const rhizome_bid_t *bid, rhizome_manifest *m);
|
||||
int rhizome_retrieve_manifest_by_prefix(const unsigned char *prefix, unsigned prefix_len, rhizome_manifest *m);
|
||||
int rhizome_advertise_manifest(struct subscriber *dest, rhizome_manifest *m);
|
||||
@ -562,7 +580,12 @@ int rhizome_delete_file(const rhizome_filehash_t *hashp);
|
||||
|
||||
int rhizome_fetching_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
|
||||
int monitor_announce_bundle(rhizome_manifest *m);
|
||||
int rhizome_find_secret(const sid_t *authorSidp, int *rs_len, const unsigned char **rs);
|
||||
enum rhizome_secret_disposition {
|
||||
FOUND_RHIZOME_SECRET = 0,
|
||||
IDENTITY_NOT_FOUND,
|
||||
IDENTITY_HAS_NO_RHIZOME_SECRET,
|
||||
};
|
||||
enum rhizome_secret_disposition find_rhizome_secret(const sid_t *authorSidp, size_t *rs_len, const unsigned char **rs);
|
||||
int rhizome_bk_xor_stream(
|
||||
const rhizome_bid_t *bidp,
|
||||
const unsigned char *rs,
|
||||
@ -584,13 +607,9 @@ int rhizome_secret2bk(
|
||||
const unsigned char secret[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES]
|
||||
);
|
||||
unsigned char *rhizome_bundle_shared_secret(rhizome_manifest *m);
|
||||
int rhizome_extract_privatekey(rhizome_manifest *m, const rhizome_bk_t *bsk);
|
||||
int rhizome_extract_privatekey_required(rhizome_manifest *m, rhizome_bk_t *bsk);
|
||||
int rhizome_sign_hash_with_key(rhizome_manifest *m,const unsigned char *sk,
|
||||
const unsigned char *pk,rhizome_signature *out);
|
||||
int rhizome_verify_bundle_privatekey(rhizome_manifest *m, const unsigned char *sk,
|
||||
const unsigned char *pk);
|
||||
int rhizome_find_bundle_author(rhizome_manifest *m);
|
||||
int rhizome_verify_bundle_privatekey(const unsigned char *sk, const unsigned char *pk);
|
||||
int rhizome_queue_ignore_manifest(unsigned char *bid_prefix, int prefix_len, int timeout);
|
||||
int rhizome_ignore_manifest_check(unsigned char *bid_prefix, int prefix_len);
|
||||
|
||||
@ -866,11 +885,10 @@ int rhizome_import_file(rhizome_manifest *m, const char *filepath);
|
||||
int rhizome_import_buffer(rhizome_manifest *m, unsigned char *buffer, size_t length);
|
||||
int rhizome_stat_file(rhizome_manifest *m, const char *filepath);
|
||||
int rhizome_add_file(rhizome_manifest *m, const char *filepath);
|
||||
int rhizome_derive_key(rhizome_manifest *m, rhizome_bk_t *bsk);
|
||||
int rhizome_derive_payload_key(rhizome_manifest *m);
|
||||
|
||||
int rhizome_open_write_journal(rhizome_manifest *m, rhizome_bk_t *bsk, uint64_t advance_by, uint64_t new_size);
|
||||
int rhizome_append_journal_buffer(rhizome_manifest *m, rhizome_bk_t *bsk, uint64_t advance_by, unsigned char *buffer, size_t len);
|
||||
int rhizome_append_journal_file(rhizome_manifest *m, rhizome_bk_t *bsk, uint64_t advance_by, const char *filename);
|
||||
int rhizome_append_journal_buffer(rhizome_manifest *m, uint64_t advance_by, unsigned char *buffer, size_t len);
|
||||
int rhizome_append_journal_file(rhizome_manifest *m, uint64_t advance_by, const char *filename);
|
||||
int rhizome_journal_pipe(struct rhizome_write *write, const rhizome_filehash_t *hashp, uint64_t start_offset, uint64_t length);
|
||||
|
||||
int rhizome_crypt_xor_block(unsigned char *buffer, size_t buffer_size, uint64_t stream_offset,
|
||||
@ -879,8 +897,8 @@ int rhizome_open_read(struct rhizome_read *read, const rhizome_filehash_t *hashp
|
||||
ssize_t rhizome_read(struct rhizome_read *read, unsigned char *buffer, size_t buffer_length);
|
||||
int rhizome_read_buffered(struct rhizome_read *read, struct rhizome_read_buffer *buffer, unsigned char *data, size_t len);
|
||||
int rhizome_read_close(struct rhizome_read *read);
|
||||
int rhizome_open_decrypt_read(rhizome_manifest *m, rhizome_bk_t *bsk, struct rhizome_read *read_state);
|
||||
int rhizome_extract_file(rhizome_manifest *m, const char *filepath, rhizome_bk_t *bsk);
|
||||
int rhizome_open_decrypt_read(rhizome_manifest *m, struct rhizome_read *read_state);
|
||||
int rhizome_extract_file(rhizome_manifest *m, const char *filepath);
|
||||
int rhizome_dump_file(const rhizome_filehash_t *hashp, const char *filepath, int64_t *length);
|
||||
int rhizome_read_cached(const rhizome_bid_t *bid, uint64_t version, time_ms_t timeout,
|
||||
uint64_t fileOffset, unsigned char *buffer, size_t length);
|
||||
|
203
rhizome_bundle.c
203
rhizome_bundle.c
@ -117,8 +117,21 @@ void _rhizome_manifest_set_id(struct __sourceloc __whence, rhizome_manifest *m,
|
||||
{
|
||||
const char *v = rhizome_manifest_set(m, "id", alloca_tohex_rhizome_bid_t(*bidp));
|
||||
assert(v); // TODO: remove known manifest fields from vars[]
|
||||
if (bidp != &m->cryptoSignPublic)
|
||||
if (bidp != &m->cryptoSignPublic && cmp_rhizome_bid_t(&m->cryptoSignPublic, bidp) != 0) {
|
||||
m->cryptoSignPublic = *bidp;
|
||||
// The BID just changed, so the secret key and bundle key are no longer valid.
|
||||
if (m->haveSecret) {
|
||||
m->haveSecret = SECRET_UNKNOWN;
|
||||
bzero(m->cryptoSignSecret, sizeof m->cryptoSignSecret); // not strictly necessary but aids debugging
|
||||
}
|
||||
if (m->has_bundle_key) {
|
||||
m->has_bundle_key = 0;
|
||||
m->bundle_key = RHIZOME_BK_NONE; // not strictly necessary but aids debugging
|
||||
}
|
||||
// Any authenticated author is no longer authenticated, but is still known to be in the keyring.
|
||||
if (m->authorship == AUTHOR_AUTHENTIC)
|
||||
m->authorship = AUTHOR_LOCAL;
|
||||
}
|
||||
}
|
||||
|
||||
void _rhizome_manifest_set_version(struct __sourceloc __whence, rhizome_manifest *m, int64_t version)
|
||||
@ -169,11 +182,21 @@ void _rhizome_manifest_set_bundle_key(struct __sourceloc __whence, rhizome_manif
|
||||
assert(v); // TODO: remove known manifest fields from vars[]
|
||||
m->bundle_key = *bkp;
|
||||
m->has_bundle_key = 1;
|
||||
} else {
|
||||
} else
|
||||
_rhizome_manifest_del_bundle_key(__whence, m);
|
||||
}
|
||||
|
||||
void _rhizome_manifest_del_bundle_key(struct __sourceloc __whence, rhizome_manifest *m)
|
||||
{
|
||||
if (m->has_bundle_key) {
|
||||
rhizome_manifest_del(m, "BK");
|
||||
m->bundle_key = RHIZOME_BK_NONE;
|
||||
m->has_bundle_key = 0;
|
||||
}
|
||||
m->bundle_key = RHIZOME_BK_NONE; // not strictly necessary, but aids debugging
|
||||
} else
|
||||
assert(rhizome_manifest_get(m, "BK") == NULL);
|
||||
// Once there is no BK field, any authenticated authorship is no longer.
|
||||
if (m->authorship == AUTHOR_AUTHENTIC)
|
||||
m->authorship = AUTHOR_LOCAL;
|
||||
}
|
||||
|
||||
void _rhizome_manifest_set_service(struct __sourceloc __whence, rhizome_manifest *m, const char *service)
|
||||
@ -182,10 +205,17 @@ void _rhizome_manifest_set_service(struct __sourceloc __whence, rhizome_manifest
|
||||
const char *v = rhizome_manifest_set(m, "service", service);
|
||||
assert(v); // TODO: remove known manifest fields from vars[]
|
||||
m->service = v;
|
||||
} else {
|
||||
rhizome_manifest_del(m, "service");
|
||||
} else
|
||||
_rhizome_manifest_del_service(__whence, m);
|
||||
}
|
||||
|
||||
void _rhizome_manifest_del_service(struct __sourceloc __whence, rhizome_manifest *m)
|
||||
{
|
||||
if (m->service) {
|
||||
m->service = NULL;
|
||||
}
|
||||
rhizome_manifest_del(m, "service");
|
||||
} else
|
||||
assert(rhizome_manifest_get(m, "service") == NULL);
|
||||
}
|
||||
|
||||
void _rhizome_manifest_set_name(struct __sourceloc __whence, rhizome_manifest *m, const char *name)
|
||||
@ -200,6 +230,15 @@ void _rhizome_manifest_set_name(struct __sourceloc __whence, rhizome_manifest *m
|
||||
}
|
||||
}
|
||||
|
||||
void _rhizome_manifest_del_name(struct __sourceloc __whence, rhizome_manifest *m)
|
||||
{
|
||||
if (m->name) {
|
||||
m->name = NULL;
|
||||
rhizome_manifest_del(m, "name");
|
||||
} else
|
||||
assert(rhizome_manifest_get(m, "name") == NULL);
|
||||
}
|
||||
|
||||
void _rhizome_manifest_set_date(struct __sourceloc __whence, rhizome_manifest *m, time_ms_t date)
|
||||
{
|
||||
const char *v = rhizome_manifest_set_ll(m, "date", date);
|
||||
@ -215,11 +254,18 @@ void _rhizome_manifest_set_sender(struct __sourceloc __whence, rhizome_manifest
|
||||
assert(v); // TODO: remove known manifest fields from vars[]
|
||||
m->sender = *sidp;
|
||||
m->has_sender = 1;
|
||||
} else {
|
||||
} else
|
||||
_rhizome_manifest_del_sender(__whence, m);
|
||||
}
|
||||
|
||||
void _rhizome_manifest_del_sender(struct __sourceloc __whence, rhizome_manifest *m)
|
||||
{
|
||||
if (m->has_sender) {
|
||||
rhizome_manifest_del(m, "sender");
|
||||
m->sender = SID_ANY;
|
||||
m->has_sender = 0;
|
||||
}
|
||||
} else
|
||||
assert(rhizome_manifest_get(m, "sender") == NULL);
|
||||
}
|
||||
|
||||
void _rhizome_manifest_set_recipient(struct __sourceloc __whence, rhizome_manifest *m, const sid_t *sidp)
|
||||
@ -229,11 +275,18 @@ void _rhizome_manifest_set_recipient(struct __sourceloc __whence, rhizome_manife
|
||||
assert(v); // TODO: remove known manifest fields from vars[]
|
||||
m->recipient = *sidp;
|
||||
m->has_recipient = 1;
|
||||
} else {
|
||||
} else
|
||||
_rhizome_manifest_del_recipient(__whence, m);
|
||||
}
|
||||
|
||||
void _rhizome_manifest_del_recipient(struct __sourceloc __whence, rhizome_manifest *m)
|
||||
{
|
||||
if (m->has_recipient) {
|
||||
rhizome_manifest_del(m, "recipient");
|
||||
m->recipient = SID_ANY;
|
||||
m->has_recipient = 0;
|
||||
}
|
||||
} else
|
||||
assert(rhizome_manifest_get(m, "recipient") == NULL);
|
||||
}
|
||||
|
||||
void _rhizome_manifest_set_crypt(struct __sourceloc __whence, rhizome_manifest *m, enum rhizome_manifest_crypt flag)
|
||||
@ -257,14 +310,31 @@ void _rhizome_manifest_set_crypt(struct __sourceloc __whence, rhizome_manifest *
|
||||
m->payloadEncryption = flag;
|
||||
}
|
||||
|
||||
void _rhizome_manifest_set_inserttime(struct __sourceloc __whence, rhizome_manifest *m, time_ms_t time)
|
||||
{
|
||||
m->inserttime = time;
|
||||
}
|
||||
|
||||
void _rhizome_manifest_set_author(struct __sourceloc __whence, rhizome_manifest *m, const sid_t *sidp)
|
||||
{
|
||||
if (sidp) {
|
||||
m->author = *sidp;
|
||||
m->has_author = 1;
|
||||
} else {
|
||||
if (m->authorship == ANONYMOUS || cmp_sid_t(&m->author, sidp) != 0) {
|
||||
if (config.debug.rhizome_manifest)
|
||||
DEBUGF("SET manifest[%d] author = %s", m->manifest_record_number, alloca_tohex_sid_t(*sidp));
|
||||
m->author = *sidp;
|
||||
m->authorship = AUTHOR_NOT_CHECKED;
|
||||
}
|
||||
} else
|
||||
_rhizome_manifest_del_author(__whence, m);
|
||||
}
|
||||
|
||||
void _rhizome_manifest_del_author(struct __sourceloc __whence, rhizome_manifest *m)
|
||||
{
|
||||
if (m->authorship != ANONYMOUS) {
|
||||
if (config.debug.rhizome_manifest)
|
||||
DEBUGF("DEL manifest[%d] author", m->manifest_record_number);
|
||||
m->author = SID_ANY;
|
||||
m->has_author = 0;
|
||||
m->authorship = ANONYMOUS;
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,7 +473,11 @@ int rhizome_manifest_parse(rhizome_manifest *m)
|
||||
} else {
|
||||
m->vars[m->var_count] = strdup(var);
|
||||
m->values[m->var_count] = strdup(value);
|
||||
// if any of these fields are not well formed, the manifest is invalid and cannot be imported
|
||||
/* The bundle ID is implicit in transit, but we need to store it in the manifest, so that
|
||||
* reimporting manifests on receiver nodes works easily. We might implement something that
|
||||
* strips the id variable out of the manifest when sending it, or some other scheme to avoid
|
||||
* sending all the extra bytes.
|
||||
*/
|
||||
if (strcasecmp(var, "id") == 0) {
|
||||
have_id = 1;
|
||||
if (str_to_rhizome_bid_t(&m->cryptoSignPublic, value) == -1) {
|
||||
@ -455,7 +529,7 @@ int rhizome_manifest_parse(rhizome_manifest *m)
|
||||
if (!str_to_uint64(value, 10, &tail, NULL) || tail == RHIZOME_SIZE_UNSET) {
|
||||
if (config.debug.rejecteddata)
|
||||
DEBUGF("Invalid tail: %s", value);
|
||||
m->warnings++;
|
||||
m->errors++;
|
||||
} else {
|
||||
m->tail = tail;
|
||||
m->is_journal = 1;
|
||||
@ -853,17 +927,6 @@ int rhizome_write_manifest_file(rhizome_manifest *m, const char *path, char appe
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
Adds a group that this bundle should be present in. If we have the means to sign
|
||||
the bundle as a member of that group, then we create the appropriate signature block.
|
||||
The group signature blocks, like all signature blocks, will be appended to the
|
||||
manifest data during the finalisation process.
|
||||
*/
|
||||
int rhizome_manifest_add_group(rhizome_manifest *m,char *groupid)
|
||||
{
|
||||
return WHY("Not implemented.");
|
||||
}
|
||||
|
||||
int rhizome_manifest_dump(rhizome_manifest *m, const char *msg)
|
||||
{
|
||||
unsigned i;
|
||||
@ -904,42 +967,41 @@ int rhizome_manifest_finalise(rhizome_manifest *m, rhizome_manifest **mout, int
|
||||
OUT();
|
||||
}
|
||||
|
||||
int rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t *authorSidp, rhizome_bk_t *bsk)
|
||||
int rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t *authorSidp)
|
||||
{
|
||||
/* Fill in a few missing manifest fields, to make it easier to use when adding new files:
|
||||
- the default service is FILE
|
||||
- use the current time for "date"
|
||||
- use the current time for "date" and "version"
|
||||
- if service is file, then use the payload file's basename for "name"
|
||||
*/
|
||||
|
||||
/* Set version of manifest, either from version variable, or using current time */
|
||||
/* Set version of manifest from current time if not already set. */
|
||||
if (m->version == 0)
|
||||
rhizome_manifest_set_version(m, gettime_ms());
|
||||
|
||||
/* Set the manifest's author (not stored). This must be done before binding to a new ID (below).
|
||||
* If no author was specified, then the manifest's "sender" field is used, if present.
|
||||
/* Set the manifest's author. This must be done before binding to a new ID (below). If no author
|
||||
* was specified, then the manifest's "sender" field is used, if present.
|
||||
*/
|
||||
if (authorSidp)
|
||||
rhizome_manifest_set_author(m, authorSidp);
|
||||
else if (m->has_sender)
|
||||
rhizome_manifest_set_author(m, &m->sender);
|
||||
|
||||
if (!m->haveSecret) {
|
||||
if (rhizome_bid_t_is_zero(m->cryptoSignPublic)) {
|
||||
if (config.debug.rhizome)
|
||||
DEBUG("creating new bundle");
|
||||
if (rhizome_manifest_bind_id(m) == -1)
|
||||
return WHY("Could not bind manifest to an ID");
|
||||
} else {
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("modifying existing bundle bid=%s", alloca_tohex_rhizome_bid_t(m->cryptoSignPublic));
|
||||
// Modifying an existing bundle. Make sure we can find the bundle secret.
|
||||
if (rhizome_extract_privatekey_required(m, bsk) == -1)
|
||||
return -1;
|
||||
// TODO assert that new version > old version?
|
||||
}
|
||||
/* Set the bundle ID (public key) and secret key.
|
||||
*/
|
||||
if (!m->haveSecret && rhizome_bid_t_is_zero(m->cryptoSignPublic)) {
|
||||
if (config.debug.rhizome)
|
||||
DEBUG("creating new bundle");
|
||||
if (rhizome_manifest_createid(m) == -1)
|
||||
return WHY("Could not bind manifest to an ID");
|
||||
if (m->authorship != ANONYMOUS)
|
||||
rhizome_manifest_add_bundle_key(m); // set the BK field
|
||||
} else {
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("modifying existing bundle bid=%s", alloca_tohex_rhizome_bid_t(m->cryptoSignPublic));
|
||||
// Modifying an existing bundle. Try to discover the bundle secret key and the author.
|
||||
rhizome_authenticate_author(m);
|
||||
// TODO assert that new version > old version?
|
||||
}
|
||||
assert(m->haveSecret);
|
||||
|
||||
if (m->service == NULL)
|
||||
return WHYF("missing 'service'");
|
||||
@ -981,32 +1043,49 @@ int rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Work out the authorship status of the bundle without performing any cryptographic checks.
|
||||
* Sets the 'authorship' element and returns 1 if an author was found, 0 if not.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int rhizome_lookup_author(rhizome_manifest *m)
|
||||
{
|
||||
IN();
|
||||
int cn, in, kp;
|
||||
switch (m->authorship) {
|
||||
case AUTHOR_NOT_CHECKED:
|
||||
if (m->has_author) {
|
||||
int cn = 0, in = 0, kp = 0;
|
||||
if (keyring_find_sid(keyring, &cn, &in, &kp, &m->author)) {
|
||||
m->authorship = AUTHOR_LOCAL;
|
||||
return 1;
|
||||
}
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("manifest[%d] lookup author=%s", m->manifest_record_number, alloca_tohex_sid_t(m->author));
|
||||
cn = 0, in = 0, kp = 0;
|
||||
if (keyring_find_sid(keyring, &cn, &in, &kp, &m->author)) {
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("found author");
|
||||
m->authorship = AUTHOR_LOCAL;
|
||||
RETURN(1);
|
||||
}
|
||||
// fall through
|
||||
case ANONYMOUS:
|
||||
if (m->has_sender) {
|
||||
int cn = 0, in = 0, kp = 0;
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("manifest[%d] lookup sender=%s", m->manifest_record_number, alloca_tohex_sid_t(m->sender));
|
||||
cn = 0, in = 0, kp = 0;
|
||||
if (keyring_find_sid(keyring, &cn, &in, &kp, &m->sender)) {
|
||||
m->author = m->sender;
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("found sender");
|
||||
rhizome_manifest_set_author(m, &m->sender);
|
||||
m->authorship = AUTHOR_LOCAL;
|
||||
return 1;
|
||||
RETURN(1);
|
||||
}
|
||||
}
|
||||
case AUTHOR_ERROR:
|
||||
case AUTHENTICATION_ERROR:
|
||||
case AUTHOR_UNKNOWN:
|
||||
case AUTHOR_IMPOSTOR:
|
||||
return 0;
|
||||
RETURN(0);
|
||||
case AUTHOR_LOCAL:
|
||||
case AUTHOR_AUTHENTIC:
|
||||
return 1;
|
||||
RETURN(1);
|
||||
}
|
||||
FATAL("m->authorship = %d", m->authorship);
|
||||
FATALF("m->authorship = %d", m->authorship);
|
||||
RETURN(0);
|
||||
OUT();
|
||||
}
|
||||
|
380
rhizome_crypto.c
380
rhizome_crypto.c
@ -44,6 +44,8 @@ int rhizome_manifest_createid(rhizome_manifest *m)
|
||||
return WHY("Failed to create keypair for manifest ID.");
|
||||
rhizome_manifest_set_id(m, &m->cryptoSignPublic);
|
||||
m->haveSecret = NEW_BUNDLE_ID;
|
||||
// A new Bundle ID and secret invalidates any existing BK field.
|
||||
rhizome_manifest_del_bundle_key(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -60,7 +62,7 @@ static int generate_keypair(const char *seed, struct signing_key *key)
|
||||
|
||||
// The first 256 bits (32 bytes) of the hash will be used as the private key of the BID.
|
||||
bcopy(hash, key->Private, sizeof key->Private);
|
||||
if (crypto_sign_compute_public_key(key->Private, key->Public.binary))
|
||||
if (crypto_sign_compute_public_key(key->Private, key->Public.binary) == -1)
|
||||
return WHY("Could not generate public key");
|
||||
// The last 32 bytes of the private key should be identical to the public key. This is what
|
||||
// crypto_sign_edwards25519sha512batch_keypair() returns, and there is code that depends on it.
|
||||
@ -81,13 +83,13 @@ int rhizome_get_bundle_from_seed(rhizome_manifest *m, const char *seed)
|
||||
return -1;
|
||||
if (ret == 1) {
|
||||
// manifest not retrieved
|
||||
rhizome_manifest_set_id(m, &key.Public);
|
||||
rhizome_manifest_set_id(m, &key.Public); // zerofills m->cryptoSignSecret
|
||||
m->haveSecret = NEW_BUNDLE_ID;
|
||||
} else {
|
||||
m->haveSecret = EXISTING_BUNDLE_ID;
|
||||
}
|
||||
bcopy(key.Private, m->cryptoSignSecret, sizeof m->cryptoSignSecret);
|
||||
//Disabled for performance, but these asserts should always hold.
|
||||
// Disabled for performance, these asserts should nevertheless always hold.
|
||||
//assert(cmp_rhizome_bid_t(&m->cryptoSignPublic, &key.Public) == 0);
|
||||
//assert(memcmp(m->cryptoSignPublic.binary, m->cryptoSignSecret + RHIZOME_BUNDLE_KEY_BYTES, sizeof m->cryptoSignPublic.binary) == 0);
|
||||
return ret;
|
||||
@ -124,10 +126,12 @@ int rhizome_bk_xor_stream(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
CryptoSign Secret Keys in cupercop-20120525 onwards have the public key as the
|
||||
second half of the secret key. The public key is the BID, so this simplifies
|
||||
the BK<-->SECRET conversion processes. */
|
||||
/* CryptoSign Secret Keys in cupercop-20120525 onwards have the public key as the second half of the
|
||||
* secret key. The public key is the BID, so this simplifies the BK<-->SECRET conversion processes.
|
||||
*
|
||||
* Returns 0 if the BK decodes correctly to the bundle secret, 1 if not. Returns -1 if there is an
|
||||
* error.
|
||||
*/
|
||||
int rhizome_bk2secret(rhizome_manifest *m,
|
||||
const rhizome_bid_t *bidp,
|
||||
const unsigned char *rs, const size_t rs_len,
|
||||
@ -138,21 +142,16 @@ int rhizome_bk2secret(rhizome_manifest *m,
|
||||
{
|
||||
IN();
|
||||
unsigned char xor_stream[RHIZOME_BUNDLE_KEY_BYTES];
|
||||
if (rhizome_bk_xor_stream(bidp,rs,rs_len,xor_stream,RHIZOME_BUNDLE_KEY_BYTES))
|
||||
if (rhizome_bk_xor_stream(bidp, rs, rs_len, xor_stream, RHIZOME_BUNDLE_KEY_BYTES))
|
||||
RETURN(WHY("rhizome_bk_xor_stream() failed"));
|
||||
|
||||
int i;
|
||||
|
||||
/* XOR and store secret part of secret key */
|
||||
for(i = 0; i != RHIZOME_BUNDLE_KEY_BYTES; i++)
|
||||
unsigned i;
|
||||
for (i = 0; i != RHIZOME_BUNDLE_KEY_BYTES; ++i)
|
||||
secret[i] = bkin[i] ^ xor_stream[i];
|
||||
/* Copy BID as public-key part of secret key */
|
||||
for(;i!=crypto_sign_edwards25519sha512batch_SECRETKEYBYTES;++i)
|
||||
secret[i] = bidp->binary[i - RHIZOME_BUNDLE_KEY_BYTES];
|
||||
|
||||
bzero(xor_stream, sizeof xor_stream);
|
||||
|
||||
RETURN(rhizome_verify_bundle_privatekey(m, secret, bidp->binary));
|
||||
/* Copy BID as public-key part of secret key */
|
||||
bcopy(bidp->binary, secret + RHIZOME_BUNDLE_KEY_BYTES, sizeof bidp->binary);
|
||||
RETURN(rhizome_verify_bundle_privatekey(secret, bidp->binary) ? 0 : 1);
|
||||
OUT();
|
||||
}
|
||||
|
||||
@ -181,243 +180,245 @@ int rhizome_secret2bk(
|
||||
}
|
||||
|
||||
|
||||
/* Given the SID of a bundle's author, search for an identity in the keyring and return its
|
||||
* Rhizome secret if found.
|
||||
/* Given a SID, search the keyring for an identity with the same SID and return its Rhizome secret
|
||||
* if found.
|
||||
*
|
||||
* Returns -1 if an error occurs.
|
||||
* Returns 0 if the author's rhizome secret is found; '*rs' is set to point to the secret key in the
|
||||
* keyring, and '*rs_len' is set to the key length.
|
||||
* Returns 2 if the author's identity is not in the keyring.
|
||||
* Returns 3 if the author's identity is in the keyring but has no rhizome secret.
|
||||
* Returns FOUND_RHIZOME_SECRET if the author's rhizome secret is found; '*rs' is set to point to
|
||||
* the secret key in the keyring, and '*rs_len' is set to the key length.
|
||||
*
|
||||
* Returns IDENTITY_NOT_FOUND if the SID is not in the keyring.
|
||||
*
|
||||
* Returns IDENTITY_HAS_NO_RHIZOME_SECRET if the SID is in the keyring but has no Rhizome Secret.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int rhizome_find_secret(const sid_t *authorSidp, int *rs_len, const unsigned char **rs)
|
||||
enum rhizome_secret_disposition find_rhizome_secret(const sid_t *authorSidp, size_t *rs_len, const unsigned char **rs)
|
||||
{
|
||||
IN();
|
||||
int cn=0, in=0, kp=0;
|
||||
if (!keyring_find_sid(keyring,&cn,&in,&kp, authorSidp)) {
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("identity sid=%s is not in keyring", alloca_tohex_sid_t(*authorSidp));
|
||||
return 2;
|
||||
RETURN(IDENTITY_NOT_FOUND);
|
||||
}
|
||||
kp = keyring_identity_find_keytype(keyring, cn, in, KEYTYPE_RHIZOME);
|
||||
if (kp == -1) {
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("identity sid=%s has no Rhizome Secret", alloca_tohex_sid_t(*authorSidp));
|
||||
return 3;
|
||||
WARNF("Identity sid=%s has no Rhizome Secret", alloca_tohex_sid_t(*authorSidp));
|
||||
RETURN(IDENTITY_HAS_NO_RHIZOME_SECRET);
|
||||
}
|
||||
int rslen = keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key_len;
|
||||
if (rslen < 16 || rslen > 1024)
|
||||
return WHYF("identity sid=%s has invalid Rhizome Secret: length=%d", alloca_tohex_sid_t(*authorSidp), rslen);
|
||||
assert(rslen >= 16);
|
||||
assert(rslen <= 1024);
|
||||
if (rs_len)
|
||||
*rs_len = rslen;
|
||||
if (rs)
|
||||
*rs = keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key;
|
||||
return 0;
|
||||
RETURN(FOUND_RHIZOME_SECRET);
|
||||
}
|
||||
|
||||
/* Given the SID of a bundle's author and the bundle ID, XOR a bundle key (private or public) with
|
||||
* RS##BID where RS is the rhizome secret of the bundle's author, and BID is the bundle's public key
|
||||
* (aka the Bundle ID).
|
||||
*
|
||||
* This will convert a manifest BK field into the bundle's private key, or vice versa.
|
||||
*
|
||||
* Returns -1 if an error occurs.
|
||||
* Returns 0 if the author's private key is located and the XOR is performed successfully.
|
||||
* Returns 2 if the author's identity is not in the keyring (this return code from
|
||||
* rhizome_find_secret()).
|
||||
* Returns 3 if the author's identity is in the keyring but has no rhizome secret (this return code
|
||||
* from rhizome_find_secret()).
|
||||
*
|
||||
* Looks up the SID in the keyring, and if it is present and has a valid-looking RS, calls
|
||||
* rhizome_bk_xor_rs() to perform the XOR.
|
||||
/* Attempt to authenticate the authorship of the given bundle, and set the 'authorship' element
|
||||
* accordingly. If the manifest has nk BK field, then no authentication can be performed.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
|
||||
/* See if the manifest has a BK entry, and if so, use it to obtain the private key for the BID. The
|
||||
* manifest's 'author' field must contain the (binary) SID of the purported author of the bundle,
|
||||
* which is used to look up the author's rhizome secret in the keyring.
|
||||
*
|
||||
* Returns 0 if a valid private key was extracted, with the private key in the manifest
|
||||
* 'cryptoSignSecret' field and the 'haveSecret' field set to EXISTING_BUNDLE_ID.
|
||||
*
|
||||
* Returns 1 if the manifest does not have a BK field.
|
||||
*
|
||||
* Returns 2 if the author is not found in the keyring (not unlocked?) -- this return code from
|
||||
* rhizome_bk_xor().
|
||||
*
|
||||
* Returns 3 if the author is found in the keyring but has no rhizome secret -- this return code
|
||||
* from rhizome_bk_xor().
|
||||
*
|
||||
* Returns 4 if the author is found in the keyring and has a rhizome secret but the private bundle
|
||||
* key formed using it does not verify.
|
||||
*
|
||||
* Returns -1 on error.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
|
||||
*/
|
||||
int rhizome_extract_privatekey(rhizome_manifest *m, const rhizome_bk_t *bsk)
|
||||
void rhizome_authenticate_author(rhizome_manifest *m)
|
||||
{
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("manifest[%d] bsk=%s", m->manifest_record_number, bsk ? alloca_tohex_rhizome_bk_t(*bsk) : "NULL");
|
||||
IN();
|
||||
int result;
|
||||
if (m->has_bundle_key) {
|
||||
if (!m->has_author) {
|
||||
result = rhizome_find_bundle_author(m);
|
||||
} else {
|
||||
int rs_len;
|
||||
const unsigned char *rs;
|
||||
result = rhizome_find_secret(&m->author, &rs_len, &rs);
|
||||
if (result == 0)
|
||||
result = rhizome_bk2secret(m, &m->cryptoSignPublic, rs, rs_len, m->bundle_key.binary, m->cryptoSignSecret);
|
||||
}
|
||||
if (result == 0 && bsk && !rhizome_is_bk_none(bsk)){
|
||||
// If a bundle secret key was supplied that does not match the secret key derived from the
|
||||
// author, then warn but carry on using the author's.
|
||||
if (memcmp(bsk->binary, m->cryptoSignSecret, sizeof bsk->binary) != 0)
|
||||
WARNF("Supplied bundle secret key is invalid -- ignoring");
|
||||
}
|
||||
}else if (bsk && !rhizome_is_bk_none(bsk)){
|
||||
bcopy(bsk->binary, m->cryptoSignSecret, sizeof bsk->binary);
|
||||
bcopy(m->cryptoSignPublic.binary, m->cryptoSignSecret + sizeof bsk->binary, sizeof m->cryptoSignPublic.binary);
|
||||
if (rhizome_verify_bundle_privatekey(m, m->cryptoSignSecret, m->cryptoSignPublic.binary))
|
||||
result=5;
|
||||
else
|
||||
result=0;
|
||||
}else{
|
||||
result=1;
|
||||
if (!m->has_bundle_key)
|
||||
RETURNVOID;
|
||||
switch (m->authorship) {
|
||||
case ANONYMOUS:
|
||||
rhizome_find_bundle_author_and_secret(m);
|
||||
break;
|
||||
case AUTHOR_NOT_CHECKED:
|
||||
case AUTHOR_LOCAL: {
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("manifest[%d] authenticate author=%s", m->manifest_record_number, alloca_tohex_sid_t(m->author));
|
||||
size_t rs_len;
|
||||
const unsigned char *rs;
|
||||
enum rhizome_secret_disposition d = find_rhizome_secret(&m->author, &rs_len, &rs);
|
||||
switch (d) {
|
||||
case FOUND_RHIZOME_SECRET:
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("author has Rhizome secret");
|
||||
switch (rhizome_bk2secret(m, &m->cryptoSignPublic, rs, rs_len, m->bundle_key.binary, m->cryptoSignSecret)) {
|
||||
case 0:
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("authentic");
|
||||
m->authorship = AUTHOR_AUTHENTIC;
|
||||
if (!m->haveSecret)
|
||||
m->haveSecret = EXISTING_BUNDLE_ID;
|
||||
break;
|
||||
case -1:
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("error");
|
||||
m->authorship = AUTHENTICATION_ERROR;
|
||||
break;
|
||||
default:
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("impostor");
|
||||
m->authorship = AUTHOR_IMPOSTOR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IDENTITY_NOT_FOUND:
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("author not found");
|
||||
m->authorship = AUTHOR_UNKNOWN;
|
||||
break;
|
||||
case IDENTITY_HAS_NO_RHIZOME_SECRET:
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("author has no Rhizome secret");
|
||||
m->authorship = AUTHENTICATION_ERROR;
|
||||
break;
|
||||
default:
|
||||
FATALF("find_rhizome_secret() returned unknown code %d", (int)d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AUTHENTICATION_ERROR:
|
||||
case AUTHOR_UNKNOWN:
|
||||
case AUTHOR_IMPOSTOR:
|
||||
case AUTHOR_AUTHENTIC:
|
||||
// work has already been done, don't repeat it
|
||||
break;
|
||||
default:
|
||||
FATALF("m->authorship = %d", (int)m->authorship);
|
||||
break;
|
||||
}
|
||||
if (result == 0)
|
||||
m->haveSecret = EXISTING_BUNDLE_ID;
|
||||
else {
|
||||
memset(m->cryptoSignSecret, 0, sizeof m->cryptoSignSecret);
|
||||
m->haveSecret = SECRET_UNKNOWN;
|
||||
}
|
||||
RETURN(result);
|
||||
OUT();
|
||||
}
|
||||
|
||||
/* Same as rhizome_extract_privatekey, except warnings become errors and are logged */
|
||||
int rhizome_extract_privatekey_required(rhizome_manifest *m, rhizome_bk_t *bsk)
|
||||
/* If the given bundle secret key corresponds to the bundle's ID (public key) then store it in the
|
||||
* manifest structure and mark the secret key as known. Return 1 if the secret key was assigned,
|
||||
* 0 if not.
|
||||
*
|
||||
* This function should only be called on a manifest that already has a public key (ID) and does
|
||||
* not have a known secret key.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int rhizome_apply_bundle_secret(rhizome_manifest *m, const rhizome_bk_t *bsk)
|
||||
{
|
||||
int result = rhizome_extract_privatekey(m, bsk);
|
||||
switch (result) {
|
||||
case -1:
|
||||
case 0:
|
||||
return result;
|
||||
case 1:
|
||||
return WHY("Bundle contains no BK field, and no bundle secret supplied");
|
||||
case 2:
|
||||
return WHY("Author unknown");
|
||||
case 3:
|
||||
return WHY("Author does not have a Rhizome Secret");
|
||||
case 4:
|
||||
return WHY("Author does not have permission to modify manifest");
|
||||
case 5:
|
||||
return WHY("Bundle secret is not valid for this manifest");
|
||||
default:
|
||||
return WHYF("Unknown result from rhizome_extract_privatekey(): %d", result);
|
||||
IN();
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("manifest[%d] bsk=%s", m->manifest_record_number, bsk ? alloca_tohex_rhizome_bk_t(*bsk) : "NULL");
|
||||
assert(m->haveSecret == SECRET_UNKNOWN);
|
||||
assert(is_all_matching(m->cryptoSignSecret, sizeof m->cryptoSignSecret, 0));
|
||||
assert(!rhizome_bid_t_is_zero(m->cryptoSignPublic));
|
||||
assert(bsk != NULL);
|
||||
assert(!rhizome_is_bk_none(bsk));
|
||||
if (rhizome_verify_bundle_privatekey(bsk->binary, m->cryptoSignPublic.binary)) {
|
||||
if (config.debug.rhizome)
|
||||
DEBUG("bundle secret verifies ok");
|
||||
bcopy(bsk->binary, m->cryptoSignSecret, sizeof bsk->binary);
|
||||
bcopy(m->cryptoSignPublic.binary, m->cryptoSignSecret + sizeof bsk->binary, sizeof m->cryptoSignPublic.binary);
|
||||
m->haveSecret = EXISTING_BUNDLE_ID;
|
||||
RETURN(1);
|
||||
}
|
||||
RETURN(0);
|
||||
OUT();
|
||||
}
|
||||
|
||||
/* Discover if the given manifest was created (signed) by any unlocked identity currently in the
|
||||
* keyring.
|
||||
*
|
||||
* Returns 0 if an identity is found with permission to alter the bundle, after setting the manifest
|
||||
* 'author' field to the SID of the identity and the manifest 'cryptoSignSecret' field to the bundle
|
||||
* secret key and the 'haveSecret' field to EXISTING_BUNDLE_ID.
|
||||
* This function must only be called if the bundle secret is not known. If it is known, then
|
||||
* use
|
||||
*
|
||||
* Returns 1 if no identity in the keyring is the author of this bundle.
|
||||
* If the authorship is already known (ie, not ANONYMOUS) then returns without changing anything.
|
||||
* That means this function can be called several times on the same manifest, but will only perform
|
||||
* any work the first time.
|
||||
*
|
||||
* Returns 4 if the manifest has no BK field.
|
||||
* If the manifest has no bundle key (BK) field, then it is anonymous, so leaves 'authorship'
|
||||
* unchanged and returns.
|
||||
*
|
||||
* Returns -1 if an error occurs, eg, the manifest contains an invalid BK field.
|
||||
* If an identity is found in the keyring with permission to alter the bundle, then sets the
|
||||
* manifest 'authorship' field to AUTHOR_AUTHENTIC, the 'author' field to the SID of the identity,
|
||||
* the manifest 'cryptoSignSecret' field to the bundle secret key and the 'haveSecret' field to
|
||||
* EXISTING_BUNDLE_ID.
|
||||
*
|
||||
* If no identity is found in the keyring that combines with the bundle key (BK) field to yield
|
||||
* the bundle's secret key, then leaves the manifest 'authorship' field as ANONYMOUS.
|
||||
*
|
||||
* If an error occurs, eg, the keyring contains an invalid Rhizome Secret or a cryptographic
|
||||
* operation fails, then sets the 'authorship' field to AUTHENTICATION_ERROR and leaves the
|
||||
* 'author', 'haveSecret' and 'cryptoSignSecret' fields unchanged.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int rhizome_find_bundle_author(rhizome_manifest *m)
|
||||
void rhizome_find_bundle_author_and_secret(rhizome_manifest *m)
|
||||
{
|
||||
IN();
|
||||
if (!m->has_bundle_key) {
|
||||
if (config.debug.rhizome)
|
||||
DEBUG("missing BK");
|
||||
RETURN(4);
|
||||
}
|
||||
if (m->authorship != ANONYMOUS)
|
||||
RETURNVOID;
|
||||
assert(is_sid_t_any(m->author));
|
||||
if (!m->has_bundle_key)
|
||||
RETURNVOID;
|
||||
int cn = 0, in = 0, kp = 0;
|
||||
for (; keyring_next_identity(keyring, &cn, &in, &kp); ++kp) {
|
||||
const sid_t *authorSidp = (const sid_t *) keyring->contexts[cn]->identities[in]->keypairs[kp]->public_key;
|
||||
//if (config.debug.rhizome) DEBUGF("try author identity sid=%s", alloca_tohex_sid_t(*authorSidp));
|
||||
int rkp = keyring_identity_find_keytype(keyring, cn, in, KEYTYPE_RHIZOME);
|
||||
if (rkp != -1) {
|
||||
int rs_len = keyring->contexts[cn]->identities[in]->keypairs[rkp]->private_key_len;
|
||||
if (rs_len < 16 || rs_len > 1024)
|
||||
RETURN(WHYF("invalid Rhizome Secret: length=%d", rs_len));
|
||||
size_t rs_len = keyring->contexts[cn]->identities[in]->keypairs[rkp]->private_key_len;
|
||||
if (rs_len < 16 || rs_len > 1024) {
|
||||
WHYF("invalid Rhizome Secret: length=%zu", rs_len);
|
||||
m->authorship = AUTHENTICATION_ERROR;
|
||||
RETURNVOID;
|
||||
}
|
||||
const unsigned char *rs = keyring->contexts[cn]->identities[in]->keypairs[rkp]->private_key;
|
||||
if (rhizome_bk2secret(m, &m->cryptoSignPublic, rs, rs_len, m->bundle_key.binary, m->cryptoSignSecret) == 0) {
|
||||
m->haveSecret = EXISTING_BUNDLE_ID;
|
||||
if (!m->has_author || cmp_sid_t(&m->author, authorSidp) != 0){
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("found bundle author sid=%s", alloca_tohex_sid_t(*authorSidp));
|
||||
rhizome_manifest_set_author(m, authorSidp);
|
||||
// if this bundle is already in the database, update the author.
|
||||
if (m->inserttime)
|
||||
sqlite_exec_void_loglevel(LOG_LEVEL_WARN,
|
||||
"UPDATE MANIFESTS SET author = ? WHERE id = ?;",
|
||||
SID_T, &m->author,
|
||||
RHIZOME_BID_T, &m->cryptoSignPublic,
|
||||
END);
|
||||
}
|
||||
RETURN(0); // bingo
|
||||
unsigned char *secretp = m->cryptoSignSecret;
|
||||
if (m->haveSecret)
|
||||
secretp = alloca(sizeof m->cryptoSignSecret);
|
||||
if (rhizome_bk2secret(m, &m->cryptoSignPublic, rs, rs_len, m->bundle_key.binary, secretp) == 0) {
|
||||
if (m->haveSecret) {
|
||||
if (memcmp(secretp, m->cryptoSignSecret, sizeof m->cryptoSignSecret) != 0)
|
||||
FATALF("Bundle secret does not match derived secret");
|
||||
} else
|
||||
m->haveSecret = EXISTING_BUNDLE_ID;
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("found bundle author sid=%s", alloca_tohex_sid_t(*authorSidp));
|
||||
rhizome_manifest_set_author(m, authorSidp);
|
||||
m->authorship = AUTHOR_AUTHENTIC;
|
||||
// if this bundle is already in the database, update the author.
|
||||
if (m->inserttime)
|
||||
sqlite_exec_void_loglevel(LOG_LEVEL_WARN,
|
||||
"UPDATE MANIFESTS SET author = ? WHERE id = ?;",
|
||||
SID_T, &m->author,
|
||||
RHIZOME_BID_T, &m->cryptoSignPublic,
|
||||
END);
|
||||
RETURNVOID; // bingo
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(m->authorship == ANONYMOUS);
|
||||
if (config.debug.rhizome)
|
||||
DEBUG("bundle author not found");
|
||||
RETURN(1);
|
||||
OUT();
|
||||
}
|
||||
|
||||
/* Verify the validity of the manifest's secret key, ie, is the given manifest's 'cryptoSignSecret'
|
||||
* field actually the secret key corresponding to the public key in 'cryptoSignPublic'?
|
||||
* Return 0 if valid, 1 if not. Return -1 if an error occurs.
|
||||
/* Verify the validity of a given secret manifest key. Return 1 if valid, 0 if not.
|
||||
*
|
||||
* There is no NaCl API to efficiently test this. We use a modified version of
|
||||
* crypto_sign_keypair() to accomplish this task.
|
||||
*/
|
||||
int rhizome_verify_bundle_privatekey(rhizome_manifest *m,
|
||||
const unsigned char *sk,
|
||||
const unsigned char *pkin)
|
||||
int rhizome_verify_bundle_privatekey(const unsigned char *sk, const unsigned char *pkin)
|
||||
{
|
||||
IN();
|
||||
unsigned char pk[32];
|
||||
int i;
|
||||
crypto_sign_compute_public_key(sk,pk);
|
||||
for (i = 0;i < 32;++i)
|
||||
if (pkin[i] != pk[i]) {
|
||||
if (m&&sk==m->cryptoSignSecret&&pkin==m->cryptoSignPublic.binary)
|
||||
m->haveSecret = SECRET_UNKNOWN;
|
||||
RETURN(-1);
|
||||
}
|
||||
if (m&&sk==m->cryptoSignSecret&&pkin==m->cryptoSignPublic.binary) {
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("We have the private key for this bundle.");
|
||||
m->haveSecret = EXISTING_BUNDLE_ID;
|
||||
}
|
||||
RETURN(0);
|
||||
OUT();
|
||||
rhizome_bid_t pk;
|
||||
if (crypto_sign_compute_public_key(sk, pk.binary) == -1)
|
||||
RETURN(0);
|
||||
int ret = bcmp(pkin, pk.binary, sizeof pk.binary) == 0;
|
||||
RETURN(ret);
|
||||
}
|
||||
|
||||
int rhizome_sign_hash(rhizome_manifest *m,
|
||||
rhizome_signature *out)
|
||||
int rhizome_sign_hash(rhizome_manifest *m, rhizome_signature *out)
|
||||
{
|
||||
IN();
|
||||
if (!m->haveSecret && rhizome_extract_privatekey_required(m, NULL))
|
||||
RETURN(-1);
|
||||
|
||||
int ret=rhizome_sign_hash_with_key(m, m->cryptoSignSecret, m->cryptoSignPublic.binary, out);
|
||||
assert(m->haveSecret);
|
||||
int ret = rhizome_sign_hash_with_key(m, m->cryptoSignSecret, m->cryptoSignPublic.binary, out);
|
||||
RETURN(ret);
|
||||
OUT();
|
||||
}
|
||||
@ -627,7 +628,7 @@ int rhizome_crypt_xor_block(unsigned char *buffer, size_t buffer_size, uint64_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rhizome_derive_key(rhizome_manifest *m, rhizome_bk_t *bsk)
|
||||
int rhizome_derive_payload_key(rhizome_manifest *m)
|
||||
{
|
||||
// don't do anything if the manifest isn't flagged as being encrypted
|
||||
if (m->payloadEncryption != PAYLOAD_ENCRYPTED)
|
||||
@ -655,9 +656,8 @@ int rhizome_derive_key(rhizome_manifest *m, rhizome_bk_t *bsk)
|
||||
bcopy(hash, m->payloadKey, RHIZOME_CRYPT_KEY_BYTES);
|
||||
|
||||
}else{
|
||||
if (!m->haveSecret && rhizome_extract_privatekey_required(m, bsk))
|
||||
return -1;
|
||||
assert(m->haveSecret);
|
||||
if (!m->haveSecret)
|
||||
return WHY("Cannot derive payload key because bundle secret is unknown");
|
||||
|
||||
unsigned char raw_key[9+crypto_sign_edwards25519sha512batch_SECRETKEYBYTES]="sasquatch";
|
||||
bcopy(m->cryptoSignSecret, &raw_key[9], crypto_sign_edwards25519sha512batch_SECRETKEYBYTES);
|
||||
|
@ -167,7 +167,8 @@ void verify_bundles(){
|
||||
ret=rhizome_store_bundle(m);
|
||||
}
|
||||
if (ret!=0){
|
||||
DEBUGF("Removing invalid manifest entry @%lld", rowid);
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("Removing invalid manifest entry @%lld", rowid);
|
||||
sqlite_exec_void_retry(&retry, "DELETE FROM MANIFESTS WHERE ROWID = ?;", INT64, rowid, END);
|
||||
}
|
||||
rhizome_manifest_free(m);
|
||||
@ -1278,15 +1279,9 @@ int rhizome_store_bundle(rhizome_manifest *m)
|
||||
if (!m->finalised)
|
||||
return WHY("Manifest was not finalised");
|
||||
|
||||
if (m->haveSecret) {
|
||||
/* We used to store the secret in the database, but we don't anymore, as we use
|
||||
the BK field in the manifest. So nothing to do here. */
|
||||
} else {
|
||||
/* We don't have the secret for this manifest, so only allow updates if
|
||||
the self-signature is valid */
|
||||
if (!m->selfSigned)
|
||||
return WHY("Manifest is not signed, and I don't have the key. Manifest might be forged or corrupt.");
|
||||
}
|
||||
// If we don't have the secret for this manifest, only store it if its self-signature is valid
|
||||
if (!m->haveSecret && !m->selfSigned)
|
||||
return WHY("Manifest is not signed, and I don't have the key. Manifest might be forged or corrupt.");
|
||||
|
||||
/* Bind BAR to data field */
|
||||
unsigned char bar[RHIZOME_BAR_BYTES];
|
||||
@ -1301,6 +1296,8 @@ int rhizome_store_bundle(rhizome_manifest *m)
|
||||
if (sqlite_exec_void_retry(&retry, "BEGIN TRANSACTION;", END) == -1)
|
||||
return WHY("Failed to begin transaction");
|
||||
|
||||
time_ms_t now = gettime_ms();
|
||||
|
||||
sqlite3_stmt *stmt;
|
||||
if ((stmt = sqlite_prepare_bind(&retry,
|
||||
"INSERT OR REPLACE INTO MANIFESTS("
|
||||
@ -1323,11 +1320,12 @@ int rhizome_store_bundle(rhizome_manifest *m)
|
||||
RHIZOME_BID_T, &m->cryptoSignPublic,
|
||||
STATIC_BLOB, m->manifestdata, m->manifest_bytes,
|
||||
INT64, m->version,
|
||||
INT64, (int64_t) gettime_ms(),
|
||||
INT64, (int64_t) now,
|
||||
STATIC_BLOB, bar, RHIZOME_BAR_BYTES,
|
||||
INT64, m->filesize,
|
||||
RHIZOME_FILEHASH_T|NUL, m->filesize > 0 ? &m->filehash : NULL,
|
||||
SID_T|NUL, m->has_author ? &m->author : NULL,
|
||||
// Only store the author if it is known to be authentic.
|
||||
SID_T|NUL, m->authorship == AUTHOR_AUTHENTIC ? &m->author : NULL,
|
||||
STATIC_TEXT, m->service,
|
||||
STATIC_TEXT|NUL, m->name,
|
||||
SID_T|NUL, m->has_sender ? &m->sender : NULL,
|
||||
@ -1341,6 +1339,7 @@ int rhizome_store_bundle(rhizome_manifest *m)
|
||||
goto rollback;
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = NULL;
|
||||
rhizome_manifest_set_inserttime(m, now);
|
||||
|
||||
// if (serverMode)
|
||||
// rhizome_sync_bundle_inserted(bar);
|
||||
@ -1414,17 +1413,17 @@ struct rhizome_list_cursor {
|
||||
const char *name;
|
||||
sid_t sender;
|
||||
sid_t recipient;
|
||||
unsigned limit;
|
||||
unsigned offset;
|
||||
// Set by calling the next() function.
|
||||
rhizome_manifest *manifest;
|
||||
size_t row;
|
||||
int64_t rowid;
|
||||
rhizome_manifest *manifest;
|
||||
size_t rowcount;
|
||||
// Private state.
|
||||
sqlite3_stmt *_statement;
|
||||
unsigned _offset;
|
||||
};
|
||||
|
||||
/* Fill in the parameters in the cursor struct prior to calling this function.
|
||||
/* The cursor struct must be zerofilled and the query parameters optionally filled in prior to
|
||||
* calling this function.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
@ -1441,23 +1440,22 @@ static int rhizome_list_open(sqlite_retry_state *retry, struct rhizome_list_curs
|
||||
strbuf_puts(b, " AND sender = @sender");
|
||||
if (!is_sid_t_any(cursor->recipient))
|
||||
strbuf_puts(b, " AND recipient = @recipient");
|
||||
strbuf_puts(b, " ORDER BY inserttime DESC OFFSET @offset");
|
||||
strbuf_puts(b, " ORDER BY inserttime DESC LIMIT -1 OFFSET @offset");
|
||||
if (strbuf_overrun(b))
|
||||
RETURN(WHYF("SQL command too long: %s", strbuf_str(b)));
|
||||
cursor->_statement = sqlite_prepare_bind(retry, strbuf_str(b));
|
||||
if (!statement)
|
||||
cursor->_statement = sqlite_prepare(retry, strbuf_str(b));
|
||||
if (cursor->_statement == NULL)
|
||||
RETURN(-1);
|
||||
int ret = 0;
|
||||
if (cursor->service && *cursor->service && sqlite_bind(retry, statement, NAMED|STATIC_TEXT, "service", cursor->service, END) == -1)
|
||||
if (sqlite_bind(retry, cursor->_statement, NAMED|INT, "@offset", cursor->_offset, END) == -1)
|
||||
goto failure;
|
||||
if (cursor->name && *cursor->name && sqlite_bind(retry, statement, NAMED|STATIC_TEXT, "name", cursor->name, END) == -1)
|
||||
if (cursor->service && sqlite_bind(retry, cursor->_statement, NAMED|STATIC_TEXT, "@service", cursor->service, END) == -1)
|
||||
goto failure;
|
||||
if (!is_sid_t_any(cursor->sender) && sqlite_bind(retry, statement, NAMED|SID_T, "sender", &cursor->sender, END) == -1)
|
||||
if (cursor->name && sqlite_bind(retry, cursor->_statement, NAMED|STATIC_TEXT, "@name", cursor->name, END) == -1)
|
||||
goto failure;
|
||||
if (!is_sid_t_any(cursor->recipient) && sqlite_bind(retry, statement, NAMED|SID_T, "recipient", &cursor->recipient, END) == -1)
|
||||
if (!is_sid_t_any(cursor->sender) && sqlite_bind(retry, cursor->_statement, NAMED|SID_T, "@sender", &cursor->sender, END) == -1)
|
||||
goto failure;
|
||||
if (!is_sid_t_any(cursor->recipient) && sqlite_bind(retry, cursor->_statement, NAMED|SID_T, "@recipient", &cursor->recipient, END) == -1)
|
||||
goto failure;
|
||||
if (sqlite_bind(retry, statement, NAMED|INT, "offset", cursor->offset + cursor->_row, END) == -1)
|
||||
goto cleanup;
|
||||
cursor->manifest = NULL;
|
||||
RETURN(0);
|
||||
OUT();
|
||||
@ -1473,9 +1471,8 @@ static int rhizome_list_next(sqlite_retry_state *retry, struct rhizome_list_curs
|
||||
IN();
|
||||
if (cursor->_statement == NULL && rhizome_list_open(retry, cursor) == -1)
|
||||
RETURN(-1);
|
||||
if (cursor->limit && cursor->_row >= cursor->limit)
|
||||
RETURN(NULL);
|
||||
while (sqlite_step_retry(retry, cursor->_statement) == SQLITE_ROW) {
|
||||
++cursor->_offset;
|
||||
if (cursor->manifest) {
|
||||
rhizome_manifest_free(cursor->manifest);
|
||||
cursor->manifest = NULL;
|
||||
@ -1487,21 +1484,14 @@ static int rhizome_list_next(sqlite_retry_state *retry, struct rhizome_list_curs
|
||||
assert(sqlite3_column_type(cursor->_statement, 3) == SQLITE_INTEGER);
|
||||
assert(sqlite3_column_type(cursor->_statement, 4) == SQLITE_TEXT || sqlite3_column_type(cursor->_statement, 4) == SQLITE_NULL);
|
||||
assert(sqlite3_column_type(cursor->_statement, 5) == SQLITE_INTEGER);
|
||||
rhizome_manifest *m = cursor->manifest = rhizome_new_manifest();
|
||||
if (m == NULL)
|
||||
RETURN(-1);
|
||||
const char *q_manifestid = (const char *) sqlite3_column_text(cursor->_statement, 0);
|
||||
const char *manifestblob = (char *) sqlite3_column_blob(cursor->_statement, 1);
|
||||
size_t manifestblobsize = sqlite3_column_bytes(cursor->_statement, 1); // must call after sqlite3_column_blob()
|
||||
int64_t q_version = sqlite3_column_int64(cursor->_statement, 2);
|
||||
int64_t q_inserttime = sqlite3_column_int64(cursor->_statement, 3);
|
||||
const char *q_author = (const char *) sqlite3_column_text(cursor->_statement, 4);
|
||||
int64_t rowid = sqlite3_column_int64(cursor->_statement, 5);
|
||||
if (rhizome_read_manifest_file(m, manifestblob, manifestblobsize) == -1) {
|
||||
WHYF("MANIFESTS row id=%s has invalid manifest blob -- skipped", q_manifestid);
|
||||
continue;
|
||||
}
|
||||
const sid_t *author = NULL;
|
||||
cursor->rowid = sqlite3_column_int64(cursor->_statement, 5);
|
||||
sid_t *author = NULL;
|
||||
if (q_author) {
|
||||
author = alloca(sizeof *author);
|
||||
if (str_to_sid_t(author, q_author) == -1) {
|
||||
@ -1509,8 +1499,11 @@ static int rhizome_list_next(sqlite_retry_state *retry, struct rhizome_list_curs
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (rhizome_fill_manifest(m, NULL, author, NULL) == -1) {
|
||||
WHYF("MANIFESTS row id=%s has invalid manifest -- skipped", q_manifestid);
|
||||
rhizome_manifest *m = cursor->manifest = rhizome_new_manifest();
|
||||
if (m == NULL)
|
||||
RETURN(-1);
|
||||
if (rhizome_read_manifest_file(m, manifestblob, manifestblobsize) == -1) {
|
||||
WHYF("MANIFESTS row id=%s has invalid manifest blob -- skipped", q_manifestid);
|
||||
continue;
|
||||
}
|
||||
if (m->version != q_version) {
|
||||
@ -1518,23 +1511,25 @@ static int rhizome_list_next(sqlite_retry_state *retry, struct rhizome_list_curs
|
||||
q_manifestid, q_version, m->version);
|
||||
continue;
|
||||
}
|
||||
if (author)
|
||||
rhizome_manifest_set_author(m, author);
|
||||
rhizome_manifest_set_inserttime(m, q_inserttime);
|
||||
if (cursor->service && !(m->service && strcasecmp(cursor->service, m->service) == 0))
|
||||
continue;
|
||||
if (!is_sid_t_any(cursor->sender) && !(m->has_sender && cmp_sid_t(&cursor->sender, &m->sender) == 0))
|
||||
continue;
|
||||
if (!is_sid_t_any(cursor->recipient) && !(m->has_recipient && cmp_sid_t(&cursor->recipient, &m->recipient) == 0))
|
||||
continue;
|
||||
rhizome_lookup_author(m);
|
||||
// Don't do rhizome_verify_author(m); too CPU expensive for a listing. Save that for when
|
||||
// the bundle is extracted or exported.
|
||||
++cursor->_row;
|
||||
++cursor->rowcount;
|
||||
RETURN(1);
|
||||
}
|
||||
RETURN(0);
|
||||
OUT();
|
||||
}
|
||||
|
||||
static void rhizome_list_release(struct rhizome_list_cursor *)
|
||||
static void rhizome_list_release(struct rhizome_list_cursor *cursor)
|
||||
{
|
||||
if (cursor->manifest) {
|
||||
rhizome_manifest_free(cursor->manifest);
|
||||
@ -1548,14 +1543,16 @@ static void rhizome_list_release(struct rhizome_list_cursor *)
|
||||
|
||||
int rhizome_list_manifests(struct cli_context *context, const char *service, const char *name,
|
||||
const char *sender_hex, const char *recipient_hex,
|
||||
int limit, int offset, char count_rows)
|
||||
size_t rowlimit, size_t rowoffset, char count_rows)
|
||||
{
|
||||
IN();
|
||||
struct rhizome_list_cursor cursor;
|
||||
bzero(&cursor, sizeof cursor);
|
||||
if (sender_hex && *sender_hex && str_to_sid_t(&cursor->sender, sender_hex) == -1)
|
||||
cursor.service = service && service[0] ? service : NULL;
|
||||
cursor.name = name && name[0] ? name : NULL;
|
||||
if (sender_hex && *sender_hex && str_to_sid_t(&cursor.sender, sender_hex) == -1)
|
||||
RETURN(WHYF("Invalid sender SID: %s", sender_hex));
|
||||
if (recipient_hex && *recipient_hex && str_to_sid_t(&cursor->recipient, recipient_hex) == -1)
|
||||
if (recipient_hex && *recipient_hex && str_to_sid_t(&cursor.recipient, recipient_hex) == -1)
|
||||
RETURN(WHYF("Invalid recipient SID: %s", recipient_hex));
|
||||
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
|
||||
if (rhizome_list_open(&retry, &cursor) == -1)
|
||||
@ -1575,33 +1572,42 @@ int rhizome_list_manifests(struct cli_context *context, const char *service, con
|
||||
"recipient",
|
||||
"name"
|
||||
};
|
||||
cli_columns(context, 13, names);
|
||||
cli_columns(context, NELS(names), names);
|
||||
while (rhizome_list_next(&retry, &cursor) == 1) {
|
||||
cli_put_long(context, cursor.rowid, ":");
|
||||
cli_put_string(context, m->service, ":");
|
||||
cli_put_hexvalue(context, m->cryptoSignPublic.binary, sizeof m->cryptoSignPublic.binary, ":");
|
||||
cli_put_long(context, m->version, ":");
|
||||
cli_put_long(context, m->has_date ? m->date : 0, ":");
|
||||
cli_put_long(context, q_inserttime, ":");
|
||||
cli_put_hexvalue(context, m->has_author ? m->author.binary : NULL, sizeof m->author.binary, ":");
|
||||
cli_put_long(context, from_here, ":");
|
||||
rhizome_manifest *m = cursor.manifest;
|
||||
assert(m->filesize != RHIZOME_SIZE_UNSET);
|
||||
cli_put_long(context, m->filesize, ":");
|
||||
cli_put_hexvalue(context, m->filesize ? m->filehash.binary : NULL, sizeof m->filehash.binary, ":");
|
||||
cli_put_hexvalue(context, m->has_sender ? m->sender.binary : NULL, sizeof m->sender.binary, ":");
|
||||
cli_put_hexvalue(context, m->has_recipient ? m->recipient.binary : NULL, sizeof m->recipient.binary, ":");
|
||||
cli_put_string(context, m->name, "\n");
|
||||
if (cursor.rowcount < rowoffset)
|
||||
continue;
|
||||
if (rowlimit == 0 || cursor.rowcount <= rowlimit) {
|
||||
rhizome_lookup_author(m);
|
||||
cli_put_long(context, cursor.rowid, ":");
|
||||
cli_put_string(context, m->service, ":");
|
||||
cli_put_hexvalue(context, m->cryptoSignPublic.binary, sizeof m->cryptoSignPublic.binary, ":");
|
||||
cli_put_long(context, m->version, ":");
|
||||
cli_put_long(context, m->has_date ? m->date : 0, ":");
|
||||
cli_put_long(context, m->inserttime, ":");
|
||||
switch (m->authorship) {
|
||||
case AUTHOR_LOCAL:
|
||||
case AUTHOR_AUTHENTIC:
|
||||
cli_put_hexvalue(context, m->author.binary, sizeof m->author.binary, ":");
|
||||
cli_put_long(context, 1, ":");
|
||||
break;
|
||||
default:
|
||||
cli_put_string(context, NULL, ":");
|
||||
cli_put_long(context, 0, ":");
|
||||
break;
|
||||
}
|
||||
cli_put_long(context, m->filesize, ":");
|
||||
cli_put_hexvalue(context, m->filesize ? m->filehash.binary : NULL, sizeof m->filehash.binary, ":");
|
||||
cli_put_hexvalue(context, m->has_sender ? m->sender.binary : NULL, sizeof m->sender.binary, ":");
|
||||
cli_put_hexvalue(context, m->has_recipient ? m->recipient.binary : NULL, sizeof m->recipient.binary, ":");
|
||||
cli_put_string(context, m->name, "\n");
|
||||
} else if (!count_rows)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret==0 && count_rows){
|
||||
while (sqlite_step_retry(&retry, statement) == SQLITE_ROW)
|
||||
++rows;
|
||||
}
|
||||
cli_row_count(context, rows);
|
||||
|
||||
cleanup:
|
||||
sqlite3_finalize(statement);
|
||||
RETURN(ret);
|
||||
rhizome_list_release(&cursor);
|
||||
cli_row_count(context, cursor.rowcount);
|
||||
RETURN(0);
|
||||
OUT();
|
||||
}
|
||||
|
||||
@ -1703,9 +1709,9 @@ int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found)
|
||||
rhizome_manifest_set_author(blob_m, &author);
|
||||
}
|
||||
// check that we can re-author this manifest
|
||||
if (rhizome_extract_privatekey(blob_m, NULL)){
|
||||
rhizome_authenticate_author(blob_m);
|
||||
if (m->authorship != AUTHOR_AUTHENTIC)
|
||||
goto next;
|
||||
}
|
||||
*found = blob_m;
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("Found duplicate payload, %s", q_manifestid);
|
||||
@ -1738,7 +1744,7 @@ static int unpack_manifest_row(rhizome_manifest *m, sqlite3_stmt *statement)
|
||||
}
|
||||
if (m->version != q_version)
|
||||
WARNF("Version mismatch, manifest is %"PRId64", database is %"PRId64, m->version, q_version);
|
||||
m->inserttime = q_inserttime;
|
||||
rhizome_manifest_set_inserttime(m, q_inserttime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -222,13 +222,12 @@ static int rhizome_direct_addfile_end(struct http_request *hr)
|
||||
return 0;
|
||||
}
|
||||
// If manifest template did not specify a service field, then by default it is "file".
|
||||
if (!rhizome_is_bk_none(&config.rhizome.api.addfile.bundle_secret_key))
|
||||
rhizome_apply_bundle_secret(m, &config.rhizome.api.addfile.bundle_secret_key);
|
||||
if (m->service == NULL)
|
||||
rhizome_manifest_set_service(m, RHIZOME_SERVICE_FILE);
|
||||
sid_t *author = NULL;
|
||||
if (!is_sid_t_any(config.rhizome.api.addfile.default_author))
|
||||
author = &config.rhizome.api.addfile.default_author;
|
||||
rhizome_bk_t bsk = config.rhizome.api.addfile.bundle_secret_key;
|
||||
if (rhizome_fill_manifest(m, r->data_file_name, author, &bsk)) {
|
||||
const sid_t *author = is_sid_t_any(config.rhizome.api.addfile.default_author) ? NULL : &config.rhizome.api.addfile.default_author;
|
||||
if (rhizome_fill_manifest(m, r->data_file_name, author)) {
|
||||
rhizome_manifest_free(m);
|
||||
rhizome_direct_clear_temporary_files(r);
|
||||
http_request_simple_response(&r->http, 500, "Internal Error: Could not fill manifest");
|
||||
|
@ -114,7 +114,6 @@ struct rhizome_fetch_candidate queue3[4];
|
||||
struct rhizome_fetch_candidate queue4[2];
|
||||
struct rhizome_fetch_candidate queue5[2];
|
||||
|
||||
#define NELS(a) (sizeof (a) / sizeof *(a))
|
||||
#define slotno(slot) (int)((struct rhizome_fetch_queue *)(slot) - &rhizome_fetch_queues[0])
|
||||
|
||||
/* Static allocation of the queue structures. Must be in order of ascending log_size_threshold.
|
||||
|
@ -637,13 +637,13 @@ int rhizome_stat_file(rhizome_manifest *m, const char *filepath)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rhizome_write_derive_key(rhizome_manifest *m, rhizome_bk_t *bsk, struct rhizome_write *write)
|
||||
static int rhizome_write_derive_key(rhizome_manifest *m, struct rhizome_write *write)
|
||||
{
|
||||
if (m->payloadEncryption != PAYLOAD_ENCRYPTED)
|
||||
return 0;
|
||||
|
||||
// if the manifest specifies encryption, make sure we can generate the payload key and encrypt the contents as we go
|
||||
if (rhizome_derive_key(m, bsk))
|
||||
if (rhizome_derive_payload_key(m))
|
||||
return -1;
|
||||
|
||||
if (config.debug.rhizome)
|
||||
@ -664,7 +664,7 @@ int rhizome_write_open_manifest(struct rhizome_write *write, rhizome_manifest *m
|
||||
if (rhizome_open_write(write, NULL, m->filesize, RHIZOME_PRIORITY_DEFAULT))
|
||||
return -1;
|
||||
|
||||
if (rhizome_write_derive_key(m, NULL, write))
|
||||
if (rhizome_write_derive_key(m, write))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@ -1083,13 +1083,13 @@ static int write_file(struct rhizome_read *read, const char *filepath){
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_derive_key(rhizome_manifest *m, rhizome_bk_t *bsk, struct rhizome_read *read_state)
|
||||
static int read_derive_key(rhizome_manifest *m, struct rhizome_read *read_state)
|
||||
{
|
||||
read_state->crypt = m->payloadEncryption == PAYLOAD_ENCRYPTED;
|
||||
if (read_state->crypt){
|
||||
// if the manifest specifies encryption, make sure we can generate the payload key and encrypt
|
||||
// the contents as we go
|
||||
if (rhizome_derive_key(m, bsk)) {
|
||||
if (rhizome_derive_payload_key(m)) {
|
||||
rhizome_read_close(read_state);
|
||||
return WHY("Unable to decrypt bundle, valid key not found");
|
||||
}
|
||||
@ -1103,11 +1103,11 @@ static int read_derive_key(rhizome_manifest *m, rhizome_bk_t *bsk, struct rhizom
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rhizome_open_decrypt_read(rhizome_manifest *m, rhizome_bk_t *bsk, struct rhizome_read *read_state)
|
||||
int rhizome_open_decrypt_read(rhizome_manifest *m, struct rhizome_read *read_state)
|
||||
{
|
||||
int ret = rhizome_open_read(read_state, &m->filehash);
|
||||
if (ret == 0)
|
||||
ret = read_derive_key(m, bsk, read_state);
|
||||
ret = read_derive_key(m, read_state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1116,11 +1116,11 @@ int rhizome_open_decrypt_read(rhizome_manifest *m, rhizome_bk_t *bsk, struct rhi
|
||||
*
|
||||
* Returns -1 on error, 0 if extracted successfully, 1 if not found.
|
||||
*/
|
||||
int rhizome_extract_file(rhizome_manifest *m, const char *filepath, rhizome_bk_t *bsk)
|
||||
int rhizome_extract_file(rhizome_manifest *m, const char *filepath)
|
||||
{
|
||||
struct rhizome_read read_state;
|
||||
bzero(&read_state, sizeof read_state);
|
||||
int ret = rhizome_open_decrypt_read(m, bsk, &read_state);
|
||||
int ret = rhizome_open_decrypt_read(m, &read_state);
|
||||
if (ret == 0)
|
||||
ret = write_file(&read_state, filepath);
|
||||
rhizome_read_close(&read_state);
|
||||
@ -1185,7 +1185,7 @@ int rhizome_journal_pipe(struct rhizome_write *write, const rhizome_filehash_t *
|
||||
}
|
||||
|
||||
// open an existing journal bundle, advance the head pointer, duplicate the existing content and get ready to add more.
|
||||
int rhizome_write_open_journal(struct rhizome_write *write, rhizome_manifest *m, rhizome_bk_t *bsk, uint64_t advance_by, uint64_t new_size)
|
||||
int rhizome_write_open_journal(struct rhizome_write *write, rhizome_manifest *m, uint64_t advance_by, uint64_t new_size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -1213,7 +1213,7 @@ int rhizome_write_open_journal(struct rhizome_write *write, rhizome_manifest *m,
|
||||
goto failure;
|
||||
}
|
||||
|
||||
ret = rhizome_write_derive_key(m, bsk, write);
|
||||
ret = rhizome_write_derive_key(m, write);
|
||||
if (ret)
|
||||
goto failure;
|
||||
|
||||
@ -1225,12 +1225,12 @@ failure:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rhizome_append_journal_buffer(rhizome_manifest *m, rhizome_bk_t *bsk, uint64_t advance_by, unsigned char *buffer, size_t len)
|
||||
int rhizome_append_journal_buffer(rhizome_manifest *m, uint64_t advance_by, unsigned char *buffer, size_t len)
|
||||
{
|
||||
struct rhizome_write write;
|
||||
bzero(&write, sizeof write);
|
||||
|
||||
int ret = rhizome_write_open_journal(&write, m, bsk, advance_by, (uint64_t) len);
|
||||
int ret = rhizome_write_open_journal(&write, m, advance_by, (uint64_t) len);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
@ -1253,7 +1253,7 @@ failure:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rhizome_append_journal_file(rhizome_manifest *m, rhizome_bk_t *bsk, uint64_t advance_by, const char *filename)
|
||||
int rhizome_append_journal_file(rhizome_manifest *m, uint64_t advance_by, const char *filename)
|
||||
{
|
||||
struct stat stat;
|
||||
if (lstat(filename,&stat))
|
||||
@ -1261,7 +1261,7 @@ int rhizome_append_journal_file(rhizome_manifest *m, rhizome_bk_t *bsk, uint64_t
|
||||
|
||||
struct rhizome_write write;
|
||||
bzero(&write, sizeof write);
|
||||
int ret = rhizome_write_open_journal(&write, m, bsk, advance_by, stat.st_size);
|
||||
int ret = rhizome_write_open_journal(&write, m, advance_by, stat.st_size);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
|
@ -651,7 +651,7 @@ test_AddUpdateNoAuthor() {
|
||||
execute $servald rhizome add file $SIDB1 file1_2 file1_2.manifest
|
||||
tfw_cat --stderr
|
||||
assertExitStatus '!=' 0
|
||||
# Rhizome store contents have old payload.
|
||||
# Rhizome store contents have old payload, with the original author.
|
||||
executeOk_servald rhizome list
|
||||
assert_rhizome_list --fromhere=1 --author=$SIDB1 file1 file2
|
||||
}
|
||||
@ -664,9 +664,10 @@ test_AddUpdateNoAuthorWithSecret() {
|
||||
tfw_cat -v file1_2.manifest
|
||||
executeOk_servald rhizome add file $SIDB1 file1_2 file1_2.manifest "$file1_secret"
|
||||
tfw_cat --stderr
|
||||
# Rhizome store contents have new payload.
|
||||
# Rhizome store contents have new payload, but it has lost its author (no BK
|
||||
# field any more).
|
||||
executeOk_servald rhizome list
|
||||
assert_rhizome_list --fromhere=1 --author=$SIDB1 file1_2 file2
|
||||
assert_rhizome_list --fromhere=0 file1_2 --fromhere=1 --author=$SIDB1 file2
|
||||
}
|
||||
|
||||
doc_AddUpdateAutoVersion="Add new payload to existing manifest with automatic version"
|
||||
|
Loading…
x
Reference in New Issue
Block a user