Issue #17, overhaul manifest author crypto logic

Add test case for new feature of the "rhizome add" command: if the author SID
is not specified (empty arg) then it searches the keyring for the author.

Removed "authorSid" argument from several functions that also take a struct
rhizome_manifest * arg, since the author, if known, is now supplied in the
struct.

Improve return value handling and refactored some rhizome crypto code.
This commit is contained in:
Andrew Bettison 2012-10-11 17:58:24 +10:30
parent f4d0b7a16a
commit 3f1f495d68
8 changed files with 255 additions and 152 deletions

View File

@ -1042,29 +1042,75 @@ int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_
if (rhizome_manifest_get(m, "id", NULL, 0) == NULL) { if (rhizome_manifest_get(m, "id", NULL, 0) == NULL) {
if (rhizome_manifest_bind_id(m) == -1) { if (rhizome_manifest_bind_id(m) == -1) {
rhizome_manifest_free(m); rhizome_manifest_free(m);
m = NULL;
return WHY("Could not bind manifest to an ID"); return WHY("Could not bind manifest to an ID");
} }
} else if (bskhex[0]) { } else {
/* Modifying an existing bundle. If the caller provides the bundle secret key, then ensure that // Modifying an existing bundle. If an author SID is supplied, we must ensure that it is valid,
it corresponds to the bundle's public key (its bundle ID), otherwise the caller cannot modify // ie, that identity has permission to alter the bundle. If no author SID is supplied but a BSK
the bundle. */ // is supplied, then use that to alter the bundle. Otherwise, search the keyring for an
// identity with permission to alter the bundle.
if (!is_sid_any(m->author)) {
// Check that the given author has permission to alter the bundle, and extract the secret
// bundle key if so.
int result = rhizome_extract_privatekey(m);
switch (result) {
case -1:
rhizome_manifest_free(m);
return WHY("error in rhizome_extract_privatekey()");
case 0:
break;
case 1:
if (bskhex[0])
break;
rhizome_manifest_free(m);
return WHY("Manifest does not have BK field");
case 2:
rhizome_manifest_free(m);
return WHY("Author unknown");
case 3:
rhizome_manifest_free(m);
return WHY("Author does not have a Rhizome Secret");
case 4:
rhizome_manifest_free(m);
return WHY("Author does not have permission to modify manifest");
default:
rhizome_manifest_free(m);
return WHYF("Unknown result from rhizome_extract_privatekey(): %d", result);
}
}
if (bskhex[0]) {
if (m->haveSecret) {
// 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, m->cryptoSignSecret, RHIZOME_BUNDLE_KEY_BYTES) != 0)
WARNF("Supplied bundle secret key is invalid -- ignoring");
} else {
// The caller provided the bundle secret key, so ensure that it corresponds to the bundle's
// public key (its bundle ID), otherwise it won't work.
memcpy(m->cryptoSignSecret, bsk, RHIZOME_BUNDLE_KEY_BYTES); memcpy(m->cryptoSignSecret, bsk, RHIZOME_BUNDLE_KEY_BYTES);
if (rhizome_verify_bundle_privatekey(m) == -1) { if (rhizome_verify_bundle_privatekey(m) == -1) {
rhizome_manifest_free(m); rhizome_manifest_free(m);
m = NULL;
return WHY("Incorrect BID secret key."); return WHY("Incorrect BID secret key.");
} }
} else if (!authorSidHex[0]) { }
/* In order to modify an existing bundle, the author must be known. */ }
// If we still don't know the bundle secret or the author, then search for an author.
if (!m->haveSecret && is_sid_any(m->author)) {
int result = rhizome_find_bundle_author(m);
if (result != 0) {
rhizome_manifest_free(m); rhizome_manifest_free(m);
m = NULL; switch (result) {
return WHY("Author SID not specified"); case -1:
} else if (rhizome_extract_privatekey(m, authorSid) == -1) { return WHY("error in rhizome_find_bundle_author()");
/* Only the original author can modify an existing bundle. */ case 4:
rhizome_manifest_free(m); return WHY("Manifest does not have BK field");
m = NULL; case 1:
return WHY("Could not extract BID secret key. Does the manifest have a BK?"); return WHY("No author found");
default:
return WHYF("Unknown result from rhizome_find_bundle_author(): %d", result);
}
}
}
} }
int encryptP = 0; // TODO Determine here whether payload is to be encrypted. int encryptP = 0; // TODO Determine here whether payload is to be encrypted.
if (rhizome_manifest_bind_file(m, filepath, encryptP)) { if (rhizome_manifest_bind_file(m, filepath, encryptP)) {

View File

@ -50,7 +50,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
get - 8 bit variable value get - 8 bit variable value
*/ */
#define SID_SIZE 32 #define SID_SIZE 32 // == crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES
#define SAS_SIZE 32 // == crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES #define SAS_SIZE 32 // == crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES
#define DID_MINSIZE 5 #define DID_MINSIZE 5
#define DID_MAXSIZE 32 #define DID_MAXSIZE 32

View File

@ -157,9 +157,7 @@ int rhizome_manifest_bind_id(rhizome_manifest *m_in)
manifests on receiver nodes works easily. We might implement something that strips the id 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 variable out of the manifest when sending it, or some other scheme to avoid sending all the
extra bytes. */ extra bytes. */
char id[RHIZOME_MANIFEST_ID_STRLEN + 1]; rhizome_manifest_set(m_in, "id", alloca_tohex_bid(m_in->cryptoSignPublic));
rhizome_bytes_to_hex_upper(m_in->cryptoSignPublic, id, RHIZOME_MANIFEST_ID_BYTES);
rhizome_manifest_set(m_in, "id", id);
if (!is_sid_any(m_in->author)) { if (!is_sid_any(m_in->author)) {
/* Set the BK using the provided authorship information. /* Set the BK using the provided authorship information.
Serval Security Framework defines BK as being: Serval Security Framework defines BK as being:

View File

@ -234,7 +234,7 @@ int rhizome_add_manifest(rhizome_manifest *m_in,int ttl);
void rhizome_bytes_to_hex_upper(unsigned const char *in, char *out, int byteCount); void rhizome_bytes_to_hex_upper(unsigned const char *in, char *out, int byteCount);
int rhizome_find_privatekey(rhizome_manifest *m); int rhizome_find_privatekey(rhizome_manifest *m);
rhizome_signature *rhizome_sign_hash(rhizome_manifest *m, const unsigned char *authorSid); int rhizome_sign_hash(rhizome_manifest *m, rhizome_signature *out);
__RHIZOME_INLINE int sqlite_code_ok(int code) __RHIZOME_INLINE int sqlite_code_ok(int code)
{ {
@ -299,9 +299,9 @@ int rhizome_bk_xor(const unsigned char *authorSid, // binary
unsigned char bkin[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES], unsigned char bkin[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES],
unsigned char bkout[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES]); unsigned char bkout[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES]);
unsigned char *rhizome_bundle_shared_secret(rhizome_manifest *m); unsigned char *rhizome_bundle_shared_secret(rhizome_manifest *m);
int rhizome_extract_privatekey(rhizome_manifest *m, const unsigned char *authorSid); int rhizome_extract_privatekey(rhizome_manifest *m);
int rhizome_verify_bundle_privatekey(rhizome_manifest *m); int rhizome_verify_bundle_privatekey(rhizome_manifest *m);
int rhizome_is_self_signed(rhizome_manifest *m); int rhizome_find_bundle_author(rhizome_manifest *m);
int rhizome_queue_ignore_manifest(rhizome_manifest *m, int rhizome_queue_ignore_manifest(rhizome_manifest *m,
struct sockaddr_in *peerip,int timeout); struct sockaddr_in *peerip,int timeout);
int rhizome_ignore_manifest_check(rhizome_manifest *m, int rhizome_ignore_manifest_check(rhizome_manifest *m,

View File

@ -570,22 +570,17 @@ int rhizome_manifest_pack_variables(rhizome_manifest *m)
*/ */
int rhizome_manifest_selfsign(rhizome_manifest *m) int rhizome_manifest_selfsign(rhizome_manifest *m)
{ {
if (!m->haveSecret) return WHY("Need private key to sign manifest"); if (!m->haveSecret)
rhizome_signature *sig = rhizome_sign_hash(m, m->cryptoSignSecret); return WHY("Need private key to sign manifest");
if (!sig) return WHY("rhizome_sign_hash() failed."); rhizome_signature sig;
if (rhizome_sign_hash(m, &sig) == -1)
return WHY("rhizome_sign_hash() failed");
/* Append signature to end of manifest data */ /* Append signature to end of manifest data */
if (sig->signatureLength+m->manifest_bytes>MAX_MANIFEST_BYTES) { if (sig.signatureLength + m->manifest_bytes > MAX_MANIFEST_BYTES)
free(sig); return WHY("Manifest plus signatures is too long");
return WHY("Manifest plus signatures is too long."); bcopy(&sig.signature[0], &m->manifestdata[m->manifest_bytes], sig.signatureLength);
} m->manifest_bytes += sig.signatureLength;
m->manifest_all_bytes = m->manifest_bytes;
bcopy(&sig->signature[0],&m->manifestdata[m->manifest_bytes],sig->signatureLength);
m->manifest_bytes+=sig->signatureLength;
m->manifest_all_bytes=m->manifest_bytes;
free(sig);
return 0; return 0;
} }

View File

@ -38,123 +38,187 @@ int rhizome_manifest_createid(rhizome_manifest *m)
return WHY("Failed to create keypair for manifest ID."); return WHY("Failed to create keypair for manifest ID.");
} }
/* /* Given a Rhizome Secret (RS) and bundle ID (BID), XOR a bundle key 'bkin' (private or public) with
Return -1 if an error occurs. * RS##BID.
Return 0 if the author's private key is located and the XOR is performed successfully. *
Return 1 if the author's identity is not in the keyring. * @author Andrew Bettison <andrew@servalproject.com>
Return 2 if the author's identity is in the keyring but has no rhizome secret. */
*/ static void rhizome_bk_xor_rs(
const unsigned char *rs,
size_t rs_len,
unsigned char bid[crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES],
unsigned char bkin[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES],
unsigned char bkout[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES]
)
{
IN();
int combined_len = rs_len + crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES;
unsigned char buffer[combined_len];
bcopy(&rs[0], &buffer[0], rs_len);
bcopy(&bid[0], &buffer[rs_len], crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES);
unsigned char hash[crypto_hash_sha512_BYTES];
crypto_hash_sha512(hash,buffer,combined_len);
int i;
for(i = 0; i != crypto_sign_edwards25519sha512batch_SECRETKEYBYTES; ++i)
bkout[i] = bkin[i] ^ hash[i];
bzero(buffer, combined_len);
bzero(hash, sizeof hash);
OUT();
}
/* 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.
* Returns 3 if the author's identity is in the keyring but has no rhizome 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.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int rhizome_bk_xor(const unsigned char *authorSid, // binary int rhizome_bk_xor(const unsigned char *authorSid, // binary
unsigned char bid[crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES], unsigned char bid[crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES],
unsigned char bkin[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES], unsigned char bkin[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES],
unsigned char bkout[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES]) unsigned char bkout[crypto_sign_edwards25519sha512batch_SECRETKEYBYTES])
{ {
IN();
if (crypto_sign_edwards25519sha512batch_SECRETKEYBYTES > crypto_hash_sha512_BYTES) if (crypto_sign_edwards25519sha512batch_SECRETKEYBYTES > crypto_hash_sha512_BYTES)
{ RETURN(WHY("BK needs to be longer than it can be")); } return WHY("BK needs to be longer than it can be");
int cn=0,in=0,kp=0; int cn=0,in=0,kp=0;
if (!keyring_find_sid(keyring,&cn,&in,&kp,authorSid)) { if (!keyring_find_sid(keyring,&cn,&in,&kp,authorSid)) {
if (debug & DEBUG_RHIZOME) DEBUG("identity not in keyring"); if (debug & DEBUG_RHIZOME)
{ RETURN(1); } DEBUGF("identity sid=%s is not in keyring", alloca_tohex_sid(authorSid));
return 2;
} }
kp = keyring_identity_find_keytype(keyring, cn, in, KEYTYPE_RHIZOME); kp = keyring_identity_find_keytype(keyring, cn, in, KEYTYPE_RHIZOME);
if (kp == -1) { if (kp == -1) {
if (debug & DEBUG_RHIZOME) DEBUG("identity has no Rhizome Secret"); if (debug & DEBUG_RHIZOME)
RETURN(2); DEBUGF("identity sid=%s has no Rhizome Secret", alloca_tohex_sid(authorSid));
return 3;
} }
int rs_len=keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key_len; int rs_len = keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key_len;
if (rs_len<16||rs_len>1024) if (rs_len < 16 || rs_len > 1024)
{ RETURN(WHYF("invalid Rhizome Secret: length=%d", rs_len)); } return WHYF("identity sid=%s has invalid Rhizome Secret: length=%d", alloca_tohex_sid(authorSid), rs_len);
unsigned char *rs=keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key; const unsigned char *rs = keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key;
int combined_len=rs_len+crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES; if (debug & DEBUG_RHIZOME)
unsigned char buffer[combined_len]; DEBUGF("using identity sid=%s", alloca_tohex_sid(authorSid));
bcopy(&rs[0],&buffer[0],rs_len); rhizome_bk_xor_rs(rs, rs_len, bid, bkin, bkout);
bcopy(&bid[0],&buffer[rs_len],crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES); return 0;
unsigned char hash[crypto_hash_sha512_BYTES];
crypto_hash_sha512(hash,buffer,combined_len);
int i;
for(i = 0; i != crypto_sign_edwards25519sha512batch_SECRETKEYBYTES; ++i)
bkout[i]=bkin[i]^hash[i];
bzero(&buffer[0],combined_len);
bzero(&hash[0],crypto_hash_sha512_BYTES);
RETURN(0);
} }
/* See if the manifest has a BK entry, and if so, use it to obtain the /* See if the manifest has a BK entry, and if so, use it to obtain the private key for the BID. The
private key for the BID. Decoding BK's relies on the provision of * manifest's 'author' field must contain the (binary) SID of the purported author of the bundle,
the appropriate SID. * which is used to look up the author's rhizome secret in the keyring.
*
Return 0 if the private key was extracted, 1 if not. Return -1 if an error occurs. * Returns 0 if a valid private key was extracted, with the private key in the manifest
* 'cryptoSignSecret' field and the 'haveSecret' field set to 1.
XXX Note that this function is not able to verify that the private key *
is correct, as there is no exposed API in NaCl for calculating the * Returns 1 if the manifest does not have a BK field.
public key from a cryptosign private key. We thus have to trust that *
the supplied SID is correct. * Returns 2 if the author is not found in the keyring (not unlocked?) -- this return code from
* rhizome_bk_xor().
*/ *
int rhizome_extract_privatekey(rhizome_manifest *m, const unsigned char *authorSid) * 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)
{ {
IN(); IN();
char *bk = rhizome_manifest_get(m, "BK", NULL, 0); char *bk = rhizome_manifest_get(m, "BK", NULL, 0);
if (!bk) { RETURN(WHY("missing BK field")); } if (!bk)
RETURN(1);
unsigned char bkBytes[RHIZOME_BUNDLE_KEY_BYTES]; unsigned char bkBytes[RHIZOME_BUNDLE_KEY_BYTES];
if (fromhexstr(bkBytes, bk, RHIZOME_BUNDLE_KEY_BYTES) == -1) if (fromhexstr(bkBytes, bk, RHIZOME_BUNDLE_KEY_BYTES) == -1)
{ RETURN(WHYF("invalid BK field: %s", bk)); } RETURN(WHYF("invalid BK field: %s", bk));
switch (rhizome_bk_xor(authorSid, m->cryptoSignPublic, bkBytes, m->cryptoSignSecret)) { int result = rhizome_bk_xor(m->author, m->cryptoSignPublic, bkBytes, m->cryptoSignSecret);
case -1: if (result == 0) {
RETURN(WHY("rhizome_bk_xor() failed")); int verified = rhizome_verify_bundle_privatekey(m);
case 0: if (verified == 0)
RETURN(rhizome_verify_bundle_privatekey(m)); RETURN(0); // bingo
if (verified == -1)
result = WHY("rhizome_bk_xor() failed");
else {
if (debug & DEBUG_RHIZOME)
DEBUGF("identity sid=%s is not the author of bundle with BK=%s", alloca_tohex_sid(m->author), bk);
result = 3;
} }
RETURN(WHYF("Rhizome secret for %s not found. (Have you unlocked the identity?)", alloca_tohex_sid(authorSid))); }
memset(m->cryptoSignSecret, 0, sizeof m->cryptoSignSecret);
RETURN(result);
} }
/* /* Discover if the given manifest was created (signed) by any unlocked identity currently in the
Test to see if the given manifest was created (signed) by any unlocked identity currently in the * keyring.
keyring. *
- Returns -1 if an error occurs, eg, the manifest contains an invalid BK field. * Returns 0 if an identity is found with permission to alter the bundle, after setting the manifest
- Return 0 if the manifest's BK field was produced by any currently unlocked SID. * 'author' field to the SID of the identity and the manifest 'cryptoSignSecret' field to the bundle
- Returns 1 if the manifest has no BK field. * secret key and the 'haveSecret' field to 1.
- Returns 2 otherwise. *
Currently unused; was called from rhizome_list_manifests() to compute the now-defunct * Returns 1 if no identity in the keyring is the author of this bundle.
".selfsigned" column, but that made the Rhizome List view too slow in the Serval Mesh app. *
See issue servalproject/serval-dna#17. * Returns 4 if the manifest has no BK field.
@author Andrew Bettison <andrew@servalproject.com> *
* Returns -1 if an error occurs, eg, the manifest contains an invalid BK field.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/ */
int rhizome_is_self_signed(rhizome_manifest *m) int rhizome_find_bundle_author(rhizome_manifest *m)
{ {
IN(); IN();
char *bk = rhizome_manifest_get(m, "BK", NULL, 0); char *bk = rhizome_manifest_get(m, "BK", NULL, 0);
if (!bk) { if (!bk) {
if (debug & DEBUG_RHIZOME) DEBUGF("missing BK field"); if (debug & DEBUG_RHIZOME)
RETURN(1); DEBUGF("missing BK field");
RETURN(4);
} }
unsigned char bkBytes[RHIZOME_BUNDLE_KEY_BYTES]; unsigned char bkBytes[RHIZOME_BUNDLE_KEY_BYTES];
if (fromhexstr(bkBytes, bk, RHIZOME_BUNDLE_KEY_BYTES) == -1) if (fromhexstr(bkBytes, bk, RHIZOME_BUNDLE_KEY_BYTES) == -1)
{ RETURN(WHYF("invalid BK field: %s", bk)); } RETURN(WHYF("invalid BK field: %s", bk));
int cn = 0, in = 0, kp = 0; int cn = 0, in = 0, kp = 0;
for (; keyring_next_identity(keyring, &cn, &in, &kp); ++kp) { for (; keyring_next_identity(keyring, &cn, &in, &kp); ++kp) {
const unsigned char *authorSid = keyring->contexts[cn]->identities[in]->keypairs[kp]->public_key; const unsigned char *authorSid = keyring->contexts[cn]->identities[in]->keypairs[kp]->public_key;
//if (debug & DEBUG_RHIZOME) DEBUGF("identity %s", alloca_tohex(authorSid, SID_SIZE)); //if (debug & DEBUG_RHIZOME) DEBUGF("try author identity sid=%s", alloca_tohex(authorSid, SID_SIZE));
int rkp = keyring_identity_find_keytype(keyring, cn, in, KEYTYPE_RHIZOME); int rkp = keyring_identity_find_keytype(keyring, cn, in, KEYTYPE_RHIZOME);
if (rkp != -1) { if (rkp != -1) {
switch (rhizome_bk_xor(authorSid, m->cryptoSignPublic, bkBytes, m->cryptoSignSecret)) { int rs_len = keyring->contexts[cn]->identities[in]->keypairs[rkp]->private_key_len;
case -1: if (rs_len < 16 || rs_len > 1024)
RETURN(WHY("rhizome_bk_xor() failed")); RETURN(WHYF("invalid Rhizome Secret: length=%d", rs_len));
case 0: const unsigned char *rs = keyring->contexts[cn]->identities[in]->keypairs[rkp]->private_key;
if (rhizome_verify_bundle_privatekey(m) == 0) rhizome_bk_xor_rs(rs, rs_len, m->cryptoSignPublic, bkBytes, m->cryptoSignSecret);
int verified = rhizome_verify_bundle_privatekey(m);
if (verified == 0) {
memcpy(m->author, authorSid, sizeof m->author);
if (debug & DEBUG_RHIZOME)
DEBUGF("found bundle author sid=%s", alloca_tohex_sid(m->author));
RETURN(0); // bingo RETURN(0); // bingo
break; }
memset(m->cryptoSignSecret, 0, sizeof m->cryptoSignSecret);
if (verified == -1)
RETURN(WHY("rhizome_verify_bundle_privatekey() failed"));
} }
} }
} if (debug & DEBUG_RHIZOME)
RETURN(2); // not self signed DEBUG("bundle author not found");
RETURN(1);
} }
/* Verify the validity of the manifest's sccret key. /* Verify the validity of the manifest's secret key, ie, is the given manifest's 'cryptoSignSecret'
Return 0 if valid, 1 if not. Return -1 if an error occurs. * field actually the secret key corresponding to the public key in 'cryptoSignPublic'?
XXX This is a pretty ugly way to do it, but NaCl offers no API to * Return 0 if valid, 1 if not. Return -1 if an error occurs.
do this cleanly. *
* XXX This is a pretty ugly way to do it, but NaCl offers no API to do this cleanly.
*/ */
int rhizome_verify_bundle_privatekey(rhizome_manifest *m) int rhizome_verify_bundle_privatekey(rhizome_manifest *m)
{ {
@ -194,45 +258,32 @@ int rhizome_verify_bundle_privatekey(rhizome_manifest *m)
#endif //!ge25519 #endif //!ge25519
} }
rhizome_signature *rhizome_sign_hash(rhizome_manifest *m, const unsigned char *authorSid) int rhizome_sign_hash(rhizome_manifest *m, rhizome_signature *out)
{ {
IN(); IN();
unsigned char *hash=m->manifesthash; unsigned char *hash = m->manifesthash;
unsigned char *publicKeyBytes=m->cryptoSignPublic; unsigned char *publicKeyBytes = m->cryptoSignPublic;
if (!m->haveSecret && rhizome_extract_privatekey(m))
if (!m->haveSecret && rhizome_extract_privatekey(m, authorSid)) { RETURN(WHY("Cannot find secret key to sign manifest data."));
WHY("Cannot find secret key to sign manifest data.");
RETURN(NULL);
}
/* Signature is formed by running crypto_sign_edwards25519sha512batch() on the /* Signature is formed by running crypto_sign_edwards25519sha512batch() on the
hash of the manifest. The signature actually contains the hash, so to save hash of the manifest. The signature actually contains the hash, so to save
space we cut the hash out of the signature. */ space we cut the hash out of the signature. */
unsigned char signatureBuffer[crypto_sign_edwards25519sha512batch_BYTES+crypto_hash_sha512_BYTES]; unsigned char signatureBuffer[crypto_sign_edwards25519sha512batch_BYTES + crypto_hash_sha512_BYTES];
unsigned long long sigLen=0; unsigned long long sigLen = 0;
int mLen=crypto_hash_sha512_BYTES; int mLen = crypto_hash_sha512_BYTES;
int r = crypto_sign_edwards25519sha512batch(signatureBuffer, &sigLen, &hash[0], mLen, m->cryptoSignSecret);
int r=crypto_sign_edwards25519sha512batch(signatureBuffer,&sigLen, if (r)
&hash[0],mLen,m->cryptoSignSecret); RETURN(WHY("crypto_sign_edwards25519sha512batch() failed."));
if (r) {
WHY("crypto_sign() failed.");
RETURN(NULL);
}
rhizome_signature *out=calloc(sizeof(rhizome_signature),1);
/* Here we use knowledge of the internal structure of the signature block /* Here we use knowledge of the internal structure of the signature block
to remove the hash, since that is implicitly transported, thus reducing the to remove the hash, since that is implicitly transported, thus reducing the
actual signature size down to 64 bytes. actual signature size down to 64 bytes.
We do then need to add the public key of the signatory on. */ We do then need to add the public key of the signatory on. */
bcopy(&signatureBuffer[0],&out->signature[1],32); bcopy(&signatureBuffer[0], &out->signature[1], 32);
bcopy(&signatureBuffer[96],&out->signature[33],32); bcopy(&signatureBuffer[96], &out->signature[33], 32);
bcopy(&publicKeyBytes[0],&out->signature[65],crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES); bcopy(&publicKeyBytes[0], &out->signature[65], crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES);
out->signatureLength=65+crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES; out->signatureLength = 65 + crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES;
out->signature[0] = out->signatureLength;
out->signature[0]=out->signatureLength; RETURN(0);
RETURN(out);
} }
typedef struct manifest_signature_block_cache { typedef struct manifest_signature_block_cache {

View File

@ -914,9 +914,9 @@ void dump_stack();
_this_call.totals=&_aggregate_stats; \ _this_call.totals=&_aggregate_stats; \
fd_func_enter(&_this_call); fd_func_enter(&_this_call);
#define OUT() fd_func_exit(&_this_call); #define OUT() fd_func_exit(&_this_call)
#define RETURN(X) { OUT() return(X); } #define RETURN(X) do { OUT(); return (X); } while (0);
#define RETURNNULL { OUT() return(NULL); } #define RETURNNULL do { OUT(); return (NULL); } while (0);

View File

@ -366,6 +366,19 @@ test_AddUpdateNewVersion() {
assert_rhizome_list file1_2@$SIDB1 file2@$SIDB1 assert_rhizome_list file1_2@$SIDB1 file2@$SIDB1
} }
doc_AddUpdateDiscoverAuthor="Add new payload to manifest with author discovery"
setup_AddUpdateDiscoverAuthor() {
setup_AddUpdateNewVersion
}
test_AddUpdateDiscoverAuthor() {
tfw_cat -v file1_2.manifest
executeOk_servald rhizome add file '' '' file1_2 file1_2.manifest "$file1_secret"
tfw_cat --stderr
# Rhizome store contents have new payload.
executeOk_servald rhizome list ''
assert_rhizome_list file1_2@$SIDB1 file2@$SIDB1
}
doc_AddUpdateNoAuthor="Cannot add new payload to authorless manifest" doc_AddUpdateNoAuthor="Cannot add new payload to authorless manifest"
setup_AddUpdateNoAuthor() { setup_AddUpdateNoAuthor() {
setup_AddUpdateNewVersion setup_AddUpdateNewVersion