diff --git a/keyring.c b/keyring.c index 1356f01f..a0757222 100644 --- a/keyring.c +++ b/keyring.c @@ -247,8 +247,10 @@ void keyring_free_identity(keyring_identity *id) if (id->PKRPin) { /* Wipe pin before freeing (slightly tricky since this is a variable length string */ for(i=0;id->PKRPin[i];i++) { - fprintf(stderr,"clearing PIN char '%c'\n",id->PKRPin[i]); - id->PKRPin[i]=' '; } + if (debug & DEBUG_KEYRING) + DEBUGF("clearing PIN char '%c'", id->PKRPin[i]); + id->PKRPin[i]=' '; + } i=0; free(id->PKRPin); id->PKRPin=NULL; @@ -973,23 +975,22 @@ int keyring_commit(keyring_file *k) k->contexts[cn]->KeyRingPin, k->contexts[cn]->identities[in]->PKRPin)) errorCount++; - else - { - /* Store */ - off_t file_offset - =KEYRING_PAGE_SIZE - *k->contexts[cn]->identities[in]->slot; - if (!file_offset) { - fprintf(stderr,"ID %d:%d has slot=0\n", - cn,in); - } - else if (fseeko(k->file,file_offset,SEEK_SET)) - errorCount++; - else - if (fwrite(pkr,KEYRING_PAGE_SIZE,1,k->file)!=1) - errorCount++; + else { + /* Store */ + off_t file_offset + =KEYRING_PAGE_SIZE + *k->contexts[cn]->identities[in]->slot; + if (!file_offset) { + if (debug * DEBUG_KEYRING) + DEBUGF("ID %d:%d has slot=0", cn,in); } - } + else if (fseeko(k->file,file_offset,SEEK_SET)) + errorCount++; + else + if (fwrite(pkr,KEYRING_PAGE_SIZE,1,k->file)!=1) + errorCount++; + } + } } if (errorCount) WHY("One or more errors occurred while commiting keyring to disk"); @@ -1006,7 +1007,8 @@ int keyring_set_did(keyring_identity *id,char *did,char *name) int i; for(i=0;ikeypair_count;i++) if (id->keypairs[i]->type==KEYTYPE_DID) { - DEBUG("Identity contains DID"); + if (debug & DEBUG_KEYRING) + DEBUG("Identity contains DID"); break; } @@ -1026,7 +1028,8 @@ int keyring_set_did(keyring_identity *id,char *did,char *name) id->keypairs[i]->public_key=packedName; id->keypairs[i]->public_key_len=64; id->keypair_count++; - DEBUG("Created DID record for identity"); + if (debug & DEBUG_KEYRING) + DEBUG("Created DID record for identity"); } /* Store DID unpacked for ease of searching */ @@ -1131,7 +1134,8 @@ unsigned char *keyring_find_sas_private(keyring_file *k,unsigned char *sid, if (sas_public) *sas_public= k->contexts[cn]->identities[in]->keypairs[kp]->public_key; - if (0) DEBUGF("Found SAS entry for %s*", alloca_tohex(sid, 7)); + if (debug & DEBUG_KEYRING) + DEBUGF("Found SAS entry for %s*", alloca_tohex(sid, 7)); RETURN(k->contexts[cn]->identities[in]->keypairs[kp]->private_key); } @@ -1196,11 +1200,13 @@ int keyring_mapping_request(keyring_file *k,overlay_mdp_frame *req) +slen; overlay_mdp_swap_src_dst(req); req->packetTypeAndFlags=MDP_TX; /* crypt and sign */ - DEBUG("Sent SID:SAS mapping mutual-signature"); - printf("%d byte reply is from %s:%u\n to %s:%u\n", - req->out.payload_length, - alloca_tohex_sid(req->out.src.sid),req->out.src.port, - alloca_tohex_sid(req->out.dst.sid),req->out.dst.port); + if (debug & DEBUG_KEYRING) { + DEBUG("Sent SID:SAS mapping mutual-signature"); + DEBUGF("%d byte reply from %s:%u to %s:%u", + req->out.payload_length, + alloca_tohex_sid(req->out.src.sid),req->out.src.port, + alloca_tohex_sid(req->out.dst.sid),req->out.dst.port); + } return overlay_mdp_dispatch(req,1,NULL,0); } else { /* It's probably a response. */ @@ -1228,16 +1234,16 @@ int keyring_mapping_request(keyring_file *k,overlay_mdp_frame *req) 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"); + 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) + if (plain_len!=SID_SIZE) return WHY("key mapping signed block is wrong length"); if (memcmp(plain,req->out.src.sid,SID_SIZE)) return WHY("key mapping signed block is for wrong SID"); - DEBUG("Key mapping looks valid"); + if (debug & DEBUG_KEYRING) + DEBUG("Key mapping looks valid"); /* work out where to put it */ int i; @@ -1251,15 +1257,17 @@ int keyring_mapping_request(keyring_file *k,overlay_mdp_frame *req) bcopy(&req->out.src.sid,&sid_sas_mappings[i].sid[0],SID_SIZE); bcopy(sas_public,&sid_sas_mappings[i].sas_public[0], crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES); - fprintf(stderr,"Mapping #%d (count=%d) SID=%s to SAS=%s*\n",i, - sid_sas_mapping_count, - alloca_tohex_sid(sid_sas_mappings[i].sid), - alloca_tohex_sid(sid_sas_mappings[i].sas_public)); + if (debug & DEBUG_KEYRING) + DEBUGF("Mapping #%d (count=%d) SID=%s to SAS=%s*\n",i, + sid_sas_mapping_count, + alloca_tohex_sid(sid_sas_mappings[i].sid), + alloca_tohex_sid(sid_sas_mappings[i].sas_public)); sid_sas_mappings[i].validP=1; sid_sas_mappings[i].last_request_time_in_ms=0; - DEBUG("Stored mapping"); + if (debug & DEBUG_KEYRING) + DEBUG("Stored mapping"); return 0; - } + } break; default: WARN("Key mapping response for unknown key type. Oh well."); @@ -1289,7 +1297,8 @@ unsigned char *keyring_find_sas_public(keyring_file *k,unsigned char *sid) { if (memcmp(sid,sid_sas_mappings[i].sid,SID_SIZE)) continue; if (sid_sas_mappings[i].validP) { - if (0) DEBUGF("Found SAS public entry for %s*", alloca_tohex(sid, 7)); + if (debug & DEBUG_KEYRING) + DEBUGF("Found SAS public entry for %s*", alloca_tohex(sid, 7)); RETURN(sid_sas_mappings[i].sas_public); } /* Don't flood the network with mapping requests */ diff --git a/log.c b/log.c index 11d19a24..dee63bc5 100644 --- a/log.c +++ b/log.c @@ -264,7 +264,7 @@ unsigned int debugFlagMask(const char *flagname) { else if (!strcasecmp(flagname,"packetformats")) return DEBUG_PACKETFORMATS; else if (!strcasecmp(flagname,"packetconstruction")) return DEBUG_PACKETCONSTRUCTION; else if (!strcasecmp(flagname,"gateway")) return DEBUG_GATEWAY; - else if (!strcasecmp(flagname,"hlr")) return DEBUG_HLR; + else if (!strcasecmp(flagname,"keyring")) return DEBUG_KEYRING; else if (!strcasecmp(flagname,"sockio")) return DEBUG_IO; else if (!strcasecmp(flagname,"frames")) return DEBUG_OVERLAYFRAMES; else if (!strcasecmp(flagname,"abbreviations")) return DEBUG_OVERLAYABBREVIATIONS; diff --git a/serval.h b/serval.h index 0b777f12..cd336ea0 100644 --- a/serval.h +++ b/serval.h @@ -1132,7 +1132,7 @@ int overlay_saw_mdp_containing_frame(overlay_frame *f,long long now); #define DEBUG_RHIZOME_RX (1 << 8) #define DEBUG_PACKETFORMATS (1 << 9) #define DEBUG_GATEWAY (1 << 10) -#define DEBUG_HLR (1 << 11) // Deprecated, TODO: delete +#define DEBUG_KEYRING (1 << 11) #define DEBUG_IO (1 << 12) #define DEBUG_OVERLAYFRAMES (1 << 13) #define DEBUG_OVERLAYABBREVIATIONS (1 << 14) diff --git a/server.c b/server.c index e45d623b..8057ab3a 100644 --- a/server.c +++ b/server.c @@ -509,261 +509,244 @@ int processRequest(unsigned char *packet,int len, unsigned char *transaction_id,int recvttl, char *did,char *sid) { /* Find HLR entry by DID or SID, unless creating */ - int records_searched=0; - int prev_pofs=0; int pofs=OFS_PAYLOAD; - while(pofscontexts[0], ""); + if (id) + keyring_set_did(id, did, "Mr. Smith"); + if (id==NULL||keyring_commit(keyring)) + return respondSimple(NULL, ACTION_DECLINED, NULL, 0, transaction_id, recvttl, sender, CRYPT_CIPHERED|CRYPT_SIGNED); + else + return respondSimple(id, ACTION_OKAY, NULL, 0, transaction_id, recvttl, sender, CRYPT_CIPHERED|CRYPT_SIGNED); + pofs += 1; + pofs += 1 + SID_SIZE; + } + break; + case ACTION_PAD: /* Skip padding */ + pofs++; + pofs+=1+packet[pofs]; + break; + case ACTION_EOT: /* EOT */ + pofs=len; + break; + case ACTION_STATS: { + /* short16 variable id, + int32 value */ + pofs++; + short field=packet[pofs+1]+(packet[pofs]<<8); + int value=packet[pofs+5]+(packet[pofs+4]<<8)+(packet[pofs+3]<<16)+(packet[pofs+2]<<24); + pofs+=6; + if (instrumentation_file) + { + if (!i_f) { if (strcmp(instrumentation_file,"-")) i_f=fopen(instrumentation_file,"a"); else i_f=stdout; } + if (i_f) fprintf(i_f,"%ld:%02x%02x%02x%02x:%d:%d\n",time(0),sender->sa_data[0],sender->sa_data[1],sender->sa_data[2],sender->sa_data[3],field,value); + if (i_f) fflush(i_f); + } + } + break; + case ACTION_SET: + WHY("You can only set keyring variables locally"); + return respondSimple(NULL,ACTION_ERROR, + (unsigned char *)"Would be insecure", + 0,transaction_id,recvttl, + sender,CRYPT_CIPHERED|CRYPT_SIGNED); + break; + case ACTION_GET: { + /* Limit transfer size to MAX_DATA_BYTES, plus an allowance for variable packing. */ + unsigned char data[MAX_DATA_BYTES+16]; + int dlen=0; + int sendDone=0; + + if (debug&DEBUG_DNARESPONSES) + dump("Request bytes", &packet[pofs], 8); + + pofs++; + int var_id=packet[pofs]; + int instance=-1; + if (var_id&0x80) instance=packet[++pofs]; + if (instance==0xff) instance=-1; + pofs++; + int offset=(packet[pofs]<<8)+packet[pofs+1]; pofs+=2; + keyring_identity *responding_id=NULL; + + pofs+=2; + + if (debug&DEBUG_DNARESPONSES) { + DEBUGF("Processing ACTION_GET (var_id=%02x, instance=%02x, pofs=0x%x, len=%d)",var_id,instance,pofs,len); + DEBUGF("Looking for identities with sid=%s did='%s'", (sid&&sid[0])?sid:"null",did?did:"null"); + } - /* Creating an identity is nice and easy now with the new keyring */ - keyring_identity *id=keyring_create_identity(keyring,keyring->contexts[0], ""); - if (id) keyring_set_did(id,did,"Mr. Smith"); - if (id==NULL||keyring_commit(keyring)) - return respondSimple(NULL,ACTION_DECLINED,NULL,0,transaction_id,recvttl, - sender,CRYPT_CIPHERED|CRYPT_SIGNED); - else - return respondSimple(id,ACTION_OKAY,NULL,0,transaction_id,recvttl, - sender,CRYPT_CIPHERED|CRYPT_SIGNED); - - pofs+=1; - pofs+=1+SID_SIZE; + /* Keyring only has DIDs in it for now. Location is implied, so we allow that */ + switch (var_id) { + case VAR_DIDS: + case VAR_LOCATIONS: + break; + default: + return respondSimple(NULL,ACTION_ERROR, + (unsigned char *)"Unsupported variable", + 0,transaction_id,recvttl, + sender,CRYPT_CIPHERED|CRYPT_SIGNED); } - else + { - if (debug&DEBUG_DNARESPONSES) DEBUGF("Looking at action code 0x%02x @ packet offset 0x%x", - packet[pofs],pofs); - switch(packet[pofs]) - { - case ACTION_PAD: /* Skip padding */ - pofs++; - pofs+=1+packet[pofs]; - break; - case ACTION_EOT: /* EOT */ - pofs=len; - break; - case ACTION_STATS: - /* short16 variable id, - int32 value */ - { - pofs++; - short field=packet[pofs+1]+(packet[pofs]<<8); - int value=packet[pofs+5]+(packet[pofs+4]<<8)+(packet[pofs+3]<<16)+(packet[pofs+2]<<24); - pofs+=6; - if (instrumentation_file) - { - if (!i_f) { if (strcmp(instrumentation_file,"-")) i_f=fopen(instrumentation_file,"a"); else i_f=stdout; } - if (i_f) fprintf(i_f,"%ld:%02x%02x%02x%02x:%d:%d\n",time(0),sender->sa_data[0],sender->sa_data[1],sender->sa_data[2],sender->sa_data[3],field,value); - if (i_f) fflush(i_f); - } + int cn=0,in=0,kp=0; + int found=0; + int count=0; + while(cncontext_count) { + found=0; + if (sid&&sid[0]) { + unsigned char packedSid[SID_SIZE]; + stowSid(packedSid,0,sid); + found=keyring_find_sid(keyring,&cn,&in,&kp,packedSid); + } else { + found=keyring_find_did(keyring,&cn,&in,&kp,did); + } + + struct response r; + unsigned char packedDid[64]; + + if (found&&(instance==-1||instance==count)) { + /* We have a matching identity/DID, now see what variable + they want. + VAR_DIDS and VAR_LOCATIONS are the only ones we support + with the new keyring file format for now. */ + r.var_id=var_id; + r.var_instance=instance; + switch(var_id) { + case VAR_DIDS: + /* We need to pack the DID before sending off */ + r.value_len=0; + stowDid(packedDid,&r.value_len, + (char *)keyring->contexts[cn]->identities[in] + ->keypairs[kp]->private_key); + r.response=packedDid; + break; + case VAR_LOCATIONS: + r.response=(unsigned char *)"4000@"; + r.value_len=strlen((char *)r.response); + break; } - break; - case ACTION_SET: - WHY("You can only set keyring variables locally"); - return respondSimple(NULL,ACTION_ERROR, - (unsigned char *)"Would be insecure", - 0,transaction_id,recvttl, - sender,CRYPT_CIPHERED|CRYPT_SIGNED); - - break; - case ACTION_GET: - { - /* Limit transfer size to MAX_DATA_BYTES, plus an allowance for variable packing. */ - unsigned char data[MAX_DATA_BYTES+16]; - int dlen=0; - int sendDone=0; - if (debug&DEBUG_HLR) dump("Request bytes",&packet[pofs],8); + /* For multiple packet responses, we want to tag only the + last one with DONE, so we queue up the most recently generated + packet, and only dispatch it when we are about to produce + another. Then at the end of the loop, if we have a packet + waiting we simply mark that with with DONE, and everything + falls into place. */ + if (sendDone>0) + /* Send previous packet */ + respondSimple(responding_id,ACTION_DATA,data,dlen, + transaction_id,recvttl,sender, + CRYPT_CIPHERED|CRYPT_SIGNED); + /* Prepare new packet */ + dlen=0; + if (packageVariableSegment(data,&dlen,&r,offset, MAX_DATA_BYTES+16)) + return WHY("packageVariableSegment() failed."); + responding_id = keyring->contexts[cn]->identities[in]; - pofs++; - int var_id=packet[pofs]; - int instance=-1; - if (var_id&0x80) instance=packet[++pofs]; - if (instance==0xff) instance=-1; - pofs++; - int offset=(packet[pofs]<<8)+packet[pofs+1]; pofs+=2; - keyring_identity *responding_id=NULL; + /* Remember that we need to send this new packet */ + sendDone++; - pofs+=2; - - if (debug&DEBUG_DNARESPONSES) DEBUGF("Processing ACTION_GET (var_id=%02x, instance=%02x, pofs=0x%x, len=%d)",var_id,instance,pofs,len); - - if (debug&DEBUG_HLR) DEBUGF("Looking for identities with sid='%s' / did='%s'",(sid&&sid[0])?sid:"null",did?did:"null"); - - /* Keyring only has DIDs in it for now. - Location is implied, so we allow that */ - switch(var_id) { - case VAR_DIDS: - case VAR_LOCATIONS: - break; - default: - return respondSimple(NULL,ACTION_ERROR, - (unsigned char *)"Unsupported variable", - 0,transaction_id,recvttl, - sender,CRYPT_CIPHERED|CRYPT_SIGNED); - - } - - { - int cn=0,in=0,kp=0; - int found=0; - int count=0; - while(cncontext_count) { - found=0; - if (sid&&sid[0]) { - unsigned char packedSid[SID_SIZE]; - stowSid(packedSid,0,sid); - found=keyring_find_sid(keyring,&cn,&in,&kp,packedSid); - } else { - found=keyring_find_did(keyring,&cn,&in,&kp,did); - } - - struct response r; - unsigned char packedDid[64]; - - if (found&&(instance==-1||instance==count)) { - /* We have a matching identity/DID, now see what variable - they want. - VAR_DIDS and VAR_LOCATIONS are the only ones we support - with the new keyring file format for now. */ - r.var_id=var_id; - r.var_instance=instance; - switch(var_id) { - case VAR_DIDS: - /* We need to pack the DID before sending off */ - r.value_len=0; - stowDid(packedDid,&r.value_len, - (char *)keyring->contexts[cn]->identities[in] - ->keypairs[kp]->private_key); - r.response=packedDid; - break; - case VAR_LOCATIONS: - r.response=(unsigned char *)"4000@"; - r.value_len=strlen((char *)r.response); - break; - } - - /* For multiple packet responses, we want to tag only the - last one with DONE, so we queue up the most recently generated - packet, and only dispatch it when we are about to produce - another. Then at the end of the loop, if we have a packet - waiting we simply mark that with with DONE, and everything - falls into place. */ - if (sendDone>0) - /* Send previous packet */ - respondSimple(responding_id,ACTION_DATA,data,dlen, - transaction_id,recvttl,sender, - CRYPT_CIPHERED|CRYPT_SIGNED); - /* Prepare new packet */ - dlen=0; - if (packageVariableSegment(data,&dlen,&r,offset, - MAX_DATA_BYTES+16)) - return WHY("packageVariableSegment() failed."); - responding_id = keyring->contexts[cn]->identities[in]; - - /* Remember that we need to send this new packet */ - sendDone++; - - count++; - } - - /* look for next record. - Here the placing of DONE at the end of the response stream - becomes challenging, as we may be responding as multiple - identities. This means we have to DONE after each identity. */ - int lastin=in,lastcn=cn; - kp++; - keyring_sanitise_position(keyring,&cn,&in,&kp); - if (lastin!=in||lastcn!=cn) { - /* moved off last identity, so send waiting packet if there is - one. */ - if (sendDone) - { - data[dlen++]=ACTION_DONE; - data[dlen++]=sendDone&0xff; - respondSimple(responding_id,ACTION_DATA,data,dlen, - transaction_id, - recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED); - } - sendDone=0; - - } - - } - } - - /* Now, see if we have a final queued packet which needs marking with - DONE and then sending. */ - if (sendDone) - { - data[dlen++]=ACTION_DONE; - data[dlen++]=sendDone&0xff; - respondSimple(responding_id,ACTION_DATA,data,dlen,transaction_id, - recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED); - } - - if (gatewayspec&&(var_id==VAR_LOCATIONS)&&did&&strlen(did)) - { - /* We are a gateway, so offer connection via the gateway as well */ - unsigned char data[MAX_DATA_BYTES+16]; - int dlen=0; - struct response fake; - unsigned char uri[1024]; - - /* We use asterisk to provide the gateway service, - so we need to create a temporary extension in extensions.conf, - ask asterisk to re-read extensions.conf, and then make sure it has - a functional SIP gateway. - */ - if (!asteriskObtainGateway(sid,did,(char *)uri)) - { - - fake.value_len=strlen((char *)uri); - fake.var_id=var_id; - fake.response=uri; - - if (packageVariableSegment(data,&dlen,&fake,offset,MAX_DATA_BYTES+16)) - return WHY("packageVariableSegment() of gateway URI failed."); - - WHY("Gateway claims to be 1st identity, when it should probably have its own identity"); - respondSimple(keyring->contexts[0]->identities[0], - ACTION_DATA,data,dlen, - transaction_id,recvttl,sender, - CRYPT_CIPHERED|CRYPT_SIGNED); - } - else - { - /* Should we indicate the gateway is not available? */ - } - } - + count++; + } + + /* look for next record. + Here the placing of DONE at the end of the response stream + becomes challenging, as we may be responding as multiple + identities. This means we have to DONE after each identity. */ + int lastin=in,lastcn=cn; + kp++; + keyring_sanitise_position(keyring,&cn,&in,&kp); + if (lastin!=in||lastcn!=cn) { + /* moved off last identity, so send waiting packet if there is + one. */ + if (sendDone) { + data[dlen++]=ACTION_DONE; + data[dlen++]=sendDone&0xff; + respondSimple(responding_id,ACTION_DATA,data,dlen, + transaction_id, + recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED); } - break; - default: - if (debug&DEBUG_PACKETFORMATS) DEBUGF("Asked to perform unsipported action at Packet offset = 0x%x",pofs); - if (debug&DEBUG_PACKETFORMATS) dump("Packet",packet,len); - return WHY("Asked to perform unsupported action."); - } + sendDone=0; + } + } } + + /* Now, see if we have a final queued packet which needs marking with + DONE and then sending. */ + if (sendDone) { + data[dlen++]=ACTION_DONE; + data[dlen++]=sendDone&0xff; + respondSimple(responding_id,ACTION_DATA,data,dlen,transaction_id, + recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED); + } + + if (gatewayspec&&(var_id==VAR_LOCATIONS)&&did&&strlen(did)) + { + /* We are a gateway, so offer connection via the gateway as well */ + unsigned char data[MAX_DATA_BYTES+16]; + int dlen=0; + struct response fake; + unsigned char uri[1024]; + + /* We use asterisk to provide the gateway service, + so we need to create a temporary extension in extensions.conf, + ask asterisk to re-read extensions.conf, and then make sure it has + a functional SIP gateway. + */ + if (!asteriskObtainGateway(sid,did,(char *)uri)) + { + + fake.value_len=strlen((char *)uri); + fake.var_id=var_id; + fake.response=uri; + + if (packageVariableSegment(data,&dlen,&fake,offset,MAX_DATA_BYTES+16)) + return WHY("packageVariableSegment() of gateway URI failed."); + + WHY("Gateway claims to be 1st identity, when it should probably have its own identity"); + respondSimple(keyring->contexts[0]->identities[0], + ACTION_DATA,data,dlen, + transaction_id,recvttl,sender, + CRYPT_CIPHERED|CRYPT_SIGNED); + } + else + { + /* Should we indicate the gateway is not available? */ + } + } + + } + break; + default: + if (debug & DEBUG_PACKETFORMATS) { + DEBUGF("Asked to perform unsipported action at Packet offset = 0x%x", pofs); + dump("Packet", packet, len); + } + return WHY("unsupported action"); } - - if (debug&DEBUG_HLR) DEBUGF("Searched %d HLR entries",records_searched); + } return 0; }