Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cawg_identity): Define CredentialHolder trait #821

Merged
merged 2 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions cawg_identity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
async-trait = "0.1.78"
c2pa-crypto = { path = "../internal/crypto", version = "0.2.0" }
ciborium = "0.2.2"
hex-literal = "0.4.1"
serde = { version = "1.0.197", features = ["derive"] }
serde_bytes = "0.11.14"
thiserror = "1.0.61"

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2.95"
Expand Down
51 changes: 51 additions & 0 deletions cawg_identity/src/builder/credential_holder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2024 Adobe. All rights reserved.
// This file is licensed to you under the Apache License,
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT license (http://opensource.org/licenses/MIT),
// at your option.

// Unless required by applicable law or agreed to in writing,
// this software is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
// specific language governing permissions and limitations under
// each license.

use async_trait::async_trait;

use crate::{builder::IdentityBuilderError, SignerPayload};

/// An implementation of `CredentialHolder` is able to generate a signature over
/// the [`SignerPayload`] data structure on behalf of a credential holder.
///
/// Implementations of this trait will specialize based on the kind of
/// credential as specified in [§8. Credentials, signatures, and validation
/// methods] from the CAWG Identity Assertion specification.
///
/// [§8. Credentials, signatures, and validation methods]: https://cawg.io/identity/1.1-draft/#_credentials_signatures_and_validation_methods
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
pub trait CredentialHolder {
/// Returns the designated `sig_type` value for this kind of credential.
fn sig_type(&self) -> &'static str;

/// Returns the maximum expected size in bytes of the `signature`
/// field for the identity assertion which will be subsequently
/// returned by the [`sign`] function. Signing will fail if the
/// subsequent signature is larger than this number of bytes.
///
/// [`sign`]: Self::sign
fn reserve_size(&self) -> usize;

/// Signs the [`SignerPayload`] data structure on behalf of the credential
/// holder.
///
/// If successful, returns the exact binary content to be placed in
/// the `signature` field for this identity assertion.
///
/// The signature MUST NOT be larger than the size previously stated
/// by the [`reserve_size`] function.
///
/// [`reserve_size`]: Self::reserve_size
async fn sign(&self, signer_payload: &SignerPayload) -> Result<Vec<u8>, IdentityBuilderError>;
}
44 changes: 44 additions & 0 deletions cawg_identity/src/builder/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2025 Adobe. All rights reserved.
// This file is licensed to you under the Apache License,
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT license (http://opensource.org/licenses/MIT),
// at your option.

// Unless required by applicable law or agreed to in writing,
// this software is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
// specific language governing permissions and limitations under
// each license.

use std::fmt::Debug;

use c2pa_crypto::raw_signature::RawSignerError;
use thiserror::Error;

/// Describes errors that can occur when building a CAWG identity assertion.
#[derive(Debug, Error)]
pub enum IdentityBuilderError {
/// The box size provided for the signature is too small.
#[error("the signature box is too small")]
BoxSizeTooSmall,

/// An error occurred while generating CBOR.
#[error("error while generating CBOR ({0})")]
CborGenerationError(String),

/// An error occurred when generating the underlying raw signature.
#[error(transparent)]
RawSignerError(#[from] RawSignerError),

/// An unexpected internal error occured while requesting the time stamp
/// response.
#[error("internal error ({0})")]
InternalError(String),
}

impl<T: Debug> From<ciborium::ser::Error<T>> for IdentityBuilderError {
fn from(err: ciborium::ser::Error<T>) -> Self {
Self::CborGenerationError(err.to_string())
}
}
21 changes: 21 additions & 0 deletions cawg_identity/src/builder/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2024 Adobe. All rights reserved.
// This file is licensed to you under the Apache License,
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT license (http://opensource.org/licenses/MIT),
// at your option.

// Unless required by applicable law or agreed to in writing,
// this software is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
// specific language governing permissions and limitations under
// each license.

//! This module contains the APIs you will use to build a
//! C2PA Manifest that contains one or more CAWG identity assertions.

pub(crate) mod credential_holder;
pub use credential_holder::CredentialHolder;

mod error;
pub use error::IdentityBuilderError;
2 changes: 2 additions & 0 deletions cawg_identity/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#![deny(warnings)]
#![doc = include_str!("../README.md")]

pub mod builder;

mod identity_assertion;
pub use identity_assertion::signer_payload::{HashedUri, SignerPayload};

Expand Down
25 changes: 25 additions & 0 deletions cawg_identity/src/tests/builder/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2025 Adobe. All rights reserved.
// This file is licensed to you under the Apache License,
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT license (http://opensource.org/licenses/MIT),
// at your option.

// Unless required by applicable law or agreed to in writing,
// this software is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
// specific language governing permissions and limitations under
// each license.

use crate::builder::IdentityBuilderError;

#[test]
fn impl_from_ciborium_err() {
let ciborium_err: ciborium::ser::Error<String> = ciborium::ser::Error::Value("foo".to_string());
let builder_err: IdentityBuilderError = ciborium_err.into();

assert_eq!(
builder_err.to_string(),
"error while generating CBOR (Value(\"foo\"))"
);
}
14 changes: 14 additions & 0 deletions cawg_identity/src/tests/builder/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2025 Adobe. All rights reserved.
// This file is licensed to you under the Apache License,
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT license (http://opensource.org/licenses/MIT),
// at your option.

// Unless required by applicable law or agreed to in writing,
// this software is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
// specific language governing permissions and limitations under
// each license.

mod error;
16 changes: 16 additions & 0 deletions cawg_identity/src/tests/fixtures/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2024 Adobe. All rights reserved.
// This file is licensed to you under the Apache License,
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT license (http://opensource.org/licenses/MIT),
// at your option.

// Unless required by applicable law or agreed to in writing,
// this software is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
// specific language governing permissions and limitations under
// each license.

mod naive_credential_holder;
#[allow(unused)]
pub(crate) use naive_credential_holder::NaiveCredentialHolder;
50 changes: 50 additions & 0 deletions cawg_identity/src/tests/fixtures/naive_credential_holder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2024 Adobe. All rights reserved.
// This file is licensed to you under the Apache License,
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT license (http://opensource.org/licenses/MIT),
// at your option.

// Unless required by applicable law or agreed to in writing,
// this software is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
// specific language governing permissions and limitations under
// each license.

//! Naive implementation of credential-handling traits for
//! proof-of-concept/testing purposes.
//!
//! The "signature" in this example is simply the CBOR encoding
//! of the `signer_payload` struct. This is really intended to test
//! the signature mechanism, not to be a meaningful signature itself.
//!
//! Not suitable for production use.

use async_trait::async_trait;

use crate::{
builder::{CredentialHolder, IdentityBuilderError},
SignerPayload,
};

pub(crate) struct NaiveCredentialHolder {}

#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl CredentialHolder for NaiveCredentialHolder {
fn sig_type(&self) -> &'static str {
"INVALID.identity.naive_credential"
}

fn reserve_size(&self) -> usize {
1000
}

async fn sign(&self, signer_payload: &SignerPayload) -> Result<Vec<u8>, IdentityBuilderError> {
// Naive implementation simply serializes SignerPayload
// in CBOR format and calls it a "signature."
let mut result: Vec<u8> = vec![];
ciborium::into_writer(signer_payload, &mut result)?;
Ok(result)
}
}
2 changes: 2 additions & 0 deletions cawg_identity/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#![allow(clippy::panic)]
#![allow(clippy::unwrap_used)]

mod builder;
pub(crate) mod fixtures;
mod identity_assertion;
mod internal;

Expand Down
Loading