COAP_CONTEXT(3)

NAME
coap_context, coap_new_context, coap_free_context, coap_context_set_pki, coap_context_set_psk, coap_new_endpoint, coap_new_client_session, coap_new_client_session_pki, coap_new_client_session_psk - work with CoAP contexts

SYNOPSIS
#include <coap/coap.h> coap_context_t *coap_new_context(const coap_address_t *listen_addr); void coap_free_context(coap_context_t *context); int coap_context_set_pki(coap_context_t *context, coap_dtls_pki_t *setup_data); int coap_context_set_psk(coap_context_t *context, const char *hint, const uint8_t *key, size_t key_len); coap_endpoint_t *coap_new_endpoint(coap_context_t *context, const coap_address_t *listen_addr, coap_proto_t proto); void coap_free_endpoint(coap_endpoint_t *endpoint); void coap_endpoint_set_default_mtu(coap_endpoint_t *endpoint, unsigned mtu); const char *coap_endpoint_str(const coap_endpoint_t *endpoint); coap_session_t *coap_new_client_session(coap_context_t *context, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto); coap_session_t *coap_new_client_session_psk(coap_context_t *context, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, const char *identity, const uint8_t *key, unsigned key_len); coap_session_t *coap_new_client_session_pki(coap_context_t *context, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_pki_t *setup_data); coap_session_t *coap_session_reference(coap_session_t *session); void coap_session_release(coap_session_t *session); void coap_session_set_mtu(coap_session_t *session, unsigned mtu); Link with -lcoap-2, -lcoap-2-openssl or -lcoap-2-tinydtls depending on your (D)TLS library type.

