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