Skip to main content

coset/context/
mod.rs

1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://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,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15////////////////////////////////////////////////////////////////////////////////
16
17//! COSE_KDF_Context functionality.
18
19use crate::{
20    cbor::value::Value,
21    common::AsCborValue,
22    iana,
23    util::{cbor_type_error, ValueTryAs},
24    Algorithm, CoseError, ProtectedHeader, Result,
25};
26use alloc::{vec, vec::Vec};
27use core::convert::TryInto;
28
29#[cfg(test)]
30mod tests;
31
32/// A nonce value.
33#[derive(Clone, Debug, Eq, PartialEq)]
34pub enum Nonce {
35    Bytes(Vec<u8>),
36    Integer(i64),
37}
38
39/// Structure representing a party involved in key derivation.
40///
41/// ```cddl
42///  PartyInfo = (
43///      identity : bstr / nil,
44///      nonce : bstr / int / nil,
45///      other : bstr / nil
46///  )
47///  ```
48#[derive(Clone, Debug, Default, Eq, PartialEq)]
49pub struct PartyInfo {
50    pub identity: Option<Vec<u8>>,
51    pub nonce: Option<Nonce>,
52    pub other: Option<Vec<u8>>,
53}
54
55impl crate::CborSerializable for PartyInfo {}
56
57impl AsCborValue for PartyInfo {
58    fn from_cbor_value(value: Value) -> Result<Self> {
59        let mut a = value.try_as_array()?;
60        if a.len() != 3 {
61            return Err(CoseError::UnexpectedItem("array", "array with 3 items"));
62        }
63
64        // Remove array elements in reverse order to avoid shifts.
65        Ok(Self {
66            other: match a.remove(2) {
67                Value::Null => None,
68                Value::Bytes(b) => Some(b),
69                v => return cbor_type_error(&v, "bstr / nil"),
70            },
71            nonce: match a.remove(1) {
72                Value::Null => None,
73                Value::Bytes(b) => Some(Nonce::Bytes(b)),
74                Value::Integer(u) => Some(Nonce::Integer(u.try_into()?)),
75                v => return cbor_type_error(&v, "bstr / int / nil"),
76            },
77            identity: match a.remove(0) {
78                Value::Null => None,
79                Value::Bytes(b) => Some(b),
80                v => return cbor_type_error(&v, "bstr / nil"),
81            },
82        })
83    }
84
85    fn to_cbor_value(self) -> Result<Value> {
86        Ok(Value::Array(vec![
87            match self.identity {
88                None => Value::Null,
89                Some(b) => Value::Bytes(b),
90            },
91            match self.nonce {
92                None => Value::Null,
93                Some(Nonce::Bytes(b)) => Value::Bytes(b),
94                Some(Nonce::Integer(i)) => Value::from(i),
95            },
96            match self.other {
97                None => Value::Null,
98                Some(b) => Value::Bytes(b),
99            },
100        ]))
101    }
102}
103
104/// Builder for [`PartyInfo`] objects.
105#[derive(Debug, Default)]
106pub struct PartyInfoBuilder(PartyInfo);
107
108impl PartyInfoBuilder {
109    builder! {PartyInfo}
110    builder_set_optional! {identity: Vec<u8>}
111    builder_set_optional! {nonce: Nonce}
112    builder_set_optional! {other: Vec<u8>}
113}
114
115/// Structure representing supplemental public information.
116///
117/// ```cddl
118///  SuppPubInfo : [
119///      keyDataLength : uint,
120///      protected : empty_or_serialized_map,
121///      ? other : bstr
122///  ],
123///  ```
124#[derive(Clone, Debug, Default, PartialEq)]
125pub struct SuppPubInfo {
126    pub key_data_length: u64,
127    pub protected: ProtectedHeader,
128    pub other: Option<Vec<u8>>,
129}
130
131impl crate::CborSerializable for SuppPubInfo {}
132
133impl AsCborValue for SuppPubInfo {
134    fn from_cbor_value(value: Value) -> Result<Self> {
135        let mut a = value.try_as_array()?;
136        if a.len() != 2 && a.len() != 3 {
137            return Err(CoseError::UnexpectedItem(
138                "array",
139                "array with 2 or 3 items",
140            ));
141        }
142
143        // Remove array elements in reverse order to avoid shifts.
144        Ok(Self {
145            other: {
146                if a.len() == 3 {
147                    Some(a.remove(2).try_as_bytes()?)
148                } else {
149                    None
150                }
151            },
152            protected: ProtectedHeader::from_cbor_bstr(a.remove(1))?,
153            key_data_length: a.remove(0).try_as_integer()?.try_into()?,
154        })
155    }
156
157    fn to_cbor_value(self) -> Result<Value> {
158        let mut v = vec![
159            Value::from(self.key_data_length),
160            self.protected.cbor_bstr()?,
161        ];
162        if let Some(other) = self.other {
163            v.push(Value::Bytes(other));
164        }
165        Ok(Value::Array(v))
166    }
167}
168
169/// Builder for [`SuppPubInfo`] objects.
170#[derive(Debug, Default)]
171pub struct SuppPubInfoBuilder(SuppPubInfo);
172
173impl SuppPubInfoBuilder {
174    builder! {SuppPubInfo}
175    builder_set! {key_data_length: u64}
176    builder_set_protected! {protected}
177    builder_set_optional! {other: Vec<u8>}
178}
179
180/// Structure representing a a key derivation context.
181/// ```cdl
182///  COSE_KDF_Context = [
183///      AlgorithmID : int / tstr,
184///      PartyUInfo : [ PartyInfo ],
185///      PartyVInfo : [ PartyInfo ],
186///      SuppPubInfo : [
187///          keyDataLength : uint,
188///          protected : empty_or_serialized_map,
189///          ? other : bstr
190///      ],
191///      ? SuppPrivInfo : bstr
192///  ]
193/// ```
194#[derive(Clone, Debug, Default, PartialEq)]
195pub struct CoseKdfContext {
196    algorithm_id: Algorithm,
197    party_u_info: PartyInfo,
198    party_v_info: PartyInfo,
199    supp_pub_info: SuppPubInfo,
200    supp_priv_info: Vec<Vec<u8>>,
201}
202
203impl crate::CborSerializable for CoseKdfContext {}
204
205impl AsCborValue for CoseKdfContext {
206    fn from_cbor_value(value: Value) -> Result<Self> {
207        let mut a = value.try_as_array()?;
208        if a.len() < 4 {
209            return Err(CoseError::UnexpectedItem(
210                "array",
211                "array with at least 4 items",
212            ));
213        }
214
215        // Remove array elements in reverse order to avoid shifts.
216        let mut supp_priv_info = Vec::with_capacity(a.len() - 4);
217        for i in (4..a.len()).rev() {
218            supp_priv_info.push(a.remove(i).try_as_bytes()?);
219        }
220        supp_priv_info.reverse();
221
222        Ok(Self {
223            supp_priv_info,
224            supp_pub_info: SuppPubInfo::from_cbor_value(a.remove(3))?,
225            party_v_info: PartyInfo::from_cbor_value(a.remove(2))?,
226            party_u_info: PartyInfo::from_cbor_value(a.remove(1))?,
227            algorithm_id: Algorithm::from_cbor_value(a.remove(0))?,
228        })
229    }
230
231    fn to_cbor_value(self) -> Result<Value> {
232        let mut v = vec![
233            self.algorithm_id.to_cbor_value()?,
234            self.party_u_info.to_cbor_value()?,
235            self.party_v_info.to_cbor_value()?,
236            self.supp_pub_info.to_cbor_value()?,
237        ];
238        for supp_priv_info in self.supp_priv_info {
239            v.push(Value::Bytes(supp_priv_info));
240        }
241        Ok(Value::Array(v))
242    }
243}
244
245/// Builder for [`CoseKdfContext`] objects.
246#[derive(Debug, Default)]
247pub struct CoseKdfContextBuilder(CoseKdfContext);
248
249impl CoseKdfContextBuilder {
250    builder! {CoseKdfContext}
251    builder_set! {party_u_info: PartyInfo}
252    builder_set! {party_v_info: PartyInfo}
253    builder_set! {supp_pub_info: SuppPubInfo}
254
255    /// Set the algorithm.
256    #[must_use]
257    pub fn algorithm(mut self, alg: iana::Algorithm) -> Self {
258        self.0.algorithm_id = Algorithm::Assigned(alg);
259        self
260    }
261
262    /// Add supplemental private info.
263    #[must_use]
264    pub fn add_supp_priv_info(mut self, supp_priv_info: Vec<u8>) -> Self {
265        self.0.supp_priv_info.push(supp_priv_info);
266        self
267    }
268}