DESCRIPTION
The CoAP stack&#8217;s global state is stored in a coap_context_t Context object. Resources, Endpoints and Sessions are associated with this context object. There can be more than one coap_context_t object per application, it is up to the application to manage each one accordingly. Network traffic can be encrypted or un-encrypted. If TLS is going to be used for encrypting the network traffic, then the TLS information for Pre-Shared Keys (PSK) or Public Key Infrastructure (PKI) needs to be configured before any network traffic starts to flow. For Servers, this has to be done before the Endpoint is created, for Clients, this is done during the Client Session set up. For Servers, all the encryption information is held internally by the TLS Context level and the CoAP Context level as the Server is listening for new incoming traffic. The TLS and CoAP session will not get built until the new traffic starts, which is done by the libcoap library, with the session having a reference count of 1. For Clients, all the encryption information can be held at the TLS Context and CoAP Context levels, or at the TLS Session and CoAP Session levels. If defined at the Context level, then when Sessions are created, they will inherit the Context definitions, unless they have separately been defined for the Session level, in which case the Session version will get used. Typically the information will be at the Session level for Clients. In principle the set-up sequence for CoAP Servers looks like

    coap_new_context() coap_context_set_psk() and/or coap_context_set_pki() if encryption is required coap_new_endpoint() NOTE: coap_context_set_psk() should be called before coap_context_set_pki() to make sure that the PSK ciphers are in place for the first PSK incoming connection if both PSK and PKI are to be hosted. Multiple endpoints can be set up per Context, each listening for a new traffic flow with different TCP/UDP protocols, TLS protocols, port numbers etc. When a new traffic flow is started, then the CoAP library will create and start a new server session. In principle the set-up sequence for CoAP Clients looks like

    coap_new_context() coap_new_client_session(), coap_new_client_session_pki() or coap_new_client_session_psk() Multiple client sessions are supported per Context. Due to the nature of TLS, there can be Callbacks that are invoked as the TLS session negotiates encryption algorithms, encryption keys etc. Where possible, by default, the CoAP layer handles all this automatically. However, there is the flexibility of the Callbacks for imposing additional security checks etc. when PKI is being used. These Callbacks will be different (different structures etc.) depending on the TLS implementation type. See coap_tls_library(3) for more information. To determine the TLS implementation type to use within the Callback, use the function coap_get_tls_library_version(). The coap_new_context() function creates a new Context that is then used to keep all the CoAP Resources, Endpoints and Sessions information. The optional listen_addr parameter, if set for a CoAP server, creates an Endpoint that is added to the context that is listening for un-encrypted traffic on the IP address and port number defined by listen_addr. The coap_free_context() function must be used to release the CoAP stack context. It clears all entries from the receive queue and send queue and deletes the Resources that have been registered with context, and frees the attached Sessions and Endpoints. The coap_context_set_pki() function, for a specific context, is used to configure the TLS context using the setup_data variables as defined in the coap_dtls_pki_t structure below which includes an optional callback function call_back which will get called from within this function. coap_context_set_pki() will always add public_cert and private_key from one of the 2 alternatives provided in setup_data, Alternative 1 taking precedence, to the TLS Context. Any CA file updates have to be done in the call_back function defined in setup_data, which can be used as well to set up additional callbacks (e.g. for determining whether incoming connection is PSK or PKI). Set call_back in setup_data to NULL if this callback is not required. This function can be used for both Clients and Servers.
    typedef struct coap_dtls_pki_t {
      /* Optional CallBack for additional setup */
      coap_dtls_security_setup_t call_back;
      /* Alternative 1: Name of file on disk */
      const char *ca_file;
      const char *public_cert;
      const char *private_key;
      /* Alternative 2: ASN1 version */
      const uint8_t *asn1_ca_file;
      const uint8_t *asn1_public_cert;
      const uint8_t *asn1_private_key;
      int asn1_ca_file_len;
      int asn1_public_cert_len;
      int asn1_private_key_len;
      coap_asn1_privatekey_type_t asn1_private_key_type;
    } coap_dtls_pki_t;
    typedef enum coap_asn1_privatekey_type_t {
      COAP_ASN1_PKEY_NONE,
      COAP_ASN1_PKEY_RSA,
      COAP_ASN1_PKEY_RSA2,
      COAP_ASN1_PKEY_DSA,
      COAP_ASN1_PKEY_DSA1,
      COAP_ASN1_PKEY_DSA2,
      COAP_ASN1_PKEY_DSA3,
      COAP_ASN1_PKEY_DSA4,
      COAP_ASN1_PKEY_DH,
      COAP_ASN1_PKEY_DHX,
      COAP_ASN1_PKEY_EC,
      COAP_ASN1_PKEY_HMAC,
      COAP_ASN1_PKEY_CMAC,
      COAP_ASN1_PKEY_TLS1_PRF,
      COAP_ASN1_PKEY_HKDF
    } coap_asn1_privatekey_type_t;
    The coap_context_set_psk() function is used to configure the TLS context using the server hint, PreShared Key key with length key_len. All parameters must be defined, NULL is not valid. An empty string is valid for hint. key_len must be greater than 0. This function can only be used for Servers as it provides a hint, not an identity. The coap_new_endpoint() function creates a new endpoint for context that is listening for new traffic on the IP address and port number defined by listen_addr. Different CoAP protocols can be defined for proto - the current supported list is:
    COAP_PROTO_UDP
    COAP_PROTO_DTLS
    COAP_PROTO_TCP
    COAP_PROTO_TLS
    The coap_free_endpoint() function must be used to free off the endpoint. It clears out all the sessions associated with this endpoint. The coap_endpoint_set_default_mtu() function is used to set the MTU size (the maximum message size) of the data in a packet, excluding any IP or TCP/UDP overhead to mtu for the endpoint. A sensible default is 1280. The coap_endpoint_str() function returns a description string of the endpoint. The coap_new_client_session() function initiates a new client session associated with context to the specified server using the CoAP protocol proto. If the port is not specified in server, then the default CoAP port is used. Normally local_if would be set to NULL, but by specifying local_if the source of the network session can be bound to a specific IP address or port. The session will initially have a reference count of 1. The coap_new_client_session_pki() function, for a specific context, is used to configure the TLS context using the setup_data variables as defined in the coap_dtls_pki_t structure above, which includes an optional callback function call_back which will get called from within this function. coap_new_client_session_pki() will always add public_cert and private_key from one of the 2 alternatives provided in the structure, Alternative 1 taking precedence, to the TLS Context. Any CA setup functions will have to be done in the call_back function, which can be used as well to set up other additional callbacks. Set call_back to NULL if this callback is not required. This function also includes the server to connect to, optionally the local interface local_if to bind to and the CoAP protocol proto to use. The session will initially have a reference count of 1. The coap_new_client_session_psk() function, for a specific context, is used to configure the TLS context using the client identity, Pre-Shared Key key with length key_len. All 3 parameters must be defined, NULL is not valid. An empty string is valid for identity. key_len must be greater than 0. This function also includes the server to connect to, optionally the local interface local_if to bind to and the CoAP protocol proto to use. The session will initially have a reference count of 1. The coap_session_reference() is used to increment the reference count of the session. Incrementing the reference count by an application means that the library will not inadvertently remove the session when it has finished processing the session. The coap_session_release() function must be used to decrement the session reference count, which when it gets to 0, will free off the session if this is a Client, which then clears all entries from the receive queue and send queue. If the reference count goes to 0 for a Server, then the session is added to a free pool ready for subsequent re-use. If the Server session is not used for 5 minutes, then it will get completely freed off. The coap_sesson_set_default_mtu() function is used to set the MTU size (the maximum message size) of the data in a packet, excluding any IP or TCP/UDP overhead to mtu for the session.

