From f1b0374b970bb1c256114f64a275be743d1fee1d Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Fri, 19 Oct 2012 14:54:41 +1030 Subject: [PATCH] Extract crypto signing primitives from mdp processing --- Android.mk | 1 + Makefile.in | 2 + crypto.c | 99 ++++++++++++++++++++++++++++++++++++++ crypto.h | 17 +++++++ overlay_mdp.c | 129 ++++++++++---------------------------------------- rhizome.h | 1 + serval.h | 2 - 7 files changed, 146 insertions(+), 105 deletions(-) mode change 100755 => 100644 Makefile.in create mode 100644 crypto.c create mode 100644 crypto.h diff --git a/Android.mk b/Android.mk index 0b8a534c..df2adf6d 100644 --- a/Android.mk +++ b/Android.mk @@ -11,6 +11,7 @@ SERVALD_SRC_FILES = \ serval-dna/overlay_route.c \ serval-dna/overlay_mdp.c \ serval-dna/batman.c \ + serval-dna/crypto.c \ serval-dna/ciphers.c \ serval-dna/cli.c \ serval-dna/client.c \ diff --git a/Makefile.in b/Makefile.in old mode 100755 new mode 100644 index 8964a154..b520ae6d --- a/Makefile.in +++ b/Makefile.in @@ -10,6 +10,7 @@ SRCS= $(NACL_SOURCES) \ codecs.c \ commandline.c \ conf.c \ + crypto.c \ dataformats.c \ directory_client.c \ dna_helper.c \ @@ -113,6 +114,7 @@ HDRS= fifo.h \ strbuf_helpers.h \ sha2.h \ conf.h \ + crypto.h \ log.h \ net.h \ xprintf.h \ diff --git a/crypto.c b/crypto.c new file mode 100644 index 00000000..5f19bcc0 --- /dev/null +++ b/crypto.c @@ -0,0 +1,99 @@ +#include "serval.h" +#include "overlay_address.h" +#include "crypto.h" + +// verify a signature against a public sas key. +int crypto_verify_signature(unsigned char *sas_key, + unsigned char *content, unsigned long long content_len, + unsigned char *signature_block, unsigned long long signature_len) +{ + IN(); + + if (signature_len!=SIGNATURE_BYTES) + RETURN(WHY("Invalid signature length")); + + /* reconstitute signed message by putting hash at end of signature */ + unsigned char reassembled[signature_len + content_len]; + bcopy(signature_block, reassembled, signature_len); + bcopy(content, &reassembled[signature_len], content_len); + + /* verify signature. + Note that crypto_sign_open requires m to be as large as signature, even + though it will not need the whole length eventually -- it does use the + full length and will overwrite the end of a short buffer. */ + unsigned char message[sizeof(reassembled)+64]; + unsigned long long mlen=0; + int result + =crypto_sign_edwards25519sha512batch_open(message,&mlen, + reassembled,sizeof(reassembled), + sas_key); + + if (result) { + WHY("Signature verification failed"); + 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, int *message_len) +{ + if (!subscriber->sas_valid){ + keyring_send_sas_request(subscriber); + return WHY("SAS key not currently on record, cannot verify"); + } + + *message_len -= SIGNATURE_BYTES; + + unsigned char hash[crypto_hash_sha512_BYTES]; + crypto_hash_sha512(hash,message,*message_len); + + return crypto_verify_signature(subscriber->sas_public, hash, + crypto_hash_sha512_BYTES, &message[*message_len], SIGNATURE_BYTES); +} + +// generate a signature for this raw content, copy the signature to the address requested. +int crypto_create_signature(unsigned char *key, + unsigned char *content, unsigned long long content_len, + unsigned char *signature, unsigned long long *sig_length) +{ + IN(); + + if (*sig_length < SIGNATURE_BYTES) + RETURN(WHY("Not enough space to store signature")); + + unsigned char sig[content_len + SIGNATURE_BYTES]; + /* Why does this primitive copy the whole input message? We don't want that message format, it just seems like a waste of effor to me. */ + unsigned long long length = 0; + crypto_sign_edwards25519sha512batch(sig,&length, + content,content_len, + key); + + if (length != sizeof(sig)) + RETURN(WHYF("Signing seems to have failed (%d, expected %d)",length,sizeof(sig))); + + bcopy(sig, signature, SIGNATURE_BYTES); + *sig_length=SIGNATURE_BYTES; + RETURN(0); +} + +// sign the hash of a message, adding the signature to the end of the message buffer. +int crypto_sign_message(struct subscriber *source, unsigned char *content, int buffer_len, int *content_len) +{ + if (*content_len + SIGNATURE_BYTES > buffer_len) + return WHYF("Insufficient space in message buffer to add signature. %d, need %d",buffer_len, *content_len + SIGNATURE_BYTES); + + unsigned char *key=keyring_find_sas_private(keyring, source->sid, NULL); + if (!key) + return WHY("Could not find signing key"); + + unsigned char hash[crypto_hash_sha512_BYTES]; + crypto_hash_sha512(hash, content, *content_len); + + unsigned long long sig_length = SIGNATURE_BYTES; + + int ret=crypto_create_signature(key, hash, crypto_hash_sha512_BYTES, &content[*content_len], &sig_length); + *content_len+=sig_length; + return ret; +} diff --git a/crypto.h b/crypto.h new file mode 100644 index 00000000..01929809 --- /dev/null +++ b/crypto.h @@ -0,0 +1,17 @@ + +#ifndef __SERVALD_CRYPTO_H +#define __SERVALD_CRYPTO_H + +#include "nacl.h" +#define SIGNATURE_BYTES crypto_sign_edwards25519sha512batch_BYTES + +int crypto_verify_signature(unsigned char *sas_key, + unsigned char *content, unsigned long long content_len, + unsigned char *signature_block, unsigned long long signature_len); +int crypto_verify_message(struct subscriber *subscriber, unsigned char *message, int *message_len); +int crypto_create_signature(unsigned char *key, + unsigned char *content, unsigned long long content_len, + unsigned char *signature, unsigned long long *sig_length); +int crypto_sign_message(struct subscriber *source, unsigned char *content, int buffer_len, int *content_len); + +#endif \ No newline at end of file diff --git a/overlay_mdp.c b/overlay_mdp.c index 8f88ad33..71262bac 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "overlay_address.h" #include "overlay_packet.h" #include "mdp_client.h" +#include "crypto.h" struct profile_total mdp_stats={.name="overlay_mdp_poll"}; @@ -263,7 +264,7 @@ int overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp) IN(); int len=f->payload->sizeLimit - f->payload->position; - unsigned char *b = NULL; + unsigned char *b = &f->payload->bytes[f->payload->position]; unsigned char plain_block[len+16]; /* Indicate MDP message type */ @@ -271,56 +272,25 @@ int overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp) switch(f->modifiers&OF_CRYPTO_BITS) { case 0: - /* get payload */ - b=&f->payload->bytes[f->payload->position]; + /* nothing to do, b already points to the plain text */ mdp->packetTypeAndFlags|=MDP_NOCRYPT|MDP_NOSIGN; break; + case OF_CRYPTO_CIPHERED: RETURN(WHY("decryption not implemented")); - case OF_CRYPTO_SIGNED: - { - /* This call below will dispatch the request for the SAS if we don't - already have it. In the meantime, we just drop the frame if the SAS - is not available. */ - if (!f->source->sas_valid){ - keyring_send_sas_request(f->source); - RETURN(WHY("SAS key not currently on record, cannot verify")); - } - /* get payload and following compacted signature */ - b=&f->payload->bytes[f->payload->position]; - len=f->payload->sizeLimit - f->payload->position - crypto_sign_edwards25519sha512batch_BYTES; - - /* reconstitute signature by putting hash at end of signature */ - unsigned char signature[crypto_hash_sha512_BYTES - +crypto_sign_edwards25519sha512batch_BYTES]; - bcopy(&b[len],&signature[0],64); - crypto_hash_sha512(&signature[64],b,len); - if (0) dump("hash for verification",&signature[32],crypto_hash_sha512_BYTES); - /* verify signature. - Note that crypto_sign_open requires m to be as large as signature, even - though it will not need the whole length eventually -- it does use the - full length and will overwrite the end of a short buffer. */ - unsigned char m[sizeof(signature)]; - unsigned long long mlen=0; - int result - =crypto_sign_edwards25519sha512batch_open(m,&mlen, - signature,sizeof(signature), - f->source->sas_public); - if (result) { - WHY("Signature verification failed"); - dump("data", b, len); - dump("signature", signature, sizeof(signature)); - RETURN(-1); - } else if (0) DEBUG("signature check passed"); - } + case OF_CRYPTO_SIGNED: + if (crypto_verify_message(f->source, b, &len)) + RETURN(-1); + mdp->packetTypeAndFlags|=MDP_NOCRYPT; break; + case OF_CRYPTO_CIPHERED|OF_CRYPTO_SIGNED: { - if (0) DEBUGF("crypted MDP frame for %s", alloca_tohex_sid(mdp->out.dst.sid)); + if (0) DEBUGF("crypted MDP frame for %s", alloca_tohex_sid(f->destination->sid)); - unsigned char *k=keyring_get_nm_bytes(mdp->out.dst.sid, mdp->out.src.sid); + unsigned char *k=keyring_get_nm_bytes(f->destination->sid, f->source->sid); unsigned char *nonce=&f->payload->bytes[f->payload->position]; int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES; int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES; @@ -831,73 +801,26 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, } } break; + case MDP_NOCRYPT: - /* Payload is sent unencrypted, but signed. - - To save space we do a trick where we hash the payload, and get the - signature of that, but do not send the hash itself, since that can - be reproduced (and indeed must be for verification) at the receiver's - end. - - As the signing key is implicit, and the hash is also implicit, we can - chop out part of the signature and thus save some bytes. - */ + /* Payload is sent unencrypted, but signed. */ frame->modifiers=OF_CRYPTO_SIGNED; /* Prepare payload */ - ob_makespace(frame->payload, - 1 // frame type (MDP) - +1 // MDP version - +4 // dst port - +4 // src port - +crypto_sign_edwards25519sha512batch_BYTES - +mdp->out.payload_length); - { - unsigned char *key=keyring_find_sas_private(keyring, frame->source->sid, NULL); - if (!key) { - op_free(frame); - RETURN(WHY("could not find signing key")); - } - - /* Build plain-text that includes header and hash it so that - we can sign that hash. */ - unsigned char hash[crypto_hash_sha512_BYTES]; - int plain_len = 10+mdp->out.payload_length; - unsigned char *plain = frame->payload->bytes + frame->payload->position; - - if (!plain) - return WHY("Unable to allocate space for payload and signature"); - - /* MDP version 1 */ - ob_append_byte(frame->payload,0x01); - ob_append_byte(frame->payload,0x01); - /* Destination port */ - ob_append_ui32(frame->payload,mdp->out.src.port); - ob_append_ui32(frame->payload,mdp->out.dst.port); - ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length); - - /* now hash it */ - crypto_hash_sha512(hash,plain,plain_len); - - unsigned char signature[crypto_hash_sha512_BYTES - +crypto_sign_edwards25519sha512batch_BYTES]; - unsigned long long sig_len=0; - crypto_sign_edwards25519sha512batch(signature,&sig_len, - hash,crypto_hash_sha512_BYTES, - key); - if (!sig_len) { - op_free(frame); - RETURN(WHY("Signing MDP frame failed")); - } - - if (0){ - dump("payload", plain, plain_len); - dump("signature", signature, sizeof(signature)); - } - /* chop hash from end of signature since it has to be recomputed - at the far end, anyway. */ - ob_append_bytes(frame->payload,&signature[0],64); + /* MDP version 1 */ + ob_append_byte(frame->payload,0x01); + ob_append_byte(frame->payload,0x01); + /* Destination port */ + ob_append_ui32(frame->payload,mdp->out.src.port); + ob_append_ui32(frame->payload,mdp->out.dst.port); + ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length); + ob_makespace(frame->payload,SIGNATURE_BYTES); + + if (crypto_sign_message(frame->source, frame->payload->bytes, frame->payload->allocSize, &frame->payload->position)){ + op_free(frame); + RETURN(-1); } break; + case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */ frame->modifiers=0; /* Copy payload body in */ diff --git a/rhizome.h b/rhizome.h index 35f1c078..e8d823f5 100644 --- a/rhizome.h +++ b/rhizome.h @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "sha2.h" #include "strbuf.h" +#include "nacl.h" #include #ifndef __RHIZOME_INLINE diff --git a/serval.h b/serval.h index 6c241618..746e2a4a 100644 --- a/serval.h +++ b/serval.h @@ -632,8 +632,6 @@ int rhizome_server_get_fds(struct pollfd *fds,int *fdcount,int fdmax); int rhizome_saw_voice_traffic(); int overlay_saw_mdp_containing_frame(struct overlay_frame *f, time_ms_t now); -#include "nacl.h" - int serval_packetvisualise(XPRINTF xpf, const char *message, const unsigned char *packet, size_t len); int rhizome_fetching_get_fds(struct pollfd *fds,int *fdcount,int fdmax);