Loading...
Searching...
No Matches
coap_oscore.c
Go to the documentation of this file.
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* coap_oscore.c -- Object Security for Constrained RESTful Environments
* (OSCORE) support for libcoap
*
* Copyright (C) 2019-2021 Olaf Bergmann <bergmann@tzi.org>
* Copyright (C) 2021-2024 Jon Shallow <supjps-libcoap@jpshallow.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#include "coap3/coap_libcoap_build.h"
#if COAP_OSCORE_SUPPORT
#include <ctype.h>
#define AAD_BUF_LEN 200 /* length of aad_buffer */
static oscore_ctx_t *coap_oscore_init(coap_context_t *c_context,
coap_oscore_conf_t *oscore_conf);
#if COAP_CLIENT_SUPPORT
int
coap_oscore_initiate(coap_session_t *session, coap_oscore_conf_t *oscore_conf) {
if (oscore_conf) {
oscore_ctx_t *osc_ctx;
if (oscore_conf->recipient_id_count == 0) {
coap_log_warn("OSCORE: Recipient ID must be defined for a client\n");
return 0;
}
if (oscore_conf->rfc8613_b_2) {
/* Need to replace id_context with random value */
coap_binary_t *id_context = coap_new_binary(8);
if (id_context == NULL)
return 0;
coap_delete_bin_const(oscore_conf->id_context);
coap_prng_lkd(id_context->s, id_context->length);
oscore_conf->id_context = (coap_bin_const_t *)id_context;
session->b_2_step = COAP_OSCORE_B_2_STEP_1;
coap_log_oscore("Appendix B.2 client step 1 (Generated ID1)\n");
}
osc_ctx = coap_oscore_init(session->context, oscore_conf);
if (osc_ctx == NULL) {
return 0;
}
session->recipient_ctx = osc_ctx->recipient_chain;
session->oscore_encryption = 1;
}
return 1;
}
COAP_API coap_session_t *
coap_new_client_session_oscore(coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
coap_oscore_conf_t *oscore_conf) {
coap_session_t *session;
coap_lock_lock(ctx, return NULL);
session = coap_new_client_session_oscore_lkd(ctx, local_if, server, proto, oscore_conf);
coap_lock_unlock(ctx);
return session;
}
coap_session_t *
coap_new_client_session_oscore_lkd(coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
coap_oscore_conf_t *oscore_conf) {
coap_session_t *session =
coap_new_client_session_lkd(ctx, local_if, server, proto);
if (!session)
return NULL;
if (coap_oscore_initiate(session, oscore_conf) == 0) {
coap_session_release_lkd(session);
return NULL;
}
return session;
}
COAP_API coap_session_t *
coap_new_client_session_oscore_psk(coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
coap_dtls_cpsk_t *psk_data,
coap_oscore_conf_t *oscore_conf) {
coap_session_t *session;
coap_lock_lock(ctx, return NULL);
session = coap_new_client_session_oscore_psk_lkd(ctx, local_if, server, proto, psk_data,
oscore_conf);
coap_lock_unlock(ctx);
return session;
}
coap_session_t *
coap_new_client_session_oscore_psk_lkd(coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
coap_dtls_cpsk_t *psk_data,
coap_oscore_conf_t *oscore_conf) {
coap_session_t *session;
coap_lock_check_locked(ctx);
session = coap_new_client_session_psk2_lkd(ctx, local_if, server, proto, psk_data);
if (!session)
return NULL;
if (coap_oscore_initiate(session, oscore_conf) == 0) {
coap_session_release_lkd(session);
return NULL;
}
return session;
}
COAP_API coap_session_t *
coap_new_client_session_oscore_pki(coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
coap_dtls_pki_t *pki_data,
coap_oscore_conf_t *oscore_conf) {
coap_session_t *session;
coap_lock_lock(ctx, return NULL);
session = coap_new_client_session_oscore_pki_lkd(ctx, local_if, server, proto, pki_data,
oscore_conf);
coap_lock_unlock(ctx);
return session;
}
coap_session_t *
coap_new_client_session_oscore_pki_lkd(coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
coap_dtls_pki_t *pki_data,
coap_oscore_conf_t *oscore_conf) {
coap_session_t *session;
coap_lock_check_locked(ctx);
session = coap_new_client_session_pki_lkd(ctx, local_if, server, proto, pki_data);
if (!session)
return NULL;
if (coap_oscore_initiate(session, oscore_conf) == 0) {
coap_session_release_lkd(session);
return NULL;
}
return session;
}
#endif /* COAP_CLIENT_SUPPORT */
#if COAP_SERVER_SUPPORT
COAP_API int
coap_context_oscore_server(coap_context_t *context,
coap_oscore_conf_t *oscore_conf) {
int ret;
coap_lock_lock(context, return 0);
ret = coap_context_oscore_server_lkd(context, oscore_conf);
coap_lock_unlock(context);
return ret;
}
int
coap_context_oscore_server_lkd(coap_context_t *context,
coap_oscore_conf_t *oscore_conf) {
oscore_ctx_t *osc_ctx;
coap_lock_check_locked(context);
osc_ctx = coap_oscore_init(context, oscore_conf);
/* osc_ctx already added to context->osc_ctx */
if (osc_ctx)
return 1;
return 0;
}
#endif /* COAP_SERVER_SUPPORT */
int
coap_rebuild_pdu_for_proxy(coap_pdu_t *pdu) {
coap_uri_t uri;
coap_opt_iterator_t opt_iter;
coap_opt_t *option;
uint8_t option_value_buffer[15];
coap_optlist_t *optlist_chain = NULL;
if ((option =
coap_check_option(pdu, COAP_OPTION_PROXY_URI, &opt_iter)) == NULL)
return 1;
/* Need to break down into the component parts, but keep data safe */
memset(&uri, 0, sizeof(uri));
if (coap_split_proxy_uri(coap_opt_value(option),
coap_opt_length(option),
&uri) < 0 || uri.scheme >= COAP_URI_SCHEME_LAST) {
coap_log_warn("Proxy URI '%.*s' not decodable\n",
coap_opt_length(option),
(const char *)coap_opt_value(option));
goto error;
}
if (!coap_remove_option(pdu, COAP_OPTION_PROXY_URI))
goto error;
if (!coap_insert_option(pdu,
COAP_OPTION_URI_HOST,
uri.host.length,
uri.host.s))
goto error;
if (uri.port != (coap_uri_scheme_is_secure(&uri) ? COAPS_DEFAULT_PORT : COAP_DEFAULT_PORT) &&
!coap_insert_option(pdu,
COAP_OPTION_URI_PORT,
coap_encode_var_safe(option_value_buffer,
sizeof(option_value_buffer),
uri.port & 0xffff),
option_value_buffer))
goto error;
if (uri.path.length) {
/* Add in the Uri-Path options */
if (!coap_path_into_optlist(uri.path.s, uri.path.length, COAP_OPTION_URI_PATH,
&optlist_chain))
goto error;
}
if (uri.query.length) {
/* Add in the Uri-Query options */
if (!coap_query_into_optlist(uri.query.s, uri.query.length, COAP_OPTION_URI_QUERY,
&optlist_chain))
goto error;
}
if (!coap_add_optlist_pdu(pdu, &optlist_chain))
goto error;
if (!coap_insert_option(pdu,
COAP_OPTION_PROXY_SCHEME,
strlen(coap_uri_scheme[uri.scheme].name),
(const uint8_t *)coap_uri_scheme[uri.scheme].name))
goto error;
coap_delete_optlist(optlist_chain);
return 1;
error:
coap_delete_optlist(optlist_chain);
return 0;
}
static void
dump_cose(cose_encrypt0_t *cose, const char *message) {
#if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_OSCORE
(void)cose;
(void)message;
#else /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_OSCORE */
if (coap_get_log_level() >= COAP_LOG_OSCORE) {
char buffer[30];
coap_log_oscore("%s Cose information\n", message);
oscore_log_char_value(COAP_LOG_OSCORE, "alg",
cose_get_alg_name(cose->alg, buffer, sizeof(buffer)));
oscore_log_hex_value(COAP_LOG_OSCORE, "key", &cose->key);
oscore_log_hex_value(COAP_LOG_OSCORE, "partial_iv", &cose->partial_iv);
oscore_log_hex_value(COAP_LOG_OSCORE, "key_id", &cose->key_id);
oscore_log_hex_value(COAP_LOG_OSCORE, "kid_context", &cose->kid_context);
oscore_log_hex_value(COAP_LOG_OSCORE,
"oscore_option",
&cose->oscore_option);
oscore_log_hex_value(COAP_LOG_OSCORE, "nonce", &cose->nonce);
oscore_log_hex_value(COAP_LOG_OSCORE, "external_aad", &cose->external_aad);
oscore_log_hex_value(COAP_LOG_OSCORE, "aad", &cose->aad);
}
#endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_OSCORE */
}
COAP_API coap_pdu_t *
coap_oscore_new_pdu_encrypted(coap_session_t *session,
coap_pdu_t *pdu,
coap_bin_const_t *kid_context,
oscore_partial_iv_t send_partial_iv) {
coap_pdu_t *ret_pdu;
coap_lock_lock(session->context, return NULL);
ret_pdu = coap_oscore_new_pdu_encrypted_lkd(session, pdu, kid_context, send_partial_iv);
coap_lock_unlock(session->context);
return ret_pdu;
}
/*
* Take current PDU, create a new one approriately separated as per RFC8613
* and then encrypt / integrity check the OSCORE data
*/
coap_pdu_t *
coap_oscore_new_pdu_encrypted_lkd(coap_session_t *session,
coap_pdu_t *pdu,
coap_bin_const_t *kid_context,
oscore_partial_iv_t send_partial_iv) {
uint8_t coap_request = COAP_PDU_IS_REQUEST(pdu) || COAP_PDU_IS_PING(pdu);
coap_pdu_code_t code =
coap_request ? COAP_REQUEST_CODE_POST : COAP_RESPONSE_CODE(204);
coap_pdu_t *osc_pdu;
coap_pdu_t *plain_pdu = NULL;
coap_bin_const_t pdu_token;
coap_opt_iterator_t opt_iter;
coap_opt_t *option;
uint8_t pdu_code = pdu->code;
size_t length;
const uint8_t *data;
uint8_t *ciphertext_buffer = NULL;
size_t ciphertext_len = 0;
uint8_t aad_buffer[AAD_BUF_LEN];
uint8_t nonce_buffer[13];
coap_bin_const_t aad;
coap_bin_const_t nonce;
oscore_recipient_ctx_t *rcp_ctx;
oscore_ctx_t *osc_ctx;
cose_encrypt0_t cose[1];
uint8_t group_flag = 0;
int show_pdu = 0;
int doing_observe = 0;
uint32_t observe_value = 0;
oscore_association_t *association = NULL;
oscore_sender_ctx_t *snd_ctx;
uint8_t external_aad_buffer[200];
coap_bin_const_t external_aad;
uint8_t oscore_option[48];
size_t oscore_option_len;
/* Check that OSCORE has not already been done */
if (coap_check_option(pdu, COAP_OPTION_OSCORE, &opt_iter))
return NULL;
if (coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter))
doing_observe = 1;
coap_log_debug("PDU to encrypt\n");
coap_show_pdu(COAP_LOG_DEBUG, pdu);
osc_pdu = coap_pdu_init(pdu->type == COAP_MESSAGE_NON &&
session->b_2_step != COAP_OSCORE_B_2_NONE ?
COAP_MESSAGE_CON : pdu->type,
code,
pdu->mid,
pdu->used_size + coap_oscore_overhead(session, pdu));
if (osc_pdu == NULL)
return NULL;
cose_encrypt0_init(cose); /* clears cose memory */
pdu_token = coap_pdu_get_token(pdu);
if (coap_request) {
/*
* RFC8613 8.1 Step 1. Protecting the client's request
* Get the Sender Context
*/
rcp_ctx = session->recipient_ctx;
if (rcp_ctx == NULL)
goto error;
osc_ctx = rcp_ctx->osc_ctx;
assert(osc_ctx);
snd_ctx = osc_ctx->sender_context;
} else {
/*
* RFC8613 8.3 Step 1. Protecting the server's response
* Get the Sender Context
*/
association = oscore_find_association(session, &pdu_token);
if (association == NULL)
goto error;
rcp_ctx = association->recipient_ctx;
osc_ctx = rcp_ctx->osc_ctx;
snd_ctx = osc_ctx->sender_context;
cose_encrypt0_set_partial_iv(cose, association->partial_iv);
cose_encrypt0_set_aad(cose, association->aad);
}
cose_encrypt0_set_alg(cose, osc_ctx->aead_alg);
if (coap_request || doing_observe ||
send_partial_iv == OSCORE_SEND_PARTIAL_IV) {
uint8_t partial_iv_buffer[8];
size_t partial_iv_len;
coap_bin_const_t partial_iv;
partial_iv_len = coap_encode_var_safe8(partial_iv_buffer,
sizeof(partial_iv_buffer),
snd_ctx->seq);
if (snd_ctx->seq == 0) {
/* Need to special case */
partial_iv_buffer[0] = '\000';
partial_iv_len = 1;
}
partial_iv.s = partial_iv_buffer;
partial_iv.length = partial_iv_len;
cose_encrypt0_set_partial_iv(cose, &partial_iv);
}
if (coap_request)
cose_encrypt0_set_kid_context(cose, osc_ctx->id_context);
cose_encrypt0_set_key_id(cose, snd_ctx->sender_id);
/* nonce (needs to have sender information correctly set up) */
if (coap_request || doing_observe ||
send_partial_iv == OSCORE_SEND_PARTIAL_IV) {
/*
* 8.1 Step 3 or RFC8613 8.3.1 Step A
* Compose the AEAD nonce
*
* Requires in COSE object as appropriate
* key_id (kid) (sender)
* partial_iv (sender)
* common_iv (already in osc_ctx)
*/
nonce.s = nonce_buffer;
nonce.length = 13;
oscore_generate_nonce(cose, osc_ctx, nonce_buffer, 13);
cose_encrypt0_set_nonce(cose, &nonce);
if (!oscore_increment_sender_seq(osc_ctx))
goto error;
if (osc_ctx->save_seq_num_func) {
if (osc_ctx->sender_context->seq > osc_ctx->sender_context->next_seq) {
/* Only update at ssn_freq rate */
osc_ctx->sender_context->next_seq += osc_ctx->ssn_freq;
osc_ctx->save_seq_num_func(osc_ctx->sender_context->next_seq,
osc_ctx->save_seq_num_func_param);
}
}
} else {
/*
* 8.3 Step 3.
* Use nonce from request
*/
cose_encrypt0_set_nonce(cose, association->nonce);
}
/* OSCORE_option (needs to be before AAD as included in AAD if group) */
/* cose is modified for encode option in response message */
if (!coap_request) {
/* no kid on response */
cose_encrypt0_set_key_id(cose, NULL);
if (!doing_observe && send_partial_iv == OSCORE_SEND_NO_IV)
cose_encrypt0_set_partial_iv(cose, NULL);
}
if (kid_context) {
cose_encrypt0_set_kid_context(cose, kid_context);
}
oscore_option_len =
oscore_encode_option_value(oscore_option, sizeof(oscore_option), cose,
group_flag,
session->b_2_step != COAP_OSCORE_B_2_NONE);
if (!coap_request) {
/* Reset what was just unset as appropriate for AAD */
cose_encrypt0_set_key_id(cose, rcp_ctx->recipient_id);
cose_encrypt0_set_partial_iv(cose, association->partial_iv);
}
if (kid_context)
cose_encrypt0_set_kid_context(cose, osc_ctx->id_context);
/*
* RFC8613 8.1/8.3 Step 2(a) (5.4).
* Compose the External AAD and then AAD
*
* OSCORE_option requires
* partial_iv (cose partial_iv)
* kid_context (cose kid_context)
* key_id (cose key_id)
* group_flag
*
* Non Group (based on osc_tx->mode) requires the following
* aead_alg (osc_ctx)
* request_kid (request key_id using cose)
* request_piv (request partial_iv using cose)
* options (none at present)
* Group (based on osc_tx->mode) requires the following
* aead_alg (osc_ctx) (pairwise mode)
* sign_enc_alg (osc_ctx) (group mode)
* sign_alg (osc_ctx) (group mode)
* alg_pairwise_key_agreement (osc_ctx) (pairwise mode)
* request_kid (request key_id using cose)
* request_piv (request partial_iv using cose)
* options (none at present)
* request_kid_context (osc_ctx id_context)
* OSCORE_option (parameter)
* test_gs_public_key (osc_ctx sender_context public_key)
* gm_public_key (osc_ctx gm_public_key)
*
* Note: No I options at present
*/
if (coap_request || osc_ctx->mode != OSCORE_MODE_SINGLE ||
send_partial_iv == OSCORE_SEND_PARTIAL_IV) {
/* External AAD */
external_aad.s = external_aad_buffer;
external_aad.length = oscore_prepare_e_aad(osc_ctx,
cose,
NULL,
0,
NULL,
external_aad_buffer,
sizeof(external_aad_buffer));
cose_encrypt0_set_external_aad(cose, &external_aad);
/* AAD */
aad.s = aad_buffer;
aad.length = oscore_prepare_aad(external_aad_buffer,
external_aad.length,
aad_buffer,
sizeof(aad_buffer));
assert(aad.length < AAD_BUF_LEN);
cose_encrypt0_set_aad(cose, &aad);
}
/*
* RFC8613 8.1/8.3 Step 2(b) (5.3).
*
* Set up temp plaintext pdu, the data including token, options and
* optional payload will get encrypted as COSE ciphertext.
*/
plain_pdu = coap_pdu_init(pdu->type,
pdu->code,
pdu->mid,
pdu->used_size + 1 /* pseudo-token with actual code */);
if (plain_pdu == NULL)
goto error;
coap_add_token(osc_pdu, pdu_token.length, pdu_token.s);
/* First byte of plain is real CoAP code. Pretend it is token */
coap_add_token(plain_pdu, 1, &pdu_code);
/* Copy across the Outer/Inner Options to respective PDUs */
coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
while ((option = coap_option_next(&opt_iter))) {
switch (opt_iter.number) {
case COAP_OPTION_URI_HOST:
case COAP_OPTION_URI_PORT:
case COAP_OPTION_PROXY_SCHEME:
case COAP_OPTION_HOP_LIMIT:
/* Outer only */
if (!coap_insert_option(osc_pdu,
opt_iter.number,
coap_opt_length(option),
coap_opt_value(option)))
goto error;
break;
case COAP_OPTION_OBSERVE:
/* Make as Outer option as-is */
if (!coap_insert_option(osc_pdu,
opt_iter.number,
coap_opt_length(option),
coap_opt_value(option)))
goto error;
if (coap_request) {
/* Make as Inner option (unchanged) */
if (!coap_insert_option(plain_pdu,
opt_iter.number,
coap_opt_length(option),
coap_opt_value(option)))
goto error;
osc_pdu->code = COAP_REQUEST_CODE_FETCH;
} else {
/* Make as Inner option but empty */
if (!coap_insert_option(plain_pdu, opt_iter.number, 0, NULL))
goto error;
osc_pdu->code = COAP_RESPONSE_CODE(205);
}
show_pdu = 1;
doing_observe = 1;
observe_value = coap_decode_var_bytes(coap_opt_value(option),
coap_opt_length(option));
break;
case COAP_OPTION_PROXY_URI:
/*
* Should have already been caught by doing
* coap_rebuild_pdu_for_proxy() before calling
* coap_oscore_new_pdu_encrypted_lkd()
*/
assert(0);
break;
default:
/* Make as Inner option */
if (!coap_insert_option(plain_pdu,
opt_iter.number,
coap_opt_length(option),
coap_opt_value(option)))
goto error;
break;
}
}
/* Add in data to plain */
if (coap_get_data(pdu, &length, &data)) {
if (!coap_add_data(plain_pdu, length, data))
goto error;
}
if (show_pdu) {
coap_log_oscore("OSCORE payload\n");
coap_show_pdu(COAP_LOG_OSCORE, plain_pdu);
}
/*
* 8.1/8.3 Step 4.
* Encrypt the COSE object.
*
* Requires in COSE object as appropriate
* alg (already set)
* key (sender key)
* nonce (already set)
* aad (already set)
* plaintext
*/
cose_encrypt0_set_key(cose, snd_ctx->sender_key);
cose_encrypt0_set_plaintext(cose, plain_pdu->token, plain_pdu->used_size);
dump_cose(cose, "Pre encrypt");
ciphertext_buffer =
coap_malloc_type(COAP_OSCORE_BUF, OSCORE_CRYPTO_BUFFER_SIZE);
if (ciphertext_buffer == NULL)
goto error;
ciphertext_len = cose_encrypt0_encrypt(cose,
ciphertext_buffer,
plain_pdu->used_size + AES_CCM_TAG);
if ((int)ciphertext_len <= 0) {
coap_log_warn("OSCORE: Encryption Failure, result code: %d \n",
(int)ciphertext_len);
goto error;
}
assert(ciphertext_len < OSCORE_CRYPTO_BUFFER_SIZE);
/* Add in OSCORE option (previously computed) */
if (!coap_insert_option(osc_pdu,
COAP_OPTION_OSCORE,
oscore_option_len,
oscore_option))
goto error;
/* Add now encrypted payload */
if (!coap_add_data(osc_pdu, ciphertext_len, ciphertext_buffer))
goto error;
coap_free_type(COAP_OSCORE_BUF, ciphertext_buffer);
ciphertext_buffer = NULL;
coap_delete_pdu(plain_pdu);
plain_pdu = NULL;
if (association && association->is_observe == 0)
oscore_delete_association(session, association);
association = NULL;
/*
* If this is a response ACK with data, make it a separate response
* by sending an Empty ACK and changing osc_pdu's MID and type. This
* then allows lost response ACK (now CON) with data to be recovered.
*/
if (coap_request == 0 && osc_pdu->type == COAP_MESSAGE_ACK &&
COAP_RESPONSE_CLASS(pdu->code) == 2 &&
COAP_PROTO_NOT_RELIABLE(session->proto)) {
coap_pdu_t *empty = coap_pdu_init(COAP_MESSAGE_ACK,
0,
osc_pdu->mid,
0);
if (empty) {
if (coap_send_internal(session, empty) != COAP_INVALID_MID) {
osc_pdu->mid = coap_new_message_id_lkd(session);
osc_pdu->type = COAP_MESSAGE_CON;
}
}
}
if (!coap_pdu_encode_header(osc_pdu, session->proto)) {
goto error;
}
/*
* Set up an association for handling a response if this is a request
*/
if (coap_request) {
association = oscore_find_association(session, &pdu_token);
if (association) {
if (doing_observe && observe_value == 1) {
association->is_observe = 0;
}
/* Refresh the association */
coap_delete_bin_const(association->nonce);
association->nonce =
coap_new_bin_const(cose->nonce.s, cose->nonce.length);
if (association->nonce == NULL)
goto error;
coap_delete_bin_const(association->aad);
association->aad = coap_new_bin_const(cose->aad.s, cose->aad.length);
if (association->aad == NULL)
goto error;
coap_delete_bin_const(association->partial_iv);
association->partial_iv =
coap_new_bin_const(cose->partial_iv.s, cose->partial_iv.length);
if (association->partial_iv == NULL)
goto error;
association->recipient_ctx = rcp_ctx;
coap_delete_pdu(association->sent_pdu);
if (session->b_2_step != COAP_OSCORE_B_2_NONE && !session->done_b_1_2) {
size_t size;
association->sent_pdu = coap_pdu_duplicate_lkd(pdu, session,
pdu_token.length,
pdu_token.s, NULL);
if (association->sent_pdu == NULL)
goto error;
if (coap_get_data(pdu, &size, &data)) {
coap_add_data(association->sent_pdu, size, data);
}
} else {
association->sent_pdu = NULL;
}
} else if (!oscore_new_association(session,
pdu,
&pdu_token,
rcp_ctx,
&cose->aad,
&cose->nonce,
&cose->partial_iv,
doing_observe)) {
goto error;
}
session->done_b_1_2 = 1;
}
return osc_pdu;
error:
if (ciphertext_buffer)
coap_free_type(COAP_OSCORE_BUF, ciphertext_buffer);
coap_delete_pdu(osc_pdu);
coap_delete_pdu(plain_pdu);
return NULL;
}
static void
build_and_send_error_pdu(coap_session_t *session,
coap_pdu_t *rcvd,
coap_pdu_code_t code,
const char *diagnostic,
uint8_t *echo_data,
coap_bin_const_t *kid_context,
int encrypt_oscore) {
coap_pdu_t *err_pdu = NULL;
coap_bin_const_t token;
int oscore_encryption = session->oscore_encryption;
unsigned char buf[4];
token = coap_pdu_get_token(rcvd);
err_pdu = coap_pdu_init(rcvd->type == COAP_MESSAGE_NON ? COAP_MESSAGE_NON :
COAP_MESSAGE_ACK,
code,
rcvd->mid,
token.length + 2 + 8 +
(diagnostic ? strlen(diagnostic) : 0));
if (!err_pdu)
return;
coap_add_token(err_pdu, token.length, token.s);
if (echo_data) {
coap_add_option_internal(err_pdu, COAP_OPTION_ECHO, 8, echo_data);
} else if (kid_context == NULL) {
coap_add_option_internal(err_pdu,
COAP_OPTION_MAXAGE,
coap_encode_var_safe(buf, sizeof(buf), 0),
buf);
}
if (diagnostic)
coap_add_data(err_pdu, strlen(diagnostic), (const uint8_t *)diagnostic);
session->oscore_encryption = encrypt_oscore;
if ((echo_data || kid_context) && encrypt_oscore) {
coap_pdu_t *osc_pdu;
osc_pdu =
coap_oscore_new_pdu_encrypted_lkd(session, err_pdu, kid_context,
echo_data ? 1 : 0);
if (!osc_pdu)
goto fail_resp;
session->oscore_encryption = 0;
coap_send_internal(session, osc_pdu);
coap_delete_pdu(err_pdu);
err_pdu = NULL;
} else {
coap_send_internal(session, err_pdu);
err_pdu = NULL;
}
fail_resp:
session->oscore_encryption = oscore_encryption;
coap_delete_pdu(err_pdu);
return;
}
/* pdu contains incoming message with encrypted COSE ciphertext payload
* function returns decrypted message
* and verifies signature, if present
* returns NULL when decryption,verification fails
*/
coap_pdu_t *
coap_oscore_decrypt_pdu(coap_session_t *session,
coap_pdu_t *pdu) {
coap_pdu_t *decrypt_pdu = NULL;
coap_pdu_t *plain_pdu = NULL;
const uint8_t *osc_value; /* value of OSCORE option */
uint8_t osc_size; /* size of OSCORE OPTION */
coap_opt_iterator_t opt_iter;
coap_opt_t *opt = NULL;
cose_encrypt0_t cose[1];
oscore_ctx_t *osc_ctx = NULL;
uint8_t aad_buffer[AAD_BUF_LEN];
uint8_t nonce_buffer[13];
coap_bin_const_t aad;
coap_bin_const_t nonce;
int pltxt_size = 0;
uint8_t coap_request = COAP_PDU_IS_REQUEST(pdu);
coap_bin_const_t pdu_token;
uint8_t *st_encrypt;
size_t encrypt_len;
size_t tag_len;
oscore_recipient_ctx_t *rcp_ctx = NULL;
oscore_association_t *association = NULL;
uint8_t external_aad_buffer[100];
coap_bin_const_t external_aad;
oscore_sender_ctx_t *snd_ctx = NULL;
#if COAP_CLIENT_SUPPORT
coap_pdu_t *sent_pdu = NULL;
#endif /* COAP_CLIENT_SUPPORT */
opt = coap_check_option(pdu, COAP_OPTION_OSCORE, &opt_iter);
assert(opt);
if (opt == NULL)
return NULL;
if (session->context->p_osc_ctx == NULL) {
coap_log_warn("OSCORE: Not enabled\n");
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_NOT_ENABLED,
session);
return NULL;
}
if (pdu->data == NULL) {
coap_log_warn("OSCORE: No protected payload\n");
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD,
session);
return NULL;
}
osc_size = coap_opt_length(opt);
osc_value = coap_opt_value(opt);
cose_encrypt0_init(cose); /* clear cose memory */
/* PDU code will be filled in after decryption */
decrypt_pdu =
coap_pdu_init(pdu->type, 0, pdu->mid, pdu->used_size);
if (decrypt_pdu == NULL) {
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_INTERNAL_ERROR,
session);
goto error;
}
/* Copy across the Token */
pdu_token = coap_pdu_get_token(pdu);
coap_add_token(decrypt_pdu, pdu_token.length, pdu_token.s);
/*
* 8.2/8.4 Step 1.
* Copy outer options across, except E and OSCORE options
*/
coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
while ((opt = coap_option_next(&opt_iter))) {
switch (opt_iter.number) {
/* 'E' options skipped */
case COAP_OPTION_IF_MATCH:
case COAP_OPTION_ETAG:
case COAP_OPTION_IF_NONE_MATCH:
case COAP_OPTION_OBSERVE:
case COAP_OPTION_LOCATION_PATH:
case COAP_OPTION_URI_PATH:
case COAP_OPTION_CONTENT_FORMAT:
case COAP_OPTION_MAXAGE:
case COAP_OPTION_URI_QUERY:
case COAP_OPTION_ACCEPT:
case COAP_OPTION_LOCATION_QUERY:
case COAP_OPTION_BLOCK2:
case COAP_OPTION_BLOCK1:
case COAP_OPTION_SIZE2:
case COAP_OPTION_SIZE1:
case COAP_OPTION_NORESPONSE:
case COAP_OPTION_ECHO:
case COAP_OPTION_RTAG:
/* OSCORE does not get copied across */
case COAP_OPTION_OSCORE:
break;
default:
if (!coap_add_option_internal(decrypt_pdu,
opt_iter.number,
coap_opt_length(opt),
coap_opt_value(opt))) {
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_INTERNAL_ERROR,
session);
goto error;
}
break;
}
}
if (coap_request) {
uint64_t incoming_seq;
/*
* 8.2 Step 2
* Decompress COSE object
* Get Recipient Context based on kid and optional kid_context
*/
if (oscore_decode_option_value(osc_value, osc_size, cose) == 0) {
coap_log_warn("OSCORE: OSCORE Option cannot be decoded.\n");
build_and_send_error_pdu(session,
pdu,
COAP_RESPONSE_CODE(402),
"Failed to decode COSE",
NULL,
NULL,
0);
goto error_no_ack;
}
osc_ctx = oscore_find_context(session->context,
cose->key_id,
&cose->kid_context,
NULL,
&rcp_ctx);
if (!osc_ctx) {
if (cose->kid_context.length > 0) {
const uint8_t *ptr;
size_t length;
/* Appendix B.2 protocol check - Is the recipient key_id known */
osc_ctx = oscore_find_context(session->context,
cose->key_id,
NULL,
session->oscore_r2 != 0 ? (uint8_t *)&session->oscore_r2 : NULL,
&rcp_ctx);
ptr = cose->kid_context.s;
length = cose->kid_context.length;
if (ptr && osc_ctx && osc_ctx->rfc8613_b_2 &&
osc_ctx->mode == OSCORE_MODE_SINGLE) {
/* Processing Appendix B.2 protocol */
/* Need to CBOR unwrap kid_context */
coap_bin_const_t kid_context;
kid_context.length = oscore_cbor_get_element_size(&ptr, &length);
kid_context.s = ptr;
cose_encrypt0_set_kid_context(cose, (coap_bin_const_t *)&kid_context);
if (session->oscore_r2 != 0) {
/* B.2 step 4 */
coap_bin_const_t *kc = coap_new_bin_const(cose->kid_context.s,
cose->kid_context.length);
if (kc == NULL)
goto error;
session->b_2_step = COAP_OSCORE_B_2_STEP_4;
coap_log_oscore("Appendix B.2 server step 4 (R2 || R3)\n");
oscore_update_ctx(osc_ctx, kc);
} else {
session->b_2_step = COAP_OSCORE_B_2_STEP_2;
coap_log_oscore("Appendix B.2 server step 2 (ID1)\n");
osc_ctx = oscore_duplicate_ctx(session->context,
osc_ctx,
osc_ctx->sender_context->sender_id,
&cose->key_id,
&cose->kid_context);
if (osc_ctx == NULL)
goto error;
/*
* Complete the Verify (B.2 step 2)
* before sending back the response
*/
rcp_ctx = osc_ctx->recipient_chain;
}
} else {
osc_ctx = NULL;
}
}
} else if (session->b_2_step != COAP_OSCORE_B_2_NONE) {
session->b_2_step = COAP_OSCORE_B_2_NONE;
coap_log_oscore("Appendix B.2 server finished\n");
}
if (!osc_ctx) {
coap_log_crit("OSCORE: Security Context not found\n");
oscore_log_hex_value(COAP_LOG_OSCORE, "key_id", &cose->key_id);
oscore_log_hex_value(COAP_LOG_OSCORE, "kid_context", &cose->kid_context);
build_and_send_error_pdu(session,
pdu,
COAP_RESPONSE_CODE(401),
"Security context not found",
NULL,
NULL,
0);
goto error_no_ack;
}
/* to be used for encryption of returned response later */
session->recipient_ctx = rcp_ctx;
snd_ctx = osc_ctx->sender_context;
/*
* 8.2 Step 3.
* Verify Partial IV is not duplicated.
*
* Requires in COSE object as appropriate
* partial_iv (as received)
*/
if (rcp_ctx->initial_state == 0 &&
!oscore_validate_sender_seq(rcp_ctx, cose)) {
coap_log_warn("OSCORE: Replayed or old message\n");
build_and_send_error_pdu(session,
pdu,
COAP_RESPONSE_CODE(401),
"Replay detected",
NULL,
NULL,
0);
goto error_no_ack;
}
incoming_seq =
coap_decode_var_bytes8(cose->partial_iv.s, cose->partial_iv.length);
rcp_ctx->last_seq = incoming_seq;
} else { /* !coap_request */
/*
* 8.4 Step 2
* Decompress COSE object
* Get Recipient Context based on token
*/
if (oscore_decode_option_value(osc_value, osc_size, cose) == 0) {
coap_log_warn("OSCORE: OSCORE Option cannot be decoded.\n");
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_DECODE_ERROR,
session);
goto error;
}
association = oscore_find_association(session, &pdu_token);
if (association) {
rcp_ctx = association->recipient_ctx;
osc_ctx = rcp_ctx->osc_ctx;
snd_ctx = osc_ctx->sender_context;
#if COAP_CLIENT_SUPPORT
sent_pdu = association->sent_pdu;
if (session->b_2_step != COAP_OSCORE_B_2_NONE) {
const uint8_t *ptr = cose->kid_context.s;
size_t length = cose->kid_context.length;
if (ptr) {
/* Need to CBOR unwrap kid_context */
coap_bin_const_t kid_context;
kid_context.length = oscore_cbor_get_element_size(&ptr, &length);
kid_context.s = ptr;
cose_encrypt0_set_kid_context(cose, &kid_context);
}
if (ptr && !coap_binary_equal(osc_ctx->id_context, &cose->kid_context)) {
/* If Appendix B.2 step 3 is in operation */
/* Need to update Security Context with new (R2 || ID1) ID Context */
coap_binary_t *kc = coap_new_binary(cose->kid_context.length +
osc_ctx->id_context->length);
if (kc == NULL) {
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_INTERNAL_ERROR,
session);
goto error;
}
memcpy(kc->s, cose->kid_context.s, cose->kid_context.length);
memcpy(&kc->s[cose->kid_context.length],
osc_ctx->id_context->s,
osc_ctx->id_context->length);
session->b_2_step = COAP_OSCORE_B_2_STEP_3;
coap_log_oscore("Appendix B.2 client step 3 (R2 || ID1)\n");
oscore_update_ctx(osc_ctx, (coap_bin_const_t *)kc);
} else {
session->b_2_step = COAP_OSCORE_B_2_STEP_5;
coap_log_oscore("Appendix B.2 client step 5 (R2 || R3)\n");
}
}
#endif /* COAP_CLIENT_SUPPORT */
} else {
coap_log_crit("OSCORE: Security Context association not found\n");
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_NO_SECURITY,
session);
goto error;
}
}
cose_encrypt0_set_alg(cose, osc_ctx->aead_alg);
if (coap_request) {
/*
* RFC8613 8.2 Step 4.
* Compose the External AAD and then AAD
*
* Non Group (based on osc_tx->mode) requires the following
* aead_alg (osc_ctx)
* request_kid (request key_id using cose)
* request_piv (request partial_iv using cose)
* options (none at present)
* Group (based on osc_tx->mode) requires the following
* aead_alg (osc_ctx) (pairwise mode)
* sign_enc_alg (osc_ctx) (group mode)
* sign_alg (osc_ctx) (group mode)
* alg_pairwise_key_agreement (osc_ctx) (pairwise mode)
* request_kid (request key_id using cose)
* request_piv (request partial_iv using cose)
* options (none at present)
* request_kid_context (osc_ctx id_context)
* OSCORE_option (as received in request)
* test_gs_public_key (recipient public key)
* gm_public_key (osc_ctx gm_public_key)
*
* Note: No I options at present
*/
/* External AAD */
external_aad.s = external_aad_buffer;
external_aad.length = oscore_prepare_e_aad(osc_ctx,
cose,
osc_value,
osc_size,
NULL,
external_aad_buffer,
sizeof(external_aad_buffer));
cose_encrypt0_set_external_aad(cose, &external_aad);
/* AAD */
aad.s = aad_buffer;
aad.length = oscore_prepare_aad(external_aad_buffer,
external_aad.length,
aad_buffer,
sizeof(aad_buffer));
assert(aad.length < AAD_BUF_LEN);
cose_encrypt0_set_aad(cose, &aad);
/*
* RFC8613 8.2 Step 5.
* Compute the AEAD nonce.
*
* Requires in COSE object as appropriate
* key_id (kid) (Recipient ID)
* partial_iv (as received in request)
* common_iv (already in osc_ctx)
*/
nonce.s = nonce_buffer;
nonce.length = 13;
oscore_generate_nonce(cose, osc_ctx, nonce_buffer, 13);
cose_encrypt0_set_nonce(cose, &nonce);
/*
* Set up an association for use in the response
*/
association = oscore_find_association(session, &pdu_token);
if (association) {
/* Refresh the association */
coap_delete_bin_const(association->nonce);
association->nonce =
coap_new_bin_const(cose->nonce.s, cose->nonce.length);
if (association->nonce == NULL)
goto error;
coap_delete_bin_const(association->partial_iv);
association->partial_iv =
coap_new_bin_const(cose->partial_iv.s, cose->partial_iv.length);
if (association->partial_iv == NULL)
goto error;
coap_delete_bin_const(association->aad);
association->aad = coap_new_bin_const(cose->aad.s, cose->aad.length);
if (association->aad == NULL)
goto error;
association->recipient_ctx = rcp_ctx;
} else if (!oscore_new_association(session,
NULL,
&pdu_token,
rcp_ctx,
&cose->aad,
&cose->nonce,
&cose->partial_iv,
0)) {
goto error;
}
/* So association is not released when handling decrypt */
association = NULL;
} else { /* ! coap_request */
/* Need to do nonce before AAD because of different partial_iv */
/*
* 8.4 Step 4.
* Compose the AEAD nonce.
*/
cose_encrypt0_set_key_id(cose, rcp_ctx->recipient_id);
if (cose->partial_iv.length == 0) {
cose_encrypt0_set_partial_iv(cose, association->partial_iv);
cose_encrypt0_set_nonce(cose, association->nonce);
} else {
uint64_t last_seq;
if (rcp_ctx->initial_state == 0 &&
!oscore_validate_sender_seq(rcp_ctx, cose)) {
coap_log_warn("OSCORE: Replayed or old message\n");
goto error;
}
last_seq =
coap_decode_var_bytes8(cose->partial_iv.s, cose->partial_iv.length);
if (rcp_ctx->last_seq>= OSCORE_SEQ_MAX) {
coap_log_warn("OSCORE Replay protection, SEQ larger than SEQ_MAX.\n");
goto error;
}
if (last_seq > rcp_ctx->last_seq)
rcp_ctx->last_seq = last_seq;
/*
* Requires in COSE object as appropriate
* kid (set above)
* partial_iv (as received)
* common_iv (already in osc_ctx)
*/
oscore_generate_nonce(cose, osc_ctx, nonce_buffer, 13);
nonce.s = nonce_buffer;
nonce.length = 13;
cose_encrypt0_set_nonce(cose, &nonce);
}
#ifdef OSCORE_EXTRA_DEBUG
dump_cose(cose, "!req post set nonce");
#endif /* OSCORE_EXTRA_DEBUG */
/*
* 8.4 Step 3.
* Compose the External AAD and then AAD (same as request non-group (5.4)
*
* Non Group (based on osc_tx->mode) requires the following
* aead_alg (osc_ctx)
* request_kid (request key_id using cose)
* request_piv (request partial_iv using cose)
* options (none at present)
* Group (based on osc_tx->mode) requires the following
* aead_alg (osc_ctx) (pairwise mode)
* sign_enc_alg (osc_ctx) (group mode)
* sign_alg (osc_ctx) (group mode)
* alg_pairwise_key_agreement (osc_ctx) (pairwise mode)
* request_kid (request key_id using cose)
* request_piv (request partial_iv using cose)
* options (none at present)
* request_kid_context (osc_ctx id_context)
* OSCORE_option (as received in request)
* test_gs_public_key (recipient public key)
* gm_public_key (osc_ctx gm_public_key)
*
* Note: No I options at present
*/
/* External AAD */
cose_encrypt0_set_key_id(cose, snd_ctx->sender_id);
cose_encrypt0_set_partial_iv(cose, association->partial_iv);
#ifdef OSCORE_EXTRA_DEBUG
dump_cose(cose, "!req pre aad");
#endif /* OSCORE_EXTRA_DEBUG */
external_aad.s = external_aad_buffer;
external_aad.length = oscore_prepare_e_aad(osc_ctx,
cose,
NULL,
0,
NULL,
external_aad_buffer,
sizeof(external_aad_buffer));
cose_encrypt0_set_external_aad(cose, &external_aad);
/* AAD */
aad.s = aad_buffer;
aad.length = oscore_prepare_aad(external_aad_buffer,
external_aad.length,
aad_buffer,
sizeof(aad_buffer));
assert(aad.length < AAD_BUF_LEN);
cose_encrypt0_set_aad(cose, &aad);
#ifdef OSCORE_EXTRA_DEBUG
dump_cose(cose, "!req post set aad");
#endif /* OSCORE_EXTRA_DEBUG */
}
/*
* 8.2 Step 6 / 8.4 Step 5.
* Decrypt the COSE object.
*
* Requires in COSE object as appropriate
* alg (already set)
* key
* nonce (already set)
* aad (already set)
* ciphertext
*/
st_encrypt = pdu->data;
encrypt_len = pdu->used_size - (pdu->data - pdu->token);
if (encrypt_len <= 0) {
coap_log_warn("OSCORE: No protected payload\n");
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD,
session);
goto error;
}
cose_encrypt0_set_key(cose, rcp_ctx->recipient_key);
cose_encrypt0_set_ciphertext(cose, st_encrypt, encrypt_len);
tag_len = cose_tag_len(cose->alg);
/* Decrypt into plain_pdu, so code (token), options and data are in place */
plain_pdu = coap_pdu_init(0, 0, 0, encrypt_len /* - tag_len */);
if (plain_pdu == NULL) {
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_INTERNAL_ERROR,
session);
goto error;
}
/* need the tag_len on the end for TinyDTLS to do its work - yuk */
if (!coap_pdu_resize(plain_pdu, encrypt_len /* - tag_len */)) {
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_INTERNAL_ERROR,
session);
goto error;
}
/* Account for 1 byte 'code' used as token */
plain_pdu->e_token_length = 1;
plain_pdu->actual_token.length = 1;
/* Account for the decrypted data */
plain_pdu->used_size = encrypt_len - tag_len;
dump_cose(cose, "Pre decrypt");
pltxt_size =
cose_encrypt0_decrypt(cose, plain_pdu->token, encrypt_len - tag_len);
if (pltxt_size <= 0) {
coap_log_warn("OSCORE: Decryption Failure, result code: %d \n",
(int)pltxt_size);
if (coap_request) {
build_and_send_error_pdu(session,
pdu,
COAP_RESPONSE_CODE(400),
"Decryption failed",
NULL,
NULL,
0);
oscore_roll_back_seq(rcp_ctx);
goto error_no_ack;
} else {
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_DECRYPTION_FAILURE,
session);
}
goto error;
}
assert((size_t)pltxt_size < pdu->alloc_size + pdu->max_hdr_size);
/* Appendix B.2 Trap */
if (session->b_2_step == COAP_OSCORE_B_2_STEP_2) {
/* Need to update Security Context with new (R2 || ID1) ID Context */
coap_binary_t *kc =
coap_new_binary(sizeof(session->oscore_r2) + cose->kid_context.length);
coap_bin_const_t oscore_r2;
if (kc == NULL) {
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_INTERNAL_ERROR,
session);
goto error;
}
coap_prng_lkd(&session->oscore_r2, sizeof(session->oscore_r2));
memcpy(kc->s, &session->oscore_r2, sizeof(session->oscore_r2));
memcpy(&kc->s[sizeof(session->oscore_r2)],
cose->kid_context.s,
cose->kid_context.length);
coap_log_oscore("Appendix B.2 server step 2 (R2 || ID1)\n");
oscore_update_ctx(osc_ctx, (coap_bin_const_t *)kc);
oscore_r2.length = sizeof(session->oscore_r2);
oscore_r2.s = (const uint8_t *)&session->oscore_r2;
coap_log_oscore("Appendix B.2 server step 2 plain response\n");
build_and_send_error_pdu(session,
pdu,
COAP_RESPONSE_CODE(401),
NULL,
NULL,
&oscore_r2,
1);
goto error_no_ack;
}
#if COAP_CLIENT_SUPPORT
if (session->b_2_step == COAP_OSCORE_B_2_STEP_3) {
coap_log_oscore("Appendix B.2 client step 3 (R2 || R3)\n");
coap_pdu_encode_header(plain_pdu, session->proto);
plain_pdu->actual_token.s = plain_pdu->token;
plain_pdu->code = plain_pdu->token[0];
if (plain_pdu->code != COAP_RESPONSE_CODE(401)) {
coap_log_warn("OSCORE Appendix B.2: Expected 4.01 response\n");
}
/* Skip the options */
coap_option_iterator_init(plain_pdu, &opt_iter, COAP_OPT_ALL);
while (coap_option_next(&opt_iter)) {
}
if (opt_iter.length > 0 && opt_iter.next_option &&
opt_iter.next_option[0] == COAP_PAYLOAD_START) {
plain_pdu->data = &opt_iter.next_option[1];
}
coap_log_oscore("Inner Response PDU (plaintext)\n");
coap_show_pdu(COAP_LOG_OSCORE, plain_pdu);
/*
* Need to update Security Context with new (R2 || R3) ID Context
* and retransmit the request
*/
coap_binary_t *kc = coap_new_binary(cose->kid_context.length + 8);
if (kc == NULL) {
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_INTERNAL_ERROR,
session);
goto error;
}
memcpy(kc->s, cose->kid_context.s, cose->kid_context.length);
coap_prng_lkd(&kc->s[cose->kid_context.length], 8);
oscore_update_ctx(osc_ctx, (coap_bin_const_t *)kc);
coap_cancel_all_messages(session->context,
session,
&pdu->actual_token);
if (session->con_active)
session->con_active--;
coap_send_ack_lkd(session, pdu);
if (sent_pdu) {
coap_log_oscore("Appendix B.2 retransmit pdu\n");
if (coap_retransmit_oscore_pdu(session, sent_pdu, NULL) ==
COAP_INVALID_MID)
goto error_no_ack;
}
goto error_no_ack;
}
#endif /* COAP_CLIENT_SUPPORT */
#if COAP_SERVER_SUPPORT
/* Appendix B.1.2 request Trap */
if (coap_request && osc_ctx->rfc8613_b_1_2) {
if (rcp_ctx->initial_state == 1) {
opt = coap_check_option(plain_pdu, COAP_OPTION_ECHO, &opt_iter);
if (opt) {
/* Verify Client is genuine */
if (coap_opt_length(opt) == 8 &&
memcmp(coap_opt_value(opt), rcp_ctx->echo_value, 8) == 0) {
if (!oscore_validate_sender_seq(rcp_ctx, cose)) {
coap_log_warn("OSCORE: Replayed or old message\n");
build_and_send_error_pdu(session,
pdu,
COAP_RESPONSE_CODE(401),
"Replay detected",
NULL,
NULL,
0);
goto error_no_ack;
}
} else
goto error;
} else {
/* RFC 8163 Appendix B.1.2 */
if (session->b_2_step == COAP_OSCORE_B_2_STEP_4) {
session->b_2_step = COAP_OSCORE_B_2_NONE;
coap_log_oscore("Appendix B.2 server finished\n");
}
coap_prng_lkd(rcp_ctx->echo_value, sizeof(rcp_ctx->echo_value));
coap_log_oscore("Appendix B.1.2 server plain response\n");
build_and_send_error_pdu(session,
pdu,
COAP_RESPONSE_CODE(401),
NULL,
rcp_ctx->echo_value,
NULL,
1);
goto error_no_ack;
}
}
}
#endif /* COAP_SERVER_SUPPORT */
/*
* 8.2 Step 7 / 8.4 Step 6.
* Add decrypted Code, options and payload
* [OSCORE option not copied across previously]
*/
/* PDU code is pseudo plain_pdu token */
decrypt_pdu->code = plain_pdu->token[0];
/* Copy inner decrypted options across */
coap_option_iterator_init(plain_pdu, &opt_iter, COAP_OPT_ALL);
while ((opt = coap_option_next(&opt_iter))) {
size_t len;
size_t bias;
switch (opt_iter.number) {
case COAP_OPTION_OSCORE:
break;
case COAP_OPTION_OBSERVE:
if (!coap_request) {
bias = cose->partial_iv.length > 3 ? cose->partial_iv.length - 3 : 0;
len = cose->partial_iv.length > 3 ? 3 : cose->partial_iv.length;
/* Make Observe option reflect last 3 bytes of partial_iv */
if (!coap_add_option_internal(
decrypt_pdu,
opt_iter.number,
len,
cose->partial_iv.s ? &cose->partial_iv.s[bias] : NULL)) {
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_INTERNAL_ERROR,
session);
goto error;
}
break;
}
association = oscore_find_association(session, &pdu_token);
if (association) {
association->is_observe = 1;
association = NULL;
}
/* Fall Through */
default:
if (!coap_insert_option(decrypt_pdu,
opt_iter.number,
coap_opt_length(opt),
coap_opt_value(opt))) {
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_INTERNAL_ERROR,
session);
goto error;
}
break;
}
}
/* Need to copy across any data */
if (opt_iter.length > 0 && opt_iter.next_option &&
opt_iter.next_option[0] == COAP_PAYLOAD_START) {
plain_pdu->data = &opt_iter.next_option[1];
if (!coap_add_data(decrypt_pdu,
plain_pdu->used_size -
(plain_pdu->data - plain_pdu->token),
plain_pdu->data)) {
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_INTERNAL_ERROR,
session);
goto error;
}
}
coap_delete_pdu(plain_pdu);
plain_pdu = NULL;
/* Make sure headers are correctly set up */
if (!coap_pdu_encode_header(decrypt_pdu, session->proto)) {
if (!coap_request)
coap_handle_event_lkd(session->context,
COAP_EVENT_OSCORE_INTERNAL_ERROR,
session);
goto error;
}
if (session->b_2_step != COAP_OSCORE_B_2_NONE) {
session->b_2_step = COAP_OSCORE_B_2_NONE;
coap_log_oscore("Appendix B.2 client finished\n");
}
#if COAP_CLIENT_SUPPORT
if (decrypt_pdu->code == COAP_RESPONSE_CODE(401) &&
(opt = coap_check_option(decrypt_pdu, COAP_OPTION_ECHO, &opt_iter))) {
/* Server is requesting Echo refresh check */
coap_cancel_all_messages(session->context,
session,
&pdu->actual_token);
if (session->con_active)
session->con_active--;
if (sent_pdu) {
coap_send_ack_lkd(session, pdu);
coap_log_debug("PDU requesting re-transmit\n");
coap_show_pdu(COAP_LOG_DEBUG, decrypt_pdu);
coap_log_oscore("RFC9175 retransmit pdu\n");
/* Do not care if this fails */
coap_retransmit_oscore_pdu(session, sent_pdu, opt);
goto error_no_ack;
}
}
#endif /* COAP_CLIENT_SUPPORT */
if (association && association->is_observe == 0)
oscore_delete_association(session, association);
return decrypt_pdu;
error:
coap_send_ack_lkd(session, pdu);
error_no_ack:
if (association && association->is_observe == 0)
oscore_delete_association(session, association);
coap_delete_pdu(decrypt_pdu);
coap_delete_pdu(plain_pdu);
return NULL;
}
typedef enum {
COAP_ENC_ASCII = 0x01,
COAP_ENC_HEX = 0x02,
COAP_ENC_INTEGER = 0x08,
COAP_ENC_TEXT = 0x10,
COAP_ENC_BOOL = 0x20,
COAP_ENC_LAST
} coap_oscore_coding_t;
#undef TEXT_MAPPING
#define TEXT_MAPPING(t, v) \
{ { sizeof(#t)-1, (const uint8_t *)#t }, v }
static struct coap_oscore_encoding_t {
coap_str_const_t name;
coap_oscore_coding_t encoding;
} oscore_encoding[] = {
TEXT_MAPPING(ascii, COAP_ENC_ASCII),
TEXT_MAPPING(hex, COAP_ENC_HEX),
TEXT_MAPPING(integer, COAP_ENC_INTEGER),
TEXT_MAPPING(text, COAP_ENC_TEXT),
TEXT_MAPPING(bool, COAP_ENC_BOOL),
{{0, NULL}, COAP_ENC_LAST}
};
typedef struct {
coap_oscore_coding_t encoding;
const char *encoding_name;
union {
int value_int;
coap_bin_const_t *value_bin;
coap_str_const_t value_str;
} u;
} oscore_value_t;
static uint8_t
hex2char(char c) {
assert(isxdigit(c));
if ('a' <= c && c <= 'f')
return c - 'a' + 10;
else if ('A' <= c && c <= 'F')
return c - 'A' + 10;
else
return c - '0';
}
/* Parse the hex into binary */
static coap_bin_const_t *
parse_hex_bin(const char *begin, const char *end) {
coap_binary_t *binary = NULL;
size_t i;
if ((end - begin) % 2 != 0)
goto bad_entry;
binary = coap_new_binary((end - begin) / 2);
if (binary == NULL)
goto bad_entry;
for (i = 0; (i < (size_t)(end - begin)) && isxdigit((u_char)begin[i]) &&
isxdigit((u_char)begin[i + 1]);
i += 2) {
binary->s[i / 2] = (hex2char(begin[i]) << 4) + hex2char(begin[i + 1]);
}
if (i != (size_t)(end - begin))
goto bad_entry;
return (coap_bin_const_t *)binary;
bad_entry:
coap_delete_binary(binary);
return NULL;
}
/*
* Break up each OSCORE Configuration line entry into the 3 parts which
* are comma separated
*
* keyword,encoding,value
*/
static int
get_split_entry(const char **start,
size_t size,
coap_str_const_t *keyword,
oscore_value_t *value) {
const char *begin = *start;
const char *end;
const char *kend;
const char *split;
size_t i;
size_t len;
retry:
kend = end = memchr(begin, '\n', size);
if (end == NULL)
return 0;
/* Track beginning of next line */
*start = end + 1;
if (end > begin && end[-1] == '\r')
end--;
if (begin[0] == '#' || (end - begin) == 0) {
/* Skip comment / blank line */
size -= kend - begin + 1;
begin = *start;
goto retry;
}
/* Get in the keyword */
split = memchr(begin, ',', end - begin);
if (split == NULL)
goto bad_entry;
keyword->s = (const uint8_t *)begin;
keyword->length = split - begin;
begin = split + 1;
if ((end - begin) == 0)
goto bad_entry;
/* Get in the encoding */
split = memchr(begin, ',', end - begin);
if (split == NULL)
goto bad_entry;
for (i = 0; oscore_encoding[i].name.s; i++) {
coap_str_const_t temp = { split - begin, (const uint8_t *)begin };
if (coap_string_equal(&temp, &oscore_encoding[i].name)) {
value->encoding = oscore_encoding[i].encoding;
value->encoding_name = (const char *)oscore_encoding[i].name.s;
break;
}
}
if (oscore_encoding[i].name.s == NULL)
goto bad_entry;
begin = split + 1;
if ((end - begin) == 0)
goto bad_entry;
/* Get in the keyword's value */
if (begin[0] == '"') {
split = memchr(&begin[1], '"', end - split - 1);
if (split == NULL)
goto bad_entry;
end = split;
begin++;
}
switch (value->encoding) {
case COAP_ENC_ASCII:
value->u.value_bin =
coap_new_bin_const((const uint8_t *)begin, end - begin);
break;
case COAP_ENC_HEX:
/* Parse the hex into binary */
value->u.value_bin = parse_hex_bin(begin, end);
if (value->u.value_bin == NULL)
goto bad_entry;
break;
case COAP_ENC_INTEGER:
value->u.value_int = atoi(begin);
break;
case COAP_ENC_TEXT:
value->u.value_str.s = (const uint8_t *)begin;
value->u.value_str.length = end - begin;
break;
case COAP_ENC_BOOL:
len = (size_t)(end - begin);
if (len == 4 && memcmp("true", begin, len) == 0)
value->u.value_int = 1;
else if (len == 5 && memcmp("false", begin, len) == 0)
value->u.value_int = 0;
else
goto bad_entry;
break;
case COAP_ENC_LAST:
default:
goto bad_entry;
}
return 1;
bad_entry:
coap_log_warn("oscore_conf: Unrecognized configuration entry '%.*s'\n",
(int)(end - begin),
begin);
return -1;
}
#undef CONFIG_ENTRY
#define CONFIG_ENTRY(n, e, t) \
{ { sizeof(#n)-1, (const uint8_t *)#n }, e, \
offsetof(coap_oscore_conf_t, n), t }
typedef struct oscore_text_mapping_t {
coap_str_const_t text;
int value;
} oscore_text_mapping_t;
/* Naming as per https://www.iana.org/assignments/cose/cose.xhtml#algorithms */
static oscore_text_mapping_t text_aead_alg[] = {
TEXT_MAPPING(AES-CCM-16-64-128, COSE_ALGORITHM_AES_CCM_16_64_128),
TEXT_MAPPING(AES-CCM-16-64-256, COSE_ALGORITHM_AES_CCM_16_64_256),
{{0, NULL}, 0}
};
static oscore_text_mapping_t text_hkdf_alg[] = {
TEXT_MAPPING(direct+HKDF-SHA-256, COSE_HKDF_ALG_HKDF_SHA_256),
{{0, NULL}, 0}
};
static struct oscore_config_t {
coap_str_const_t str_keyword;
coap_oscore_coding_t encoding;
size_t offset;
oscore_text_mapping_t *text_mapping;
} oscore_config[] = {
CONFIG_ENTRY(master_secret, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
CONFIG_ENTRY(master_salt, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
CONFIG_ENTRY(sender_id, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
CONFIG_ENTRY(id_context, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
CONFIG_ENTRY(recipient_id, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),
CONFIG_ENTRY(replay_window, COAP_ENC_INTEGER, NULL),
CONFIG_ENTRY(ssn_freq, COAP_ENC_INTEGER, NULL),
CONFIG_ENTRY(aead_alg, COAP_ENC_INTEGER | COAP_ENC_TEXT, text_aead_alg),
CONFIG_ENTRY(hkdf_alg, COAP_ENC_INTEGER | COAP_ENC_TEXT, text_hkdf_alg),
CONFIG_ENTRY(rfc8613_b_1_2, COAP_ENC_BOOL, NULL),
CONFIG_ENTRY(rfc8613_b_2, COAP_ENC_BOOL, NULL),
CONFIG_ENTRY(break_sender_key, COAP_ENC_BOOL, NULL),
CONFIG_ENTRY(break_recipient_key, COAP_ENC_BOOL, NULL),
};
int
coap_delete_oscore_conf(coap_oscore_conf_t *oscore_conf) {
uint32_t i;
if (oscore_conf == NULL)
return 0;
coap_delete_bin_const(oscore_conf->master_secret);
coap_delete_bin_const(oscore_conf->master_salt);
coap_delete_bin_const(oscore_conf->id_context);
coap_delete_bin_const(oscore_conf->sender_id);
for (i = 0; i < oscore_conf->recipient_id_count; i++) {
coap_delete_bin_const(oscore_conf->recipient_id[i]);
}
coap_free_type(COAP_STRING, oscore_conf->recipient_id);
coap_free_type(COAP_STRING, oscore_conf);
return 1;
}
static coap_oscore_conf_t *
coap_parse_oscore_conf_mem(coap_str_const_t conf_mem) {
const char *start = (const char *)conf_mem.s;
const char *end = start + conf_mem.length;
coap_str_const_t keyword;
oscore_value_t value;
coap_oscore_conf_t *oscore_conf;
int split_ok = -1;
oscore_conf = coap_malloc_type(COAP_STRING, sizeof(coap_oscore_conf_t));
if (oscore_conf == NULL)
return NULL;
memset(oscore_conf, 0, sizeof(coap_oscore_conf_t));
memset(&value, 0, sizeof(value));
/* Preset with defaults */
oscore_conf->replay_window = COAP_OSCORE_DEFAULT_REPLAY_WINDOW;
oscore_conf->ssn_freq = 1;
oscore_conf->aead_alg = COSE_ALGORITHM_AES_CCM_16_64_128;
oscore_conf->hkdf_alg = COSE_HKDF_ALG_HKDF_SHA_256;
oscore_conf->rfc8613_b_1_2 = 1;
oscore_conf->rfc8613_b_2 = 0;
oscore_conf->break_sender_key = 0;
oscore_conf->break_recipient_key = 0;
while (end > start &&
(split_ok = get_split_entry(&start, end - start, &keyword, &value)) > 0) {
size_t i;
size_t j;
for (i = 0; i < sizeof(oscore_config) / sizeof(oscore_config[0]); i++) {
if (coap_string_equal(&oscore_config[i].str_keyword, &keyword) != 0 &&
value.encoding & oscore_config[i].encoding) {
if (coap_string_equal(coap_make_str_const("recipient_id"), &keyword)) {
if (value.u.value_bin->length > 7) {
coap_log_warn("oscore_conf: Maximum size of recipient_id is 7 bytes\n");
goto error_free_value_bin;
}
/* Special case as there are potentially multiple entries */
oscore_conf->recipient_id =
coap_realloc_type(COAP_STRING,
oscore_conf->recipient_id,
sizeof(oscore_conf->recipient_id[0]) *
(oscore_conf->recipient_id_count + 1));
if (oscore_conf->recipient_id == NULL) {
goto error_free_value_bin;
}
oscore_conf->recipient_id[oscore_conf->recipient_id_count++] =
value.u.value_bin;
} else {
coap_bin_const_t *unused_check;
switch (value.encoding) {
case COAP_ENC_HEX:
case COAP_ENC_ASCII:
memcpy(&unused_check,
&(((char *)oscore_conf)[oscore_config[i].offset]),
sizeof(unused_check));
if (unused_check != NULL) {
coap_log_warn("oscore_conf: Keyword '%.*s' duplicated\n",
(int)keyword.length,
(const char *)keyword.s);
goto error;
}
memcpy(&(((char *)oscore_conf)[oscore_config[i].offset]),
&value.u.value_bin,
sizeof(value.u.value_bin));
break;
case COAP_ENC_INTEGER:
case COAP_ENC_BOOL:
memcpy(&(((char *)oscore_conf)[oscore_config[i].offset]),
&value.u.value_int,
sizeof(value.u.value_int));
break;
case COAP_ENC_TEXT:
for (j = 0; oscore_config[i].text_mapping[j].text.s != NULL; j++) {
if (coap_string_equal(&value.u.value_str,
&oscore_config[i].text_mapping[j].text)) {
memcpy(&(((char *)oscore_conf)[oscore_config[i].offset]),
&oscore_config[i].text_mapping[j].value,
sizeof(oscore_config[i].text_mapping[j].value));
break;
}
}
if (oscore_config[i].text_mapping[j].text.s == NULL) {
coap_log_warn("oscore_conf: Keyword '%.*s': value '%.*s' unknown\n",
(int)keyword.length,
(const char *)keyword.s,
(int)value.u.value_str.length,
(const char *)value.u.value_str.s);
goto error;
}
break;
case COAP_ENC_LAST:
default:
assert(0);
break;
}
}
break;
}
}
if (i == sizeof(oscore_config) / sizeof(oscore_config[0])) {
coap_log_warn("oscore_conf: Keyword '%.*s', type '%s' unknown\n",
(int)keyword.length,
(const char *)keyword.s,
value.encoding_name);
if (value.encoding == COAP_ENC_HEX || value.encoding == COAP_ENC_ASCII)
coap_delete_bin_const(value.u.value_bin);
goto error;
}
}
if (split_ok == -1)
goto error;
if (!oscore_conf->master_secret) {
coap_log_warn("oscore_conf: master_secret not defined\n");
goto error;
}
if (!oscore_conf->sender_id) {
coap_log_warn("oscore_conf: sender_id not defined\n");
goto error;
}
if (oscore_conf->sender_id->length > 7) {
coap_log_warn("oscore_conf: Maximum size of sender_id is 7 bytes\n");
goto error;
}
if (oscore_conf->recipient_id && oscore_conf->recipient_id[0]->length > 7) {
coap_log_warn("oscore_conf: Maximum size of recipient_id is 7 bytes\n");
goto error;
}
return oscore_conf;
error_free_value_bin:
coap_delete_bin_const(value.u.value_bin);
error:
coap_delete_oscore_conf(oscore_conf);
return NULL;
}
static oscore_ctx_t *
coap_oscore_init(coap_context_t *c_context, coap_oscore_conf_t *oscore_conf) {
oscore_ctx_t *osc_ctx = NULL;
if (!coap_crypto_check_cipher_alg(oscore_conf->aead_alg)) {
coap_log_warn("COSE: Cipher Algorithm %d not supported\n",
oscore_conf->aead_alg);
goto error;
}
if (!coap_crypto_check_hkdf_alg(oscore_conf->hkdf_alg)) {
coap_log_warn("COSE: HKDF Algorithm %d not supported\n",
oscore_conf->hkdf_alg);
goto error;
}
osc_ctx = oscore_derive_ctx(c_context, oscore_conf);
if (!osc_ctx) {
coap_log_crit("OSCORE: Could not create Security Context!\n");
goto error;
}
/* Free off the recipient_id array */
coap_free_type(COAP_STRING, oscore_conf->recipient_id);
oscore_conf->recipient_id = NULL;
/* As all is stored in osc_ctx, oscore_conf is no longer needed */
coap_free_type(COAP_STRING, oscore_conf);
/* return default first context */
return osc_ctx;
error:
/* Remove from linked chain */
oscore_remove_context(c_context, osc_ctx);
coap_delete_oscore_conf(oscore_conf);
return NULL;
}
void
coap_delete_all_oscore(coap_context_t *c_context) {
oscore_free_contexts(c_context);
}
void
coap_delete_oscore_associations(coap_session_t *session) {
oscore_delete_server_associations(session);
}
coap_oscore_conf_t *
coap_new_oscore_conf(coap_str_const_t conf_mem,
coap_oscore_save_seq_num_t save_seq_num_func,
void *save_seq_num_func_param,
uint64_t start_seq_num) {
coap_oscore_conf_t *oscore_conf = coap_parse_oscore_conf_mem(conf_mem);
if (oscore_conf == NULL)
return NULL;
oscore_conf->save_seq_num_func = save_seq_num_func;
oscore_conf->save_seq_num_func_param = save_seq_num_func_param;
oscore_conf->start_seq_num = start_seq_num;
coap_log_oscore("Start Seq no %" PRIu64 "\n", start_seq_num);
return oscore_conf;
}
/*
* Compute the size of the potential OSCORE overhead
*/
size_t
coap_oscore_overhead(coap_session_t *session, coap_pdu_t *pdu) {
size_t overhead = 0;
oscore_recipient_ctx_t *rcp_ctx = session->recipient_ctx;
oscore_ctx_t *osc_ctx = rcp_ctx ? rcp_ctx->osc_ctx : NULL;
coap_opt_iterator_t opt_iter;
coap_opt_t *option;
if (osc_ctx == NULL)
return 0;
/* Protected code held in inner PDU as token */
overhead += 1;
/* Observe option (creates inner and outer */
option = coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter);
if (option) {
/* Assume delta is small */
overhead += 2 + coap_opt_length(option);
}
/* Proxy URI option Split - covered by coap_rebuild_pdu_for_proxy () */
/* OSCORE option */
/* Option header */
overhead += 1 +
/* Partial IV (64 bits max)*/
8 +
/* kid context */
(osc_ctx->id_context ? osc_ctx->id_context->length : 0) +
/* kid */
osc_ctx->sender_context->sender_id->length;
/* AAD overhead */
overhead += AES_CCM_TAG;
/* End of options marker */
overhead += 1;
return overhead;
}
COAP_API int
coap_new_oscore_recipient(coap_context_t *context,
coap_bin_const_t *recipient_id) {
int ret;
coap_lock_lock(context, return 0);
ret = coap_new_oscore_recipient_lkd(context, recipient_id);
coap_lock_unlock(context);
return ret;
}
int
coap_new_oscore_recipient_lkd(coap_context_t *context,
coap_bin_const_t *recipient_id) {
coap_lock_check_locked(context);
if (context->p_osc_ctx == NULL)
return 0;
if (oscore_add_recipient(context->p_osc_ctx, recipient_id, 0) == NULL)
return 0;
return 1;
}
COAP_API int
coap_delete_oscore_recipient(coap_context_t *context,
coap_bin_const_t *recipient_id) {
int ret;
if (!context || !recipient_id)
return 0;
coap_lock_lock(context, return 0);
ret = coap_delete_oscore_recipient_lkd(context, recipient_id);
coap_lock_unlock(context);
return ret;
}
int
coap_delete_oscore_recipient_lkd(coap_context_t *context,
coap_bin_const_t *recipient_id) {
coap_lock_check_locked(context);
if (context->p_osc_ctx == NULL)
return 0;
return oscore_delete_recipient(context->p_osc_ctx, recipient_id);
}
#else /* !COAP_OSCORE_SUPPORT */
int
coap_oscore_is_supported(void) {
return 0;
}
coap_session_t *
coap_new_client_session_oscore(coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
coap_oscore_conf_t *oscore_conf) {
(void)ctx;
(void)local_if;
(void)server;
(void)proto;
(void)oscore_conf;
return NULL;
}
coap_session_t *
coap_new_client_session_oscore_psk(coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
coap_dtls_cpsk_t *psk_data,
coap_oscore_conf_t *oscore_conf) {
(void)ctx;
(void)local_if;
(void)server;
(void)proto;
(void)psk_data;
(void)oscore_conf;
return NULL;
}
coap_session_t *
coap_new_client_session_oscore_pki(coap_context_t *ctx,
const coap_address_t *local_if,
const coap_address_t *server,
coap_proto_t proto,
coap_dtls_pki_t *pki_data,
coap_oscore_conf_t *oscore_conf) {
(void)ctx;
(void)local_if;
(void)server;
(void)proto;
(void)pki_data;
(void)oscore_conf;
return NULL;
}
int
coap_context_oscore_server(coap_context_t *context,
coap_oscore_conf_t *oscore_conf) {
(void)context;
(void)oscore_conf;
return 0;
}
coap_oscore_conf_t *
coap_new_oscore_conf(coap_str_const_t conf_mem,
coap_oscore_save_seq_num_t save_seq_num_func,
void *save_seq_num_func_param,
uint64_t start_seq_num) {
(void)conf_mem;
(void)save_seq_num_func;
(void)save_seq_num_func_param;
(void)start_seq_num;
return NULL;
}
int
coap_delete_oscore_conf(coap_oscore_conf_t *oscore_conf) {
(void)oscore_conf;
return 0;
}
int
coap_new_oscore_recipient(coap_context_t *context,
coap_bin_const_t *recipient_id) {
(void)context;
(void)recipient_id;
return 0;
}
int
coap_delete_oscore_recipient(coap_context_t *context,
coap_bin_const_t *recipient_id) {
(void)context;
(void)recipient_id;
return 0;
}
#endif /* !COAP_OSCORE_SUPPORT */
PRIu64
#define PRIu64
Definition coap_internal.h:51
coap_libcoap_build.h
Library specific build wrapper for coap_internal.h.
COAP_API
#define COAP_API
Definition coap_libcoap_build.h:41
COAP_OSCORE_BUF
@ COAP_OSCORE_BUF
Definition coap_mem.h:66
COAP_STRING
@ COAP_STRING
Definition coap_mem.h:39
coap_realloc_type
void * coap_realloc_type(coap_memory_tag_t type, void *p, size_t size)
Reallocates a chunk p of bytes created by coap_malloc_type() or coap_realloc_type() and returns a poi...
coap_malloc_type
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
coap_free_type
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
coap_opt_t
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition coap_option.h:26
coap_uri_scheme_is_secure
static int coap_uri_scheme_is_secure(const coap_uri_t *uri)
Definition coap_uri.h:81
COAP_URI_SCHEME_LAST
@ COAP_URI_SCHEME_LAST
Definition coap_uri.h:37
coap_send_ack_lkd
coap_mid_t coap_send_ack_lkd(coap_session_t *session, const coap_pdu_t *request)
Sends an ACK message with code 0 for the specified request to dst.
Definition coap_net.c:986
coap_retransmit_oscore_pdu
coap_mid_t coap_retransmit_oscore_pdu(coap_session_t *session, coap_pdu_t *pdu, coap_opt_t *echo)
coap_prng_lkd
int coap_prng_lkd(void *buf, size_t len)
Fills buf with len random bytes using the default pseudo random number generator.
Definition coap_prng.c:178
coap_handle_event_lkd
int coap_handle_event_lkd(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
Definition coap_net.c:4358
coap_new_message_id_lkd
uint16_t coap_new_message_id_lkd(coap_session_t *session)
Returns a new message id and updates session->tx_mid accordingly.
Definition coap_session.c:1909
coap_send_internal
coap_mid_t coap_send_internal(coap_session_t *session, coap_pdu_t *pdu)
Sends a CoAP message to given peer.
Definition coap_net.c:1679
coap_cancel_all_messages
void coap_cancel_all_messages(coap_context_t *context, coap_session_t *session, coap_bin_const_t *token)
Cancels all outstanding messages for session session that have the specified token.
Definition coap_net.c:2616
COAP_OSCORE_DEFAULT_REPLAY_WINDOW
#define COAP_OSCORE_DEFAULT_REPLAY_WINDOW
Definition coap_crypto_internal.h:38
coap_crypto_check_hkdf_alg
int coap_crypto_check_hkdf_alg(cose_hkdf_alg_t hkdf_alg)
Check whether the defined hkdf algorithm is supported by the underlying crypto library.
coap_crypto_check_cipher_alg
int coap_crypto_check_cipher_alg(cose_alg_t alg)
Check whether the defined cipher algorithm is supported by the underlying crypto library.
coap_encode_var_safe
unsigned int coap_encode_var_safe(uint8_t *buf, size_t length, unsigned int val)
Encodes multiple-length byte sequences.
Definition coap_encode.c:47
coap_decode_var_bytes
unsigned int coap_decode_var_bytes(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition coap_encode.c:38
coap_decode_var_bytes8
uint64_t coap_decode_var_bytes8(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition coap_encode.c:67
coap_encode_var_safe8
unsigned int coap_encode_var_safe8(uint8_t *buf, size_t length, uint64_t val)
Encodes multiple-length byte sequences.
Definition coap_encode.c:77
COAP_EVENT_OSCORE_DECODE_ERROR
@ COAP_EVENT_OSCORE_DECODE_ERROR
Triggered when there is an OSCORE decode of OSCORE option failure.
Definition coap_event.h:118
COAP_EVENT_OSCORE_INTERNAL_ERROR
@ COAP_EVENT_OSCORE_INTERNAL_ERROR
Triggered when there is an OSCORE internal error i.e malloc failed.
Definition coap_event.h:116
COAP_EVENT_OSCORE_NOT_ENABLED
@ COAP_EVENT_OSCORE_NOT_ENABLED
Triggered when trying to use OSCORE to decrypt, but it is not enabled.
Definition coap_event.h:110
COAP_EVENT_OSCORE_NO_SECURITY
@ COAP_EVENT_OSCORE_NO_SECURITY
Triggered when there is no OSCORE security definition found.
Definition coap_event.h:114
COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD
@ COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD
Triggered when there is no OSCORE encrypted payload provided.
Definition coap_event.h:112
COAP_EVENT_OSCORE_DECRYPTION_FAILURE
@ COAP_EVENT_OSCORE_DECRYPTION_FAILURE
Triggered when there is an OSCORE decryption failure.
Definition coap_event.h:108
coap_lock_unlock
#define coap_lock_unlock(c)
Dummy for no thread-safe code.
Definition coap_threadsafe_internal.h:477
coap_lock_lock
#define coap_lock_lock(c, failed)
Dummy for no thread-safe code.
Definition coap_threadsafe_internal.h:465
coap_lock_check_locked
#define coap_lock_check_locked(c)
Dummy for no thread-safe code.
Definition coap_threadsafe_internal.h:491
coap_log_debug
#define coap_log_debug(...)
Definition coap_debug.h:120
coap_get_log_level
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition coap_debug.c:95
coap_show_pdu
void coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu)
Display the contents of the specified pdu.
Definition coap_debug.c:778
coap_log_oscore
#define coap_log_oscore(...)
Definition coap_debug.h:126
coap_log_warn
#define coap_log_warn(...)
Definition coap_debug.h:102
coap_log_crit
#define coap_log_crit(...)
Definition coap_debug.h:90
COAP_LOG_OSCORE
@ COAP_LOG_OSCORE
Definition coap_debug.h:59
COAP_LOG_DEBUG
@ COAP_LOG_DEBUG
Definition coap_debug.h:58
coap_option_next
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
Definition coap_option.c:153
coap_opt_length
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition coap_option.c:212
coap_option_iterator_init
coap_opt_iterator_t * coap_option_iterator_init(const coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t *filter)
Initializes the given option iterator oi to point to the beginning of the pdu's option list.
Definition coap_option.c:117
coap_delete_optlist
void coap_delete_optlist(coap_optlist_t *queue)
Removes all entries from the optlist_chain, freeing off their memory usage.
Definition coap_option.c:592
COAP_OPT_ALL
#define COAP_OPT_ALL
Pre-defined filter that includes all options.
Definition coap_option.h:108
coap_add_optlist_pdu
int coap_add_optlist_pdu(coap_pdu_t *pdu, coap_optlist_t **options)
The current optlist of optlist_chain is first sorted (as per RFC7272 ordering requirements) and then ...
Definition coap_option.c:551
coap_check_option
coap_opt_t * coap_check_option(const coap_pdu_t *pdu, coap_option_num_t number, coap_opt_iterator_t *oi)
Retrieves the first option of number number from pdu.
Definition coap_option.c:199
coap_opt_value
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition coap_option.c:249
oscore_cbor_get_element_size
size_t oscore_cbor_get_element_size(const uint8_t **buffer, size_t *buf_len)
Definition oscore_cbor.c:240
cose_encrypt0_set_plaintext
void cose_encrypt0_set_plaintext(cose_encrypt0_t *ptr, uint8_t *buffer, size_t size)
Definition oscore_cose.c:315
cose_encrypt0_set_key
int cose_encrypt0_set_key(cose_encrypt0_t *ptr, coap_bin_const_t *key)
Definition oscore_cose.c:401
cose_encrypt0_set_kid_context
void cose_encrypt0_set_kid_context(cose_encrypt0_t *ptr, coap_bin_const_t *kid_context)
Definition oscore_cose.c:368
cose_get_alg_name
const char * cose_get_alg_name(cose_alg_t id, char *buffer, size_t buflen)
Definition oscore_cose.c:120
cose_encrypt0_set_ciphertext
void cose_encrypt0_set_ciphertext(cose_encrypt0_t *ptr, uint8_t *buffer, size_t size)
Definition oscore_cose.c:307
cose_encrypt0_decrypt
int cose_encrypt0_decrypt(cose_encrypt0_t *ptr, uint8_t *plaintext_buffer, size_t plaintext_len)
Definition oscore_cose.c:460
cose_tag_len
size_t cose_tag_len(cose_alg_t cose_alg)
Definition oscore_cose.c:196
cose_encrypt0_set_aad
void cose_encrypt0_set_aad(cose_encrypt0_t *ptr, coap_bin_const_t *aad)
Definition oscore_cose.c:390
cose_encrypt0_encrypt
int cose_encrypt0_encrypt(cose_encrypt0_t *ptr, uint8_t *ciphertext_buffer, size_t ciphertext_len)
Definition oscore_cose.c:421
cose_encrypt0_set_partial_iv
void cose_encrypt0_set_partial_iv(cose_encrypt0_t *ptr, coap_bin_const_t *partial_iv)
Definition oscore_cose.c:325
cose_encrypt0_set_external_aad
void cose_encrypt0_set_external_aad(cose_encrypt0_t *ptr, coap_bin_const_t *external_aad)
Definition oscore_cose.c:379
cose_encrypt0_init
void cose_encrypt0_init(cose_encrypt0_t *ptr)
Definition oscore_cose.c:297
cose_encrypt0_set_alg
void cose_encrypt0_set_alg(cose_encrypt0_t *ptr, uint8_t alg)
Definition oscore_cose.c:302
cose_encrypt0_set_key_id
void cose_encrypt0_set_key_id(cose_encrypt0_t *ptr, coap_bin_const_t *key_id)
Definition oscore_cose.c:346
cose_encrypt0_set_nonce
void cose_encrypt0_set_nonce(cose_encrypt0_t *ptr, coap_bin_const_t *nonce)
Definition oscore_cose.c:411
COSE_HKDF_ALG_HKDF_SHA_256
@ COSE_HKDF_ALG_HKDF_SHA_256
Definition oscore_cose.h:167
COSE_ALGORITHM_AES_CCM_16_64_128
@ COSE_ALGORITHM_AES_CCM_16_64_128
Definition oscore_cose.h:145
COSE_ALGORITHM_AES_CCM_16_64_256
@ COSE_ALGORITHM_AES_CCM_16_64_256
Definition oscore_cose.h:146
coap_new_client_session_oscore_psk_lkd
coap_session_t * coap_new_client_session_oscore_psk_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_cpsk_t *psk_data, coap_oscore_conf_t *oscore_conf)
Creates a new client session to the designated server with PSK credentials as well as protecting the ...
oscore_prepare_aad
size_t oscore_prepare_aad(const uint8_t *external_aad_buffer, size_t external_aad_len, uint8_t *aad_buffer, size_t aad_size)
Definition oscore.c:312
oscore_encode_option_value
size_t oscore_encode_option_value(uint8_t *option_buffer, size_t option_buf_len, cose_encrypt0_t *cose, uint8_t group_flag, uint8_t appendix_b_2)
Definition oscore.c:170
coap_delete_oscore_recipient_lkd
int coap_delete_oscore_recipient_lkd(coap_context_t *context, coap_bin_const_t *recipient_id)
Release all the information associated for the specific Recipient ID (and hence and stop any further ...
oscore_delete_association
int oscore_delete_association(coap_session_t *session, oscore_association_t *association)
Definition oscore_context.c:756
oscore_validate_sender_seq
uint8_t oscore_validate_sender_seq(oscore_recipient_ctx_t *ctx, cose_encrypt0_t *cose)
Definition oscore.c:366
oscore_add_recipient
oscore_recipient_ctx_t * oscore_add_recipient(oscore_ctx_t *osc_ctx, coap_bin_const_t *rid, uint32_t break_key)
oscore_add_recipient - add in recipient information
Definition oscore_context.c:600
OSCORE_SEQ_MAX
#define OSCORE_SEQ_MAX
Definition oscore_context.h:72
AES_CCM_TAG
#define AES_CCM_TAG
Definition oscore_crypto.h:61
oscore_decode_option_value
int oscore_decode_option_value(const uint8_t *opt_value, size_t option_len, cose_encrypt0_t *cose)
Definition oscore.c:246
coap_oscore_new_pdu_encrypted_lkd
coap_pdu_t * coap_oscore_new_pdu_encrypted_lkd(coap_session_t *session, coap_pdu_t *pdu, coap_bin_const_t *kid_context, oscore_partial_iv_t send_partial_iv)
Encrypts the specified pdu when OSCORE encryption is required on session.
coap_new_client_session_oscore_lkd
coap_session_t * coap_new_client_session_oscore_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_oscore_conf_t *oscore_conf)
Creates a new client session to the designated server, protecting the data using OSCORE.
oscore_delete_recipient
int oscore_delete_recipient(oscore_ctx_t *osc_ctx, coap_bin_const_t *rid)
Definition oscore_context.c:654
oscore_increment_sender_seq
uint8_t oscore_increment_sender_seq(oscore_ctx_t *ctx)
Definition oscore.c:430
oscore_update_ctx
void oscore_update_ctx(oscore_ctx_t *osc_ctx, coap_bin_const_t *id_context)
oscore_update_ctx - update a osc_ctx with a new id_context
Definition oscore_context.c:387
oscore_derive_ctx
oscore_ctx_t * oscore_derive_ctx(coap_context_t *c_context, coap_oscore_conf_t *oscore_conf)
oscore_derive_ctx - derive a osc_ctx from oscore_conf information
Definition oscore_context.c:513
coap_oscore_new_pdu_encrypted
COAP_API coap_pdu_t * coap_oscore_new_pdu_encrypted(coap_session_t *session, coap_pdu_t *pdu, coap_bin_const_t *kid_context, oscore_partial_iv_t send_partial_iv)
Encrypts the specified pdu when OSCORE encryption is required on session.
oscore_roll_back_seq
void oscore_roll_back_seq(oscore_recipient_ctx_t *ctx)
Definition oscore.c:447
oscore_new_association
int oscore_new_association(coap_session_t *session, coap_pdu_t *sent_pdu, coap_bin_const_t *token, oscore_recipient_ctx_t *recipient_ctx, coap_bin_const_t *aad, coap_bin_const_t *nonce, coap_bin_const_t *partial_iv, int is_observe)
Definition oscore_context.c:686
oscore_prepare_e_aad
size_t oscore_prepare_e_aad(oscore_ctx_t *ctx, cose_encrypt0_t *cose, const uint8_t *oscore_option, size_t oscore_option_len, coap_bin_const_t *sender_public_key, uint8_t *external_aad_ptr, size_t external_aad_size)
Definition oscore.c:119
oscore_delete_server_associations
void oscore_delete_server_associations(coap_session_t *session)
Definition oscore_context.c:767
oscore_log_char_value
void oscore_log_char_value(coap_log_t level, const char *name, const char *value)
Definition oscore_context.c:268
coap_oscore_decrypt_pdu
struct coap_pdu_t * coap_oscore_decrypt_pdu(coap_session_t *session, coap_pdu_t *pdu)
Decrypts the OSCORE-encrypted parts of pdu when OSCORE is used.
coap_rebuild_pdu_for_proxy
int coap_rebuild_pdu_for_proxy(coap_pdu_t *pdu)
Convert PDU to use Proxy-Scheme option if Proxy-Uri option is present.
oscore_free_contexts
void oscore_free_contexts(coap_context_t *c_context)
Definition oscore_context.c:149
oscore_log_hex_value
void oscore_log_hex_value(coap_log_t level, const char *name, coap_bin_const_t *value)
Definition oscore_context.c:235
coap_delete_oscore_associations
void coap_delete_oscore_associations(coap_session_t *session)
Cleanup all allocated OSCORE association information.
coap_oscore_initiate
int coap_oscore_initiate(coap_session_t *session, coap_oscore_conf_t *oscore_conf)
Initiate an OSCORE session.
coap_new_oscore_recipient_lkd
int coap_new_oscore_recipient_lkd(coap_context_t *context, coap_bin_const_t *recipient_id)
Add in the specific Recipient ID into the OSCORE context (server only).
oscore_duplicate_ctx
oscore_ctx_t * oscore_duplicate_ctx(coap_context_t *c_context, oscore_ctx_t *o_osc_ctx, coap_bin_const_t *sender_id, coap_bin_const_t *recipient_id, coap_bin_const_t *id_context)
oscore_duplicate_ctx - duplicate a osc_ctx
Definition oscore_context.c:429
oscore_partial_iv_t
oscore_partial_iv_t
Definition coap_oscore_internal.h:63
coap_delete_all_oscore
void coap_delete_all_oscore(coap_context_t *context)
Cleanup all allocated OSCORE information.
oscore_generate_nonce
void oscore_generate_nonce(cose_encrypt0_t *ptr, oscore_ctx_t *ctx, uint8_t *buffer, uint8_t size)
Definition oscore.c:343
oscore_remove_context
int oscore_remove_context(coap_context_t *c_context, oscore_ctx_t *osc_ctx)
Definition oscore_context.c:160
oscore_find_association
oscore_association_t * oscore_find_association(coap_session_t *session, coap_bin_const_t *token)
Definition oscore_context.c:748
coap_context_oscore_server_lkd
int coap_context_oscore_server_lkd(coap_context_t *context, coap_oscore_conf_t *oscore_conf)
Set the context's default OSCORE configuration for a server.
oscore_find_context
oscore_ctx_t * oscore_find_context(const coap_context_t *c_context, const coap_bin_const_t rcpkey_id, const coap_bin_const_t *ctxkey_id, uint8_t *oscore_r2, oscore_recipient_ctx_t **recipient_ctx)
oscore_find_context - Locate recipient context (and hence OSCORE context)
Definition oscore_context.c:185
coap_new_client_session_oscore_pki_lkd
coap_session_t * coap_new_client_session_oscore_pki_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_pki_t *pki_data, coap_oscore_conf_t *oscore_conf)
Creates a new client session to the designated server with PKI credentials as well as protecting the ...
coap_oscore_overhead
size_t coap_oscore_overhead(coap_session_t *session, coap_pdu_t *pdu)
Determine the additional data size requirements for adding in OSCORE.
OSCORE_MODE_SINGLE
@ OSCORE_MODE_SINGLE
Vanilla RFC8613 support.
Definition oscore_context.h:75
OSCORE_SEND_PARTIAL_IV
@ OSCORE_SEND_PARTIAL_IV
Send partial IV with encrypted PDU.
Definition coap_oscore_internal.h:65
OSCORE_SEND_NO_IV
@ OSCORE_SEND_NO_IV
Do not send partial IV unless added by a response.
Definition coap_oscore_internal.h:64
coap_new_oscore_conf
coap_oscore_conf_t * coap_new_oscore_conf(coap_str_const_t conf_mem, coap_oscore_save_seq_num_t save_seq_num_func, void *save_seq_num_func_param, uint64_t start_seq_num)
Parse an OSCORE configuration (held in memory) and populate a OSCORE configuration structure.
Definition coap_oscore.c:2243
coap_new_client_session_oscore_psk
coap_session_t * coap_new_client_session_oscore_psk(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_cpsk_t *psk_data, coap_oscore_conf_t *oscore_conf)
Creates a new client session to the designated server with PSK credentials as well as protecting the ...
Definition coap_oscore.c:2203
coap_delete_oscore_conf
int coap_delete_oscore_conf(coap_oscore_conf_t *oscore_conf)
Release all the information associated with the OSCORE configuration.
Definition coap_oscore.c:2255
coap_new_client_session_oscore
coap_session_t * coap_new_client_session_oscore(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_oscore_conf_t *oscore_conf)
Creates a new client session to the designated server, protecting the data using OSCORE.
Definition coap_oscore.c:2189
coap_context_oscore_server
int coap_context_oscore_server(coap_context_t *context, coap_oscore_conf_t *oscore_conf)
Set the context's default OSCORE configuration for a server.
Definition coap_oscore.c:2235
coap_new_client_session_oscore_pki
coap_session_t * coap_new_client_session_oscore_pki(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_pki_t *pki_data, coap_oscore_conf_t *oscore_conf)
Creates a new client session to the designated server with PKI credentials as well as protecting the ...
Definition coap_oscore.c:2219
coap_new_oscore_recipient
int coap_new_oscore_recipient(coap_context_t *context, coap_bin_const_t *recipient_id)
Add in the specific Recipient ID into the OSCORE context (server only).
Definition coap_oscore.c:2261
coap_oscore_save_seq_num_t
int(* coap_oscore_save_seq_num_t)(uint64_t sender_seq_num, void *param)
Definition of the function used to save the current Sender Sequence Number.
Definition coap_oscore.h:130
coap_delete_oscore_recipient
int coap_delete_oscore_recipient(coap_context_t *context, coap_bin_const_t *recipient_id)
Release all the information associated for the specific Recipient ID (and hence and stop any further ...
Definition coap_oscore.c:2269
coap_insert_option
size_t coap_insert_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Inserts option of given number in the pdu with the appropriate data.
Definition coap_pdu.c:612
coap_remove_option
int coap_remove_option(coap_pdu_t *pdu, coap_option_num_t number)
Removes (first) option of given number from the pdu.
Definition coap_pdu.c:475
COAP_PDU_IS_PING
#define COAP_PDU_IS_PING(pdu)
Definition coap_pdu_internal.h:106
coap_pdu_encode_header
size_t coap_pdu_encode_header(coap_pdu_t *pdu, coap_proto_t proto)
Compose the protocol specific header for the specified PDU.
Definition coap_pdu.c:1476
coap_pdu_duplicate_lkd
coap_pdu_t * coap_pdu_duplicate_lkd(const coap_pdu_t *old_pdu, coap_session_t *session, size_t token_length, const uint8_t *token, coap_opt_filter_t *drop_options)
Duplicate an existing PDU.
Definition coap_pdu.c:214
COAP_PAYLOAD_START
#define COAP_PAYLOAD_START
Definition coap_pdu_internal.h:99
coap_pdu_resize
int coap_pdu_resize(coap_pdu_t *pdu, size_t new_size)
Dynamically grows the size of pdu to new_size.
Definition coap_pdu.c:281
COAP_PDU_IS_REQUEST
#define COAP_PDU_IS_REQUEST(pdu)
Definition coap_pdu_internal.h:102
coap_add_option_internal
size_t coap_add_option_internal(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Adds option of given number to pdu that is passed as first parameter.
Definition coap_pdu.c:767
COAP_OPTION_HOP_LIMIT
#define COAP_OPTION_HOP_LIMIT
Definition coap_pdu.h:133
COAP_OPTION_NORESPONSE
#define COAP_OPTION_NORESPONSE
Definition coap_pdu.h:145
COAP_OPTION_URI_HOST
#define COAP_OPTION_URI_HOST
Definition coap_pdu.h:120
COAP_OPTION_IF_MATCH
#define COAP_OPTION_IF_MATCH
Definition coap_pdu.h:119
COAP_OPTION_BLOCK2
#define COAP_OPTION_BLOCK2
Definition coap_pdu.h:137
COAP_OPTION_CONTENT_FORMAT
#define COAP_OPTION_CONTENT_FORMAT
Definition coap_pdu.h:128
COAP_OPTION_SIZE2
#define COAP_OPTION_SIZE2
Definition coap_pdu.h:139
COAP_OPTION_BLOCK1
#define COAP_OPTION_BLOCK1
Definition coap_pdu.h:138
COAP_OPTION_PROXY_SCHEME
#define COAP_OPTION_PROXY_SCHEME
Definition coap_pdu.h:142
COAP_DEFAULT_PORT
#define COAP_DEFAULT_PORT
Definition coap_pdu.h:37
COAP_OPTION_URI_QUERY
#define COAP_OPTION_URI_QUERY
Definition coap_pdu.h:132
coap_delete_pdu
void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and frees associated storage.
Definition coap_pdu.c:179
COAP_OPTION_IF_NONE_MATCH
#define COAP_OPTION_IF_NONE_MATCH
Definition coap_pdu.h:122
COAP_OPTION_LOCATION_PATH
#define COAP_OPTION_LOCATION_PATH
Definition coap_pdu.h:125
COAP_OPTION_URI_PATH
#define COAP_OPTION_URI_PATH
Definition coap_pdu.h:127
COAP_RESPONSE_CODE
#define COAP_RESPONSE_CODE(N)
Definition coap_pdu.h:160
COAP_RESPONSE_CLASS
#define COAP_RESPONSE_CLASS(C)
Definition coap_pdu.h:163
coap_proto_t
coap_proto_t
CoAP protocol types.
Definition coap_pdu.h:312
coap_pdu_code_t
coap_pdu_code_t
Set of codes available for a PDU.
Definition coap_pdu.h:326
COAP_OPTION_OSCORE
#define COAP_OPTION_OSCORE
Definition coap_pdu.h:126
COAP_OPTION_SIZE1
#define COAP_OPTION_SIZE1
Definition coap_pdu.h:143
coap_add_token
int coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds token of length len to pdu.
Definition coap_pdu.c:342
COAP_OPTION_LOCATION_QUERY
#define COAP_OPTION_LOCATION_QUERY
Definition coap_pdu.h:136
COAPS_DEFAULT_PORT
#define COAPS_DEFAULT_PORT
Definition coap_pdu.h:38
coap_get_data
int coap_get_data(const coap_pdu_t *pdu, size_t *len, const uint8_t **data)
Retrieves the length and data pointer of specified PDU.
Definition coap_pdu.c:863
COAP_OPTION_RTAG
#define COAP_OPTION_RTAG
Definition coap_pdu.h:146
COAP_OPTION_URI_PORT
#define COAP_OPTION_URI_PORT
Definition coap_pdu.h:124
coap_pdu_init
coap_pdu_t * coap_pdu_init(coap_pdu_type_t type, coap_pdu_code_t code, coap_mid_t mid, size_t size)
Creates a new CoAP PDU with at least enough storage space for the given size maximum message size.
Definition coap_pdu.c:97
COAP_OPTION_ACCEPT
#define COAP_OPTION_ACCEPT
Definition coap_pdu.h:134
COAP_INVALID_MID
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition coap_pdu.h:266
COAP_OPTION_MAXAGE
#define COAP_OPTION_MAXAGE
Definition coap_pdu.h:131
COAP_OPTION_ETAG
#define COAP_OPTION_ETAG
Definition coap_pdu.h:121
COAP_OPTION_PROXY_URI
#define COAP_OPTION_PROXY_URI
Definition coap_pdu.h:141
COAP_OPTION_OBSERVE
#define COAP_OPTION_OBSERVE
Definition coap_pdu.h:123
COAP_OPTION_ECHO
#define COAP_OPTION_ECHO
Definition coap_pdu.h:144
coap_add_data
int coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds given data to the pdu that is passed as first parameter.
Definition coap_pdu.c:832
coap_pdu_get_token
coap_bin_const_t coap_pdu_get_token(const coap_pdu_t *pdu)
Gets the token associated with pdu.
Definition coap_pdu.c:1596
COAP_REQUEST_CODE_POST
@ COAP_REQUEST_CODE_POST
Definition coap_pdu.h:330
COAP_REQUEST_CODE_FETCH
@ COAP_REQUEST_CODE_FETCH
Definition coap_pdu.h:333
COAP_MESSAGE_NON
@ COAP_MESSAGE_NON
Definition coap_pdu.h:70
COAP_MESSAGE_ACK
@ COAP_MESSAGE_ACK
Definition coap_pdu.h:71
COAP_MESSAGE_CON
@ COAP_MESSAGE_CON
Definition coap_pdu.h:69
coap_new_client_session_psk2_lkd
coap_session_t * coap_new_client_session_psk2_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_cpsk_t *setup_data)
Creates a new client session to the designated server with PSK credentials.
coap_new_client_session_pki_lkd
coap_session_t * coap_new_client_session_pki_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto, coap_dtls_pki_t *setup_data)
Creates a new client session to the designated server with PKI credentials.
coap_new_client_session_lkd
coap_session_t * coap_new_client_session_lkd(coap_context_t *ctx, const coap_address_t *local_if, const coap_address_t *server, coap_proto_t proto)
Creates a new client session to the designated server.
coap_session_release_lkd
void coap_session_release_lkd(coap_session_t *session)
Decrement reference counter on a session.
Definition coap_session.c:376
COAP_OSCORE_B_2_NONE
@ COAP_OSCORE_B_2_NONE
Definition coap_session_internal.h:47
COAP_OSCORE_B_2_STEP_3
@ COAP_OSCORE_B_2_STEP_3
Definition coap_session_internal.h:50
COAP_OSCORE_B_2_STEP_1
@ COAP_OSCORE_B_2_STEP_1
Definition coap_session_internal.h:48
COAP_OSCORE_B_2_STEP_4
@ COAP_OSCORE_B_2_STEP_4
Definition coap_session_internal.h:51
COAP_OSCORE_B_2_STEP_5
@ COAP_OSCORE_B_2_STEP_5
Definition coap_session_internal.h:52
COAP_OSCORE_B_2_STEP_2
@ COAP_OSCORE_B_2_STEP_2
Definition coap_session_internal.h:49
COAP_PROTO_NOT_RELIABLE
#define COAP_PROTO_NOT_RELIABLE(p)
Definition coap_session.h:37
coap_delete_bin_const
void coap_delete_bin_const(coap_bin_const_t *s)
Deletes the given const binary data and releases any memory allocated.
Definition coap_str.c:120
coap_new_binary
coap_binary_t * coap_new_binary(size_t size)
Returns a new binary object with at least size bytes storage allocated.
Definition coap_str.c:77
coap_make_str_const
coap_str_const_t * coap_make_str_const(const char *string)
Take the specified byte array (text) and create a coap_str_const_t *.
Definition coap_str.c:66
coap_new_bin_const
coap_bin_const_t * coap_new_bin_const(const uint8_t *data, size_t size)
Take the specified byte array (text) and create a coap_bin_const_t * Returns a new const binary objec...
Definition coap_str.c:110
coap_str_const_t
struct coap_str_const_t coap_str_const_t
CoAP string data definition with const data.
coap_delete_binary
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
Definition coap_str.c:105
coap_binary_equal
#define coap_binary_equal(binary1, binary2)
Compares the two binary data for equality.
Definition coap_str.h:211
coap_string_equal
#define coap_string_equal(string1, string2)
Compares the two strings for equality.
Definition coap_str.h:197
coap_oscore_is_supported
int coap_oscore_is_supported(void)
Check whether OSCORE is available.
Definition coap_oscore.c:2184
coap_query_into_optlist
int coap_query_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum, coap_optlist_t **optlist_chain)
Splits the given URI query into '&' separate segments, and then adds the Uri-Query / Location-Query o...
Definition coap_uri.c:840
coap_path_into_optlist
int coap_path_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum, coap_optlist_t **optlist_chain)
Splits the given URI path into '/' separate segments, and then adds the Uri-Path / Location-Path opti...
Definition coap_uri.c:750
coap_split_proxy_uri
int coap_split_proxy_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri)
Parses a given string into URI components.
Definition coap_uri.c:294
coap_uri_scheme
coap_uri_info_t coap_uri_scheme[COAP_URI_SCHEME_LAST]
Definition coap_uri.c:51
coap_address_t
Multi-purpose address abstraction.
Definition coap_address.h:148
coap_bin_const_t
CoAP binary data definition with const data.
Definition coap_str.h:64
coap_bin_const_t::length
size_t length
length of binary data
Definition coap_str.h:65
coap_bin_const_t::s
const uint8_t * s
read-only binary data
Definition coap_str.h:66
coap_binary_t
CoAP binary data definition.
Definition coap_str.h:56
coap_binary_t::length
size_t length
length of binary data
Definition coap_str.h:57
coap_binary_t::s
uint8_t * s
binary data
Definition coap_str.h:58
coap_context_t
The CoAP stack's global state is stored in a coap_context_t object.
Definition coap_net_internal.h:50
coap_dtls_cpsk_t
The structure used for defining the Client PSK setup data to be used.
Definition coap_dtls.h:410
coap_dtls_pki_t
The structure used for defining the PKI setup data to be used.
Definition coap_dtls.h:312
coap_opt_iterator_t
Iterator to run through PDU options.
Definition coap_option.h:168
coap_opt_iterator_t::next_option
coap_opt_t * next_option
pointer to the unparsed next option
Definition coap_option.h:173
coap_opt_iterator_t::length
size_t length
remaining length of PDU
Definition coap_option.h:169
coap_opt_iterator_t::number
coap_option_num_t number
decoded option number
Definition coap_option.h:170
coap_optlist_t
Representation of chained list of CoAP options to install.
Definition coap_option.h:325
coap_oscore_conf_t
The structure used to hold the OSCORE configuration information.
Definition coap_oscore_internal.h:36
coap_oscore_conf_t::save_seq_num_func_param
void * save_seq_num_func_param
Passed to save_seq_num_func().
Definition coap_oscore_internal.h:59
coap_oscore_conf_t::rfc8613_b_2
uint32_t rfc8613_b_2
1 if rfc8613 B.2 protocol else 0
Definition coap_oscore_internal.h:50
coap_oscore_conf_t::hkdf_alg
cose_hkdf_alg_t hkdf_alg
Set to one of COSE_HKDF_ALG_*.
Definition coap_oscore_internal.h:48
coap_oscore_conf_t::break_sender_key
uint32_t break_sender_key
1 if sender key to be broken, else 0
Definition coap_oscore_internal.h:53
coap_oscore_conf_t::ssn_freq
uint32_t ssn_freq
Sender Seq Num update frequency.
Definition coap_oscore_internal.h:46
coap_oscore_conf_t::save_seq_num_func
coap_oscore_save_seq_num_t save_seq_num_func
Called every seq num change.
Definition coap_oscore_internal.h:57
coap_oscore_conf_t::rfc8613_b_1_2
uint32_t rfc8613_b_1_2
1 if rfc8613 B.1.2 enabled else 0
Definition coap_oscore_internal.h:49
coap_oscore_conf_t::start_seq_num
uint64_t start_seq_num
Used for ssn_freq updating.
Definition coap_oscore_internal.h:60
coap_oscore_conf_t::sender_id
coap_bin_const_t * sender_id
Sender ID (i.e.
Definition coap_oscore_internal.h:39
coap_oscore_conf_t::recipient_id
coap_bin_const_t ** recipient_id
Recipient ID (i.e.
Definition coap_oscore_internal.h:41
coap_oscore_conf_t::break_recipient_key
uint32_t break_recipient_key
1 if recipient key to be broken, else 0
Definition coap_oscore_internal.h:54
coap_oscore_conf_t::master_secret
coap_bin_const_t * master_secret
Common Master Secret.
Definition coap_oscore_internal.h:37
coap_oscore_conf_t::aead_alg
cose_alg_t aead_alg
Set to one of COSE_ALGORITHM_AES*.
Definition coap_oscore_internal.h:47
coap_oscore_conf_t::master_salt
coap_bin_const_t * master_salt
Common Master Salt.
Definition coap_oscore_internal.h:38
coap_oscore_conf_t::replay_window
uint32_t replay_window
Replay window size Use COAP_OSCORE_DEFAULT_REPLAY_WINDOW.
Definition coap_oscore_internal.h:44
coap_oscore_conf_t::id_context
coap_bin_const_t * id_context
Common ID context.
Definition coap_oscore_internal.h:40
coap_oscore_conf_t::recipient_id_count
uint32_t recipient_id_count
Number of recipient_id entries.
Definition coap_oscore_internal.h:43
coap_pdu_t
structure for CoAP PDUs
Definition coap_pdu_internal.h:135
coap_pdu_t::max_hdr_size
uint8_t max_hdr_size
space reserved for protocol-specific header
Definition coap_pdu_internal.h:141
coap_pdu_t::token
uint8_t * token
first byte of token (or extended length bytes prefix), if any, or options
Definition coap_pdu_internal.h:155
coap_pdu_t::code
coap_pdu_code_t code
request method (value 1–31) or response code (value 64-255)
Definition coap_pdu_internal.h:137
coap_pdu_t::actual_token
coap_bin_const_t actual_token
Actual token in pdu.
Definition coap_pdu_internal.h:148
coap_pdu_t::data
uint8_t * data
first byte of payload, if any
Definition coap_pdu_internal.h:157
coap_pdu_t::mid
coap_mid_t mid
message id, if any, in regular host byte order
Definition coap_pdu_internal.h:139
coap_pdu_t::e_token_length
uint32_t e_token_length
length of Token space (includes leading extended bytes
Definition coap_pdu_internal.h:146
coap_pdu_t::used_size
size_t used_size
used bytes of storage for token, options and payload
Definition coap_pdu_internal.h:151
coap_pdu_t::type
coap_pdu_type_t type
message type
Definition coap_pdu_internal.h:136
coap_session_t
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
Definition coap_session_internal.h:68
coap_session_t::proto
coap_proto_t proto
protocol used
Definition coap_session_internal.h:69
coap_session_t::con_active
uint8_t con_active
Active CON request sent.
Definition coap_session_internal.h:90
coap_session_t::context
coap_context_t * context
session's context
Definition coap_session_internal.h:86
coap_str_const_t
CoAP string data definition with const data.
Definition coap_str.h:46
coap_str_const_t::s
const uint8_t * s
read-only string data
Definition coap_str.h:48
coap_str_const_t::length
size_t length
length of string
Definition coap_str.h:47
coap_uri_t
Representation of parsed URI.
Definition coap_uri.h:65
coap_uri_t::scheme
enum coap_uri_scheme_t scheme
The parsed scheme specifier.
Definition coap_uri.h:77
coap_uri_t::path
coap_str_const_t path
The complete path if present or {0, NULL}.
Definition coap_uri.h:68
coap_uri_t::port
uint16_t port
The port in host byte order.
Definition coap_uri.h:67
coap_uri_t::query
coap_str_const_t query
The complete query if present or {0, NULL}.
Definition coap_uri.h:72
coap_uri_t::host
coap_str_const_t host
The host part of the URI.
Definition coap_uri.h:66
cose_encrypt0_t
Definition oscore_cose.h:197
cose_encrypt0_t::aad
coap_bin_const_t aad
Definition oscore_cose.h:208
cose_encrypt0_t::key
coap_bin_const_t key
Definition oscore_cose.h:199
cose_encrypt0_t::partial_iv
coap_bin_const_t partial_iv
Definition oscore_cose.h:202
cose_encrypt0_t::kid_context
coap_bin_const_t kid_context
Definition oscore_cose.h:204
cose_encrypt0_t::nonce
coap_bin_const_t nonce
Definition oscore_cose.h:206
cose_encrypt0_t::external_aad
coap_bin_const_t external_aad
Definition oscore_cose.h:207
cose_encrypt0_t::key_id
coap_bin_const_t key_id
Definition oscore_cose.h:203
cose_encrypt0_t::oscore_option
coap_bin_const_t oscore_option
Definition oscore_cose.h:205
cose_encrypt0_t::alg
cose_alg_t alg
Definition oscore_cose.h:198
oscore_association_t
Definition oscore_context.h:142
oscore_association_t::partial_iv
coap_bin_const_t * partial_iv
Definition oscore_context.h:149
oscore_association_t::sent_pdu
coap_pdu_t * sent_pdu
Definition oscore_context.h:145
oscore_association_t::aad
coap_bin_const_t * aad
Definition oscore_context.h:147
oscore_association_t::nonce
coap_bin_const_t * nonce
Definition oscore_context.h:148
oscore_association_t::recipient_ctx
oscore_recipient_ctx_t * recipient_ctx
Definition oscore_context.h:144
oscore_association_t::is_observe
uint8_t is_observe
Definition oscore_context.h:151
oscore_ctx_t
Definition oscore_context.h:84
oscore_ctx_t::mode
oscore_mode_t mode
Definition oscore_context.h:95
oscore_ctx_t::rfc8613_b_1_2
uint8_t rfc8613_b_1_2
1 if rfc8613 B.1.2 enabled else 0
Definition oscore_context.h:96
oscore_ctx_t::save_seq_num_func_param
void * save_seq_num_func_param
Passed to save_seq_num_func().
Definition oscore_context.h:102
oscore_ctx_t::sender_context
oscore_sender_ctx_t * sender_context
Definition oscore_context.h:91
oscore_ctx_t::aead_alg
cose_alg_t aead_alg
Definition oscore_context.h:93
oscore_ctx_t::rfc8613_b_2
uint8_t rfc8613_b_2
1 if rfc8613 B.2 protocol else 0
Definition oscore_context.h:97
oscore_ctx_t::save_seq_num_func
coap_oscore_save_seq_num_t save_seq_num_func
Called every seq num change.
Definition oscore_context.h:100
oscore_ctx_t::recipient_chain
oscore_recipient_ctx_t * recipient_chain
Definition oscore_context.h:92
oscore_ctx_t::id_context
coap_bin_const_t * id_context
contains GID in case of group
Definition oscore_context.h:90
oscore_ctx_t::ssn_freq
uint32_t ssn_freq
Sender Seq Num update frequency.
Definition oscore_context.h:98
oscore_recipient_ctx_t
Definition oscore_context.h:112
oscore_recipient_ctx_t::echo_value
uint8_t echo_value[8]
Definition oscore_context.h:123
oscore_recipient_ctx_t::last_seq
uint64_t last_seq
Definition oscore_context.h:116
oscore_recipient_ctx_t::recipient_key
coap_bin_const_t * recipient_key
Definition oscore_context.h:121
oscore_recipient_ctx_t::recipient_id
coap_bin_const_t * recipient_id
Definition oscore_context.h:122
oscore_recipient_ctx_t::initial_state
uint8_t initial_state
Definition oscore_context.h:124
oscore_recipient_ctx_t::osc_ctx
oscore_ctx_t * osc_ctx
Definition oscore_context.h:115
oscore_sender_ctx_t
Definition oscore_context.h:105
oscore_sender_ctx_t::sender_id
coap_bin_const_t * sender_id
Definition oscore_context.h:109
oscore_sender_ctx_t::seq
uint64_t seq
Definition oscore_context.h:106
oscore_sender_ctx_t::sender_key
coap_bin_const_t * sender_key
Definition oscore_context.h:108
oscore_sender_ctx_t::next_seq
uint64_t next_seq
Used for ssn_freq updating.
Definition oscore_context.h:107