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 if tag == Tag::Unassigned(message::ENC0_TAG) {
153 Ok(message::ENC0_TYPE.to_string())
154 } else if tag == Tag::Unassigned(message::MAC0_TAG) {
155 Ok(message::MAC0_TYPE.to_string())
156 } else if tag == Tag::Unassigned(message::SIG1_TAG) {
157 Ok(message::SIG1_TYPE.to_string())
158 } else if tag == Tag::Unassigned(message::ENC_TAG) {
159 Ok(message::ENC_TYPE.to_string())
160 } else if tag == Tag::Unassigned(message::MAC_TAG) {
161 Ok(message::MAC_TYPE.to_string())
162 } else if tag == Tag::Unassigned(message::SIG_TAG) {
163 Ok(message::SIG_TYPE.to_string())
164 } else {
165 Err(CoseError::InvalidCoseStructure())
166 }
167}
168
169/// Function that encodes a json object to a COSE message and applies the respective cryptographic
170/// operations with the given cose-key.
171///
172/// `tag` parameter is the COSE message type identifier.
173#[cfg(feature = "json")]
174pub fn decode_json(
175 message_json: &str,
176 key: &keys::CoseKey,
177 tag: u64,
178) -> CoseResultWithRet<Vec<u8>> {
179 let message_value: Value = serde_json::from_str(message_json)?;
180 let mut header = headers::CoseHeader::new();
181 decode_json_header(&mut header, &message_value["protected"].to_string(), true)?;
182 decode_json_header(
183 &mut header,
184 &message_value["unprotected"].to_string(),
185 false,
186 )?;
187 let payload = match &message_value["payload"] {
188 Value::String(r) => r.as_bytes().to_vec(),
189 _ => Vec::new(),
190 };
191
192 if tag == message::SIG1_TAG {
193 let mut sign = CoseMessage::new_sign();
194 sign.payload(payload);
195 sign.add_header(header);
196 sign.key(&key)?;
197 sign.secure_content(None)?;
198 sign.encode(true)?;
199 Ok(sign.bytes)
200 } else if tag == message::ENC0_TAG {
201 let mut enc = CoseMessage::new_encrypt();
202 enc.payload(payload);
203 enc.add_header(header);
204 enc.key(&key)?;
205 enc.secure_content(None)?;
206 enc.encode(true)?;
207 Ok(enc.bytes)
208 } else if tag == message::MAC0_TAG {
209 let mut mac = CoseMessage::new_mac();
210 mac.payload(payload);
211 mac.add_header(header);
212 mac.key(&key)?;
213 mac.secure_content(None)?;
214 mac.encode(true)?;
215 Ok(mac.bytes)
216 } else {
217 Ok(Vec::new())
218 }
219}
220
221#[cfg(feature = "json")]
222fn decode_json_header(
223 header: &mut headers::CoseHeader,
224 json_header: &str,
225 prot: bool,
226) -> CoseResult {
227 let json_value: Value = serde_json::from_str(json_header)?;
228 if json_value.get("crit") != None {
229 for i in json_value["crit"].as_array().unwrap().to_vec() {
230 header.crit.push(i.as_i64().unwrap() as i32);
231 }
232 }
233 if json_value.get("alg") != None {
234 let alg = match &json_value["alg"] {
235 Value::String(r) => common::get_alg_id(r.to_string())?,
236 Value::Number(v) => v.as_i64().unwrap() as i32,
237 _ => 0,
238 };
239 header.alg(alg, prot, false);
240 }
241 if json_value.get("kid") != None {
242 header.kid(
243 json_value["kid"].as_str().unwrap().as_bytes().to_vec(),
244 prot,
245 false,
246 );
247 }
248 if json_value.get("iv") != None {
249 header.iv(
250 hex::decode(json_value["iv"].as_str().unwrap().to_string())?,
251 prot,
252 false,
253 );
254 }
255 if json_value.get("partial iv") != None {
256 header.partial_iv(
257 hex::decode(json_value["partial iv"].as_str().unwrap().to_string())?,
258 prot,
259 false,
260 );
261 }
262 if json_value.get("content type") != None {
263 match &json_value["content_type"] {
264 Value::String(r) => {
265 header.content_type(
266 headers::ContentTypeTypes::Tstr(r.as_str().to_string()),
267 prot,
268 false,
269 );
270 }
271 Value::Number(v) => {
272 header.content_type(
273 headers::ContentTypeTypes::Uint(v.as_u64().unwrap() as u32),
274 prot,
275 false,
276 );
277 }
278 _ => (),
279 };
280 }
281 Ok(())
282}
283
284/// Function to decode a json object to a cose-key structure.
285#[cfg(feature = "json")]
286pub fn decode_json_key(json_key: &str) -> CoseResultWithRet<keys::CoseKey> {
287 let json_value: Value = serde_json::from_str(json_key)?;
288 let mut key = keys::CoseKey::new();
289 if json_value.get("alg") != None {
290 let alg = match &json_value["alg"] {
291 Value::String(r) => common::get_alg_id(r.to_string())?,
292 Value::Number(v) => v.as_i64().unwrap() as i32,
293 _ => 0,
294 };
295 key.alg(alg);
296 }
297 if json_value.get("kty") != None {
298 let kty = match &json_value["kty"] {
299 Value::String(r) => common::get_kty_id(r.to_string())?,
300 Value::Number(v) => v.as_i64().unwrap() as i32,
301 _ => 0,
302 };
303 key.kty(kty);
304 }
305 if json_value.get("crv") != None {
306 let crv = match &json_value["crv"] {
307 Value::String(r) => common::get_crv_id(r.to_string())?,
308 Value::Number(v) => v.as_i64().unwrap() as i32,
309 _ => 0,
310 };
311 key.crv(crv);
312 }
313 if json_value.get("key ops") != None {
314 let mut key_ops = Vec::new();
315 for i in json_value["key ops"].as_array().unwrap().to_vec() {
316 key_ops.push(match i {
317 Value::String(r) => common::get_key_op_id(r.to_string())?,
318 Value::Number(v) => v.as_i64().unwrap() as i32,
319 _ => 0,
320 });
321 }
322 key.key_ops(key_ops);
323 }
324 if json_value.get("x") != None {
325 key.x(hex::decode(json_value["x"].as_str().unwrap().to_string())?);
326 }
327 if json_value.get("y") != None {
328 match &json_value["y"] {
329 Value::String(r) => {
330 key.y(hex::decode(r.as_str().to_string())?);
331 }
332 _ => {}
333 };
334 }
335 if json_value.get("d") != None {
336 key.d(hex::decode(json_value["d"].as_str().unwrap().to_string())?);
337 }
338 if json_value.get("k") != None {
339 key.k(hex::decode(json_value["k"].as_str().unwrap().to_string())?);
340 }
341 Ok(key)
342}