/*---------------------------------------------------------------------------*/ int anti_replay_was_replayed(struct anti_replay_info *info) { uint32_t received_counter; received_counter = anti_replay_get_counter(); if(packetbuf_holds_broadcast()) { #if DEBUG if(received_counter < info->his_broadcast_counter.u32) { PRINTF("anti-replay: Broadcast out of order\n"); } #endif /* DEBUG */ if(received_counter <= info->his_broadcast_counter.u32) { return 1; } else { info->his_broadcast_counter.u32 = received_counter; return 0; } } else { #if DEBUG if(received_counter < info->his_unicast_counter.u32) { PRINTF("anti-replay: Unicast out of order\n"); } #endif /* DEBUG */ if(received_counter <= info->his_unicast_counter.u32) { return 1; } else { info->his_unicast_counter.u32 = received_counter; return 0; } } }
/*---------------------------------------------------------------------------*/ int anti_replay_was_replayed(struct anti_replay_info *info) { uint32_t received_counter; received_counter = anti_replay_get_counter(); if(packetbuf_holds_broadcast()) { /* broadcast */ if(received_counter <= info->last_broadcast_counter) { return 1; } else { info->last_broadcast_counter = received_counter; return 0; } } else { /* unicast */ if(received_counter <= info->last_unicast_counter) { return 1; } else { info->last_unicast_counter = received_counter; return 0; } } }
/*---------------------------------------------------------------------------*/ void anti_replay_init_info(struct anti_replay_info *info) { info->last_broadcast_counter = info->last_unicast_counter = anti_replay_get_counter(); }
/*---------------------------------------------------------------------------*/ int anti_replay_set_counter(struct anti_replay_info *receiver_info) { #if ANTI_REPLAY_WITH_SUPPRESSION if(packetbuf_holds_broadcast()) { order_and_set_counter(++anti_replay_my_broadcast_counter); } else { if(++my_unicast_counter == 0xFFFFFFFF) { return 0; } order_and_set_counter(++receiver_info->my_unicast_counter.u32); } #else /* ANTI_REPLAY_WITH_SUPPRESSION */ order_and_set_counter(++my_counter); #endif /* ANTI_REPLAY_WITH_SUPPRESSION */ return (anti_replay_get_counter() != 0xFFFFFFFF); }
/*---------------------------------------------------------------------------*/ 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; }