From 3f14c34554882f5a03b619bf4da03f1ff3ada9d3 Mon Sep 17 00:00:00 2001 From: Enrico Marconi Date: Fri, 26 Jan 2024 11:49:58 +0100 Subject: [PATCH 1/7] credentials cannot be unrevoked with StatusList2021 --- .../revocation/status_list_2021/credential.rs | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/identity_credential/src/revocation/status_list_2021/credential.rs b/identity_credential/src/revocation/status_list_2021/credential.rs index 3588772e82..f60956a6e8 100644 --- a/identity_credential/src/revocation/status_list_2021/credential.rs +++ b/identity_credential/src/revocation/status_list_2021/credential.rs @@ -20,7 +20,7 @@ const CREDENTIAL_SUBJECT_TYPE: &str = "StatusList2021"; /// [Error](std::error::Error) type that represents the possible errors that can be /// encountered when dealing with [`StatusList2021Credential`]s. -#[derive(Clone, Debug, Error, strum::IntoStaticStr)] +#[derive(Clone, Debug, Error, strum::IntoStaticStr, PartialEq, Eq)] pub enum StatusList2021CredentialError { /// The provided [`Credential`] has more than one `credentialSubject`. #[error("A StatusList2021Credential may only have one credentialSubject")] @@ -34,9 +34,12 @@ pub enum StatusList2021CredentialError { /// Inner status list failures. #[error(transparent)] StatusListError(#[from] StatusListError), - /// Missing status list id + /// Missing status list id. #[error("Cannot set the status of a credential without a \"credentialSubject.id\".")] Unreferenceable, + /// Credentials cannot be unrevoked. + #[error("A previously revoked credential cannot be unrevoked.")] + UnrevocableCredential, } use crate::credential::Credential; @@ -117,6 +120,10 @@ impl StatusList2021Credential { /// Sets the credential status of a given [`Credential`], /// mapping it to the `index`-th entry of this [`StatusList2021Credential`]. + /// + /// ## Note: + /// A revoked credential cannot ever be unrevoked and will lead to a + /// [`StatusList2021CredentialError::UnrevocableCredential`]. pub fn set_credential_status( &mut self, credential: &mut Credential, @@ -137,6 +144,9 @@ impl StatusList2021Credential { /// Sets the `index`-th entry to `value` pub(crate) fn set_entry(&mut self, index: usize, value: bool) -> Result<(), StatusList2021CredentialError> { + if self.purpose() == StatusPurpose::Revocation && !value { + return Err(StatusList2021CredentialError::UnrevocableCredential); + } let mut status_list = self.status_list()?; status_list.set(index, value)?; self.subject.encoded_list = status_list.into_encoded_str(); @@ -403,4 +413,19 @@ mod tests { .expect("Failed to deserialize"); assert_eq!(credential.purpose(), StatusPurpose::Revocation); } + #[test] + fn revoked_credential_cannot_be_unrevoked() { + let url = Url::parse("http://example.com").unwrap(); + let mut status_list_credential = StatusList2021CredentialBuilder::new(StatusList2021::default()) + .issuer(Issuer::Url(url.clone())) + .purpose(StatusPurpose::Revocation) + .subject_id(url) + .build() + .unwrap(); + + assert_eq!( + status_list_credential.set_entry(420, false), + Err(StatusList2021CredentialError::UnrevocableCredential) + ); + } } From 486342c06c660dbf60e081936408a87061a05000 Mon Sep 17 00:00:00 2001 From: Enrico Marconi Date: Fri, 26 Jan 2024 11:59:53 +0100 Subject: [PATCH 2/7] Add test for unsuspension of credentials --- .../src/revocation/status_list_2021/credential.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/identity_credential/src/revocation/status_list_2021/credential.rs b/identity_credential/src/revocation/status_list_2021/credential.rs index f60956a6e8..ab869d59fd 100644 --- a/identity_credential/src/revocation/status_list_2021/credential.rs +++ b/identity_credential/src/revocation/status_list_2021/credential.rs @@ -428,4 +428,16 @@ mod tests { Err(StatusList2021CredentialError::UnrevocableCredential) ); } + #[test] + fn suspended_credential_can_be_unsuspended() { + let url = Url::parse("http://example.com").unwrap(); + let mut status_list_credential = StatusList2021CredentialBuilder::new(StatusList2021::default()) + .issuer(Issuer::Url(url.clone())) + .purpose(StatusPurpose::Suspension) + .subject_id(url) + .build() + .unwrap(); + + assert!(status_list_credential.set_entry(420, false).is_ok()); + } } From 95bd1cc64e382031a3f013584153dd6f991d93db Mon Sep 17 00:00:00 2001 From: Enrico Marconi Date: Fri, 26 Jan 2024 12:02:50 +0100 Subject: [PATCH 3/7] fmt clippy --- .../src/revocation/status_list_2021/credential.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/identity_credential/src/revocation/status_list_2021/credential.rs b/identity_credential/src/revocation/status_list_2021/credential.rs index ab869d59fd..2728842c50 100644 --- a/identity_credential/src/revocation/status_list_2021/credential.rs +++ b/identity_credential/src/revocation/status_list_2021/credential.rs @@ -438,6 +438,6 @@ mod tests { .build() .unwrap(); - assert!(status_list_credential.set_entry(420, false).is_ok()); + assert!(status_list_credential.set_entry(420, false).is_ok()); } } From 1c0a16706fbf1bbd986ac07c29dfc8032c45a60b Mon Sep 17 00:00:00 2001 From: Enrico Marconi Date: Fri, 26 Jan 2024 12:15:43 +0100 Subject: [PATCH 4/7] unrevoking valid credential does nothing --- .../src/revocation/status_list_2021/credential.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/identity_credential/src/revocation/status_list_2021/credential.rs b/identity_credential/src/revocation/status_list_2021/credential.rs index 2728842c50..d01d28a155 100644 --- a/identity_credential/src/revocation/status_list_2021/credential.rs +++ b/identity_credential/src/revocation/status_list_2021/credential.rs @@ -122,8 +122,9 @@ impl StatusList2021Credential { /// mapping it to the `index`-th entry of this [`StatusList2021Credential`]. /// /// ## Note: - /// A revoked credential cannot ever be unrevoked and will lead to a + /// - A revoked credential cannot ever be unrevoked and will lead to a /// [`StatusList2021CredentialError::UnrevocableCredential`]. + /// - Trying to unrevoke an already valid credential won't do anything. pub fn set_credential_status( &mut self, credential: &mut Credential, @@ -144,10 +145,11 @@ impl StatusList2021Credential { /// Sets the `index`-th entry to `value` pub(crate) fn set_entry(&mut self, index: usize, value: bool) -> Result<(), StatusList2021CredentialError> { - if self.purpose() == StatusPurpose::Revocation && !value { + let mut status_list = self.status_list()?; + let entry_status = status_list.get(index)?; + if self.purpose() == StatusPurpose::Revocation && !value && entry_status { return Err(StatusList2021CredentialError::UnrevocableCredential); } - let mut status_list = self.status_list()?; status_list.set(index, value)?; self.subject.encoded_list = status_list.into_encoded_str(); @@ -423,6 +425,8 @@ mod tests { .build() .unwrap(); + assert!(status_list_credential.set_entry(420, false).is_ok()); + status_list_credential.set_entry(420, true).unwrap(); assert_eq!( status_list_credential.set_entry(420, false), Err(StatusList2021CredentialError::UnrevocableCredential) From 33670b6347cad06dfffb097ea672d7f025a00b99 Mon Sep 17 00:00:00 2001 From: Enrico Marconi Date: Fri, 26 Jan 2024 13:23:54 +0100 Subject: [PATCH 5/7] change error name, fix test --- .../src/revocation/status_list_2021/credential.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/identity_credential/src/revocation/status_list_2021/credential.rs b/identity_credential/src/revocation/status_list_2021/credential.rs index d01d28a155..3784358290 100644 --- a/identity_credential/src/revocation/status_list_2021/credential.rs +++ b/identity_credential/src/revocation/status_list_2021/credential.rs @@ -39,7 +39,7 @@ pub enum StatusList2021CredentialError { Unreferenceable, /// Credentials cannot be unrevoked. #[error("A previously revoked credential cannot be unrevoked.")] - UnrevocableCredential, + UnreversibleRevocation, } use crate::credential::Credential; @@ -148,7 +148,7 @@ impl StatusList2021Credential { let mut status_list = self.status_list()?; let entry_status = status_list.get(index)?; if self.purpose() == StatusPurpose::Revocation && !value && entry_status { - return Err(StatusList2021CredentialError::UnrevocableCredential); + return Err(StatusList2021CredentialError::UnreversibleRevocation); } status_list.set(index, value)?; self.subject.encoded_list = status_list.into_encoded_str(); @@ -429,7 +429,7 @@ mod tests { status_list_credential.set_entry(420, true).unwrap(); assert_eq!( status_list_credential.set_entry(420, false), - Err(StatusList2021CredentialError::UnrevocableCredential) + Err(StatusList2021CredentialError::UnreversibleRevocation) ); } #[test] @@ -443,5 +443,7 @@ mod tests { .unwrap(); assert!(status_list_credential.set_entry(420, false).is_ok()); + status_list_credential.set_entry(420, true).unwrap(); + assert!(status_list_credential.set_entry(420, false).is_ok()); } } From 7d3eb520247f9193c61e00e0eecb7ac57039cd4c Mon Sep 17 00:00:00 2001 From: Enrico Marconi <31142849+UMR1352@users.noreply.github.com> Date: Fri, 26 Jan 2024 15:06:09 +0100 Subject: [PATCH 6/7] Update identity_credential/src/revocation/status_list_2021/credential.rs Co-authored-by: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com> --- .../src/revocation/status_list_2021/credential.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/identity_credential/src/revocation/status_list_2021/credential.rs b/identity_credential/src/revocation/status_list_2021/credential.rs index 3784358290..796a44f5b0 100644 --- a/identity_credential/src/revocation/status_list_2021/credential.rs +++ b/identity_credential/src/revocation/status_list_2021/credential.rs @@ -124,7 +124,7 @@ impl StatusList2021Credential { /// ## Note: /// - A revoked credential cannot ever be unrevoked and will lead to a /// [`StatusList2021CredentialError::UnrevocableCredential`]. - /// - Trying to unrevoke an already valid credential won't do anything. + /// - Trying to set `revoked_or_suspended` to `false` for an already valid credential will have no impact. pub fn set_credential_status( &mut self, credential: &mut Credential, From 7a862626619cefd7134337e225bf6bed2c0d8bd0 Mon Sep 17 00:00:00 2001 From: Enrico Marconi <31142849+UMR1352@users.noreply.github.com> Date: Fri, 26 Jan 2024 15:06:23 +0100 Subject: [PATCH 7/7] Update identity_credential/src/revocation/status_list_2021/credential.rs Co-authored-by: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com> --- .../src/revocation/status_list_2021/credential.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/identity_credential/src/revocation/status_list_2021/credential.rs b/identity_credential/src/revocation/status_list_2021/credential.rs index 796a44f5b0..e3f0875216 100644 --- a/identity_credential/src/revocation/status_list_2021/credential.rs +++ b/identity_credential/src/revocation/status_list_2021/credential.rs @@ -123,7 +123,7 @@ impl StatusList2021Credential { /// /// ## Note: /// - A revoked credential cannot ever be unrevoked and will lead to a - /// [`StatusList2021CredentialError::UnrevocableCredential`]. + /// [`StatusList2021CredentialError::UnreversibleRevocation`]. /// - Trying to set `revoked_or_suspended` to `false` for an already valid credential will have no impact. pub fn set_credential_status( &mut self,