libcoap_rs/oscore.rs
1// SPDX-License-Identifier: BSD-2-Clause
2/*
3 * Copyright © The libcoap-rs Contributors, all rights reserved.
4 * This file is part of the libcoap-rs project, see the README file for
5 * general information on this project and the NOTICE.md and LICENSE files
6 * for information regarding copyright ownership and terms of use.
7 *
8 * oscore.rs - Wrapper for libcoap OSCORE functionality.
9 */
10
11use core::{ffi::c_void, ptr};
12
13use libcoap_sys::{
14 coap_delete_oscore_conf, coap_delete_str_const, coap_new_oscore_conf, coap_new_str_const, coap_oscore_conf_t,
15};
16
17use crate::error::OscoreConfigError;
18
19/// Represents an oscore config object which stores the underlying
20/// coap_oscore_conf_t C struct.
21pub struct OscoreConf {
22 raw_conf: *mut coap_oscore_conf_t,
23 initial_recipient: Option<String>,
24}
25
26impl OscoreConf {
27 /// Creates a new OscoreConf.
28 ///
29 /// # Errors
30 /// Will return a [OscoreConfigError] if creating the oscore config fails (most likely due to
31 /// invalid oscore config bytes provided).
32 pub fn new(
33 seq_initial: u64,
34 oscore_conf_bytes: &[u8],
35 save_seq_num_func: extern "C" fn(seq_num: u64, _param: *mut c_void) -> i32,
36 ) -> Result<Self, OscoreConfigError> {
37 // Creates the raw_struct containing the config provided by the caller.
38 // SAFETY: Provided pointer and length point to a valid byte string usable by
39 // coap_new_str_const().
40 let conf = unsafe { coap_new_str_const(oscore_conf_bytes.as_ptr(), oscore_conf_bytes.len()) };
41 if conf.is_null() {
42 return Err(OscoreConfigError::Unknown);
43 }
44
45 // SAFETY:
46 // The parts of the byte string referenced by conf are defensively copied if used
47 // by the newly created oscore_conf.
48 // Conf was just checked for invalidity, whether or not it containes all required fields.
49 // - save_seq_num_func is specifically designed to work as a callback for this
50 // function.
51 // - save_seq_num_func_param may be a null pointer (save_seq_num_func does
52 // not use it).
53 let oscore_conf = unsafe { coap_new_oscore_conf(*conf, Some(save_seq_num_func), ptr::null_mut(), seq_initial) };
54 unsafe {
55 coap_delete_str_const(conf);
56 }
57 if oscore_conf.is_null() {
58 return Err(OscoreConfigError::Unknown);
59 }
60
61 // Save the initial recipient_id (if present). This needs to be added to the context when
62 // calling oscore_server to prevent a double free when trying to add an identical
63 // recipient_id later.
64 let mut initial_recipient: Option<String> = None;
65 let oscore_conf_str = core::str::from_utf8(oscore_conf_bytes).expect("could not parse config bytes to str");
66 for line in oscore_conf_str.lines() {
67 if line.starts_with("recipient_id") {
68 let parts: Vec<&str> = line.split(",").collect();
69 initial_recipient = Some(parts[2].trim().trim_matches('"').to_string());
70 break;
71 }
72 }
73
74 // Return the valid OscoreConf.
75 Ok(Self {
76 raw_conf: oscore_conf,
77 initial_recipient,
78 })
79 }
80
81 /// Cosumes the OscoreConf and returns the contained raw_conf libcoap struct as well as an
82 /// optional initial recipient if set.
83 /// The caller is responsible for managing the memory of the raw_conf returned by this function,
84 /// e.g., by using coap_delete_oscore_conf() to free the returned memory after use.
85 pub(crate) fn into_raw_conf(mut self) -> (*mut coap_oscore_conf_t, Option<String>) {
86 // Replace pointer in structure with a null pointer, so the destructor knows that we know longer own
87 // the raw structure and must therefore not free it.
88 let raw_conf = std::mem::replace(&mut self.raw_conf, ptr::null_mut());
89 (raw_conf, self.initial_recipient.clone())
90 }
91}
92
93impl Drop for OscoreConf {
94 /// Drop the OscoreConf's raw_conf.
95 fn drop(&mut self) {
96 if !self.raw_conf.is_null() {
97 // SAFETY: If the CoapConf was consumed by calling the unsafe function into_raw_conf() the
98 // pointer will be null, but we just checked that this is not the case.
99 // Therefore, we are still the owner of the raw config and can therefore free it.
100 unsafe {
101 coap_delete_oscore_conf(self.raw_conf);
102 }
103 }
104 }
105}