From 48d73a5ee0897f04e630889e8e0b99f2d544349d Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Thu, 2 May 2024 10:34:01 +0200 Subject: [PATCH] Allow missing algorithms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The algorithm field is optional, see RFC 8152 ยง 7: COSE_Key = { 1 => tstr / int, ; kty ? 2 => bstr, ; kid ? 3 => tstr / int, ; alg ? 4 => [+ (tstr / int) ], ; key_ops ? 5 => bstr, ; Base IV * label => values } alg: This parameter is used to restrict the algorithm that is used with the key. If this parameter is present in the key structure, the application MUST verify that this algorithm matches the algorithm for which the key is being used. Fixes: https://github.com/trussed-dev/cosey/issues/3 --- src/lib.rs | 7 +++--- tests/cose.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d34c4b5..08fa556 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -423,12 +423,13 @@ fn check_key_constants( crv: Option, ) -> Result<(), E> { let kty = kty.ok_or_else(|| E::missing_field("kty"))?; - let alg = alg.ok_or_else(|| E::missing_field("alg"))?; if kty != K::KTY { return Err(E::invalid_value(Unexpected::Signed(kty as _), &K::KTY)); } - if alg != K::ALG { - return Err(E::invalid_value(Unexpected::Signed(alg as _), &K::ALG)); + if let Some(alg) = alg { + if alg != K::ALG { + return Err(E::invalid_value(Unexpected::Signed(alg as _), &K::ALG)); + } } if K::CRV != Crv::None { let crv = crv.ok_or_else(|| E::missing_field("crv"))?; diff --git a/tests/cose.rs b/tests/cose.rs index 6d8837c..1e96473 100644 --- a/tests/cose.rs +++ b/tests/cose.rs @@ -55,6 +55,50 @@ fn test_de(s: &str, data: T) { assert_eq!(data, deserialized); } +fn test_de_alg( + data: T, + alg: Option, +) -> bool { + let serialized_value = Value::serialized(&data).unwrap(); + let mut fields = serialized_value.into_map().unwrap(); + // this must be alg + assert_eq!(fields[1].0, Value::Integer(3.into())); + + let expect_success = if let Some(alg) = alg { + // alg values may only work if they are correct + let alg = Value::Integer(alg.into()); + if fields[1].1 == alg { + true + } else { + fields[1].1 = alg; + false + } + } else { + // deserialization without alg must work + fields.remove(1); + true + }; + + let (deserialized, serialized) = deserialize_map::(fields); + let is_success = deserialized.is_ok() == expect_success; + + if !is_success { + if alg.is_some() { + if expect_success { + println!("Expected correct deserialization for original algorithm"); + } else { + println!("Expected error for invalid algorithm"); + } + } else { + println!("Expected correct deserialization for missing algorithm"); + } + println!("alg: {:?}", alg); + print_input_output(&data, &serialized, &deserialized); + } + + is_success +} + fn test_de_order(data: T) -> bool { let serialized_value = Value::serialized(&data).unwrap(); let canonical_fields = serialized_value.into_map().unwrap(); @@ -167,4 +211,24 @@ quickcheck::quickcheck! { x: x.0, }) } + + fn de_alg_p256(x: Input, y: Input, alg: Option) -> bool { + test_de_alg(P256PublicKey { + x: x.0, + y: y.0, + }, alg) + } + + fn de_alg_ecdh(x: Input, y: Input, alg: Option) -> bool { + test_de_alg(EcdhEsHkdf256PublicKey { + x: x.0, + y: y.0, + }, alg) + } + + fn de_alg_ed25519(x: Input, alg: Option) -> bool { + test_de_alg(Ed25519PublicKey { + x: x.0, + }, alg) + } }