1 /*
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that the following conditions
4 * are met:
5 * 1. Redistributions of source code must retain the above copyright
6 * notice, this list of conditions and the following disclaimer.
7 * 2. Redistributions in binary form must reproduce the above copyright
8 * notice, this list of conditions and the following disclaimer in the
9 * documentation and/or other materials provided with the distribution.
10 * 3. Neither the name of the Institute nor the names of its contributors
11 * may be used to endorse or promote products derived from this software
12 * without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * This file is part of the Contiki operating system.
27 *
28 */
29
30 #include "contiki.h"
31 #include "contiki-lib.h"
32 #include "contiki-net.h"
33
34 #include "dev/serial-line.h"
35
36 #include <string.h>
37
38 #include "tinydtls.h"
39
40 #ifndef DEBUG
41 #define DEBUG DEBUG_PRINT
42 #endif
43 #include "net/ip/uip-debug.h"
44
45 #include "debug.h"
46 #include "dtls.h"
47
48 #ifdef DTLS_PSK
49 /* The PSK information for DTLS */
50 /* make sure that default identity and key fit into buffer, i.e.
51 * sizeof(PSK_DEFAULT_IDENTITY) - 1 <= PSK_ID_MAXLEN and
52 * sizeof(PSK_DEFAULT_KEY) - 1 <= PSK_MAXLEN
53 */
54
55 #define PSK_ID_MAXLEN 32
56 #define PSK_MAXLEN 32
57 #define PSK_DEFAULT_IDENTITY "Client_identity"
58 #define PSK_DEFAULT_KEY "secretPSK"
59 #endif /* DTLS_PSK */
60
61 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
62 #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
63
64 #define MAX_PAYLOAD_LEN 120
65
66 static struct uip_udp_conn *client_conn;
67 static dtls_context_t *dtls_context;
68 static char buf[200];
69 static size_t buflen = 0;
70
71 static const unsigned char ecdsa_priv_key[] = {
72 0x41, 0xC1, 0xCB, 0x6B, 0x51, 0x24, 0x7A, 0x14,
73 0x43, 0x21, 0x43, 0x5B, 0x7A, 0x80, 0xE7, 0x14,
74 0x89, 0x6A, 0x33, 0xBB, 0xAD, 0x72, 0x94, 0xCA,
75 0x40, 0x14, 0x55, 0xA1, 0x94, 0xA9, 0x49, 0xFA};
76
77 static const unsigned char ecdsa_pub_key_x[] = {
78 0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
79 0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
80 0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
81 0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52};
82
83 static const unsigned char ecdsa_pub_key_y[] = {
84 0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
85 0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
86 0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
87 0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29};
88
89 static void
try_send(struct dtls_context_t * ctx,session_t * dst)90 try_send(struct dtls_context_t *ctx, session_t *dst) {
91 int res;
92 res = dtls_write(ctx, dst, (uint8 *)buf, buflen);
93 if (res >= 0) {
94 memmove(buf, buf + res, buflen - res);
95 buflen -= res;
96 }
97 }
98
99 static int
read_from_peer(struct dtls_context_t * ctx,session_t * session,uint8 * data,size_t len)100 read_from_peer(struct dtls_context_t *ctx,
101 session_t *session, uint8 *data, size_t len) {
102 size_t i;
103 for (i = 0; i < len; i++)
104 PRINTF("%c", data[i]);
105 return 0;
106 }
107
108 static int
send_to_peer(struct dtls_context_t * ctx,session_t * session,uint8 * data,size_t len)109 send_to_peer(struct dtls_context_t *ctx,
110 session_t *session, uint8 *data, size_t len) {
111
112 struct uip_udp_conn *conn = (struct uip_udp_conn *)dtls_get_app_data(ctx);
113
114 uip_ipaddr_copy(&conn->ripaddr, &session->addr);
115 conn->rport = session->port;
116
117 PRINTF("send to ");
118 PRINT6ADDR(&conn->ripaddr);
119 PRINTF(":%u\n", uip_ntohs(conn->rport));
120
121 uip_udp_packet_send(conn, data, len);
122
123 /* Restore server connection to allow data from any node */
124 /* FIXME: do we want this at all? */
125 memset(&conn->ripaddr, 0, sizeof(conn->ripaddr));
126 memset(&conn->rport, 0, sizeof(conn->rport));
127
128 return len;
129 }
130
131 #ifdef DTLS_PSK
132 static unsigned char psk_id[PSK_ID_MAXLEN] = PSK_DEFAULT_IDENTITY;
133 static size_t psk_id_length = sizeof(PSK_DEFAULT_IDENTITY) - 1;
134 static unsigned char psk_key[PSK_MAXLEN] = PSK_DEFAULT_KEY;
135 static size_t psk_key_length = sizeof(PSK_DEFAULT_KEY) - 1;
136
137 #ifdef __GNUC__
138 #define UNUSED_PARAM __attribute__((unused))
139 #else
140 #define UNUSED_PARAM
141 #endif /* __GNUC__ */
142
143 /* This function is the "key store" for tinyDTLS. It is called to
144 * retrieve a key for the given identity within this particular
145 * session. */
146 static int
get_psk_info(struct dtls_context_t * ctx UNUSED_PARAM,const session_t * session UNUSED_PARAM,dtls_credentials_type_t type,const unsigned char * id,size_t id_len,unsigned char * result,size_t result_length)147 get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM,
148 const session_t *session UNUSED_PARAM,
149 dtls_credentials_type_t type,
150 const unsigned char *id, size_t id_len,
151 unsigned char *result, size_t result_length) {
152
153 switch (type) {
154 case DTLS_PSK_IDENTITY:
155 if (result_length < psk_id_length) {
156 dtls_warn("cannot set psk_identity -- buffer too small\n");
157 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
158 }
159
160 memcpy(result, psk_id, psk_id_length);
161 return psk_id_length;
162 case DTLS_PSK_KEY:
163 if (id_len != psk_id_length || memcmp(psk_id, id, id_len) != 0) {
164 dtls_warn("PSK for unknown id requested, exiting\n");
165 return dtls_alert_fatal_create(DTLS_ALERT_ILLEGAL_PARAMETER);
166 } else if (result_length < psk_key_length) {
167 dtls_warn("cannot set psk -- buffer too small\n");
168 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
169 }
170
171 memcpy(result, psk_key, psk_key_length);
172 return psk_key_length;
173 default:
174 dtls_warn("unsupported request type: %d\n", type);
175 }
176
177 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
178 }
179 #endif /* DTLS_PSK */
180
181 #ifdef DTLS_ECC
182 static int
get_ecdsa_key(struct dtls_context_t * ctx,const session_t * session,const dtls_ecdsa_key_t ** result)183 get_ecdsa_key(struct dtls_context_t *ctx,
184 const session_t *session,
185 const dtls_ecdsa_key_t **result) {
186 static const dtls_ecdsa_key_t ecdsa_key = {
187 .curve = DTLS_ECDH_CURVE_SECP256R1,
188 .priv_key = ecdsa_priv_key,
189 .pub_key_x = ecdsa_pub_key_x,
190 .pub_key_y = ecdsa_pub_key_y
191 };
192
193 *result = &ecdsa_key;
194 return 0;
195 }
196
197 static int
verify_ecdsa_key(struct dtls_context_t * ctx,const session_t * session,const unsigned char * other_pub_x,const unsigned char * other_pub_y,size_t key_size)198 verify_ecdsa_key(struct dtls_context_t *ctx,
199 const session_t *session,
200 const unsigned char *other_pub_x,
201 const unsigned char *other_pub_y,
202 size_t key_size) {
203 return 0;
204 }
205 #endif /* DTLS_ECC */
206
207 PROCESS(udp_server_process, "UDP server process");
208 AUTOSTART_PROCESSES(&udp_server_process);
209 /*---------------------------------------------------------------------------*/
210 static void
dtls_handle_read(dtls_context_t * ctx)211 dtls_handle_read(dtls_context_t *ctx) {
212 static session_t session;
213
214 if(uip_newdata()) {
215 uip_ipaddr_copy(&session.addr, &UIP_IP_BUF->srcipaddr);
216 session.port = UIP_UDP_BUF->srcport;
217 session.size = sizeof(session.addr) + sizeof(session.port);
218
219 ((char *)uip_appdata)[uip_datalen()] = 0;
220 PRINTF("Client received message from ");
221 PRINT6ADDR(&session.addr);
222 PRINTF(":%d\n", uip_ntohs(session.port));
223
224 dtls_handle_message(ctx, &session, uip_appdata, uip_datalen());
225 }
226 }
227 /*---------------------------------------------------------------------------*/
228 static void
print_local_addresses(void)229 print_local_addresses(void)
230 {
231 int i;
232 uint8_t state;
233
234 PRINTF("Client IPv6 addresses: ");
235 for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
236 state = uip_ds6_if.addr_list[i].state;
237 if(uip_ds6_if.addr_list[i].isused &&
238 (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
239 PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr);
240 PRINTF("\n");
241 }
242 }
243 }
244
245 static void
set_connection_address(uip_ipaddr_t * ipaddr)246 set_connection_address(uip_ipaddr_t *ipaddr)
247 {
248 #define _QUOTEME(x) #x
249 #define QUOTEME(x) _QUOTEME(x)
250 #ifdef UDP_CONNECTION_ADDR
251 if(uiplib_ipaddrconv(QUOTEME(UDP_CONNECTION_ADDR), ipaddr) == 0) {
252 PRINTF("UDP client failed to parse address '%s'\n", QUOTEME(UDP_CONNECTION_ADDR));
253 }
254 #elif UIP_CONF_ROUTER
255 uip_ip6addr(ipaddr,0xaaaa,0,0,0,0x0200,0x0000,0x0000,0x0001);
256 #else
257 uip_ip6addr(ipaddr,0xfe80,0,0,0,0x6466,0x6666,0x6666,0x6666);
258 #endif /* UDP_CONNECTION_ADDR */
259 }
260
261 void
init_dtls(session_t * dst)262 init_dtls(session_t *dst) {
263 static dtls_handler_t cb = {
264 .write = send_to_peer,
265 .read = read_from_peer,
266 .event = NULL,
267 #ifdef DTLS_PSK
268 .get_psk_info = get_psk_info,
269 #endif /* DTLS_PSK */
270 #ifdef DTLS_ECC
271 .get_ecdsa_key = get_ecdsa_key,
272 .verify_ecdsa_key = verify_ecdsa_key
273 #endif /* DTLS_ECC */
274 };
275 PRINTF("DTLS client started\n");
276
277 print_local_addresses();
278
279 dst->size = sizeof(dst->addr) + sizeof(dst->port);
280 dst->port = UIP_HTONS(20220);
281
282 set_connection_address(&dst->addr);
283 client_conn = udp_new(&dst->addr, 0, NULL);
284 udp_bind(client_conn, dst->port);
285
286 PRINTF("set connection address to ");
287 PRINT6ADDR(&dst->addr);
288 PRINTF(":%d\n", uip_ntohs(dst->port));
289
290 dtls_set_log_level(DTLS_LOG_DEBUG);
291
292 dtls_context = dtls_new_context(client_conn);
293 if (dtls_context)
294 dtls_set_handler(dtls_context, &cb);
295 }
296
297 /*---------------------------------------------------------------------------*/
PROCESS_THREAD(udp_server_process,ev,data)298 PROCESS_THREAD(udp_server_process, ev, data)
299 {
300 static int connected = 0;
301 static session_t dst;
302
303 PROCESS_BEGIN();
304
305 dtls_init();
306
307 init_dtls(&dst);
308 serial_line_init();
309
310 if (!dtls_context) {
311 dtls_emerg("cannot create context\n");
312 PROCESS_EXIT();
313 }
314
315 while(1) {
316 PROCESS_YIELD();
317 if(ev == tcpip_event) {
318 dtls_handle_read(dtls_context);
319 } else if (ev == serial_line_event_message) {
320 register size_t len = min(strlen(data), sizeof(buf) - buflen);
321 memcpy(buf + buflen, data, len);
322 buflen += len;
323 if (buflen < sizeof(buf) - 1)
324 buf[buflen++] = '\n'; /* serial event does not contain LF */
325 }
326
327 if (buflen) {
328 if (!connected)
329 connected = dtls_connect(dtls_context, &dst) >= 0;
330
331 try_send(dtls_context, &dst);
332 }
333 }
334
335 PROCESS_END();
336 }
337 /*---------------------------------------------------------------------------*/
338