RETURN VALUES
coap_new_context() function returns a newly created context or NULL if there is a creation failure. coap_new_endpoint() function returns a newly created endpoint or NULL if there is a creation failure. coap_new_client_session(), coap_new_client_session_psk(), coap_new_client_session_pki() functions returns a newly created client session or NULL if there is a creation failure. coap_session_reference() function returns a pointer to the session. coap_endpoint_str() function returns a description string of the endpoint. coap_dtls_is_supported(), coap_tls_is_supported(), coap_context_set_pki() coap_context_set_psk() functions return 0 on failure, 1 on success. coap_get_tls_library_version() function returns the TLS implementation type and library version in a coap_tls_version_t* structure.

EXAMPLES
CoAP Server Non-Encrypted Setup
#include <coap/coap.h>
static coap_context_t *setup_server_context (void) {
  coap_endpoint_t *endpoint;
  coap_address_t listen_addr;
  coap_context_t *context = coap_new_context(NULL);
  if (!context)
    return NULL;
  coap_address_init(&listen_addr);
  listen_addr.addr.sa.sa_family = AF_INET;
  listen_addr.addr.sin.sin_port = htons (5683);
  endpoint = coap_new_endpoint(context, &listen_addr, COAP_PROTO_UDP);
  if (!endpoint) {
    coap_free_context(context);
    return NULL;
  }
  /* See coap_resource(3) */
  init_resources(context);
  return context;
}
CoAP Server DTLS PKI Setup
#include <coap/coap.h>
static coap_context_t *setup_server_context_pki (const char *public_cert_file,
const char *private_key_file, const char *ca_file) {
  coap_endpoint_t *endpoint;
  coap_address_t listen_addr;
  coap_dtls_pki_t dtls_pki;
  coap_context_t *context;
  if (!coap_dtls_is_supported())
    return NULL;
  context = coap_new_context(NULL);
  if (!context)
    return NULL;
  memset (&dtls_pki, 0, sizeof (dtls_pki));
  dtls_pki.ca_file     = ca_file;
  dtls_pki.public_cert = public_cert_file;
  dtls_pki.private_key = private_key_file;
  dtls_pki.call_back   = setup_callback;
  if (coap_context_set_pki(context, &dtls_pki)) {
    coap_free_context(context);
    return NULL;
  }
  coap_address_init(&listen_addr);
  listen_addr.addr.sa.sa_family = AF_INET;
  listen_addr.addr.sin.sin_port = htons (5684);
  endpoint = coap_new_endpoint(context, &listen_addr, COAP_PROTO_DTLS);
  if (!endpoint) {
    coap_free_context(context);
    return NULL;
  }
  /* See coap_resource(3) */
  init_resources(context);
  return context;
}
CoAP Server OpenSSL DTLS Setup Callback
#include <coap/coap.h>
#include <openssl/ssl.h>
 /*
  * Callback function for coap_context_set_pki()
  *
  * parameter tls_context for OpenSSL is SSL_CTX*
  * parameter setup_data is a pointer to coap_dtls_pki_t structure
  */
