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