Skip to content

Commit 2d622e0

Browse files
author
Tero Heinonen
authored
Support for certificate mode (ARMmbed#72)
* Support for certificate mode Added API for setting certificates for client mode. * coap-service unit test updates New unit tests for coap service API functions
1 parent d65b6b0 commit 2d622e0

14 files changed

+367
-187
lines changed

Diff for: coap-service/coap_service_api.h

+19
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,25 @@ extern int8_t coap_service_set_handshake_timeout(int8_t service_id, uint32_t min
309309
*- 0 For success
310310
*/
311311
extern int8_t coap_service_set_duplicate_message_buffer(int8_t service_id, uint8_t size);
312+
313+
/**
314+
* \brief Set DTLS certificates
315+
*
316+
* Set DTLS certificates.
317+
*
318+
* \param service_id Id number of the current service.
319+
* \param root_cert Pointer to CA certificate
320+
* \param root_cert_len CA certificate length
321+
* \param own_cert pointer to own certificate
322+
* \param own_cert_len length of own certificate
323+
* \param priv_key pointer to private key
324+
* \param priv_key_len length of private key
325+
*
326+
* \return -1 For failure
327+
*- 0 For success
328+
*/
329+
330+
extern int8_t coap_service_certificate_set(int8_t service_id, const unsigned char *root_cert, uint16_t root_cert_len, const unsigned char *own_cert, uint16_t own_cert_len, const unsigned char *priv_key, uint8_t priv_key_len);
312331
#ifdef __cplusplus
313332
}
314333
#endif

Diff for: source/coap_connection_handler.c

+61-66
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ static int8_t virtual_socket_id_allocate()
141141
return new_virtual_socket_id;
142142
}
143143

