Skip to content

Commit

Permalink
Match against Labels not Values
Browse files Browse the repository at this point in the history
Labels implement Eq and can be created as constants, making code more
readable.
  • Loading branch information
ciphergoth committed Jan 10, 2022
1 parent e30a755 commit 8e8084a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 68 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -18,7 +18,7 @@
- Use new `DuplicateMapKey` error when a CBOR map contains duplicate keys (and is thus invalid).
- Extend `DecodeFailed` error to include the underlying `ciborium::de::Error` value.
- Use new `ExtraneousData` error when data remains after reading a CBOR value.
- Rename `UnexpectedType` error to `UnexpectedItem` to reflect broader usage than type
- Rename `UnexpectedType` error to `UnexpectedItem` to reflect broader usage than type.
- Add a crate-specific `Result` type whose `E` field defaults to `CoseError`.

## 0.2.0 - 2021-12-09
Expand Down
64 changes: 25 additions & 39 deletions src/header/mod.rs
Expand Up @@ -86,27 +86,13 @@ impl Header {

impl crate::CborSerializable for Header {}

fn alg_value() -> Value {
Value::from(iana::HeaderParameter::Alg as u64)
}
fn crit_value() -> Value {
Value::from(iana::HeaderParameter::Crit as u64)
}
fn content_type_value() -> Value {
Value::from(iana::HeaderParameter::ContentType as u64)
}
fn kid_value() -> Value {
Value::from(iana::HeaderParameter::Kid as u64)
}
fn iv_value() -> Value {
Value::from(iana::HeaderParameter::Iv as u64)
}
fn partial_iv_value() -> Value {
Value::from(iana::HeaderParameter::PartialIv as u64)
}
fn counter_sig_value() -> Value {
Value::from(iana::HeaderParameter::CounterSignature as u64)
}
const ALG: Label = Label::Int(iana::HeaderParameter::Alg as i64);
const CRIT: Label = Label::Int(iana::HeaderParameter::Crit as i64);
const CONTENT_TYPE: Label = Label::Int(iana::HeaderParameter::ContentType as i64);
const KID: Label = Label::Int(iana::HeaderParameter::Kid as i64);
const IV: Label = Label::Int(iana::HeaderParameter::Iv as i64);
const PARTIAL_IV: Label = Label::Int(iana::HeaderParameter::PartialIv as i64);
const COUNTER_SIG: Label = Label::Int(iana::HeaderParameter::CounterSignature as i64);

impl AsCborValue for Header {
fn from_cbor_value(value: Value) -> Result<Self> {
Expand All @@ -120,15 +106,15 @@ impl AsCborValue for Header {
for (l, value) in m.into_iter() {
// The `ciborium` CBOR library does not police duplicate map keys.
// RFC 8152 section 14 requires that COSE does police duplicates, so do it here.
let label = Label::from_cbor_value(l.clone())?;
let label = Label::from_cbor_value(l)?;
if seen.contains(&label) {
return Err(CoseError::DuplicateMapKey);
}
seen.insert(label.clone());
match l {
x if x == alg_value() => headers.alg = Some(Algorithm::from_cbor_value(value)?),
match label {
ALG => headers.alg = Some(Algorithm::from_cbor_value(value)?),

x if x == crit_value() => match value {
CRIT => match value {
Value::Array(a) => {
if a.is_empty() {
return Err(CoseError::UnexpectedItem(
Expand All @@ -145,7 +131,7 @@ impl AsCborValue for Header {
v => return cbor_type_error(&v, "array value"),
},

x if x == content_type_value() => {
CONTENT_TYPE => {
headers.content_type = Some(ContentType::from_cbor_value(value)?);
if let Some(ContentType::Text(text)) = &headers.content_type {
if text.is_empty() {
Expand All @@ -168,7 +154,7 @@ impl AsCborValue for Header {
}
}

x if x == kid_value() => match value {
KID => match value {
Value::Bytes(v) => {
if v.is_empty() {
return Err(CoseError::UnexpectedItem("empty bstr", "non-empty bstr"));
Expand All @@ -178,7 +164,7 @@ impl AsCborValue for Header {
v => return cbor_type_error(&v, "bstr value"),
},

x if x == iv_value() => match value {
IV => match value {
Value::Bytes(v) => {
if v.is_empty() {
return Err(CoseError::UnexpectedItem("empty bstr", "non-empty bstr"));
Expand All @@ -188,7 +174,7 @@ impl AsCborValue for Header {
v => return cbor_type_error(&v, "bstr value"),
},

x if x == partial_iv_value() => match value {
PARTIAL_IV => match value {
Value::Bytes(v) => {
if v.is_empty() {
return Err(CoseError::UnexpectedItem("empty bstr", "non-empty bstr"));
Expand All @@ -197,7 +183,7 @@ impl AsCborValue for Header {
}
v => return cbor_type_error(&v, "bstr value"),
},
x if x == counter_sig_value() => match value {
COUNTER_SIG => match value {
Value::Array(sig_or_sigs) => {
if sig_or_sigs.is_empty() {
return Err(CoseError::UnexpectedItem(
Expand Down Expand Up @@ -229,7 +215,7 @@ impl AsCborValue for Header {
v => return cbor_type_error(&v, "array value"),
},

_l => headers.rest.push((label, value)),
label => headers.rest.push((label, value)),
}
// RFC 8152 section 3.1: "The 'Initialization Vector' and 'Partial Initialization
// Vector' parameters MUST NOT both be present in the same security layer."
Expand All @@ -246,40 +232,40 @@ impl AsCborValue for Header {
fn to_cbor_value(mut self) -> Result<Value> {
let mut map = Vec::<(Value, Value)>::new();
if let Some(alg) = self.alg {
map.push((alg_value(), alg.to_cbor_value()?));
map.push((ALG.to_cbor_value()?, alg.to_cbor_value()?));
}
if !self.crit.is_empty() {
let mut arr = Vec::new();
for c in self.crit {
arr.push(c.to_cbor_value()?);
}
map.push((crit_value(), Value::Array(arr)));
map.push((CRIT.to_cbor_value()?, Value::Array(arr)));
}
if let Some(content_type) = self.content_type {
map.push((content_type_value(), content_type.to_cbor_value()?));
map.push((CONTENT_TYPE.to_cbor_value()?, content_type.to_cbor_value()?));
}
if !self.key_id.is_empty() {
map.push((kid_value(), Value::Bytes(self.key_id)));
map.push((KID.to_cbor_value()?, Value::Bytes(self.key_id)));
}
if !self.iv.is_empty() {
map.push((iv_value(), Value::Bytes(self.iv)));
map.push((IV.to_cbor_value()?, Value::Bytes(self.iv)));
}
if !self.partial_iv.is_empty() {
map.push((partial_iv_value(), Value::Bytes(self.partial_iv)));
map.push((PARTIAL_IV.to_cbor_value()?, Value::Bytes(self.partial_iv)));
}
if !self.counter_signatures.is_empty() {
if self.counter_signatures.len() == 1 {
// A single counter signature is encoded differently.
map.push((
counter_sig_value(),
COUNTER_SIG.to_cbor_value()?,
self.counter_signatures.remove(0).to_cbor_value()?,
));
} else {
let mut arr = Vec::new();
for cs in self.counter_signatures {
arr.push(cs.to_cbor_value()?);
}
map.push((counter_sig_value(), Value::Array(arr)));
map.push((COUNTER_SIG.to_cbor_value()?, Value::Array(arr)));
}
}
let mut seen = BTreeSet::new();
Expand Down
46 changes: 18 additions & 28 deletions src/key/mod.rs
Expand Up @@ -99,21 +99,11 @@ pub struct CoseKey {

impl crate::CborSerializable for CoseKey {}

fn kty_value() -> Value {
Value::from(iana::KeyParameter::Kty.to_i64())
}
fn kid_value() -> Value {
Value::from(iana::KeyParameter::Kid.to_i64())
}
fn alg_value() -> Value {
Value::from(iana::KeyParameter::Alg.to_i64())
}
fn key_ops_value() -> Value {
Value::from(iana::KeyParameter::KeyOps.to_i64())
}
fn base_iv_value() -> Value {
Value::from(iana::KeyParameter::BaseIv.to_i64())
}
const KTY: Label = Label::Int(iana::KeyParameter::Kty as i64);
const KID: Label = Label::Int(iana::KeyParameter::Kid as i64);
const ALG: Label = Label::Int(iana::KeyParameter::Alg as i64);
const KEY_OPS: Label = Label::Int(iana::KeyParameter::KeyOps as i64);
const BASE_IV: Label = Label::Int(iana::KeyParameter::BaseIv as i64);

impl AsCborValue for CoseKey {
fn from_cbor_value(value: Value) -> Result<Self> {
Expand All @@ -127,15 +117,15 @@ impl AsCborValue for CoseKey {
for (l, value) in m.into_iter() {
// The `ciborium` CBOR library does not police duplicate map keys.
// RFC 8152 section 14 requires that COSE does police duplicates, so do it here.
let label = Label::from_cbor_value(l.clone())?;
let label = Label::from_cbor_value(l)?;
if seen.contains(&label) {
return Err(CoseError::DuplicateMapKey);
}
seen.insert(label.clone());
match l {
x if x == kty_value() => key.kty = KeyType::from_cbor_value(value)?,
match label {
KTY => key.kty = KeyType::from_cbor_value(value)?,

x if x == kid_value() => match value {
KID => match value {
Value::Bytes(v) => {
if v.is_empty() {
return Err(CoseError::UnexpectedItem("empty bstr", "non-empty bstr"));
Expand All @@ -145,9 +135,9 @@ impl AsCborValue for CoseKey {
v => return cbor_type_error(&v, "bstr value"),
},

x if x == alg_value() => key.alg = Some(Algorithm::from_cbor_value(value)?),
ALG => key.alg = Some(Algorithm::from_cbor_value(value)?),

x if x == key_ops_value() => match value {
KEY_OPS => match value {
Value::Array(key_ops) => {
for key_op in key_ops.into_iter() {
if !key.key_ops.insert(KeyOperation::from_cbor_value(key_op)?) {
Expand All @@ -167,7 +157,7 @@ impl AsCborValue for CoseKey {
v => return cbor_type_error(&v, "array value"),
},

x if x == base_iv_value() => match value {
BASE_IV => match value {
Value::Bytes(v) => {
if v.is_empty() {
return Err(CoseError::UnexpectedItem("empty bstr", "non-empty bstr"));
Expand All @@ -177,7 +167,7 @@ impl AsCborValue for CoseKey {
v => return cbor_type_error(&v, "bstr value"),
},

_l => key.params.push((label, value)),
label => key.params.push((label, value)),
}
}
// Check that key type has been set.
Expand All @@ -192,22 +182,22 @@ impl AsCborValue for CoseKey {
}

fn to_cbor_value(self) -> Result<Value> {
let mut map: Vec<(Value, Value)> = vec![(kty_value(), self.kty.to_cbor_value()?)];
let mut map: Vec<(Value, Value)> = vec![(KTY.to_cbor_value()?, self.kty.to_cbor_value()?)];
if !self.key_id.is_empty() {
map.push((kid_value(), Value::Bytes(self.key_id)));
map.push((KID.to_cbor_value()?, Value::Bytes(self.key_id)));
}
if let Some(alg) = self.alg {
map.push((alg_value(), alg.to_cbor_value()?));
map.push((ALG.to_cbor_value()?, alg.to_cbor_value()?));
}
if !self.key_ops.is_empty() {
let mut arr = Vec::new();
for op in self.key_ops {
arr.push(op.to_cbor_value()?);
}
map.push((key_ops_value(), Value::Array(arr)));
map.push((KEY_OPS.to_cbor_value()?, Value::Array(arr)));
}
if !self.base_iv.is_empty() {
map.push((base_iv_value(), Value::Bytes(self.base_iv)));
map.push((BASE_IV.to_cbor_value()?, Value::Bytes(self.base_iv)));
}
let mut seen = BTreeSet::new();
for (label, value) in self.params {
Expand Down

0 comments on commit 8e8084a

Please sign in to comment.