Create authored bundle from bundle secret

Improve the logic in rhizome_fill_manifest() to handle the case where
the secret and author are both supplied, by setting the BK field so the
secret can be recovered from the manifest later
This commit is contained in:
Andrew Bettison 2014-11-14 13:01:44 +10:30
parent e743e4d7f9
commit 65d6005cbf
3 changed files with 96 additions and 27 deletions

View File

@ -1166,34 +1166,63 @@ int rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t
else if (m->has_sender)
rhizome_manifest_set_author(m, &m->sender);
/* Set the bundle ID (public key) and secret key.
/* Fill in the bundle secret and bundle ID.
*/
if (!m->haveSecret && !m->has_id) {
int valid_haveSecret = 0;
switch (m->haveSecret) {
case SECRET_UNKNOWN:
valid_haveSecret = 1;
// If the Bundle Id is already known, then derive the bundle secret from BK if known.
// If there is no Bundle Id, then create a new bundle Id and secret from scratch.
if (m->has_id) {
if (config.debug.rhizome)
DEBUGF("discover secret for bundle bid=%s", alloca_tohex_rhizome_bid_t(m->cryptoSignPublic));
rhizome_authenticate_author(m);
break;
}
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)
// fall through to set the BK field...
case NEW_BUNDLE_ID:
valid_haveSecret = 1;
assert(m->has_id);
if (m->authorship != ANONYMOUS) {
if (config.debug.rhizome)
DEBUGF("set BK field for bid=%s", alloca_tohex_rhizome_bid_t(m->cryptoSignPublic));
rhizome_manifest_add_bundle_key(m); // set the BK field
} else {
}
break;
case EXISTING_BUNDLE_ID:
valid_haveSecret = 1;
// If modifying an existing bundle, try to discover the bundle secret key and the author.
assert(m->has_id);
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?
}
if (!valid_haveSecret)
FATALF("haveSecret = %d", m->haveSecret);
/* Service field must already be set.
*/
if (m->service == NULL)
return WHYF("missing 'service'");
if (config.debug.rhizome)
DEBUGF("manifest service=%s", m->service);
/* Fill in 'date' field to current time unless already set.
*/
if (!m->has_date) {
rhizome_manifest_set_date(m, (int64_t) gettime_ms());
if (config.debug.rhizome)
DEBUGF("missing 'date', set default date=%"PRItime_ms_t, m->date);
}
/* Fill in 'name' field if service=file.
*/
if (strcasecmp(RHIZOME_SERVICE_FILE, m->service) == 0) {
if (m->name) {
if (config.debug.rhizome)
@ -1204,7 +1233,9 @@ int rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t
DEBUGF("manifest missing 'name'");
}
// Anything sent from one person to another should be considered private and encrypted by default.
/* Fill in 'crypt' field. Anything sent from one person to another should be considered private
* and encrypted by default.
*/
if ( m->payloadEncryption == PAYLOAD_CRYPT_UNKNOWN
&& m->has_sender
&& m->has_recipient

View File

@ -233,58 +233,65 @@ enum rhizome_secret_disposition find_rhizome_secret(const sid_t *authorSidp, siz
}
/* 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.
* accordingly. If the manifest has no BK field, then no authentication can be performed.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
void rhizome_authenticate_author(rhizome_manifest *m)
{
IN();
if (!m->has_bundle_key)
if (config.debug.rhizome)
DEBUGF("authenticate author for bid=%s", m->has_id ? alloca_tohex_rhizome_bid_t(m->cryptoSignPublic) : "(none)");
if (!m->has_bundle_key) {
if (config.debug.rhizome)
DEBUG(" no BK field");
RETURNVOID;
}
switch (m->authorship) {
case ANONYMOUS:
if (config.debug.rhizome)
DEBUGF(" manifest[%d] author unknown", m->manifest_record_number);
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));
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");
DEBUGF(" author has Rhizome secret");
switch (rhizome_bk2secret(&m->cryptoSignPublic, rs, rs_len, m->bundle_key.binary, m->cryptoSignSecret)) {
case 0:
if (config.debug.rhizome)
DEBUGF("authentic");
DEBUGF(" is authentic");
m->authorship = AUTHOR_AUTHENTIC;
if (!m->haveSecret)
m->haveSecret = EXISTING_BUNDLE_ID;
break;
case -1:
if (config.debug.rhizome)
DEBUGF("error");
DEBUGF(" error");
m->authorship = AUTHENTICATION_ERROR;
break;
default:
if (config.debug.rhizome)
DEBUGF("impostor");
DEBUGF(" author is impostor");
m->authorship = AUTHOR_IMPOSTOR;
break;
}
break;
case IDENTITY_NOT_FOUND:
if (config.debug.rhizome)
DEBUGF("author not found");
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");
DEBUGF(" author has no Rhizome secret");
m->authorship = AUTHENTICATION_ERROR;
break;
default:
@ -340,9 +347,6 @@ int rhizome_apply_bundle_secret(rhizome_manifest *m, const rhizome_bk_t *bsk)
/* Discover if the given manifest was created (signed) by any unlocked identity currently in the
* keyring.
*
* This function must only be called if the bundle secret is not known. If it is known, then
* use
*
* 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.
@ -367,16 +371,23 @@ int rhizome_apply_bundle_secret(rhizome_manifest *m, const rhizome_bk_t *bsk)
void rhizome_find_bundle_author_and_secret(rhizome_manifest *m)
{
IN();
if (m->authorship != ANONYMOUS)
if (config.debug.rhizome)
DEBUGF("Finding author and secret for bid=%s", m->has_id ? alloca_tohex_rhizome_bid_t(m->cryptoSignPublic) : "(none)");
if (m->authorship != ANONYMOUS) {
if (config.debug.rhizome)
DEBUGF(" bundle is anonymous");
RETURNVOID;
}
assert(is_sid_t_any(m->author));
if (!m->has_bundle_key)
if (!m->has_bundle_key) {
if (config.debug.rhizome)
DEBUGF(" bundle has no BK field");
RETURNVOID;
}
keyring_iterator it;
keyring_iterator_start(keyring, &it);
keypair *kp;
while((kp=keyring_next_keytype(&it, KEYTYPE_RHIZOME))){
while ((kp = keyring_next_keytype(&it, KEYTYPE_RHIZOME))) {
size_t rs_len = kp->private_key_len;
if (rs_len < 16 || rs_len > 1024) {
// should a bad key be fatal??
@ -393,12 +404,11 @@ void rhizome_find_bundle_author_and_secret(rhizome_manifest *m)
FATALF("Bundle secret does not match derived secret");
} else
m->haveSecret = EXISTING_BUNDLE_ID;
keypair *kp_sid = keyring_identity_keytype(it.identity, KEYTYPE_CRYPTOBOX);
if (kp_sid){
if (kp_sid) {
const sid_t *authorSidp = (const sid_t *) kp_sid->public_key;
if (config.debug.rhizome)
DEBUGF("found bundle author sid=%s", alloca_tohex_sid_t(*authorSidp));
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.
@ -409,13 +419,12 @@ void rhizome_find_bundle_author_and_secret(rhizome_manifest *m)
INT64, m->rowid,
END);
}
RETURNVOID; // bingo
}
}
assert(m->authorship == ANONYMOUS);
if (config.debug.rhizome)
DEBUG("bundle author not found");
DEBUG(" bundle author not found");
OUT();
}

View File

@ -809,6 +809,35 @@ test_AddUpdateNoAuthorWithPassphrase() {
assert diff file1_2 file1x
}
doc_AddUpdateWithPassphrase="Add and update bundle using secret passphrase"
setup_AddUpdateWithPassphrase() {
setup_servald
setup_rhizome
create_file file1 1k
create_file file1_2 2k
pass='On the Ning Nang Nong'
}
test_AddUpdateWithPassphrase() {
executeOk_servald rhizome add file $SIDB1 file1 file1.manifest "#$pass"
tfw_cat --stdout --stderr
assert_stdout_add_file file1 .author=$SIDB1
assert_manifest_complete file1.manifest
extract_manifest_id BID file1.manifest
executeOk_servald rhizome list
assert_rhizome_list --fromhere=1 file1
executeOk_servald rhizome add file $SIDB1 file1_2 file1_2.manifest "#$pass"
tfw_cat --stdout --stderr
assert_stdout_add_file file1_2 .author=$SIDB1
assert_manifest_complete file1_2.manifest
extract_manifest_id BID2 file1.manifest
assert [ "$BID" = "$BID2" ]
executeOk_servald rhizome list
assert_rhizome_list --fromhere=1 file1_2
executeOk_servald rhizome extract file $BID file1x
tfw_cat --stdout --stderr
assert diff file1_2 file1x
}
doc_EncryptedPayload="Add and extract an encrypted payload"
setup_EncryptedPayload() {
setup_servald