Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gcoap: add DTLS integration #12104

Closed
wants to merge 17 commits into from
Closed
8 changes: 8 additions & 0 deletions examples/gcoap/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ USEMODULE += gcoap
# Additional networking modules that can be dropped if not needed
USEMODULE += gnrc_icmpv6_echo

# DTLS configuration
# Choose which DTLS stack to use
# USEMODULE += tinydtls_sock_dtls
# CFLAGS += -DDTLS_PSK
# CFLAGS += -DDTLS_ECC
# Uncomment to enable debug logs when using DTLS
# CFLAGS += -DDTLS_DEBUG

# Required by gcoap example
USEMODULE += od
USEMODULE += fmt
Expand Down
56 changes: 56 additions & 0 deletions examples/gcoap/credentials.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2018 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup tests
* @{
*
* @file
* @brief tlsman test application (PSK and ECC keys)
cgundogan marked this conversation as resolved.
Show resolved Hide resolved
*
* Small test for TLSMAN. Many definitions defined here are also available at
* sock_secure (and are intended to be used in standard applications)
*
* @author Raul Fuentes <raul.fuentes-samaniego@inria.fr>
*
* @}
*/

#ifdef MODULE_SOCK_DTLS
#ifdef DTLS_PSK
const char psk_key[] = "secretPSK";
const char psk_id[] = "Client_identity";
const unsigned psk_key_len = sizeof(psk_key) - 1;
const unsigned psk_id_len = sizeof(psk_id) - 1;
#endif /* DTLS_PSK */

#ifdef DTLS_ECC
const unsigned char ecdsa_priv_key[] = {
0x41, 0xC1, 0xCB, 0x6B, 0x51, 0x24, 0x7A, 0x14,
0x43, 0x21, 0x43, 0x5B, 0x7A, 0x80, 0xE7, 0x14,
0x89, 0x6A, 0x33, 0xBB, 0xAD, 0x72, 0x94, 0xCA,
0x40, 0x14, 0x55, 0xA1, 0x94, 0xA9, 0x49, 0xFA
};

const unsigned char ecdsa_pub_key_x[] = {
0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52
};

const unsigned char ecdsa_pub_key_y[] = {
0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29
};
#endif /* DTLS_ECC */
#endif /* MODULE_SOCK_DTLS */

typedef int unused_workaround;
63 changes: 63 additions & 0 deletions examples/gcoap/gcoap_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@
#include "net/gcoap.h"
#include "od.h"
#include "fmt.h"
#ifdef MODULE_SOCK_DTLS
#include "net/credman.h"

#define SOCK_DTLS_GCOAP_TAG (10)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you choose 10 for this value? Why not 1 or 5?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be any unsigned values. No reason specifically why 10 is chosen here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More importantly, why define this value here? If it was defined in gcoap.c or gcoap.h, you would not need gcoap_set_credential_tag(), right? Is there any value to defining it in the application? Would gcoap ever need more than one credential? Do we need a distinction between a gcoap server credential and a client credential?

Copy link
Member

@kb2ma kb2ma Dec 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following this line of thinking, why not move all of the code from this PR in gcoap_cli.c into gcoap itself? gcoap provides CoAP as a service, so why should every application need to add this code? With this approach the application/user only needs to provide credentials.c.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More importantly, why define this value here? If it was defined in gcoap.c or gcoap.h, you would not need gcoap_set_credential_tag(), right? Is there any value to defining it in the application?

Yup, you're right. The credential tag is defined in the client to avoid reserving values for the tag used in gcoap. Other modules (e.g. LWM2M) might also hard-code the tag used for the DTLS sock and then there will be a need to track the available tag somewhere to avoid collisions.

Would gcoap ever need more than one credential?

Yes. gcoap might be talking to other secure coap clients/servers that use different credentials.

Do we need a distinction between a gcoap server credential and a client credential?

No.

