Extract crypto signing primitives from mdp processing

This commit is contained in:
Jeremy Lakeman 2012-10-19 14:54:41 +10:30
parent bb973e764e
commit f1b0374b97
7 changed files with 146 additions and 105 deletions

View File

@ -11,6 +11,7 @@ SERVALD_SRC_FILES = \
serval-dna/overlay_route.c \ serval-dna/overlay_route.c \
serval-dna/overlay_mdp.c \ serval-dna/overlay_mdp.c \
serval-dna/batman.c \ serval-dna/batman.c \
serval-dna/crypto.c \
serval-dna/ciphers.c \ serval-dna/ciphers.c \
serval-dna/cli.c \ serval-dna/cli.c \
serval-dna/client.c \ serval-dna/client.c \

2
Makefile.in Executable file → Normal file
View File

@ -10,6 +10,7 @@ SRCS= $(NACL_SOURCES) \
codecs.c \ codecs.c \
commandline.c \ commandline.c \
conf.c \ conf.c \
crypto.c \
dataformats.c \ dataformats.c \
directory_client.c \ directory_client.c \
dna_helper.c \ dna_helper.c \
@ -113,6 +114,7 @@ HDRS= fifo.h \
strbuf_helpers.h \ strbuf_helpers.h \
sha2.h \ sha2.h \
conf.h \ conf.h \
crypto.h \
log.h \ log.h \
net.h \ net.h \
xprintf.h \ xprintf.h \

99
crypto.c Normal file
View File

@ -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;
}

17
crypto.h Normal file
View File

@ -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

View File

@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "overlay_address.h" #include "overlay_address.h"
#include "overlay_packet.h" #include "overlay_packet.h"
#include "mdp_client.h" #include "mdp_client.h"
#include "crypto.h"
struct profile_total mdp_stats={.name="overlay_mdp_poll"}; 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(); IN();
int len=f->payload->sizeLimit - f->payload->position; 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]; unsigned char plain_block[len+16];
/* Indicate MDP message type */ /* 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) { switch(f->modifiers&OF_CRYPTO_BITS) {
case 0: case 0:
/* get payload */ /* nothing to do, b already points to the plain text */
b=&f->payload->bytes[f->payload->position];
mdp->packetTypeAndFlags|=MDP_NOCRYPT|MDP_NOSIGN; mdp->packetTypeAndFlags|=MDP_NOCRYPT|MDP_NOSIGN;
break; break;
case OF_CRYPTO_CIPHERED: case OF_CRYPTO_CIPHERED:
RETURN(WHY("decryption not implemented")); 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. case OF_CRYPTO_SIGNED:
Note that crypto_sign_open requires m to be as large as signature, even if (crypto_verify_message(f->source, b, &len))
though it will not need the whole length eventually -- it does use the RETURN(-1);
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");
}
mdp->packetTypeAndFlags|=MDP_NOCRYPT; mdp->packetTypeAndFlags|=MDP_NOCRYPT;
break; break;
case OF_CRYPTO_CIPHERED|OF_CRYPTO_SIGNED: 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]; unsigned char *nonce=&f->payload->bytes[f->payload->position];
int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES; int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES;
int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES; int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
@ -831,73 +801,26 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
} }
} }
break; break;
case MDP_NOCRYPT: case MDP_NOCRYPT:
/* Payload is sent unencrypted, but signed. /* 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.
*/
frame->modifiers=OF_CRYPTO_SIGNED; frame->modifiers=OF_CRYPTO_SIGNED;
/* Prepare payload */ /* Prepare payload */
ob_makespace(frame->payload, /* MDP version 1 */
1 // frame type (MDP) ob_append_byte(frame->payload,0x01);
+1 // MDP version ob_append_byte(frame->payload,0x01);
+4 // dst port /* Destination port */
+4 // src port ob_append_ui32(frame->payload,mdp->out.src.port);
+crypto_sign_edwards25519sha512batch_BYTES ob_append_ui32(frame->payload,mdp->out.dst.port);
+mdp->out.payload_length); ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length);
{ ob_makespace(frame->payload,SIGNATURE_BYTES);
unsigned char *key=keyring_find_sas_private(keyring, frame->source->sid, NULL);
if (!key) { if (crypto_sign_message(frame->source, frame->payload->bytes, frame->payload->allocSize, &frame->payload->position)){
op_free(frame); op_free(frame);
RETURN(WHY("could not find signing key")); RETURN(-1);
}
/* 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);
} }
break; break;
case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */ case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */
frame->modifiers=0; frame->modifiers=0;
/* Copy payload body in */ /* Copy payload body in */

View File

@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <sqlite3.h> #include <sqlite3.h>
#include "sha2.h" #include "sha2.h"
#include "strbuf.h" #include "strbuf.h"
#include "nacl.h"
#include <sys/stat.h> #include <sys/stat.h>
#ifndef __RHIZOME_INLINE #ifndef __RHIZOME_INLINE

View File

@ -632,8 +632,6 @@ int rhizome_server_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int rhizome_saw_voice_traffic(); int rhizome_saw_voice_traffic();
int overlay_saw_mdp_containing_frame(struct overlay_frame *f, time_ms_t now); 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 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); int rhizome_fetching_get_fds(struct pollfd *fds,int *fdcount,int fdmax);