From 466f1e0b5c341e6d7520bf5bd341f018a0fd0e54 Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Fri, 25 Oct 2024 14:30:36 +0100 Subject: [PATCH] coap_oscore.c: Process queued OSCORE Observe responses after de-registration If an Observe is de-registered, but an unsolicited Observe response is received before the de-register response is received, then the unsolicited response failed to get decrypted. --- examples/coap-client.c | 1 + examples/coap-server.c | 1 + examples/oscore-interop-server.c | 1 + include/oscore/oscore_context.h | 1 + src/coap_net.c | 1 + src/coap_oscore.c | 26 +++++++++++++++++++++----- src/oscore/oscore_context.c | 1 + 7 files changed, 27 insertions(+), 5 deletions(-) diff --git a/examples/coap-client.c b/examples/coap-client.c index a91993f6f5..bfa24c2202 100644 --- a/examples/coap-client.c +++ b/examples/coap-client.c @@ -798,6 +798,7 @@ get_oscore_conf(void) { if (oscore_seq_num_fp == NULL) { fprintf(stderr, "OSCORE save restart info file error: %s\n", oscore_seq_save_file); + coap_free(buf); return NULL; } } diff --git a/examples/coap-server.c b/examples/coap-server.c index 53e0e4ed74..9065841d8c 100644 --- a/examples/coap-server.c +++ b/examples/coap-server.c @@ -1938,6 +1938,7 @@ get_oscore_conf(coap_context_t *context) { if (oscore_seq_num_fp == NULL) { fprintf(stderr, "OSCORE save restart info file error: %s\n", oscore_seq_save_file); + coap_free(buf); return NULL; } } diff --git a/examples/oscore-interop-server.c b/examples/oscore-interop-server.c index e9acae2f57..814283809a 100644 --- a/examples/oscore-interop-server.c +++ b/examples/oscore-interop-server.c @@ -526,6 +526,7 @@ get_oscore_conf(coap_context_t *context) { if (oscore_seq_num_fp == NULL) { fprintf(stderr, "OSCORE save restart info file error: %s\n", oscore_seq_save_file); + coap_free(buf); return NULL; } } diff --git a/include/oscore/oscore_context.h b/include/oscore/oscore_context.h index 1806cccb5f..021262278e 100644 --- a/include/oscore/oscore_context.h +++ b/include/oscore/oscore_context.h @@ -147,6 +147,7 @@ struct oscore_association_t { coap_bin_const_t *aad; coap_bin_const_t *nonce; coap_bin_const_t *partial_iv; + coap_bin_const_t *obs_partial_iv; coap_tick_t last_seen; uint8_t is_observe; }; diff --git a/src/coap_net.c b/src/coap_net.c index a3ee53a688..42af27a986 100644 --- a/src/coap_net.c +++ b/src/coap_net.c @@ -1843,6 +1843,7 @@ coap_send_internal(coap_session_t *session, coap_pdu_t *pdu) { #if COAP_OSCORE_SUPPORT if (session->oscore_encryption && + pdu->type != COAP_MESSAGE_RST && !(pdu->type == COAP_MESSAGE_ACK && pdu->code == COAP_EMPTY_CODE)) { /* Refactor PDU as appropriate RFC8613 */ coap_pdu_t *osc_pdu = coap_oscore_new_pdu_encrypted_lkd(session, pdu, NULL, diff --git a/src/coap_oscore.c b/src/coap_oscore.c index 13f9ad25d2..a7f6a21046 100644 --- a/src/coap_oscore.c +++ b/src/coap_oscore.c @@ -697,9 +697,6 @@ coap_oscore_new_pdu_encrypted_lkd(coap_session_t *session, 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 = @@ -710,7 +707,12 @@ coap_oscore_new_pdu_encrypted_lkd(coap_session_t *session, 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); + if (doing_observe && observe_value == 1) { + coap_delete_bin_const(association->obs_partial_iv); + association->obs_partial_iv = association->partial_iv; + } else { + 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) @@ -831,6 +833,8 @@ coap_oscore_decrypt_pdu(coap_session_t *session, coap_bin_const_t aad; coap_bin_const_t nonce; int pltxt_size = 0; + int got_resp_piv = 0; + int doing_resp_observe = 0; uint8_t coap_request = COAP_PDU_IS_REQUEST(pdu); coap_bin_const_t pdu_token; uint8_t *st_encrypt; @@ -1065,6 +1069,8 @@ coap_oscore_decrypt_pdu(coap_session_t *session, session); goto error; } + got_resp_piv = cose->partial_iv.length ? 1 : 0; + association = oscore_find_association(session, &pdu_token); if (association) { rcp_ctx = association->recipient_ctx; @@ -1281,7 +1287,11 @@ coap_oscore_decrypt_pdu(coap_session_t *session, /* External AAD */ cose_encrypt0_set_key_id(cose, snd_ctx->sender_id); - cose_encrypt0_set_partial_iv(cose, association->partial_iv); + if (association->is_observe && association->obs_partial_iv && got_resp_piv) { + cose_encrypt0_set_partial_iv(cose, association->obs_partial_iv); + } else { + cose_encrypt0_set_partial_iv(cose, association->partial_iv); + } #ifdef OSCORE_EXTRA_DEBUG dump_cose(cose, "!req pre aad"); #endif /* OSCORE_EXTRA_DEBUG */ @@ -1549,6 +1559,7 @@ coap_oscore_decrypt_pdu(coap_session_t *session, session); goto error; } + doing_resp_observe = 1; break; } association = oscore_find_association(session, &pdu_token); @@ -1571,6 +1582,11 @@ coap_oscore_decrypt_pdu(coap_session_t *session, break; } } + if (!coap_request && !doing_resp_observe) { + if (association) { + association->is_observe = 0; + } + } /* Need to copy across any data */ if (opt_iter.length > 0 && opt_iter.next_option && opt_iter.next_option[0] == COAP_PAYLOAD_START) { diff --git a/src/oscore/oscore_context.c b/src/oscore/oscore_context.c index 4dd727c536..1146568755 100644 --- a/src/oscore/oscore_context.c +++ b/src/oscore/oscore_context.c @@ -678,6 +678,7 @@ oscore_free_association(oscore_association_t *association) { coap_delete_bin_const(association->aad); coap_delete_bin_const(association->nonce); coap_delete_bin_const(association->partial_iv); + coap_delete_bin_const(association->obs_partial_iv); coap_free_type(COAP_STRING, association); } }