Following this line of thinking, why not move all of the code from this PR in gcoap_cli.c into gcoap itself? gcoap provides CoAP as a service, so why should every application need to add this code? With this approach, the application/user only needs to provide credentials.c.

The credentials are added in gcoap_cli.c because we do not want to make any assumption or limit what the name of the variables used for the credentials should be.

In general, the design of coupling DTLS sock with credman is to avoid limiting what the name of the credentials should be or where it can be found. This is left to the user to define.


#ifdef DTLS_PSK
extern const char psk_key[];
extern const char psk_id[];
extern const unsigned psk_key_len;
extern const unsigned psk_id_len;
#else /* DTLS_PSK */
extern const unsigned char ecdsa_priv_key[];
extern const unsigned char ecdsa_pub_key_x[];
extern const unsigned char ecdsa_pub_key_y[];
#endif /* DTLS_ECC */
#endif /* MODULE_SOCK_DTLS */

#define ENABLE_DEBUG (0)
#include "debug.h"
Expand Down Expand Up @@ -283,6 +299,9 @@ int gcoap_cli_cmd(int argc, char **argv)
uint8_t open_reqs = gcoap_op_state();

printf("CoAP server is listening on port %u\n", GCOAP_PORT);
#ifdef MODULE_SOCK_DTLS
printf("Connection secured with DTLS\n");
#endif
printf(" CLI requests sent: %u\n", req_count);
printf("CoAP open requests: %u\n", open_reqs);
return 0;
Expand Down Expand Up @@ -380,5 +399,49 @@ int gcoap_cli_cmd(int argc, char **argv)

void gcoap_cli_init(void)
{
#ifdef MODULE_SOCK_DTLS
#ifdef DTLS_PSK
credman_credential_t credential = {
.type = CREDMAN_TYPE_PSK,
.tag = SOCK_DTLS_GCOAP_TAG,
.params = {
.psk = {
.key = { .s = (char *)psk_key, .len = psk_key_len },
.id = { .s = (char *)psk_id, .len = psk_id_len },
},
},
};
#else
ecdsa_public_key_t other_pubkeys[] = {
{ .x = ecdsa_pub_key_x, .y = ecdsa_pub_key_y },
};

credman_credential_t credential = {
.type = CREDMAN_TYPE_ECDSA,
.tag = SOCK_DTLS_GCOAP_TAG,
.params = {
.ecdsa = {
.private_key = ecdsa_priv_key,
.public_key = {
.x = ecdsa_pub_key_x,
.y = ecdsa_pub_key_y,
},
.client_keys = other_pubkeys,
.client_keys_size = ARRAY_SIZE(other_pubkeys),
}
},
};
#endif /* DTLS_ECC */
if (credman_add(&credential) < 0) {
puts("gcoap_cli: unable to add credential");
return;
}

/* tell gcoap with tag to use */
gcoap_set_credential_tag(SOCK_DTLS_GCOAP_TAG);
/* start gcoap server */
gcoap_init();
#endif

gcoap_register_listener(&_listener);
}
6 changes: 6 additions & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,10 @@ ifneq (,$(filter prng_fortuna,$(USEMODULE)))
CFLAGS += -DCRYPTO_AES
endif

ifneq (,$(filter gcoap,$(USEMODULE)))
ifneq (,$(filter sock_dtls,$(USEMODULE)))
CFLAGS += -DGCOAP_NO_AUTO_INIT
endif
endif

