Skip to content

Commit

Permalink
Feature-gate Domain Linkage (#1184)
Browse files Browse the repository at this point in the history
* Move domain-linkage to its own module

* Reexport domain-linkage feature in `identity_iota`

* Add license header
  • Loading branch information
PhilippGackstatter authored Jun 12, 2023
1 parent 68055e2 commit b8374a7
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 94 deletions.
2 changes: 1 addition & 1 deletion bindings/wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ wasm-bindgen-futures = { version = "0.4", default-features = false }
version = "0.7.0-alpha.6"
path = "../../identity_iota"
default-features = false
features = ["client", "revocation-bitmap", "resolver", "eddsa"]
features = ["client", "revocation-bitmap", "resolver", "eddsa", "domain-linkage"]

[dev-dependencies]
rand = "0.8.5"
Expand Down
3 changes: 2 additions & 1 deletion identity_credential/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@ credential = []
presentation = ["credential"]
revocation-bitmap = ["dep:dataurl", "dep:flate2", "dep:roaring"]
validator = ["dep:itertools", "dep:serde_repr", "credential", "presentation", "identity_verification/eddsa"]
domain-linkage-fetch = ["dep:reqwest", "dep:futures", "credential"]
domain-linkage = ["validator"]
domain-linkage-fetch = ["domain-linkage", "dep:reqwest", "dep:futures"]
9 changes: 0 additions & 9 deletions identity_credential/src/credential/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@

mod builder;
mod credential;
// TODO: Feature-gate Domain Linkage Types behind its own flag and require flag = ["validator"].
#[cfg(feature = "validator")]
mod domain_linkage_configuration;
#[cfg(feature = "validator")]
mod domain_linkage_credential_builder;
mod evidence;
mod issuer;
mod jws;
Expand All @@ -28,10 +23,6 @@ mod subject;

pub use self::builder::CredentialBuilder;
pub use self::credential::Credential;
#[cfg(feature = "validator")]
pub use self::domain_linkage_configuration::DomainLinkageConfiguration;
#[cfg(feature = "validator")]
pub use self::domain_linkage_credential_builder::DomainLinkageCredentialBuilder;
pub use self::evidence::Evidence;
pub use self::issuer::Issuer;
pub use self::jws::Jws;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use crate::credential::Jwt;
use crate::error::Result;
use crate::validator::vc_jwt_validation::CredentialValidator;
use crate::validator::vc_jwt_validation::ValidationError;
Expand All @@ -15,8 +16,6 @@ use std::fmt::Formatter;

use crate::Error::DomainLinkageError;

use super::Jwt;

lazy_static! {
static ref WELL_KNOWN_CONTEXT: Context =
Context::Url(Url::parse("https://identity.foundation/.well-known/did-configuration/v1").unwrap());
Expand Down Expand Up @@ -110,7 +109,7 @@ impl DomainLinkageConfiguration {

#[cfg(feature = "domain-linkage-fetch")]
mod __fetch_configuration {
use crate::credential::DomainLinkageConfiguration;
use crate::domain_linkage::DomainLinkageConfiguration;
use crate::error::Result;
use crate::Error::DomainLinkageError;
use futures::StreamExt;
Expand Down Expand Up @@ -168,7 +167,7 @@ mod __fetch_configuration {

#[cfg(test)]
mod tests {
use crate::credential::domain_linkage_configuration::DomainLinkageConfiguration;
use crate::domain_linkage::DomainLinkageConfiguration;
use identity_core::convert::FromJson;
use identity_core::error::Result;
use serde_json::json;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

use crate::credential::Credential;
use crate::credential::DomainLinkageConfiguration;
use crate::credential::Issuer;
use crate::credential::Subject;
use crate::domain_linkage::DomainLinkageConfiguration;
use crate::error::Result;
use crate::Error;
use identity_core::common::Object;
Expand Down Expand Up @@ -107,8 +107,8 @@ impl DomainLinkageCredentialBuilder {

#[cfg(test)]
mod tests {
use crate::credential::domain_linkage_credential_builder::DomainLinkageCredentialBuilder;
use crate::credential::Credential;
use crate::domain_linkage::DomainLinkageCredentialBuilder;
use crate::error::Result;
use crate::Error;
use identity_core::common::Timestamp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// SPDX-License-Identifier: Apache-2.0

use crate::credential::Credential;
use crate::credential::DomainLinkageConfiguration;
use crate::credential::Jwt;
use crate::validator::errors::DomainLinkageValidationError;
use crate::validator::errors::DomainLinkageValidationErrorCause;
use crate::domain_linkage::DomainLinkageConfiguration;
use crate::domain_linkage::DomainLinkageValidationError;
use crate::domain_linkage::DomainLinkageValidationErrorCause;
use crate::validator::vc_jwt_validation::CredentialValidationOptions;
use crate::validator::vc_jwt_validation::CredentialValidator;
use crate::validator::FailFast;
Expand All @@ -16,9 +16,9 @@ use identity_document::document::CoreDocument;
use identity_verification::jws::EdDSAJwsVerifier;
use identity_verification::jws::JwsVerifier;

use super::vc_jwt_validation::DecodedJwtCredential;
use crate::validator::vc_jwt_validation::DecodedJwtCredential;

type DomainLinkageValidationResult = Result<(), DomainLinkageValidationError>;
use super::DomainLinkageValidationResult;

/// A validator for a Domain Linkage Configuration and Credentials.
Expand Down Expand Up @@ -229,13 +229,13 @@ impl Default for DomainLinkageValidator {
#[cfg(test)]
mod tests {
use crate::credential::Credential;
use crate::credential::DomainLinkageConfiguration;
use crate::credential::DomainLinkageCredentialBuilder;
use crate::credential::Jws;
use crate::credential::Jwt;
use crate::validator::domain_linkage_validator::DomainLinkageValidationResult;
use crate::validator::domain_linkage_validator::DomainLinkageValidator;
use crate::validator::errors::DomainLinkageValidationErrorCause;
use crate::domain_linkage::DomainLinkageConfiguration;
use crate::domain_linkage::DomainLinkageCredentialBuilder;
use crate::domain_linkage::DomainLinkageValidationErrorCause;
use crate::domain_linkage::DomainLinkageValidationResult;
use crate::domain_linkage::DomainLinkageValidator;
use crate::validator::test_utils::generate_jwk_document_with_keys;
use crate::validator::vc_jwt_validation::CredentialValidationOptions;

Expand Down
65 changes: 65 additions & 0 deletions identity_credential/src/domain_linkage/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use std::error::Error;

pub(crate) type DomainLinkageValidationResult = Result<(), DomainLinkageValidationError>;

#[derive(Debug, thiserror::Error)]
/// An error caused by a failure to verify a Domain Linkage configuration or credential.
pub struct DomainLinkageValidationError {
/// Cause of the error.
pub cause: DomainLinkageValidationErrorCause,
/// Source of the error.
pub source: Option<Box<dyn Error + Send + Sync + 'static>>,
}

impl std::fmt::Display for DomainLinkageValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.cause)
}
}

impl From<DomainLinkageValidationError> for &str {
fn from(value: DomainLinkageValidationError) -> Self {
value.cause.into()
}
}

/// The causes for why domain linkage validation can fail.
#[non_exhaustive]
#[derive(Debug, thiserror::Error, strum::IntoStaticStr)]
pub enum DomainLinkageValidationErrorCause {
#[error("invalid credential")]
CredentialValidationError,
#[error("invalid JWT")]
InvalidJwt,
#[error("the expiration date is missing")]
MissingExpirationDate,
#[error("id property is not allowed")]
ImpermissibleIdProperty,
#[error("issuer DID does not match the subject")]
IssuerSubjectMismatch,
#[error("subject id is invalid")]
InvalidSubjectId,
#[error("credential contains multiple subjects")]
MultipleCredentialSubjects,
#[error("invalid issuer DID")]
InvalidIssuer,
#[error("subject id property is missing")]
MissingSubjectId,
#[error("credential type is invalid")]
InvalidTypeProperty,
#[error("the issuer's id does not match the provided DID Document(s)")]
DocumentMismatch,
#[error("the subject's origin does not match the provided domain origin")]
OriginMismatch,
#[error("the subject's origin property is either invalid or missing")]
InvalidSubjectOrigin,
#[error("invalid semantic structure of the domain linkage configuration")]
InvalidStructure,
#[error("multiple domain linkage credentials reference the same DID")]
AmbiguousCredential,
#[error("a domain linkage credential referencing the provided DID is not found")]
CredentialNotFound,
}
12 changes: 12 additions & 0 deletions identity_credential/src/domain_linkage/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

mod domain_linkage_configuration;
mod domain_linkage_credential_builder;
mod domain_linkage_validator;
mod error;

pub use self::domain_linkage_configuration::*;
pub use self::domain_linkage_credential_builder::*;
pub use self::domain_linkage_validator::*;
pub use error::*;
4 changes: 3 additions & 1 deletion identity_credential/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#![warn(
rust_2018_idioms,
unreachable_pub,
missing_docs,
// missing_docs,
rustdoc::missing_crate_level_docs,
rustdoc::broken_intra_doc_links,
rustdoc::private_intra_doc_links,
Expand All @@ -25,6 +25,8 @@ pub use self::error::Result;

#[cfg(feature = "credential")]
pub mod credential;
#[cfg(feature = "domain-linkage")]
pub mod domain_linkage;
pub mod error;
#[cfg(feature = "presentation")]
pub mod presentation;
Expand Down
58 changes: 0 additions & 58 deletions identity_credential/src/validator/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,61 +142,3 @@ impl Display for CompoundPresentationValidationError {
}

impl Error for CompoundPresentationValidationError {}

#[derive(Debug, thiserror::Error)]
/// An error caused by a failure to verify a Domain Linkage configuration or credential.
pub struct DomainLinkageValidationError {
/// Cause of the error.
pub cause: DomainLinkageValidationErrorCause,
/// Source of the error.
pub source: Option<Box<dyn Error + Send + Sync + 'static>>,
}

impl Display for DomainLinkageValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.cause)
}
}

impl From<DomainLinkageValidationError> for &str {
fn from(value: DomainLinkageValidationError) -> Self {
value.cause.into()
}
}

#[non_exhaustive]
#[derive(Debug, thiserror::Error, strum::IntoStaticStr)]
pub enum DomainLinkageValidationErrorCause {
#[error("invalid credential")]
CredentialValidationError,
#[error("invalid JWT")]
InvalidJwt,
#[error("the expiration date is missing")]
MissingExpirationDate,
#[error("id property is not allowed")]
ImpermissibleIdProperty,
#[error("issuer DID does not match the subject")]
IssuerSubjectMismatch,
#[error("subject id is invalid")]
InvalidSubjectId,
#[error("credential contains multiple subjects")]
MultipleCredentialSubjects,
#[error("invalid issuer DID")]
InvalidIssuer,
#[error("subject id property is missing")]
MissingSubjectId,
#[error("credential type is invalid")]
InvalidTypeProperty,
#[error("the issuer's id does not match the provided DID Document(s)")]
DocumentMismatch,
#[error("the subject's origin does not match the provided domain origin")]
OriginMismatch,
#[error("the subject's origin property is either invalid or missing")]
InvalidSubjectOrigin,
#[error("invalid semantic structure of the domain linkage configuration")]
InvalidStructure,
#[error("multiple domain linkage credentials reference the same DID")]
AmbiguousCredential,
#[error("a domain linkage credential referencing the provided DID is not found")]
CredentialNotFound,
}
5 changes: 1 addition & 4 deletions identity_credential/src/validator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
//! Verifiable Credential and Presentation validators.
pub use self::credential_validator::CredentialValidator;
pub use self::domain_linkage_validator::DomainLinkageValidator;
pub use self::errors::CompoundCredentialValidationError;
pub use self::errors::CompoundPresentationValidationError;
pub use self::errors::DomainLinkageValidationError;
pub use self::errors::SignerContext;
pub use self::errors::ValidationError;
pub use self::presentation_validator::PresentationValidator;
Expand All @@ -19,11 +17,10 @@ pub use self::validation_options::SubjectHolderRelationship;
pub use vp_jwt_validation::*;

mod credential_validator;
mod domain_linkage_validator;
mod errors;
mod presentation_validator;
#[cfg(test)]
mod test_utils;
pub(crate) mod test_utils;
mod validation_options;
mod vp_jwt_validation;

Expand Down
8 changes: 4 additions & 4 deletions identity_credential/src/validator/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub(crate) fn encode_public_ed25519_jwk(public_key: &PublicKey) -> Jwk {
jwk
}

pub(super) fn generate_jwk_document_with_keys() -> (CoreDocument, SecretKey, String) {
pub(crate) fn generate_jwk_document_with_keys() -> (CoreDocument, SecretKey, String) {
let secret: SecretKey = SecretKey::generate().unwrap();
let public: PublicKey = secret.public_key();
let jwk: Jwk = encode_public_ed25519_jwk(&public);
Expand All @@ -51,7 +51,7 @@ pub(super) fn generate_jwk_document_with_keys() -> (CoreDocument, SecretKey, Str
(document, secret, fragment)
}

pub(super) fn generate_document_with_keys() -> (CoreDocument, KeyPair) {
pub(crate) fn generate_document_with_keys() -> (CoreDocument, KeyPair) {
let keypair: KeyPair = KeyPair::new(KeyType::Ed25519).unwrap();
let did: CoreDID = CoreDID::parse(format!("did:example:{}", BaseEncoding::encode_base58(keypair.public()))).unwrap();
let document: CoreDocument = CoreDocument::builder(Object::new())
Expand All @@ -62,7 +62,7 @@ pub(super) fn generate_document_with_keys() -> (CoreDocument, KeyPair) {
(document, keypair)
}

pub(super) fn generate_credential(
pub(crate) fn generate_credential(
issuer: &CoreDocument,
subjects: &[CoreDocument],
issuance_date: Timestamp,
Expand Down Expand Up @@ -97,7 +97,7 @@ pub(super) fn generate_credential(
}

// generates a triple: issuer document, issuer's keys, unsigned credential issued by issuer
pub(super) fn credential_setup() -> (CoreDocument, KeyPair, Credential) {
pub(crate) fn credential_setup() -> (CoreDocument, KeyPair, Credential) {
let (issuer_doc, issuer_key) = generate_document_with_keys();
let (subject_doc, _) = generate_document_with_keys();
let issuance_date = Timestamp::parse("2020-01-01T00:00:00Z").unwrap();
Expand Down
3 changes: 3 additions & 0 deletions identity_iota/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ resolver = ["dep:identity_resolver"]
# Enables `Send` + `Sync` bounds for the storage traits.
send-sync-storage = ["identity_storage/send-sync-storage"]

# Enables domain linkage support.
domain-linkage = ["identity_credential/domain-linkage"]

# Enables fetching domain linkage configuration files.
domain-linkage-fetch = ["identity_credential/domain-linkage-fetch"]

Expand Down
2 changes: 2 additions & 0 deletions identity_iota/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub mod credential {
//! [Specification](https://www.w3.org/TR/vc-data-model/)
pub use identity_credential::credential::*;
#[cfg(feature = "domain-linkage")]
pub use identity_credential::domain_linkage::*;
pub use identity_credential::error::*;
pub use identity_credential::presentation::*;
#[cfg(feature = "revocation-bitmap")]
Expand Down

0 comments on commit b8374a7

Please sign in to comment.