1 /*
2 * Copyright (c) 2015 Intel Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /* Various utility functions taken from libcoap with this license:
18
19 Copyright (c) 2010--2015, Olaf Bergmann
20 All rights reserved.
21
22 Redistribution and use in source and binary forms, with or without
23 modification, are permitted provided that the following conditions are
24 met:
25
26 o Redistributions of source code must retain the above copyright
27 notice, this list of conditions and the following disclaimer.
28
29 o Redistributions in binary form must reproduce the above copyright
30 notice, this list of conditions and the following disclaimer in
31 the documentation and/or other materials provided with the
32 distribution.
33
34 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
35 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
36 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
37 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
38 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
39 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
41 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
42 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
43 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
44 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 */
46
47 #include <stdio.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <poll.h>
51 #include <errno.h>
52 #include <arpa/inet.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <stdbool.h>
56 #include <net/if.h>
57 #include <linux/sockios.h>
58 #include <ifaddrs.h>
59 #include <signal.h>
60 #include <sys/ioctl.h>
61 #include <unistd.h>
62
63 #include <tinydtls.h>
64 #include <global.h>
65 #include <debug.h>
66 #include <dtls.h>
67
68 /* tinyDTLS and libcoap have same preprocessor symbols defined in their
69 * include files so undef conflicting symbols here.
70 */
71 #undef PACKAGE_BUGREPORT
72 #undef PACKAGE_NAME
73 #undef PACKAGE_STRING
74 #undef PACKAGE_TARNAME
75 #undef PACKAGE_URL
76 #undef PACKAGE_VERSION
77 #undef UTHASH_VERSION
78 #undef HASH_FIND
79 #undef HASH_ADD
80 #undef HASH_ADD_KEYPTR
81 #undef HASH_DELETE
82 #undef HASH_FIND_STR
83 #undef HASH_ADD_STR
84 #undef HASH_BER
85 #undef HASH_FNV
86 #undef HASH_JEN
87 #undef HASH_SFH
88 #undef HASH_FIND_IN_BKT
89 #undef HASH_SRT
90 #undef HASH_CLEAR
91 #undef UTLIST_VERSION
92 #undef _NEXT
93 #undef _NEXTASGN
94 #undef _PREVASGN
95 #undef LL_SORT
96 #undef DL_SORT
97 #undef CDL_SORT
98 #undef LL_PREPEND
99 #undef LL_APPEND
100 #undef LL_DELETE
101 #undef LL_APPEND_VS2008
102 #undef LL_DELETE_VS2008
103 #undef LL_FOREACH
104 #undef LL_FOREACH_SAFE
105 #undef LL_SEARCH_SCALAR
106 #undef LL_SEARCH
107 #undef DL_PREPEND
108 #undef DL_APPEND
109 #undef DL_DELETE
110 #undef DL_FOREACH
111 #undef DL_FOREACH_SAFE
112 #undef CDL_PREPEND
113 #undef CDL_DELETE
114 #undef CDL_FOREACH
115 #undef CDL_FOREACH_SAFE
116 #undef CDL_SEARCH_SCALAR
117 #undef CDL_SEARCH
118 #define UTHASH_H
119
120 #include <coap/coap.h>
121
122 typedef struct coap_list_t {
123 struct coap_list_t *next;
124 char data[];
125 } coap_list_t;
126
127 #ifdef __GNUC__
128 #define UNUSED_PARAM __attribute__((unused))
129 #else
130 #define UNUSED_PARAM
131 #endif /* __GNUC__ */
132
133 #define SERVER_PORT 5683
134 #define SERVER_SECURE_PORT 5684
135
136 #define CLIENT_PORT 8484
137 #define MAX_BUF_SIZE 1280 /* min IPv6 MTU, the actual data is smaller */
138 #define MAX_TIMEOUT 6 /* in seconds */
139
140 static bool debug;
141 static int renegotiate = -1;
142 static session_t session;
143 static bool no_dtls;
144 static const char *target;
145 static int family;
146
147 static coap_block_t block = {
148 .num = 0,
149 .m = 0,
150 .szx = 6
151 };
152 static unsigned int wait_seconds = MAX_TIMEOUT; /* default timeout in secs */
153 static coap_tick_t max_wait;
154 static unsigned int obs_seconds = MAX_TIMEOUT * 2; /* default observe time */
155 static coap_tick_t obs_wait = 0; /* timeout for current subscription */
156 static int ready = 0;
157 static coap_list_t *optlist;
158 static unsigned char _token_data[8];
159 static str the_token = { 0, _token_data };
160 typedef unsigned char method_t;
161 static str payload = { 0, NULL }; /* optional payload to send */
162 static int flags = 0;
163 #define FLAGS_BLOCK 0x01
164 static method_t method;
165
166 static coap_pdu_t *coap_new_request(coap_context_t *ctx,
167 method_t m,
168 coap_list_t **options,
169 const unsigned char *data,
170 size_t length,
171 int msgtype);
172
173 #define ENTRY(desc, entry, expect_result, method, test_data, length, mid,\
174 confirmed) \
175 { \
176 .description = #desc , \
177 .len = sizeof(entry), \
178 .buf = entry, \
179 .expecting_reply = expect_result, \
180 .data = test_data, \
181 .data_len = length, \
182 .coap_method = COAP_REQUEST_ ## method, \
183 .check_mid = mid, \
184 .message_type = confirmed, \
185 }
186
187 #define ENTRY2(desc, entry, expect_result, method, test_data, length, \
188 test_payload, test_payload_len, mid, confirmed) \
189 { \
190 .description = #desc , \
191 .len = sizeof(entry), \
192 .buf = entry, \
193 .expecting_reply = expect_result, \
194 .data = test_data, \
195 .data_len = length, \
196 .payload = test_payload, \
197 .payload_len = test_payload_len, \
198 .coap_method = COAP_REQUEST_ ## method, \
199 .check_mid = mid, \
200 .message_type = confirmed, \
201 }
202
203 #define ENTRY3(desc, entry, expect_result, method, test_data, length, mid,\
204 confirmed) \
205 { \
206 .description = #desc , \
207 .len = sizeof(entry), \
208 .buf = entry, \
209 .expecting_reply = expect_result, \
210 .data = test_data, \
211 .data_len = length, \
212 .coap_method = COAP_REQUEST_ ## method, \
213 .check_mid = mid, \
214 .message_type = confirmed, \
215 .add_token = true, \
216 }
217
218 #define ENTRY4(desc, entry, expect_result, method, test_data, length, \
219 test_payload, test_payload_len, mid, confirmed) \
220 { \
221 .description = #desc , \
222 .len = sizeof(entry), \
223 .buf = entry, \
224 .expecting_reply = expect_result, \
225 .data = test_data, \
226 .data_len = length, \
227 .payload = test_payload, \
228 .payload_len = test_payload_len, \
229 .coap_method = COAP_REQUEST_ ## method, \
230 .check_mid = mid, \
231 .message_type = confirmed, \
232 .add_token = true, \
233 }
234
235 #define GET_CON(desc, e, r, c) ENTRY(desc, e, true, GET, r, sizeof(r), c, \
236 COAP_MESSAGE_CON)
237 #define POST_CON(desc, e, r, c) ENTRY(desc, e, true, POST, r, sizeof(r), c, \
238 COAP_MESSAGE_CON)
239 #define PUT_CON(desc, e, d, p, c) ENTRY2(desc, e, true, PUT, d, sizeof(d), \
240 p, sizeof(p), c, COAP_MESSAGE_CON)
241 #define DELETE_CON(desc,e, r, c) ENTRY(desc, e, true, DELETE, r, sizeof(r), c,\
242 COAP_MESSAGE_CON)
243
244 #define GET_NON(desc, e, r, c) ENTRY(desc, e, true, GET, r, sizeof(r), c, \
245 COAP_MESSAGE_NON)
246 #define POST_NON(desc, e, r, c) ENTRY(desc, e, true, POST, r, sizeof(r), c, \
247 COAP_MESSAGE_NON)
248 #define PUT_NON(desc, e, d, p, c) ENTRY2(desc, e, true, PUT, d, sizeof(d), \
249 p, sizeof(p), c, COAP_MESSAGE_NON)
250 #define DELETE_NON(desc,e, r, c) ENTRY(desc, e, true, DELETE, r, sizeof(r), c,\
251 COAP_MESSAGE_NON)
252
253 #define GET_CON_TOKEN(desc, e, r, c) ENTRY3(desc, e, true, GET, r, sizeof(r), \
254 c, COAP_MESSAGE_CON)
255 #define POST_CON_TOKEN(desc, e, r, c) ENTRY3(desc, e, true, POST, r, \
256 sizeof(r), c, COAP_MESSAGE_CON)
257 #define PUT_CON_TOKEN(desc, e, d, p, c) ENTRY4(desc, e, true, PUT, d, \
258 sizeof(d), p, sizeof(p), c,\
259 COAP_MESSAGE_CON)
260 #define DELETE_CON_TOKEN(desc,e, r, c) ENTRY3(desc, e, true, DELETE, r, \
261 sizeof(r), c, COAP_MESSAGE_CON)
262
263 #define GET_CON_PAYLOAD(desc, e, d, p, c) ENTRY2(desc, e, true, GET, \
264 d, sizeof(d), \
265 p, sizeof(p), c, \
266 COAP_MESSAGE_CON)
267
268 #define RES(var, path) \
269 static const char res_ ## var [] = path ;
270
271 #define DATA_ARRAY(var, data, ...) \
272 static const char var [] = { data, __VA_ARGS__ } ;
273
274 #define DATA_STRING(var, data) \
275 static const char var [] = data;
276
277 RES(core, ".well-known/core");
278 RES(test, "test");
279 RES(seg, "seg1/seg2/seg3");
280 RES(query, "query");
281
282 /* See this test specification document for different test descriptions
283 * http://www.etsi.org/plugtests/CoAP/Document/CoAP_TestDescriptions_v015.pdf
284 */
285 DATA_STRING(get_con, "Type: 0\nCode: 1\n");
286 DATA_STRING(post_con, "Type: 0\nCode: 2\n");
287 DATA_STRING(put_con, "Type: 0\nCode: 3\n");
288 DATA_STRING(delete_con, "Type: 0\nCode: 4\n");
289 DATA_STRING(get_non, "Type: 1\nCode: 1\n");
290 DATA_STRING(post_non, "Type: 1\nCode: 2\n");
291 DATA_STRING(put_non, "Type: 1\nCode: 3\n");
292 DATA_STRING(delete_non, "Type: 1\nCode: 4\n");
293
294 /* Generated by http://www.lipsum.com/
295 * 1202 bytes of Lorem Ipsum.
296 *
297 * This is the maximum we can send with encryption.
298 */
299 static const char lorem_ipsum[] =
300 "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin congue orci et lectus ultricies, sed elementum urna finibus. Nam bibendum, massa id sollicitudin finibus, massa ante pharetra lacus, nec semper felis metus eu massa. Curabitur gravida, neque a pulvinar suscipit, felis massa maximus neque, eu sagittis felis enim nec justo. Suspendisse sit amet sem a magna aliquam tincidunt. Mauris consequat ante in consequat auctor. Nam eu congue mauris, congue aliquet metus. Etiam elit ipsum, vehicula et lectus at, dignissim accumsan turpis. Sed magna nisl, tempor ut dolor sed, feugiat pharetra velit. Nulla sed purus at elit dapibus lobortis. In hac habitasse platea dictumst. Praesent quis libero id enim aliquet viverra eleifend non urna. Vivamus metus justo, dignissim eget libero molestie, tincidunt pellentesque purus. Quisque pulvinar, nisi sed egestas vestibulum, ante felis elementum justo, ut viverra nisl est sagittis leo. Curabitur pharetra eros at felis ultricies efficitur."
301 "\n"
302 "Ut rutrum urna vitae neque rhoncus, id dictum ex dictum. Suspendisse venenatis vel mauris sed maximus. Sed malesuada elit vel neque hendrerit, in accumsan odio sodales. Aliquam erat volutpat. Praesent non situ.\n";
303
304 static const char lorem_ipsum_short[] = "Lorem ipsum dolor sit amet.";
305
306 static struct data {
307 const char *description;
308 int len;
309 method_t coap_method;
310 const unsigned char *buf;
311 bool expecting_reply;
312 const unsigned char *data; /* data to be sent */
313 int data_len;
314 const unsigned char *payload; /* possible payload to be sent */
315 int payload_len;
316 bool check_mid;
317 int expected_mid; /* message id we sent */
318 int message_type;
319 bool add_token;
320 } data[] = {
321 GET_CON(TD_COAP_CORE_01, res_test, get_con, true),
322 POST_CON(TD_COAP_CORE_02, res_test, post_con, false),
323 PUT_CON(TD_COAP_CORE_03, res_test, put_con, lorem_ipsum, false),
324 DELETE_CON(TD_COAP_CORE_04, res_test, delete_con, false),
325
326 GET_NON(TD_COAP_CORE_05, res_test, get_non, true),
327 POST_NON(TD_COAP_CORE_06, res_test, post_non, false),
328 PUT_NON(TD_COAP_CORE_07, res_test, put_non, lorem_ipsum, false),
329 DELETE_NON(TD_COAP_CORE_08, res_test, delete_non, false),
330
331 /* /separate not supported atm */
332 //GET_CON(TD_COAP_CORE_09, res_separate, get_con, true),
333
334 GET_CON_TOKEN(TD_COAP_CORE_10, res_test, get_con, true),
335
336 /* Isn't test case 11 same as test case 01? */
337 GET_CON(TD_COAP_CORE_11, res_test, get_con, true),
338
339 GET_CON(TD_COAP_CORE_12, res_seg, get_con, true),
340 GET_CON(TD_COAP_CORE_13, res_query, get_con, true),
341
342 /* Test 14 & 15 are for testing gateway scenario so not used here */
343 // TD_COAP_CORE_14
344 // TD_COAP_CORE_15
345
346 /* /separate not supported atm */
347 //GET_NON(TD_COAP_CORE_16, res_separate, get_con, true),
348
349 #if TO_BE_DONE
350 GET_CON(TD_COAP_LINK_01, res_core, get_con, true),
351 //TD_COAP_LINK_02
352
353 // TD_COAP_BLOCK_01
354 // TD_COAP_BLOCK_02
355 // TD_COAP_BLOCK_03
356 // TD_COAP_BLOCK_04
357
358 // TD_COAP_OBS_01
359 // TD_COAP_OBS_02
360 // TD_COAP_OBS_03
361 // TD_COAP_OBS_04
362 // TD_COAP_OBS_05
363 #endif
364
365 { 0, 0 }
366 };
367
368 struct client_data {
369 bool fail;
370 int fd;
371 int index; /* position in data[] */
372 int ifindex; /* network interface index */
373 coap_context_t *coap_ctx;
374 coap_address_t coap_dst;
375 int len;
376 #define MAX_READ_BUF 2000
377 uint8 buf[MAX_READ_BUF];
378 };
379 static struct client_data *test_context;
380
set_coap_timeout(coap_tick_t * timer,const unsigned int seconds)381 static void set_coap_timeout(coap_tick_t *timer, const unsigned int seconds)
382 {
383 coap_ticks(timer);
384 *timer += seconds * COAP_TICKS_PER_SECOND;
385 }
386
get_ifindex(const char * name)387 static int get_ifindex(const char *name)
388 {
389 struct ifreq ifr;
390 int sk, err;
391
392 if (!name)
393 return -1;
394
395 sk = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
396 if (sk < 0)
397 return -1;
398
399 memset(&ifr, 0, sizeof(ifr));
400 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name) - 1);
401
402 err = ioctl(sk, SIOCGIFINDEX, &ifr);
403
404 close(sk);
405
406 if (err < 0)
407 return -1;
408
409 return ifr.ifr_ifindex;
410 }
411
find_address(int family,struct ifaddrs * if_address,const char * if_name,void * address)412 static int find_address(int family, struct ifaddrs *if_address,
413 const char *if_name, void *address)
414 {
415 struct ifaddrs *tmp;
416 struct sockaddr_in6 *ll = NULL;
417 int error = -ENOENT;
418
419 for (tmp = if_address; tmp; tmp = tmp->ifa_next) {
420 if (tmp->ifa_addr &&
421 !strncmp(tmp->ifa_name, if_name, IF_NAMESIZE) &&
422 tmp->ifa_addr->sa_family == family) {
423
424 switch (family) {
425 case AF_INET: {
426 struct sockaddr_in *in4 =
427 (struct sockaddr_in *)tmp->ifa_addr;
428 if (in4->sin_addr.s_addr == INADDR_ANY)
429 continue;
430 if ((in4->sin_addr.s_addr & IN_CLASSB_NET) ==
431 ((in_addr_t)0xa9fe0000))
432 continue;
433 memcpy(address, &in4->sin_addr,
434 sizeof(struct in_addr));
435 error = 0;
436 goto out;
437 }
438 case AF_INET6: {
439 struct sockaddr_in6 *in6 =
440 (struct sockaddr_in6 *)tmp->ifa_addr;
441 if (!memcmp(&in6->sin6_addr, &in6addr_any,
442 sizeof(struct in6_addr)))
443 continue;
444 if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
445 ll = in6;
446 continue;
447 }
448
449 memcpy(address, &in6->sin6_addr,
450 sizeof(struct in6_addr));
451 error = 0;
452 goto out;
453 }
454 default:
455 error = -EINVAL;
456 goto out;
457 }
458 }
459 }
460
461 out:
462 if (error < 0 && ll) {
463 /* As a last resort use link local address */
464 memcpy(address, &ll->sin6_addr, sizeof(struct in6_addr));
465 error = 0;
466 }
467
468 return error;
469 }
470
get_address(const char * if_name,int family,void * address)471 static int get_address(const char *if_name, int family, void *address)
472 {
473 struct ifaddrs *if_address;
474 int err;
475
476 if (getifaddrs(&if_address) < 0) {
477 err = -errno;
478 fprintf(stderr, "Cannot get interface addresses for "
479 "interface %s error %d/%s",
480 if_name, err, strerror(-err));
481 return err;
482 }
483
484 err = find_address(family, if_address, if_name, address);
485
486 freeifaddrs(if_address);
487
488 return err;
489 }
490
491 #define PSK_DEFAULT_IDENTITY "Client_identity"
492 #define PSK_DEFAULT_KEY "secretPSK"
493 #define PSK_OPTIONS "i:k:"
494
495 static bool quit = false;
496 static dtls_context_t *dtls_context;
497
498 static const unsigned char ecdsa_priv_key[] = {
499 0x41, 0xC1, 0xCB, 0x6B, 0x51, 0x24, 0x7A, 0x14,
500 0x43, 0x21, 0x43, 0x5B, 0x7A, 0x80, 0xE7, 0x14,
501 0x89, 0x6A, 0x33, 0xBB, 0xAD, 0x72, 0x94, 0xCA,
502 0x40, 0x14, 0x55, 0xA1, 0x94, 0xA9, 0x49, 0xFA};
503
504 static const unsigned char ecdsa_pub_key_x[] = {
505 0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
506 0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
507 0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
508 0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52};
509
510 static const unsigned char ecdsa_pub_key_y[] = {
511 0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
512 0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
513 0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
514 0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29};
515
516 #ifdef DTLS_PSK
517 /* The PSK information for DTLS */
518 #define PSK_ID_MAXLEN 256
519 #define PSK_MAXLEN 256
520 static unsigned char psk_id[PSK_ID_MAXLEN];
521 static size_t psk_id_length = 0;
522 static unsigned char psk_key[PSK_MAXLEN];
523 static size_t psk_key_length = 0;
524
525 /* This function is the "key store" for tinyDTLS. It is called to
526 * retrieve a key for the given identity within this particular
527 * session. */
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)528 static int get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM,
529 const session_t *session UNUSED_PARAM,
530 dtls_credentials_type_t type,
531 const unsigned char *id, size_t id_len,
532 unsigned char *result, size_t result_length)
533 {
534 switch (type) {
535 case DTLS_PSK_IDENTITY:
536 if (id_len) {
537 dtls_debug("got psk_identity_hint: '%.*s'\n", id_len,
538 id);
539 }
540
541 if (result_length < psk_id_length) {
542 dtls_warn("cannot set psk_identity -- buffer too small\n");
543 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
544 }
545
546 memcpy(result, psk_id, psk_id_length);
547 return psk_id_length;
548
549 case DTLS_PSK_KEY:
550 if (id_len != psk_id_length || memcmp(psk_id, id, id_len) != 0) {
551 dtls_warn("PSK for unknown id requested, exiting\n");
552 return dtls_alert_fatal_create(DTLS_ALERT_ILLEGAL_PARAMETER);
553 } else if (result_length < psk_key_length) {
554 dtls_warn("cannot set psk -- buffer too small\n");
555 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
556 }
557
558 memcpy(result, psk_key, psk_key_length);
559 return psk_key_length;
560
561 default:
562 dtls_warn("unsupported request type: %d\n", type);
563 }
564
565 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
566 }
567 #endif /* DTLS_PSK */
568
569 #ifdef DTLS_ECC
get_ecdsa_key(struct dtls_context_t * ctx,const session_t * session,const dtls_ecdsa_key_t ** result)570 static int get_ecdsa_key(struct dtls_context_t *ctx,
571 const session_t *session,
572 const dtls_ecdsa_key_t **result)
573 {
574 static const dtls_ecdsa_key_t ecdsa_key = {
575 .curve = DTLS_ECDH_CURVE_SECP256R1,
576 .priv_key = ecdsa_priv_key,
577 .pub_key_x = ecdsa_pub_key_x,
578 .pub_key_y = ecdsa_pub_key_y
579 };
580
581 *result = &ecdsa_key;
582 return 0;
583 }
584
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)585 static int verify_ecdsa_key(struct dtls_context_t *ctx,
586 const session_t *session,
587 const unsigned char *other_pub_x,
588 const unsigned char *other_pub_y,
589 size_t key_size)
590 {
591 return 0;
592 }
593 #endif /* DTLS_ECC */
594
print_data(const unsigned char * packet,int length)595 static void print_data(const unsigned char *packet, int length)
596 {
597 int n = 0;
598
599 while (length--) {
600 if (n % 16 == 0)
601 printf("%X: ", n);
602
603 printf("%X ", *packet++);
604
605 n++;
606 if (n % 8 == 0) {
607 if (n % 16 == 0)
608 printf("\n");
609 else
610 printf(" ");
611 }
612 }
613 printf("\n");
614 }
615
new_option_node(unsigned short key,unsigned int length,unsigned char * data)616 static coap_list_t *new_option_node(unsigned short key,
617 unsigned int length,
618 unsigned char *data)
619 {
620 coap_list_t *node;
621
622 node = coap_malloc(sizeof(coap_list_t) + sizeof(coap_option) + length);
623
624 if (node) {
625 coap_option *option = (coap_option *)(node->data);
626
627 COAP_OPTION_KEY(*option) = key;
628 COAP_OPTION_LENGTH(*option) = length;
629 memcpy(COAP_OPTION_DATA(*option), data, length);
630 } else {
631 coap_log(LOG_DEBUG, "new_option_node: malloc\n");
632 }
633
634 return node;
635 }
636
coap_insert(coap_list_t ** head,coap_list_t * node)637 static int coap_insert(coap_list_t **head, coap_list_t *node)
638 {
639 if (!node) {
640 coap_log(LOG_WARNING, "cannot create option Proxy-Uri\n");
641 } else {
642 LL_APPEND((*head), node);
643 }
644
645 return node != NULL;
646 }
647
coap_delete(coap_list_t * node)648 static int coap_delete(coap_list_t *node)
649 {
650 if (node) {
651 coap_free(node);
652 }
653 return 1;
654 }
655
coap_delete_list(coap_list_t * queue)656 static void coap_delete_list(coap_list_t *queue)
657 {
658 coap_list_t *elt, *tmp;
659
660 if (!queue)
661 return;
662
663 LL_FOREACH_SAFE(queue, elt, tmp) {
664 coap_delete(elt);
665 }
666 }
667
parse_uri(const char * arg)668 static coap_list_t *parse_uri(const char *arg)
669 {
670 coap_uri_t uri;
671 coap_list_t *opts = NULL;
672 #define BUFSIZE 40
673 unsigned char _buf[BUFSIZE];
674 unsigned char *buf = _buf;
675 size_t buflen;
676 int res;
677
678 coap_split_uri((unsigned char *)arg, strlen(arg), &uri );
679
680 if (uri.path.length) {
681 buflen = BUFSIZE;
682 res = coap_split_path(uri.path.s, uri.path.length,
683 buf, &buflen);
684
685 while (res--) {
686 coap_insert(&opts,
687 new_option_node(COAP_OPTION_URI_PATH,
688 COAP_OPT_LENGTH(buf),
689 COAP_OPT_VALUE(buf)));
690
691 buf += COAP_OPT_SIZE(buf);
692 }
693 }
694
695 if (uri.query.length) {
696 buflen = BUFSIZE;
697 buf = _buf;
698 res = coap_split_query(uri.query.s, uri.query.length,
699 buf, &buflen);
700
701 while (res--) {
702 coap_insert(&opts,
703 new_option_node(COAP_OPTION_URI_QUERY,
704 COAP_OPT_LENGTH(buf),
705 COAP_OPT_VALUE(buf)));
706
707 buf += COAP_OPT_SIZE(buf);
708 }
709 }
710
711 return opts;
712 }
713
clone_option(coap_list_t * item)714 static coap_list_t *clone_option(coap_list_t *item)
715 {
716 coap_list_t *node;
717 coap_option *option = (coap_option *)(item->data);
718
719 node = coap_malloc(sizeof(coap_list_t) + sizeof(coap_option) +
720 option->length);
721 if (node) {
722 memcpy(node->data, option,
723 sizeof(coap_option) + option->length);
724 return node;
725 } else
726 return NULL;
727 }
728
create_uri(char * uri,int len,const char * target,struct client_data * user_data)729 static char *create_uri(char *uri, int len, const char *target,
730 struct client_data *user_data)
731 {
732 snprintf(uri, len, "coap://%s%s%s/%s",
733 family == AF_INET6 ? "[" : "",
734 target,
735 family == AF_INET6 ? "]" : "",
736 data[user_data->index].buf);
737
738 if (debug)
739 print_data(uri, data[user_data->index].len);
740
741 return uri;
742 }
743
create_pdu(struct client_data * user_data)744 static coap_pdu_t *create_pdu(struct client_data *user_data)
745 {
746 coap_pdu_t *pdu;
747 coap_list_t *opts;
748 coap_list_t *elt, *tmp;
749 #define MAX_URI 256
750 char uri_buf[MAX_URI], *uri;
751 const unsigned char *send_data = NULL;
752 int send_data_len = 0;
753
754 uri = create_uri(uri_buf, MAX_URI, target, user_data);
755 opts = parse_uri(uri);
756
757 LL_FOREACH_SAFE(optlist, elt, tmp) {
758 coap_insert(&opts,
759 clone_option(elt));
760 }
761
762 if (data[user_data->index].data) {
763 send_data = data[user_data->index].data;
764 send_data_len = data[user_data->index].data_len;
765 if (send_data[send_data_len] == '\0')
766 send_data_len--; /* skip the null at the end */
767 }
768 pdu = coap_new_request(user_data->coap_ctx,
769 data[user_data->index].coap_method,
770 &opts,
771 send_data, send_data_len,
772 data[user_data->index].message_type);
773 if (pdu) {
774 if (data[user_data->index].check_mid)
775 data[user_data->index].expected_mid = ntohs(pdu->hdr->id);
776 }
777 coap_delete_list(opts);
778
779 return pdu;
780 }
781
send_packets(struct client_data * user_data)782 static void send_packets(struct client_data *user_data)
783 {
784 int ret;
785 coap_pdu_t *pdu;
786 coap_tid_t tid;
787
788 printf("%s: sending [%d] %d bytes\n",
789 data[user_data->index].description,
790 user_data->index, data[user_data->index].len);
791
792 test_context = user_data;
793
794 pdu = create_pdu(user_data);
795 if (!pdu) {
796 /* Failure */
797 quit = true;
798 user_data->fail = true;
799 printf("Cannot allocate pdu\n");
800 return;
801 }
802
803 method = data[user_data->index].coap_method;
804
805 if (coap_get_log_level() >= LOG_DEBUG) {
806 printf("sending CoAP request:\n");
807 coap_show_pdu(pdu);
808 }
809
810 if (pdu->hdr->type == COAP_MESSAGE_CON)
811 tid = coap_send_confirmed(user_data->coap_ctx,
812 user_data->coap_ctx->endpoint,
813 &user_data->coap_dst,
814 pdu);
815 else
816 tid = coap_send(user_data->coap_ctx,
817 user_data->coap_ctx->endpoint,
818 &user_data->coap_dst,
819 pdu);
820
821 if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
822 coap_delete_pdu(pdu);
823
824 set_coap_timeout(&max_wait, wait_seconds);
825
826 if (debug)
827 printf("timeout is set to %d seconds\n", wait_seconds);
828 }
829
try_send(struct dtls_context_t * ctx)830 static void try_send(struct dtls_context_t *ctx)
831 {
832 struct client_data *user_data =
833 (struct client_data *)dtls_get_app_data(ctx);
834 int ret;
835 coap_pdu_t *pdu;
836 coap_tid_t tid;
837
838 printf("%s: sending [%d] %d bytes\n",
839 data[user_data->index].description,
840 user_data->index, data[user_data->index].len);
841
842 test_context = user_data;
843
844 pdu = create_pdu(user_data);
845 if (!pdu) {
846 /* Failure */
847 quit = true;
848 user_data->fail = true;
849 printf("Cannot allocate pdu\n");
850 return;
851 }
852
853 method = data[user_data->index].coap_method;
854
855 if (coap_get_log_level() >= LOG_DEBUG) {
856 printf("sending CoAP request:\n");
857 coap_show_pdu(pdu);
858 }
859
860 if (pdu->hdr->type == COAP_MESSAGE_CON)
861 tid = coap_send_confirmed(user_data->coap_ctx,
862 user_data->coap_ctx->endpoint,
863 &user_data->coap_dst,
864 pdu);
865 else
866 tid = coap_send(user_data->coap_ctx,
867 user_data->coap_ctx->endpoint,
868 &user_data->coap_dst,
869 pdu);
870
871 if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
872 coap_delete_pdu(pdu);
873
874 set_coap_timeout(&max_wait, wait_seconds);
875
876 if (debug)
877 printf("timeout is set to %d seconds\n", wait_seconds);
878 }
879
dispatch_data(char * buf,ssize_t bytes_read,coap_context_t * ctx,coap_address_t * src)880 static int dispatch_data(char *buf, ssize_t bytes_read,
881 coap_context_t *ctx, coap_address_t *src)
882 {
883 coap_hdr_t *pdu;
884 coap_queue_t *node;
885
886 pdu = (coap_hdr_t *)buf;
887
888 if ((size_t)bytes_read < sizeof(coap_hdr_t)) {
889 printf("coap_read: discarded invalid frame\n");
890 goto error_early;
891 }
892
893 if (pdu->version != COAP_DEFAULT_VERSION) {
894 printf("coap_read: unknown protocol version\n");
895 goto error_early;
896 }
897
898 node = coap_new_node();
899 if (!node)
900 goto error_early;
901
902 node->pdu = coap_pdu_init(0, 0, 0, bytes_read);
903
904 if (!node->pdu)
905 goto error;
906
907 coap_ticks(&node->t);
908 memcpy(&node->local_if, ctx->endpoint, sizeof(coap_endpoint_t));
909 memcpy(&node->remote, src, sizeof(coap_address_t));
910
911 if (!coap_pdu_parse((unsigned char *)buf, bytes_read, node->pdu)) {
912 printf("discard malformed PDU");
913 goto error;
914 }
915
916 coap_transaction_id(&node->remote, node->pdu, &node->id);
917
918 if (coap_get_log_level() >= LOG_DEBUG) {
919 unsigned char addr[INET6_ADDRSTRLEN+8];
920
921 if (coap_print_addr(src, addr, INET6_ADDRSTRLEN+8))
922 printf("** received %d bytes from %s:\n",
923 (int)bytes_read, addr);
924 coap_show_pdu(node->pdu);
925 }
926
927 coap_dispatch(ctx, node);
928 return 0;
929
930 error:
931 coap_delete_node(node);
932 error_early:
933 return -1;
934 }
935
read_from_peer(struct dtls_context_t * ctx,session_t * session,uint8 * read_data,size_t read_len)936 static int read_from_peer(struct dtls_context_t *ctx,
937 session_t *session,
938 uint8 *read_data, size_t read_len)
939 {
940 struct client_data *user_data =
941 (struct client_data *)dtls_get_app_data(ctx);
942 coap_address_t addr;
943
944 printf("%s: read [%u] from peer %zu bytes\n",
945 data[user_data->index].description, user_data->index, read_len);
946
947 memcpy(&(addr.addr), &(session->addr), session->size);
948 addr.size = session->size;
949
950 /* Process the received CoAP packet */
951 if (dispatch_data(read_data, read_len, user_data->coap_ctx,
952 &addr) < 0) {
953 printf("Cannot parse received CoAP packet.\n");
954 quit = true;
955 user_data->fail = true;
956 return 0;
957 }
958
959 if (debug)
960 print_data(read_data, read_len);
961
962 if (!data[user_data->index + 1].buf) {
963 /* last entry, just bail out */
964 quit = true;
965 return 0;
966 }
967
968 if (user_data->index == renegotiate) {
969 printf("Starting to renegotiate keys\n");
970 dtls_renegotiate(ctx, session);
971 return 1;
972 }
973
974 try_send(ctx);
975
976 return 0;
977 }
978
sleep_ms(int ms)979 static inline void sleep_ms(int ms)
980 {
981 struct timeval tv;
982
983 tv.tv_sec = 0;
984 tv.tv_usec = ms * 1000;
985
986 select(1, NULL, NULL, NULL, &tv);
987 }
988
send_to_peer(struct dtls_context_t * ctx,session_t * session,uint8 * data,size_t len)989 static int send_to_peer(struct dtls_context_t *ctx,
990 session_t *session,
991 uint8 *data, size_t len)
992 {
993 struct client_data *user_data =
994 (struct client_data *)dtls_get_app_data(ctx);
995
996 /* The Qemu uart driver can loose chars if sent too fast.
997 * So before sending more data, sleep a while.
998 */
999 sleep_ms(200);
1000
1001 printf("Sending to peer encrypted data %p len %zu\n", data, len);
1002
1003 return sendto(user_data->fd, data, len, 0,
1004 &session->addr.sa, session->size);
1005 }
1006
dtls_handle_read(struct dtls_context_t * ctx)1007 static int dtls_handle_read(struct dtls_context_t *ctx)
1008 {
1009 struct client_data *user_data;
1010
1011 user_data = (struct client_data *)dtls_get_app_data(ctx);
1012
1013 if (!user_data || !user_data->fd)
1014 return -1;
1015
1016 memset(&session, 0, sizeof(session_t));
1017 session.size = sizeof(session.addr);
1018 user_data->len = recvfrom(user_data->fd, user_data->buf, MAX_READ_BUF,
1019 0, &session.addr.sa, &session.size);
1020 if (user_data->len < 0) {
1021 perror("recvfrom");
1022 return -1;
1023 } else {
1024 dtls_dsrv_log_addr(DTLS_LOG_DEBUG, "peer", &session);
1025 dtls_debug_dump("bytes from peer", user_data->buf,
1026 user_data->len);
1027 }
1028
1029 return dtls_handle_message(ctx, &session, user_data->buf,
1030 user_data->len);
1031 }
1032
handle_event(struct dtls_context_t * ctx,session_t * session,dtls_alert_level_t level,unsigned short code)1033 static int handle_event(struct dtls_context_t *ctx, session_t *session,
1034 dtls_alert_level_t level, unsigned short code)
1035 {
1036 struct client_data *user_data;
1037
1038 user_data = (struct client_data *)dtls_get_app_data(ctx);
1039
1040 if (debug)
1041 printf("event: level %d code %d\n", level, code);
1042
1043 if (level > 0) {
1044 /* alert code, quit */
1045 quit = true;
1046 user_data->fail = true;
1047 } else if (level == 0) {
1048 /* internal event */
1049 if (code == DTLS_EVENT_CONNECTED) {
1050 /* We can send data now */
1051 try_send(ctx);
1052 }
1053 }
1054
1055 return 0;
1056 }
1057
1058 static dtls_handler_t cb = {
1059 .write = send_to_peer,
1060 .read = read_from_peer,
1061 .event = handle_event,
1062 #ifdef DTLS_PSK
1063 .get_psk_info = get_psk_info,
1064 #endif /* DTLS_PSK */
1065 #ifdef DTLS_ECC
1066 .get_ecdsa_key = get_ecdsa_key,
1067 .verify_ecdsa_key = verify_ecdsa_key
1068 #endif /* DTLS_ECC */
1069 };
1070
read_data_from_net(struct client_data * user_data)1071 static int read_data_from_net(struct client_data *user_data)
1072 {
1073 coap_packet_t *packet;
1074 coap_address_t addr;
1075
1076 if (!user_data || !user_data->fd)
1077 return -1;
1078
1079 return coap_read(user_data->coap_ctx);
1080 }
1081
signal_handler(int signum)1082 void signal_handler(int signum)
1083 {
1084 switch (signum) {
1085 case SIGINT:
1086 case SIGTERM:
1087 quit = true;
1088 break;
1089 }
1090 }
1091
check_token(coap_pdu_t * received)1092 static inline int check_token(coap_pdu_t *received)
1093 {
1094 return received->hdr->token_length == the_token.length &&
1095 memcmp(received->hdr->token, the_token.s,
1096 the_token.length) == 0;
1097 }
1098
is_our_own(coap_context_t * coap_ctx,const coap_address_t * remote,coap_pdu_t * sent,coap_pdu_t * received)1099 static bool is_our_own(coap_context_t *coap_ctx,
1100 const coap_address_t *remote,
1101 coap_pdu_t *sent,
1102 coap_pdu_t *received)
1103 {
1104 if (data[test_context->index].add_token && !check_token(received)) {
1105 if (!sent &&
1106 (received->hdr->type == COAP_MESSAGE_CON ||
1107 received->hdr->type == COAP_MESSAGE_NON))
1108 coap_send_rst(coap_ctx, coap_ctx->endpoint, remote,
1109 received);
1110 return false;
1111 }
1112
1113 return true;
1114 }
1115
add_options(coap_pdu_t * pdu)1116 static void add_options(coap_pdu_t *pdu)
1117 {
1118 coap_list_t *option;
1119
1120 for (option = optlist; option; option = option->next ) {
1121 switch (COAP_OPTION_KEY(*(coap_option *)option->data)) {
1122 case COAP_OPTION_URI_HOST :
1123 case COAP_OPTION_URI_PORT :
1124 case COAP_OPTION_URI_PATH :
1125 case COAP_OPTION_CONTENT_FORMAT :
1126 case COAP_OPTION_URI_QUERY :
1127 coap_add_option(pdu,
1128 COAP_OPTION_KEY(*(coap_option *)option->data),
1129 COAP_OPTION_LENGTH(*(coap_option *)option->data),
1130 COAP_OPTION_DATA(*(coap_option *)option->data));
1131 break;
1132 default:
1133 break;
1134 }
1135 }
1136 }
1137
order_opts(void * a,void * b)1138 static int order_opts(void *a, void *b)
1139 {
1140 coap_option *o1, *o2;
1141
1142 if (!a || !b)
1143 return a < b ? -1 : 1;
1144
1145 o1 = (coap_option *)(((coap_list_t *)a)->data);
1146 o2 = (coap_option *)(((coap_list_t *)b)->data);
1147
1148 return (COAP_OPTION_KEY(*o1) < COAP_OPTION_KEY(*o2)) ? -1
1149 : (COAP_OPTION_KEY(*o1) != COAP_OPTION_KEY(*o2));
1150 }
1151
coap_new_request(coap_context_t * ctx,method_t m,coap_list_t ** options,const unsigned char * req,size_t length,int msgtype)1152 static coap_pdu_t *coap_new_request(coap_context_t *ctx,
1153 method_t m,
1154 coap_list_t **options,
1155 const unsigned char *req,
1156 size_t length,
1157 int msgtype)
1158 {
1159 coap_pdu_t *pdu;
1160 coap_list_t *opt;
1161
1162 if (!(pdu = coap_new_pdu()))
1163 return NULL;
1164
1165 pdu->hdr->type = msgtype;
1166 pdu->hdr->id = coap_new_message_id(ctx);
1167 pdu->hdr->code = m;
1168
1169 if (data[test_context->index].add_token) {
1170 pdu->hdr->token_length = the_token.length;
1171 if (!coap_add_token(pdu, the_token.length, the_token.s)) {
1172 printf("cannot add token to request\n");
1173 test_context->fail = true;
1174 quit = true;
1175 return NULL;
1176 }
1177 }
1178
1179 coap_show_pdu(pdu);
1180
1181 if (options) {
1182 LL_SORT((*options), order_opts);
1183
1184 LL_FOREACH((*options), opt) {
1185 coap_option *o = (coap_option *)(opt->data);
1186 coap_add_option(pdu,
1187 COAP_OPTION_KEY(*o),
1188 COAP_OPTION_LENGTH(*o),
1189 COAP_OPTION_DATA(*o));
1190 }
1191 }
1192
1193 if (length) {
1194 if ((flags & FLAGS_BLOCK) == 0)
1195 coap_add_data(pdu, length, req);
1196 else
1197 coap_add_block(pdu, length, req,
1198 block.num, block.szx);
1199 }
1200
1201 return pdu;
1202 }
1203
read_blocks(coap_context_t * coap_ctx,const coap_endpoint_t * endpoint,const coap_address_t * remote,coap_opt_iterator_t * opt_iter,coap_pdu_t * received,coap_opt_t * block_opt)1204 static coap_pdu_t *read_blocks(coap_context_t *coap_ctx,
1205 const coap_endpoint_t *endpoint,
1206 const coap_address_t *remote,
1207 coap_opt_iterator_t *opt_iter,
1208 coap_pdu_t *received,
1209 coap_opt_t *block_opt)
1210 {
1211 unsigned short blktype = opt_iter->type;
1212 size_t len;
1213 unsigned char *databuf;
1214 coap_pdu_t *pdu = NULL;
1215 unsigned char buf[4];
1216 coap_tid_t tid;
1217
1218 if (coap_get_data(received, &len, &databuf))
1219 printf("Received: databuf %p len %zu\n", databuf, len);
1220
1221 if (COAP_OPT_BLOCK_MORE(block_opt)) {
1222 printf("found the M bit, block size is %u, block nr. %u\n",
1223 COAP_OPT_BLOCK_SZX(block_opt),
1224 coap_opt_block_num(block_opt));
1225
1226 pdu = coap_new_request(coap_ctx, method, NULL, NULL, 0,
1227 COAP_MESSAGE_CON);
1228 if (pdu) {
1229 add_options(pdu);
1230
1231 printf("query block %d\n",
1232 (coap_opt_block_num(block_opt) + 1));
1233
1234 coap_add_option(pdu, blktype,
1235 coap_encode_var_bytes(buf,
1236 ((coap_opt_block_num(block_opt) + 1) << 4) |
1237 COAP_OPT_BLOCK_SZX(block_opt)), buf);
1238
1239 if (received->hdr->type == COAP_MESSAGE_CON)
1240 tid = coap_send_confirmed(coap_ctx,
1241 endpoint,
1242 remote,
1243 pdu);
1244 else
1245 tid = coap_send(coap_ctx,
1246 endpoint,
1247 remote,
1248 pdu);
1249
1250 if (tid == COAP_INVALID_TID) {
1251 printf("error sending new request\n");
1252 coap_delete_pdu(pdu);
1253 } else {
1254 set_coap_timeout(&max_wait, wait_seconds);
1255 if (received->hdr->type != COAP_MESSAGE_CON) {
1256 coap_delete_pdu(pdu);
1257 return NULL;
1258 }
1259 }
1260 }
1261 }
1262
1263 return pdu;
1264 }
1265
get_block(coap_pdu_t * pdu,coap_opt_iterator_t * opt_iter)1266 static coap_opt_t *get_block(coap_pdu_t *pdu, coap_opt_iterator_t *opt_iter)
1267 {
1268 coap_opt_filter_t f;
1269
1270 memset(f, 0, sizeof(coap_opt_filter_t));
1271 coap_option_setb(f, COAP_OPTION_BLOCK1);
1272 coap_option_setb(f, COAP_OPTION_BLOCK2);
1273
1274 coap_option_iterator_init(pdu, opt_iter, f);
1275 return coap_option_next(opt_iter);
1276 }
1277
check_mid(const unsigned char * databuf,int len,int test_case)1278 static bool check_mid(const unsigned char *databuf, int len,
1279 int test_case)
1280 {
1281 unsigned char buf[2048];
1282
1283 snprintf(buf, sizeof(buf), "%sMID: %d", data[test_case].data,
1284 data[test_case].expected_mid);
1285 if (!memcmp(databuf, buf, strlen(buf)))
1286 return true;
1287 else {
1288 printf("FAIL:\n received %d bytes\n>>>>\n%.*s\n<<<<\n", len,
1289 len, databuf);
1290 printf(" expected %zu bytes\n>>>>\n%s\n<<<<\n", strlen(buf), buf);
1291 return false;
1292 }
1293 }
1294
receive_data(coap_pdu_t * received)1295 static void receive_data(coap_pdu_t *received)
1296 {
1297 size_t len;
1298 unsigned char *databuf;
1299
1300 if (coap_get_data(received, &len, &databuf)) {
1301 if (!test_context)
1302 return;
1303
1304 if (data[test_context->index].check_mid &&
1305 !check_mid(databuf, len, test_context->index)) {
1306 printf("Test %d failed\n",
1307 test_context->index);
1308 test_context->fail = true;
1309 quit = true;
1310 } else {
1311 if (!data[test_context->index + 1].buf) {
1312 /* last entry, just bail out */
1313 quit = true;
1314 } else
1315 test_context->index++;
1316 }
1317 } else {
1318 if (!test_context)
1319 return;
1320
1321 if (data[test_context->index].check_mid) {
1322 printf("Packet error\n");
1323 quit = true;
1324 test_context->fail = true;
1325 } else {
1326 if (!data[test_context->index + 1].buf) {
1327 /* last entry, just bail out */
1328 quit = true;
1329 } else
1330 test_context->index++;
1331 }
1332 }
1333 }
1334
coap_message_handler(struct coap_context_t * coap_ctx,const coap_endpoint_t * endpoint,const coap_address_t * remote,coap_pdu_t * sent,coap_pdu_t * received,const coap_tid_t id)1335 static void coap_message_handler(struct coap_context_t *coap_ctx,
1336 const coap_endpoint_t *endpoint,
1337 const coap_address_t *remote,
1338 coap_pdu_t *sent,
1339 coap_pdu_t *received,
1340 const coap_tid_t id)
1341 {
1342 coap_pdu_t *pdu = NULL;
1343 coap_opt_t *block_opt;
1344 coap_opt_iterator_t opt_iter;
1345 size_t len;
1346 unsigned char *databuf;
1347
1348 if (coap_get_log_level() >= LOG_DEBUG) {
1349 printf("process incoming %d.%02d response:\n",
1350 (received->hdr->code >> 5), received->hdr->code & 0x1F);
1351 coap_show_pdu(received);
1352 }
1353
1354 if (!is_our_own(coap_ctx, remote, sent, received))
1355 return;
1356
1357 switch (received->hdr->type) {
1358 case COAP_MESSAGE_CON:
1359 coap_send_ack(coap_ctx, endpoint, remote, received);
1360 break;
1361 case COAP_MESSAGE_RST:
1362 printf("CoAP RST\n");
1363 return;
1364 default:
1365 break;
1366 }
1367
1368 if (COAP_RESPONSE_CLASS(received->hdr->code) == 2) {
1369
1370 if (sent && coap_check_option(received,
1371 COAP_OPTION_SUBSCRIPTION,
1372 &opt_iter)) {
1373 printf("observation timeout set to %d\n", obs_seconds);
1374 set_coap_timeout(&obs_wait, obs_seconds);
1375 }
1376
1377 block_opt = get_block(received, &opt_iter);
1378 if (block_opt)
1379 pdu = read_blocks(coap_ctx,
1380 endpoint,
1381 remote,
1382 &opt_iter,
1383 received,
1384 block_opt);
1385 else {
1386 block_opt = coap_check_option(received,
1387 COAP_OPTION_BLOCK1,
1388 &opt_iter);
1389 if (block_opt) { /* handle Block1 */
1390 unsigned char buf[4];
1391 coap_tid_t tid;
1392
1393 block.szx = COAP_OPT_BLOCK_SZX(block_opt);
1394 block.num = coap_opt_block_num(block_opt);
1395
1396 debug("found Block1, block size is %u, "
1397 "block nr. %u\n",
1398 block.szx, block.num);
1399
1400 if (payload.length <= (block.num+1) *
1401 (1 << (block.szx + 4))) {
1402 debug("upload ready\n");
1403 ready = 1;
1404 return;
1405 }
1406
1407 /* create pdu with request for next block */
1408 pdu = coap_new_request(coap_ctx, method, NULL,
1409 NULL, 0, COAP_MESSAGE_CON);
1410 if (pdu) {
1411 /* add URI components from optlist */
1412 add_options(pdu);
1413
1414 block.num++;
1415 block.m = ((block.num+1) *
1416 (1 << (block.szx + 4)) <
1417 payload.length);
1418
1419 debug("send block %d\n", block.num);
1420 coap_add_option(pdu,
1421 COAP_OPTION_BLOCK1,
1422 coap_encode_var_bytes(buf,
1423 (block.num << 4) |
1424 (block.m << 3) |
1425 block.szx), buf);
1426
1427 coap_add_block(pdu,
1428 payload.length,
1429 payload.s,
1430 block.num,
1431 block.szx);
1432 coap_show_pdu(pdu);
1433 if (pdu->hdr->type == COAP_MESSAGE_CON)
1434 tid = coap_send_confirmed(coap_ctx,
1435 endpoint, remote, pdu);
1436 else
1437 tid = coap_send(coap_ctx,
1438 endpoint, remote, pdu);
1439
1440 if (tid == COAP_INVALID_TID) {
1441 debug("message_handler: error "
1442 "sending new request");
1443 coap_delete_pdu(pdu);
1444 } else {
1445 set_coap_timeout(&max_wait, wait_seconds);
1446 if (pdu->hdr->type != COAP_MESSAGE_CON)
1447 coap_delete_pdu(pdu);
1448 }
1449
1450 return;
1451 }
1452 } else {
1453 /* There is no block option set, just read the data and we are done. */
1454 receive_data(received);
1455 }
1456 }
1457 } else {
1458 if (COAP_RESPONSE_CLASS(received->hdr->code) >= 4) {
1459 fprintf(stderr, "ERROR %d.%02d",
1460 (received->hdr->code >> 5),
1461 received->hdr->code & 0x1F);
1462 if (coap_get_data(received, &len, &databuf)) {
1463 fprintf(stderr, " ");
1464 while(len--)
1465 fprintf(stderr, "%c", *databuf++);
1466 }
1467 fprintf(stderr, "\n");
1468
1469 if (test_context)
1470 test_context->fail = true;
1471 quit = true;
1472 }
1473 }
1474
1475 if (pdu && coap_send(coap_ctx, endpoint,
1476 remote, pdu) == COAP_INVALID_TID)
1477 printf("error sending response\n");
1478
1479 coap_delete_pdu(pdu);
1480
1481 ready = coap_check_option(received, COAP_OPTION_SUBSCRIPTION,
1482 &opt_iter) == NULL;
1483 }
1484
set_blocksize(void)1485 static void set_blocksize(void)
1486 {
1487 static unsigned char buf[4];
1488 unsigned short opt;
1489 unsigned int opt_length;
1490
1491 if (method != COAP_REQUEST_DELETE) {
1492 opt = method == COAP_REQUEST_GET ? COAP_OPTION_BLOCK2 :
1493 COAP_OPTION_BLOCK1;
1494
1495 block.m = (opt == COAP_OPTION_BLOCK1) &&
1496 ((1u << (block.szx + 4)) < payload.length);
1497
1498 opt_length = coap_encode_var_bytes(buf,
1499 (block.num << 4 | block.m << 3 | block.szx));
1500
1501 coap_insert(&optlist, new_option_node(opt, opt_length, buf));
1502 }
1503 }
1504
my_coap_network_send(struct coap_context_t * ctx,const coap_endpoint_t * endpoint,const coap_address_t * dst,unsigned char * data,size_t datalen)1505 static ssize_t my_coap_network_send(struct coap_context_t *ctx,
1506 const coap_endpoint_t *endpoint,
1507 const coap_address_t *dst,
1508 unsigned char *data,
1509 size_t datalen)
1510 {
1511 ssize_t bytes_written = dtls_write(dtls_context, &session,
1512 data, datalen);
1513 if (bytes_written <= 0) {
1514 coap_log(LOG_CRIT, "coap_send: sendto\n");
1515 }
1516
1517 return bytes_written;
1518 }
1519
my_coap_network_read(coap_endpoint_t * endpoint,coap_packet_t ** packet)1520 static ssize_t my_coap_network_read(coap_endpoint_t *endpoint,
1521 coap_packet_t **packet)
1522 {
1523 printf("*** We should not get here if we are using DTLS ***\n");
1524
1525 return -EINVAL;
1526 }
1527
get_coap_context(struct sockaddr * ipaddr,int ipaddrlen)1528 static coap_context_t *get_coap_context(struct sockaddr *ipaddr, int ipaddrlen)
1529 {
1530 coap_address_t addr;
1531 coap_context_t *ctx;
1532
1533 coap_address_init(&addr);
1534 addr.size = ipaddrlen;
1535 memcpy(&addr.addr, ipaddr, ipaddrlen);
1536
1537 ctx = coap_new_context(&addr);
1538 if (!ctx)
1539 return NULL;
1540
1541 if (!no_dtls) {
1542 ctx->network_send = my_coap_network_send;
1543 ctx->network_read = my_coap_network_read;
1544 }
1545
1546 return ctx;
1547 }
1548
set_token(char * arg)1549 static inline void set_token(char *arg)
1550 {
1551 strncpy((char *)the_token.s, arg, min(sizeof(_token_data),
1552 strlen(arg)));
1553 the_token.length = strlen(arg);
1554 }
1555
1556
1557 extern int optind, opterr, optopt;
1558 extern char *optarg;
1559
1560 /* The application returns:
1561 * < 0 : connection or similar error
1562 * 0 : no errors, all tests passed
1563 * > 0 : could not send all the data to server
1564 */
main(int argc,char ** argv)1565 int main(int argc, char**argv)
1566 {
1567 int c, ret, fd, timeout = 0;
1568 struct sockaddr_in6 addr6_send = { 0 }, addr6_recv = { 0 };
1569 struct sockaddr_in addr4_send = { 0 }, addr4_recv = { 0 };
1570 struct sockaddr *addr_send, *addr_recv;
1571 int addr_len;
1572 const struct in6_addr any = IN6ADDR_ANY_INIT;
1573 const char *interface = NULL;
1574 fd_set rfds;
1575 struct timeval tv = {};
1576 int ifindex = -1, on, port;
1577 void *address = NULL;
1578 session_t dst;
1579 struct client_data user_data = {};
1580
1581 coap_tid_t tid = COAP_INVALID_TID;
1582 coap_context_t *coap_ctx;
1583 coap_tick_t now;
1584 coap_queue_t *nextpdu;
1585 coap_pdu_t *pdu;
1586
1587 #ifdef DTLS_PSK
1588 psk_id_length = strlen(PSK_DEFAULT_IDENTITY);
1589 psk_key_length = strlen(PSK_DEFAULT_KEY);
1590 memcpy(psk_id, PSK_DEFAULT_IDENTITY, psk_id_length);
1591 memcpy(psk_key, PSK_DEFAULT_KEY, psk_key_length);
1592 #endif /* DTLS_PSK */
1593
1594 opterr = 0;
1595
1596 while ((c = getopt(argc, argv, "i:Drb:n")) != -1) {
1597 switch (c) {
1598 case 'i':
1599 interface = optarg;
1600 break;
1601 case 'n':
1602 no_dtls = true;
1603 break;
1604 case 'r':
1605 /* Do a renegotiate once during the test run. */
1606 srandom(time(0));
1607 renegotiate = random() %
1608 (sizeof(data) / sizeof(struct data) - 1);
1609 printf("Renegotating after %d messages.\n", renegotiate);
1610 break;
1611 case 'D':
1612 debug = true;
1613 break;
1614 case 'h':
1615 goto usage;
1616 }
1617 }
1618
1619 if (optind < argc)
1620 target = argv[optind];
1621
1622 if (!target) {
1623 usage:
1624 printf("usage: %s [-i tun0] [-D] [-r] [-n]"
1625 "<IPv{6|4} address of the dtls-server>\n",
1626 argv[0]);
1627 printf("\t-i Use this network interface.\n");
1628 printf("\t-n Do not use DTLS\n");
1629 printf("\t-r Renegoating keys once during the test run.\n");
1630 printf("\t-D Activate debugging.\n");
1631 exit(-EINVAL);
1632 }
1633
1634 if (inet_pton(AF_INET6, target, &addr6_send.sin6_addr) != 1) {
1635 if (inet_pton(AF_INET, target, &addr4_send.sin_addr) != 1) {
1636 printf("Invalid address family\n");
1637 exit(-EINVAL);
1638 } else {
1639 addr_send = (struct sockaddr *)&addr4_send;
1640 addr_recv = (struct sockaddr *)&addr4_recv;
1641 if (no_dtls)
1642 addr4_send.sin_port = port = htons(SERVER_PORT);
1643 else
1644 addr4_send.sin_port = port = htons(SERVER_SECURE_PORT);
1645 addr4_recv.sin_family = AF_INET;
1646 addr4_recv.sin_addr.s_addr = INADDR_ANY;
1647 addr4_recv.sin_port = htons(CLIENT_PORT);
1648 family = AF_INET;
1649 addr_len = sizeof(addr4_send);
1650 address = &addr4_recv.sin_addr;
1651 }
1652 } else {
1653 addr_send = (struct sockaddr *)&addr6_send;
1654 addr_recv = (struct sockaddr *)&addr6_recv;
1655 if (no_dtls)
1656 addr6_send.sin6_port = port = htons(SERVER_PORT);
1657 else
1658 addr6_send.sin6_port = port = htons(SERVER_SECURE_PORT);
1659 addr6_recv.sin6_family = AF_INET6;
1660 addr6_recv.sin6_addr = any;
1661 addr6_recv.sin6_port = htons(CLIENT_PORT);
1662 family = AF_INET6;
1663 addr_len = sizeof(addr6_send);
1664 address = &addr6_recv.sin6_addr;
1665 }
1666
1667 addr_send->sa_family = family;
1668 addr_recv->sa_family = family;
1669
1670 fd = socket(family, SOCK_DGRAM, IPPROTO_UDP);
1671 if (fd < 0) {
1672 perror("socket");
1673 exit(-errno);
1674 }
1675
1676 if (interface) {
1677 struct ifreq ifr;
1678 char addr_buf[INET6_ADDRSTRLEN];
1679
1680 memset(&ifr, 0, sizeof(ifr));
1681 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", interface);
1682
1683 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
1684 (void *)&ifr, sizeof(ifr)) < 0) {
1685 perror("SO_BINDTODEVICE");
1686 exit(-errno);
1687 }
1688
1689 ifindex = get_ifindex(interface);
1690 if (ifindex < 0) {
1691 printf("Invalid interface %s\n", interface);
1692 exit(-EINVAL);
1693 }
1694
1695 ret = get_address(interface, family, address);
1696 if (ret < 0) {
1697 printf("Cannot find suitable source address "
1698 "for interface %s [%d/%s]\n",
1699 interface, ret, strerror(-ret));
1700 }
1701
1702 printf("Binding to %s\n", inet_ntop(family, address,
1703 addr_buf, sizeof(addr_buf)));
1704 }
1705
1706 coap_ctx = get_coap_context(addr_recv, addr_len);
1707 if (!coap_ctx) {
1708 printf("\nCannot get CoAP context\n");
1709 exit(-1);
1710 }
1711
1712 /* We do not use libcoap fd but our own so we can bind to this
1713 * specific interface. Done like this so that we do not need
1714 * to modify libcoap.
1715 */
1716 close(coap_ctx->endpoint->handle.fd);
1717
1718 ret = bind(fd, addr_recv, addr_len);
1719 if (ret < 0) {
1720 perror("bind");
1721 exit(-errno);
1722 }
1723
1724 on = 1;
1725 #ifdef IPV6_RECVPKTINFO
1726 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
1727 sizeof(on) ) < 0) {
1728 #else /* IPV6_RECVPKTINFO */
1729 if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on,
1730 sizeof(on) ) < 0) {
1731 #endif /* IPV6_RECVPKTINFO */
1732 printf("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
1733 }
1734 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
1735 printf("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
1736 }
1737
1738 signal(SIGINT, signal_handler);
1739 signal(SIGTERM, signal_handler);
1740
1741 user_data.fd = fd;
1742 user_data.index = 0;
1743 user_data.ifindex = ifindex;
1744
1745 user_data.coap_ctx = coap_ctx;
1746 coap_ctx->endpoint->handle.fd = fd;
1747
1748 coap_address_init(&user_data.coap_dst);
1749 memcpy(&user_data.coap_dst.addr, addr_send, addr_len);
1750 user_data.coap_dst.size = addr_len;
1751
1752 if (debug)
1753 coap_set_log_level(LOG_DEBUG);
1754
1755 coap_register_option(coap_ctx, COAP_OPTION_BLOCK2);
1756 coap_register_response_handler(coap_ctx, coap_message_handler);
1757 set_coap_timeout(&max_wait, wait_seconds);
1758 printf("CoAP timeout is set to %d seconds\n", wait_seconds);
1759
1760 coap_insert(&optlist,
1761 new_option_node(COAP_OPTION_URI_HOST,
1762 strlen(target),
1763 (char *)target));
1764
1765 if (port) {
1766 unsigned char p[2];
1767 p[0] = ntohs(port) >> 8;
1768 p[1] = ntohs(port) & 0xff;
1769 coap_insert(&optlist,
1770 new_option_node(COAP_OPTION_URI_PORT,
1771 2, p));
1772 }
1773
1774 printf("Connecting to port %d\n", ntohs(port));
1775
1776 if (!no_dtls) {
1777 dtls_init();
1778
1779 memset(&dst, 0, sizeof(dst));
1780 memcpy(&dst.addr.sa, addr_send, addr_len);
1781 dst.size = addr_len;
1782
1783 dtls_context = dtls_new_context(&user_data);
1784 if (!dtls_context) {
1785 dtls_emerg("cannot create context\n");
1786 exit(-EINVAL);
1787 }
1788
1789 dtls_set_handler(dtls_context, &cb);
1790
1791 if (debug)
1792 dtls_set_log_level(DTLS_LOG_DEBUG);
1793
1794 dtls_connect(dtls_context, &dst);
1795 }
1796
1797 set_token("07162534");
1798
1799 do {
1800 FD_ZERO(&rfds);
1801 FD_SET(fd, &rfds);
1802 tv.tv_sec = MAX_TIMEOUT;
1803 tv.tv_usec = 0;
1804
1805 if (no_dtls)
1806 send_packets(&user_data);
1807
1808 if (quit || user_data.fail)
1809 break;
1810
1811 nextpdu = coap_peek_next(coap_ctx);
1812
1813 coap_ticks(&now);
1814 while (nextpdu && nextpdu->t <=
1815 (now - coap_ctx->sendqueue_basetime)) {
1816 coap_retransmit(coap_ctx, coap_pop_next(coap_ctx));
1817 nextpdu = coap_peek_next(coap_ctx);
1818 }
1819
1820 if (nextpdu && nextpdu->t < min(obs_wait ? obs_wait : max_wait,
1821 max_wait) - now) {
1822 tv.tv_usec = ((nextpdu->t) % COAP_TICKS_PER_SECOND) *
1823 1000000 / COAP_TICKS_PER_SECOND;
1824 tv.tv_sec = (nextpdu->t) / COAP_TICKS_PER_SECOND;
1825 } else {
1826 if (obs_wait && obs_wait < max_wait) {
1827 tv.tv_usec = ((obs_wait - now) %
1828 COAP_TICKS_PER_SECOND) * 1000000 /
1829 COAP_TICKS_PER_SECOND;
1830 tv.tv_sec = (obs_wait - now) /
1831 COAP_TICKS_PER_SECOND;
1832 } else {
1833 tv.tv_usec = ((max_wait - now) %
1834 COAP_TICKS_PER_SECOND) * 1000000 /
1835 COAP_TICKS_PER_SECOND;
1836 tv.tv_sec = (max_wait - now) /
1837 COAP_TICKS_PER_SECOND;
1838 }
1839 }
1840
1841 ret = select(fd + 1, &rfds, NULL, NULL, &tv);
1842 if (ret < 0) {
1843 perror("select");
1844 break;
1845 } else if (ret == 0) {
1846 if (quit)
1847 break;
1848
1849 if (user_data.index >
1850 (sizeof(data) / sizeof(struct data)) - 1)
1851 break;
1852
1853 if (!data[user_data.index].expecting_reply) {
1854 printf("Did not expect a reply, send next entry.\n");
1855 user_data.index++;
1856 if (!data[user_data.index].buf) {
1857 user_data.fail = true;
1858 break;
1859 }
1860 continue;
1861 }
1862
1863 fprintf(stderr, "Timeout [%d] while waiting len %d\n",
1864 user_data.index, data[user_data.index].len);
1865 ret = user_data.index + 1;
1866 user_data.fail = true;
1867 break;
1868 } else if (!FD_ISSET(fd, &rfds)) {
1869 fprintf(stderr, "Invalid fd in read, quitting.\n");
1870 ret = user_data.index + 1;
1871 user_data.fail = true;
1872 break;
1873 }
1874
1875 if (!no_dtls) {
1876 if (dtls_handle_read(dtls_context) < 0) {
1877 fprintf(stderr, "Peer connection failed.\n");
1878 ret = user_data.index + 1;
1879 user_data.fail = true;
1880 break;
1881 }
1882 } else {
1883 user_data.fd = fd;
1884 if (read_data_from_net(&user_data) < 0) {
1885 fprintf(stderr, "Packet read error.\n");
1886 ret = user_data.index + 1;
1887 user_data.fail = true;
1888 break;
1889 }
1890 }
1891
1892 } while(!quit);
1893
1894 printf("\n");
1895
1896 if (!no_dtls)
1897 dtls_close(dtls_context, &dst);
1898
1899 dtls_free_context(dtls_context);
1900
1901 close(fd);
1902
1903 if (!user_data.fail) {
1904 if (debug)
1905 printf("Weird: No failures but error code (%d) "
1906 "indicates error\n", ret);
1907 ret = 0;
1908 }
1909
1910 exit(ret);
1911 }
1912