include $(RIOTBASE)/sys/test_utils/Makefile.dep
60 changes: 57 additions & 3 deletions sys/include/net/gcoap.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* - Client Operation
* - Observe Server Operation
* - Block Operation
* - Secure CoAP with DTLS
* - Implementation Notes
* - Implementation Status
*
Expand Down Expand Up @@ -305,6 +306,26 @@
* - Finally, use coap_block1_finish() to finalize the block option with the
* proper value for the _more_ parameter.
*
* ## Secure CoAP with DTLS
*
* gcoap supports securing CoAP packets with [DTLS](@ref net_sock_dtls).
* To enable this feature, add the following line in the Makefile:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {Makefile}
* USEMODULE += tinydtls_sock_dtls
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* After that, add credential to use using @ref credman_add(), tell
* gcoap which credential tag to use with gcoap_set_credential_tag(). **After**
* setting up the credentials, we need to start the gcoap server manually by
* calling gcoap_init().
*
* Sending and receiving CoAP packets with DTLS is the same as using plain CoAP.
* gcoap will automatically encrypt/decrypt CoAP packets with DTLS before
* sending/receiving them over the network.
*
* To read more on DTLS support in RIOT, refer @ref net_dtls and @ref net_sock_dtls.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth specifically mentioning configuration parameters here. I got hung up for a while on the default value of 1 for tinydtls DTLS_PEER_MAX.

*
* ## Implementation Notes ##
*
* ### Waiting for a response ###
Expand Down Expand Up @@ -350,6 +371,10 @@
#include "net/ipv6/addr.h"
#include "net/sock/udp.h"
#include "net/nanocoap.h"
#ifdef MODULE_SOCK_DTLS
#include "net/sock/dtls.h"
#include "net/credman.h"
#endif
#include "xtimer.h"

#ifdef __cplusplus
Expand All @@ -373,15 +398,23 @@ extern "C" {
* @brief Server port; use RFC 7252 default if not defined
*/
#ifndef GCOAP_PORT
#ifdef MODULE_SOCK_DTLS
#define GCOAP_PORT (5684)
#else
#define GCOAP_PORT (5683)
#endif
#endif /* MODULE_SOCK_DTLS */
#endif /* GCOAP_PORT */

/**
* @brief Size of the buffer used to build a CoAP request or response
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expected to see a comment similar to what was in Makefile.dep. The additional 128 bytes deserves some explanation so the user can change it if that is reasonable.

Payload size might be bigger when using DTLS with ECC, causing errors not present
when using plain CoAP

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rephrased and added the comment in dfdbb86

*/
#ifndef GCOAP_PDU_BUF_SIZE
#ifdef MODULE_SOCK_DTLS
#define GCOAP_PDU_BUF_SIZE (256)
#else
#define GCOAP_PDU_BUF_SIZE (128)
#endif
#endif /* MODULE_SOCK_DTLS */
#endif /* GCOAP_PDU_BUF_SIZE */

/**
* @brief Reduce payload length by this value for a request
Expand Down Expand Up @@ -590,9 +623,16 @@ extern "C" {
* @brief Stack size for module thread
*/
#ifndef GCOAP_STACK_SIZE
#ifdef MODULE_SOCK_DTLS
/* DTLS pkg will need at least (THREAD_STACKSIZE_DEFAULT + 1024) stack size */
#define GCOAP_STACK_SIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE \
+ sizeof(coap_pkt_t) \
+ 1024)
#else
#define GCOAP_STACK_SIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE \
+ sizeof(coap_pkt_t))
#endif
#endif /* MODULE_SOCK_DTLS */
#endif /* GCOAP_STACK_SIZE */

/**
* @ingroup net_gcoap_conf
Expand Down Expand Up @@ -944,6 +984,20 @@ ssize_t gcoap_encode_link(const coap_resource_t *resource, char *buf,
*/
int gcoap_add_qstring(coap_pkt_t *pdu, const char *key, const char *val);

#if defined(MODULE_SOCK_DTLS) || defined(DOXYGEN)
/**
* @brief Set credential tag to use
*
* Set the DTLS credential tag. This will tell gcoap which credential
* to use for authentication.
*
* @param[in] tag The credential tag to use
*
* @see @ref net_credman
*/
void gcoap_set_credential_tag(credman_tag_t tag);
#endif

#ifdef __cplusplus
}
#endif
Expand Down
Loading