mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-18 02:39:44 +00:00
Extract crypto signing primitives from mdp processing
This commit is contained in:
parent
bb973e764e
commit
f1b0374b97
@ -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 \
|
||||
|
2
Makefile.in
Executable file → Normal file
2
Makefile.in
Executable file → Normal file
@ -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 \
|
||||
|
99
crypto.c
Normal file
99
crypto.c
Normal 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
17
crypto.h
Normal 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
|
109
overlay_mdp.c
109
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));
|
||||
if (crypto_verify_message(f->source, b, &len))
|
||||
RETURN(-1);
|
||||
} else if (0) DEBUG("signature check passed");
|
||||
}
|
||||
|
||||
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,42 +801,11 @@ 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);
|
||||
@ -874,30 +813,14 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
|
||||
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);
|
||||
|
||||
/* 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) {
|
||||
if (crypto_sign_message(frame->source, frame->payload->bytes, frame->payload->allocSize, &frame->payload->position)){
|
||||
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);
|
||||
RETURN(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */
|
||||
frame->modifiers=0;
|
||||
/* Copy payload body in */
|
||||
|
@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include <sqlite3.h>
|
||||
#include "sha2.h"
|
||||
#include "strbuf.h"
|
||||
#include "nacl.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef __RHIZOME_INLINE
|
||||
|
2
serval.h
2
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);
|
||||
|
Loading…
Reference in New Issue
Block a user