diff --git a/coap-service/coap_service_api.h b/coap-service/coap_service_api.h index 14a7d39ec6..8496fca40d 100644 --- a/coap-service/coap_service_api.h +++ b/coap-service/coap_service_api.h @@ -69,9 +69,9 @@ extern const uint8_t COAP_MULTICAST_ADDR_SITE_LOCAL[16]; //!> ff05::fd, COAP sit * * Function that handles CoAP service message receiving and parsing * - * \param msg_id Id number of the current message. + * \param service_id Service handle. * \param source_address IPv6 source address. - * \param source_port Source port + * \param source_port Source port. * \param response_ptr Pointer to CoAP header structure. * * \return 0 for success / -1 for failure @@ -85,10 +85,11 @@ typedef int coap_service_response_recv(int8_t service_id, uint8_t source_address * * \param service_id Id number of the current service. * \param source_address IPv6 source address. - * \param source_port Source port + * \param source_port Source port. * \param request_ptr Pointer to CoAP header structure. * - * \return Status + * \return -1 = Message ignored, no response will be sent. Transaction will be deleted. + * 0 = Response is either already sent or will be send. Transaction is not deleted. */ typedef int coap_service_request_recv_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *request_ptr); @@ -98,8 +99,10 @@ typedef int coap_service_request_recv_cb(int8_t service_id, uint8_t source_addre * Starts security service handling and fetches device password. * * \param service_id Id number of the current service. - * \param address Address of sender - * \param port Port of the device + * \param address Address of sender. + * \param port Port of the device. + * \param pw Pointer where to write the ecjpake password. + * \param pw_len Pointer where to write length of the ecjpake password. * * \return 0 for success / -1 for failure */ @@ -111,8 +114,8 @@ typedef int coap_service_security_start_cb(int8_t service_id, uint8_t address[st * CoAP service security done callback function. * * \param service_id Id number of the current service. - * \param address Address of sender - * \param keyblock Security key (40 bits) + * \param address Address of sender. + * \param keyblock Security key (40 bits). * * \return 0 for success / -1 for failure */ @@ -147,23 +150,12 @@ extern void coap_service_delete( int8_t service_id ); * * Closes secure connection (if present), but leaves socket open. * - * \param service_id Id number of the current service. + * \param service_id Id number of the current service. + * \param destimation_addr_ptr Connection destination address. + * \param port Connection destination port. */ extern void coap_service_close_secure_connection(int8_t service_id, uint8_t destination_addr_ptr[static 16], uint16_t port); -/** - * \brief Sets password for device - * - * \param service_id Service id - * \param address Device address - * \param port Device port - * \param pw_ptr Pointer to password. - * \param pw_len Lenght of password. - * - * \return 0 for success / -1 for failure - */ -//int coap_service_security_key_set(int8_t service_id, uint8_t address[static 16], uint16_t port, uint8_t *pw_ptr, uint8_t pw_len); - /** * \brief Virtual socket sent callback. * @@ -213,7 +205,6 @@ extern int16_t coap_service_virtual_socket_set_cb(int8_t service_id, coap_servic * * \param service_id Id number of the current service. * \param *uri Uri address. - * \param port port that Application wants to use for communicate with coap server. * \param allowed_method Informs method that is allowed to use (used defines described above). * \param *request_recv_cb CoAP service request receive callback function pointer. * @@ -240,7 +231,7 @@ extern int8_t coap_service_unregister_uri(int8_t service_id, const char *uri); * * \param service_id Id number of the current service. * \param options Options defined above. - * \param destination_addr IPv6 address. + * \param destination_addr IPv6 address. * \param destination_port Destination port * \param msg_type Message type can be found from sn_coap_header. * \param msg_code Message code can be found from sn_coap_header. @@ -261,15 +252,39 @@ extern uint16_t coap_service_request_send(int8_t service_id, uint8_t options, co * Build and sends CoAP service response message. * * \param service_id Id number of the current service. - * \param msg_id Message ID number. * \param options Options defined above. - * \param response_ptr Pointer to CoAP header structure. + * \param request_ptr Pointer to CoAP request message header structure. + * \param message_code Message code can be found from sn_coap_header. + * \param content_type Content type can be found from sn_coap_header. + * \param payload_ptr Pointer to message content. + * \param payload_len Lenght of the message. * * \return -1 For failure *- 0 For success */ extern int8_t coap_service_response_send(int8_t service_id, uint8_t options, sn_coap_hdr_s *request_ptr, sn_coap_msg_code_e message_code, sn_coap_content_format_e content_type, const uint8_t *payload_ptr,uint16_t payload_len); +/** + * \brief Sends CoAP service response + * + * Build and sends CoAP service response message based on CoAP request message id. + * + * \param service_id Id number of the current service. + * \param options Options defined above. + * \param msg_id Request messages ID. + * \param msg_type Message type can be found from sn_coap_header. + * \param message_code Message code can be found from sn_coap_header. + * \param content_type Content type can be found from sn_coap_header. + * \param payload_ptr Pointer to message content. + * \param payload_len Lenght of the message. + * + * \return -1 For failure + *- 0 For success + */ +extern int8_t coap_service_response_send_by_msg_id(int8_t service_id, uint8_t options, uint16_t msg_id, sn_coap_msg_code_e message_code, sn_coap_content_format_e content_type, const uint8_t *payload_ptr,uint16_t payload_len); + + + /** * \brief Delete CoAP request transaction * @@ -297,18 +312,48 @@ extern int8_t coap_service_request_delete(int8_t service_id, uint16_t msg_id); */ extern int8_t coap_service_set_handshake_timeout(int8_t service_id, uint32_t min, uint32_t max); +/** + * \brief Set DTLS handshake limit values + * + * Configures the limits for DTLS sessions. Values must be > 0. + * + * \param handshakes_max Maximum amount of simultaneous handshakes. + * \param connections_max Maximum amount of sessions. + * + * \return -1 For failure + *- 0 For success + */ +extern int8_t coap_service_handshake_limits_set(uint8_t handshakes_max, uint8_t connections_max); + /** * \brief Set CoAP duplication message buffer size * * Configures the CoAP duplication message buffer size. * * \param service_id Id number of the current service. - * \param size Buffer size (messages) + * \param size Buffer size (messages). * * \return -1 For failure *- 0 For success */ extern int8_t coap_service_set_duplicate_message_buffer(int8_t service_id, uint8_t size); + +/** + * \brief Set DTLS certificates + * + * Set DTLS certificates. + * + * \param service_id Id number of the current service. + * \param cert Pointer to certificate chain. + * \param cert_len Certificate length. + * \param priv_key pointer to private key. + * \param priv_key_len length of private key. + * + * \return -1 For failure + *- 0 For success + */ + +extern int8_t coap_service_certificate_set(int8_t service_id, const unsigned char *cert, uint16_t cert_len, const unsigned char *priv_key, uint8_t priv_key_len); #ifdef __cplusplus } #endif diff --git a/source/coap_connection_handler.c b/source/coap_connection_handler.c index 722a05c15c..154b84b339 100644 --- a/source/coap_connection_handler.c +++ b/source/coap_connection_handler.c @@ -48,6 +48,9 @@ const uint8_t COAP_MULTICAST_ADDR_SITE_LOCAL[16] = { 0xff, 0x05, [15] = 0xfd }; static NS_LIST_DEFINE(socket_list, internal_socket_t, link); +static uint8_t max_handshakes = MAX_ONGOING_HANDSHAKES; +static uint8_t max_sessions = MAX_SECURE_SESSION_COUNT; + static void timer_cb(void* param); static void recv_sckt_msg(void *cb_res); @@ -141,13 +144,14 @@ static int8_t virtual_socket_id_allocate() return new_virtual_socket_id; } -static secure_session_t *secure_session_create(internal_socket_t *parent, const uint8_t *address_ptr, uint16_t port) +static secure_session_t *secure_session_create(internal_socket_t *parent, const uint8_t *address_ptr, uint16_t port, SecureConnectionMode secure_mode) { + uint8_t handshakes = 0; if(!address_ptr){ return NULL; } - if(MAX_SECURE_SESSION_COUNT <= ns_list_count(&secure_session_list)){ + if(max_sessions <= ns_list_count(&secure_session_list)){ // Seek & destroy oldest session where close notify have been sent secure_session_t *to_be_removed = NULL; ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) { @@ -164,6 +168,16 @@ static secure_session_t *secure_session_create(internal_socket_t *parent, const secure_session_delete(to_be_removed); } + // Count for ongoing handshakes + ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) { + if(cur_ptr->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){ + handshakes++; + } + } + if(handshakes >= max_handshakes) { + return NULL; + } + secure_session_t *this = ns_dyn_mem_alloc(sizeof(secure_session_t)); if (!this) { return NULL; @@ -179,12 +193,13 @@ static secure_session_t *secure_session_create(internal_socket_t *parent, const } timer_id++; } + this->last_contact_time = coap_service_get_internal_timer_ticks(); this->timer.id = timer_id; this->remote_host.type = ADDRESS_IPV6; memcpy(this->remote_host.address, address_ptr, 16); this->remote_host.identifier = port; - this->sec_handler = coap_security_create(parent->socket, this->timer.id, this, ECJPAKE, + this->sec_handler = coap_security_create(parent->socket, this->timer.id, this, secure_mode, &secure_session_sendto, &secure_session_recvfrom, &start_timer, &timer_status); if( !this->sec_handler ){ ns_dyn_mem_free(this); @@ -595,31 +610,34 @@ static void secure_recv_sckt_msg(void *cb_res) // Create session if (!session) { - session = secure_session_create(sock, src_address.address, src_address.identifier); - } - if (!session) { - tr_err("secure_recv_sckt_msg session creation failed - OOM"); - return; - } - // Record the destination. We are not strict on local address - all - // session_find calls match only on remote address and port. But we - // record the last-used destination address to use it as the source of - // outgoing packets. - memcpy(session->local_address, dst_address, 16); - session->last_contact_time = coap_service_get_internal_timer_ticks(); - // Start handshake - if (!coap_security_handler_is_started(session->sec_handler) ){ - uint8_t *pw = ns_dyn_mem_alloc(64); - uint8_t pw_len; - if( sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->socket, src_address.address, src_address.identifier, pw, &pw_len)){ - //TODO: get_password_cb should support certs and PSK also - coap_security_keys_t keys; - keys._priv = pw; - keys._priv_len = pw_len; - coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, sock->timeout_min, sock->timeout_max); + coap_security_keys_t keys; + memset(&keys, 0, sizeof(coap_security_keys_t)); + + if (sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->socket, src_address.address, src_address.identifier, &keys)) { + session = secure_session_create(sock, src_address.address, src_address.identifier, keys.mode); + if (!session) { + tr_err("secure_recv_sckt_msg session creation failed - OOM"); + ns_dyn_mem_free(keys._key); + return; + } //TODO: error handling + } else { + return; + } + + // Record the destination. We are not strict on local address - all + // session_find calls match only on remote address and port. But we + // record the last-used destination address to use it as the source of + // outgoing packets. + memcpy(session->local_address, dst_address, 16); + + session->last_contact_time = coap_service_get_internal_timer_ticks(); + // Start handshake + if (!coap_security_handler_is_started(session->sec_handler)) { + coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, sock->timeout_min, sock->timeout_max); + ns_dyn_mem_free(keys._key); + } - ns_dyn_mem_free(pw); } else { //Continue handshake if (session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING) { @@ -703,34 +721,29 @@ int coap_connection_handler_virtual_recv(coap_conn_handler_t *handler, uint8_t a } if (handler->socket->is_secure) { + coap_security_keys_t keys; + memset(&keys, 0, sizeof(coap_security_keys_t)); + secure_session_t *session = secure_session_find(sock, address, port); if (!session) { - session = secure_session_create(sock, address, port); - } - if (!session) { - tr_err("coap_connection_handler_virtual_recv session creation failed - OOM"); - return -1; + if (sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->socket, address, port, &keys)) { + session = secure_session_create(sock, address, port, keys.mode); + if (!session) { + tr_err("coap_connection_handler_virtual_recv session creation failed - OOM"); + ns_dyn_mem_free(keys._key); + return -1; + } + coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max); + ns_dyn_mem_free(keys._key); + return 0; + } else { + return -1; + } } session->last_contact_time = coap_service_get_internal_timer_ticks(); - if (!coap_security_handler_is_started(session->sec_handler)) { - uint8_t *pw = ns_dyn_mem_alloc(64); - uint8_t pw_len; - if (sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->socket, address, port, pw, &pw_len)) { - //TODO: get_password_cb should support certs and PSK also - coap_security_keys_t keys; - keys._priv = pw; - keys._priv_len = pw_len; - coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max); - //TODO: error handling - ns_dyn_mem_free(pw); - return 0; - } else { - ns_dyn_mem_free(pw); - return -1; - } - } else { + if (coap_security_handler_is_started(session->sec_handler)) { if (session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING) { int ret = coap_security_handler_continue_connecting(session->sec_handler); if(ret == 0){ @@ -813,6 +826,9 @@ void connection_handler_destroy(coap_conn_handler_t *handler, bool multicast_gro if (multicast_group_leave) { coap_multicast_group_join_or_leave(handler->socket->socket, SOCKET_IPV6_LEAVE_GROUP, handler->socket_interface_selection); } + if (handler->security_keys) { + ns_dyn_mem_free(handler->security_keys); + } int_socket_delete(handler->socket); ns_dyn_mem_free(handler); } @@ -869,56 +885,59 @@ int coap_connection_handler_send_data(coap_conn_handler_t *handler, const ns_add if (!handler || !handler->socket || !dest_addr) { return -1; } + + /* Secure send */ if (handler->socket->is_secure) { handler->socket->bypass_link_sec = bypass_link_sec; secure_session_t *session = secure_session_find(handler->socket, dest_addr->address, dest_addr->identifier); if (!session) { - session = secure_session_create(handler->socket, dest_addr->address, dest_addr->identifier); - if (!session) { + coap_security_keys_t security_material; + int ret_val = 0; + + memset(&security_material, 0, sizeof(coap_security_keys_t)); + + if (!handler->_get_password_cb || 0 != handler->_get_password_cb(handler->socket->socket, (uint8_t*)dest_addr->address, dest_addr->identifier, &security_material)) { return -1; } - session->last_contact_time = coap_service_get_internal_timer_ticks(); - uint8_t *pw = ns_dyn_mem_alloc(64); - if (!pw) { - //todo: free secure session? - return -1; - } - uint8_t pw_len; - if (handler->_get_password_cb && 0 == handler->_get_password_cb(handler->socket->socket, (uint8_t*)dest_addr->address, dest_addr->identifier, pw, &pw_len)) { - //TODO: get_password_cb should support certs and PSK also - coap_security_keys_t keys; - keys._priv = pw; - keys._priv_len = pw_len; - coap_security_handler_connect_non_blocking(session->sec_handler, false, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max); - ns_dyn_mem_free(pw); - return -2; - } else { - //free secure session? - ns_dyn_mem_free(pw); - return -1; + + session = secure_session_create(handler->socket, dest_addr->address, dest_addr->identifier, security_material.mode); + if (!session || (0 > coap_security_handler_connect_non_blocking(session->sec_handler, false, DTLS, security_material, handler->socket->timeout_min, handler->socket->timeout_max))) { + ret_val = -1; } + + ns_dyn_mem_free(security_material._key); + return ret_val; + } else if (session->session_state == SECURE_SESSION_OK) { - if (coap_security_handler_send_message(session->sec_handler, data_ptr, data_len ) > 0 ) { - session->last_contact_time = coap_service_get_internal_timer_ticks(); - return 0; + session->last_contact_time = coap_service_get_internal_timer_ticks(); + if (0 > coap_security_handler_send_message(session->sec_handler, data_ptr, data_len )) { + return -1; } } - return -1; - }else{ + /* Unsecure */ + } else { + /* Virtual socket */ if (!handler->socket->real_socket && handler->_send_cb) { - return handler->_send_cb((int8_t)handler->socket->socket, dest_addr->address, dest_addr->identifier, data_ptr, data_len); - } - int opt_name = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT; - int8_t securityLinkLayer = 1; - if (bypass_link_sec) { - securityLinkLayer = 0; - } + if (handler->_send_cb((int8_t)handler->socket->socket, dest_addr->address, dest_addr->identifier, data_ptr, data_len) < 0) { + return -1; + } + } else { + int opt_name = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT; + int8_t securityLinkLayer = 1; + if (bypass_link_sec) { + securityLinkLayer = 0; + } - socket_setsockopt(handler->socket->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &opt_name, sizeof(int)); - socket_setsockopt(handler->socket->socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t)); + socket_setsockopt(handler->socket->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &opt_name, sizeof(int)); + socket_setsockopt(handler->socket->socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t)); - return send_to_real_socket(handler->socket->socket, dest_addr, src_address, data_ptr, data_len); + if (0 > send_to_real_socket(handler->socket->socket, dest_addr, src_address, data_ptr, data_len)) { + return -1; + } + } } + + return 1; } bool coap_connection_handler_socket_belongs_to(coap_conn_handler_t *handler, int8_t socket_id) @@ -944,22 +963,35 @@ int8_t coap_connection_handler_set_timeout(coap_conn_handler_t *handler, uint32_ return 0; } +int8_t coap_connection_handler_handshake_limits_set(uint8_t handshakes_limit, uint8_t connections_limit) +{ + if (!handshakes_limit || !connections_limit) { + return -1; + } + max_handshakes = handshakes_limit; + max_sessions = connections_limit; + + return 0; +} + /* No need to call every second - call rather like every minute (SECURE_SESSION_CLEAN_INTERVAL sets this) */ void coap_connection_handler_exec(uint32_t time) { if(ns_list_count(&secure_session_list)){ // Seek & destroy old sessions where close notify have been sent ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) { - if(cur_ptr->session_state == SECURE_SESSION_CLOSED || - cur_ptr->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){ + if(cur_ptr->session_state == SECURE_SESSION_CLOSED) { if((cur_ptr->last_contact_time + CLOSED_SECURE_SESSION_TIMEOUT) <= time){ secure_session_delete(cur_ptr); } - } - if(cur_ptr->session_state == SECURE_SESSION_OK){ + } else if(cur_ptr->session_state == SECURE_SESSION_OK){ if((cur_ptr->last_contact_time + OPEN_SECURE_SESSION_TIMEOUT) <= time){ secure_session_delete(cur_ptr); } + } else if(cur_ptr->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){ + if((cur_ptr->last_contact_time + ONGOING_HANDSHAKE_TIMEOUT) <= time){ + secure_session_delete(cur_ptr); + } } } } diff --git a/source/coap_message_handler.c b/source/coap_message_handler.c index 2bd05770d4..fc15d27064 100644 --- a/source/coap_message_handler.c +++ b/source/coap_message_handler.c @@ -96,10 +96,6 @@ static coap_transaction_t *transaction_create(void) static void transaction_free(coap_transaction_t *this) { - if (!this) { - return; - } - if (this->data_ptr) { ns_dyn_mem_free(this->data_ptr); } @@ -108,11 +104,13 @@ static void transaction_free(coap_transaction_t *this) void transaction_delete(coap_transaction_t *this) { - if (this) { - ns_list_remove(&request_list, this); - transaction_free(this); + if (!coap_message_handler_transaction_valid(this)) { + return; } + ns_list_remove(&request_list, this); + transaction_free(this); + return; } @@ -227,11 +225,14 @@ coap_transaction_t *coap_message_handler_find_transaction(uint8_t *address_ptr, int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t socket_id, const uint8_t source_addr_ptr[static 16], uint16_t port, const uint8_t dst_addr_ptr[static 16], uint8_t *data_ptr, uint16_t data_len, int16_t (cb)(int8_t, sn_coap_hdr_s *, coap_transaction_t *)) { + sn_nsdl_addr_s src_addr; + sn_coap_hdr_s *coap_message; + int16_t ret_val = 0; + if (!cb || !handle) { return -1; } - sn_nsdl_addr_s src_addr; - sn_coap_hdr_s *coap_message; + src_addr.addr_ptr = (uint8_t *)source_addr_ptr; src_addr.addr_len = 16; src_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; @@ -242,13 +243,16 @@ int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t tr_err("CoAP Parsing failed"); return -1; } + tr_debug("CoAP status:%d, type:%d, code:%d, id:%d", coap_message->coap_status, coap_message->msg_type, coap_message->msg_code, coap_message->msg_id); + /* Check, if coap itself sends response, or block receiving is ongoing... */ if (coap_message->coap_status != COAP_STATUS_OK && coap_message->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { tr_debug("CoAP library responds"); - sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); - return -1; + ret_val = -1; + goto exit; } + /* Request received */ if (coap_message->msg_code > 0 && coap_message->msg_code < 32) { coap_transaction_t *transaction_ptr = transaction_create(); @@ -256,19 +260,20 @@ int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t transaction_ptr->service_id = coap_service_id_find_by_socket(socket_id); transaction_ptr->msg_id = coap_message->msg_id; transaction_ptr->client_request = false;// this is server transaction + transaction_ptr->req_msg_type = coap_message->msg_type; memcpy(transaction_ptr->local_address, *(dst_addr_ptr) == 0xFF ? ns_in6addr_any : dst_addr_ptr, 16); memcpy(transaction_ptr->remote_address, source_addr_ptr, 16); - transaction_ptr->remote_port = port; - - int ret = cb(socket_id, coap_message, transaction_ptr); - if (ret != 0) { - tr_debug("Service %d, no response expected", transaction_ptr->service_id); - sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); - transaction_delete(transaction_ptr); - return -1; + if (coap_message->token_len) { + memcpy(transaction_ptr->token, coap_message->token_ptr, coap_message->token_len); } + transaction_ptr->remote_port = port; + if (cb(socket_id, coap_message, transaction_ptr) < 0) { + // negative return value = message ignored -> delete transaction + transaction_delete(transaction_ptr); + } + goto exit; } else { - //TODO: handle error case + ret_val = -1; } /* Response received */ } else { @@ -278,20 +283,21 @@ int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t } if (!this) { tr_error("client transaction not found"); - sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); - return -1; + ret_val = -1; + goto exit; } tr_debug("Service %d, response received", this->service_id); ns_list_remove(&request_list, this); if (this->resp_cb) { this->resp_cb(this->service_id, (uint8_t *)source_addr_ptr, port, coap_message); } - sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); transaction_free(this); } - return 0; +exit: + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message); + return ret_val; } uint16_t coap_message_handler_request_send(coap_msg_handler_t *handle, int8_t service_id, uint8_t options, const uint8_t destination_addr[static 16], @@ -358,13 +364,37 @@ uint16_t coap_message_handler_request_send(coap_msg_handler_t *handle, int8_t se return transaction_ptr->msg_id; } -int8_t coap_message_handler_response_send(coap_msg_handler_t *handle, int8_t service_id, uint8_t options, sn_coap_hdr_s *request_ptr, sn_coap_msg_code_e message_code, sn_coap_content_format_e content_type, const uint8_t *payload_ptr, uint16_t payload_len) +static int8_t coap_message_handler_resp_build_and_send(coap_msg_handler_t *handle, sn_coap_hdr_s *coap_msg_ptr, coap_transaction_t *transaction_ptr) { - coap_transaction_t *transaction_ptr; - sn_coap_hdr_s *response; sn_nsdl_addr_s dst_addr; uint16_t data_len; uint8_t *data_ptr; + + + dst_addr.addr_ptr = transaction_ptr->remote_address; + dst_addr.addr_len = 16; + dst_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; + dst_addr.port = transaction_ptr->remote_port; + + data_len = sn_coap_builder_calc_needed_packet_data_size(coap_msg_ptr); + data_ptr = own_alloc(data_len); + if (data_len > 0 && !data_ptr) { + return -1; + } + sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, coap_msg_ptr, transaction_ptr); + + handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr); + own_free(data_ptr); + + return 0; + +} + +int8_t coap_message_handler_response_send(coap_msg_handler_t *handle, int8_t service_id, uint8_t options, sn_coap_hdr_s *request_ptr, sn_coap_msg_code_e message_code, sn_coap_content_format_e content_type, const uint8_t *payload_ptr, uint16_t payload_len) +{ + sn_coap_hdr_s *response; + coap_transaction_t *transaction_ptr; + int8_t ret_val = 0; (void) options; (void)service_id; @@ -380,10 +410,6 @@ int8_t coap_message_handler_response_send(coap_msg_handler_t *handle, int8_t ser tr_error("response transaction not found"); return -2; } - dst_addr.addr_ptr = transaction_ptr->remote_address; - dst_addr.addr_len = 16; - dst_addr.type = SN_NSDL_ADDRESS_TYPE_IPV6; - dst_addr.port = transaction_ptr->remote_port; response = sn_coap_build_response(handle->coap, request_ptr, message_code); if( !response ){ @@ -393,18 +419,53 @@ int8_t coap_message_handler_response_send(coap_msg_handler_t *handle, int8_t ser response->payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... response->content_format = content_type; - data_len = sn_coap_builder_calc_needed_packet_data_size(response); - data_ptr = own_alloc(data_len); - if (data_len > 0 && !data_ptr) { - sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response); + + ret_val = coap_message_handler_resp_build_and_send(handle, response, transaction_ptr); + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response); + if(ret_val == 0) { + transaction_delete(transaction_ptr); + } + + return ret_val; +} + +int8_t coap_message_handler_response_send_by_msg_id(coap_msg_handler_t *handle, int8_t service_id, uint8_t options, uint16_t msg_id, sn_coap_msg_code_e message_code, sn_coap_content_format_e content_type, const uint8_t *payload_ptr,uint16_t payload_len) +{ + sn_coap_hdr_s response; + coap_transaction_t *transaction_ptr; + int8_t ret_val; + + (void) options; + (void)service_id; + + transaction_ptr = transaction_find_server(msg_id); + if (!transaction_ptr || !handle) { return -1; } - sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, response, transaction_ptr); - sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response); - handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr); - sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, request_ptr); - own_free(data_ptr); - return 0; + + tr_debug("Service %d, send CoAP response", service_id); + + memset(&response, 0, sizeof(sn_coap_hdr_s)); + + response.payload_len = payload_len; + response.payload_ptr = (uint8_t *) payload_ptr; // Cast away const and trust that nsdl doesn't modify... + response.content_format = content_type; + response.token_len = 4; + response.token_ptr = transaction_ptr->token; + response.msg_code = message_code; + if (transaction_ptr->req_msg_type == COAP_MSG_TYPE_CONFIRMABLE) { + response.msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; + response.msg_id = msg_id; + } else { + response.msg_type = COAP_MSG_TYPE_NON_CONFIRMABLE; + } + + ret_val = coap_message_handler_resp_build_and_send(handle, &response, transaction_ptr); + if(ret_val == 0) { + transaction_delete(transaction_ptr); + } + + return ret_val; } int8_t coap_message_handler_request_delete(coap_msg_handler_t *handle, int8_t service_id, uint16_t msg_id) diff --git a/source/coap_security_handler.c b/source/coap_security_handler.c index 5e920208b9..646be0b852 100644 --- a/source/coap_security_handler.c +++ b/source/coap_security_handler.c @@ -69,10 +69,10 @@ static const int PSK_SUITES[] = { 0 }; +#define TRACE_GROUP "CsSh" static void set_timer( void *sec_obj, uint32_t int_ms, uint32_t fin_ms ); static int get_timer( void *sec_obj ); -static int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_keys_t keys ); int entropy_poll( void *data, unsigned char *output, size_t len, size_t *olen ); @@ -276,37 +276,35 @@ static int export_key_block(void *ctx, } #endif -int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_keys_t keys ) +static int coap_security_handler_configure_keys (coap_security_t *sec, coap_security_keys_t keys, bool is_server) { + (void) is_server; + int ret = -1; switch( sec->_conn_mode ){ - case Certificate:{ + case CERTIFICATE:{ #if defined(MBEDTLS_X509_CRT_PARSE_C) - if( mbedtls_x509_crt_parse( &sec->_cacert, keys._server_cert, - keys._server_cert_len ) < 0 ){ + if( keys._cert && mbedtls_x509_crt_parse( &sec->_owncert, keys._cert, keys._cert_len ) < 0 ){ break; } - if( mbedtls_x509_crt_parse( &sec->_owncert, keys._pub_cert_or_identifier, - keys._pub_len ) < 0 ){ + + if( mbedtls_pk_parse_key(&sec->_pkey, keys._priv_key, keys._priv_key_len, NULL, 0) < 0){ break; } - if( mbedtls_pk_parse_key(&sec->_pkey, keys._priv, keys._priv_len, NULL, 0) < 0){ + + if (0 != mbedtls_ssl_conf_own_cert(&sec->_conf, &sec->_owncert, &sec->_pkey)) { break; } - //TODO: If needed in server mode, this won't work - if( 0 != mbedtls_ssl_conf_own_cert(&sec->_conf, &sec->_owncert, &sec->_pkey) ){ - break; - } - //TODO: use MBEDTLS_SSL_VERIFY_REQUIRED instead of optional - mbedtls_ssl_conf_authmode( &sec->_conf, MBEDTLS_SSL_VERIFY_OPTIONAL ); - mbedtls_ssl_conf_ca_chain( &sec->_conf, &sec->_cacert, NULL ); + + mbedtls_ssl_conf_authmode( &sec->_conf, MBEDTLS_SSL_VERIFY_NONE ); + mbedtls_ssl_conf_ca_chain( &sec->_conf, &sec->_owncert, NULL ); ret = 0; #endif break; } case PSK: { #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) - if( 0 != mbedtls_ssl_conf_psk(&sec->_conf, keys._priv, keys._priv_len, keys._pub_cert_or_identifier, keys._pub_len) ){ + if( 0 != mbedtls_ssl_conf_psk(&sec->_conf, keys._priv_key, keys._priv_key_len, keys._cert, keys._cert_len) ){ break; } mbedtls_ssl_conf_ciphersuites(&sec->_conf, PSK_SUITES); @@ -316,7 +314,7 @@ int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_ke } case ECJPAKE: { #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) - if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._priv, keys._priv_len) != 0 ){ + if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._key, keys._key_len) != 0 ){ return -1; } mbedtls_ssl_conf_ciphersuites(&sec->_conf, ECJPAKE_SUITES); @@ -336,82 +334,8 @@ int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_ke return ret; } -int coap_security_handler_connect(coap_security_t *sec, bool is_server, SecureSocketMode sock_mode, coap_security_keys_t keys){ - int ret = -1; - - if( !sec ){ - return ret; - } - sec->_is_blocking = true; - - int endpoint = MBEDTLS_SSL_IS_CLIENT; - if( is_server ){ - endpoint = MBEDTLS_SSL_IS_SERVER; - } - - int mode = MBEDTLS_SSL_TRANSPORT_DATAGRAM; - if( sock_mode == TLS ){ - mode = MBEDTLS_SSL_TRANSPORT_STREAM; - } - - if( ( mbedtls_ssl_config_defaults( &sec->_conf, - endpoint, - mode, 0 ) ) != 0 ) - { - return -1; - } - - mbedtls_ssl_set_bio( &sec->_ssl, sec, - f_send, f_recv, NULL ); - - mbedtls_ssl_set_timer_cb( &sec->_ssl, sec, set_timer, - get_timer ); - - if( coap_security_handler_configure_keys( sec, keys ) != 0 ){ - return -1; - } - -#ifdef MBEDTLS_SSL_SRV_C - mbedtls_ssl_conf_dtls_cookies(&sec->_conf, simple_cookie_write, - simple_cookie_check, - &sec->_cookie); -#endif - - sec->_is_started = true; - - do { - ret = mbedtls_ssl_handshake_step( &sec->_ssl ); - if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ){ //cookie check failed - if( is_server ){ - mbedtls_ssl_session_reset(&sec->_ssl); -#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) - if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._priv, keys._priv_len) != 0 ){ - return -1; - } -#endif - ret = MBEDTLS_ERR_SSL_WANT_READ; //needed to keep doing - }else{ - ret = -1; - } - } - }while( ret == MBEDTLS_ERR_SSL_WANT_READ || - ret == MBEDTLS_ERR_SSL_WANT_WRITE ); - - if( ret != 0){ - ret = -1; - }else{ - if( mbedtls_ssl_get_verify_result( &sec->_ssl ) != 0 ) - { - ret = -1; - } - } - - return ret; -} - int coap_security_handler_connect_non_blocking(coap_security_t *sec, bool is_server, SecureSocketMode sock_mode, coap_security_keys_t keys, uint32_t timeout_min, uint32_t timeout_max) { - if( !sec ){ return -1; } @@ -457,13 +381,14 @@ int coap_security_handler_connect_non_blocking(coap_security_t *sec, bool is_ser #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) //TODO: Figure out better way!!! //Password should never be stored in multiple places!!! - if( is_server && keys._priv_len > 0){ - memcpy(sec->_pw, keys._priv, keys._priv_len); - sec->_pw_len = keys._priv_len; + if ((sec->_conn_mode == ECJPAKE) && is_server && keys._key_len > 0){ + memcpy(sec->_pw, keys._key, keys._key_len); + sec->_pw_len = keys._key_len; } #endif - if( coap_security_handler_configure_keys( sec, keys ) != 0 ){ + if (coap_security_handler_configure_keys(sec, keys, is_server) != 0) { + tr_debug("security credential configure failed"); return -1; } @@ -499,7 +424,6 @@ int coap_security_handler_continue_connecting(coap_security_t *sec){ while( ret != MBEDTLS_ERR_SSL_WANT_READ ){ ret = mbedtls_ssl_handshake_step( &sec->_ssl ); - if( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED == ret){ mbedtls_ssl_session_reset(&sec->_ssl); #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) diff --git a/source/coap_service_api.c b/source/coap_service_api.c index 50fdef713b..cfb9a0970f 100644 --- a/source/coap_service_api.c +++ b/source/coap_service_api.c @@ -146,6 +146,7 @@ static uint8_t coap_tx_function(uint8_t *data_ptr, uint16_t data_len, sn_nsdl_ad coap_service_t *this; coap_transaction_t *transaction_ptr = coap_message_handler_transaction_valid(param); ns_address_t dest_addr; + int ret_val; if (!transaction_ptr || !data_ptr) { return 0; @@ -162,17 +163,19 @@ static uint8_t coap_tx_function(uint8_t *data_ptr, uint16_t data_len, sn_nsdl_ad dest_addr.identifier = address_ptr->port; dest_addr.type = ADDRESS_IPV6; - if (-2 == coap_connection_handler_send_data(this->conn_handler, &dest_addr, transaction_ptr->local_address, - data_ptr, data_len, (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS)) { - transaction_ptr->data_ptr = ns_dyn_mem_alloc(data_len); + ret_val = coap_connection_handler_send_data(this->conn_handler, &dest_addr, transaction_ptr->local_address, + data_ptr, data_len, (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS); + if (ret_val == 0) { if (!transaction_ptr->data_ptr) { - tr_debug("coap tx out of memory"); - return 0; - + transaction_ptr->data_ptr = ns_dyn_mem_alloc(data_len); + if (!transaction_ptr->data_ptr) { + tr_debug("coap tx out of memory"); + return 0; + } + memcpy(transaction_ptr->data_ptr, data_ptr, data_len); + transaction_ptr->data_len = data_len; } - memcpy(transaction_ptr->data_ptr, data_ptr, data_len); - transaction_ptr->data_len = data_len; - } else if (transaction_ptr->resp_cb == NULL ) { + } else if ((ret_val == -1) || (transaction_ptr->resp_cb == NULL)) { transaction_delete(transaction_ptr); } @@ -252,7 +255,7 @@ static int recv_cb(int8_t socket_id, uint8_t src_address[static 16], uint16_t po return ret; } -static int send_cb(int8_t socket_id, const uint8_t address[static 16], uint16_t port, const void *data_ptr, int data_len) +static int virtual_send_cb(int8_t socket_id, const uint8_t address[static 16], uint16_t port, const void *data_ptr, int data_len) { coap_service_t *this = service_find_by_socket(socket_id); if (this && this->virtual_socket_send_cb) { @@ -290,12 +293,34 @@ static void sec_done_cb(int8_t socket_id, uint8_t address[static 16], uint16_t p } } -static int get_passwd_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t *pw_ptr, uint8_t *pw_len) +static int get_passwd_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, coap_security_keys_t *security_ptr) { + uint8_t *pw_ptr = NULL; + uint8_t pw_len = 0; coap_service_t *this = service_find_by_socket(socket_id); - if (this && this->security_start_cb) { - return this->security_start_cb(this->service_id, address, port, pw_ptr, pw_len); + + if (!this || !security_ptr) { + return -1; } + + /* Certificates set */ + if (this->conn_handler->security_keys) { + *security_ptr = *this->conn_handler->security_keys; + return 0; + } + + pw_ptr = ns_dyn_mem_alloc(64); + if (!pw_ptr) { + return -1; + } + + if (this->security_start_cb && !this->security_start_cb(this->service_id, address, port, pw_ptr, &pw_len)) { + security_ptr->mode = ECJPAKE; + security_ptr->_key = pw_ptr; + security_ptr->_key_len = pw_len; + return 0; + } + return -1; } @@ -326,7 +351,7 @@ int8_t coap_service_initialize(int8_t interface_id, uint16_t listen_port, uint8_ tasklet_id = eventOS_event_handler_create(&service_event_handler, ARM_LIB_TASKLET_INIT_EVENT); } - this->conn_handler = connection_handler_create(recv_cb, send_cb, get_passwd_cb, sec_done_cb); + this->conn_handler = connection_handler_create(recv_cb, virtual_send_cb, get_passwd_cb, sec_done_cb); if(!this->conn_handler){ ns_dyn_mem_free(this); return -1; @@ -494,6 +519,10 @@ int8_t coap_service_response_send(int8_t service_id, uint8_t options, sn_coap_hd return coap_message_handler_response_send(coap_service_handle, service_id, options, request_ptr, message_code, content_type, payload_ptr, payload_len); } +int8_t coap_service_response_send_by_msg_id(int8_t service_id, uint8_t options, uint16_t msg_id, sn_coap_msg_code_e message_code, sn_coap_content_format_e content_type, const uint8_t *payload_ptr,uint16_t payload_len) { + return coap_message_handler_response_send_by_msg_id(coap_service_handle, service_id, options, msg_id, message_code, content_type, payload_ptr, payload_len); +} + int8_t coap_service_request_delete(int8_t service_id, uint16_t msg_id) { return coap_message_handler_request_delete(coap_service_handle, service_id, msg_id); @@ -509,6 +538,11 @@ int8_t coap_service_set_handshake_timeout(int8_t service_id, uint32_t min, uint3 return coap_connection_handler_set_timeout(this->conn_handler, min, max); } +int8_t coap_service_handshake_limits_set(uint8_t handshakes_max, uint8_t connections_max) +{ + return coap_connection_handler_handshake_limits_set(handshakes_max, connections_max); +} + int8_t coap_service_set_duplicate_message_buffer(int8_t service_id, uint8_t size) { (void) service_id; @@ -531,3 +565,31 @@ uint16_t coap_service_id_find_by_socket(int8_t socket_id) return this ? this->service_id:0; } + +int8_t coap_service_certificate_set(int8_t service_id, const unsigned char *cert, uint16_t cert_len, const unsigned char *priv_key, uint8_t priv_key_len) +{ + coap_service_t *this = service_find(service_id); + if (!this) { + return -1; + } + + if (!this->conn_handler->security_keys) { + this->conn_handler->security_keys = ns_dyn_mem_alloc(sizeof(coap_security_keys_t)); + + if (!this->conn_handler->security_keys) { + return -1; + } + } + + memset(this->conn_handler->security_keys, 0, sizeof(coap_security_keys_t)); + + this->conn_handler->security_keys->_cert = cert; + this->conn_handler->security_keys->_cert_len = cert_len; + + this->conn_handler->security_keys->_priv_key = priv_key; + this->conn_handler->security_keys->_priv_key_len = priv_key_len; + + this->conn_handler->security_keys->mode = CERTIFICATE; + + return 0; +} diff --git a/source/include/coap_connection_handler.h b/source/include/coap_connection_handler.h index 179fb24119..7d34c45e6c 100644 --- a/source/include/coap_connection_handler.h +++ b/source/include/coap_connection_handler.h @@ -24,26 +24,31 @@ #include #include "ns_address.h" #include "coap_service_api_internal.h" +#include "coap_security_handler.h" #define MAX_SECURE_SESSION_COUNT 3 +#define MAX_ONGOING_HANDSHAKES 2 #define CLOSED_SECURE_SESSION_TIMEOUT 3600 // Seconds -#define OPEN_SECURE_SESSION_TIMEOUT 18000 // Seconds +#define ONGOING_HANDSHAKE_TIMEOUT 600 // Seconds +#define OPEN_SECURE_SESSION_TIMEOUT 18000 // Seconds #define SECURE_SESSION_CLEAN_INTERVAL 60 // Seconds struct internal_socket_s; typedef int send_to_socket_cb(int8_t socket_id, const uint8_t address[static 16], uint16_t port, const void *, int); typedef int receive_from_socket_cb(int8_t socket_id, uint8_t src_address[static 16], uint16_t port, const uint8_t dst_address[static 16], unsigned char *, int); -typedef int get_pw_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t *pw_ptr, uint8_t *pw_len); +typedef int get_pw_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, coap_security_keys_t *security_ptr); typedef void security_done_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t keyblock[static 40]); typedef struct coap_conn_handler_s{ struct internal_socket_s *socket; + coap_security_keys_t *security_keys; receive_from_socket_cb *_recv_cb; send_to_socket_cb *_send_cb; get_pw_cb *_get_password_cb; security_done_cb *_security_done_cb; + int8_t socket_interface_selection; bool registered_to_multicast; } coap_conn_handler_t; @@ -60,6 +65,11 @@ void connection_handler_close_secure_connection( coap_conn_handler_t *handler, u int coap_connection_handler_open_connection(coap_conn_handler_t *handler, uint16_t listen_port, bool use_ephemeral_port, bool is_secure, bool real_socket, bool bypassSec); //If returns -2, it means security was started and data was not send +/* + * \return > 0 in OK + * \return 0 Session started, data not send + * \return -1 failure + */ int coap_connection_handler_send_data(coap_conn_handler_t *handler, const ns_address_t *dest_addr, const uint8_t src_address[static 16], uint8_t *data_ptr, uint16_t data_len, bool bypass_link_sec); int coap_connection_handler_virtual_recv(coap_conn_handler_t *handler, uint8_t address[static 16], uint16_t port, uint8_t *data_ptr, uint16_t data_len); @@ -68,6 +78,8 @@ bool coap_connection_handler_socket_belongs_to(coap_conn_handler_t *handler, int int8_t coap_connection_handler_set_timeout(coap_conn_handler_t *handler, uint32_t min, uint32_t max); +int8_t coap_connection_handler_handshake_limits_set(uint8_t handshakes_limit, uint8_t connections_limit); + void coap_connection_handler_exec(uint32_t time); #endif diff --git a/source/include/coap_message_handler.h b/source/include/coap_message_handler.h index 9cfa6a4e3e..707d42cad4 100644 --- a/source/include/coap_message_handler.h +++ b/source/include/coap_message_handler.h @@ -59,6 +59,7 @@ typedef struct coap_transaction { int8_t service_id; uint8_t options; uint8_t *data_ptr; + sn_coap_msg_type_e req_msg_type; bool client_request: 1; coap_message_handler_response_recv *resp_cb; @@ -93,4 +94,7 @@ extern void transaction_delete(coap_transaction_t *this); extern void transactions_delete_all(uint8_t *address_ptr, uint16_t port); +extern int8_t coap_message_handler_response_send_by_msg_id(coap_msg_handler_t *handle, int8_t service_id, uint8_t options, uint16_t msg_id, sn_coap_msg_code_e message_code, + sn_coap_content_format_e content_type, const uint8_t *payload_ptr,uint16_t payload_len); + #endif diff --git a/source/include/coap_security_handler.h b/source/include/coap_security_handler.h index f02167e028..d3e14fdb54 100644 --- a/source/include/coap_security_handler.h +++ b/source/include/coap_security_handler.h @@ -52,18 +52,21 @@ typedef enum { }SecureSocketMode; typedef enum { - Certificate, + CERTIFICATE, PSK, ECJPAKE }SecureConnectionMode; typedef struct { - unsigned char *_server_cert; - uint8_t _server_cert_len; - unsigned char *_pub_cert_or_identifier; - uint8_t _pub_len; - unsigned char *_priv; - uint8_t _priv_len; + SecureConnectionMode mode; + /* Certificate pointers, not owned */ + const unsigned char *_cert; + uint16_t _cert_len; + const unsigned char *_priv_key; + uint8_t _priv_key_len; + /* Secure key pointer, owned */ + unsigned char *_key; + uint8_t _key_len; } coap_security_keys_t; typedef struct coap_security_s coap_security_t; @@ -79,8 +82,6 @@ coap_security_t *coap_security_create(int8_t socket_id, int8_t timer_id, void *h void coap_security_destroy(coap_security_t *sec); -int coap_security_handler_connect(coap_security_t *sec, bool is_server, SecureSocketMode sock_mode, coap_security_keys_t keys); - int coap_security_handler_connect_non_blocking(coap_security_t *sec, bool is_server, SecureSocketMode sock_mode, coap_security_keys_t keys, uint32_t timeout_min, uint32_t timeout_max); int coap_security_handler_continue_connecting(coap_security_t *sec); @@ -100,15 +101,25 @@ const void *coap_security_handler_keyblock(const coap_security_t *sec); NS_DUMMY_DEFINITIONS_OK /* Dummy definitions, including needed error codes */ +#ifndef MBEDTLS_ERR_SSL_TIMEOUT #define MBEDTLS_ERR_SSL_TIMEOUT (-1) +#endif + +#ifndef MBEDTLS_ERR_SSL_WANT_READ #define MBEDTLS_ERR_SSL_WANT_READ (-2) +#endif + +#ifndef MBEDTLS_ERR_SSL_WANT_WRITE #define MBEDTLS_ERR_SSL_WANT_WRITE (-3) +#endif + +#ifndef MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE #define MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE (-4) +#endif #define coap_security_create(socket_id, timer_id, handle, \ mode, send_cb, receive_cb, start_timer_cb, timer_status_cb) ((coap_security_t *) 0) #define coap_security_destroy(sec) ((void) 0) -#define coap_security_handler_connect(sec, is_server, sock_mode, keys) (-1) #define coap_security_handler_connect_non_blocking(sec, is_server, sock_mode, keys, timeout_min, timeout_max) (-1) #define coap_security_handler_continue_connecting(sec) (-1) #define coap_security_handler_send_message(sec, message, len) (-1) diff --git a/test/coap-service/unittest/coap_connection_handler/test_coap_connection_handler.c b/test/coap-service/unittest/coap_connection_handler/test_coap_connection_handler.c index fb691ee41e..106c41c567 100644 --- a/test/coap-service/unittest/coap_connection_handler/test_coap_connection_handler.c +++ b/test/coap-service/unittest/coap_connection_handler/test_coap_connection_handler.c @@ -29,7 +29,7 @@ int get_passwd_cb(int8_t socket_id, uint8_t address, uint16_t port, uint8_t *pw_ return 0; } -void sec_done_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t keyblock[static 40]) +void sec_done_cb_test(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t keyblock[static 40]) { return 1; } @@ -161,7 +161,7 @@ bool test_coap_connection_handler_send_data() return false; socket_api_stub.int8_value = 7; - if( 7 != coap_connection_handler_send_data(handler, &addr, ns_in6addr_any, NULL, 0, true)) + if( 1 != coap_connection_handler_send_data(handler, &addr, ns_in6addr_any, NULL, 0, true)) return false; connection_handler_destroy(handler, false); @@ -212,7 +212,7 @@ bool test_coap_connection_handler_virtual_recv() connection_handler_destroy(handler, false); nsdynmemlib_stub.returnCounter = 1; - coap_conn_handler_t *handler2 = connection_handler_create(&receive_from_sock_cb, &send_to_sock_cb, &get_passwd_cb, &sec_done_cb); + coap_conn_handler_t *handler2 = connection_handler_create(&receive_from_sock_cb, &send_to_sock_cb, &get_passwd_cb, &sec_done_cb_test); nsdynmemlib_stub.returnCounter = 2; if( 0 != coap_connection_handler_open_connection(handler2, 24,false,true,true,false) ) return false; @@ -241,7 +241,7 @@ bool test_coap_connection_handler_virtual_recv() coap_security_handler_stub.sec_obj = NULL; nsdynmemlib_stub.returnCounter = 1; - coap_conn_handler_t *handler3 = connection_handler_create(&receive_from_sock_cb, &send_to_sock_cb, &get_passwd_cb, &sec_done_cb); + coap_conn_handler_t *handler3 = connection_handler_create(&receive_from_sock_cb, &send_to_sock_cb, &get_passwd_cb, &sec_done_cb_test); nsdynmemlib_stub.returnCounter = 2; if( 0 != coap_connection_handler_open_connection(handler3, 26,false,false,true,false) ) return false; @@ -367,7 +367,7 @@ bool test_socket_api_callbacks() connection_handler_destroy(handler, false); nsdynmemlib_stub.returnCounter = 1; - coap_conn_handler_t *handler2 = connection_handler_create(&receive_from_sock_cb, &send_to_sock_cb, &get_passwd_cb, &sec_done_cb); + coap_conn_handler_t *handler2 = connection_handler_create(&receive_from_sock_cb, &send_to_sock_cb, &get_passwd_cb, &sec_done_cb_test); nsdynmemlib_stub.returnCounter = 2; if( 0 != coap_connection_handler_open_connection(handler2, 22,false,true,true,false) ) return false; diff --git a/test/coap-service/unittest/coap_message_handler/test_coap_message_handler.c b/test/coap-service/unittest/coap_message_handler/test_coap_message_handler.c index a1b7ffd748..ac11c26aaa 100644 --- a/test/coap-service/unittest/coap_message_handler/test_coap_message_handler.c +++ b/test/coap-service/unittest/coap_message_handler/test_coap_message_handler.c @@ -119,6 +119,7 @@ bool test_coap_message_handler_coap_msg_process() { uint8_t buf[16]; memset(&buf, 1, 16); + /*Handler is null*/ if( -1 != coap_message_handler_coap_msg_process(NULL, 0, buf, 22, ns_in6addr_any, NULL, 0, NULL)) return false; @@ -128,12 +129,14 @@ bool test_coap_message_handler_coap_msg_process() coap_msg_handler_t *handle = coap_message_handler_init(&own_alloc, &own_free, &coap_tx_function); sn_coap_protocol_stub.expectedHeader = NULL; + /* Coap parse returns null */ if( -1 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) return false; sn_coap_protocol_stub.expectedHeader = (sn_coap_hdr_s *)malloc(sizeof(sn_coap_hdr_s)); memset(sn_coap_protocol_stub.expectedHeader, 0, sizeof(sn_coap_hdr_s)); sn_coap_protocol_stub.expectedHeader->coap_status = 66; + /* Coap library responds */ if( -1 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) return false; @@ -142,12 +145,17 @@ bool test_coap_message_handler_coap_msg_process() sn_coap_protocol_stub.expectedHeader->coap_status = COAP_STATUS_OK; sn_coap_protocol_stub.expectedHeader->msg_code = 1; retValue = 0; + /* request received */ if( 0 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) return false; + sn_coap_protocol_stub.expectedHeader = (sn_coap_hdr_s *)malloc(sizeof(sn_coap_hdr_s)); + memset(sn_coap_protocol_stub.expectedHeader, 0, sizeof(sn_coap_hdr_s)); + sn_coap_protocol_stub.expectedHeader->coap_status = COAP_STATUS_OK; + sn_coap_protocol_stub.expectedHeader->msg_code = 1; nsdynmemlib_stub.returnCounter = 1; retValue = -1; - if( -1 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) + if( 0 != coap_message_handler_coap_msg_process(handle, 0, buf, 22, ns_in6addr_any, NULL, 0, process_cb)) return false; sn_coap_protocol_stub.expectedHeader = (sn_coap_hdr_s *)malloc(sizeof(sn_coap_hdr_s)); @@ -310,7 +318,7 @@ bool test_coap_message_handler_response_send() if( 0 != coap_message_handler_response_send(handle, 2, 0, header, 1,3,NULL, 0)) return false; -// free(header); + free(header); free(sn_coap_protocol_stub.expectedCoap); sn_coap_protocol_stub.expectedCoap = NULL; coap_message_handler_destroy(handle); diff --git a/test/coap-service/unittest/coap_security_handler/test_coap_security_handler.c b/test/coap-service/unittest/coap_security_handler/test_coap_security_handler.c index 160d4dfac7..c48af7a229 100644 --- a/test/coap-service/unittest/coap_security_handler/test_coap_security_handler.c +++ b/test/coap-service/unittest/coap_security_handler/test_coap_security_handler.c @@ -80,8 +80,8 @@ bool test_coap_security_handler_connect() unsigned char pw = "pwd"; coap_security_keys_t keys; - keys._priv = &pw; - keys._priv_len = 3; + keys._key = &pw; + keys._key_len = 3; if( -1 != coap_security_handler_connect_non_blocking(NULL, true, DTLS, keys, 0, 1) ) return false; mbedtls_stub.useCounter = true; diff --git a/test/coap-service/unittest/coap_service_api/Makefile b/test/coap-service/unittest/coap_service_api/Makefile index cc8c0a3cce..00940f3154 100644 --- a/test/coap-service/unittest/coap_service_api/Makefile +++ b/test/coap-service/unittest/coap_service_api/Makefile @@ -22,5 +22,5 @@ TEST_SRC_FILES = \ include ../MakefileWorker.mk -CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT +CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT -I ../../../../source/ diff --git a/test/coap-service/unittest/coap_service_api/coap_service_apitest.cpp b/test/coap-service/unittest/coap_service_api/coap_service_apitest.cpp index 412ef3e6d7..73b0608113 100644 --- a/test/coap-service/unittest/coap_service_api/coap_service_apitest.cpp +++ b/test/coap-service/unittest/coap_service_api/coap_service_apitest.cpp @@ -75,3 +75,32 @@ TEST(coap_service_api, test_conn_handler_callbacks) CHECK(test_conn_handler_callbacks()); } +TEST(coap_service_api, test_certificate_set) +{ + CHECK(test_certificate_set()); +} + +TEST(coap_service_api, test_handshake_timeout_set) +{ + CHECK(test_handshake_timeout_set()); +} + +TEST(coap_service_api, test_coap_duplcate_msg_buffer_set) +{ + CHECK(test_coap_duplcate_msg_buffer_set()); +} + +TEST(coap_service_api, test_coap_service_get_internal_timer_ticks) +{ + CHECK(test_coap_service_get_internal_timer_ticks()) +} + +TEST(coap_service_api, test_coap_service_if_find_by_socket) +{ + CHECK(test_coap_service_if_find_by_socket()) +} + +TEST(coap_service_api, test_coap_service_handshake_limit_set) +{ + CHECK(test_coap_service_handshake_limit_set()) +} diff --git a/test/coap-service/unittest/coap_service_api/test_coap_service_api.c b/test/coap-service/unittest/coap_service_api/test_coap_service_api.c index 052d51693a..1f5e41d3d3 100644 --- a/test/coap-service/unittest/coap_service_api/test_coap_service_api.c +++ b/test/coap-service/unittest/coap_service_api/test_coap_service_api.c @@ -10,14 +10,15 @@ #include "eventOS_event_stub.h" #include "eventOS_event.h" #include "net_interface.h" +#include "coap_service_api.c" -int sec_done_cb(int8_t service_id, uint8_t address[static 16], uint8_t keyblock[static 40]){ +int sec_done_cb_test(int8_t service_id, uint8_t address[static 16], uint8_t keyblock[static 40]){ return 2; } int sec_start_cb(int8_t service_id, uint8_t address[static 16], uint16_t port, uint8_t* pw, uint8_t *pw_len) { - return 2; + return 0; } int request_recv_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *request_ptr) @@ -284,6 +285,7 @@ bool test_coap_callbacks() free( coap_message_handler_stub.coap_ptr ); coap_message_handler_stub.coap_ptr = NULL; + coap_service_handle = NULL; free( thread_conn_handler_stub.handler_obj ); thread_conn_handler_stub.handler_obj = NULL; @@ -322,7 +324,7 @@ bool test_conn_handler_callbacks() thread_conn_handler_stub.handler_obj = (coap_conn_handler_t*)malloc(sizeof(coap_conn_handler_t)); memset(thread_conn_handler_stub.handler_obj, 0, sizeof(coap_conn_handler_t)); nsdynmemlib_stub.returnCounter = 1; - if( 1 != coap_service_initialize(1, 2, COAP_SERVICE_OPTIONS_SECURE_BYPASS, &sec_start_cb, &sec_done_cb )) + if( 1 != coap_service_initialize(1, 2, COAP_SERVICE_OPTIONS_SECURE_BYPASS, &sec_start_cb, &sec_done_cb_test )) return false; if( thread_conn_handler_stub.send_to_sock_cb ){ @@ -389,11 +391,15 @@ bool test_conn_handler_callbacks() } if(thread_conn_handler_stub.get_passwd_cb){ + coap_security_keys_t security_ptr; + memset(&security_ptr, 0, sizeof(coap_security_keys_t)); + nsdynmemlib_stub.returnCounter = 1; thread_conn_handler_stub.bool_value = true; - if( 2 != thread_conn_handler_stub.get_passwd_cb(1, buf, 12, NULL, 0)) + if( 0 != thread_conn_handler_stub.get_passwd_cb(1, buf, 12, &security_ptr)) return false; + free(security_ptr._key); thread_conn_handler_stub.bool_value = false; - if( -1 != thread_conn_handler_stub.get_passwd_cb(1, buf, 12, NULL, 0)) + if( -1 != thread_conn_handler_stub.get_passwd_cb(1, buf, 12, NULL)) return false; } @@ -423,3 +429,150 @@ bool test_conn_handler_callbacks() return true; } + +bool test_certificate_set() +{ + /* Service not found, return failure */ + if (-1 != coap_service_certificate_set(1, NULL, 0, NULL, 0)) { + return false; + } + + /* Init service */ + thread_conn_handler_stub.handler_obj = (coap_conn_handler_t*)malloc(sizeof(coap_conn_handler_t)); + memset(thread_conn_handler_stub.handler_obj, 0, sizeof(coap_conn_handler_t)); + + nsdynmemlib_stub.returnCounter = 1; + if( 1 != coap_service_initialize(1, 2, 0, NULL, NULL )) + return false; + + /* Allocation fails */ + if (-1 != coap_service_certificate_set(1, NULL, 0, NULL, 0)) { + return false; + } + + /* All OK */ + nsdynmemlib_stub.returnCounter = 1; + if (0 != coap_service_certificate_set(1, NULL, 0, NULL, 0)) { + return false; + } + + /* Teardown */ + coap_service_delete(1); + free(thread_conn_handler_stub.handler_obj->security_keys); + free(thread_conn_handler_stub.handler_obj); + + return true; +} + +bool test_handshake_timeout_set() +{ + /* Service not found, return failure */ + if (-1 != coap_service_set_handshake_timeout(1, 0, 0)) { + return false; + } + + /* Init service */ + thread_conn_handler_stub.handler_obj = (coap_conn_handler_t*)malloc(sizeof(coap_conn_handler_t)); + memset(thread_conn_handler_stub.handler_obj, 0, sizeof(coap_conn_handler_t)); + + nsdynmemlib_stub.returnCounter = 1; + if( 1 != coap_service_initialize(1, 2, 0, NULL, NULL )) + return false; + + /* All OK */ + nsdynmemlib_stub.returnCounter = 1; + if (0 != coap_service_set_handshake_timeout(1, 0, 0)) { + return false; + } + + /* Teardown */ + coap_service_delete(1); + free(thread_conn_handler_stub.handler_obj->security_keys); + free(thread_conn_handler_stub.handler_obj); + + return true; +} + +bool test_coap_duplcate_msg_buffer_set() +{ + bool ret = true; + /* no coap handle - return failure */ + if (-1 != coap_service_set_duplicate_message_buffer(0, 0)) { + return false; + } + + /* Init service */ + thread_conn_handler_stub.handler_obj = (coap_conn_handler_t*)malloc(sizeof(coap_conn_handler_t)); + memset(thread_conn_handler_stub.handler_obj, 0, sizeof(coap_conn_handler_t)); + coap_message_handler_stub.coap_ptr = (coap_msg_handler_t *)malloc(sizeof(coap_msg_handler_t)); + memset(coap_message_handler_stub.coap_ptr, 0, sizeof(coap_msg_handler_t)); + + nsdynmemlib_stub.returnCounter = 1; + if( 1 != coap_service_initialize(1, 2, 0, NULL, NULL )) + ret = false; + + /* All OK */ + if(0 != coap_service_set_duplicate_message_buffer(0, 0)) { + ret = false; + } + + /* Teardown */ + coap_service_delete(1); + free(coap_message_handler_stub.coap_ptr); + coap_message_handler_stub.coap_ptr = NULL; + coap_service_handle = NULL; + free(thread_conn_handler_stub.handler_obj); + thread_conn_handler_stub.handler_obj = NULL; + + return ret; +} + +bool test_coap_service_get_internal_timer_ticks() +{ + coap_service_get_internal_timer_ticks(); + return true; +} + +bool test_coap_service_if_find_by_socket() +{ + /* No service ID - return failure */ + if (0 != coap_service_id_find_by_socket(1)) { + return false; + } + + /* Init service */ + thread_conn_handler_stub.handler_obj = (coap_conn_handler_t*)malloc(sizeof(coap_conn_handler_t)); + memset(thread_conn_handler_stub.handler_obj, 0, sizeof(coap_conn_handler_t)); + + nsdynmemlib_stub.returnCounter = 1; + thread_conn_handler_stub.bool_value = 0; + if( 1 != coap_service_initialize(1, 2, 0, NULL, NULL )) + return false; + + /* No matching service ID - return false */ + if(0 != coap_service_id_find_by_socket(1)) { + return false; + } + + thread_conn_handler_stub.bool_value = 1; + /* All OK */ + if(1 != coap_service_id_find_by_socket(1)) { + return false; + } + + /* Teardown */ + coap_service_delete(1); + free(thread_conn_handler_stub.handler_obj); + thread_conn_handler_stub.handler_obj = NULL; + + return true; +} + +bool test_coap_service_handshake_limit_set() +{ + if (0 != coap_service_handshake_limits_set(2, 2)) { + return false; + } + + return true; +} diff --git a/test/coap-service/unittest/coap_service_api/test_coap_service_api.h b/test/coap-service/unittest/coap_service_api/test_coap_service_api.h index 01600c4921..9b5e4883f1 100644 --- a/test/coap-service/unittest/coap_service_api/test_coap_service_api.h +++ b/test/coap-service/unittest/coap_service_api/test_coap_service_api.h @@ -48,6 +48,18 @@ bool test_eventOS_callbacks(); bool test_conn_handler_callbacks(); +bool test_certificate_set(); + +bool test_handshake_timeout_set(); + +bool test_coap_duplcate_msg_buffer_set(); + +bool test_coap_service_get_internal_timer_ticks(); + +bool test_coap_service_if_find_by_socket(); + +bool test_coap_service_handshake_limit_set(); + #ifdef __cplusplus } diff --git a/test/coap-service/unittest/stub/coap_connection_handler_stub.c b/test/coap-service/unittest/stub/coap_connection_handler_stub.c index 23e5e881dd..87a6b881ce 100644 --- a/test/coap-service/unittest/stub/coap_connection_handler_stub.c +++ b/test/coap-service/unittest/stub/coap_connection_handler_stub.c @@ -22,7 +22,7 @@ int coap_connection_handler_virtual_recv(coap_conn_handler_t *handler, uint8_t a coap_conn_handler_t *connection_handler_create(int (*recv_cb)(int8_t socket_id, uint8_t src_address[static 16], uint16_t port, const uint8_t dst_address[static 16], unsigned char *, int), int (*send_cb)(int8_t socket_id, uint8_t const address[static 16], uint16_t port, const void *, int), - int (*pw_cb)(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t *pw_ptr, uint8_t *pw_len), + int (*pw_cb)(int8_t socket_id, uint8_t address[static 16], uint16_t port, coap_security_keys_t *security_ptr), void(*done_cb)(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t keyblock[static KEY_BLOCK_LEN]) ) { thread_conn_handler_stub.send_to_sock_cb = send_cb; @@ -61,6 +61,11 @@ int8_t coap_connection_handler_set_timeout(coap_conn_handler_t *handler, uint32_ return 0; } +int8_t coap_connection_handler_handshake_limits_set(uint8_t handshakes_limit, uint8_t connections_limit) +{ + return 0; +} + void coap_connection_handler_exec(uint32_t time) { diff --git a/test/coap-service/unittest/stub/coap_connection_handler_stub.h b/test/coap-service/unittest/stub/coap_connection_handler_stub.h index f8b361bd62..a1f8929b8d 100644 --- a/test/coap-service/unittest/stub/coap_connection_handler_stub.h +++ b/test/coap-service/unittest/stub/coap_connection_handler_stub.h @@ -34,7 +34,7 @@ typedef struct { int (*send_to_sock_cb)(int8_t socket_id, uint8_t address[static 16], uint16_t port, const void *, int); int (*receive_from_sock_cb)(int8_t socket_id, uint8_t src_address[static 16], uint16_t port, const uint8_t dst_address[static 16], unsigned char *data, int len); - int (*get_passwd_cb)(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t *pw_ptr, uint8_t *pw_len); + int (*get_passwd_cb)(int8_t socket_id, uint8_t address[static 16], uint16_t port, coap_security_keys_t *security_ptr); void (*sec_done_cb)(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t keyblock[static 40]); } thread_conn_handler_stub_def; diff --git a/test/coap-service/unittest/stub/coap_message_handler_stub.c b/test/coap-service/unittest/stub/coap_message_handler_stub.c index 54d4759a60..dc92363719 100644 --- a/test/coap-service/unittest/stub/coap_message_handler_stub.c +++ b/test/coap-service/unittest/stub/coap_message_handler_stub.c @@ -70,3 +70,8 @@ int8_t coap_message_handler_exec(coap_msg_handler_t *handle, uint32_t current_ti return coap_message_handler_stub.int8_value; } +int8_t coap_message_handler_response_send_by_msg_id(coap_msg_handler_t *handle, int8_t service_id, uint8_t options, uint16_t msg_id, sn_coap_msg_code_e message_code, + sn_coap_content_format_e content_type, const uint8_t *payload_ptr,uint16_t payload_len) +{ + return coap_message_handler_stub.int8_value; +}