blob: b218c82ab0c05989fbd8ae714bbe5e6cb0dab6df [file] [log] [blame]
Alice Wangfacc2b82023-10-05 14:05:47 +00001// Copyright 2023, The Android Open Source Project
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//! Utility functions for CBOR serialization/deserialization.
16
Alice Wang5dddeea2023-10-13 12:56:22 +000017#![cfg_attr(not(feature = "std"), no_std)]
18
19extern crate alloc;
20
Alice Wangdd29c5d2023-12-07 09:56:23 +000021use alloc::string::String;
Alice Wangfacc2b82023-10-05 14:05:47 +000022use alloc::vec::Vec;
Alice Wangdd29c5d2023-12-07 09:56:23 +000023use ciborium::value::{Integer, Value};
Alice Wangff381112024-05-22 12:14:39 +000024use coset::{
25 iana::{self, EnumI64},
26 CborSerializable, CoseError, CoseKey, Label, Result,
27};
Alice Wangdd29c5d2023-12-07 09:56:23 +000028use log::error;
Alice Wangfacc2b82023-10-05 14:05:47 +000029use serde::{de::DeserializeOwned, Serialize};
30
31/// Serializes the given data to a CBOR-encoded byte vector.
Alice Wang5dddeea2023-10-13 12:56:22 +000032pub fn serialize<T: ?Sized + Serialize>(v: &T) -> Result<Vec<u8>> {
Alice Wangfacc2b82023-10-05 14:05:47 +000033 let mut data = Vec::new();
34 ciborium::into_writer(v, &mut data)?;
35 Ok(data)
36}
37
38/// Deserializes the given type from a CBOR-encoded byte slice, failing if any extra
39/// data remains after the type has been read.
Alice Wang5dddeea2023-10-13 12:56:22 +000040pub fn deserialize<T: DeserializeOwned>(mut data: &[u8]) -> Result<T> {
Alice Wangfacc2b82023-10-05 14:05:47 +000041 let res = ciborium::from_reader(&mut data)?;
42 if data.is_empty() {
43 Ok(res)
44 } else {
45 Err(CoseError::ExtraneousData)
46 }
47}
Alice Wangdd29c5d2023-12-07 09:56:23 +000048
Alice Wang5fb76c52024-01-05 13:16:13 +000049/// Parses the given CBOR-encoded byte slice as a value array.
50pub fn parse_value_array(data: &[u8], context: &'static str) -> Result<Vec<Value>> {
51 value_to_array(Value::from_slice(data)?, context)
52}
53
Alice Wangdd29c5d2023-12-07 09:56:23 +000054/// Converts the provided value `v` to a value array.
55pub fn value_to_array(v: Value, context: &'static str) -> Result<Vec<Value>> {
56 v.into_array().map_err(|e| to_unexpected_item_error(&e, "array", context))
57}
58
59/// Converts the provided value `v` to a text string.
60pub fn value_to_text(v: Value, context: &'static str) -> Result<String> {
61 v.into_text().map_err(|e| to_unexpected_item_error(&e, "tstr", context))
62}
63
64/// Converts the provided value `v` to a map.
65pub fn value_to_map(v: Value, context: &'static str) -> Result<Vec<(Value, Value)>> {
66 v.into_map().map_err(|e| to_unexpected_item_error(&e, "map", context))
67}
68
69/// Converts the provided value `v` to a number.
70pub fn value_to_num<T: TryFrom<Integer>>(v: Value, context: &'static str) -> Result<T> {
71 let num = v.into_integer().map_err(|e| to_unexpected_item_error(&e, "int", context))?;
72 num.try_into().map_err(|_| {
73 error!("The provided value '{num:?}' is not a valid number: {context}");
74 CoseError::OutOfRangeIntegerValue
75 })
76}
77
78/// Converts the provided value `v` to a byte array of length `N`.
79pub fn value_to_byte_array<const N: usize>(v: Value, context: &'static str) -> Result<[u8; N]> {
80 let arr = value_to_bytes(v, context)?;
81 arr.try_into().map_err(|e| {
82 error!("The provided value '{context}' is not an array of length {N}: {e:?}");
83 CoseError::UnexpectedItem("bstr", "array of length {N}")
84 })
85}
86
87/// Converts the provided value `v` to bytes array.
88pub fn value_to_bytes(v: Value, context: &'static str) -> Result<Vec<u8>> {
89 v.into_bytes().map_err(|e| to_unexpected_item_error(&e, "bstr", context))
90}
91
92/// Builds a `CoseError::UnexpectedItem` error when the provided value `v` is not of the expected
93/// type `expected_type` and logs the error message with the provided `context`.
94pub fn to_unexpected_item_error(
95 v: &Value,
96 expected_type: &'static str,
97 context: &'static str,
98) -> CoseError {
99 let v_type = cbor_value_type(v);
100 assert!(v_type != expected_type);
101 error!("The provided value type '{v_type}' is not of type '{expected_type}': {context}");
102 CoseError::UnexpectedItem(v_type, expected_type)
103}
104
105/// Reads the type of the provided value `v`.
106pub fn cbor_value_type(v: &Value) -> &'static str {
107 match v {
108 Value::Integer(_) => "int",
109 Value::Bytes(_) => "bstr",
110 Value::Float(_) => "float",
111 Value::Text(_) => "tstr",
112 Value::Bool(_) => "bool",
113 Value::Null => "nul",
114 Value::Tag(_, _) => "tag",
115 Value::Array(_) => "array",
116 Value::Map(_) => "map",
117 _ => "other",
118 }
119}
120
121/// Returns the value of the given label in the given COSE key as bytes.
122pub fn get_label_value_as_bytes(key: &CoseKey, label: Label) -> Result<&[u8]> {
123 let v = get_label_value(key, label)?;
124 Ok(v.as_bytes().ok_or_else(|| {
125 to_unexpected_item_error(v, "bstr", "Get label value in CoseKey as bytes")
126 })?)
127}
128
129/// Returns the value of the given label in the given COSE key.
130pub fn get_label_value(key: &CoseKey, label: Label) -> Result<&Value> {
131 Ok(&key
132 .params
133 .iter()
134 .find(|(k, _)| k == &label)
135 .ok_or(CoseError::UnexpectedItem("", "Label not found in CoseKey"))?
136 .1)
137}
Alice Wangff381112024-05-22 12:14:39 +0000138
139/// Converts the provided COSE key algorithm integer to an `iana::Algorithm` used
140/// by DICE chains.
141pub fn dice_cose_key_alg(cose_key_alg: i32) -> Result<iana::Algorithm> {
142 let key_alg = iana::Algorithm::from_i64(cose_key_alg as i64).ok_or_else(|| {
143 error!("Unsupported COSE key algorithm for DICE: {cose_key_alg}");
144 CoseError::UnexpectedItem("COSE key algorithm", "")
145 })?;
146 match key_alg {
147 iana::Algorithm::EdDSA | iana::Algorithm::ES256 | iana::Algorithm::ES384 => Ok(key_alg),
148 _ => {
149 error!("Unsupported COSE key algorithm for DICE: {key_alg:?}");
150 Err(CoseError::UnexpectedItem("-8, -7 or -35", ""))
151 }
152 }
153}