mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-29 15:43:56 +00:00
Move SAS key storage into subscriber structure
This commit is contained in:
parent
9a7c18c9f6
commit
b72c01518b
196
keyring.c
196
keyring.c
@ -1133,16 +1133,61 @@ unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid,
|
||||
RETURN(WHYNULL("Identity lacks SAS"));
|
||||
}
|
||||
|
||||
struct sid_sas_mapping {
|
||||
unsigned char sid[SID_SIZE];
|
||||
unsigned char sas_public[SAS_SIZE];
|
||||
time_ms_t last_request_time_in_ms;
|
||||
unsigned char validP;
|
||||
};
|
||||
static int keyring_store_sas(overlay_mdp_frame *req){
|
||||
struct subscriber *subscriber = find_subscriber(req->in.src.sid,SID_SIZE,1);
|
||||
|
||||
if (subscriber->sas_valid){
|
||||
if (debug & DEBUG_KEYRING)
|
||||
DEBUGF("Ignoring SID:SAS mapping for %s, already have one", alloca_tohex_sid(req->in.src.sid));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug & DEBUG_KEYRING)
|
||||
DEBUGF("Received SID:SAS mapping, %d bytes", req->out.payload_length);
|
||||
|
||||
unsigned keytype = req->out.payload[0];
|
||||
|
||||
if (keytype!=KEYTYPE_CRYPTOSIGN)
|
||||
return WHYF("Ignoring SID:SAS mapping with unsupported key type %u", keytype);
|
||||
|
||||
#define MAX_SID_SAS_MAPPINGS 1024
|
||||
int sid_sas_mapping_count=0;
|
||||
struct sid_sas_mapping sid_sas_mappings[MAX_SID_SAS_MAPPINGS];
|
||||
if (req->out.payload_length < 1 + SAS_SIZE)
|
||||
return WHY("Truncated key mapping announcement?");
|
||||
|
||||
unsigned char plain[req->out.payload_length];
|
||||
unsigned long long plain_len=0;
|
||||
unsigned char *sas_public=&req->out.payload[1];
|
||||
unsigned char *compactsignature = &req->out.payload[1+SAS_SIZE];
|
||||
int siglen=SID_SIZE+crypto_sign_edwards25519sha512batch_BYTES;
|
||||
unsigned char signature[siglen];
|
||||
|
||||
/* reconstitute signed SID for verification */
|
||||
bcopy(&compactsignature[0],&signature[0],32);
|
||||
bcopy(&req->out.src.sid[0],&signature[32],SID_SIZE);
|
||||
bcopy(&compactsignature[32],&signature[32+SID_SIZE],32);
|
||||
|
||||
int r=crypto_sign_edwards25519sha512batch_open(plain,&plain_len,
|
||||
signature,siglen,
|
||||
sas_public);
|
||||
if (r)
|
||||
return WHY("SID:SAS mapping verification signature does not verify");
|
||||
/* These next two tests should never be able to fail, but let's just check anyway. */
|
||||
if (plain_len != SID_SIZE)
|
||||
return WHY("SID:SAS mapping signed block is wrong length");
|
||||
if (memcmp(plain, req->out.src.sid, SID_SIZE) != 0)
|
||||
return WHY("SID:SAS mapping signed block is for wrong SID");
|
||||
|
||||
/* now store it */
|
||||
bcopy(sas_public, subscriber->sas_public, SAS_SIZE);
|
||||
subscriber->sas_valid=1;
|
||||
subscriber->sas_last_request=-1;
|
||||
|
||||
if (debug & DEBUG_KEYRING)
|
||||
DEBUGF("Stored SID:SAS mapping, SID=%s to SAS=%s",
|
||||
alloca_tohex_sid(req->out.src.sid),
|
||||
alloca_tohex_sas(subscriber->sas_public)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int keyring_mapping_request(keyring_file *k, overlay_mdp_frame *req)
|
||||
{
|
||||
@ -1193,123 +1238,28 @@ int keyring_mapping_request(keyring_file *k, overlay_mdp_frame *req)
|
||||
);
|
||||
return overlay_mdp_dispatch(req,0,NULL,0);
|
||||
} else {
|
||||
/* It's probably a response. */
|
||||
if (debug & DEBUG_KEYRING)
|
||||
DEBUGF("Received SID:SAS mapping, %d bytes", req->out.payload_length);
|
||||
unsigned keytype = req->out.payload[0];
|
||||
|
||||
switch (keytype) {
|
||||
case KEYTYPE_CRYPTOSIGN:
|
||||
{
|
||||
if (req->out.payload_length < 1 + SAS_SIZE)
|
||||
return WHY("Truncated key mapping announcement?");
|
||||
unsigned char plain[req->out.payload_length];
|
||||
unsigned long long plain_len=0;
|
||||
unsigned char *sas_public=&req->out.payload[1];
|
||||
unsigned char *compactsignature = &req->out.payload[1+SAS_SIZE];
|
||||
/* reconstitute signed SID for verification */
|
||||
int siglen=SID_SIZE+crypto_sign_edwards25519sha512batch_BYTES;
|
||||
unsigned char signature[siglen];
|
||||
bcopy(&compactsignature[0],&signature[0],32);
|
||||
bcopy(&req->out.src.sid[0],&signature[32],SID_SIZE);
|
||||
bcopy(&compactsignature[32],&signature[32+SID_SIZE],32);
|
||||
|
||||
int r=crypto_sign_edwards25519sha512batch_open(plain,&plain_len,
|
||||
signature,siglen,
|
||||
sas_public);
|
||||
if (r)
|
||||
return WHY("SID:SAS mapping verification signature does not verify");
|
||||
/* These next two tests should never be able to fail, but let's just check anyway. */
|
||||
if (plain_len != SID_SIZE)
|
||||
return WHY("SID:SAS mapping signed block is wrong length");
|
||||
if (memcmp(plain, req->out.src.sid, SID_SIZE) != 0)
|
||||
return WHY("SID:SAS mapping signed block is for wrong SID");
|
||||
|
||||
/* work out where to put it */
|
||||
int i;
|
||||
for (i = 0; i < sid_sas_mapping_count; ++i)
|
||||
if (memcmp(req->out.src.sid, sid_sas_mappings[i].sid, SID_SIZE) == 0)
|
||||
break;
|
||||
if (i >= MAX_SID_SAS_MAPPINGS)
|
||||
i = random() % MAX_SID_SAS_MAPPINGS;
|
||||
else if (i >= sid_sas_mapping_count)
|
||||
i = sid_sas_mapping_count++;
|
||||
|
||||
/* now put it */
|
||||
bcopy(&req->out.src.sid, &sid_sas_mappings[i].sid[0], SID_SIZE);
|
||||
bcopy(sas_public, &sid_sas_mappings[i].sas_public[0], SAS_SIZE);
|
||||
if (debug & DEBUG_KEYRING)
|
||||
DEBUGF("Stored SID:SAS mapping #%d of %d, SID=%s to SAS=%s",
|
||||
i, sid_sas_mapping_count,
|
||||
alloca_tohex_sid(sid_sas_mappings[i].sid),
|
||||
alloca_tohex_sas(sid_sas_mappings[i].sas_public)
|
||||
);
|
||||
sid_sas_mappings[i].validP=1;
|
||||
sid_sas_mappings[i].last_request_time_in_ms = -1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARNF("Ignoring SID:SAS mapping with unsupported key type %u", keytype);
|
||||
break;
|
||||
}
|
||||
return keyring_store_sas(req);
|
||||
}
|
||||
return WHY("Not implemented");
|
||||
}
|
||||
|
||||
unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid)
|
||||
{
|
||||
/* Main issue here is that we need to have the public SAS key for
|
||||
this sender. This needs to be cached somewhere (possibly persistently,
|
||||
or not depending on a persons paranoia level, as having a SID:SAS
|
||||
mapping implies that at least machine to machine contact has occurred
|
||||
with that identity.
|
||||
|
||||
See the Serval Security Framework document for a discussion of some of the
|
||||
privacy and security issues that vex a persistent store.
|
||||
|
||||
For now we will just use a non-persistent cache for safety (and it happens
|
||||
to be easy to implement as well :)
|
||||
*/
|
||||
IN();
|
||||
int i;
|
||||
int keyring_send_sas_request(struct subscriber *subscriber){
|
||||
if (subscriber->sas_valid)
|
||||
return 0;
|
||||
|
||||
time_ms_t now = gettime_ms();
|
||||
for(i=0;i<sid_sas_mapping_count;i++)
|
||||
{
|
||||
if (memcmp(sid,sid_sas_mappings[i].sid,SID_SIZE)) continue;
|
||||
if (sid_sas_mappings[i].validP) {
|
||||
if (debug & DEBUG_KEYRING)
|
||||
DEBUGF("Found SAS for SID=%s", alloca_tohex_sid(sid));
|
||||
RETURN(sid_sas_mappings[i].sas_public);
|
||||
}
|
||||
/* Don't flood the network with mapping requests */
|
||||
if (sid_sas_mappings[i].last_request_time_in_ms != -1 && now < sid_sas_mappings[i].last_request_time_in_ms + 100) {
|
||||
INFO("Too soon to ask for SAS mapping again");
|
||||
RETURN(NULL);
|
||||
}
|
||||
/* we can request again, so fall out to where we do that.
|
||||
i is set to this mapping, so the request process will update this
|
||||
record. */
|
||||
break;
|
||||
}
|
||||
if (debug & DEBUG_KEYRING)
|
||||
DEBUGF("Requesting SAS mapping for SID=%s", alloca_tohex_sid(sid));
|
||||
|
||||
/* allocate mapping slot or replace one at random, depending on how full things
|
||||
are */
|
||||
if (i==sid_sas_mapping_count) {
|
||||
if (i>=MAX_SID_SAS_MAPPINGS) i=random()%MAX_SID_SAS_MAPPINGS;
|
||||
else sid_sas_mapping_count++;
|
||||
|
||||
if (now < subscriber->sas_last_request + 100){
|
||||
if (debug & DEBUG_KEYRING)
|
||||
INFO("Too soon to ask for SAS mapping again");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* pre-populate mapping slot */
|
||||
bcopy(&sid[0], &sid_sas_mappings[i].sid[0], SID_SIZE);
|
||||
bzero(&sid_sas_mappings[i].sas_public, SAS_SIZE);
|
||||
sid_sas_mappings[i].validP=0;
|
||||
sid_sas_mappings[i].last_request_time_in_ms = now;
|
||||
|
||||
|
||||
if (!my_subscriber)
|
||||
RETURN(WHYNULL("couldn't request SAS (I don't know who I am)"));
|
||||
return WHY("couldn't request SAS (I don't know who I am)");
|
||||
|
||||
if (debug & DEBUG_KEYRING)
|
||||
DEBUGF("Requesting SAS mapping for SID=%s", alloca_tohex_sid(subscriber->sid));
|
||||
|
||||
// always send our sid in full, it's likely this is a new peer
|
||||
my_subscriber->send_full = 1;
|
||||
@ -1319,7 +1269,7 @@ unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid)
|
||||
memset(&mdp,0,sizeof(overlay_mdp_frame));
|
||||
|
||||
mdp.packetTypeAndFlags=MDP_TX;
|
||||
bcopy(sid,mdp.out.dst.sid,SID_SIZE);
|
||||
bcopy(subscriber->sid,mdp.out.dst.sid,SID_SIZE);
|
||||
mdp.out.dst.port=MDP_PORT_KEYMAPREQUEST;
|
||||
mdp.out.src.port=MDP_PORT_KEYMAPREQUEST;
|
||||
bcopy(my_subscriber->sid,mdp.out.src.sid,SID_SIZE);
|
||||
@ -1327,10 +1277,12 @@ unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid)
|
||||
mdp.out.payload[0]=KEYTYPE_CRYPTOSIGN;
|
||||
|
||||
if (overlay_mdp_dispatch(&mdp, 0 /* system generated */, NULL, 0))
|
||||
RETURN(WHYNULL("Failed to send SAS resolution request"));
|
||||
return WHY("Failed to send SAS resolution request");
|
||||
if (debug & DEBUG_KEYRING)
|
||||
DEBUGF("Dispatched SAS resolution request");
|
||||
RETURN(NULL);
|
||||
|
||||
subscriber->sas_last_request=now;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int keyring_find_sid(const keyring_file *k, int *cn, int *in, int *kp, const unsigned char *sid)
|
||||
|
@ -230,7 +230,11 @@ int set_reachable(struct subscriber *subscriber, int reachable){
|
||||
break;
|
||||
}
|
||||
|
||||
// Hacky layering violation...
|
||||
/* Pre-emptively send a sas request */
|
||||
if (!subscriber->sas_valid && reachable!=REACHABLE_SELF && reachable!=REACHABLE_NONE && reachable!=REACHABLE_BROADCAST)
|
||||
keyring_send_sas_request(subscriber);
|
||||
|
||||
// Hacky layering violation... send our identity to a directory service
|
||||
if (subscriber==directory_service &&
|
||||
(old_value==REACHABLE_NONE||old_value==REACHABLE_BROADCAST) &&
|
||||
(reachable!=REACHABLE_NONE&&reachable!=REACHABLE_BROADCAST)
|
||||
@ -249,13 +253,11 @@ int reachable_unicast(struct subscriber *subscriber, overlay_interface *interfac
|
||||
return WHYF("Subscriber %s is already known for overlay routing", alloca_tohex_sid(subscriber->sid));
|
||||
|
||||
subscriber->interface = interface;
|
||||
set_reachable(subscriber, REACHABLE_UNICAST);
|
||||
subscriber->address.sin_family = AF_INET;
|
||||
subscriber->address.sin_addr = addr;
|
||||
subscriber->address.sin_port = htons(port);
|
||||
set_reachable(subscriber, REACHABLE_UNICAST);
|
||||
|
||||
/* Pre-emptively check if we have their sas in memory, or send a request */
|
||||
keyring_find_sas_public(keyring, subscriber->sid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,12 @@ struct subscriber{
|
||||
struct sockaddr_in address;
|
||||
};
|
||||
};
|
||||
|
||||
// public signing key details
|
||||
unsigned char sas_public[SAS_SIZE];
|
||||
time_ms_t sas_last_request;
|
||||
unsigned char sas_valid;
|
||||
|
||||
};
|
||||
|
||||
struct broadcast{
|
||||
|
@ -287,10 +287,12 @@ int overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp)
|
||||
/* 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. */
|
||||
unsigned char *key = keyring_find_sas_public(keyring,mdp->out.src.sid);
|
||||
if (!key)
|
||||
|
||||
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;
|
||||
@ -311,7 +313,7 @@ int overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp)
|
||||
int result
|
||||
=crypto_sign_edwards25519sha512batch_open(m,&mlen,
|
||||
signature,sizeof(signature),
|
||||
key);
|
||||
f->source->sas_public);
|
||||
if (result) {
|
||||
WHY("Signature verification failed");
|
||||
dump("data", b, len);
|
||||
|
@ -534,9 +534,6 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
|
||||
/* Make sure node is advertised soon */
|
||||
overlay_route_please_advertise(n);
|
||||
monitor_announce_peer(n->subscriber->sid);
|
||||
|
||||
/* Pre-emptively check if we have their sas in memory, or send a request */
|
||||
keyring_find_sas_public(keyring, n->subscriber->sid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
5
serval.h
5
serval.h
@ -189,6 +189,8 @@ extern char *batman_socket;
|
||||
extern char *batman_peerfile;
|
||||
|
||||
|
||||
struct subscriber;
|
||||
|
||||
typedef struct keypair {
|
||||
int type;
|
||||
unsigned char *private_key;
|
||||
@ -273,7 +275,7 @@ int keyring_find_did(const keyring_file *k,int *cn,int *in,int *kp,char *did);
|
||||
int keyring_find_sid(const keyring_file *k,int *cn,int *in,int *kp, const unsigned char *sid);
|
||||
unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid,
|
||||
unsigned char **sas_public);
|
||||
unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid);
|
||||
int keyring_send_sas_request(struct subscriber *subscriber);
|
||||
|
||||
int keyring_commit(keyring_file *k);
|
||||
keyring_identity *keyring_create_identity(keyring_file *k,keyring_context *c, const char *pin);
|
||||
@ -322,7 +324,6 @@ struct sched_ent{
|
||||
};
|
||||
|
||||
struct overlay_buffer;
|
||||
struct subscriber;
|
||||
|
||||
#define STRUCT_SCHED_ENT_UNUSED ((struct sched_ent){NULL, NULL, NULL, NULL, {-1, 0, 0}, 0LL, 0LL, NULL, -1})
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user