| /* |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the Institute nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * |
| * This file is part of the Contiki operating system. |
| * |
| */ |
| |
| #include "contiki.h" |
| #include "contiki-lib.h" |
| #include "contiki-net.h" |
| |
| #if UIP_CONF_IPV6_RPL |
| #include "contiki/rpl/rpl.h" |
| #endif /* UIP_CONF_IPV6_RPL */ |
| |
| #include <string.h> |
| |
| #include "tinydtls.h" |
| |
| #ifndef DEBUG |
| #define DEBUG DEBUG_PRINT |
| #endif |
| #include "contiki/ip/uip-debug.h" |
| |
| #include "debug.h" |
| #include "dtls.h" |
| |
| #ifdef ENABLE_POWERTRACE |
| #include "powertrace.h" |
| #endif |
| |
| #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) |
| #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) |
| |
| #define MAX_PAYLOAD_LEN 120 |
| |
| static struct uip_udp_conn *server_conn; |
| |
| static dtls_context_t *dtls_context; |
| |
| static const unsigned char ecdsa_priv_key[] = { |
| 0xD9, 0xE2, 0x70, 0x7A, 0x72, 0xDA, 0x6A, 0x05, |
| 0x04, 0x99, 0x5C, 0x86, 0xED, 0xDB, 0xE3, 0xEF, |
| 0xC7, 0xF1, 0xCD, 0x74, 0x83, 0x8F, 0x75, 0x70, |
| 0xC8, 0x07, 0x2D, 0x0A, 0x76, 0x26, 0x1B, 0xD4}; |
| |
| static const unsigned char ecdsa_pub_key_x[] = { |
| 0xD0, 0x55, 0xEE, 0x14, 0x08, 0x4D, 0x6E, 0x06, |
| 0x15, 0x59, 0x9D, 0xB5, 0x83, 0x91, 0x3E, 0x4A, |
| 0x3E, 0x45, 0x26, 0xA2, 0x70, 0x4D, 0x61, 0xF2, |
| 0x7A, 0x4C, 0xCF, 0xBA, 0x97, 0x58, 0xEF, 0x9A}; |
| |
| static const unsigned char ecdsa_pub_key_y[] = { |
| 0xB4, 0x18, 0xB6, 0x4A, 0xFE, 0x80, 0x30, 0xDA, |
| 0x1D, 0xDC, 0xF4, 0xF4, 0x2E, 0x2F, 0x26, 0x31, |
| 0xD0, 0x43, 0xB1, 0xFB, 0x03, 0xE2, 0x2F, 0x4D, |
| 0x17, 0xDE, 0x43, 0xF9, 0xF9, 0xAD, 0xEE, 0x70}; |
| |
| static int |
| read_from_peer(struct dtls_context_t *ctx, |
| session_t *session, uint8 *data, size_t len) { |
| size_t i; |
| for (i = 0; i < len; i++) |
| PRINTF("%c", data[i]); |
| |
| /* echo incoming application data */ |
| dtls_write(ctx, session, data, len); |
| return 0; |
| } |
| |
| static int |
| send_to_peer(struct dtls_context_t *ctx, |
| session_t *session, uint8 *data, size_t len) { |
| |
| struct uip_udp_conn *conn = (struct uip_udp_conn *)dtls_get_app_data(ctx); |
| |
| uip_ipaddr_copy(&conn->ripaddr, &session->addr); |
| conn->rport = session->port; |
| |
| PRINTF("send to "); |
| PRINT6ADDR(&conn->ripaddr); |
| PRINTF(":%u\n", uip_ntohs(conn->rport)); |
| |
| uip_udp_packet_send(conn, data, len); |
| |
| /* Restore server connection to allow data from any node */ |
| memset(&conn->ripaddr, 0, sizeof(conn->ripaddr)); |
| memset(&conn->rport, 0, sizeof(conn->rport)); |
| |
| return len; |
| } |
| |
| #ifdef DTLS_PSK |
| /* This function is the "key store" for tinyDTLS. It is called to |
| * retrieve a key for the given identity within this particular |
| * session. */ |
| static int |
| get_psk_info(struct dtls_context_t *ctx, const session_t *session, |
| dtls_credentials_type_t type, |
| const unsigned char *id, size_t id_len, |
| unsigned char *result, size_t result_length) { |
| |
| struct keymap_t { |
| unsigned char *id; |
| size_t id_length; |
| unsigned char *key; |
| size_t key_length; |
| } psk[3] = { |
| { (unsigned char *)"Client_identity", 15, |
| (unsigned char *)"secretPSK", 9 }, |
| { (unsigned char *)"default identity", 16, |
| (unsigned char *)"\x11\x22\x33", 3 }, |
| { (unsigned char *)"\0", 2, |
| (unsigned char *)"", 1 } |
| }; |
| |
| if (type != DTLS_PSK_KEY) { |
| return 0; |
| } |
| |
| if (id) { |
| int i; |
| for (i = 0; i < sizeof(psk)/sizeof(struct keymap_t); i++) { |
| if (id_len == psk[i].id_length && memcmp(id, psk[i].id, id_len) == 0) { |
| if (result_length < psk[i].key_length) { |
| dtls_warn("buffer too small for PSK"); |
| return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); |
| } |
| |
| memcpy(result, psk[i].key, psk[i].key_length); |
| return psk[i].key_length; |
| } |
| } |
| } |
| |
| return dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR); |
| } |
| #endif /* DTLS_PSK */ |
| |
| #ifdef DTLS_ECC |
| static int |
| get_ecdsa_key(struct dtls_context_t *ctx, |
| const session_t *session, |
| const dtls_ecdsa_key_t **result) { |
| static const dtls_ecdsa_key_t ecdsa_key = { |
| .curve = DTLS_ECDH_CURVE_SECP256R1, |
| .priv_key = ecdsa_priv_key, |
| .pub_key_x = ecdsa_pub_key_x, |
| .pub_key_y = ecdsa_pub_key_y |
| }; |
| |
| *result = &ecdsa_key; |
| return 0; |
| } |
| |
| 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) { |
| return 0; |
| } |
| #endif /* DTLS_ECC */ |
| |
| PROCESS(udp_server_process, "UDP server process"); |
| AUTOSTART_PROCESSES(&udp_server_process); |
| /*---------------------------------------------------------------------------*/ |
| static void |
| dtls_handle_read(dtls_context_t *ctx) { |
| session_t session; |
| |
| if(uip_newdata()) { |
| uip_ipaddr_copy(&session.addr, &UIP_IP_BUF->srcipaddr); |
| session.port = UIP_UDP_BUF->srcport; |
| session.size = sizeof(session.addr) + sizeof(session.port); |
| |
| dtls_handle_message(ctx, &session, uip_appdata, uip_datalen()); |
| } |
| } |
| /*---------------------------------------------------------------------------*/ |
| static void |
| print_local_addresses(void) |
| { |
| int i; |
| uint8_t state; |
| |
| PRINTF("Server IPv6 addresses: \n"); |
| for(i = 0; i < UIP_DS6_ADDR_NB; i++) { |
| state = uip_ds6_if.addr_list[i].state; |
| if(uip_ds6_if.addr_list[i].isused && |
| (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { |
| PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr); |
| PRINTF("\n"); |
| } |
| } |
| } |
| |
| #if 0 |
| static void |
| create_rpl_dag(uip_ipaddr_t *ipaddr) |
| { |
| struct uip_ds6_addr *root_if; |
| |
| root_if = uip_ds6_addr_lookup(ipaddr); |
| if(root_if != NULL) { |
| rpl_dag_t *dag; |
| uip_ipaddr_t prefix; |
| |
| rpl_set_root(RPL_DEFAULT_INSTANCE, ipaddr); |
| dag = rpl_get_any_dag(); |
| uip_ip6addr(&prefix, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); |
| rpl_set_prefix(dag, &prefix, 64); |
| PRINTF("created a new RPL dag\n"); |
| } else { |
| PRINTF("failed to create a new RPL DAG\n"); |
| } |
| } |
| #endif |
| |
| void |
| init_dtls() { |
| static dtls_handler_t cb = { |
| .write = send_to_peer, |
| .read = read_from_peer, |
| .event = NULL, |
| #ifdef DTLS_PSK |
| .get_psk_info = get_psk_info, |
| #endif /* DTLS_PSK */ |
| #ifdef DTLS_ECC |
| .get_ecdsa_key = get_ecdsa_key, |
| .verify_ecdsa_key = verify_ecdsa_key |
| #endif /* DTLS_ECC */ |
| }; |
| #if 0 |
| uip_ipaddr_t ipaddr; |
| /* struct uip_ds6_addr *root_if; */ |
| #endif /* UIP_CONF_ROUTER */ |
| |
| PRINTF("DTLS server started\n"); |
| |
| #if 0 /* TEST */ |
| memset(&tmp_addr, 0, sizeof(rimeaddr_t)); |
| if(get_eui64_from_eeprom(tmp_addr.u8)); |
| #if NETSTACK_CONF_WITH_IPV6 |
| memcpy(&uip_lladdr.addr, &tmp_addr.u8, 8); |
| #endif |
| #endif /* TEST */ |
| |
| #if 0 |
| /* uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); */ |
| /* uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); */ |
| /* uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); */ |
| |
| /* create_rpl_dag(&ipaddr); */ |
| /* #else */ |
| /* uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); */ |
| |
| uip_ip6addr(&ipaddr, 0xaaaa, 0,0,0,0x0200,0,0,0x0003); |
| uip_ds6_addr_add(&ipaddr, 0, ADDR_MANUAL); |
| |
| create_rpl_dag(&ipaddr); |
| #endif /* UIP_CONF_ROUTER */ |
| |
| server_conn = udp_new(NULL, 0, NULL); |
| udp_bind(server_conn, UIP_HTONS(20220)); |
| |
| dtls_set_log_level(DTLS_LOG_DEBUG); |
| |
| dtls_context = dtls_new_context(server_conn); |
| if (dtls_context) |
| dtls_set_handler(dtls_context, &cb); |
| } |
| |
| /*---------------------------------------------------------------------------*/ |
| PROCESS_THREAD(udp_server_process, ev, data) |
| { |
| PROCESS_BEGIN(); |
| |
| dtls_init(); |
| init_dtls(); |
| |
| print_local_addresses(); |
| |
| if (!dtls_context) { |
| dtls_emerg("cannot create context\n"); |
| PROCESS_EXIT(); |
| } |
| |
| #ifdef ENABLE_POWERTRACE |
| powertrace_start(CLOCK_SECOND * 2); |
| #endif |
| |
| while(1) { |
| PROCESS_WAIT_EVENT(); |
| if(ev == tcpip_event) { |
| dtls_handle_read(dtls_context); |
| } |
| #if 0 |
| if (bytes_read > 0) { |
| /* dtls_handle_message(dtls_context, &the_session, readbuf, bytes_read); */ |
| read_from_peer(dtls_context, &the_session, readbuf, bytes_read); |
| } |
| dtls_handle_message(ctx, &session, uip_appdata, bytes_read); |
| #endif |
| } |
| |
| PROCESS_END(); |
| } |
| /*---------------------------------------------------------------------------*/ |