1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 //! Utilities related to CBOR encode/decode.
16
17 use crate::error::{DpeResult, ErrCode};
18 use crate::memory::SizedMessage;
19 use log::error;
20 use minicbor::{Decoder, Encoder};
21
22 // Required in order for minicbor to write into a SizedMessage.
23 impl<const S: usize> minicbor::encode::Write for SizedMessage<S> {
24 type Error = ();
write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error>25 fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
26 self.vec.extend_from_slice(buf)
27 }
28 }
29
30 /// Creates a CBOR [Encoder] which encodes into `output`.
cbor_encoder_from_message<const S: usize>( output: &mut SizedMessage<S>, ) -> Encoder<&mut SizedMessage<S>>31 pub fn cbor_encoder_from_message<const S: usize>(
32 output: &mut SizedMessage<S>,
33 ) -> Encoder<&mut SizedMessage<S>> {
34 Encoder::new(output)
35 }
36
37 /// Creates a CBOR [Decoder] which decodes from `input`.
cbor_decoder_from_message<const S: usize>( input: &SizedMessage<S>, ) -> Decoder38 pub fn cbor_decoder_from_message<const S: usize>(
39 input: &SizedMessage<S>,
40 ) -> Decoder {
41 Decoder::new(input.as_slice())
42 }
43
44 /// Extends minicbor::Decoder.
45 pub trait DecoderExt {
46 /// Decodes a byte slice and returns only its position. This is useful when
47 /// the byte slice is the last CBOR item, might be large, and will be
48 /// processed in-place using up to the entire available message buffer.
49 /// This is intended to be used in conjunction with [`remove_prefix`].
50 ///
51 /// # Errors
52 ///
53 /// Returns an InvalidArgument error if a CBOR Bytes item cannot be decoded.
54 ///
55 /// # Example
56 ///
57 /// ```rust
58 /// use dpe_rs::cbor::{
59 /// cbor_decoder_from_message,
60 /// cbor_encoder_from_message,
61 /// DecoderExt,
62 /// };
63 /// use dpe_rs::memory::Message;
64 ///
65 /// let mut message = Message::new();
66 /// cbor_encoder_from_message(&mut message).bytes(&[0; 1000]);
67 /// let mut decoder = cbor_decoder_from_message(&message);
68 /// let position = decoder.decode_bytes_prefix().unwrap();
69 /// assert_eq!(&message.as_slice()[position..], &[0; 1000]);
70 /// ```
71 /// [`remove_prefix`]: SizedMessage::remove_prefix
decode_bytes_prefix(&mut self) -> DpeResult<usize>72 fn decode_bytes_prefix(&mut self) -> DpeResult<usize>;
73 }
74 impl DecoderExt for Decoder<'_> {
decode_bytes_prefix(&mut self) -> DpeResult<usize>75 fn decode_bytes_prefix(&mut self) -> DpeResult<usize> {
76 let bytes_len = self.bytes()?.len();
77 Ok(self.position() - bytes_len)
78 }
79 }
80
81 /// Encodes a CBOR Bytes prefix for a given `bytes_len` and appends it to
82 /// `buffer`. This must be appended by `bytes_len` bytes to form a valid CBOR
83 /// encoding.
84 ///
85 /// # Errors
86 ///
87 /// Returns an InternalError error if `bytes_len` is too large for the remaining
88 /// capacity of the `buffer`.
89 ///
90 /// # Example
91 ///
92 /// ```rust
93 /// use dpe_rs::cbor::{
94 /// cbor_decoder_from_message,
95 /// cbor_encoder_from_message,
96 /// encode_bytes_prefix,
97 /// };
98 /// use dpe_rs::memory::{
99 /// Message,
100 /// SizedMessage,
101 /// };
102 /// type Prefix = SizedMessage<10>;
103 ///
104 /// let mut message = Message::from_slice(&[0; 100]).unwrap();
105 /// let mut prefix = Prefix::new();
106 /// encode_bytes_prefix(&mut prefix, message.len()).unwrap();
107 /// message.insert_prefix(prefix.as_slice()).unwrap();
108 /// let mut decoder = cbor_decoder_from_message(&message);
109 /// assert_eq!(decoder.bytes().unwrap(), &[0; 100]);
110 /// ```
encode_bytes_prefix<const S: usize>( buffer: &mut SizedMessage<S>, bytes_len: usize, ) -> DpeResult<()>111 pub fn encode_bytes_prefix<const S: usize>(
112 buffer: &mut SizedMessage<S>,
113 bytes_len: usize,
114 ) -> DpeResult<()> {
115 // See RFC 8949 sections 3 and 3.1 for how this is encoded.
116 // `CBOR_BYTES_MAJOR_TYPE` is major type 2 in the high-order 3 bits.
117 const CBOR_BYTES_MAJOR_TYPE: u8 = 2 << 5;
118 const CBOR_VALUE_IN_ONE_BYTE: u8 = 24;
119 const CBOR_VALUE_IN_TWO_BYTES: u8 = 25;
120 let initial_byte_value;
121 let mut following_bytes: &[u8] = &[];
122 let mut big_endian_value: [u8; 2] = Default::default();
123 match bytes_len {
124 0..=23 => {
125 // Encode the length in the lower 5 bits of the initial byte.
126 initial_byte_value = bytes_len as u8;
127 }
128 24..=255 => {
129 // Encode the length in a single additional byte.
130 initial_byte_value = CBOR_VALUE_IN_ONE_BYTE;
131 big_endian_value[0] = bytes_len as u8;
132 following_bytes = &big_endian_value[..1];
133 }
134 256..=65535 => {
135 // Encode the length in two additional bytes, big endian.
136 initial_byte_value = CBOR_VALUE_IN_TWO_BYTES;
137 big_endian_value = (bytes_len as u16).to_be_bytes();
138 following_bytes = &big_endian_value;
139 }
140 _ => {
141 error!("Unsupported CBOR length");
142 return Err(ErrCode::InternalError);
143 }
144 }
145 buffer
146 .vec
147 .push(CBOR_BYTES_MAJOR_TYPE + initial_byte_value)
148 .map_err(|_| ErrCode::InternalError)?;
149 buffer
150 .vec
151 .extend_from_slice(following_bytes)
152 .map_err(|_| ErrCode::InternalError)?;
153 Ok(())
154 }
155