int olsrd_mdp_init(co_obj_t *self, co_obj_t **output, co_obj_t *params) { svl_crypto_ctx *ctx = NULL; CHECK(IS_LIST(params) && co_list_length(params) == 2, "Invalid params"); size_t sid_len = co_str_len(co_list_element(params, 1)); char *sid_str = _LIST_ELEMENT(params, 1); CHECK(sid_len == (2 * SID_SIZE) + 1 && str_is_subscriber_id(sid_str) == 1, "Invalid SID"); ctx = svl_crypto_ctx_new(); stowSid(ctx->sid, 0, sid_str); ctx->keyring_path = _LIST_ELEMENT(params, 0); ctx->keyring_len = co_str_len(co_list_element(params, 0)) - 1; CHECK_ERR(ctx->keyring_len < PATH_MAX,"Keyring path too long"); CHECK(serval_init_keyring(ctx), "Failed to initialize Serval keyring"); CMD_OUTPUT("key", co_bin8_create((char*)ctx->sas_private, crypto_sign_SECRETKEYBYTES, 0)); return 1; error: if (ctx) svl_crypto_ctx_free(ctx); return 0; }
int olsrd_mdp_init(co_obj_t *self, co_obj_t **output, co_obj_t *params) { keyring_file *mdp_keyring = NULL; unsigned char *mdp_key = NULL; int mdp_key_len = 0; unsigned char packedSid[SID_SIZE] = {0}; CHECK(IS_LIST(params) && co_list_length(params) == 2,"Invalid params"); size_t sid_len = co_str_len(co_list_element(params,1)); char *sid_str = _LIST_ELEMENT(params,1); CHECK(sid_len == 2*SID_SIZE + 1 && str_is_subscriber_id(sid_str) == 1,"Invalid SID"); stowSid(packedSid,0,sid_str); CHECK(serval_init_keyring(packedSid, SID_SIZE, _LIST_ELEMENT(params,0), co_str_len(co_list_element(params,0)), &mdp_keyring, &mdp_key, &mdp_key_len), "Failed to initialize Serval keyring"); CMD_OUTPUT("key",co_bin8_create((char*)mdp_key,mdp_key_len,0)); return 1; error: return 0; }
int createHlr(char *did,char *sid) { int i; int record_offset=0; /* Generate random SID */ for(i=0;i<64;i++) sid[i]=hexdigit[random()&0xf]; sid[64]=0; if (debug>1) fprintf(stderr,"Creating new HLR entry with sid %s\n",sid); /* Find first free byte of HLR */ findHlr(hlr,&record_offset,NULL,NULL); if (record_offset>=hlr_size) { /* No space */ return setReason("No space in HLR for a new record"); } else { /* We have found space, but is it enough? */ int bytes=hlr_size-record_offset; if (bytes<1024) return setReason("<1KB space in HLR"); /* Write shiny fresh new record. 32bit - record length 32 bytes - SID Total length = 4+32=36 bytes. */ if (stowSid(hlr,record_offset+4,sid)) return setReason("Could not store SID in new HLR entry"); /* Write length last of all to make entry valid */ hlr[record_offset]=0; hlr[record_offset+1]=0; hlr[record_offset+2]=0; hlr[record_offset+3]=36; /* Store the DID */ { unsigned char packeddid[DID_MAXSIZE]; int pdidlen=0; stowDid(packeddid,&pdidlen,did); /* Work out reduced length of DID */ for(pdidlen=1;pdidlen<DID_MAXSIZE;pdidlen++) if (packeddid[pdidlen-1]==0xff) break; hlrSetVariable(hlr,record_offset,VAR_DIDS,0x00,packeddid,pdidlen); } if (debug) fprintf(stderr,"Created new 36 byte HLR record for DID=[%s] @ 0x%x with SID=[%s]\n", did,record_offset,sid); if (debug>2) dump("after HLR create",&hlr[0],256); return 0; } return setReason("Unreachable code turned out not to be"); }
int packetSetSid(unsigned char *packet,int packet_maxlen,int *packet_len,char *sid) { /* Convert and store hex formatted sid */ int ofs=OFS_SIDDIDFIELD; /* where the DID/subscriber ID gets written */ if (strlen(sid)!=64) { if (debug) fprintf(stderr,"Invalid SID: [%s] - should be 64 hex digits\n",sid); return setReason("SID must consist of 64 hex digits"); } packet[ofs++]=0x01; /* SID */ return stowSid(packet,ofs,sid); }
int cmd_serval_sign(const char *sid_str, const size_t sid_len, const unsigned char *msg, const size_t msg_len, char *sig_str_buf, const size_t sig_str_size, const char *keyring_path, const size_t keyring_len) { int ret = 0; unsigned char signed_msg[msg_len + SIGNATURE_BYTES]; keyring_file *_keyring = NULL; unsigned char *key = NULL; unsigned char packedSid[SID_SIZE] = {0}; CHECK(sig_str_size >= 2*SIGNATURE_BYTES + 1,"Signature buffer too small"); if (sid_str) { CHECK_ERR(sid_len == 2*SID_SIZE && str_is_subscriber_id(sid_str) == 1,"Invalid SID"); stowSid(packedSid,0,sid_str); } if (keyring_path) { CHECK_ERR(serval_init_keyring(sid_str ? packedSid : NULL, sid_str ? SID_SIZE : 0, keyring_path, keyring_len, &_keyring, &key, NULL), "Failed to initialize Serval keyring"); } else { CHECK_ERR(serval_extract_sas(&key,NULL,keyring,packedSid),"Failed to fetch SAS key"); } CHECK_ERR(serval_create_signature(key, msg, msg_len, signed_msg, SIGNATURE_BYTES + msg_len),"Failed to create signature"); strncpy(sig_str_buf,alloca_tohex(signed_msg + msg_len,SIGNATURE_BYTES),2*SIGNATURE_BYTES); sig_str_buf[2*SIGNATURE_BYTES] = '\0'; ret = 1; error: if (_keyring) keyring_free(_keyring); return ret; }
int serval_verify_client(const char *sid_str, const size_t sid_len, const unsigned char *msg, const size_t msg_len, const char *sig, const size_t sig_len, const char *keyring_path, const size_t keyring_len) { int verdict = 0; char sas_str[2*SAS_SIZE+1] = {0}; unsigned char packedSid[SID_SIZE] = {0}; CHECK(sid_len == 2*SID_SIZE,"Invalid SID length"); CHECK(sig_len == 2*SIGNATURE_BYTES,"Invalid signature length"); CHECK(str_is_subscriber_id(sid_str) != 0,"Invalid SID"); stowSid(packedSid,0,sid_str); CHECK(serval_init_keyring(packedSid, SID_SIZE, keyring_path, keyring_len, &keyring, NULL, NULL), "Failed to initialize Serval keyring"); struct subscriber *sub = find_subscriber(packedSid, SID_SIZE, 1); // get Serval identity described by given SID CHECK(sub,"Failed to fetch Serval subscriber"); CHECK(keyring_send_sas_request_client(sub),"SAS request failed"); CHECK(sub->sas_valid,"Could not validate the signing key!"); CHECK(sub->sas_public[0],"Could not validate the signing key!"); CHECK(tohex(sas_str,sub->sas_public,SAS_SIZE),"Failed to convert signing key"); verdict = cmd_serval_verify(sas_str,2*SAS_SIZE, msg,msg_len,sig,sig_len); error: return verdict; }
static int load_directory_config(){ if (!directory_service){ const char *sid_hex = confValueGet("directory.service", NULL); if (!sid_hex) return 0; unsigned char sid[SID_SIZE]; if (stowSid(sid, 0, sid_hex)==-1) return WHYF("Invalid directory server SID %s", sid_hex); directory_service = find_subscriber(sid, SID_SIZE, 1); if (!directory_service) return WHYF("Failed to create subscriber record"); // used by tests INFOF("ADD DIRECTORY SERVICE %s", alloca_tohex_sid(directory_service->sid)); } // always attempt to reload the address, may depend on DNS resolution return load_subscriber_address(directory_service); }
int serval_sign(const char *sid, const size_t sid_len, const unsigned char *msg, const size_t msg_len, char *sig_buffer, const size_t sig_size, const char *keyringName, const size_t keyring_len) { keyring_identity *new_ident; char keyringFile[1024]; assert(msg_len); if (sid) assert(sid_len == 2*SID_SIZE); if (keyringName == NULL || keyring_len == 0) { FORM_SERVAL_INSTANCE_PATH(keyringFile, "serval.keyring"); // if no keyring specified, use default keyring } else { // otherwise, use specified keyring (NOTE: if keyring does not exist, it will be created) strncpy(keyringFile,keyringName,keyring_len); keyringFile[keyring_len] = '\0'; } keyring = keyring_open(keyringFile); keyring_enter_pin(keyring, KEYRING_PIN); // unlocks Serval keyring for using identities (also initializes global default identity my_subscriber) if (!sid) { //create new sid int c; for(c=0;c<keyring->context_count;c++) { // cycle through the keyring contexts until we find one with room for another identity new_ident = keyring_create_identity(keyring,keyring->contexts[c], KEYRING_PIN); // create new Serval identity if (new_ident) break; } if (!new_ident) { fprintf(stderr, "failed to create new SID\n"); return 1; } if (keyring_commit(keyring)) { // need to commit keyring or else new identity won't be saved (needs root permissions) fprintf(stderr, "Failed to save new SID into keyring...make sure you are running as root!\n"); return 1; } sid = alloca_tohex_sid(new_ident->subscriber->sid); // convert SID from binary to hex } else { if (!str_is_subscriber_id(sid)) { fprintf(stderr,"Invalid SID\n"); return 1; } } unsigned char packedSid[SID_SIZE]; stowSid(packedSid,0,sid); unsigned char *key=keyring_find_sas_private(keyring, packedSid, NULL); // get SAS key associated with our SID if (!key) return 1; unsigned char hash[crypto_hash_sha512_BYTES]; unsigned long long sig_length = SIGNATURE_BYTES; crypto_hash_sha512(hash, msg, msg_len); // create sha512 hash of message, which will then be signed unsigned char signed_msg[msg_len + sig_length]; memcpy(signed_msg,msg,msg_len); int ret = crypto_create_signature(key, hash, crypto_hash_sha512_BYTES, &signed_msg[msg_len], &sig_length); // create signature of message hash, append it to end of message if (!ret) { //success printf("%s\n", alloca_tohex(signed_msg + msg_len, sig_length)); printf("%s\n",sid); if (sig_size > 0) { if (sig_size >= 2*sig_length + 1) { strncpy(sig_buffer,alloca_tohex(signed_msg + msg_len,sig_length),2*sig_length); sig_buffer[2*sig_length] = '\0'; } else fprintf(stderr,"Insufficient signature buffer size\n"); } } keyring_free(keyring); return ret; }
int serval_crypto_handler(co_obj_t *self, co_obj_t **output, co_obj_t *params) { CLEAR_ERR(); svl_crypto_ctx *ctx = NULL; int list_len = co_list_length(params); int keypath = 0; CHECK_ERR(IS_LIST(params) && list_len >= 2, "Invalid params"); if (!strncmp("--keyring=", co_obj_data_ptr(co_list_get_last(params)), 10)) { keypath = 1; --list_len; } ctx = svl_crypto_ctx_new(); if (co_str_cmp_str(co_list_element(params, 0), "sign") == 0) { CHECK_ERR(list_len == 2 || list_len == 3, "Invalid arguments"); if (list_len == 3) { char *sid_str = _LIST_ELEMENT(params, 1); size_t sid_len = co_str_len(co_list_element(params, 1)) - 1; CHECK_ERR(sid_len == (2 * SID_SIZE) && str_is_subscriber_id(sid_str) == 1, "Invalid SID"); stowSid(ctx->sid, 0, sid_str); ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 2); ctx->msg_len = co_str_len(co_list_element(params, 2)) - 1; if (keypath) { ctx->keyring_path = _LIST_ELEMENT(params, 3) + 10; ctx->keyring_len = co_str_len(co_list_element(params, 3)) - 11; CHECK_ERR(ctx->keyring_len < PATH_MAX,"Keyring path too long"); } } else if (list_len == 2) { ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 1); ctx->msg_len = co_str_len(co_list_element(params, 1)) - 1; if (keypath) { ctx->keyring_path = _LIST_ELEMENT(params, 2) + 10; ctx->keyring_len = co_str_len(co_list_element(params, 2)) - 11; CHECK_ERR(ctx->keyring_len < PATH_MAX,"Keyring path too long"); } } CHECK_ERR(cmd_serval_sign(ctx), "Failed to create signature"); // convert ctx->signature, ctx->sas_public, and ctx->sid to hex: char sid_str[(2 * SID_SIZE) + 1] = {0}; strncpy(sid_str, alloca_tohex(ctx->sid, SID_SIZE), 2 * SID_SIZE); char sas_str[(2 * crypto_sign_PUBLICKEYBYTES) + 1] = {0}; strncpy(sas_str, alloca_tohex(ctx->sas_public, crypto_sign_PUBLICKEYBYTES), 2 * crypto_sign_PUBLICKEYBYTES); char sig_str[(2 * SIGNATURE_BYTES) + 1] = {0}; strncpy(sig_str, alloca_tohex(ctx->signature, SIGNATURE_BYTES), 2 * SIGNATURE_BYTES); CMD_OUTPUT("SID", co_str8_create(sid_str, (2 * SID_SIZE) + 1, 0)); CMD_OUTPUT("SAS", co_str8_create(sas_str, (2 * crypto_sign_PUBLICKEYBYTES) + 1, 0)); CMD_OUTPUT("signature", co_str8_create(sig_str, (2 * SIGNATURE_BYTES) + 1, 0)); } else if (co_str_cmp_str(co_list_element(params, 0), "verify") == 0) { CHECK_ERR(!keypath, "Keyring option not available for verification"); CHECK_ERR(list_len == 4, "Invalid arguments"); // convert SAS and signature from hex to bin CHECK_ERR(fromhexstr(ctx->signature, _LIST_ELEMENT(params, 2), SIGNATURE_BYTES) == 0, "Invalid signature"); CHECK_ERR(fromhexstr(ctx->sas_public, _LIST_ELEMENT(params, 1), crypto_sign_PUBLICKEYBYTES) == 0, "Invalid SAS key"); ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 3); ctx->msg_len = co_str_len(co_list_element(params, 3)) - 1; int verdict = cmd_serval_verify(ctx); if (verdict == 1) { DEBUG("signature verified"); CMD_OUTPUT("result", co_bool_create(true, 0)); // successfully verified CMD_OUTPUT("verified",co_str8_create("true",sizeof("true"),0)); } else if (verdict == 0) { DEBUG("signature NOT verified"); CMD_OUTPUT("result", co_bool_create(false, 0)); CMD_OUTPUT("verified",co_str8_create("false",sizeof("false"),0)); } } error: INS_ERROR(); if (ctx) svl_crypto_ctx_free(ctx); return 1; }
int findHlr(unsigned char *hlr,int *ofs,char *sid,char *did) { unsigned int record_length; int match=0; int records_searched=0; int pid_len=0; unsigned char packed_id[40]; if ((*ofs)>=hlr_size) return 0; if (debug>1) fprintf(stderr,"Searching for HLR record sid=[%s]/did=[%s]\n",sid?sid:"NULL",did?did:"NULL"); if (did&&did[0]) { /* Make packed version of DID so that we can compare faster with the DIDs in the HLR */ if (stowDid(packed_id,&pid_len,did)) return setReason("DID appears to be invalid"); /* Find significant length of packed DID */ for(pid_len=0;pid_len<DID_MAXSIZE;pid_len++) if ((packed_id[pid_len]&0x0f)==0x0f) { pid_len++; break; } if (debug>1) dump("Searching for DID records that match",packed_id,pid_len); } if (sid&&sid[0]) { /* Make packed version of SID for fast comparison */ if (stowSid(packed_id,pid_len,sid)) return setReason("SID appears to be invalid"); pid_len=SID_SIZE; } while(!match) { /* Get length of this record */ record_length =hlr[(*ofs)+3]<<0; record_length|=hlr[(*ofs)+2]<<8; record_length|=hlr[(*ofs)+1]<<16; record_length|=hlr[(*ofs)+0]<<24; if (!record_length) return 0; if (debug>1) fprintf(stderr,"Considering HLR entry @ 0x%x\n",*ofs); records_searched++; if (sid&&sid[0]) { /* Lookup by SID, so just see if it matches */ if (!bcompare(packed_id,&hlr[(*ofs)+4],SID_SIZE)) { if (debug>1) fprintf(stderr,"Found requested SID at address 0x%x.\n",*ofs); match=1; } } if (did&&did[0]) { /* Lookup by did, so see if there are any matching DID entries for this subscriber */ int rofs=(*ofs); struct hlrentry_handle *h=openhlrentry(hlr,rofs); while(h) { /* Search through variables for matching DIDs */ if (debug>2) { fprintf(stderr,"Considering variable 0x%02x, instance %d.\n", h->var_id,h->var_instance); dump("variable value",h->value,h->value_len); } if (h->var_id==VAR_DIDS) { /* DID entry */ if (debug>2) fprintf(stderr,"Checking DID against record DID\n"); if (!bcompare(packed_id,h->value,pid_len)) { if (debug>1) fprintf(stderr,"Found matching DID in HLR record #%d\n",records_searched); match=1; break; } } else { if (debug>2) fprintf(stderr,"Skipping non-DID variable while searching for DID.\n"); } h=hlrentrygetent(h); } } /* For each match ... */ if (match) { if (debug>1) fprintf(stderr,"Returning HLR entry @ 0x%x\n",*ofs); return 1; } /* Consider next record */ (*ofs)+=record_length; if ((*ofs)>=hlr_size) return 0; } return 0; }