Contiki 3.x
noncoresec.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Hasso-Plattner-Institut.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * 802.15.4 security implementation, which uses a network-wide key
36  * \author
37  * Konrad Krentz <konrad.krentz@gmail.com>
38  */
39 
40 /**
41  * \addtogroup noncoresec
42  * @{
43  */
44 
46 #include "net/llsec/anti-replay.h"
47 #include "net/llsec/llsec802154.h"
48 #include "net/llsec/ccm-star.h"
49 #include "net/mac/frame802154.h"
50 #include "net/netstack.h"
51 #include "net/packetbuf.h"
52 #include "net/nbr-table.h"
53 #include "net/linkaddr.h"
54 #include "lib/aes-128.h"
55 #include <string.h>
56 
57 #define WITH_ENCRYPTION (LLSEC802154_SECURITY_LEVEL & (1 << 2))
58 
59 #ifdef NONCORESEC_CONF_KEY
60 #define NONCORESEC_KEY NONCORESEC_CONF_KEY
61 #else /* NONCORESEC_CONF_KEY */
62 #define NONCORESEC_KEY { 0x00 , 0x01 , 0x02 , 0x03 , \
63  0x04 , 0x05 , 0x06 , 0x07 , \
64  0x08 , 0x09 , 0x0A , 0x0B , \
65  0x0C , 0x0D , 0x0E , 0x0F }
66 #endif /* NONCORESEC_CONF_KEY */
67 
68 #define SECURITY_HEADER_LENGTH 5
69 
70 #define DEBUG 0
71 #if DEBUG
72 #include <stdio.h>
73 #define PRINTF(...) printf(__VA_ARGS__)
74 #else /* DEBUG */
75 #define PRINTF(...)
76 #endif /* DEBUG */
77 
78 /* network-wide CCM* key */
79 static uint8_t key[16] = NONCORESEC_KEY;
80 NBR_TABLE(struct anti_replay_info, anti_replay_table);
81 
82 /*---------------------------------------------------------------------------*/
83 static const uint8_t *
84 get_extended_address(const linkaddr_t *addr)
85 #if LINKADDR_SIZE == 2
86 {
87  /* workaround for short addresses: derive EUI64 as in RFC 6282 */
88  static linkaddr_extended_t template = { { 0x00 , 0x00 , 0x00 ,
89  0xFF , 0xFE , 0x00 , 0x00 , 0x00 } };
90 
91  template.u16[3] = LLSEC802154_HTONS(addr->u16);
92 
93  return template.u8;
94 }
95 #else /* LINKADDR_SIZE == 2 */
96 {
97  return addr->u8;
98 }
99 #endif /* LINKADDR_SIZE == 2 */
100 /*---------------------------------------------------------------------------*/
101 static void
102 send(mac_callback_t sent, void *ptr)
103 {
104  packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
105  packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, LLSEC802154_SECURITY_LEVEL);
107  NETSTACK_MAC.send(sent, ptr);
108 }
109 /*---------------------------------------------------------------------------*/
110 static int
111 on_frame_created(void)
112 {
113  uint8_t *dataptr;
114  uint8_t data_len;
115 
116  dataptr = packetbuf_dataptr();
117  data_len = packetbuf_datalen();
118 
119  CCM_STAR.mic(get_extended_address(&linkaddr_node_addr), dataptr + data_len, LLSEC802154_MIC_LENGTH);
120 #if WITH_ENCRYPTION
121  CCM_STAR.ctr(get_extended_address(&linkaddr_node_addr));
122 #endif /* WITH_ENCRYPTION */
123  packetbuf_set_datalen(data_len + LLSEC802154_MIC_LENGTH);
124 
125  return 1;
126 }
127 /*---------------------------------------------------------------------------*/
128 static void
129 input(void)
130 {
131  uint8_t generated_mic[LLSEC802154_MIC_LENGTH];
132  uint8_t *received_mic;
133  const linkaddr_t *sender;
134  struct anti_replay_info* info;
135 
136  if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) != LLSEC802154_SECURITY_LEVEL) {
137  PRINTF("noncoresec: received frame with wrong security level\n");
138  return;
139  }
140  sender = packetbuf_addr(PACKETBUF_ADDR_SENDER);
141  if(linkaddr_cmp(sender, &linkaddr_node_addr)) {
142  PRINTF("noncoresec: frame from ourselves\n");
143  return;
144  }
145 
146  packetbuf_set_datalen(packetbuf_datalen() - LLSEC802154_MIC_LENGTH);
147 
148 #if WITH_ENCRYPTION
149  CCM_STAR.ctr(get_extended_address(sender));
150 #endif /* WITH_ENCRYPTION */
151  CCM_STAR.mic(get_extended_address(sender), generated_mic, LLSEC802154_MIC_LENGTH);
152 
153  received_mic = ((uint8_t *) packetbuf_dataptr()) + packetbuf_datalen();
154  if(memcmp(generated_mic, received_mic, LLSEC802154_MIC_LENGTH) != 0) {
155  PRINTF("noncoresec: received nonauthentic frame %"PRIu32"\n",
157  return;
158  }
159 
160  info = nbr_table_get_from_lladdr(anti_replay_table, sender);
161  if(!info) {
162  info = nbr_table_add_lladdr(anti_replay_table, sender);
163  if(!info) {
164  PRINTF("noncoresec: could not get nbr_table_item\n");
165  return;
166  }
167 
168  /*
169  * Locking avoids replay attacks due to removed neighbor table items.
170  * Unfortunately, an attacker can mount a memory-based DoS attack
171  * on this by replaying broadcast frames from other network parts.
172  * However, this is not an issue as long as the network size does not
173  * exceed NBR_TABLE_MAX_NEIGHBORS.
174  *
175  * To avoid locking, we could swap anti-replay information
176  * to external flash. Locking is also unnecessary when using
177  * pairwise session keys, as done in coresec.
178  */
179  if(!nbr_table_lock(anti_replay_table, info)) {
180  nbr_table_remove(anti_replay_table, info);
181  PRINTF("noncoresec: could not lock\n");
182  return;
183  }
184 
185  anti_replay_init_info(info);
186  } else {
187  if(anti_replay_was_replayed(info)) {
188  PRINTF("noncoresec: received replayed frame %"PRIu32"\n",
190  return;
191  }
192  }
193 
194  NETSTACK_NETWORK.input();
195 }
196 /*---------------------------------------------------------------------------*/
197 static uint8_t
198 get_overhead(void)
199 {
200  return SECURITY_HEADER_LENGTH + LLSEC802154_MIC_LENGTH;
201 }
202 /*---------------------------------------------------------------------------*/
203 static void
204 bootstrap(llsec_on_bootstrapped_t on_bootstrapped)
205 {
206  AES_128.set_key(key);
207  nbr_table_register(anti_replay_table, NULL);
208  on_bootstrapped();
209 }
210 /*---------------------------------------------------------------------------*/
211 const struct llsec_driver noncoresec_driver = {
212  "noncoresec",
213  bootstrap,
214  send,
215  on_frame_created,
216  input,
217  get_overhead
218 };
219 /*---------------------------------------------------------------------------*/
220 
221 /** @} */
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
802.15.4 frame creation and parsing functions
void anti_replay_init_info(struct anti_replay_info *info)
Initializes the anti-replay information about the sender.
Definition: anti-replay.c:76
void anti_replay_set_counter(void)
Sets the frame counter packetbuf attributes.
Definition: anti-replay.c:54
int anti_replay_was_replayed(struct anti_replay_info *info)
Checks if received frame was replayed.
Definition: anti-replay.c:84
Header file for the Rime buffer (packetbuf) management
802.15.4 security implementation, which uses a network-wide key
#define NULL
The null pointer.
CCM* header file.
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:200
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:239
AES-128.
The structure of a link layer security driver.
Definition: llsec.h:68
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
Common functionality of 802.15.4-compliant llsec_drivers.
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:207
uint32_t anti_replay_get_counter(void)
Gets the frame counter from packetbuf.
Definition: anti-replay.c:65
Interface to anti-replay mechanisms.
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Rime address representation