From 43c98438fbb188decb8ad02fa4df1d2489e62dc4 Mon Sep 17 00:00:00 2001 From: Ian Hamilton Date: Thu, 15 Aug 2024 10:49:36 -0400 Subject: [PATCH 01/10] feat(did-key): Add EBSI Natural Person Format Enhance did:key functionality to resolve [EBSI-style did:keys](https://hub.ebsi.eu/vc-framework/did/natural-person). They use the JWK_JCS-PUB multicodec. Relevant issues that are related to this PR: [w3c-ccg/did-method-key#63](https://github.com/w3c-ccg/did-method-key/issues/63) [#536](https://github.com/spruceid/ssi/issues/536) Re-do of former PR #545 --- crates/jwk/src/lib.rs | 18 +++++++++++++++++- crates/jwk/src/multicodec.rs | 6 ++++++ tests/jwk_jcs-pub.json | 6 ++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/jwk_jcs-pub.json diff --git a/crates/jwk/src/lib.rs b/crates/jwk/src/lib.rs index aaa94b1dd..1b2f8aa4c 100644 --- a/crates/jwk/src/lib.rs +++ b/crates/jwk/src/lib.rs @@ -102,6 +102,10 @@ impl FromStr for JWK { } } +pub fn from_bytes(bytes: &[u8]) -> Result { + serde_json::from_slice(bytes) +} + impl TryFrom for JWK { type Error = serde_json::Error; @@ -1314,6 +1318,7 @@ mod tests { const RSA_DER: &[u8] = include_bytes!("../../../tests/rsa2048-2020-08-25.der"); const RSA_PK_DER: &[u8] = include_bytes!("../../../tests/rsa2048-2020-08-25-pk.der"); const ED25519_JSON: &str = include_str!("../../../tests/ed25519-2020-10-18.json"); + const JWK_JCS_JSON: &[u8] = include_bytes!("../../../tests/jwk_jcs-pub.json"); #[test] fn jwk_to_from_der_rsa() { @@ -1325,6 +1330,17 @@ mod tests { assert_eq!(key.to_public().params, Params::RSA(rsa_params)); } + #[test] + fn jwk_from_bytes() { + let actual_jwk: JWK = from_bytes(JWK_JCS_JSON).unwrap(); + let actual_params: Params = actual_jwk.params; + if let Params::EC(ref ec_params) = actual_params { + assert_eq!(ec_params.curve.as_deref(), Some("P-256")); + } else { + panic!("actual_params is not of type Params::EC"); + } + } + #[test] fn rsa_from_str() { let _key: JWK = serde_json::from_str(RSA_JSON).unwrap(); @@ -1369,7 +1385,7 @@ mod tests { "alg": "RS256", "kid": "2011-04-29" })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"); diff --git a/crates/jwk/src/multicodec.rs b/crates/jwk/src/multicodec.rs index de8532ca6..168645f76 100644 --- a/crates/jwk/src/multicodec.rs +++ b/crates/jwk/src/multicodec.rs @@ -47,6 +47,9 @@ impl JWK { ssi_multicodec::BLS12_381_G2_PUB => { crate::bls12381g2_parse(k).map_err(FromMulticodecError::Bls12381G2Pub) } + ssi_multicodec::JWK_JCS_PUB => { + crate::from_bytes(k).map_err(FromMulticodecError::JwkJcsPub) + } _ => Err(FromMulticodecError::UnsupportedCodec(codec)), } } @@ -165,6 +168,9 @@ pub enum FromMulticodecError { #[error(transparent)] Bls12381G2Pub(ssi_bbs::Error), + #[error(transparent)] + JwkJcsPub(serde_json::Error), + /// Unexpected multibase (multicodec) key prefix multicodec #[error("Unsupported multicodec key type 0x{0:x}")] UnsupportedCodec(u64), diff --git a/tests/jwk_jcs-pub.json b/tests/jwk_jcs-pub.json new file mode 100644 index 000000000..ee0545982 --- /dev/null +++ b/tests/jwk_jcs-pub.json @@ -0,0 +1,6 @@ +{ + "crv": "P-256", + "kty": "EC", + "x": "g3fsv1xpWPH099LIUn_zJoOF5Ur8xobyzZwX9m_dJ4E", + "y": "9304UAFl55xQMfrnB-zKEjjXEC4OFWSuYnr7W6hdkVA" +} From 5faedc3a0fe05433802e98e3b35745704cfa6204 Mon Sep 17 00:00:00 2001 From: Ian Hamilton Date: Thu, 15 Aug 2024 10:52:19 -0400 Subject: [PATCH 02/10] Revert "feat(did-key): Add EBSI Natural Person Format" This reverts commit 43c98438fbb188decb8ad02fa4df1d2489e62dc4. --- crates/jwk/src/lib.rs | 18 +----------------- crates/jwk/src/multicodec.rs | 6 ------ tests/jwk_jcs-pub.json | 6 ------ 3 files changed, 1 insertion(+), 29 deletions(-) delete mode 100644 tests/jwk_jcs-pub.json diff --git a/crates/jwk/src/lib.rs b/crates/jwk/src/lib.rs index 1b2f8aa4c..aaa94b1dd 100644 --- a/crates/jwk/src/lib.rs +++ b/crates/jwk/src/lib.rs @@ -102,10 +102,6 @@ impl FromStr for JWK { } } -pub fn from_bytes(bytes: &[u8]) -> Result { - serde_json::from_slice(bytes) -} - impl TryFrom for JWK { type Error = serde_json::Error; @@ -1318,7 +1314,6 @@ mod tests { const RSA_DER: &[u8] = include_bytes!("../../../tests/rsa2048-2020-08-25.der"); const RSA_PK_DER: &[u8] = include_bytes!("../../../tests/rsa2048-2020-08-25-pk.der"); const ED25519_JSON: &str = include_str!("../../../tests/ed25519-2020-10-18.json"); - const JWK_JCS_JSON: &[u8] = include_bytes!("../../../tests/jwk_jcs-pub.json"); #[test] fn jwk_to_from_der_rsa() { @@ -1330,17 +1325,6 @@ mod tests { assert_eq!(key.to_public().params, Params::RSA(rsa_params)); } - #[test] - fn jwk_from_bytes() { - let actual_jwk: JWK = from_bytes(JWK_JCS_JSON).unwrap(); - let actual_params: Params = actual_jwk.params; - if let Params::EC(ref ec_params) = actual_params { - assert_eq!(ec_params.curve.as_deref(), Some("P-256")); - } else { - panic!("actual_params is not of type Params::EC"); - } - } - #[test] fn rsa_from_str() { let _key: JWK = serde_json::from_str(RSA_JSON).unwrap(); @@ -1385,7 +1369,7 @@ mod tests { "alg": "RS256", "kid": "2011-04-29" })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"); diff --git a/crates/jwk/src/multicodec.rs b/crates/jwk/src/multicodec.rs index 168645f76..de8532ca6 100644 --- a/crates/jwk/src/multicodec.rs +++ b/crates/jwk/src/multicodec.rs @@ -47,9 +47,6 @@ impl JWK { ssi_multicodec::BLS12_381_G2_PUB => { crate::bls12381g2_parse(k).map_err(FromMulticodecError::Bls12381G2Pub) } - ssi_multicodec::JWK_JCS_PUB => { - crate::from_bytes(k).map_err(FromMulticodecError::JwkJcsPub) - } _ => Err(FromMulticodecError::UnsupportedCodec(codec)), } } @@ -168,9 +165,6 @@ pub enum FromMulticodecError { #[error(transparent)] Bls12381G2Pub(ssi_bbs::Error), - #[error(transparent)] - JwkJcsPub(serde_json::Error), - /// Unexpected multibase (multicodec) key prefix multicodec #[error("Unsupported multicodec key type 0x{0:x}")] UnsupportedCodec(u64), diff --git a/tests/jwk_jcs-pub.json b/tests/jwk_jcs-pub.json deleted file mode 100644 index ee0545982..000000000 --- a/tests/jwk_jcs-pub.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "crv": "P-256", - "kty": "EC", - "x": "g3fsv1xpWPH099LIUn_zJoOF5Ur8xobyzZwX9m_dJ4E", - "y": "9304UAFl55xQMfrnB-zKEjjXEC4OFWSuYnr7W6hdkVA" -} From 6c12ad20d8cbf08d6e9c85679bba99d8ff438770 Mon Sep 17 00:00:00 2001 From: Ian Hamilton Date: Thu, 15 Aug 2024 10:57:59 -0400 Subject: [PATCH 03/10] feat(did-key): Add EBSI Natural Person Format Enhance did:key functionality to resolve [EBSI-style did:keys](https://hub.ebsi.eu/vc-framework/did/natural-person). They use the JWK_JCS-PUB multicodec. Relevant issues that are related to this PR: [w3c-ccg/did-method-key#63](https://github.com/w3c-ccg/did-method-key/issues/63) [#536](https://github.com/spruceid/ssi/issues/536) Re-do of former PR #545 --- crates/jwk/src/lib.rs | 68 ++++++++++++++++++++++-------------- crates/jwk/src/multicodec.rs | 6 ++++ tests/jwk_jcs-pub.json | 6 ++++ 3 files changed, 54 insertions(+), 26 deletions(-) create mode 100644 tests/jwk_jcs-pub.json diff --git a/crates/jwk/src/lib.rs b/crates/jwk/src/lib.rs index aaa94b1dd..f462a888c 100644 --- a/crates/jwk/src/lib.rs +++ b/crates/jwk/src/lib.rs @@ -102,6 +102,10 @@ impl FromStr for JWK { } } +pub fn from_bytes(bytes: &[u8]) -> Result { + serde_json::from_slice(bytes) +} + impl TryFrom for JWK { type Error = serde_json::Error; @@ -418,40 +422,40 @@ impl JWK { match (&self.params, &other.params) { ( Params::RSA(RSAParams { - modulus: Some(n1), - exponent: Some(e1), - .. - }), + modulus: Some(n1), + exponent: Some(e1), + .. + }), Params::RSA(RSAParams { - modulus: Some(n2), - exponent: Some(e2), - .. - }), + modulus: Some(n2), + exponent: Some(e2), + .. + }), ) => n1 == n2 && e1 == e2, (Params::OKP(okp1), Params::OKP(okp2)) => { okp1.curve == okp2.curve && okp1.public_key == okp2.public_key } ( Params::EC(ECParams { - curve: Some(crv1), - x_coordinate: Some(x1), - y_coordinate: Some(y1), - .. - }), + curve: Some(crv1), + x_coordinate: Some(x1), + y_coordinate: Some(y1), + .. + }), Params::EC(ECParams { - curve: Some(crv2), - x_coordinate: Some(x2), - y_coordinate: Some(y2), - .. - }), + curve: Some(crv2), + x_coordinate: Some(x2), + y_coordinate: Some(y2), + .. + }), ) => crv1 == crv2 && x1 == x2 && y1 == y2, ( Params::Symmetric(SymmetricParams { - key_value: Some(kv1), - }), + key_value: Some(kv1), + }), Params::Symmetric(SymmetricParams { - key_value: Some(kv2), - }), + key_value: Some(kv2), + }), ) => kv1 == kv2, _ => false, } @@ -1314,6 +1318,7 @@ mod tests { const RSA_DER: &[u8] = include_bytes!("../../../tests/rsa2048-2020-08-25.der"); const RSA_PK_DER: &[u8] = include_bytes!("../../../tests/rsa2048-2020-08-25-pk.der"); const ED25519_JSON: &str = include_str!("../../../tests/ed25519-2020-10-18.json"); + const JWK_JCS_JSON: &[u8] = include_bytes!("../../../tests/jwk_jcs-pub.json"); #[test] fn jwk_to_from_der_rsa() { @@ -1325,6 +1330,17 @@ mod tests { assert_eq!(key.to_public().params, Params::RSA(rsa_params)); } + #[test] + fn jwk_from_bytes() { + let actual_jwk: JWK = from_bytes(JWK_JCS_JSON).unwrap(); + let actual_params: Params = actual_jwk.params; + if let Params::EC(ref ec_params) = actual_params { + assert_eq!(ec_params.curve.as_deref(), Some("P-256")); + } else { + panic!("actual_params is not of type Params::EC"); + } + } + #[test] fn rsa_from_str() { let _key: JWK = serde_json::from_str(RSA_JSON).unwrap(); @@ -1369,7 +1385,7 @@ mod tests { "alg": "RS256", "kid": "2011-04-29" })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"); @@ -1379,7 +1395,7 @@ mod tests { "kty": "OKP", "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "kPrK_qmxVWaYVA9wwBF6Iuo3vVzz7TxHCTwXBygrS4k"); @@ -1391,7 +1407,7 @@ mod tests { "x": "weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ", "y": "e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck", })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "Vy57XrArUrW0NbpI12tEzDHABxMwrTh6HHXRenSpnCo"); @@ -1400,7 +1416,7 @@ mod tests { "kty": "oct", "k": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "kcfv_I8tB4KY_ljAlRa1ip-y7jzbPdH0sUlCGb-1Jx8"); } diff --git a/crates/jwk/src/multicodec.rs b/crates/jwk/src/multicodec.rs index de8532ca6..168645f76 100644 --- a/crates/jwk/src/multicodec.rs +++ b/crates/jwk/src/multicodec.rs @@ -47,6 +47,9 @@ impl JWK { ssi_multicodec::BLS12_381_G2_PUB => { crate::bls12381g2_parse(k).map_err(FromMulticodecError::Bls12381G2Pub) } + ssi_multicodec::JWK_JCS_PUB => { + crate::from_bytes(k).map_err(FromMulticodecError::JwkJcsPub) + } _ => Err(FromMulticodecError::UnsupportedCodec(codec)), } } @@ -165,6 +168,9 @@ pub enum FromMulticodecError { #[error(transparent)] Bls12381G2Pub(ssi_bbs::Error), + #[error(transparent)] + JwkJcsPub(serde_json::Error), + /// Unexpected multibase (multicodec) key prefix multicodec #[error("Unsupported multicodec key type 0x{0:x}")] UnsupportedCodec(u64), diff --git a/tests/jwk_jcs-pub.json b/tests/jwk_jcs-pub.json new file mode 100644 index 000000000..ee0545982 --- /dev/null +++ b/tests/jwk_jcs-pub.json @@ -0,0 +1,6 @@ +{ + "crv": "P-256", + "kty": "EC", + "x": "g3fsv1xpWPH099LIUn_zJoOF5Ur8xobyzZwX9m_dJ4E", + "y": "9304UAFl55xQMfrnB-zKEjjXEC4OFWSuYnr7W6hdkVA" +} From 9f9d5e83c6fcdac01b15134e497c2a730049c8ea Mon Sep 17 00:00:00 2001 From: Ian Hamilton Date: Thu, 15 Aug 2024 10:57:59 -0400 Subject: [PATCH 04/10] feat(did-key): Add EBSI Natural Person Format Enhance did:key functionality to resolve [EBSI-style did:keys](https://hub.ebsi.eu/vc-framework/did/natural-person). They use the JWK_JCS-PUB multicodec. Relevant issues that are related to this PR: [w3c-ccg/did-method-key#63](https://github.com/w3c-ccg/did-method-key/issues/63) [#536](https://github.com/spruceid/ssi/issues/536) Re-do of former PR #545 --- crates/jwk/src/lib.rs | 68 ++++++++++++++++++++++-------------- crates/jwk/src/multicodec.rs | 6 ++++ tests/jwk_jcs-pub.json | 6 ++++ 3 files changed, 54 insertions(+), 26 deletions(-) create mode 100644 tests/jwk_jcs-pub.json diff --git a/crates/jwk/src/lib.rs b/crates/jwk/src/lib.rs index fb087a315..ecfcd10d4 100644 --- a/crates/jwk/src/lib.rs +++ b/crates/jwk/src/lib.rs @@ -103,6 +103,10 @@ impl FromStr for JWK { } } +pub fn from_bytes(bytes: &[u8]) -> Result { + serde_json::from_slice(bytes) +} + impl TryFrom for JWK { type Error = serde_json::Error; @@ -419,40 +423,40 @@ impl JWK { match (&self.params, &other.params) { ( Params::RSA(RSAParams { - modulus: Some(n1), - exponent: Some(e1), - .. - }), + modulus: Some(n1), + exponent: Some(e1), + .. + }), Params::RSA(RSAParams { - modulus: Some(n2), - exponent: Some(e2), - .. - }), + modulus: Some(n2), + exponent: Some(e2), + .. + }), ) => n1 == n2 && e1 == e2, (Params::OKP(okp1), Params::OKP(okp2)) => { okp1.curve == okp2.curve && okp1.public_key == okp2.public_key } ( Params::EC(ECParams { - curve: Some(crv1), - x_coordinate: Some(x1), - y_coordinate: Some(y1), - .. - }), + curve: Some(crv1), + x_coordinate: Some(x1), + y_coordinate: Some(y1), + .. + }), Params::EC(ECParams { - curve: Some(crv2), - x_coordinate: Some(x2), - y_coordinate: Some(y2), - .. - }), + curve: Some(crv2), + x_coordinate: Some(x2), + y_coordinate: Some(y2), + .. + }), ) => crv1 == crv2 && x1 == x2 && y1 == y2, ( Params::Symmetric(SymmetricParams { - key_value: Some(kv1), - }), + key_value: Some(kv1), + }), Params::Symmetric(SymmetricParams { - key_value: Some(kv2), - }), + key_value: Some(kv2), + }), ) => kv1 == kv2, _ => false, } @@ -1319,6 +1323,7 @@ mod tests { const RSA_DER: &[u8] = include_bytes!("../../../tests/rsa2048-2020-08-25.der"); const RSA_PK_DER: &[u8] = include_bytes!("../../../tests/rsa2048-2020-08-25-pk.der"); const ED25519_JSON: &str = include_str!("../../../tests/ed25519-2020-10-18.json"); + const JWK_JCS_JSON: &[u8] = include_bytes!("../../../tests/jwk_jcs-pub.json"); #[test] fn jwk_to_from_der_rsa() { @@ -1330,6 +1335,17 @@ mod tests { assert_eq!(key.to_public().params, Params::RSA(rsa_params)); } + #[test] + fn jwk_from_bytes() { + let actual_jwk: JWK = from_bytes(JWK_JCS_JSON).unwrap(); + let actual_params: Params = actual_jwk.params; + if let Params::EC(ref ec_params) = actual_params { + assert_eq!(ec_params.curve.as_deref(), Some("P-256")); + } else { + panic!("actual_params is not of type Params::EC"); + } + } + #[test] fn rsa_from_str() { let _key: JWK = serde_json::from_str(RSA_JSON).unwrap(); @@ -1374,7 +1390,7 @@ mod tests { "alg": "RS256", "kid": "2011-04-29" })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"); @@ -1384,7 +1400,7 @@ mod tests { "kty": "OKP", "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "kPrK_qmxVWaYVA9wwBF6Iuo3vVzz7TxHCTwXBygrS4k"); @@ -1396,7 +1412,7 @@ mod tests { "x": "weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ", "y": "e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck", })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "Vy57XrArUrW0NbpI12tEzDHABxMwrTh6HHXRenSpnCo"); @@ -1405,7 +1421,7 @@ mod tests { "kty": "oct", "k": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "kcfv_I8tB4KY_ljAlRa1ip-y7jzbPdH0sUlCGb-1Jx8"); } diff --git a/crates/jwk/src/multicodec.rs b/crates/jwk/src/multicodec.rs index de8532ca6..168645f76 100644 --- a/crates/jwk/src/multicodec.rs +++ b/crates/jwk/src/multicodec.rs @@ -47,6 +47,9 @@ impl JWK { ssi_multicodec::BLS12_381_G2_PUB => { crate::bls12381g2_parse(k).map_err(FromMulticodecError::Bls12381G2Pub) } + ssi_multicodec::JWK_JCS_PUB => { + crate::from_bytes(k).map_err(FromMulticodecError::JwkJcsPub) + } _ => Err(FromMulticodecError::UnsupportedCodec(codec)), } } @@ -165,6 +168,9 @@ pub enum FromMulticodecError { #[error(transparent)] Bls12381G2Pub(ssi_bbs::Error), + #[error(transparent)] + JwkJcsPub(serde_json::Error), + /// Unexpected multibase (multicodec) key prefix multicodec #[error("Unsupported multicodec key type 0x{0:x}")] UnsupportedCodec(u64), diff --git a/tests/jwk_jcs-pub.json b/tests/jwk_jcs-pub.json new file mode 100644 index 000000000..ee0545982 --- /dev/null +++ b/tests/jwk_jcs-pub.json @@ -0,0 +1,6 @@ +{ + "crv": "P-256", + "kty": "EC", + "x": "g3fsv1xpWPH099LIUn_zJoOF5Ur8xobyzZwX9m_dJ4E", + "y": "9304UAFl55xQMfrnB-zKEjjXEC4OFWSuYnr7W6hdkVA" +} From 05f0283ae5b8b8d394bd0abe09c58bf24d022125 Mon Sep 17 00:00:00 2001 From: Ian Hamilton Date: Wed, 28 Aug 2024 10:09:49 -0400 Subject: [PATCH 05/10] feat(did-key): Add EBSI Natural Person Format code review fixes --- crates/jwk/src/lib.rs | 75 ++++++++++++++++++++++-------------- crates/jwk/src/multicodec.rs | 2 +- 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/crates/jwk/src/lib.rs b/crates/jwk/src/lib.rs index ecfcd10d4..baf3ff298 100644 --- a/crates/jwk/src/lib.rs +++ b/crates/jwk/src/lib.rs @@ -103,8 +103,12 @@ impl FromStr for JWK { } } -pub fn from_bytes(bytes: &[u8]) -> Result { - serde_json::from_slice(bytes) +impl TryFrom<&[u8]> for JWK { + type Error = serde_json::Error; + + fn try_from(bytes: &[u8]) -> Result { + serde_json::from_slice(bytes) + } } impl TryFrom for JWK { @@ -306,6 +310,10 @@ impl JWK { } } + pub fn from_bytes(bytes: &[u8]) -> Result { + serde_json::from_slice(bytes) + } + #[cfg(feature = "ed25519")] pub fn generate_ed25519_from( rng: &mut (impl rand::CryptoRng + rand::RngCore), @@ -423,40 +431,40 @@ impl JWK { match (&self.params, &other.params) { ( Params::RSA(RSAParams { - modulus: Some(n1), - exponent: Some(e1), - .. - }), + modulus: Some(n1), + exponent: Some(e1), + .. + }), Params::RSA(RSAParams { - modulus: Some(n2), - exponent: Some(e2), - .. - }), + modulus: Some(n2), + exponent: Some(e2), + .. + }), ) => n1 == n2 && e1 == e2, (Params::OKP(okp1), Params::OKP(okp2)) => { okp1.curve == okp2.curve && okp1.public_key == okp2.public_key } ( Params::EC(ECParams { - curve: Some(crv1), - x_coordinate: Some(x1), - y_coordinate: Some(y1), - .. - }), + curve: Some(crv1), + x_coordinate: Some(x1), + y_coordinate: Some(y1), + .. + }), Params::EC(ECParams { - curve: Some(crv2), - x_coordinate: Some(x2), - y_coordinate: Some(y2), - .. - }), + curve: Some(crv2), + x_coordinate: Some(x2), + y_coordinate: Some(y2), + .. + }), ) => crv1 == crv2 && x1 == x2 && y1 == y2, ( Params::Symmetric(SymmetricParams { - key_value: Some(kv1), - }), + key_value: Some(kv1), + }), Params::Symmetric(SymmetricParams { - key_value: Some(kv2), - }), + key_value: Some(kv2), + }), ) => kv1 == kv2, _ => false, } @@ -1337,7 +1345,18 @@ mod tests { #[test] fn jwk_from_bytes() { - let actual_jwk: JWK = from_bytes(JWK_JCS_JSON).unwrap(); + let actual_jwk: JWK = JWK::from_bytes(JWK_JCS_JSON).unwrap(); + let actual_params: Params = actual_jwk.params; + if let Params::EC(ref ec_params) = actual_params { + assert_eq!(ec_params.curve.as_deref(), Some("P-256")); + } else { + panic!("actual_params is not of type Params::EC"); + } + } + + #[test] + fn jwk_try_from_bytes() { + let actual_jwk: JWK = JWK::try_from(JWK_JCS_JSON).unwrap(); let actual_params: Params = actual_jwk.params; if let Params::EC(ref ec_params) = actual_params { assert_eq!(ec_params.curve.as_deref(), Some("P-256")); @@ -1400,7 +1419,7 @@ mod tests { "kty": "OKP", "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "kPrK_qmxVWaYVA9wwBF6Iuo3vVzz7TxHCTwXBygrS4k"); @@ -1412,7 +1431,7 @@ mod tests { "x": "weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ", "y": "e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck", })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "Vy57XrArUrW0NbpI12tEzDHABxMwrTh6HHXRenSpnCo"); @@ -1421,7 +1440,7 @@ mod tests { "kty": "oct", "k": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "kcfv_I8tB4KY_ljAlRa1ip-y7jzbPdH0sUlCGb-1Jx8"); } diff --git a/crates/jwk/src/multicodec.rs b/crates/jwk/src/multicodec.rs index 168645f76..302684b32 100644 --- a/crates/jwk/src/multicodec.rs +++ b/crates/jwk/src/multicodec.rs @@ -48,7 +48,7 @@ impl JWK { crate::bls12381g2_parse(k).map_err(FromMulticodecError::Bls12381G2Pub) } ssi_multicodec::JWK_JCS_PUB => { - crate::from_bytes(k).map_err(FromMulticodecError::JwkJcsPub) + JWK::from_bytes(k).map_err(FromMulticodecError::JwkJcsPub) } _ => Err(FromMulticodecError::UnsupportedCodec(codec)), } From 0ed793aa457985aa79bb2b6ced9a5d6e09cbf420 Mon Sep 17 00:00:00 2001 From: Ian Hamilton Date: Wed, 28 Aug 2024 10:13:29 -0400 Subject: [PATCH 06/10] feat(did-key): Add EBSI Natural Person Format code review fixes --- crates/jwk/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/jwk/src/lib.rs b/crates/jwk/src/lib.rs index baf3ff298..93709196f 100644 --- a/crates/jwk/src/lib.rs +++ b/crates/jwk/src/lib.rs @@ -1409,7 +1409,7 @@ mod tests { "alg": "RS256", "kid": "2011-04-29" })) - .unwrap(); + .unwrap(); let thumbprint = key.thumbprint().unwrap(); assert_eq!(thumbprint, "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"); From 78a6adb35d235b4d98b1070732ecc39f73a67c95 Mon Sep 17 00:00:00 2001 From: Ian Hamilton Date: Wed, 4 Sep 2024 14:19:13 -0400 Subject: [PATCH 07/10] feat(did-key): Add EBSI Natural Person Format Added test for from_multicodec w/ JWK_JCS_PUB. Added an implementation of ssi_multicodec::Codec for JWK_JCS_PUB. Because of that, removed the existing from_bytes() method. --- crates/jwk/src/lib.rs | 16 +-------------- crates/jwk/src/multicodec.rs | 38 ++++++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/crates/jwk/src/lib.rs b/crates/jwk/src/lib.rs index 93709196f..67f600651 100644 --- a/crates/jwk/src/lib.rs +++ b/crates/jwk/src/lib.rs @@ -310,10 +310,6 @@ impl JWK { } } - pub fn from_bytes(bytes: &[u8]) -> Result { - serde_json::from_slice(bytes) - } - #[cfg(feature = "ed25519")] pub fn generate_ed25519_from( rng: &mut (impl rand::CryptoRng + rand::RngCore), @@ -1326,6 +1322,7 @@ impl From for Base64urlUIntString { #[cfg(test)] mod tests { use super::*; + use ssi_multicodec::Codec; const RSA_JSON: &str = include_str!("../../../tests/rsa2048-2020-08-25.json"); const RSA_DER: &[u8] = include_bytes!("../../../tests/rsa2048-2020-08-25.der"); @@ -1343,17 +1340,6 @@ mod tests { assert_eq!(key.to_public().params, Params::RSA(rsa_params)); } - #[test] - fn jwk_from_bytes() { - let actual_jwk: JWK = JWK::from_bytes(JWK_JCS_JSON).unwrap(); - let actual_params: Params = actual_jwk.params; - if let Params::EC(ref ec_params) = actual_params { - assert_eq!(ec_params.curve.as_deref(), Some("P-256")); - } else { - panic!("actual_params is not of type Params::EC"); - } - } - #[test] fn jwk_try_from_bytes() { let actual_jwk: JWK = JWK::try_from(JWK_JCS_JSON).unwrap(); diff --git a/crates/jwk/src/multicodec.rs b/crates/jwk/src/multicodec.rs index 302684b32..b6ccbd040 100644 --- a/crates/jwk/src/multicodec.rs +++ b/crates/jwk/src/multicodec.rs @@ -1,4 +1,5 @@ -use ssi_multicodec::{MultiEncoded, MultiEncodedBuf}; +use ssi_multicodec::{Codec, MultiEncoded, MultiEncodedBuf}; +use std::borrow::Cow; use crate::{Error, Params, JWK}; @@ -126,6 +127,18 @@ impl JWK { } } +impl Codec for JWK { + const CODEC: u64 = ssi_multicodec::JWK_JCS_PUB; + + fn to_bytes(&self) -> Cow<[u8]> { + Cow::Owned(serde_jcs::to_vec(self).unwrap()) + } + + fn from_bytes(bytes: &[u8]) -> Result { + Self::try_from(bytes).map_err(|_| ssi_multicodec::Error::InvalidData) + } +} + #[derive(Debug, thiserror::Error)] pub enum FromMulticodecError { #[cfg(feature = "rsa")] @@ -169,7 +182,7 @@ pub enum FromMulticodecError { Bls12381G2Pub(ssi_bbs::Error), #[error(transparent)] - JwkJcsPub(serde_json::Error), + JwkJcsPub(ssi_multicodec::Error), /// Unexpected multibase (multicodec) key prefix multicodec #[error("Unsupported multicodec key type 0x{0:x}")] @@ -190,3 +203,24 @@ pub enum ToMulticodecError { #[error("invalid input key: {0}")] InvalidInputKey(Error), } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_multicodec_jwk_jcs_pub() { + let jwk = JWK::generate_p256(); + let jwk_str = serde_jcs::to_string(&jwk).unwrap(); + // Note: can't use JWK::to_multicodec() because it's based on the particular key within the JWK + // it will see the P256 key and assign a multicodec of 0x1200. + // For jwk_jcs_pub multicodecs, we can only decode them + let jwk_buf = + MultiEncodedBuf::encode_bytes(ssi_multicodec::JWK_JCS_PUB, jwk_str.as_bytes()); + let (codec, data) = jwk_buf.parts(); + assert_eq!(codec, ssi_multicodec::JWK_JCS_PUB); + assert_eq!(*data, jwk.to_bytes().into_owned()); + let jwk2 = JWK::from_multicodec(&jwk_buf).unwrap(); + assert_eq!(jwk, jwk2); + } +} From c9ec5bc7904e53f8ddc5425bafaab893560a9816 Mon Sep 17 00:00:00 2001 From: Ian Hamilton Date: Mon, 9 Sep 2024 12:57:00 -0400 Subject: [PATCH 08/10] feat(did-key): Add EBSI Natural Person Format Fixed test_multicodec_jwk_jcs_pub() --- crates/jwk/src/multicodec.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/jwk/src/multicodec.rs b/crates/jwk/src/multicodec.rs index b6ccbd040..c27b9b6f2 100644 --- a/crates/jwk/src/multicodec.rs +++ b/crates/jwk/src/multicodec.rs @@ -211,12 +211,10 @@ mod tests { #[test] fn test_multicodec_jwk_jcs_pub() { let jwk = JWK::generate_p256(); - let jwk_str = serde_jcs::to_string(&jwk).unwrap(); // Note: can't use JWK::to_multicodec() because it's based on the particular key within the JWK // it will see the P256 key and assign a multicodec of 0x1200. // For jwk_jcs_pub multicodecs, we can only decode them - let jwk_buf = - MultiEncodedBuf::encode_bytes(ssi_multicodec::JWK_JCS_PUB, jwk_str.as_bytes()); + let jwk_buf = MultiEncodedBuf::encode(&jwk); let (codec, data) = jwk_buf.parts(); assert_eq!(codec, ssi_multicodec::JWK_JCS_PUB); assert_eq!(*data, jwk.to_bytes().into_owned()); From b3b301b6ea05239b6316ae94243f6e8cccfb8a3b Mon Sep 17 00:00:00 2001 From: Ian Hamilton Date: Mon, 9 Sep 2024 14:05:43 -0400 Subject: [PATCH 09/10] feat(did-key): Add EBSI Natural Person Format Fixed test_multicodec_jwk_jcs_pub() --- crates/jwk/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/jwk/src/lib.rs b/crates/jwk/src/lib.rs index 67f600651..f92380431 100644 --- a/crates/jwk/src/lib.rs +++ b/crates/jwk/src/lib.rs @@ -1322,7 +1322,6 @@ impl From for Base64urlUIntString { #[cfg(test)] mod tests { use super::*; - use ssi_multicodec::Codec; const RSA_JSON: &str = include_str!("../../../tests/rsa2048-2020-08-25.json"); const RSA_DER: &[u8] = include_bytes!("../../../tests/rsa2048-2020-08-25.der"); From 9953e2cd82a16bf64df187a975af26bbb8c4bd6f Mon Sep 17 00:00:00 2001 From: Ian Hamilton Date: Wed, 18 Sep 2024 10:16:33 -0400 Subject: [PATCH 10/10] feat(did-key): Add EBSI Natural Person Format feature gate test --- crates/jwk/src/multicodec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/jwk/src/multicodec.rs b/crates/jwk/src/multicodec.rs index c27b9b6f2..9e12ac8b2 100644 --- a/crates/jwk/src/multicodec.rs +++ b/crates/jwk/src/multicodec.rs @@ -209,6 +209,7 @@ mod tests { use super::*; #[test] + #[cfg(feature = "secp256r1")] fn test_multicodec_jwk_jcs_pub() { let jwk = JWK::generate_p256(); // Note: can't use JWK::to_multicodec() because it's based on the particular key within the JWK