diff --git a/crypto.c b/crypto.c index 72ded272..bc6b7859 100644 --- a/crypto.c +++ b/crypto.c @@ -30,6 +30,22 @@ int crypto_isvalid_keypair(const sign_private_t *private_key, const sign_public_ return bcmp(test_key.public_key.binary, public_key->binary, sizeof (sign_public_t)) == 0 ? 1 : 0; } +int crypto_sign_to_sid(const sign_public_t *public_key, sid_t *sid) +{ + if (crypto_sign_ed25519_pk_to_curve25519(sid->binary, public_key->binary)) + return WHY("Failed to convert sign key to sid"); + return 0; +} + +int crypto_ismatching_sign_sid(const sign_public_t *public_key, const sid_t *sid) +{ + sid_t test_sid; + if (crypto_sign_to_sid(public_key, &test_sid)==0 + && cmp_sid_t(&test_sid, sid)==0) + return 1; + return 0; +} + // verify the signature at the end of a message, on return message_len will be reduced by the length of the signature. int crypto_verify_message(struct subscriber *subscriber, unsigned char *message, size_t *message_len) { diff --git a/crypto.h b/crypto.h index f706ea8f..a94f8ea8 100644 --- a/crypto.h +++ b/crypto.h @@ -25,5 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. int crypto_isvalid_keypair(const sign_private_t *private_key, const sign_public_t *public_key); int crypto_verify_message(struct subscriber *subscriber, unsigned char *message, size_t *message_len); +int crypto_sign_to_sid(const sign_public_t *public_key, sid_t *sid); +int crypto_ismatching_sign_sid(const sign_public_t *public_key, const sid_t *sid); #endif diff --git a/overlay_address.c b/overlay_address.c index d5c11843..fc5ac823 100644 --- a/overlay_address.c +++ b/overlay_address.c @@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "serval.h" #include "conf.h" +#include "crypto.h" #include "str.h" #include "overlay_address.h" #include "overlay_buffer.h" @@ -317,12 +318,12 @@ int overlay_broadcast_parse(struct overlay_buffer *b, struct broadcast *broadcas static int decode_sid_from_signkey(struct overlay_buffer *b, struct subscriber **subscriber) { - const uint8_t *id = ob_get_bytes_ptr(b, crypto_sign_PUBLICKEYBYTES); + const sign_public_t *id = (const sign_public_t *)ob_get_bytes_ptr(b, crypto_sign_PUBLICKEYBYTES); if (!id) return WHY("Not enough space in buffer to parse address"); sid_t sid; - if (crypto_sign_ed25519_pk_to_curve25519(sid.binary, id)) - return WHY("Failed to convert sign key to sid"); + if (crypto_sign_to_sid(id, &sid)) + return -1; struct subscriber *s = find_subscriber(sid.binary, SID_SIZE, 1); if (s && !s->id_combined){ bcopy(id, s->id_public.binary, crypto_sign_PUBLICKEYBYTES); diff --git a/overlay_mdp_keymaprequest.c b/overlay_mdp_keymaprequest.c index 7ba7f847..3fa7eb28 100644 --- a/overlay_mdp_keymaprequest.c +++ b/overlay_mdp_keymaprequest.c @@ -71,17 +71,15 @@ static int keyring_store_id(struct internal_mdp_header *header, struct overlay_b if (ob_remaining(payload) < IDENTITY_SIZE + crypto_sign_BYTES) return WHY("Truncated key mapping announcement?"); - - const uint8_t *id_public = ob_get_bytes_ptr(payload, IDENTITY_SIZE); + + const sign_public_t *id_public = (const sign_public_t *)ob_get_bytes_ptr(payload, IDENTITY_SIZE); const uint8_t *compactsignature = ob_get_bytes_ptr(payload, crypto_sign_BYTES); - if (crypto_sign_verify_detached(compactsignature, header->source->sid.binary, SID_SIZE, id_public)) + if (crypto_sign_verify_detached(compactsignature, header->source->sid.binary, SID_SIZE, id_public->binary)) return WHY("SID:SAS mapping verification signature does not verify"); // test if the signing key can be used to derive the sid - sid_t sid; - if (crypto_sign_ed25519_pk_to_curve25519(sid.binary, id_public)==0 - && memcmp(&sid, &header->source->sid, sizeof sid) == 0) + if (crypto_ismatching_sign_sid(id_public, &header->source->sid)) header->source->id_combined=1; /* now store it */ diff --git a/rhizome.h b/rhizome.h index 3667f77b..84f7a81f 100644 --- a/rhizome.h +++ b/rhizome.h @@ -159,7 +159,8 @@ typedef struct rhizome_manifest 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 - AUTHOR_AUTHENTIC // a local identity is the verified author + AUTHOR_AUTHENTIC, // a local identity is the verified author + AUTHOR_REMOTE // the author of this bundle has signed it, but isn't in our keyring } authorship; /* Whether the paylaod is encrypted or not */ diff --git a/rhizome_bundle.c b/rhizome_bundle.c index 4b494227..bc611857 100644 --- a/rhizome_bundle.c +++ b/rhizome_bundle.c @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "serval.h" #include "conf.h" +#include "crypto.h" #include "rhizome.h" #include "str.h" #include "numeric_str.h" @@ -1473,7 +1474,7 @@ struct rhizome_bundle_result rhizome_fill_manifest(rhizome_manifest *m, const ch return rhizome_bundle_result(RHIZOME_BUNDLE_STATUS_NEW); } -/* Work out the authorship status of the bundle without performing any cryptographic checks. +/* Work out the authorship status of the bundle without performing expensive cryptographic checks. * Sets the 'authorship' element and returns 1 if an author was found, 0 if not. * * @author Andrew Bettison @@ -1484,6 +1485,7 @@ int rhizome_lookup_author(rhizome_manifest *m) switch (m->authorship) { case AUTHOR_LOCAL: case AUTHOR_AUTHENTIC: + case AUTHOR_REMOTE: RETURN(1); case AUTHOR_NOT_CHECKED: DEBUGF(rhizome, "manifest %p lookup author=%s", m, alloca_tohex_sid_t(m->author)); @@ -1501,6 +1503,12 @@ int rhizome_lookup_author(rhizome_manifest *m) rhizome_manifest_set_author(m, &m->sender); m->authorship = AUTHOR_LOCAL; RETURN(1); + } else if(crypto_ismatching_sign_sid(&m->keypair.public_key, &m->sender)) { + // if the author matches the bundle id... + DEBUGF(rhizome, "sender matches manifest signature"); + m->author = m->sender; + m->authorship = AUTHOR_REMOTE; + RETURN(1); } } // fall through diff --git a/rhizome_cli.c b/rhizome_cli.c index 25c77400..29c339c5 100644 --- a/rhizome_cli.c +++ b/rhizome_cli.c @@ -780,6 +780,9 @@ static int app_rhizome_list(const struct cli_parsed *parsed, struct cli_context fromhere = 1; cli_put_hexvalue(context, m->author.binary, sizeof m->author.binary, ":"); break; + case AUTHOR_REMOTE: + cli_put_hexvalue(context, m->author.binary, sizeof m->author.binary, ":"); + break; default: cli_put_string(context, NULL, ":"); break; diff --git a/rhizome_crypto.c b/rhizome_crypto.c index d3139d5c..9727027b 100644 --- a/rhizome_crypto.c +++ b/rhizome_crypto.c @@ -162,6 +162,16 @@ static keypair *get_secret(const keyring_identity *id) return kp; } +static enum rhizome_bundle_authorship set_authentic(rhizome_manifest *m, const keyring_identity *id, const sid_t *sid) +{ + m->authorship = AUTHOR_AUTHENTIC; + m->author = *sid; + m->author_identity = id; + if (!m->haveSecret) + m->haveSecret = EXISTING_BUNDLE_ID; + return m->authorship; +} + /* * If this identity has permission to alter the bundle, then set; * - the manifest 'authorship' field to AUTHOR_AUTHENTIC @@ -223,13 +233,7 @@ static enum rhizome_bundle_authorship try_author(rhizome_manifest *m, const keyr INT64, m->rowid, END); } - - m->authorship = AUTHOR_AUTHENTIC; - m->author = *sid; - m->author_identity = id; - if (!m->haveSecret) - m->haveSecret = EXISTING_BUNDLE_ID; - return m->authorship; + return set_authentic(m, id, sid); } /* Attempt to authenticate the authorship of the given bundle, and set the 'authorship' element @@ -256,6 +260,24 @@ void rhizome_authenticate_author(rhizome_manifest *m) assert(is_sid_t_any(m->author)); + if (m->has_sender){ + sid_t test_sid; + if (crypto_sign_to_sid(&m->keypair.public_key, &test_sid)==0){ + if (cmp_sid_t(&test_sid, &m->sender)==0){ + // self signed bundle, is it ours? + keyring_identity *id = keyring_find_identity(keyring, &m->keypair.public_key); + if (id){ + set_authentic(m, id, &m->sender); + RETURNVOID; + }else{ + m->authorship = AUTHOR_REMOTE; + m->author = m->sender; + RETURNVOID; + } + } + } + } + // Optimisation: try 'sender' SID first, if present. if (m->has_sender && try_author(m, NULL, &m->sender) == AUTHOR_AUTHENTIC) RETURNVOID; @@ -277,11 +299,13 @@ void rhizome_authenticate_author(rhizome_manifest *m) case AUTHOR_LOCAL: m->authorship = try_author(m, m->author_identity, &m->author); RETURNVOID; + case AUTHOR_REMOTE: case AUTHENTICATION_ERROR: case AUTHOR_UNKNOWN: case AUTHOR_IMPOSTOR: case AUTHOR_AUTHENTIC: // work has already been done, don't repeat it + // TODO rescan keyring if more identities are unlocked?? RETURNVOID; } FATALF("m->authorship = %d", (int)m->authorship); diff --git a/rhizome_restful.c b/rhizome_restful.c index b09a7770..722cad76 100644 --- a/rhizome_restful.c +++ b/rhizome_restful.c @@ -328,6 +328,9 @@ static int restful_rhizome_bundlelist_json_content_chunk(struct http_request *hr fromhere = 1; strbuf_json_hex(b, m->author.binary, sizeof m->author.binary); break; + case AUTHOR_REMOTE: + strbuf_json_hex(b, m->author.binary, sizeof m->author.binary); + break; default: strbuf_json_null(b); break; diff --git a/tests/rhizomeops b/tests/rhizomeops index f83a10f8..21a1559f 100755 --- a/tests/rhizomeops +++ b/tests/rhizomeops @@ -1446,6 +1446,26 @@ test_ImportOwnBundle() { assert_rhizome_list --fromhere=1 --author=$SIDB2 fileB } +doc_ImportSelfSigned="Import a bundle with id matching identity" +setup_ImportSelfSigned(){ + B_IDENTITY_COUNT=1 + setup_servald + setup_rhizome + echo "Self signed" > file +} +test_ImportSelfSigned(){ + set_instance +A + executeOk_servald rhizome add file $SIDA file file.manifest '' id=$IDA sender=$SIDA + extract_stdout_manifestid BID + assert [ "$BID" = "$IDA" ] + executeOk_servald rhizome list + set_instance +B + executeOk_servald rhizome import bundle file file.manifest + executeOk_servald rhizome list + tfw_cat --stdout --stderr + #TODO assert that .author == $SIDA +} + doc_ImportCombinedBundle="Create and import combined bundle" setup_ImportCombinedBundle() { # A "combined bundle" is a single file consisting of a payload with its