144-
static secure_session_t *secure_session_create(internal_socket_t *parent, const uint8_t *address_ptr, uint16_t port)
144+
static secure_session_t *secure_session_create(internal_socket_t *parent, const uint8_t *address_ptr, uint16_t port, SecureConnectionMode secure_mode)
145145
{
146146
if(!address_ptr){
147147
return NULL;
@@ -184,7 +184,7 @@ static secure_session_t *secure_session_create(internal_socket_t *parent, const
184184
memcpy(this->remote_host.address, address_ptr, 16);
185185
this->remote_host.identifier = port;
186186

187-
this->sec_handler = coap_security_create(parent->socket, this->timer.id, this, ECJPAKE,
187+
this->sec_handler = coap_security_create(parent->socket, this->timer.id, this, secure_mode,
188188
&secure_session_sendto, &secure_session_recvfrom, &start_timer, &timer_status);
189189
if( !this->sec_handler ){
190190
ns_dyn_mem_free(this);
@@ -595,31 +595,34 @@ static void secure_recv_sckt_msg(void *cb_res)
595595

596596
// Create session
597597
if (!session) {
598-
session = secure_session_create(sock, src_address.address, src_address.identifier);
599-
}
600-
if (!session) {
601-
tr_err("secure_recv_sckt_msg session creation failed - OOM");
602-
return;
603-
}
604-
// Record the destination. We are not strict on local address - all
605-
// session_find calls match only on remote address and port. But we
606-
// record the last-used destination address to use it as the source of
607-
// outgoing packets.
608-
memcpy(session->local_address, dst_address, 16);
609-
session->last_contact_time = coap_service_get_internal_timer_ticks();
610-
// Start handshake
611-
if (!coap_security_handler_is_started(session->sec_handler) ){
612-
uint8_t *pw = ns_dyn_mem_alloc(64);
613-
uint8_t pw_len;
614-
if( sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->socket, src_address.address, src_address.identifier, pw, &pw_len)){
615-
//TODO: get_password_cb should support certs and PSK also
616-
coap_security_keys_t keys;
617-
keys._priv = pw;
618-
keys._priv_len = pw_len;
619-
coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, sock->timeout_min, sock->timeout_max);
598+
coap_security_keys_t keys;
599+
memset(&keys, 0, sizeof(coap_security_keys_t));
600+
601+
if (sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->socket, src_address.address, src_address.identifier, &keys)) {
602+
session = secure_session_create(sock, src_address.address, src_address.identifier, keys.mode);
603+
if (!session) {
604+
tr_err("secure_recv_sckt_msg session creation failed - OOM");
605+
ns_dyn_mem_free(keys._key);
606+
return;
607+
}
620608
//TODO: error handling
609+
} else {
610+
return;
611+
}
612+
613+
// Record the destination. We are not strict on local address - all
614+
// session_find calls match only on remote address and port. But we
615+
// record the last-used destination address to use it as the source of
616+
// outgoing packets.
617+
memcpy(session->local_address, dst_address, 16);
618+
619+
session->last_contact_time = coap_service_get_internal_timer_ticks();
620+
// Start handshake
621+
if (!coap_security_handler_is_started(session->sec_handler)) {
622+
coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, sock->timeout_min, sock->timeout_max);
623+
ns_dyn_mem_free(keys._key);
624+
621625
}
622-
ns_dyn_mem_free(pw);
623626
} else {
624627
//Continue handshake
625628
if (session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING) {
@@ -703,34 +706,29 @@ int coap_connection_handler_virtual_recv(coap_conn_handler_t *handler, uint8_t a
703706
}
704707

705708
if (handler->socket->is_secure) {
709+
coap_security_keys_t keys;
710+
memset(&keys, 0, sizeof(coap_security_keys_t));
711+
706712
secure_session_t *session = secure_session_find(sock, address, port);
707713
if (!session) {
708-
session = secure_session_create(sock, address, port);
709-
}
710-
if (!session) {
711-
tr_err("coap_connection_handler_virtual_recv session creation failed - OOM");
712-
return -1;
713-
}
714-
715-
session->last_contact_time = coap_service_get_internal_timer_ticks();
716-
717-
if (!coap_security_handler_is_started(session->sec_handler)) {
718-
uint8_t *pw = ns_dyn_mem_alloc(64);
719-
uint8_t pw_len;
720-
if (sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->socket, address, port, pw, &pw_len)) {
721-
//TODO: get_password_cb should support certs and PSK also
722-
coap_security_keys_t keys;
723-
keys._priv = pw;
724-
keys._priv_len = pw_len;
714+
if (sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->socket, address, port, &keys)) {
715+
session = secure_session_create(sock, address, port, keys.mode);
716+
if (!session) {
717+
tr_err("coap_connection_handler_virtual_recv session creation failed - OOM");
718+
ns_dyn_mem_free(keys._key);
719+
return -1;
720+
}
725721
coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max);
726-
//TODO: error handling
727-
ns_dyn_mem_free(pw);
722+
ns_dyn_mem_free(keys._key);
728723
return 0;
729724
} else {
730-
ns_dyn_mem_free(pw);
731725
return -1;
732726
}
733-
} else {
727+
}
728+
729+
session->last_contact_time = coap_service_get_internal_timer_ticks();
730+
731+
if (coap_security_handler_is_started(session->sec_handler)) {
734732
if (session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING) {
735733
int ret = coap_security_handler_continue_connecting(session->sec_handler);
736734
if(ret == 0){
@@ -813,6 +811,9 @@ void connection_handler_destroy(coap_conn_handler_t *handler, bool multicast_gro
813811
if (multicast_group_leave) {
814812
coap_multicast_group_join_or_leave(handler->socket->socket, SOCKET_IPV6_LEAVE_GROUP, handler->socket_interface_selection);
815813
}
814+
if (handler->security_keys) {
815+
ns_dyn_mem_free(handler->security_keys);
816+
}
816817
int_socket_delete(handler->socket);
817818
ns_dyn_mem_free(handler);
818819
}
@@ -873,30 +874,24 @@ int coap_connection_handler_send_data(coap_conn_handler_t *handler, const ns_add
873874
handler->socket->bypass_link_sec = bypass_link_sec;
874875
secure_session_t *session = secure_session_find(handler->socket, dest_addr->address, dest_addr->identifier);
875876
if (!session) {
876-
session = secure_session_create(handler->socket, dest_addr->address, dest_addr->identifier);
877-
if (!session) {
878-
return -1;
879-
}
880-
session->last_contact_time = coap_service_get_internal_timer_ticks();
881-
uint8_t *pw = ns_dyn_mem_alloc(64);
882-
if (!pw) {
883-
//todo: free secure session?
877+
coap_security_keys_t security_material;
878+
memset(&security_material, 0, sizeof(coap_security_keys_t));
879+
880+
if (!handler->_get_password_cb || 0 != handler->_get_password_cb(handler->socket->socket, (uint8_t*)dest_addr->address, dest_addr->identifier, &security_material)) {
884881
return -1;
885882
}
886-
uint8_t pw_len;
887-
if (handler->_get_password_cb && 0 == handler->_get_password_cb(handler->socket->socket, (uint8_t*)dest_addr->address, dest_addr->identifier, pw, &pw_len)) {
888-
//TODO: get_password_cb should support certs and PSK also
889-
coap_security_keys_t keys;
890-
keys._priv = pw;
891-
keys._priv_len = pw_len;
892-
coap_security_handler_connect_non_blocking(session->sec_handler, false, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max);
893-
ns_dyn_mem_free(pw);
894-
return -2;
895-
} else {
896-
//free secure session?
897-
ns_dyn_mem_free(pw);
883+
884+
session = secure_session_create(handler->socket, dest_addr->address, dest_addr->identifier, security_material.mode);
885+
if (!session) {
886+
ns_dyn_mem_free(security_material._key);
898887
return -1;
899888
}
889+
session->last_contact_time = coap_service_get_internal_timer_ticks();
890+
891+
coap_security_handler_connect_non_blocking(session->sec_handler, false, DTLS, security_material, handler->socket->timeout_min, handler->socket->timeout_max);
892+
ns_dyn_mem_free(security_material._key);
893+
return -2;
894+
900895
} else if (session->session_state == SECURE_SESSION_OK) {
901896
if (coap_security_handler_send_message(session->sec_handler, data_ptr, data_len ) > 0 ) {
902897
session->last_contact_time = coap_service_get_internal_timer_ticks();

Diff for: source/coap_security_handler.c

+21-91
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ static const int PSK_SUITES[] = {
6969
0
7070
};
7171

72+
#define TRACE_GROUP "CsSh"
7273

7374
static void set_timer( void *sec_obj, uint32_t int_ms, uint32_t fin_ms );
7475
static int get_timer( void *sec_obj );
75-
static int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_keys_t keys );
7676

7777
int entropy_poll( void *data, unsigned char *output, size_t len, size_t *olen );
7878

@@ -276,26 +276,30 @@ static int export_key_block(void *ctx,
276276
}
277277
#endif
278278

279-
int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_keys_t keys )
279+
static int coap_security_handler_configure_keys (coap_security_t *sec, coap_security_keys_t keys, bool is_server)
280280
{
281281
int ret = -1;
282282
switch( sec->_conn_mode ){
283-
case Certificate:{
283+
case CERTIFICATE:{
284284
#if defined(MBEDTLS_X509_CRT_PARSE_C)
285-
if( mbedtls_x509_crt_parse( &sec->_cacert, keys._server_cert,
286-
keys._server_cert_len ) < 0 ){
285+
if( mbedtls_x509_crt_parse( &sec->_cacert, keys._ca_cert,
286+
keys._ca_cert_len ) < 0 ){
287287
break;
288288
}
289-
if( mbedtls_x509_crt_parse( &sec->_owncert, keys._pub_cert_or_identifier,
290-
keys._pub_len ) < 0 ){
289+
if( mbedtls_x509_crt_parse( &sec->_owncert, keys._own_cert,
290+
keys._own_cert_len ) < 0 ){
291291
break;
292292
}
293-
if( mbedtls_pk_parse_key(&sec->_pkey, keys._priv, keys._priv_len, NULL, 0) < 0){
293+
if( mbedtls_pk_parse_key(&sec->_pkey, keys._priv_key, keys._priv_key_len, NULL, 0) < 0){
294294
break;
295295
}
296-
//TODO: If needed in server mode, this won't work
297-
if( 0 != mbedtls_ssl_conf_own_cert(&sec->_conf, &sec->_owncert, &sec->_pkey) ){
298-
break;
296+
297+
if (!is_server) {
298+
if (0 != mbedtls_ssl_conf_own_cert(&sec->_conf, &sec->_owncert, &sec->_pkey)) {
299+
break;
300+
}
301+
} else {
302+
//TODO: add server certi
299303
}
300304
//TODO: use MBEDTLS_SSL_VERIFY_REQUIRED instead of optional
301305
mbedtls_ssl_conf_authmode( &sec->_conf, MBEDTLS_SSL_VERIFY_OPTIONAL );
@@ -306,7 +310,7 @@ int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_ke
306310
}
307311
case PSK: {
308312
#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
309-
if( 0 != mbedtls_ssl_conf_psk(&sec->_conf, keys._priv, keys._priv_len, keys._pub_cert_or_identifier, keys._pub_len) ){
313+
if( 0 != mbedtls_ssl_conf_psk(&sec->_conf, keys._priv_key, keys._priv_key_len, keys._own_cert, keys._own_cert_len) ){
310314
break;
311315
}
312316
mbedtls_ssl_conf_ciphersuites(&sec->_conf, PSK_SUITES);
@@ -316,7 +320,7 @@ int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_ke
316320
}
317321
case ECJPAKE: {
318322
#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
319-
if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._priv, keys._priv_len) != 0 ){
323+
if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._key, keys._key_len) != 0 ){
320324
return -1;
321325
}
322326
mbedtls_ssl_conf_ciphersuites(&sec->_conf, ECJPAKE_SUITES);
@@ -336,79 +340,6 @@ int coap_security_handler_configure_keys( coap_security_t *sec, coap_security_ke
336340
return ret;
337341
}
338342

339-
int coap_security_handler_connect(coap_security_t *sec, bool is_server, SecureSocketMode sock_mode, coap_security_keys_t keys){
340-
int ret = -1;
341-
342-
if( !sec ){
343-
return ret;
344-
}
345-
sec->_is_blocking = true;
346-
347-
int endpoint = MBEDTLS_SSL_IS_CLIENT;
348-
if( is_server ){
349-
endpoint = MBEDTLS_SSL_IS_SERVER;
350-
}
351-
352-
int mode = MBEDTLS_SSL_TRANSPORT_DATAGRAM;
353-
if( sock_mode == TLS ){
354-
mode = MBEDTLS_SSL_TRANSPORT_STREAM;
355-
}
356-
357-
if( ( mbedtls_ssl_config_defaults( &sec->_conf,
358-
endpoint,
359-
mode, 0 ) ) != 0 )
360-
{
361-
return -1;
362-
}
363-
364-
mbedtls_ssl_set_bio( &sec->_ssl, sec,
365-
f_send, f_recv, NULL );
366-
367-
mbedtls_ssl_set_timer_cb( &sec->_ssl, sec, set_timer,
368-
get_timer );
369-
370-
if( coap_security_handler_configure_keys( sec, keys ) != 0 ){
371-
return -1;
372-
}
373-
374-
#ifdef MBEDTLS_SSL_SRV_C
375-
mbedtls_ssl_conf_dtls_cookies(&sec->_conf, simple_cookie_write,
376-
simple_cookie_check,
377-
&sec->_cookie);
378-
#endif
379-
380-
sec->_is_started = true;
381-
382-
do {
383-
ret = mbedtls_ssl_handshake_step( &sec->_ssl );
384-
if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ){ //cookie check failed
385-
if( is_server ){
386-
mbedtls_ssl_session_reset(&sec->_ssl);
387-
#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
388-
if( mbedtls_ssl_set_hs_ecjpake_password(&sec->_ssl, keys._priv, keys._priv_len) != 0 ){
389-
return -1;
390-
}
391-
#endif
392-
ret = MBEDTLS_ERR_SSL_WANT_READ; //needed to keep doing
393-
}else{
394-
ret = -1;
395-
}
396-
}
397-
}while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
398-
ret == MBEDTLS_ERR_SSL_WANT_WRITE );
399-
400-
if( ret != 0){
401-
ret = -1;
402-
}else{
403-
if( mbedtls_ssl_get_verify_result( &sec->_ssl ) != 0 )
404-
{
405-
ret = -1;
406-
}
407-
}
408-
409-
return ret;
410-
}
411-
412343
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)
413344
{
414345

@@ -457,13 +388,13 @@ int coap_security_handler_connect_non_blocking(coap_security_t *sec, bool is_ser
457388
#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
458389
//TODO: Figure out better way!!!
459390
//Password should never be stored in multiple places!!!
460-
if( is_server && keys._priv_len > 0){
461-
memcpy(sec->_pw, keys._priv, keys._priv_len);
462-
sec->_pw_len = keys._priv_len;
391+
if ((sec->_conn_mode == ECJPAKE) && is_server && keys._key_len > 0){
392+
memcpy(sec->_pw, keys._key, keys._key_len);
393+
sec->_pw_len = keys._key_len;
463394
}
464395
#endif
465396

466-
if( coap_security_handler_configure_keys( sec, keys ) != 0 ){
397+
if (coap_security_handler_configure_keys(sec, keys, is_server) != 0) {
467398
return -1;
468399
}
469400

@@ -499,7 +430,6 @@ int coap_security_handler_continue_connecting(coap_security_t *sec){
499430

500431
while( ret != MBEDTLS_ERR_SSL_WANT_READ ){
501432
ret = mbedtls_ssl_handshake_step( &sec->_ssl );
502-
503433
if( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED == ret){
504434
mbedtls_ssl_session_reset(&sec->_ssl);
505435
#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)

0 commit comments

Comments
 (0)