use super::*;
use crate::{cbor::value::Value, iana, util::expect_err, CborSerializable, Label};
use alloc::{borrow::ToOwned, vec};
#[test]
fn test_header_encode() {
let tests = [
(
Header {
alg: Some(Algorithm::Assigned(iana::Algorithm::A128GCM)),
key_id: vec![1, 2, 3],
partial_iv: vec![1, 2, 3],
..Default::default()
},
concat!(
"a3", "01", "01", "04", "43", "010203", "06", "43", "010203", ),
),
(
Header {
alg: Some(Algorithm::PrivateUse(i64::MIN)),
..Default::default()
},
concat!(
"a1", "01",
"3b7fffffffffffffff", ),
),
(
Header {
alg: Some(Algorithm::Assigned(iana::Algorithm::A128GCM)),
crit: vec![RegisteredLabelWithPrivate::Assigned(
iana::HeaderParameter::Alg,
)],
content_type: Some(ContentType::Assigned(iana::CoapContentFormat::CoseEncrypt0)),
key_id: vec![1, 2, 3],
iv: vec![1, 2, 3],
rest: vec![
(Label::Int(0x46), Value::from(0x47)),
(Label::Int(0x66), Value::from(0x67)),
],
..Default::default()
},
concat!(
"a7", "01", "01", "02", "81", "01", "03", "10", "04", "43", "010203", "05", "43", "010203", "1846", "1847", "1866", "1867", ),
),
(
Header {
alg: Some(Algorithm::Text("abc".to_owned())),
crit: vec![RegisteredLabelWithPrivate::Text("d".to_owned())],
content_type: Some(ContentType::Text("a/b".to_owned())),
key_id: vec![1, 2, 3],
iv: vec![1, 2, 3],
rest: vec![
(Label::Int(0x46), Value::from(0x47)),
(Label::Text("a".to_owned()), Value::from(0x47)),
],
counter_signatures: vec![CoseSignature {
signature: vec![1, 2, 3],
..Default::default()
}],
..Default::default()
},
concat!(
"a8", "01", "63616263", "02", "81", "6164", "03", "63612f62", "04", "43", "010203", "05", "43", "010203", "07", "83", "40", "a0", "43010203", "1846", "1847", "6161", "1847", ),
),
(
Header {
alg: Some(Algorithm::Text("abc".to_owned())),
crit: vec![RegisteredLabelWithPrivate::Text("d".to_owned())],
content_type: Some(ContentType::Text("a/b".to_owned())),
key_id: vec![1, 2, 3],
iv: vec![1, 2, 3],
rest: vec![
(Label::Int(0x46), Value::from(0x47)),
(Label::Text("a".to_owned()), Value::from(0x47)),
],
counter_signatures: vec![
CoseSignature {
signature: vec![1, 2, 3],
..Default::default()
},
CoseSignature {
signature: vec![3, 4, 5],
..Default::default()
},
],
..Default::default()
},
concat!(
"a8", "01", "63616263", "02", "81", "6164", "03", "63612f62", "04", "43", "010203", "05", "43", "010203", "07", "82", "83", "40", "a0", "43010203", "83", "40", "a0", "43030405", "1846", "1847", "6161", "1847", ),
),
(
HeaderBuilder::new()
.add_critical(iana::HeaderParameter::Alg)
.add_critical(iana::HeaderParameter::Alg)
.build(),
concat!(
"a1", "02", "820101", ),
),
(
HeaderBuilder::new()
.add_critical_label(RegisteredLabelWithPrivate::PrivateUse(-65537))
.build(),
concat!(
"a1", "02",
"81",
"3a00010000", ),
),
];
for (i, (header, header_data)) in tests.iter().enumerate() {
let got = header.clone().to_vec().unwrap();
assert_eq!(*header_data, hex::encode(&got), "case {i}");
let mut got = Header::from_slice(&got).unwrap();
for sig in &mut got.counter_signatures {
sig.protected.original_data = None;
}
assert_eq!(*header, got);
assert!(!got.is_empty());
let protected = ProtectedHeader {
original_data: None,
header: header.clone(),
};
let protected_data = protected.clone().to_vec().unwrap();
assert_eq!(*header_data, hex::encode(&protected_data), "case {i}");
let mut got = ProtectedHeader::from_slice(&protected_data).unwrap();
for sig in &mut got.header.counter_signatures {
sig.protected.original_data = None;
}
assert!(!got.is_empty());
assert_eq!(*header, got.header);
let prot_bstr_val = protected.cbor_bstr().unwrap();
let mut got = ProtectedHeader::from_cbor_bstr(prot_bstr_val).unwrap();
for sig in &mut got.header.counter_signatures {
sig.protected.original_data = None;
}
assert!(!got.is_empty());
assert_eq!(*header, got.header);
assert_eq!(
*header_data,
hex::encode(got.original_data.expect("missing original data"))
);
}
}
#[test]
fn test_header_decode_fail() {
let tests = vec![
(
concat!(
"a1", "01", "01", "01", ),
"extraneous data in CBOR input",
),
(
concat!(
"a1", "01", "08", ),
"expected value in IANA or private use range",
),
(
concat!(
"a1", "01", "4101", ),
"expected int/tstr",
),
(
concat!(
"a1", "02", "4101", ),
"expected array",
),
(
concat!(
"a1", "02", "81", "4101", ),
"expected int/tstr",
),
(
concat!(
"a1", "02", "80", ),
"expected non-empty array",
),
(
concat!(
"a1", "03", "81", "4101", ),
"expected int/tstr",
),
(
concat!(
"a1", "03", "19", "0606", ),
"expected recognized IANA value",
),
(
concat!(
"a1", "03", "64", "20612f62" ),
"expected no leading/trailing whitespace",
),
(
concat!(
"a1", "03", "64", "612f6220" ),
"expected no leading/trailing whitespace",
),
(
concat!(
"a1", "03", "62", "6162" ),
"expected text of form type/subtype",
),
(
concat!(
"a1", "03", "60", ),
"expected non-empty tstr",
),
(
concat!(
"a1", "04", "40", ),
"expected non-empty bstr",
),
(
concat!(
"a1", "04", "01", ),
"expected bstr",
),
(
concat!(
"a1", "05", "40", ),
"expected non-empty bstr",
),
(
concat!(
"a1", "05", "01", ),
"expected bstr",
),
(
concat!(
"a1", "06", "40", ),
"expected non-empty bstr",
),
(
concat!(
"a1", "06", "01", ),
"expected bstr",
),
(
concat!(
"a1", "07", "01", ),
"expected array",
),
(
concat!(
"a1", "07", "80", ),
"expected non-empty sig array",
),
(
concat!(
"a2", "05", "4101", "06", "4101", ),
"expected only one of IV and partial IV",
),
(
concat!(
"a2", "01", "63616263", "07", "82", "63616263", "83", "40", "a0", "43010203", ),
"array or bstr value",
),
];
for (header_data, err_msg) in tests.iter() {
let data = hex::decode(header_data).unwrap();
let result = Header::from_slice(&data);
expect_err(result, err_msg);
}
}
#[test]
fn test_header_decode_dup_fail() {
let tests = [
(
concat!(
"a3", "01", "01", "1866", "1867", "1866", "1847", ),
"duplicate map key",
),
(
concat!(
"a3", "01", "01", "1866", "1867", "01", "01", ),
"duplicate map key",
),
];
for (header_data, err_msg) in tests.iter() {
let data = hex::decode(header_data).unwrap();
let result = Header::from_slice(&data);
expect_err(result, err_msg);
}
}
#[test]
fn test_header_encode_dup_fail() {
let tests = vec![
Header {
alg: Some(Algorithm::Assigned(iana::Algorithm::A128GCM)),
crit: vec![RegisteredLabelWithPrivate::Assigned(
iana::HeaderParameter::Alg,
)],
content_type: Some(ContentType::Assigned(iana::CoapContentFormat::CoseEncrypt0)),
key_id: vec![1, 2, 3],
iv: vec![1, 2, 3],
rest: vec![
(Label::Int(0x46), Value::from(0x47)),
(Label::Int(0x46), Value::from(0x67)),
],
..Default::default()
},
HeaderBuilder::new()
.text_value("doop".to_owned(), Value::from(1))
.text_value("doop".to_owned(), Value::from(2))
.build(),
];
for header in tests {
let result = header.clone().to_vec();
expect_err(result, "duplicate map key");
}
}
#[test]
fn test_header_builder() {
let tests = vec![
(
HeaderBuilder::new().build(),
Header {
..Default::default()
},
),
(
HeaderBuilder::new()
.algorithm(iana::Algorithm::A128GCM)
.add_critical(iana::HeaderParameter::Alg)
.add_critical_label(RegisteredLabelWithPrivate::Text("abc".to_owned()))
.content_format(iana::CoapContentFormat::CoseEncrypt0)
.key_id(vec![1, 2, 3])
.partial_iv(vec![4, 5, 6]) .iv(vec![1, 2, 3])
.value(0x46, Value::from(0x47))
.value(0x66, Value::from(0x67))
.build(),
Header {
alg: Some(Algorithm::Assigned(iana::Algorithm::A128GCM)),
crit: vec![
RegisteredLabelWithPrivate::Assigned(iana::HeaderParameter::Alg),
RegisteredLabelWithPrivate::Text("abc".to_owned()),
],
content_type: Some(ContentType::Assigned(iana::CoapContentFormat::CoseEncrypt0)),
key_id: vec![1, 2, 3],
iv: vec![1, 2, 3],
rest: vec![
(Label::Int(0x46), Value::from(0x47)),
(Label::Int(0x66), Value::from(0x67)),
],
..Default::default()
},
),
(
HeaderBuilder::new()
.algorithm(iana::Algorithm::A128GCM)
.add_critical(iana::HeaderParameter::Alg)
.add_critical_label(RegisteredLabelWithPrivate::Text("abc".to_owned()))
.content_type("type/subtype".to_owned())
.key_id(vec![1, 2, 3])
.iv(vec![1, 2, 3]) .partial_iv(vec![4, 5, 6])
.build(),
Header {
alg: Some(Algorithm::Assigned(iana::Algorithm::A128GCM)),
crit: vec![
RegisteredLabelWithPrivate::Assigned(iana::HeaderParameter::Alg),
RegisteredLabelWithPrivate::Text("abc".to_owned()),
],
content_type: Some(ContentType::Text("type/subtype".to_owned())),
key_id: vec![1, 2, 3],
partial_iv: vec![4, 5, 6],
..Default::default()
},
),
(
HeaderBuilder::new()
.algorithm(iana::Algorithm::A128GCM)
.add_critical_label(RegisteredLabelWithPrivate::PrivateUse(-65537))
.key_id(vec![1, 2, 3])
.build(),
Header {
alg: Some(Algorithm::Assigned(iana::Algorithm::A128GCM)),
crit: vec![RegisteredLabelWithPrivate::PrivateUse(-65537)],
key_id: vec![1, 2, 3],
..Default::default()
},
),
(
HeaderBuilder::new()
.algorithm_label(Algorithm::PrivateUse(-65537))
.add_critical_label(RegisteredLabelWithPrivate::PrivateUse(-65537))
.key_id(vec![1, 2, 3])
.build(),
Header {
alg: Some(Algorithm::PrivateUse(-65537)),
crit: vec![RegisteredLabelWithPrivate::PrivateUse(-65537)],
key_id: vec![1, 2, 3],
..Default::default()
},
),
];
for (got, want) in tests {
assert_eq!(got, want);
}
}
#[test]
#[should_panic]
fn test_header_builder_core_param_panic() {
let _hdr = HeaderBuilder::new().value(1, Value::Null).build();
}