cose/
utils.rs

1//! Utilities to help the process of encoding/decoding a COSE message.
2//!
3//! # Examples
4//!
5//! Examples on how to encode a COSE message by providing the respective
6//! parameters and cose-key in JSON format.
7//!
8//! The functions `decode_json_key` and `decode_json` used in this examples are from the optional feature `json` of this crate.
9//!
10//! ## cose-sign1
11//! ```
12//! use cose::utils;
13//! use cose::message::{CoseMessage, SIG1_TAG};
14//!
15//! fn main() {
16//!
17//!     // cose-sign1 message in JSON format
18//!     let data: &str = r#"
19//!     {
20//!             "protected": {"alg": "EDDSA" },
21//!             "unprotected": {"kid": "11" },
22//!             "payload": "signed message"
23//!     }"#;
24//!
25//!     // cose-key in JSON format
26//!     let key_json: &str = r#"
27//!     {
28//!             "kty": "OKP",
29//!             "alg": "EDDSA",
30//!             "crv": "Ed25519",
31//!             "x": "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
32//!             "d": "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
33//!             "key ops": ["sign", "verify"]
34//!     }"#;
35//!
36//!     // Decode the cose-key JSON to CoseKey structure
37//!     let key = utils::decode_json_key(key_json).unwrap();
38//!     // Encode the cose-sign1 with the decoded cose-key and cose-sign1 JSON
39//!     let res = utils::decode_json(data, &key, SIG1_TAG).unwrap();
40//!
41//!     // Verify the signature
42//!     let mut verify = CoseMessage::new_sign();
43//!     verify.bytes = res;
44//!     verify.init_decoder(None).unwrap();
45//!     verify.key(&key).unwrap();
46//!     verify.decode(None, None).unwrap();
47//! }
48//!
49//! ```
50//! ## cose-encrypt0
51//!
52//! ```
53//! use cose::utils;
54//! use cose::message::{CoseMessage, ENC0_TAG};
55//!
56//! fn main() {
57//!     // cose-encrypt0 message in JSON format
58//!     let data: &str = r#"
59//!     {
60//!             "protected": {"alg": 24 },
61//!             "unprotected": {"kid": "11", "iv": "000102030405060700010203" },
62//!             "payload": "This is the content."
63//!     }"#;
64//!     // cose-key in JSON format
65//!     let key_json: &str = r#"
66//!     {
67//!             "kty": 4,
68//!             "alg": 24,
69//!             "k": "849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c427188",
70//!             "key ops": [3, 4]
71//!     }"#;
72//!
73//!     // Decode the cose-key JSON to CoseKey structure
74//!     let key = utils::decode_json_key(key_json).unwrap();
75//!     // Encode the cose-encrypt0 with the decoded cose-key and cose-encrypt0 JSON
76//!     let res = utils::decode_json(data, &key, ENC0_TAG).unwrap();
77//!
78//!     // Decrypt and verify
79//!     let mut dec0 = CoseMessage::new_encrypt();
80//!     dec0.bytes = res;
81//!     dec0.init_decoder(None).unwrap();
82//!
83//!     dec0.key(&key).unwrap();
84//!     let resp = dec0.decode(None, None).unwrap();
85//!     assert_eq!(resp, b"This is the content.".to_vec());
86//! }
87//! ```
88//! ## cose-mac0
89//!
90//! ```
91//! use cose::utils;
92//! use cose::message::{CoseMessage, MAC0_TAG};
93//!
94//! pub fn mac0_json() {
95//!     // cose-mac0 message in JSON format
96//!     let data: &str = r#"
97//!     {
98//!         "protected": {"crit": [1, 2], "alg": 26 },
99//!         "unprotected": {"kid": "11"},
100//!         "payload": "This is the content."
101//!     }"#;
102//!
103//!     // cose-key in JSON format
104//!     let key_json: &str = r#"
105//!     {
106//!         "kty": 4,
107//!         "alg": 26,
108//!         "k": "849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c427188",
109//!         "key ops": [9, 10]
110//!     }"#;
111//!
112//!     // Decode the cose-key JSON to CoseKey structure
113//!     let key = utils::decode_json_key(key_json).unwrap();
114//!     // Encode the cose-mac0 with the decoded cose-key and cose-mac0 JSON
115//!     let res = utils::decode_json(data, &key, MAC0_TAG).unwrap();
116//!
117//!     // Verify the MAC tag
118//!     let mut verify = CoseMessage::new_mac();
119//!     verify.bytes = res;
120//!     verify.init_decoder(None).unwrap();
121//!
122//!     verify.key(&key).unwrap();
123//!     verify.decode(None, None).unwrap();
124//! }
125//!
126//! ```
127
128use crate::common;
129#[cfg(feature = "json")]
130use crate::errors::CoseResult;
131use crate::errors::{CoseError, CoseResultWithRet};
132use crate::headers;
133#[cfg(feature = "json")]
134use crate::keys;
135use crate::message;
136#[cfg(feature = "json")]
137use crate::message::CoseMessage;
138use cbor::{types::Tag, Config, Decoder};
139#[cfg(feature = "json")]
140use hex;
141#[cfg(feature = "json")]
142use serde_json::Value;
143use std::io::Cursor;
144
145/// Function that with a given COSE message bytes, identifies the corresponding message type.
146///
147/// This only works if the message is properly tagged.
148pub fn cose_type_finder(bytes: &Vec<u8>) -> CoseResultWithRet<String> {
149    let input = Cursor::new(bytes);
150    let mut decoder = Decoder::new(Config::default(), input);
151    let tag = decoder.tag()?;
152    match tag {
153        Tag::Unassigned(message::ENC0_TAG) => Ok(message::ENC0_TYPE.to_string()),
154        Tag::Unassigned(message::MAC0_TAG) => Ok(message::MAC0_TYPE.to_string()),
155        Tag::Unassigned(message::SIG1_TAG) => Ok(message::SIG1_TYPE.to_string()),
156        Tag::Unassigned(message::ENC_TAG) => Ok(message::ENC_TYPE.to_string()),
157        Tag::Unassigned(message::MAC_TAG) => Ok(message::MAC_TYPE.to_string()),
158        Tag::Unassigned(message::SIG_TAG) => Ok(message::SIG_TYPE.to_string()),
159        _ => Err(CoseError::InvalidCoseStructure()),
160    }
161}
162
163/// Function that encodes a json object to a COSE message and applies the respective cryptographic
164/// operations with the given cose-key.
165///
166/// `tag` parameter is the COSE message type identifier.
167#[cfg(feature = "json")]
168pub fn decode_json(
169    message_json: &str,
170    key: &keys::CoseKey,
171    tag: u64,
172) -> CoseResultWithRet<Vec<u8>> {
173    let message_value: Value = serde_json::from_str(message_json)?;
174    let mut header = headers::CoseHeader::new();
175    decode_json_header(&mut header, &message_value["protected"].to_string(), true)?;
176    decode_json_header(
177        &mut header,
178        &message_value["unprotected"].to_string(),
179        false,
180    )?;
181    let payload = match &message_value["payload"] {
182        Value::String(r) => r.as_bytes().to_vec(),
183        _ => Vec::new(),
184    };
185
186    if tag == message::SIG1_TAG {
187        let mut sign = CoseMessage::new_sign();
188        sign.payload(payload);
189        sign.add_header(header);
190        sign.key(&key)?;
191        sign.secure_content(None)?;
192        sign.encode(true)?;
193        Ok(sign.bytes)
194    } else if tag == message::ENC0_TAG {
195        let mut enc = CoseMessage::new_encrypt();
196        enc.payload(payload);
197        enc.add_header(header);
198        enc.key(&key)?;
199        enc.secure_content(None)?;
200        enc.encode(true)?;
201        Ok(enc.bytes)
202    } else if tag == message::MAC0_TAG {
203        let mut mac = CoseMessage::new_mac();
204        mac.payload(payload);
205        mac.add_header(header);
206        mac.key(&key)?;
207        mac.secure_content(None)?;
208        mac.encode(true)?;
209        Ok(mac.bytes)
210    } else {
211        Ok(Vec::new())
212    }
213}
214
215#[cfg(feature = "json")]
216fn decode_json_header(
217    header: &mut headers::CoseHeader,
218    json_header: &str,
219    prot: bool,
220) -> CoseResult {
221    let json_value: Value = serde_json::from_str(json_header)?;
222    if json_value.get("crit").is_some() {
223        for i in json_value["crit"].as_array().unwrap().to_vec() {
224            header.crit.push(i.as_i64().unwrap() as i32);
225        }
226    }
227    if json_value.get("alg").is_some() {
228        let alg = match &json_value["alg"] {
229            Value::String(r) => common::get_alg_id(r.to_string())?,
230            Value::Number(v) => v.as_i64().unwrap() as i32,
231            _ => 0,
232        };
233        header.alg(alg, prot, false);
234    }
235    if json_value.get("kid").is_some() {
236        header.kid(
237            json_value["kid"].as_str().unwrap().as_bytes().to_vec(),
238            prot,
239            false,
240        );
241    }
242    if json_value.get("iv").is_some() {
243        header.iv(
244            hex::decode(json_value["iv"].as_str().unwrap().to_string())?,
245            prot,
246            false,
247        );
248    }
249    if json_value.get("partial iv").is_some() {
250        header.partial_iv(
251            hex::decode(json_value["partial iv"].as_str().unwrap().to_string())?,
252            prot,
253            false,
254        );
255    }
256    if json_value.get("content type").is_some() {
257        match &json_value["content_type"] {
258            Value::String(r) => {
259                header.content_type(
260                    headers::ContentTypeTypes::Tstr(r.as_str().to_string()),
261                    prot,
262                    false,
263                );
264            }
265            Value::Number(v) => {
266                header.content_type(
267                    headers::ContentTypeTypes::Uint(v.as_u64().unwrap() as u32),
268                    prot,
269                    false,
270                );
271            }
272            _ => (),
273        };
274    }
275    Ok(())
276}
277
278/// Function to decode a json object to a cose-key structure.
279#[cfg(feature = "json")]
280pub fn decode_json_key(json_key: &str) -> CoseResultWithRet<keys::CoseKey> {
281    let json_value: Value = serde_json::from_str(json_key)?;
282    let mut key = keys::CoseKey::new();
283    if json_value.get("alg").is_some() {
284        let alg = match &json_value["alg"] {
285            Value::String(r) => common::get_alg_id(r.to_string())?,
286            Value::Number(v) => v.as_i64().unwrap() as i32,
287            _ => 0,
288        };
289        key.alg(alg);
290    }
291    if json_value.get("kty").is_some() {
292        let kty = match &json_value["kty"] {
293            Value::String(r) => common::get_kty_id(r.to_string())?,
294            Value::Number(v) => v.as_i64().unwrap() as i32,
295            _ => 0,
296        };
297        key.kty(kty);
298    }
299    if json_value.get("crv").is_some() {
300        let crv = match &json_value["crv"] {
301            Value::String(r) => common::get_crv_id(r.to_string())?,
302            Value::Number(v) => v.as_i64().unwrap() as i32,
303            _ => 0,
304        };
305        key.crv(crv);
306    }
307    if json_value.get("key ops").is_some() {
308        let mut key_ops = Vec::new();
309        for i in json_value["key ops"].as_array().unwrap().to_vec() {
310            key_ops.push(match i {
311                Value::String(r) => common::get_key_op_id(r.to_string())?,
312                Value::Number(v) => v.as_i64().unwrap() as i32,
313                _ => 0,
314            });
315        }
316        key.key_ops(key_ops);
317    }
318    if json_value.get("x").is_some() {
319        key.x(hex::decode(json_value["x"].as_str().unwrap().to_string())?);
320    }
321    if json_value.get("y").is_some() {
322        match &json_value["y"] {
323            Value::String(r) => {
324                key.y(hex::decode(r.as_str().to_string())?);
325            }
326            _ => {}
327        };
328    }
329    if json_value.get("d").is_some() {
330        key.d(hex::decode(json_value["d"].as_str().unwrap().to_string())?);
331    }
332    if json_value.get("k").is_some() {
333        key.k(hex::decode(json_value["k"].as_str().unwrap().to_string())?);
334    }
335    Ok(key)
336}