/*---------------------------------------------------------------------------*/ static enum adaptivesec_verify verify(struct akes_nbr *sender) { if(packetbuf_holds_broadcast()) { if(verify_broadcast(sender)) { PRINTF("coresec-strategy: Inauthentic broadcast\n"); return 0; } } else { #if ANTI_REPLAY_WITH_SUPPRESSION packetbuf_set_attr(PACKETBUF_ATTR_NEIGHBOR_INDEX, sender->foreign_index); #endif /* ANTI_REPLAY_WITH_SUPPRESSION */ if(adaptivesec_verify(sender->pairwise_key)) { PRINTF("coresec-strategy: Inauthentic unicast\n"); return ADAPTIVESEC_VERIFY_INAUTHENTIC; } } #if !POTR_ENABLED if(anti_replay_was_replayed(&sender->anti_replay_info)) { PRINTF("coresec-strategy: Replayed\n"); return ADAPTIVESEC_VERIFY_REPLAYED; } #endif /* !POTR_ENABLED */ return ADAPTIVESEC_VERIFY_SUCCESS; }
/*---------------------------------------------------------------------------*/ static int decrypt_verify(struct neighbor *sender) { if(packetbuf_holds_broadcast()) { if(!decrypt_verify_broadcast(sender)) { PRINTF("coresec-strategy: Unauthentic broadcast\n"); return 0; } } else { #if ANTI_REPLAY_WITH_SUPPRESSION packetbuf_set_attr(PACKETBUF_ATTR_NEIGHBOR_INDEX, sender->foreign_index); #endif /* ANTI_REPLAY_WITH_SUPPRESSION */ if(!adaptivesec_decrypt_verify(sender->pairwise_key)) { PRINTF("coresec-strategy: Unauthentic unicast\n"); return 0; } } if(anti_replay_was_replayed(&sender->anti_replay_info)) { PRINTF("coresec-strategy: Replayed\n"); return 0; } return 1; }
/*---------------------------------------------------------------------------*/ static void process_update_command(struct akes_nbr *nbr, uint8_t *data, int cmd_id) { switch(cmd_id) { case AKES_ACK_IDENTIFIER: akes_nbr_free_tentative_metadata(nbr); nbr->sent_authentic_hello = 1; break; case AKES_HELLOACK_IDENTIFIER: nbr->sent_authentic_hello = 0; break; } anti_replay_was_replayed(&nbr->anti_replay_info); #if ANTI_REPLAY_WITH_SUPPRESSION nbr->last_was_broadcast = 1; #endif /* ANTI_REPLAY_WITH_SUPPRESSION */ akes_nbr_prolong(nbr); #if AKES_NBR_WITH_INDICES nbr->foreign_index = data[0]; data++; #endif /* AKES_NBR_WITH_INDICES */ #if ANTI_REPLAY_WITH_SUPPRESSION { frame802154_frame_counter_t disordered_counter; data += 4; memcpy(disordered_counter.u8, data, 4); nbr->anti_replay_info.his_broadcast_counter.u32 = LLSEC802154_HTONL(disordered_counter.u32); data += 4; } #endif /* ANTI_REPLAY_WITH_SUPPRESSION */ #if AKES_NBR_WITH_GROUP_KEYS switch(cmd_id) { case AKES_HELLOACK_IDENTIFIER: case AKES_ACK_IDENTIFIER: akes_nbr_copy_key(nbr->group_key, data); break; } #endif /* AKES_NBR_WITH_GROUP_KEYS */ }
/*---------------------------------------------------------------------------*/ static int parse(void) { int result; const linkaddr_t *sender; struct anti_replay_info* info; result = DECORATED_FRAMER.parse(); if(result == FRAMER_FAILED) { return result; } if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) != SEC_LVL) { PRINTF("noncoresec: received frame with wrong security level\n"); return FRAMER_FAILED; } sender = packetbuf_addr(PACKETBUF_ADDR_SENDER); if(linkaddr_cmp(sender, &linkaddr_node_addr)) { PRINTF("noncoresec: frame from ourselves\n"); return FRAMER_FAILED; } packetbuf_set_datalen(packetbuf_datalen() - MIC_LEN); if(!aead(result, 0)) { PRINTF("noncoresec: received unauthentic frame %lu\n", anti_replay_get_counter()); return FRAMER_FAILED; } info = nbr_table_get_from_lladdr(anti_replay_table, sender); if(!info) { info = nbr_table_add_lladdr(anti_replay_table, sender, NBR_TABLE_REASON_LLSEC, NULL); if(!info) { PRINTF("noncoresec: could not get nbr_table_item\n"); return FRAMER_FAILED; } /* * Locking avoids replay attacks due to removed neighbor table items. * Unfortunately, an attacker can mount a memory-based DoS attack * on this by replaying broadcast frames from other network parts. * However, this is not an issue as long as the network size does not * exceed NBR_TABLE_MAX_NEIGHBORS. * * To avoid locking, we could swap anti-replay information * to external flash. Locking is also unnecessary when using * pairwise session keys, as done in coresec. */ if(!nbr_table_lock(anti_replay_table, info)) { nbr_table_remove(anti_replay_table, info); PRINTF("noncoresec: could not lock\n"); return FRAMER_FAILED; } anti_replay_init_info(info); } else { if(anti_replay_was_replayed(info)) { PRINTF("noncoresec: received replayed frame %lu\n", anti_replay_get_counter()); return FRAMER_FAILED; } } return result; }