'\" t .\" Title: coap_oscore .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 10/28/2023 .\" Manual: libcoap Manual .\" Source: coap_oscore 4.3.4 .\" Language: English .\" .TH "COAP_OSCORE" "3" "10/28/2023" "coap_oscore 4\&.3\&.4" "libcoap Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" coap_oscore, coap_oscore_is_supported, coap_new_oscore_conf, coap_delete_oscore_conf, coap_new_oscore_recipient, coap_delete_oscore_recipient, coap_new_client_session_oscore, coap_new_client_session_oscore_pki, coap_new_client_session_oscore_psk, coap_context_oscore_server \- Work with CoAP OSCORE .SH "SYNOPSIS" .sp \fB#include \fR .sp \fBint coap_oscore_is_supported(void);\fR .sp \fBcoap_oscore_conf_t *coap_new_oscore_conf(coap_str_const_t \fR\fB\fIconf_mem\fR\fR\fB, coap_oscore_save_seq_num_t \fR\fB\fIsave_seq_num_func\fR\fR\fB, void *\fR\fB\fIsave_seq_num_func_param\fR\fR\fB, uint64_t \fR\fB\fIstart_seq_num\fR\fR\fB);\fR .sp \fBint coap_delete_oscore_conf(coap_oscore_conf_t *\fR\fB\fIoscore_conf\fR\fR\fB);\fR .sp \fBint coap_new_oscore_recipient(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, coap_bin_const_t *\fR\fB\fIrecipient_id\fR\fR\fB);\fR .sp \fBint coap_delete_oscore_recipient(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, coap_bin_const_t *\fR\fB\fIrecipient_id\fR\fR\fB);\fR .sp \fBcoap_session_t *coap_new_client_session_oscore(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, const coap_address_t *\fR\fB\fIlocal_if\fR\fR\fB, const coap_address_t *\fR\fB\fIserver\fR\fR\fB, coap_proto_t \fR\fB\fIproto\fR\fR\fB, coap_oscore_conf_t *\fR\fB\fIoscore_conf\fR\fR\fB);\fR .sp \fBcoap_session_t *coap_new_client_session_oscore_psk(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, const coap_address_t *\fR\fB\fIlocal_if\fR\fR\fB, const coap_address_t *\fR\fB\fIserver\fR\fR\fB, coap_proto_t \fR\fB\fIproto\fR\fR\fB, coap_dtls_cpsk_t *\fR\fB\fIpsk_data\fR\fR\fB, coap_oscore_conf_t *\fR\fB\fIoscore_conf\fR\fR\fB);\fR .sp \fBcoap_session_t *coap_new_client_session_oscore_pki(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, const coap_address_t *\fR\fB\fIlocal_if\fR\fR\fB, const coap_address_t *\fR\fB\fIserver\fR\fR\fB, coap_proto_t \fR\fB\fIproto\fR\fR\fB, coap_dtls_pki_t *\fR\fB\fIpki_data\fR\fR\fB, coap_oscore_conf_t *\fR\fB\fIoscore_conf\fR\fR\fB);\fR .sp \fBint coap_context_oscore_server(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, coap_oscore_conf_t *\fR\fB\fIoscore_conf\fR\fR\fB);\fR .sp For specific (D)TLS library support, link with \fB\-lcoap\-3\-notls\fR, \fB\-lcoap\-3\-gnutls\fR, \fB\-lcoap\-3\-openssl\fR, \fB\-lcoap\-3\-mbedtls\fR or \fB\-lcoap\-3\-tinydtls\fR\&. Otherwise, link with \fB\-lcoap\-3\fR to get the default (D)TLS library support\&. .SH "DESCRIPTION" .sp This describes libcoap\(cqs support for using OSCORE as defined in RFC8613\&. .sp OSCORE provides end\-to\-end protection between endpoints communicating using CoAP\&. (D)TLS can only protect HOP by HOP traffic which allows proxies to manipulate information\&. .SH "CALLBACK HANDLER" .sp \fBCallback Type: coap_oscore_save_seq_num_t\fR .sp The coap_oscore_save_seq_num_t method handler function prototype is defined as: .sp .if n \{\ .RS 4 .\} .nf typedef int (*coap_oscore_save_seq_num_t)(uint64_t sender_seq_num, void *param); .fi .if n \{\ .RE .\} .sp and returns 0 on failure, 1 on succes\&. .SH "FUNCTIONS" .sp \fBFunction: coap_oscore_is_supported()\fR .sp The \fBcoap_oscore_is_supported\fR() function returns 1 if OSCORE is supported, otherwise 0\&. .sp \fBFunction: coap_new_oscore_conf()\fR .sp The \fBcoap_new_oscore_conf\fR() function is used to build a new OSCORE configuration\&. It parses the provided OSCORE configuration in \fIconf_mem\fR\&. The format of the keywords, encoding types and values is documented in \fBcoap\-oscore\-conf\fR(5)\&. It also sets an optional function \fIsave_seq_num_func\fR (which gets \fIsave_seq_num_func_param\fR passed in) that is called to store the next Sender Sequence Number (SSN) in non\-volatile storage\&. The latest next SSN from non\-volatile storage (or 0) is then put in \fIstart_seq_num\fR\&. SSN are used so that anti\-replay mechanisms do not kick in following application restarts\&. The rate of calling \fIsave_seq_num_func\fR can be controlled by the \fIssn_freq\fR parameter as defined in \fBcoap\-oscore\-conf\fR(5)\&. .sp This OSCORE configuration is then used in the client and server OSCORE version of the setup functions\&. .sp If the server is proxy enabled and the new incoming session is OSCORE encoded with the Outer CoAP ProxyScheme and Host options set, then the libcoap logic will determine whether the server is the final endpoint of the session, or whether the proxy will be forwarding the session off to another server, based on how \fBcoap_resource_proxy_uri_init\fR(3) configured the proxy logic\&. If the session is going to forwarded, then the OSCORE protection will not be removed\&. .sp If \fBcoap_context_oscore_server\fR() is not called and the proxy logic (if set) indicates the session will get forwarded, then the OSCORE protection is untouched, otherwise the session will get dropped with an unknown critical option error response\&. .sp \fBFunction: coap_new_oscore_recipient()\fR .sp The \fBcoap_new_oscore_recipient\fR() is used to add a new \fIrecipient_id\fR to the OSCORE information associated with \fIcontext\fR\&. The new \fIrecipient_id\fR should be unique and this function should only be used for server based applications as the client will only ever use the first defined \fIrecipient_id\fR\&. It is assumed that \fBcoap_context_oscore_server\fR() has already been called to update \fIcontext\fR with the appropriate OSCORE information\&. .sp \fBFunction: coap_delete_oscore_recipient()\fR .sp The \fBcoap_delete_oscore_recipient\fR() is used to remove the \fIrecipient_id\fR from the OSCORE information associated with \fIcontext\fR\&. OSCORE Traffic continuing to use \fIrecipient_id\fR will then fail\&. .sp \fBFunction: coap_delete_oscore_conf()\fR .sp The \fBcoap_delete_oscore_conf\fR() function is used to free off the coap_oscore_conf_t structure \fIoscore_conf\fR as returned by \fBcoap_new_oscore_conf\fR()\&. Normally this function never needs to be called as \fIoscore_conf\fR is freed off by the call the client or server setup functions\&. .sp \fBFunction: coap_new_client_session_oscore()\fR .sp The \fBcoap_new_client_session_oscore\fR() is basically the same as \fBcoap_new_client_session\fR(3), but has an additional parameter \fIoscore_conf\fR that is created by \fBcoap_new_oscore_conf\fR()\&. This function creates a client endpoint for a specific \fIcontext\fR and initiates a new client session to the specified \fIserver\fR using the CoAP protocol \fIproto\fR and OSCORE protected by the \fIoscore_conf\fR definition (which is freed off by this call)\&. If the port is set to 0 in \fIserver\fR, then the default CoAP port is used\&. Normally \fIlocal_if\fR would be set to NULL, but by specifying \fIlocal_if\fR 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\&. .sp \fBFunction: coap_new_client_session_oscore_psk()\fR .sp The \fBcoap_new_client_session_oscore_psk\fR() is basically the same as \fBcoap_new_client_session_psk2\fR(3), but has an additional parameter \fIoscore_conf\fR that is created by \fBcoap_new_oscore_conf\fR()\&. This function, for a specific \fIcontext\fR, is used to configure the TLS context using the \fIsetup_data\fR variables as defined in the coap_dtls_cpsk_t structure in the newly created endpoint session \- see \fBcoap_encryption\fR(3), as well as OSCORE protected by the \fIoscore_conf\fR definition (which is freed off by this call)\&. The connection is to the specified \fIserver\fR using the CoAP protocol \fIproto\fR\&. If the port is set to 0 in \fIserver\fR, then the default CoAP port is used\&. Normally \fIlocal_if\fR would be set to NULL, but by specifying \fIlocal_if\fR 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\&. .sp \fBFunction: coap_new_client_session_oscore_pki()\fR .sp The \fBcoap_new_client_session_oscore_pki\fR() is basically the same as \fBcoap_new_client_session_pki\fR(3), but has an additional parameter \fIoscore_conf\fR that is created by \fBcoap_new_oscore_conf\fR()\&. This function, for a specific \fIcontext\fR, is used to configure the TLS context using the \fIsetup_data\fR variables as defined in the coap_dtls_pki_t structure in the newly created endpoint session \- see \fBcoap_encryption\fR(3), as well as OSCORE protected by the \fIoscore_conf\fR definition (which is freed off by this call)\&. The connection is to the specified \fIserver\fR using the CoAP protocol \fIproto\fR\&. If the port is set to 0 in \fIserver\fR, then the default CoAP port is used\&. Normally \fIlocal_if\fR would be set to NULL, but by specifying \fIlocal_if\fR 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\&. .sp \fBFunction: coap_context_oscore_server()\fR .sp The \fBcoap_context_oscore_server\fR() function is used to enable the server to support OSCORE incoming sessions\&. It updates \fIcontext\fR with the OSCORE configure \fIoscore_conf\fR (which is freed off by this call)\&. .SH "RETURN VALUES" .sp \fBcoap_new_client_session_oscore\fR(), \fBcoap_new_client_session_oscore_psk\fR() and \fBcoap_new_client_session_oscore_pki\fR() return a newly created client session or NULL if there is a malloc or parameter failure\&. .sp \fBcoap_new_oscore_conf\fR() returns a \fIcoap_oscore_conf_t\fR or NULL on failure\&. .sp \fBcoap_oscore_is_supported\fR(), \fBcoap_context_oscore_server\fR(), \fBcoap_delete_oscore_conf\fR(), \fBcoap_new_oscore_recipient\fR() and \fBcoap_delete_oscore_recipient\fR() return 0 on failure, 1 on success\&. .SH "EXAMPLES" .sp \fBClient Setup\fR .sp .if n \{\ .RS 4 .\} .nf #include #include #include static uint8_t oscore_config[] = "master_secret,hex,\e"0102030405060708090a0b0c0d0e0f10\e"\en" "master_salt,hex,\e"9e7ca92223786340\e"\en" "server_id,ascii,\e"client\e"\en" "recipient_id,ascii,\e"server\e"\en" "replay_window,integer,30\en" "aead_alg,integer,10\en" "hkdf_alg,integer,\-10\en" ; static FILE *oscore_seq_num_fp = NULL; /* Not a particularly safe place to keep next Sender Sequence Number \&.\&.\&. */ static const char* oscore_seq_save_file = "/tmp/client\&.seq"; static int oscore_save_seq_num(uint64_t sender_seq_num, void *param COAP_UNUSED) { if (oscore_seq_num_fp) { rewind(oscore_seq_num_fp); fprintf(oscore_seq_num_fp, "%lu\en", sender_seq_num); fflush(oscore_seq_num_fp); } return 1; } static coap_session_t * setup_client_session (struct in_addr ip_address) { coap_session_t *session; coap_address_t server; /* See coap_context(3) */ coap_context_t *context = coap_new_context(NULL); if (!context) return NULL; /* See coap_block(3) */ coap_context_set_block_mode(context, COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY); 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); if (coap_oscore_is_supported()) { coap_str_const_t config = { sizeof (oscore_config), oscore_config }; uint64_t start_seq_num = 0; coap_oscore_conf_t *oscore_conf; if (oscore_seq_save_file) { oscore_seq_num_fp = fopen(oscore_seq_save_file, "r+"); if (oscore_seq_num_fp == NULL) { /* Try creating it */ oscore_seq_num_fp = fopen(oscore_seq_save_file, "w+"); if (oscore_seq_num_fp == NULL) { coap_log_err("OSCORE save restart info file error: %s\en", oscore_seq_save_file); return NULL; } } fscanf(oscore_seq_num_fp, "%ju", &start_seq_num); } oscore_conf = coap_new_oscore_conf(config, oscore_save_seq_num, NULL, start_seq_num); if (!oscore_conf) { coap_free_context(context); return NULL; } session = coap_new_client_session_oscore(context, NULL, &server, COAP_PROTO_UDP, oscore_conf); } else { 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; } .fi .if n \{\ .RE .\} .sp \fBServer Setup\fR .sp .if n \{\ .RS 4 .\} .nf #include #include static uint8_t oscore_config[] = "master_secret,hex,\e"0102030405060708090a0b0c0d0e0f10\e"\en" "master_salt,hex,\e"9e7ca92223786340\e"\en" "sender_id,ascii,\e"server\e"\en" "recipient_id,ascii,\e"client\e"\en" "replay_window,integer,30\en" "aead_alg,integer,10\en" "hkdf_alg,integer,\-10\en" ; static FILE *oscore_seq_num_fp = NULL; /* Not a particularly safe place to keep next Sender Sequence Number \&.\&.\&. */ static const char* oscore_seq_save_file = "/tmp/server\&.seq"; static int oscore_save_seq_num(uint64_t sender_seq_num, void *param COAP_UNUSED) { if (oscore_seq_num_fp) { rewind(oscore_seq_num_fp); fprintf(oscore_seq_num_fp, "%lu\en", sender_seq_num); fflush(oscore_seq_num_fp); } return 1; } static int setup_context (void) { /* See coap_context(3) */ coap_context_t *context = coap_new_context(NULL); if (!context) return 0; /* See coap_block(3) */ coap_context_set_block_mode(context, COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY); if (coap_oscore_is_supported()) { coap_str_const_t config = { sizeof (oscore_config), oscore_config }; uint64_t start_seq_num = 0; coap_oscore_conf_t *oscore_conf; if (oscore_seq_save_file) { oscore_seq_num_fp = fopen(oscore_seq_save_file, "r+"); if (oscore_seq_num_fp == NULL) { /* Try creating it */ oscore_seq_num_fp = fopen(oscore_seq_save_file, "w+"); if (oscore_seq_num_fp == NULL) { coap_log_err("OSCORE save restart info file error: %s\en", oscore_seq_save_file); return 0; } } fscanf(oscore_seq_num_fp, "%ju", &start_seq_num); } oscore_conf = coap_new_oscore_conf(config, oscore_save_seq_num, NULL, start_seq_num); if (!oscore_conf) { coap_free_context(context); return 0; } coap_context_oscore_server(context, oscore_conf); } return 1; } .fi .if n \{\ .RE .\} .SH "SEE ALSO" .sp \fBcoap_endpoint_client\fR(3), \fBcoap_endpoint_server\fR(3) and \fBcoap\-oscore\-conf\fR(5) .SH "FURTHER INFORMATION" .sp See .sp "RFC7252: The Constrained Application Protocol (CoAP)" .sp "RFC8613: Object Security for Constrained RESTful Environments (OSCORE)" .sp for further information\&. .SH "BUGS" .sp Please report bugs on the mailing list for libcoap: libcoap\-developers@lists\&.sourceforge\&.net or raise an issue on GitHub at https://github\&.com/obgm/libcoap/issues .SH "AUTHORS" .sp The libcoap project