int setup_callback(void *tls_context, coap_dtls_pki_t *setup_data) {
  SSL_CTX *ctx = (SSL_CTX *)tls_context;
  /*
   * Load in the CA file list
   */
  if (setup_data->ca_file && setup_data->ca_file[0]) {
    SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(setup_data->ca_file));
    if (!(SSL_CTX_load_verify_locations(ctx, setup_data->ca_file, 0))) {
      coap_log(LOG_ERR, "Unable to process CA file '%s'\n", setup_data->ca_file);
      return 0;
    }
  }
  /*
   * Add in an additional callback which gets called during
   * TLS Session Callback
   */
  SSL_CTX_set_tlsext_servername_callback(ctx, tls_server_name_callback);
  return 1;
}
CoAP Server DTLS PSK Setup
#include <coap/coap.h>
static coap_context_t *setup_server_context_psk (const char *hint, const
uint8_t *key, unsigned key_len) {
  coap_endpoint_t *endpoint;
  coap_address_t listen_addr;
  coap_context_t *context;
  if (!coap_dtls_is_supported())
    return NULL;
  context = coap_new_context(NULL);
  if (!context)
    return NULL;
  if (coap_context_set_psk(context, hint, key, key_len)) {
    coap_free_context(context);
    return NULL;
  }
  coap_address_init(&listen_addr);
  listen_addr.addr.sa.sa_family = AF_INET;
  listen_addr.addr.sin.sin_port = htons (5684);
  endpoint = coap_new_endpoint(context, &listen_addr, COAP_PROTO_DTLS);
  if (!endpoint) {
    coap_free_context(context);
    return NULL;
  }
  /* See coap_resource(3) */
  init_resources(context);
  return context;
}
CoAP Client Non-Encrypted Setup
#include <coap/coap.h>
#include <netinet/in.h>
static coap_session_t *setup_client_session (struct in_addr ip_address) {
  coap_session_t *session;
  coap_address_t server;
  coap_context_t *context = coap_new_context(NULL);
  if (!context)
    return NULL;
  coap_address_init(&server);
  server.addr.sa.sa_family = AF_INET;
  server.addr.sin.sin_addr = ip_address;
  server.addr.sin.sin_port = htons (5683);
  session = coap_new_client_session(context, NULL, &server, COAP_PROTO_UDP);
  if (!session) {
    coap_free_context(context);
    return NULL;
  }
  /* The context is in session->context */
  return session;
}
CoAP Client PKI Setup
#include <coap/coap.h>
#include <netinet/in.h>
static coap_session_t *setup_client_session_pki (struct in_addr ip_address,
const char *public_cert_file, const char *private_key_file,
const char *ca_file) {
  coap_session_t *session;
  coap_address_t server;
  coap_dtls_pki_t dtls_pki;
  coap_context_t *context = coap_new_context(NULL);
  if (!context)
    return NULL;
  coap_address_init(&server);
  server.addr.sa.sa_family = AF_INET;
  server.addr.sin.sin_addr = ip_address;
  server.addr.sin.sin_port = htons (5684);
  memset (&dtls_pki, 0, sizeof (dtls_pki));
  dtls_pki.ca_file     = ca_file;
  dtls_pki.public_cert = public_cert_file;
  dtls_pki.private_key = private_key_file;
  dtls_pki.call_back   = NULL;
  session = coap_new_client_session_pki(context, NULL, &server,
                                        COAP_PROTO_DTLS, &dtls_pki);
  if (!session) {
    coap_free_context(context);
    return NULL;
  }
  /* The context is in session->context */
  return session;
}
CoAP Client PSK Setup
#include <coap/coap.h>
#include <netinet/in.h>
static coap_session_t *setup_client_session_psk (struct in_addr ip_address,
const char *identity, const uint8_t *key, unsigned key_len) {
  coap_session_t *session;
  coap_address_t server;
  coap_context_t *context = coap_new_context(NULL);
  if (!context)
    return NULL;
  coap_address_init(&server);
  server.addr.sa.sa_family = AF_INET;
  server.addr.sin.sin_addr = ip_address;
  server.addr.sin.sin_port = htons (5684);
  session = coap_new_client_session_psk(context, NULL, &server,
                                        COAP_PROTO_DTLS, identity, key, key_len);
  if (!session) {
    coap_free_context(context);
    return NULL;
  }
  /* The context is in session->context */
  return session;
}

SEE ALSO
coap_resource(3) and coap_tls_library(3)

FURTHER INFORMATION
See "RFC7252: The Constrained Application Protocol (CoAP)" for further information.

BUGS
Please report bugs on the mailing list for libcoap: libcoap-developers@lists.sourceforge.net

AUTHORS
The libcoap project <libcoap-developers@lists.sourceforge.net>