From e7e8b2d630b0b2a07b1931e2d4fdd731b8e395e8 Mon Sep 17 00:00:00 2001 From: gardners Date: Mon, 16 Apr 2012 06:06:43 +0930 Subject: [PATCH] fixed bug in RFS size patching. A lot of debug output tweaks to track the problem down. --- dna.c | 1 + keyring.c | 86 ++++++++++++++++++++++++++++++++++++++--- overlay.c | 2 +- overlay_abbreviations.c | 5 +++ overlay_buffer.c | 25 +++++++++++- overlay_interface.c | 3 ++ overlay_mdp.c | 52 +++++++++++++++---------- overlay_packetformats.c | 7 +++- overlay_payload.c | 27 +++++++++++++ overlay_route.c | 19 +++++---- serval.h | 11 +++++- 11 files changed, 199 insertions(+), 39 deletions(-) diff --git a/dna.c b/dna.c index d510ec8b..29310b77 100644 --- a/dna.c +++ b/dna.c @@ -484,6 +484,7 @@ int setVerbosity(char *optarg) { if (strstr(optarg,"simulation")) debug|=DEBUG_SIMULATION; if (strstr(optarg,"dnavars")) debug|=DEBUG_DNAVARS; if (strstr(optarg,"packetformats")) debug|=DEBUG_PACKETFORMATS; + if (strstr(optarg,"packetconstruction")) debug|=DEBUG_PACKETCONSTRUCTION; if (strstr(optarg,"gateway")) debug|=DEBUG_GATEWAY; if (strstr(optarg,"hlr")) debug|=DEBUG_HLR; if (strstr(optarg,"sockio")) debug|=DEBUG_IO; diff --git a/keyring.c b/keyring.c index d9654231..7ef7816a 100644 --- a/keyring.c +++ b/keyring.c @@ -1055,7 +1055,8 @@ int keyring_sanitise_position(keyring_file *k,int *cn,int *in,int *kp) return 0; } -unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid) +unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid, + unsigned char **sas_public) { int cn=0,in=0,kp=0; @@ -1064,7 +1065,12 @@ unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid) for(kp=0;kpcontexts[cn]->identities[in]->keypair_count;kp++) if (k->contexts[cn]->identities[in]->keypairs[kp]->type==KEYTYPE_CRYPTOSIGN) - return k->contexts[cn]->identities[in]->keypairs[kp]->private_key; + { + if (sas_public) + *sas_public= + k->contexts[cn]->identities[in]->keypairs[kp]->public_key; + return k->contexts[cn]->identities[in]->keypairs[kp]->private_key; + } WHYRETNULL("Identity lacks SAS"); } @@ -1087,17 +1093,87 @@ int keyring_mapping_request(keyring_file *k,overlay_mdp_frame *req) /* The authcryption of the MDP frame proves that the SAS key is owned by the owner of the SID, and so is absolutely compulsory. */ - if (req->packetTypeAndFlags&MDP_NOCRYPT) + if (req->packetTypeAndFlags&(MDP_NOCRYPT|MDP_NOSIGN)) return WHY("mapping requests must be performed under authcryption"); if (req->out.payload_length==1) { /* It's a request, so find the SAS for the SID the request was addressed to, use that to sign that SID, and then return it in an authcrypted frame. */ - WHY("Not implemented"); + unsigned char *sas_public=NULL; + unsigned char *sas_priv + =keyring_find_sas_private(keyring,req->out.dst.sid,&sas_public); + + if ((!sas_priv)||(!sas_public)) return WHY("I don't have that SAS key"); + unsigned long long slen; + /* type of key being verified */ + req->out.payload[0]=KEYTYPE_CRYPTOSIGN; + /* the public key itself */ + int sigbytes=crypto_sign_edwards25519sha512batch_BYTES; + int keybytes=crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES; + bcopy(sas_public,&req->out.payload[1],keybytes); + /* and a signature of the SID using the SAS key, to prove possession of + the key. Possession of the SID has already been established by the + decrypting of the surrounding MDP packet. + XXX - We could chop the SID out of the middle of the signed block here, + just as we do for signed MDP packets to save 32 bytes. We won't worry + about doing this, however, as the mapping process is only once per session, + not once per packet. Unless I get excited enough to do it, that is. + */ + if (crypto_sign_edwards25519sha512batch + (&req->out.payload[1+keybytes],&slen,req->out.dst.sid,SID_SIZE,sas_priv)) + return WHY("crypto_sign() failed"); + /* chop the SID out of the signature, since it can be reinserted on reception */ + bcopy(&req->out.payload[1+keybytes+32+SID_SIZE], + &req->out.payload[1+keybytes+32],sigbytes-32); + slen-=SID_SIZE; + /* and record the full length of this */ + req->out.payload_length + =1 + +crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES + +slen; + overlay_mdp_swap_src_dst(req); + #warning disabled crypt and sign for debugging. + req->packetTypeAndFlags=MDP_TX; /* crypt and sign */ + WHY("Sent SID:SAS mapping mutual-signature"); + printf("%d byte reply is from %s:%u\n to %s:%u\n", + req->out.payload_length, + overlay_render_sid(req->out.src.sid),req->out.src.port, + overlay_render_sid(req->out.dst.sid),req->out.dst.port); + return overlay_mdp_dispatch(req,1,NULL,0); } else { /* It's probably a response. */ switch(req->out.payload[0]) { case KEYTYPE_CRYPTOSIGN: + { + if (req->out.payload_length< + (1 + +crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES)) + 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+crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES]; + /* 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("Verification of signed SID in key mapping assertion failed"); + /* These next two tests should never be able to fail, but let's just + check anyway. */ + if (plain_len!=SID_SIZE) + return WHY("key mapping signed block is wrong length"); + if (bcmp(plain,req->out.src.sid,SID_SIZE)) + return WHY("key mapping signed block is for wrong SID"); + WHY("Key mapping looks valid"); + } WHY("Not implemented"); break; default: @@ -1126,7 +1202,7 @@ unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid) for(i=0;isource_address_status==OA_RESOLVED&&overlay_address_is_local(f->source)) return WHY("Dropping frame claiming to come from myself."); - if (debug&DEBUG_OVERLAYFRAMES) fprintf(stderr,">>> Received frame (type=%02x)\n",f->type); + if (debug&DEBUG_OVERLAYFRAMES) fprintf(stderr,">>> Received frame (type=%02x, bytes=%d)\n",f->type,f->payload?f->payload->length:-1); /* First order of business is whether the nexthop address has been resolved. If not, we need to think about asking for it to be resolved. diff --git a/overlay_abbreviations.c b/overlay_abbreviations.c index 92b19805..23105064 100644 --- a/overlay_abbreviations.c +++ b/overlay_abbreviations.c @@ -228,6 +228,11 @@ int overlay_abbreviate_append_address(overlay_buffer *b,unsigned char *a) int count=0; ob_makespace(b,SID_SIZE+3); int r=overlay_abbreviate_address(a,&b->bytes[b->length],&count); + if (DEBUG_PACKETCONSTRUCTION) { + fprintf(stderr,"address %s abbreviates as shown in this ", + overlay_render_sid(a)); + dump(NULL,&b->bytes[b->length],count); + } if (r) return r; b->length+=count; return 0; diff --git a/overlay_buffer.c b/overlay_buffer.c index 571c23e5..8e6d86e1 100644 --- a/overlay_buffer.c +++ b/overlay_buffer.c @@ -277,7 +277,7 @@ int ob_indel_space(overlay_buffer *b,int offset,int shift) if (ob_makespace(b,-shift)) return -1; bcopy(&b->bytes[offset],&b->bytes[offset+shift],b->length-(offset+shift)); } else if (shift<0) { /* free up space */ - bcopy(&b->bytes[offset],&b->bytes[offset-shift],b->length-(offset-shift)); + bcopy(&b->bytes[offset],&b->bytes[offset+shift],b->length-(offset-shift)); } b->length+=shift; return 0; @@ -291,10 +291,31 @@ int ob_patch_rfs(overlay_buffer *b,int l) /* Adjust size of field */ int new_size=rfs_length(l); int shift=new_size-b->var_length_bytes; - if (ob_indel_space(b,b->var_length_offset,shift)) return -1; + if (shift) { + if (debug&DEBUG_PACKETCONSTRUCTION) { + fprintf(stderr,"Patching RFS for rfs_size=%d (was %d), so indel %d btyes\n", + new_size,b->var_length_bytes,shift); + dump("before indel", + &b->bytes[b->var_length_offset], + b->length-b->var_length_offset); + } + if (ob_indel_space(b,b->var_length_offset,shift)) return -1; + if (debug&DEBUG_PACKETCONSTRUCTION) { + dump("after indel", + &b->bytes[b->var_length_offset], + b->length-b->var_length_offset); + } + + } if (rfs_encode(l,&b->bytes[b->var_length_offset])) return -1; + if (debug&DEBUG_PACKETCONSTRUCTION) { + dump("after patch", + &b->bytes[b->var_length_offset], + b->length-b->var_length_offset); + } + return 0; } diff --git a/overlay_interface.c b/overlay_interface.c index c3be56be..45efab3c 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -769,6 +769,9 @@ int overlay_tick_interface(int i, long long now) if (!(debug&DEBUG_DISABLERHIZOME)) overlay_rhizome_add_advertisements(i,e); + if (debug&DEBUG_PACKETCONSTRUCTION) + dump("assembled packet",&e->bytes[0],e->length); + /* Now send the frame. This takes the form of a special DNA packet with a different service code, which we setup earlier. */ if (debug&DEBUG_OVERLAYINTERFACES) diff --git a/overlay_mdp.c b/overlay_mdp.c index 2f5e4d37..a31f2d46 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -364,6 +364,15 @@ int overlay_saw_mdp_containing_frame(int interface,overlay_frame *f,long long no return overlay_saw_mdp_frame(interface,&mdp,now); } +int overlay_mdp_swap_src_dst(overlay_mdp_frame *mdp) +{ + sockaddr_mdp temp; + bcopy(&mdp->out.dst,&temp,sizeof(sockaddr_mdp)); + bcopy(&mdp->out.src,&mdp->out.dst,sizeof(sockaddr_mdp)); + bcopy(&temp,&mdp->out.src,sizeof(sockaddr_mdp)); + return 0; +} + int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now) { int i; @@ -434,17 +443,14 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now) /* Either respond with the appropriate SAS, or record this one if it verfies out okay. */ WHY("key mapping request"); - return keyring_mapping_request(keyring,&mdp); + return keyring_mapping_request(keyring,mdp); case MDP_PORT_ECHO: /* well known ECHO port for TCP/UDP and now MDP */ { /* Echo is easy: we swap the sender and receiver addresses (and thus port numbers) and send the frame back. */ /* Swap addresses */ - sockaddr_mdp temp; - bcopy(&mdp->out.dst,&temp,sizeof(sockaddr_mdp)); - bcopy(&mdp->out.src,&mdp->out.dst,sizeof(sockaddr_mdp)); - bcopy(&temp,&mdp->out.src,sizeof(sockaddr_mdp)); + overlay_mdp_swap_src_dst(mdp); if (mdp->out.dst.port==7) return WHY("echo loop averted"); /* If the packet was sent to broadcast, then replace broadcast address @@ -502,19 +508,6 @@ int overlay_mdp_sanitytest_sourceaddr(sockaddr_mdp *src,int userGeneratedFrameP, return WHY("Packet had broadcast address as source address"); } - /* Check for build-in port listeners */ - if (!userGeneratedFrameP) - if (overlay_address_is_local(src->sid)) { - switch(src->port) { - case MDP_PORT_ECHO: - case MDP_PORT_KEYMAPREQUEST: - /* locally hard-wired port */ - return 0; - default: - break; - } - } - /* Now make sure that source address is in the list of bound addresses, and that the recvaddr matches. */ int i; @@ -534,8 +527,25 @@ int overlay_mdp_sanitytest_sourceaddr(sockaddr_mdp *src,int userGeneratedFrameP, } } - printf("addr=%s port=%d\n", - overlay_render_sid(src->sid),src->port); + /* Check for build-in port listeners */ + if (overlay_address_is_local(src->sid)) { + switch(src->port) { + case MDP_PORT_ECHO: + /* we don't allow user/network generated packets claiming to + be from the echo port, largely to prevent echo:echo connections + and the resulting denial of service from triggering endless pongs. */ + if (!userGeneratedFrameP) return 0; + break; + /* other built-in listeners */ + case MDP_PORT_KEYMAPREQUEST: + return 0; + default: + break; + } + } + + printf("addr=%s port=%u (0x%x)\n", + overlay_render_sid(src->sid),src->port,src->port); return WHY("No such socket binding:unix domain socket tuple exists -- someone might be trying to spoof someone else's connection"); } @@ -697,7 +707,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, +crypto_sign_edwards25519sha512batch_BYTES +mdp->out.payload_length); { - unsigned char *key=keyring_find_sas_private(keyring,mdp->out.src.sid); + unsigned char *key=keyring_find_sas_private(keyring,mdp->out.src.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 diff --git a/overlay_packetformats.c b/overlay_packetformats.c index ea1b1ca7..9c3d9ffa 100644 --- a/overlay_packetformats.c +++ b/overlay_packetformats.c @@ -178,6 +178,11 @@ int packetOkOverlay(int interface,unsigned char *packet,int len, int alen=0; int offset=ofs; f.nexthop_address_status=overlay_abbreviate_expand_address(interface,packet,&offset,f.nexthop,&alen); + if (debug&DEBUG_PACKETFORMATS) { + if (f.nexthop_address_status==OA_RESOLVED) + fprintf(stderr,"next hop address is %s\n", + overlay_render_sid(f.nexthop)); + } /* Now just make the rest of the frame available via the received frame structure, as the frame may not be for us, so there is no point wasting time and energy if we don't have @@ -198,7 +203,7 @@ int packetOkOverlay(int interface,unsigned char *packet,int len, /* Skip the rest of the bytes in this frame so that we can examine the next one in this ensemble */ - if (debug&DEBUG_PACKETFORMATS) fprintf(stderr,"ofs=%d, f.rfs=%d, len=%d\n",ofs,f.rfs,len); + if (debug&DEBUG_PACKETFORMATS) fprintf(stderr,"next ofs=%d, f.rfs=%d, len=%d\n",ofs,f.rfs,len); ofs+=f.rfs; } diff --git a/overlay_payload.c b/overlay_payload.c index 84f4e755..21c66724 100644 --- a/overlay_payload.c +++ b/overlay_payload.c @@ -74,6 +74,9 @@ int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b) if (!p) return WHY("p is NULL"); if (!b) return WHY("b is NULL"); + if (debug&DEBUG_PACKETCONSTRUCTION) + dump_payload(p,"package_fmt1 stuffing into packet"); + /* Build header */ int fail=0; @@ -128,6 +131,8 @@ int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b) */ if (!fail) { int max_len=((SID_SIZE+3)*3+headers->length+p->payload->length); + if (debug&DEBUG_PACKETCONSTRUCTION) + fprintf(stderr,"Appending RFS for max_len=%d\n",max_len); ob_append_rfs(headers,max_len); int addrs_start=headers->length; @@ -142,6 +147,8 @@ int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b) int addrs_len=headers->length-addrs_start; int actual_len=addrs_len+p->payload->length; + if (debug&DEBUG_PACKETCONSTRUCTION) + fprintf(stderr,"Patching RFS for actual_len=%d\n",actual_len); ob_patch_rfs(headers,actual_len); } @@ -204,6 +211,24 @@ int dump_queue(char *msg,int q) } return 0; } + +int dump_payload(overlay_frame *p,char *message) +{ + fflush(stdout); + fprintf(stderr, + "+++++\nFrame from %s to %s of type 0x%02x %s:\n", + overlay_render_sid(p->source), + overlay_render_sid(p->destination),p->type, + message?message:""); + fprintf(stderr," next hop is %s\n",overlay_render_sid(p->nexthop)); + fflush(stderr); + if (p->payload) dump("payload contents", + &p->payload->bytes[0],p->payload->length); + fflush(stdout); fflush(stderr); + fprintf(stderr,"-----\n"); + return 0; +} + int overlay_payload_enqueue(int q,overlay_frame *p) { /* Add payload p to queue q. @@ -217,6 +242,8 @@ int overlay_payload_enqueue(int q,overlay_frame *p) if (q<0||q>=OQ_MAX) return WHY("Invalid queue specified"); if (!p) return WHY("Cannot queue NULL"); + if (0) dump_payload(p,"queued for delivery"); + if (overlay_tx[q].length>=overlay_tx[q].maxLength) return WHY("Queue congested"); if (0) dump_queue("before",q); diff --git a/overlay_route.c b/overlay_route.c index 3b3b1da1..0aa8b2b7 100644 --- a/overlay_route.c +++ b/overlay_route.c @@ -943,13 +943,16 @@ int overlay_route_recalc_neighbour_metrics(overlay_neighbour *n,long long now) } -char ors_out[SID_STRLEN+1]; +int ors_rotor=0; +char ors_out[4][SID_STRLEN+1]; char *overlay_render_sid(unsigned char *sid) { int zero=0; - extractSid(sid,&zero,ors_out); - ors_out[SID_STRLEN] = '\0'; - return ors_out; + ors_rotor++; + ors_rotor&=3; + extractSid(sid,&zero,ors_out[ors_rotor]); + ors_out[ors_rotor][SID_STRLEN] = '\0'; + return ors_out[ors_rotor]; } char *overlay_render_sid_prefix(unsigned char *sid,int l) @@ -958,9 +961,11 @@ char *overlay_render_sid_prefix(unsigned char *sid,int l) if (l<0) l=0; if (l>SID_STRLEN) l=SID_STRLEN; - extractSid(sid,&zero,ors_out); - ors_out[l]=0; - return ors_out; + ors_rotor++; + ors_rotor&=3; + extractSid(sid,&zero,ors_out[ors_rotor]); + ors_out[ors_rotor][l]=0; + return ors_out[ors_rotor]; } diff --git a/serval.h b/serval.h index 087b3b3b..b459cc69 100644 --- a/serval.h +++ b/serval.h @@ -244,7 +244,8 @@ int keyring_sanitise_position(keyring_file *k,int *cn,int *in,int *kp); int keyring_next_identity(keyring_file *k,int *cn,int *in,int *kp); int keyring_find_did(keyring_file *k,int *cn,int *in,int *kp,char *did); int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp,unsigned char *sid); -unsigned char *keyring_find_sas_private(keyring_file *k,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_commit(keyring_file *k); @@ -1011,6 +1012,7 @@ int overlay_saw_mdp_containing_frame(int interface,overlay_frame *f,long long no #define DEBUG_RHIZOMESYNC (1<<21) #define DEBUG_DISABLERHIZOME (1<<22) #define DEBUG_PACKETTX (1<<23) +#define DEBUG_PACKETCONSTRUCTION (1<<24) int serval_packetvisualise(FILE *f,char *message,unsigned char *packet,int plen); @@ -1086,7 +1088,7 @@ typedef struct sockaddr_mdp { unsigned char *keyring_get_nm_bytes(sockaddr_mdp *priv,sockaddr_mdp *pub); #define MDP_PORT_ECHO 7 -#define MDP_PORT_KEYMAPREQUEST 0xf0000001 +#define MDP_PORT_KEYMAPREQUEST 0x10000001 #define MDP_TYPE_MASK 0xff #define MDP_FLAG_MASK 0xff00 @@ -1158,6 +1160,7 @@ int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms); /* Server-side MDP functions */ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now); +int overlay_mdp_swap_src_dst(overlay_mdp_frame *mdp); int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr,int recvaddrlen, overlay_mdp_frame *mdpreply); int overlay_mdp_relevant_bytes(overlay_mdp_frame *mdp); @@ -1167,6 +1170,10 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, int ob_bcopy(overlay_buffer *b,int from, int to, int len); int ob_setbyte(overlay_buffer *b,int ofs,unsigned char value); +char *overlay_render_sid(unsigned char *sid); +char *overlay_render_sid_prefix(unsigned char *sid,int l); +int dump_payload(overlay_frame *p,char *message); + int urandombytes(unsigned char *x,unsigned long long xlen); #ifdef MALLOC_PARANOIA