Remove KeyType from CBOR (#306)

* removes KeyType from CBOR

* type_label usage in writer
This commit is contained in:
kaczmarczyck
2021-04-14 10:19:10 +02:00
committed by GitHub
parent e9c66a2764
commit 9a1c060234
7 changed files with 256 additions and 302 deletions

View File

@@ -24,5 +24,5 @@ pub mod values;
pub mod writer; pub mod writer;
pub use self::reader::read; pub use self::reader::read;
pub use self::values::{KeyType, SimpleValue, Value}; pub use self::values::{SimpleValue, Value};
pub use self::writer::write; pub use self::writer::write;

View File

@@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::values::{KeyType, Value}; use crate::values::Value;
use alloc::vec; use alloc::vec;
use core::cmp::Ordering; use core::cmp::Ordering;
use core::iter::Peekable; use core::iter::Peekable;
/// This macro generates code to extract multiple values from a `Vec<(KeyType, Value)>` at once /// This macro generates code to extract multiple values from a `Vec<(Value, Value)>` at once
/// in an optimized manner, consuming the input vector. /// in an optimized manner, consuming the input vector.
/// ///
/// It takes as input a `Vec` as well as a list of identifiers and keys, and generates code /// It takes as input a `Vec` as well as a list of identifiers and keys, and generates code
@@ -57,7 +57,7 @@ macro_rules! destructure_cbor_map {
#[cfg(test)] #[cfg(test)]
$crate::assert_sorted_keys!($( $key, )+); $crate::assert_sorted_keys!($( $key, )+);
use $crate::values::{IntoCborKey, Value}; use $crate::values::{IntoCborValue, Value};
use $crate::macros::destructure_cbor_map_peek_value; use $crate::macros::destructure_cbor_map_peek_value;
// This algorithm first converts the map into a peekable iterator - whose items are sorted // This algorithm first converts the map into a peekable iterator - whose items are sorted
@@ -70,7 +70,7 @@ macro_rules! destructure_cbor_map {
// to come in the same order (i.e. sorted). // to come in the same order (i.e. sorted).
let mut it = $map.into_iter().peekable(); let mut it = $map.into_iter().peekable();
$( $(
let $variable: Option<Value> = destructure_cbor_map_peek_value(&mut it, $key.into_cbor_key()); let $variable: Option<Value> = destructure_cbor_map_peek_value(&mut it, $key.into_cbor_value());
)+ )+
}; };
} }
@@ -87,14 +87,14 @@ macro_rules! destructure_cbor_map {
/// would be inlined for every use case. As of June 2020, this saves ~40KB of binary size for the /// would be inlined for every use case. As of June 2020, this saves ~40KB of binary size for the
/// CTAP2 application of OpenSK. /// CTAP2 application of OpenSK.
pub fn destructure_cbor_map_peek_value( pub fn destructure_cbor_map_peek_value(
it: &mut Peekable<vec::IntoIter<(KeyType, Value)>>, it: &mut Peekable<vec::IntoIter<(Value, Value)>>,
needle: KeyType, needle: Value,
) -> Option<Value> { ) -> Option<Value> {
loop { loop {
match it.peek() { match it.peek() {
None => return None, None => return None,
Some(item) => { Some(item) => {
let key: &KeyType = &item.0; let key: &Value = &item.0;
match key.cmp(&needle) { match key.cmp(&needle) {
Ordering::Less => { Ordering::Less => {
it.next(); it.next();
@@ -118,9 +118,9 @@ macro_rules! assert_sorted_keys {
( $key1:expr, $key2:expr, $( $keys:expr, )* ) => { ( $key1:expr, $key2:expr, $( $keys:expr, )* ) => {
{ {
use $crate::values::{IntoCborKey, KeyType}; use $crate::values::{IntoCborValue, Value};
let k1: KeyType = $key1.into_cbor_key(); let k1: Value = $key1.into_cbor_value();
let k2: KeyType = $key2.into_cbor_key(); let k2: Value = $key2.into_cbor_value();
assert!( assert!(
k1 < k2, k1 < k2,
"{:?} < {:?} failed. The destructure_cbor_map! macro requires keys in sorted order.", "{:?} < {:?} failed. The destructure_cbor_map! macro requires keys in sorted order.",
@@ -160,10 +160,10 @@ macro_rules! cbor_map {
{ {
// The import is unused if the list is empty. // The import is unused if the list is empty.
#[allow(unused_imports)] #[allow(unused_imports)]
use $crate::values::{IntoCborKey, IntoCborValue}; use $crate::values::IntoCborValue;
let mut _map = ::alloc::vec::Vec::new(); let mut _map = ::alloc::vec::Vec::new();
$( $(
_map.push(($key.into_cbor_key(), $value.into_cbor_value())); _map.push(($key.into_cbor_value(), $value.into_cbor_value()));
)* )*
$crate::values::Value::Map(_map) $crate::values::Value::Map(_map)
} }
@@ -201,13 +201,13 @@ macro_rules! cbor_map_options {
{ {
// The import is unused if the list is empty. // The import is unused if the list is empty.
#[allow(unused_imports)] #[allow(unused_imports)]
use $crate::values::{IntoCborKey, IntoCborValueOption}; use $crate::values::{IntoCborValue, IntoCborValueOption};
let mut _map = ::alloc::vec::Vec::<(_, $crate::values::Value)>::new(); let mut _map = ::alloc::vec::Vec::<(_, $crate::values::Value)>::new();
$( $(
{ {
let opt: Option<$crate::values::Value> = $value.into_cbor_value_option(); let opt: Option<$crate::values::Value> = $value.into_cbor_value_option();
if let Some(val) = opt { if let Some(val) = opt {
_map.push(($key.into_cbor_key(), val)); _map.push(($key.into_cbor_value(), val));
} }
} }
)* )*
@@ -216,7 +216,7 @@ macro_rules! cbor_map_options {
}; };
} }
/// Creates a CBOR Value of type Map from a Vec<(KeyType, Value)>. /// Creates a CBOR Value of type Map from a Vec<(Value, Value)>.
#[macro_export] #[macro_export]
macro_rules! cbor_map_collection { macro_rules! cbor_map_collection {
( $tree:expr ) => {{ ( $tree:expr ) => {{
@@ -261,6 +261,7 @@ macro_rules! cbor_array_vec {
}}; }};
} }
/// Creates a CBOR Value of type Simple with value true.
#[macro_export] #[macro_export]
macro_rules! cbor_true { macro_rules! cbor_true {
( ) => { ( ) => {
@@ -268,6 +269,7 @@ macro_rules! cbor_true {
}; };
} }
/// Creates a CBOR Value of type Simple with value false.
#[macro_export] #[macro_export]
macro_rules! cbor_false { macro_rules! cbor_false {
( ) => { ( ) => {
@@ -275,6 +277,7 @@ macro_rules! cbor_false {
}; };
} }
/// Creates a CBOR Value of type Simple with value null.
#[macro_export] #[macro_export]
macro_rules! cbor_null { macro_rules! cbor_null {
( ) => { ( ) => {
@@ -282,6 +285,7 @@ macro_rules! cbor_null {
}; };
} }
/// Creates a CBOR Value of type Simple with the undefined value.
#[macro_export] #[macro_export]
macro_rules! cbor_undefined { macro_rules! cbor_undefined {
( ) => { ( ) => {
@@ -289,6 +293,7 @@ macro_rules! cbor_undefined {
}; };
} }
/// Creates a CBOR Value of type Simple with the given bool value.
#[macro_export] #[macro_export]
macro_rules! cbor_bool { macro_rules! cbor_bool {
( $x:expr ) => { ( $x:expr ) => {
@@ -296,37 +301,47 @@ macro_rules! cbor_bool {
}; };
} }
// For key types, we construct a KeyType and call .into(), which will automatically convert it to a /// Creates a CBOR Value of type Unsigned with the given numeric value.
// KeyType or a Value depending on the context.
#[macro_export] #[macro_export]
macro_rules! cbor_unsigned { macro_rules! cbor_unsigned {
( $x:expr ) => { ( $x:expr ) => {
$crate::cbor_key_unsigned!($x).into() $crate::values::Value::Unsigned($x)
}; };
} }
/// Creates a CBOR Value of type Unsigned or Negative with the given numeric value.
#[macro_export] #[macro_export]
macro_rules! cbor_int { macro_rules! cbor_int {
( $x:expr ) => { ( $x:expr ) => {
$crate::cbor_key_int!($x).into() $crate::values::Value::integer($x)
}; };
} }
/// Creates a CBOR Value of type Text String with the given string.
#[macro_export] #[macro_export]
macro_rules! cbor_text { macro_rules! cbor_text {
( $x:expr ) => { ( $x:expr ) => {
$crate::cbor_key_text!($x).into() $crate::values::Value::TextString($x.into())
}; };
} }
/// Creates a CBOR Value of type Byte String with the given slice or vector.
#[macro_export] #[macro_export]
macro_rules! cbor_bytes { macro_rules! cbor_bytes {
( $x:expr ) => { ( $x:expr ) => {
$crate::cbor_key_bytes!($x).into() $crate::values::Value::ByteString($x)
}; };
} }
// Macro to use with a literal, e.g. cbor_bytes_lit!(b"foo") /// Creates a CBOR Value of type Byte String with the given byte string literal.
///
/// Example usage:
///
/// ```rust
/// # extern crate alloc;
/// # use cbor::cbor_bytes_lit;
/// let byte_array = cbor_bytes_lit!(b"foo");
/// ```
#[macro_export] #[macro_export]
macro_rules! cbor_bytes_lit { macro_rules! cbor_bytes_lit {
( $x:expr ) => { ( $x:expr ) => {
@@ -334,38 +349,9 @@ macro_rules! cbor_bytes_lit {
}; };
} }
// Some explicit macros are also available for contexts where the type is not explicit.
#[macro_export]
macro_rules! cbor_key_unsigned {
( $x:expr ) => {
$crate::values::KeyType::Unsigned($x)
};
}
#[macro_export]
macro_rules! cbor_key_int {
( $x:expr ) => {
$crate::values::KeyType::integer($x)
};
}
#[macro_export]
macro_rules! cbor_key_text {
( $x:expr ) => {
$crate::values::KeyType::TextString($x.into())
};
}
#[macro_export]
macro_rules! cbor_key_bytes {
( $x:expr ) => {
$crate::values::KeyType::ByteString($x)
};
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::super::values::{KeyType, SimpleValue, Value}; use super::super::values::{SimpleValue, Value};
#[test] #[test]
fn test_cbor_simple_values() { fn test_cbor_simple_values() {
@@ -383,23 +369,20 @@ mod test {
#[test] #[test]
fn test_cbor_int_unsigned() { fn test_cbor_int_unsigned() {
assert_eq!(cbor_key_int!(0), KeyType::Unsigned(0)); assert_eq!(cbor_int!(0), Value::Unsigned(0));
assert_eq!(cbor_key_int!(1), KeyType::Unsigned(1)); assert_eq!(cbor_int!(1), Value::Unsigned(1));
assert_eq!(cbor_key_int!(123456), KeyType::Unsigned(123456)); assert_eq!(cbor_int!(123456), Value::Unsigned(123456));
assert_eq!( assert_eq!(
cbor_key_int!(std::i64::MAX), cbor_int!(std::i64::MAX),
KeyType::Unsigned(std::i64::MAX as u64) Value::Unsigned(std::i64::MAX as u64)
); );
} }
#[test] #[test]
fn test_cbor_int_negative() { fn test_cbor_int_negative() {
assert_eq!(cbor_key_int!(-1), KeyType::Negative(-1)); assert_eq!(cbor_int!(-1), Value::Negative(-1));
assert_eq!(cbor_key_int!(-123456), KeyType::Negative(-123456)); assert_eq!(cbor_int!(-123456), Value::Negative(-123456));
assert_eq!( assert_eq!(cbor_int!(std::i64::MIN), Value::Negative(std::i64::MIN));
cbor_key_int!(std::i64::MIN),
KeyType::Negative(std::i64::MIN)
);
} }
#[test] #[test]
@@ -417,16 +400,16 @@ mod test {
std::u64::MAX, std::u64::MAX,
]; ];
let b = Value::Array(vec![ let b = Value::Array(vec![
Value::KeyValue(KeyType::Negative(std::i64::MIN)), Value::Negative(std::i64::MIN),
Value::KeyValue(KeyType::Negative(std::i32::MIN as i64)), Value::Negative(std::i32::MIN as i64),
Value::KeyValue(KeyType::Negative(-123456)), Value::Negative(-123456),
Value::KeyValue(KeyType::Negative(-1)), Value::Negative(-1),
Value::KeyValue(KeyType::Unsigned(0)), Value::Unsigned(0),
Value::KeyValue(KeyType::Unsigned(1)), Value::Unsigned(1),
Value::KeyValue(KeyType::Unsigned(123456)), Value::Unsigned(123456),
Value::KeyValue(KeyType::Unsigned(std::i32::MAX as u64)), Value::Unsigned(std::i32::MAX as u64),
Value::KeyValue(KeyType::Unsigned(std::i64::MAX as u64)), Value::Unsigned(std::i64::MAX as u64),
Value::KeyValue(KeyType::Unsigned(std::u64::MAX)), Value::Unsigned(std::u64::MAX),
]); ]);
assert_eq!(a, b); assert_eq!(a, b);
} }
@@ -446,20 +429,17 @@ mod test {
cbor_map! {2 => 3}, cbor_map! {2 => 3},
]; ];
let b = Value::Array(vec![ let b = Value::Array(vec![
Value::KeyValue(KeyType::Negative(-123)), Value::Negative(-123),
Value::KeyValue(KeyType::Unsigned(456)), Value::Unsigned(456),
Value::Simple(SimpleValue::TrueValue), Value::Simple(SimpleValue::TrueValue),
Value::Simple(SimpleValue::NullValue), Value::Simple(SimpleValue::NullValue),
Value::KeyValue(KeyType::TextString(String::from("foo"))), Value::TextString(String::from("foo")),
Value::KeyValue(KeyType::ByteString(b"bar".to_vec())), Value::ByteString(b"bar".to_vec()),
Value::Array(Vec::new()), Value::Array(Vec::new()),
Value::Array(vec![ Value::Array(vec![Value::Unsigned(0), Value::Unsigned(1)]),
Value::KeyValue(KeyType::Unsigned(0)),
Value::KeyValue(KeyType::Unsigned(1)),
]),
Value::Map(Vec::new()), Value::Map(Vec::new()),
Value::Map( Value::Map(
[(KeyType::Unsigned(2), Value::KeyValue(KeyType::Unsigned(3)))] [(Value::Unsigned(2), Value::Unsigned(3))]
.iter() .iter()
.cloned() .cloned()
.collect(), .collect(),
@@ -479,10 +459,10 @@ mod test {
fn test_cbor_array_vec_int() { fn test_cbor_array_vec_int() {
let a = cbor_array_vec!(vec![1, 2, 3, 4]); let a = cbor_array_vec!(vec![1, 2, 3, 4]);
let b = Value::Array(vec![ let b = Value::Array(vec![
Value::KeyValue(KeyType::Unsigned(1)), Value::Unsigned(1),
Value::KeyValue(KeyType::Unsigned(2)), Value::Unsigned(2),
Value::KeyValue(KeyType::Unsigned(3)), Value::Unsigned(3),
Value::KeyValue(KeyType::Unsigned(4)), Value::Unsigned(4),
]); ]);
assert_eq!(a, b); assert_eq!(a, b);
} }
@@ -491,9 +471,9 @@ mod test {
fn test_cbor_array_vec_text() { fn test_cbor_array_vec_text() {
let a = cbor_array_vec!(vec!["a", "b", "c"]); let a = cbor_array_vec!(vec!["a", "b", "c"]);
let b = Value::Array(vec![ let b = Value::Array(vec![
Value::KeyValue(KeyType::TextString(String::from("a"))), Value::TextString(String::from("a")),
Value::KeyValue(KeyType::TextString(String::from("b"))), Value::TextString(String::from("b")),
Value::KeyValue(KeyType::TextString(String::from("c"))), Value::TextString(String::from("c")),
]); ]);
assert_eq!(a, b); assert_eq!(a, b);
} }
@@ -502,9 +482,9 @@ mod test {
fn test_cbor_array_vec_bytes() { fn test_cbor_array_vec_bytes() {
let a = cbor_array_vec!(vec![b"a", b"b", b"c"]); let a = cbor_array_vec!(vec![b"a", b"b", b"c"]);
let b = Value::Array(vec![ let b = Value::Array(vec![
Value::KeyValue(KeyType::ByteString(b"a".to_vec())), Value::ByteString(b"a".to_vec()),
Value::KeyValue(KeyType::ByteString(b"b".to_vec())), Value::ByteString(b"b".to_vec()),
Value::KeyValue(KeyType::ByteString(b"c".to_vec())), Value::ByteString(b"c".to_vec()),
]); ]);
assert_eq!(a, b); assert_eq!(a, b);
} }
@@ -525,40 +505,28 @@ mod test {
}; };
let b = Value::Map( let b = Value::Map(
[ [
(Value::Negative(-1), Value::Negative(-23)),
(Value::Unsigned(4), Value::Unsigned(56)),
( (
KeyType::Negative(-1), Value::TextString(String::from("foo")),
Value::KeyValue(KeyType::Negative(-23)),
),
(KeyType::Unsigned(4), Value::KeyValue(KeyType::Unsigned(56))),
(
KeyType::TextString(String::from("foo")),
Value::Simple(SimpleValue::TrueValue), Value::Simple(SimpleValue::TrueValue),
), ),
( (
KeyType::ByteString(b"bar".to_vec()), Value::ByteString(b"bar".to_vec()),
Value::Simple(SimpleValue::NullValue), Value::Simple(SimpleValue::NullValue),
), ),
(Value::Unsigned(5), Value::TextString(String::from("foo"))),
(Value::Unsigned(6), Value::ByteString(b"bar".to_vec())),
(Value::Unsigned(7), Value::Array(Vec::new())),
( (
KeyType::Unsigned(5), Value::Unsigned(8),
Value::KeyValue(KeyType::TextString(String::from("foo"))), Value::Array(vec![Value::Unsigned(0), Value::Unsigned(1)]),
), ),
(Value::Unsigned(9), Value::Map(Vec::new())),
( (
KeyType::Unsigned(6), Value::Unsigned(10),
Value::KeyValue(KeyType::ByteString(b"bar".to_vec())),
),
(KeyType::Unsigned(7), Value::Array(Vec::new())),
(
KeyType::Unsigned(8),
Value::Array(vec![
Value::KeyValue(KeyType::Unsigned(0)),
Value::KeyValue(KeyType::Unsigned(1)),
]),
),
(KeyType::Unsigned(9), Value::Map(Vec::new())),
(
KeyType::Unsigned(10),
Value::Map( Value::Map(
[(KeyType::Unsigned(2), Value::KeyValue(KeyType::Unsigned(3)))] [(Value::Unsigned(2), Value::Unsigned(3))]
.iter() .iter()
.cloned() .cloned()
.collect(), .collect(),
@@ -596,40 +564,28 @@ mod test {
}; };
let b = Value::Map( let b = Value::Map(
[ [
(Value::Negative(-1), Value::Negative(-23)),
(Value::Unsigned(4), Value::Unsigned(56)),
( (
KeyType::Negative(-1), Value::TextString(String::from("foo")),
Value::KeyValue(KeyType::Negative(-23)),
),
(KeyType::Unsigned(4), Value::KeyValue(KeyType::Unsigned(56))),
(
KeyType::TextString(String::from("foo")),
Value::Simple(SimpleValue::TrueValue), Value::Simple(SimpleValue::TrueValue),
), ),
( (
KeyType::ByteString(b"bar".to_vec()), Value::ByteString(b"bar".to_vec()),
Value::Simple(SimpleValue::NullValue), Value::Simple(SimpleValue::NullValue),
), ),
(Value::Unsigned(5), Value::TextString(String::from("foo"))),
(Value::Unsigned(6), Value::ByteString(b"bar".to_vec())),
(Value::Unsigned(7), Value::Array(Vec::new())),
( (
KeyType::Unsigned(5), Value::Unsigned(8),
Value::KeyValue(KeyType::TextString(String::from("foo"))), Value::Array(vec![Value::Unsigned(0), Value::Unsigned(1)]),
), ),
(Value::Unsigned(9), Value::Map(Vec::new())),
( (
KeyType::Unsigned(6), Value::Unsigned(10),
Value::KeyValue(KeyType::ByteString(b"bar".to_vec())),
),
(KeyType::Unsigned(7), Value::Array(Vec::new())),
(
KeyType::Unsigned(8),
Value::Array(vec![
Value::KeyValue(KeyType::Unsigned(0)),
Value::KeyValue(KeyType::Unsigned(1)),
]),
),
(KeyType::Unsigned(9), Value::Map(Vec::new())),
(
KeyType::Unsigned(10),
Value::Map( Value::Map(
[(KeyType::Unsigned(2), Value::KeyValue(KeyType::Unsigned(3)))] [(Value::Unsigned(2), Value::Unsigned(3))]
.iter() .iter()
.cloned() .cloned()
.collect(), .collect(),
@@ -652,18 +608,12 @@ mod test {
#[test] #[test]
fn test_cbor_map_collection_foo() { fn test_cbor_map_collection_foo() {
let a = cbor_map_collection!(vec![( let a = cbor_map_collection!(vec![(Value::Unsigned(2), Value::Unsigned(3))]);
KeyType::Unsigned(2), let b = Value::Map(vec![(Value::Unsigned(2), Value::Unsigned(3))]);
Value::KeyValue(KeyType::Unsigned(3))
)]);
let b = Value::Map(vec![(
KeyType::Unsigned(2),
Value::KeyValue(KeyType::Unsigned(3)),
)]);
assert_eq!(a, b); assert_eq!(a, b);
} }
fn extract_map(cbor_value: Value) -> Vec<(KeyType, Value)> { fn extract_map(cbor_value: Value) -> Vec<(Value, Value)> {
match cbor_value { match cbor_value {
Value::Map(map) => map, Value::Map(map) => map,
_ => panic!("Expected CBOR map."), _ => panic!("Expected CBOR map."),

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use super::values::{Constants, KeyType, SimpleValue, Value}; use super::values::{Constants, SimpleValue, Value};
use crate::{cbor_array_vec, cbor_bytes_lit, cbor_map_collection, cbor_text, cbor_unsigned}; use crate::{cbor_array_vec, cbor_bytes_lit, cbor_map_collection, cbor_text, cbor_unsigned};
use alloc::str; use alloc::str;
use alloc::vec::Vec; use alloc::vec::Vec;
@@ -22,7 +22,6 @@ pub enum DecoderError {
UnsupportedMajorType, UnsupportedMajorType,
UnknownAdditionalInfo, UnknownAdditionalInfo,
IncompleteCborData, IncompleteCborData,
IncorrectMapKeyType,
TooMuchNesting, TooMuchNesting,
InvalidUtf8, InvalidUtf8,
ExtranousData, ExtranousData,
@@ -134,7 +133,7 @@ impl<'a> Reader<'a> {
if signed_size < 0 { if signed_size < 0 {
Err(DecoderError::OutOfRangeIntegerValue) Err(DecoderError::OutOfRangeIntegerValue)
} else { } else {
Ok(Value::KeyValue(KeyType::Negative(-(size_value as i64) - 1))) Ok(Value::Negative(-(size_value as i64) - 1))
} }
} }
@@ -176,8 +175,7 @@ impl<'a> Reader<'a> {
let mut value_map = Vec::new(); let mut value_map = Vec::new();
let mut last_key_option = None; let mut last_key_option = None;
for _ in 0..size_value { for _ in 0..size_value {
let key_value = self.decode_complete_data_item(remaining_depth - 1)?; let key = self.decode_complete_data_item(remaining_depth - 1)?;
if let Value::KeyValue(key) = key_value {
if let Some(last_key) = last_key_option { if let Some(last_key) = last_key_option {
if last_key >= key { if last_key >= key {
return Err(DecoderError::OutOfOrderKey); return Err(DecoderError::OutOfOrderKey);
@@ -185,9 +183,6 @@ impl<'a> Reader<'a> {
} }
last_key_option = Some(key.clone()); last_key_option = Some(key.clone());
value_map.push((key, self.decode_complete_data_item(remaining_depth - 1)?)); value_map.push((key, self.decode_complete_data_item(remaining_depth - 1)?));
} else {
return Err(DecoderError::IncorrectMapKeyType);
}
} }
Ok(cbor_map_collection!(value_map)) Ok(cbor_map_collection!(value_map))
} }
@@ -614,19 +609,6 @@ mod test {
} }
} }
#[test]
fn test_read_unsupported_map_key_format_error() {
// While CBOR can handle all types as map keys, we only support a subset.
let bad_map_cbor = vec![
0xa2, // map of 2 pairs
0x82, 0x01, 0x02, // invalid key : [1, 2]
0x02, // value : 2
0x61, 0x64, // key : "d"
0x03, // value : 3
];
assert_eq!(read(&bad_map_cbor), Err(DecoderError::IncorrectMapKeyType));
}
#[test] #[test]
fn test_read_unknown_additional_info_error() { fn test_read_unknown_additional_info_error() {
let cases = vec![ let cases = vec![

View File

@@ -12,31 +12,25 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use super::writer::write;
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use alloc::vec::Vec; use alloc::vec::Vec;
use core::cmp::Ordering; use core::cmp::Ordering;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug)]
pub enum Value { pub enum Value {
KeyValue(KeyType),
Array(Vec<Value>),
Map(Vec<(KeyType, Value)>),
// TAG is omitted
Simple(SimpleValue),
}
// The specification recommends to limit the available keys.
// Currently supported are both integer and string types.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum KeyType {
Unsigned(u64), Unsigned(u64),
// We only use 63 bits of information here. // We only use 63 bits of information here.
Negative(i64), Negative(i64),
ByteString(Vec<u8>), ByteString(Vec<u8>),
TextString(String), TextString(String),
Array(Vec<Value>),
Map(Vec<(Value, Value)>),
// TAG is omitted
Simple(SimpleValue),
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum SimpleValue { pub enum SimpleValue {
FalseValue = 20, FalseValue = 20,
TrueValue = 21, TrueValue = 21,
@@ -57,6 +51,15 @@ impl Constants {
} }
impl Value { impl Value {
// For simplicity, this only takes i64. Construct directly for the last bit.
pub fn integer(int: i64) -> Value {
if int >= 0 {
Value::Unsigned(int as u64)
} else {
Value::Negative(int)
}
}
pub fn bool_value(b: bool) -> Value { pub fn bool_value(b: bool) -> Value {
if b { if b {
Value::Simple(SimpleValue::TrueValue) Value::Simple(SimpleValue::TrueValue)
@@ -66,8 +69,13 @@ impl Value {
} }
pub fn type_label(&self) -> u8 { pub fn type_label(&self) -> u8 {
// TODO use enum discriminant instead when stable
// https://github.com/rust-lang/rust/issues/60553
match self { match self {
Value::KeyValue(key) => key.type_label(), Value::Unsigned(_) => 0,
Value::Negative(_) => 1,
Value::ByteString(_) => 2,
Value::TextString(_) => 3,
Value::Array(_) => 4, Value::Array(_) => 4,
Value::Map(_) => 5, Value::Map(_) => 5,
Value::Simple(_) => 7, Value::Simple(_) => 7,
@@ -75,29 +83,11 @@ impl Value {
} }
} }
impl KeyType { impl Ord for Value {
// For simplicity, this only takes i64. Construct directly for the last bit. fn cmp(&self, other: &Value) -> Ordering {
pub fn integer(int: i64) -> KeyType { use super::values::Value::{
if int >= 0 { Array, ByteString, Map, Negative, Simple, TextString, Unsigned,
KeyType::Unsigned(int as u64) };
} else {
KeyType::Negative(int)
}
}
pub fn type_label(&self) -> u8 {
match self {
KeyType::Unsigned(_) => 0,
KeyType::Negative(_) => 1,
KeyType::ByteString(_) => 2,
KeyType::TextString(_) => 3,
}
}
}
impl Ord for KeyType {
fn cmp(&self, other: &KeyType) -> Ordering {
use super::values::KeyType::{ByteString, Negative, TextString, Unsigned};
let self_type_value = self.type_label(); let self_type_value = self.type_label();
let other_type_value = other.type_label(); let other_type_value = other.type_label();
if self_type_value != other_type_value { if self_type_value != other_type_value {
@@ -108,17 +98,35 @@ impl Ord for KeyType {
(Negative(n1), Negative(n2)) => n1.cmp(n2).reverse(), (Negative(n1), Negative(n2)) => n1.cmp(n2).reverse(),
(ByteString(b1), ByteString(b2)) => b1.len().cmp(&b2.len()).then(b1.cmp(b2)), (ByteString(b1), ByteString(b2)) => b1.len().cmp(&b2.len()).then(b1.cmp(b2)),
(TextString(t1), TextString(t2)) => t1.len().cmp(&t2.len()).then(t1.cmp(t2)), (TextString(t1), TextString(t2)) => t1.len().cmp(&t2.len()).then(t1.cmp(t2)),
_ => unreachable!(), (Array(a1), Array(a2)) if a1.len() != a2.len() => a1.len().cmp(&a2.len()),
(Map(m1), Map(m2)) if m1.len() != m2.len() => m1.len().cmp(&m2.len()),
(Simple(s1), Simple(s2)) => s1.cmp(s2),
(v1, v2) => {
// This case could handle all of the above as well. Checking individually is faster.
let mut encoding1 = Vec::new();
write(v1.clone(), &mut encoding1);
let mut encoding2 = Vec::new();
write(v2.clone(), &mut encoding2);
encoding1.cmp(&encoding2)
}
} }
} }
} }
impl PartialOrd for KeyType { impl PartialOrd for Value {
fn partial_cmp(&self, other: &KeyType) -> Option<Ordering> { fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
} }
impl Eq for Value {}
impl PartialEq for Value {
fn eq(&self, other: &Value) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl SimpleValue { impl SimpleValue {
pub fn from_integer(int: u64) -> Option<SimpleValue> { pub fn from_integer(int: u64) -> Option<SimpleValue> {
match int { match int {
@@ -131,59 +139,50 @@ impl SimpleValue {
} }
} }
impl From<u64> for KeyType { impl From<u64> for Value {
fn from(unsigned: u64) -> Self { fn from(unsigned: u64) -> Self {
KeyType::Unsigned(unsigned) Value::Unsigned(unsigned)
} }
} }
impl From<i64> for KeyType { impl From<i64> for Value {
fn from(i: i64) -> Self { fn from(i: i64) -> Self {
KeyType::integer(i) Value::integer(i)
} }
} }
impl From<i32> for KeyType { impl From<i32> for Value {
fn from(i: i32) -> Self { fn from(i: i32) -> Self {
KeyType::integer(i as i64) Value::integer(i as i64)
} }
} }
impl From<Vec<u8>> for KeyType { impl From<Vec<u8>> for Value {
fn from(bytes: Vec<u8>) -> Self { fn from(bytes: Vec<u8>) -> Self {
KeyType::ByteString(bytes) Value::ByteString(bytes)
} }
} }
impl From<&[u8]> for KeyType { impl From<&[u8]> for Value {
fn from(bytes: &[u8]) -> Self { fn from(bytes: &[u8]) -> Self {
KeyType::ByteString(bytes.to_vec()) Value::ByteString(bytes.to_vec())
} }
} }
impl From<String> for KeyType { impl From<String> for Value {
fn from(text: String) -> Self { fn from(text: String) -> Self {
KeyType::TextString(text) Value::TextString(text)
} }
} }
impl From<&str> for KeyType { impl From<&str> for Value {
fn from(text: &str) -> Self { fn from(text: &str) -> Self {
KeyType::TextString(text.to_string()) Value::TextString(text.to_string())
} }
} }
impl<T> From<T> for Value impl From<Vec<(Value, Value)>> for Value {
where fn from(map: Vec<(Value, Value)>) -> Self {
KeyType: From<T>,
{
fn from(t: T) -> Self {
Value::KeyValue(KeyType::from(t))
}
}
impl From<Vec<(KeyType, Value)>> for Value {
fn from(map: Vec<(KeyType, Value)>) -> Self {
Value::Map(map) Value::Map(map)
} }
} }
@@ -194,19 +193,6 @@ impl From<bool> for Value {
} }
} }
pub trait IntoCborKey {
fn into_cbor_key(self) -> KeyType;
}
impl<T> IntoCborKey for T
where
KeyType: From<T>,
{
fn into_cbor_key(self) -> KeyType {
KeyType::from(self)
}
}
pub trait IntoCborValue { pub trait IntoCborValue {
fn into_cbor_value(self) -> Value; fn into_cbor_value(self) -> Value;
} }
@@ -244,32 +230,69 @@ where
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::{cbor_key_bytes, cbor_key_int, cbor_key_text}; use super::*;
use crate::{cbor_array, cbor_bool, cbor_bytes, cbor_int, cbor_map, cbor_text};
#[test] #[test]
fn test_key_type_ordering() { fn test_value_ordering() {
assert!(cbor_key_int!(0) < cbor_key_int!(23)); assert!(cbor_int!(0) < cbor_int!(23));
assert!(cbor_key_int!(23) < cbor_key_int!(24)); assert!(cbor_int!(23) < cbor_int!(24));
assert!(cbor_key_int!(24) < cbor_key_int!(1000)); assert!(cbor_int!(24) < cbor_int!(1000));
assert!(cbor_key_int!(1000) < cbor_key_int!(1000000)); assert!(cbor_int!(1000) < cbor_int!(1000000));
assert!(cbor_key_int!(1000000) < cbor_key_int!(std::i64::MAX)); assert!(cbor_int!(1000000) < cbor_int!(std::i64::MAX));
assert!(cbor_key_int!(std::i64::MAX) < cbor_key_int!(-1)); assert!(cbor_int!(std::i64::MAX) < cbor_int!(-1));
assert!(cbor_key_int!(-1) < cbor_key_int!(-23)); assert!(cbor_int!(-1) < cbor_int!(-23));
assert!(cbor_key_int!(-23) < cbor_key_int!(-24)); assert!(cbor_int!(-23) < cbor_int!(-24));
assert!(cbor_key_int!(-24) < cbor_key_int!(-1000)); assert!(cbor_int!(-24) < cbor_int!(-1000));
assert!(cbor_key_int!(-1000) < cbor_key_int!(-1000000)); assert!(cbor_int!(-1000) < cbor_int!(-1000000));
assert!(cbor_key_int!(-1000000) < cbor_key_int!(std::i64::MIN)); assert!(cbor_int!(-1000000) < cbor_int!(std::i64::MIN));
assert!(cbor_key_int!(std::i64::MIN) < cbor_key_bytes!(vec![])); assert!(cbor_int!(std::i64::MIN) < cbor_bytes!(vec![]));
assert!(cbor_key_bytes!(vec![]) < cbor_key_bytes!(vec![0x00])); assert!(cbor_bytes!(vec![]) < cbor_bytes!(vec![0x00]));
assert!(cbor_key_bytes!(vec![0x00]) < cbor_key_bytes!(vec![0x01])); assert!(cbor_bytes!(vec![0x00]) < cbor_bytes!(vec![0x01]));
assert!(cbor_key_bytes!(vec![0x01]) < cbor_key_bytes!(vec![0xFF])); assert!(cbor_bytes!(vec![0x01]) < cbor_bytes!(vec![0xFF]));
assert!(cbor_key_bytes!(vec![0xFF]) < cbor_key_bytes!(vec![0x00, 0x00])); assert!(cbor_bytes!(vec![0xFF]) < cbor_bytes!(vec![0x00, 0x00]));
assert!(cbor_key_bytes!(vec![0x00, 0x00]) < cbor_key_text!("")); assert!(cbor_bytes!(vec![0x00, 0x00]) < cbor_text!(""));
assert!(cbor_key_text!("") < cbor_key_text!("a")); assert!(cbor_text!("") < cbor_text!("a"));
assert!(cbor_key_text!("a") < cbor_key_text!("b")); assert!(cbor_text!("a") < cbor_text!("b"));
assert!(cbor_key_text!("b") < cbor_key_text!("aa")); assert!(cbor_text!("b") < cbor_text!("aa"));
assert!(cbor_key_int!(1) < cbor_key_bytes!(vec![0x00])); assert!(cbor_text!("aa") < cbor_array![]);
assert!(cbor_key_int!(1) < cbor_key_text!("s")); assert!(cbor_array![] < cbor_array![0]);
assert!(cbor_key_int!(-1) < cbor_key_text!("s")); assert!(cbor_array![0] < cbor_array![-1]);
assert!(cbor_array![1] < cbor_array![b""]);
assert!(cbor_array![b""] < cbor_array![""]);
assert!(cbor_array![""] < cbor_array![cbor_array![]]);
assert!(cbor_array![cbor_array![]] < cbor_array![cbor_map! {}]);
assert!(cbor_array![cbor_map! {}] < cbor_array![false]);
assert!(cbor_array![false] < cbor_array![0, 0]);
assert!(cbor_array![0, 0] < cbor_map! {});
assert!(cbor_map! {} < cbor_map! {0 => 0});
assert!(cbor_map! {0 => 0} < cbor_map! {0 => 1});
assert!(cbor_map! {0 => 1} < cbor_map! {1 => 0});
assert!(cbor_map! {1 => 0} < cbor_map! {-1 => 0});
assert!(cbor_map! {-1 => 0} < cbor_map! {b"" => 0});
assert!(cbor_map! {b"" => 0} < cbor_map! {"" => 0});
assert!(cbor_map! {"" => 0} < cbor_map! {cbor_array![] => 0});
assert!(cbor_map! {cbor_array![] => 0} < cbor_map! {cbor_map!{} => 0});
assert!(cbor_map! {cbor_map!{} => 0} < cbor_map! {false => 0});
assert!(cbor_map! {false => 0} < cbor_map! {0 => 0, 0 => 0});
assert!(cbor_map! {0 => 0, 0 => 0} < cbor_bool!(false));
assert!(cbor_bool!(false) < cbor_bool!(true));
assert!(cbor_bool!(true) < Value::Simple(SimpleValue::NullValue));
assert!(Value::Simple(SimpleValue::NullValue) < Value::Simple(SimpleValue::Undefined));
assert!(cbor_int!(1) < cbor_bytes!(vec![0x00]));
assert!(cbor_int!(1) < cbor_text!("s"));
assert!(cbor_int!(1) < cbor_array![]);
assert!(cbor_int!(1) < cbor_map! {});
assert!(cbor_int!(1) < cbor_bool!(false));
assert!(cbor_int!(-1) < cbor_text!("s"));
assert!(cbor_int!(-1) < cbor_array![]);
assert!(cbor_int!(-1) < cbor_map! {});
assert!(cbor_int!(-1) < cbor_bool!(false));
assert!(cbor_bytes!(vec![0x00]) < cbor_array![]);
assert!(cbor_bytes!(vec![0x00]) < cbor_map! {});
assert!(cbor_bytes!(vec![0x00]) < cbor_bool!(false));
assert!(cbor_text!("s") < cbor_map! {});
assert!(cbor_text!("s") < cbor_bool!(false));
assert!(cbor_array![] < cbor_bool!(false));
} }
} }

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use super::values::{Constants, KeyType, Value}; use super::values::{Constants, Value};
use alloc::vec::Vec; use alloc::vec::Vec;
pub fn write(value: Value, encoded_cbor: &mut Vec<u8>) -> bool { pub fn write(value: Value, encoded_cbor: &mut Vec<u8>) -> bool {
@@ -35,21 +35,20 @@ impl<'a> Writer<'a> {
if remaining_depth < 0 { if remaining_depth < 0 {
return false; return false;
} }
let type_label = value.type_label();
match value { match value {
Value::KeyValue(KeyType::Unsigned(unsigned)) => self.start_item(0, unsigned), Value::Unsigned(unsigned) => self.start_item(type_label, unsigned),
Value::KeyValue(KeyType::Negative(negative)) => { Value::Negative(negative) => self.start_item(type_label, -(negative + 1) as u64),
self.start_item(1, -(negative + 1) as u64) Value::ByteString(byte_string) => {
} self.start_item(type_label, byte_string.len() as u64);
Value::KeyValue(KeyType::ByteString(byte_string)) => {
self.start_item(2, byte_string.len() as u64);
self.encoded_cbor.extend(byte_string); self.encoded_cbor.extend(byte_string);
} }
Value::KeyValue(KeyType::TextString(text_string)) => { Value::TextString(text_string) => {
self.start_item(3, text_string.len() as u64); self.start_item(type_label, text_string.len() as u64);
self.encoded_cbor.extend(text_string.into_bytes()); self.encoded_cbor.extend(text_string.into_bytes());
} }
Value::Array(array) => { Value::Array(array) => {
self.start_item(4, array.len() as u64); self.start_item(type_label, array.len() as u64);
for el in array { for el in array {
if !self.encode_cbor(el, remaining_depth - 1) { if !self.encode_cbor(el, remaining_depth - 1) {
return false; return false;
@@ -63,9 +62,9 @@ impl<'a> Writer<'a> {
if map_len != map.len() { if map_len != map.len() {
return false; return false;
} }
self.start_item(5, map_len as u64); self.start_item(type_label, map_len as u64);
for (k, v) in map { for (k, v) in map {
if !self.encode_cbor(Value::KeyValue(k), remaining_depth - 1) { if !self.encode_cbor(k, remaining_depth - 1) {
return false; return false;
} }
if !self.encode_cbor(v, remaining_depth - 1) { if !self.encode_cbor(v, remaining_depth - 1) {
@@ -73,7 +72,7 @@ impl<'a> Writer<'a> {
} }
} }
} }
Value::Simple(simple_value) => self.start_item(7, simple_value as u64), Value::Simple(simple_value) => self.start_item(type_label, simple_value as u64),
} }
true true
} }

View File

@@ -586,8 +586,8 @@ enum PublicKeyCredentialSourceField {
// - CredRandom = 5, // - CredRandom = 5,
} }
impl From<PublicKeyCredentialSourceField> for cbor::KeyType { impl From<PublicKeyCredentialSourceField> for cbor::Value {
fn from(field: PublicKeyCredentialSourceField) -> cbor::KeyType { fn from(field: PublicKeyCredentialSourceField) -> cbor::Value {
(field as u64).into() (field as u64).into()
} }
} }
@@ -1076,35 +1076,35 @@ impl From<CredentialManagementSubCommandParameters> for cbor::Value {
pub(super) fn extract_unsigned(cbor_value: cbor::Value) -> Result<u64, Ctap2StatusCode> { pub(super) fn extract_unsigned(cbor_value: cbor::Value) -> Result<u64, Ctap2StatusCode> {
match cbor_value { match cbor_value {
cbor::Value::KeyValue(cbor::KeyType::Unsigned(unsigned)) => Ok(unsigned), cbor::Value::Unsigned(unsigned) => Ok(unsigned),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE), _ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
} }
} }
pub(super) fn extract_integer(cbor_value: cbor::Value) -> Result<i64, Ctap2StatusCode> { pub(super) fn extract_integer(cbor_value: cbor::Value) -> Result<i64, Ctap2StatusCode> {
match cbor_value { match cbor_value {
cbor::Value::KeyValue(cbor::KeyType::Unsigned(unsigned)) => { cbor::Value::Unsigned(unsigned) => {
if unsigned <= core::i64::MAX as u64 { if unsigned <= core::i64::MAX as u64 {
Ok(unsigned as i64) Ok(unsigned as i64)
} else { } else {
Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE) Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
} }
} }
cbor::Value::KeyValue(cbor::KeyType::Negative(signed)) => Ok(signed), cbor::Value::Negative(signed) => Ok(signed),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE), _ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
} }
} }
pub fn extract_byte_string(cbor_value: cbor::Value) -> Result<Vec<u8>, Ctap2StatusCode> { pub fn extract_byte_string(cbor_value: cbor::Value) -> Result<Vec<u8>, Ctap2StatusCode> {
match cbor_value { match cbor_value {
cbor::Value::KeyValue(cbor::KeyType::ByteString(byte_string)) => Ok(byte_string), cbor::Value::ByteString(byte_string) => Ok(byte_string),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE), _ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
} }
} }
pub(super) fn extract_text_string(cbor_value: cbor::Value) -> Result<String, Ctap2StatusCode> { pub(super) fn extract_text_string(cbor_value: cbor::Value) -> Result<String, Ctap2StatusCode> {
match cbor_value { match cbor_value {
cbor::Value::KeyValue(cbor::KeyType::TextString(text_string)) => Ok(text_string), cbor::Value::TextString(text_string) => Ok(text_string),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE), _ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
} }
} }
@@ -1118,7 +1118,7 @@ pub(super) fn extract_array(cbor_value: cbor::Value) -> Result<Vec<cbor::Value>,
pub(super) fn extract_map( pub(super) fn extract_map(
cbor_value: cbor::Value, cbor_value: cbor::Value,
) -> Result<Vec<(cbor::KeyType, cbor::Value)>, Ctap2StatusCode> { ) -> Result<Vec<(cbor::Value, cbor::Value)>, Ctap2StatusCode> {
match cbor_value { match cbor_value {
cbor::Value::Map(map) => Ok(map), cbor::Value::Map(map) => Ok(map),
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE), _ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
@@ -1681,7 +1681,7 @@ mod test {
#[test] #[test]
fn test_into_packed_attestation_statement() { fn test_into_packed_attestation_statement() {
let certificate: cbor::values::KeyType = cbor_bytes![vec![0x5C, 0x5C, 0x5C, 0x5C]]; let certificate = cbor_bytes![vec![0x5C, 0x5C, 0x5C, 0x5C]];
let cbor_packed_attestation_statement = cbor_map! { let cbor_packed_attestation_statement = cbor_map! {
"alg" => 1, "alg" => 1,
"sig" => vec![0x55, 0x55, 0x55, 0x55], "sig" => vec![0x55, 0x55, 0x55, 0x55],

View File

@@ -326,7 +326,7 @@ mod test {
#[test] #[test]
fn test_make_credential_into_cbor() { fn test_make_credential_into_cbor() {
let certificate: cbor::values::KeyType = cbor_bytes![vec![0x5C, 0x5C, 0x5C, 0x5C]]; let certificate = cbor_bytes![vec![0x5C, 0x5C, 0x5C, 0x5C]];
let att_stmt = PackedAttestationStatement { let att_stmt = PackedAttestationStatement {
alg: 1, alg: 1,
sig: vec![0x55, 0x55, 0x55, 0x55], sig: vec![0x55, 0x55, 0x55, 0x55],