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 use super::*;
18 use crate::{cbor::value::Value, iana, util::expect_err, CborOrdering, CborSerializable};
19 use alloc::{borrow::ToOwned, string::ToString, vec};
20
21 #[test]
test_cose_key_encode()22 fn test_cose_key_encode() {
23 let tests = vec![
24 (
25 CoseKey {
26 kty: KeyType::Assigned(iana::KeyType::OKP),
27 key_id: vec![1, 2, 3],
28 ..Default::default()
29 },
30 concat!(
31 "a2", // 2-map
32 "01", "01", // 1 (kty) => OKP
33 "02", "43", "010203" // 2 (kid) => 3-bstr
34 ),
35 ),
36 (
37 CoseKey {
38 kty: KeyType::Assigned(iana::KeyType::OKP),
39 ..Default::default()
40 },
41 concat!(
42 "a1", // 1-map
43 "01", "01", // 1 (kty) => OKP
44 ),
45 ),
46 (
47 CoseKey {
48 kty: KeyType::Text("bc".to_owned()),
49 ..Default::default()
50 },
51 concat!(
52 "a1", // 1-map
53 "01", "62", "6263" // 1 (kty) => "bc"
54 ),
55 ),
56 (
57 CoseKey {
58 kty: KeyType::Assigned(iana::KeyType::OKP),
59 base_iv: vec![3, 2, 1],
60 ..Default::default()
61 },
62 concat!(
63 "a2", // 2-map
64 "01", "01", // 1 (kty) => OKP
65 "05", "43", "030201", // 5 (base_iv) => 3-bstr
66 ),
67 ),
68 (
69 CoseKey {
70 kty: KeyType::Assigned(iana::KeyType::OKP),
71 alg: Some(Algorithm::Assigned(iana::Algorithm::ES256)),
72 ..Default::default()
73 },
74 concat!(
75 "a2", // 2-map
76 "01", "01", // 1 (kty) => OKP
77 "03", "26", // 3 (alg) => -7
78 ),
79 ),
80 (
81 CoseKey {
82 kty: KeyType::Assigned(iana::KeyType::OKP),
83 alg: Some(Algorithm::PrivateUse(-70_000)),
84 ..Default::default()
85 },
86 concat!(
87 "a2", // 2-map
88 "01", "01", // 1 (kty) => OKP
89 "03", "3a", "0001116f", // 3 (alg) => -70000
90 ),
91 ),
92 (
93 CoseKey {
94 kty: KeyType::Assigned(iana::KeyType::OKP),
95 alg: Some(Algorithm::Text("abc".to_owned())),
96 ..Default::default()
97 },
98 concat!(
99 "a2", // 2-map
100 "01", "01", // 1 (kty) => OKP
101 "03", "63", "616263", // 3 (alg) => "abc"
102 ),
103 ),
104 (
105 CoseKey {
106 kty: KeyType::Assigned(iana::KeyType::OKP),
107 key_id: vec![1, 2, 3],
108 key_ops: vec![
109 KeyOperation::Assigned(iana::KeyOperation::Encrypt),
110 KeyOperation::Assigned(iana::KeyOperation::Decrypt),
111 KeyOperation::Text("abc".to_owned()),
112 ]
113 .into_iter()
114 .collect(),
115 ..Default::default()
116 },
117 concat!(
118 "a3", // 3-map
119 "01", "01", // 1 (kty) => OKP
120 "02", "43", "010203", // 2 (kid) => 3-bstr
121 "04", "83", "03", "04", "63616263", // 4 (key_ops) => 3-tuple [3,4,"abc"]
122 ),
123 ),
124 (
125 CoseKey {
126 kty: KeyType::Assigned(iana::KeyType::OKP),
127 params: vec![
128 (Label::Int(0x46), Value::from(0x47)),
129 (Label::Int(0x66), Value::from(0x67)),
130 ],
131 ..Default::default()
132 },
133 concat!(
134 "a3", // 3-map
135 "01", "01", // 1 (kty) => OKP
136 "1846", "1847", // 46 => 47 (note canonical ordering)
137 "1866", "1867", // 66 => 67
138 ),
139 ),
140 (
141 CoseKey {
142 kty: KeyType::Assigned(iana::KeyType::OKP),
143 params: vec![
144 (Label::Int(0x1234), Value::from(0x47)),
145 (Label::Text("a".to_owned()), Value::from(0x67)),
146 ],
147 ..Default::default()
148 },
149 concat!(
150 "a3", // 3-map
151 "01", "01", // 1 (kty) => OKP
152 // note canonical ordering: lexicographic
153 "191234", "1847", // 0x1234 => 47
154 "6161", "1867", // "a" => 67
155 ),
156 ),
157 (
158 CoseKey {
159 kty: KeyType::Assigned(iana::KeyType::OKP),
160 params: vec![
161 (Label::Int(0x66), Value::from(0x67)),
162 (Label::Text("a".to_owned()), Value::from(0x47)),
163 ],
164 ..Default::default()
165 },
166 concat!(
167 "a3", // 3-map
168 "01", "01", // 1 (kty) => OKP
169 "1866", "1867", // 66 => 67
170 "6161", "1847", // "a" => 47
171 ),
172 ),
173 (
174 CoseKeyBuilder::new_ec2_pub_key(
175 iana::EllipticCurve::P_256,
176 hex::decode("6b4ad240073b99cad65ab8417ce29c6844ad0ae77ce8b3f7e41233f5b9129465")
177 .unwrap(),
178 hex::decode("a7dc1c39391ab300f7b1787b6e569a031dd0750fe2509b880a41f06666fff785")
179 .unwrap(),
180 )
181 .algorithm(iana::Algorithm::ES256)
182 .param(-70000, Value::Null)
183 .build(),
184 concat!(
185 "a60102032620012158206b4ad240073b",
186 "99cad65ab8417ce29c6844ad0ae77ce8",
187 "b3f7e41233f5b9129465225820a7dc1c",
188 "39391ab300f7b1787b6e569a031dd075",
189 "0fe2509b880a41f06666fff7853a0001",
190 "116ff6"
191 ),
192 ),
193 (
194 CoseKeyBuilder::new_ec2_pub_key_y_sign(
195 iana::EllipticCurve::P_256,
196 hex::decode("aabbcc").unwrap(),
197 false,
198 )
199 .build(),
200 concat!(
201 "a4", // 3-map
202 "01", "02", // 1 (kty) => 2 (EC2)
203 "20", "01", // -1 (crv) => 1 (P_256)
204 "21", "43", "aabbcc", // -2 (x) => 3-bstr
205 "22", "f4" // -3 (y) => false
206 ),
207 ),
208 ];
209 for (i, (key, key_data)) in tests.iter().enumerate() {
210 let got = key.clone().to_vec().unwrap();
211 assert_eq!(*key_data, hex::encode(&got), "case {}", i);
212
213 let got = CoseKey::from_slice(&got).unwrap();
214 assert_eq!(*key, got);
215 }
216
217 // Now combine all of the keys into a `CoseKeySet`
218 let keyset = CoseKeySet(tests.iter().map(|(l, _v)| l.clone()).collect());
219 let mut keyset_data: Vec<u8> = vec![0x80u8 + (tests.len() as u8)]; // assumes fewer than 24 keys
220 for (_, key_data) in tests.iter() {
221 keyset_data.extend_from_slice(&hex::decode(key_data).unwrap());
222 }
223 let got_data = keyset.clone().to_vec().unwrap();
224 assert_eq!(hex::encode(keyset_data), hex::encode(&got_data));
225
226 let got = CoseKeySet::from_slice(&got_data).unwrap();
227 assert_eq!(got, keyset);
228 }
229
230 #[test]
test_rfc8152_public_cose_key_decode()231 fn test_rfc8152_public_cose_key_decode() {
232 // Public keys from RFC8152 section 6.7.1.
233 // Note that map contents have been reordered into canonical order.
234 let tests = vec![
235 (
236 CoseKeyBuilder::new_ec2_pub_key(
237 iana::EllipticCurve::P_256,
238 hex::decode("65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d").unwrap(),
239 hex::decode("1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c").unwrap(),
240 ).key_id(b"[email protected]".to_vec()).build(),
241 concat!(
242 "a5",
243 "0102",
244 "0258246d65726961646f632e6272616e64796275636b406275636b6c616e642e6578616d706c65",
245 "2001",
246 "21582065eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d",
247 "2258201e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c",
248 ),
249 ),
250 (
251 CoseKeyBuilder::new_ec2_pub_key(
252 iana::EllipticCurve::P_256,
253 hex::decode("bac5b11cad8f99f9c72b05cf4b9e26d244dc189f745228255a219a86d6a09eff").unwrap(),
254 hex::decode("20138bf82dc1b6d562be0fa54ab7804a3a64b6d72ccfed6b6fb6ed28bbfc117e").unwrap(),
255 ).key_id(b"11".to_vec()).build(),
256 concat!("a5",
257 "0102",
258 "02423131",
259 "2001",
260 "215820bac5b11cad8f99f9c72b05cf4b9e26d244dc189f745228255a219a86d6a09eff",
261 "22582020138bf82dc1b6d562be0fa54ab7804a3a64b6d72ccfed6b6fb6ed28bbfc117e",
262 ),
263 ),
264 (
265 CoseKeyBuilder::new_ec2_pub_key(
266 iana::EllipticCurve::P_521,
267 hex::decode("0072992cb3ac08ecf3e5c63dedec0d51a8c1f79ef2f82f94f3c737bf5de7986671eac625fe8257bbd0394644caaa3aaf8f27a4585fbbcad0f2457620085e5c8f42ad").unwrap(),
268 hex::decode("01dca6947bce88bc5790485ac97427342bc35f887d86d65a089377e247e60baa55e4e8501e2ada5724ac51d6909008033ebc10ac999b9d7f5cc2519f3fe1ea1d9475").unwrap(),
269 ).key_id(
270 b"[email protected]".to_vec()).build(),
271 concat!("a5",
272 "0102",
273 "02581e62696c626f2e62616767696e7340686f626269746f6e2e6578616d706c65",
274 "2003",
275 "2158420072992cb3ac08ecf3e5c63dedec0d51a8c1f79ef2f82f94f3c737bf5de7986671eac625fe8257bbd0394644caaa3aaf8f27a4585fbbcad0f2457620085e5c8f42ad",
276 "22584201dca6947bce88bc5790485ac97427342bc35f887d86d65a089377e247e60baa55e4e8501e2ada5724ac51d6909008033ebc10ac999b9d7f5cc2519f3fe1ea1d9475",
277 ),
278 ),
279 (
280 CoseKeyBuilder::new_ec2_pub_key(
281 iana::EllipticCurve::P_256,
282 hex::decode("98f50a4ff6c05861c8860d13a638ea56c3f5ad7590bbfbf054e1c7b4d91d6280").unwrap(),
283 hex::decode("f01400b089867804b8e9fc96c3932161f1934f4223069170d924b7e03bf822bb").unwrap(),
284 ).key_id(b"[email protected]".to_vec()).build(),
285 concat!("a5",
286 "0102",
287 "025821706572656772696e2e746f6f6b407475636b626f726f7567682e6578616d706c65",
288 "2001",
289 "21582098f50a4ff6c05861c8860d13a638ea56c3f5ad7590bbfbf054e1c7b4d91d6280",
290 "225820f01400b089867804b8e9fc96c3932161f1934f4223069170d924b7e03bf822bb",
291 )
292 ),
293 ];
294 for (i, (key, key_data)) in tests.iter().enumerate() {
295 let got = key.clone().to_vec().unwrap();
296 assert_eq!(*key_data, hex::encode(&got), "case {}", i);
297
298 let got = CoseKey::from_slice(&got).unwrap();
299 assert_eq!(*key, got);
300 }
301
302 // Now combine all of the keys into a `CoseKeySet`
303 let keyset = CoseKeySet(tests.iter().map(|(l, _v)| l.clone()).collect());
304 let mut keyset_data: Vec<u8> = vec![0x80u8 + (tests.len() as u8)]; // assumes fewer than 24 keys
305 for (_, key_data) in tests.iter() {
306 keyset_data.extend_from_slice(&hex::decode(key_data).unwrap());
307 }
308 let got = keyset.to_vec().unwrap();
309 assert_eq!(hex::encode(keyset_data), hex::encode(got));
310 }
311
312 #[test]
test_rfc8152_private_cose_key_decode()313 fn test_rfc8152_private_cose_key_decode() {
314 // Private keys from RFC8152 section 6.7.2.
315 // Note that map contents have been reordered into canonical order.
316 let tests = vec![
317 (
318 CoseKeyBuilder::new_ec2_priv_key(
319 iana::EllipticCurve::P_256,
320 hex::decode("65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d").unwrap(),
321 hex::decode("1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c").unwrap(),
322 hex::decode("aff907c99f9ad3aae6c4cdf21122bce2bd68b5283e6907154ad911840fa208cf").unwrap(),
323 ).key_id(b"[email protected]".to_vec()).build(),
324 concat!(
325 "a6",
326 "0102",
327 "0258246d65726961646f632e6272616e64796275636b406275636b6c616e642e6578616d706c65",
328 "2001",
329 "21582065eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d",
330 "2258201e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c",
331 "235820aff907c99f9ad3aae6c4cdf21122bce2bd68b5283e6907154ad911840fa208cf",
332 ),
333 ),
334 (
335 CoseKeyBuilder::new_ec2_priv_key(
336 iana::EllipticCurve::P_256,
337 hex::decode("bac5b11cad8f99f9c72b05cf4b9e26d244dc189f745228255a219a86d6a09eff").unwrap(),
338 hex::decode("20138bf82dc1b6d562be0fa54ab7804a3a64b6d72ccfed6b6fb6ed28bbfc117e").unwrap(),
339 hex::decode("57c92077664146e876760c9520d054aa93c3afb04e306705db6090308507b4d3").unwrap(),
340 ).key_id(b"11".to_vec()).build(),
341 concat!("a6",
342 "0102",
343 "02423131",
344 "2001",
345 "215820bac5b11cad8f99f9c72b05cf4b9e26d244dc189f745228255a219a86d6a09eff",
346 "22582020138bf82dc1b6d562be0fa54ab7804a3a64b6d72ccfed6b6fb6ed28bbfc117e",
347 "23582057c92077664146e876760c9520d054aa93c3afb04e306705db6090308507b4d3",
348 ),
349 ),
350 (
351 CoseKeyBuilder::new_ec2_priv_key(
352 iana::EllipticCurve::P_521,
353 hex::decode("0072992cb3ac08ecf3e5c63dedec0d51a8c1f79ef2f82f94f3c737bf5de7986671eac625fe8257bbd0394644caaa3aaf8f27a4585fbbcad0f2457620085e5c8f42ad").unwrap(),
354 hex::decode("01dca6947bce88bc5790485ac97427342bc35f887d86d65a089377e247e60baa55e4e8501e2ada5724ac51d6909008033ebc10ac999b9d7f5cc2519f3fe1ea1d9475").unwrap(),
355 hex::decode("00085138ddabf5ca975f5860f91a08e91d6d5f9a76ad4018766a476680b55cd339e8ab6c72b5facdb2a2a50ac25bd086647dd3e2e6e99e84ca2c3609fdf177feb26d").unwrap(),
356 ).key_id(b"[email protected]".to_vec()).build(),
357 concat!("a6",
358 "0102",
359 "02581e62696c626f2e62616767696e7340686f626269746f6e2e6578616d706c65",
360 "2003",
361 "2158420072992cb3ac08ecf3e5c63dedec0d51a8c1f79ef2f82f94f3c737bf5de7986671eac625fe8257bbd0394644caaa3aaf8f27a4585fbbcad0f2457620085e5c8f42ad",
362 "22584201dca6947bce88bc5790485ac97427342bc35f887d86d65a089377e247e60baa55e4e8501e2ada5724ac51d6909008033ebc10ac999b9d7f5cc2519f3fe1ea1d9475",
363 "23584200085138ddabf5ca975f5860f91a08e91d6d5f9a76ad4018766a476680b55cd339e8ab6c72b5facdb2a2a50ac25bd086647dd3e2e6e99e84ca2c3609fdf177feb26d",
364 ),
365 ),
366 (
367 CoseKey {
368 kty: KeyType::Assigned(iana::KeyType::Symmetric),
369 key_id: b"our-secret".to_vec(),
370 params: vec![
371 (Label::Int(iana::SymmetricKeyParameter::K as i64) ,
372 Value::Bytes(hex::decode("849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c427188").unwrap())),
373 ],
374 ..Default::default()
375 },
376 concat!("a3",
377 "0104",
378 "024a6f75722d736563726574",
379 "205820849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c427188",
380 ),
381 ),
382 (
383 CoseKeyBuilder::new_ec2_priv_key(
384 iana::EllipticCurve::P_256,
385 hex::decode("98f50a4ff6c05861c8860d13a638ea56c3f5ad7590bbfbf054e1c7b4d91d6280").unwrap(),
386 hex::decode("f01400b089867804b8e9fc96c3932161f1934f4223069170d924b7e03bf822bb").unwrap(),
387 hex::decode("02d1f7e6f26c43d4868d87ceb2353161740aacf1f7163647984b522a848df1c3").unwrap(),
388 ).key_id(b"[email protected]".to_vec()).build(),
389 concat!("a6",
390 "0102",
391 "025821706572656772696e2e746f6f6b407475636b626f726f7567682e6578616d706c65",
392 "2001",
393 "21582098f50a4ff6c05861c8860d13a638ea56c3f5ad7590bbfbf054e1c7b4d91d6280",
394 "225820f01400b089867804b8e9fc96c3932161f1934f4223069170d924b7e03bf822bb",
395 "23582002d1f7e6f26c43d4868d87ceb2353161740aacf1f7163647984b522a848df1c3",
396 )
397 ),
398 (
399 CoseKey {
400 kty: KeyType::Assigned(iana::KeyType::Symmetric),
401 key_id: b"our-secret2".to_vec(),
402 params: vec![(
403 Label::Int(iana::SymmetricKeyParameter::K as i64) ,
404 Value::Bytes(hex::decode("849b5786457c1491be3a76dcea6c4271").unwrap()),
405 )],
406 ..Default::default()
407 },
408 concat!("a3",
409 "0104",
410 "024b6f75722d73656372657432",
411 "2050849b5786457c1491be3a76dcea6c4271",
412 ),
413 ),
414 (
415 CoseKey {
416 kty: KeyType::Assigned(iana::KeyType::Symmetric),
417 key_id: b"018c0ae5-4d9b-471b-bfd6-eef314bc7037".to_vec(),
418 params: vec![(
419 Label::Int(iana::SymmetricKeyParameter::K as i64) ,
420 Value::Bytes(hex::decode("849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c427188").unwrap()),
421 )],
422 ..Default::default()
423 },
424 concat!("a3",
425 "0104",
426 "02582430313863306165352d346439622d343731622d626664362d656566333134626337303337",
427 "205820849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c427188",
428 ),
429 ),
430 ];
431 for (i, (key, key_data)) in tests.iter().enumerate() {
432 let got = key.clone().to_vec().unwrap();
433 assert_eq!(*key_data, hex::encode(&got), "case {}", i);
434
435 let got = CoseKey::from_slice(&got).unwrap();
436 assert_eq!(*key, got);
437 }
438
439 // Now combine all of the keys into a `CoseKeySet`
440 let keyset = CoseKeySet(tests.iter().map(|(l, _v)| l.clone()).collect());
441 let mut keyset_data: Vec<u8> = vec![0x80u8 + (tests.len() as u8)]; // assumes fewer than 24 keys
442 for (_, key_data) in tests.iter() {
443 keyset_data.extend_from_slice(&hex::decode(key_data).unwrap());
444 }
445 let got = keyset.to_vec().unwrap();
446 assert_eq!(hex::encode(keyset_data), hex::encode(got));
447 }
448
449 #[test]
test_cose_key_decode_fail()450 fn test_cose_key_decode_fail() {
451 let tests = vec![
452 (
453 concat!(
454 "82", // 2-tuple (invalid)
455 "01", "01", // 1 (kty) => OKP
456 ),
457 "expected map",
458 ),
459 (
460 concat!(
461 "a2", // 2-map
462 "01", "11", // 1 (kty) => invalid value
463 "02", "43", "010203" // 2 (kid) => 3-bstr
464 ),
465 "expected recognized IANA value",
466 ),
467 (
468 concat!(
469 "a2", // 2-map
470 "01", "4101", // 1 (kty) => 1-bstr (invalid value type)
471 "02", "43", "010203" // 2 (kid) => 3-bstr
472 ),
473 "expected int/tstr",
474 ),
475 (
476 concat!(
477 "a1", // 1-map (no kty value)
478 "02", "41", "01", // 2 (kid) => 1-bstr
479 ),
480 "expected mandatory kty label",
481 ),
482 (
483 concat!(
484 "a2", // 2-map
485 "01", "01", // 1 (kty) => OKP
486 "02", "40", // 2 (kid) => 0-bstr
487 ),
488 "expected non-empty bstr",
489 ),
490 (
491 concat!(
492 "a2", // 2-map
493 "01", "01", // 1 (kty) => OKP
494 "02", "01", // 2 (kid) => int (invalid value type)
495 ),
496 "expected bstr",
497 ),
498 (
499 concat!(
500 "a2", // 2-map
501 "01", "01", // 1 (kty) => OKP
502 "03", "1899", // 3 (alg) => 0x99
503 ),
504 "expected value in IANA or private use range",
505 ),
506 (
507 concat!(
508 "a2", // 2-map
509 "01", "01", // 1 (kty) => OKP
510 "03", "4101", // 3 (alg) => 1-bstr (invalid value type)
511 ),
512 "expected int/tstr",
513 ),
514 (
515 concat!(
516 "a2", // 2-map
517 "01", "01", // 1 (kty) => OKP
518 "04", "4101", // 4 (key_ops) => 1-bstr (invalid value type)
519 ),
520 "expected array",
521 ),
522 (
523 concat!(
524 "a2", // 2-map
525 "01", "01", // 1 (kty) => OKP
526 "04", "82", "03", "03", // 4 (key_ops) => 3-tuple [3,3]
527 ),
528 "expected unique array label",
529 ),
530 (
531 concat!(
532 "a2", // 2-map
533 "01", "01", // 1 (kty) => OKP
534 "04", "80", // 4 (key_ops) => 0-tuple []
535 ),
536 "expected non-empty array",
537 ),
538 (
539 concat!(
540 "a2", // 2-map
541 "01", "01", // 1 (kty) => OKP
542 "04", "82", "03", "0b", // 4 (key_ops) => 3-tuple [3,11]
543 ),
544 "expected recognized IANA value",
545 ),
546 (
547 concat!(
548 "a2", // 2-map
549 "01", "01", // 1 (kty) => OKP
550 "05", "40", // 5 (base_iv) => 0-bstr
551 ),
552 "expected non-empty bstr",
553 ),
554 (
555 concat!(
556 "a2", // 2-map
557 "01", "01", // 1 (kty) => OKP
558 "05", "01", // 5 (base_iv) => int (invalid value type)
559 ),
560 "expected bstr",
561 ),
562 ];
563 for (key_data, err_msg) in tests.iter() {
564 let data = hex::decode(key_data).unwrap();
565 let result = CoseKey::from_slice(&data);
566 expect_err(result, err_msg);
567 }
568 }
569
570 #[test]
test_cose_keyset_decode_fail()571 fn test_cose_keyset_decode_fail() {
572 let tests = [(
573 concat!(
574 "a1", // 1-map
575 "a1", // 1-map
576 "01", "01", // 1 (kty) => OKP
577 "00"
578 ),
579 "expected array",
580 )];
581 for (keyset_data, err_msg) in tests.iter() {
582 let data = hex::decode(keyset_data).unwrap();
583 let result = CoseKeySet::from_slice(&data);
584 expect_err(result, err_msg);
585 }
586 }
587
588 #[test]
test_cose_key_decode_dup_fail()589 fn test_cose_key_decode_dup_fail() {
590 let tests = [
591 (
592 concat!(
593 "a3", // 3-map
594 "01", "01", // 1 (kty) => OKP
595 "1866", "1867", // 66 => 67
596 "1866", "1847", // 66 => 47
597 ),
598 "duplicate map key",
599 ),
600 (
601 concat!(
602 "a3", // 3-map
603 "01", "01", // 1 (kty) => OKP
604 "02", "41", "01", // 2 (kid) => 1-bstr
605 "01", "01", // 1 (kty) => OKP (duplicate label)
606 ),
607 "duplicate map key",
608 ),
609 ];
610 for (key_data, err_msg) in tests.iter() {
611 let data = hex::decode(key_data).unwrap();
612 let result = CoseKey::from_slice(&data);
613 expect_err(result, err_msg);
614 }
615 }
616
617 #[test]
test_cose_key_encode_dup_fail()618 fn test_cose_key_encode_dup_fail() {
619 let tests = vec![CoseKeyBuilder::new()
620 .param(10, Value::from(0))
621 .param(10, Value::from(0))
622 .build()];
623 for key in tests {
624 let result = key.clone().to_vec();
625 expect_err(result, "duplicate map key");
626 }
627 }
628
629 #[test]
test_key_builder()630 fn test_key_builder() {
631 let tests = vec![
632 (
633 CoseKeyBuilder::new_symmetric_key(vec![1, 2, 3]).build(),
634 CoseKey {
635 kty: KeyType::Assigned(iana::KeyType::Symmetric),
636 params: vec![(
637 Label::Int(iana::SymmetricKeyParameter::K as i64),
638 Value::Bytes(vec![1, 2, 3]),
639 )],
640 ..Default::default()
641 },
642 ),
643 (
644 CoseKeyBuilder::new_symmetric_key(vec![1, 2, 3])
645 .algorithm(iana::Algorithm::A128GCM)
646 .build(),
647 CoseKey {
648 kty: KeyType::Assigned(iana::KeyType::Symmetric),
649 alg: Some(Algorithm::Assigned(iana::Algorithm::A128GCM)),
650 params: vec![(
651 Label::Int(iana::SymmetricKeyParameter::K as i64),
652 Value::Bytes(vec![1, 2, 3]),
653 )],
654 ..Default::default()
655 },
656 ),
657 (
658 CoseKeyBuilder::new_symmetric_key(vec![1, 2, 3])
659 .key_id(vec![4, 5])
660 .build(),
661 CoseKey {
662 kty: KeyType::Assigned(iana::KeyType::Symmetric),
663 key_id: vec![4, 5],
664 params: vec![(
665 Label::Int(iana::SymmetricKeyParameter::K as i64),
666 Value::Bytes(vec![1, 2, 3]),
667 )],
668 ..Default::default()
669 },
670 ),
671 (
672 CoseKeyBuilder::new_symmetric_key(vec![1, 2, 3])
673 .add_key_op(iana::KeyOperation::Encrypt)
674 .add_key_op(iana::KeyOperation::Decrypt)
675 .build(),
676 CoseKey {
677 kty: KeyType::Assigned(iana::KeyType::Symmetric),
678 key_ops: vec![
679 KeyOperation::Assigned(iana::KeyOperation::Encrypt),
680 KeyOperation::Assigned(iana::KeyOperation::Decrypt),
681 ]
682 .into_iter()
683 .collect(),
684 params: vec![(
685 Label::Int(iana::SymmetricKeyParameter::K as i64),
686 Value::Bytes(vec![1, 2, 3]),
687 )],
688 ..Default::default()
689 },
690 ),
691 (
692 CoseKeyBuilder::new_symmetric_key(vec![1, 2, 3])
693 .base_iv(vec![4, 5])
694 .build(),
695 CoseKey {
696 kty: KeyType::Assigned(iana::KeyType::Symmetric),
697 base_iv: vec![4, 5],
698 params: vec![(
699 Label::Int(iana::SymmetricKeyParameter::K as i64),
700 Value::Bytes(vec![1, 2, 3]),
701 )],
702 ..Default::default()
703 },
704 ),
705 (
706 CoseKeyBuilder::new_okp_key().build(),
707 CoseKey {
708 kty: KeyType::Assigned(iana::KeyType::OKP),
709 ..Default::default()
710 },
711 ),
712 (
713 CoseKeyBuilder::new()
714 .key_type(iana::KeyType::WalnutDSA)
715 .build(),
716 CoseKey {
717 kty: KeyType::Assigned(iana::KeyType::WalnutDSA),
718 ..Default::default()
719 },
720 ),
721 (
722 CoseKeyBuilder::new()
723 .kty(KeyType::Text("test".to_string()))
724 .build(),
725 CoseKey {
726 kty: KeyType::Text("test".to_string()),
727 ..Default::default()
728 },
729 ),
730 ];
731 for (got, want) in tests {
732 assert_eq!(got, want);
733 }
734 }
735
736 #[test]
737 #[should_panic]
test_key_builder_core_param_panic()738 fn test_key_builder_core_param_panic() {
739 // Attempting to set a core `KeyParameter` (in range [1,5]) via `.param()` panics.
740 let _key =
741 CoseKeyBuilder::new_ec2_pub_key(iana::EllipticCurve::P_256, vec![1, 2, 3], vec![2, 3, 4])
742 .param(1, Value::Null)
743 .build();
744 }
745
746 #[test]
test_key_canonicalize()747 fn test_key_canonicalize() {
748 struct TestCase {
749 key_data: &'static str, // hex
750 rfc7049_key: CoseKey,
751 rfc8949_key: CoseKey,
752 rfc7049_data: Option<&'static str>, // hex, `None` indicates same as `key_data`
753 rfc8949_data: Option<&'static str>, // hex, `None` indicates same as `key_data`
754 }
755 let tests = [
756 TestCase {
757 key_data: concat!(
758 "a2", // 2-map
759 "01", "01", // 1 (kty) => OKP
760 "03", "26", // 3 (alg) => -7
761 ),
762 rfc7049_key: CoseKey {
763 kty: KeyType::Assigned(iana::KeyType::OKP),
764 alg: Some(Algorithm::Assigned(iana::Algorithm::ES256)),
765 ..Default::default()
766 },
767 rfc8949_key: CoseKey {
768 kty: KeyType::Assigned(iana::KeyType::OKP),
769 alg: Some(Algorithm::Assigned(iana::Algorithm::ES256)),
770 ..Default::default()
771 },
772 rfc7049_data: None,
773 rfc8949_data: None,
774 },
775 TestCase {
776 key_data: concat!(
777 "a2", // 2-map
778 "03", "26", // 3 (alg) => -7
779 "01", "01", // 1 (kty) => OKP
780 ),
781 rfc7049_key: CoseKey {
782 kty: KeyType::Assigned(iana::KeyType::OKP),
783 alg: Some(Algorithm::Assigned(iana::Algorithm::ES256)),
784 ..Default::default()
785 },
786 rfc8949_key: CoseKey {
787 kty: KeyType::Assigned(iana::KeyType::OKP),
788 alg: Some(Algorithm::Assigned(iana::Algorithm::ES256)),
789 ..Default::default()
790 },
791 rfc7049_data: Some(concat!(
792 "a2", // 2-map
793 "01", "01", // 1 (kty) => OKP
794 "03", "26", // 3 (alg) => -7
795 )),
796 rfc8949_data: Some(concat!(
797 "a2", // 2-map
798 "01", "01", // 1 (kty) => OKP
799 "03", "26", // 3 (alg) => -7
800 )),
801 },
802 TestCase {
803 key_data: concat!(
804 "a4", // 4-map
805 "03", "26", // 3 (alg) => -7
806 "1904d2", "01", // 1234 => 1
807 "01", "01", // 1 (kty) => OKP
808 "6161", "01", // "a" => 1
809 ),
810 // "a" encodes shorter than 1234, so appears first
811 rfc7049_key: CoseKey {
812 kty: KeyType::Assigned(iana::KeyType::OKP),
813 alg: Some(Algorithm::Assigned(iana::Algorithm::ES256)),
814 params: vec![
815 (Label::Text("a".to_string()), Value::Integer(1.into())),
816 (Label::Int(1234), Value::Integer(1.into())),
817 ],
818 ..Default::default()
819 },
820 // 1234 encodes with leading byte 0x19, so appears before a tstr
821 rfc8949_key: CoseKey {
822 kty: KeyType::Assigned(iana::KeyType::OKP),
823 alg: Some(Algorithm::Assigned(iana::Algorithm::ES256)),
824 params: vec![
825 (Label::Int(1234), Value::Integer(1.into())),
826 (Label::Text("a".to_string()), Value::Integer(1.into())),
827 ],
828 ..Default::default()
829 },
830 rfc7049_data: Some(concat!(
831 "a4", // 4-map
832 "01", "01", // 1 (kty) => OKP
833 "03", "26", // 3 (alg) => -7
834 "6161", "01", // "a" => 1
835 "1904d2", "01", // 1234 => 1
836 )),
837 rfc8949_data: Some(concat!(
838 "a4", // 4-map
839 "01", "01", // 1 (kty) => OKP
840 "03", "26", // 3 (alg) => -7
841 "1904d2", "01", // 1234 => 1
842 "6161", "01", // "a" => 1
843 )),
844 },
845 ];
846 for testcase in tests {
847 let key_data = hex::decode(testcase.key_data).unwrap();
848 let mut key = CoseKey::from_slice(&key_data)
849 .unwrap_or_else(|e| panic!("Failed to deserialize {}: {e:?}", testcase.key_data));
850
851 // Canonicalize according to RFC 7049.
852 key.canonicalize(CborOrdering::LengthFirstLexicographic);
853 assert_eq!(
854 key, testcase.rfc7049_key,
855 "Mismatch for {}",
856 testcase.key_data
857 );
858 let got = testcase.rfc7049_key.to_vec().unwrap();
859 let want = testcase.rfc7049_data.unwrap_or(testcase.key_data);
860 assert_eq!(hex::encode(got), want, "Mismatch for {}", testcase.key_data);
861
862 // Canonicalize according to RFC 8949.
863 key.canonicalize(CborOrdering::Lexicographic);
864 assert_eq!(
865 key, testcase.rfc8949_key,
866 "Mismatch for {}",
867 testcase.key_data
868 );
869
870 let got = testcase.rfc8949_key.to_vec().unwrap();
871 let want = testcase.rfc8949_data.unwrap_or(testcase.key_data);
872 assert_eq!(hex::encode(got), want, "Mismatch for {}", testcase.key_data);
873 }
874 }
875