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_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
2
Makefile.in
Executable file → Normal 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
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
|
129
overlay_mdp.c
129
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_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 */
|
||||||
|
@ -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
|
||||||
|
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 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);
|
||||||
|
Loading…
Reference in New Issue
Block a user