Squashed 'features/nanostack/FEATURE_NANOSTACK/coap-service/' changes from d65b6b0..b1c9efb

b1c9efb Fix coap_connection_handler_send_data() return values (#81)
f9cb04f Delete transaction when not needed (#80)
daf3694 Message transaction memory handling changes (#79)
adc04c4 Add API to send response to request based on Message ID (#78)
58f0ed5 Limit number of ongoing handshakes  (#77)
42c1169 Fix redefinition of mbed TLS error codes (#76)
ba7a7c4 Added server mode certificate conf (#74)
d108199 Certificate set API changed. (#73)
2d622e0 Support for certificate mode (#72)

git-subtree-dir: features/nanostack/FEATURE_NANOSTACK/coap-service
git-subtree-split: b1c9efb6a674f47f3a34e396bc0f57e8b1c27e19
pull/5511/head
Arto Kinnunen 2017-11-16 14:21:33 +02:00
parent 9d5a9f5a29
commit 1bc6ddc3e8
18 changed files with 658 additions and 295 deletions

View File

@ -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

View File

@ -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);
}
}
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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;
}

View File

@ -24,26 +24,31 @@
#include <stdbool.h>
#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

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -22,5 +22,5 @@ TEST_SRC_FILES = \
include ../MakefileWorker.mk
CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT
CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT -I ../../../../source/

View File

@ -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())
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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;
}