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: add support for ES256 signature algorithm #236

Merged
merged 37 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
81c79d1
feat: add support for `ES256`
nanderstabel May 21, 2024
61f39a4
fix: fix `client_metadata`
nanderstabel May 21, 2024
d103c95
style: tidy up `Corgo.lock` files
nanderstabel May 21, 2024
73b066c
feat: add `pub const SUPPORTED_SIGNING_ALGORITHMS`
nanderstabel May 21, 2024
709fcee
feat: add `IntoJwsAlgorithm` convenience trait
nanderstabel May 21, 2024
de756a8
style: tidy up `stronghold.rs`
nanderstabel May 21, 2024
c53181e
style: remove unused import
nanderstabel May 21, 2024
2b50e45
fix: add `client_metadata` to fixture
nanderstabel May 21, 2024
101ab4b
style: remove unnecessary map
nanderstabel May 21, 2024
10fdc26
style: remove unnecessary references
nanderstabel May 21, 2024
f523dcc
fix: retrieve sigining algorithm from `vp_formats` in Authorization R…
nanderstabel May 21, 2024
0f36c87
Merge branch 'dev' into feat/es256
nanderstabel May 21, 2024
c9cd4e5
chore: bump did_manager
nanderstabel May 21, 2024
faf9898
Merge branch 'dev' into feat/es256
nanderstabel May 22, 2024
db82a14
Merge branch 'dev' into feat/es256
daniel-mader May 28, 2024
7bd1246
chore: bump deps
daniel-mader May 28, 2024
4e22b30
feat: add settings option for preferred key type
daniel-mader May 28, 2024
d29caee
Merge branch 'dev' into feat/es256
daniel-mader May 29, 2024
0cf4d26
chore: bump tauri deps
daniel-mader May 29, 2024
f704603
chore: bump oid4vc dep
daniel-mader May 29, 2024
0b88723
feat: add `const` of supported DID methods
daniel-mader May 29, 2024
610684c
chore: clean up code
daniel-mader May 29, 2024
ba3a638
chore(deps): bump `did_manager`
daniel-mader Jul 16, 2024
e2cd24b
Merge branch 'dev' into feat/es256
daniel-mader Jul 16, 2024
2a61688
chore(deps): bump all `tauri` versions
daniel-mader Jul 16, 2024
302f394
chore: apply review feedback
daniel-mader Jul 16, 2024
2fa0ced
chore: linting issue
daniel-mader Jul 16, 2024
43b0dd0
chore: sort ignores, add `coverage/` & untracked vite files
daniel-mader Jul 16, 2024
1483f44
style: regenerate bindings
daniel-mader Jul 16, 2024
cbb77ee
test: update test fixture
nanderstabel Jul 16, 2024
7c1cce8
refactor: hide key option `ES256K`
daniel-mader Jul 18, 2024
4167f2f
Merge branch 'dev' into feat/es256
nanderstabel Jul 24, 2024
931c9fa
fix: update supported_subject_syntax_types with preferred_did_methods
nanderstabel Jul 24, 2024
53ad873
Merge branch 'dev' into feat/es256
nanderstabel Jul 30, 2024
29abf49
fix: use `KeyFillIcon` instead of `Key`
nanderstabel Jul 30, 2024
a22e4f7
fix: update the Identity Manager
nanderstabel Jul 30, 2024
778e3db
chore: execute `npm install` to update the `package-lock.json` file
nanderstabel Jul 31, 2024
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
629 changes: 417 additions & 212 deletions Cargo.lock

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ tauri = { version = "=2.0.0-beta.19", features = [
"rustls-tls",
] }

oid4vc = { git = "https://git@github.com/impierce/openid4vc.git", rev = "7c6a6eb" }
log = "^0.4"
serde_json = "1.0"
did_manager = { git = "https://github.com/impierce/did-manager.git", rev = "aacecc1" }
did_manager = { git = "https://github.com/impierce/did-manager.git", rev = "d32ed05" }
daniel-mader marked this conversation as resolved.
Show resolved Hide resolved
indoc = "2.0"
jsonwebtoken = "9.3"
log = "^0.4"
rand = "0.8"
wiremock = "0.5"
serde_json = "1.0"
serial_test = "2.0"
tempfile = "3.5.0"
oid4vc = { git = "https://git@github.com/impierce/openid4vc.git", rev = "274a3e9" }
wiremock = "0.5"

[workspace.package]
name = "unime"
Expand Down
28 changes: 15 additions & 13 deletions identity-wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,37 @@ rust-version = "1.75.0"

[dependencies]
tauri.workspace = true
oid4vc.workspace = true
log.workspace = true
serde_json.workspace = true
did_manager.workspace = true

identity_credential = { version = "1.2.0", default-features = false, features = [
"validator",
"credential",
"presentation",
] }
identity_iota = { version = "1.2.0" }
iota_stronghold = { version = "=2.0.0" }
stronghold_engine = "=2.0.0"
anyhow = "1.0"
async-trait = "0.1"
base64 = "0.22"
chrono = "0.4"
derivative = "2.2"
did_manager.workspace = true
downcast-rs = "1.2"
futures = "0.3"
identity_credential = { version = "1.2.0", default-features = false, features = [
"validator",
"credential",
"presentation",
] }
identity_iota = { version = "1.2" }
iota_stronghold = { git = "https://github.com/iotaledger/stronghold.rs", branch = "2.0" }
itertools = "0.10.5"
jsonwebtoken = "8.2"
jsonwebtoken.workspace = true
lazy_static = "1.4.0"
log.workspace = true
oid4vc.workspace = true
p256 = { version = "0.13", features = ["jwk"] }
reqwest = { version = "0.11", default-features = false, features = [
"json",
"rustls-tls",
] }
serde = { version = "1.0", features = ["derive"] }
serde_json.workspace = true
sha256 = "1.4"
stronghold_engine = { git = "https://github.com/iotaledger/stronghold.rs", branch = "2.0" }
stronghold_ext = { git = "https://github.com/tensor-programming/stronghold_ext", features = ["crypto"] }
strum = { version = "0.25", features = ["derive"] }
thiserror = "1.0"
tokio = { version = "1.26.0", features = ["macros"] }
Expand Down
17 changes: 13 additions & 4 deletions identity-wallet/src/state/common/reducers/unlock_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::state::actions::{listen, Action};
use crate::state::common::actions::unlock_storage::UnlockStorage;
use crate::state::core_utils::IdentityManager;
use crate::state::user_prompt::CurrentUserPrompt;
use crate::state::AppState;
use crate::state::{AppState, SUPPORTED_SIGNING_ALGORITHMS};
use crate::stronghold::StrongholdManager;
use crate::subject::subject;

Expand All @@ -21,9 +21,18 @@ pub async fn unlock_storage(state: AppState, action: Action) -> Result<AppState,

let subject = subject(stronghold_manager.clone(), password).await;

let provider_manager =
ProviderManager::new(subject.clone(), preferred_did_method).map_err(OID4VCProviderManagerError)?;
let wallet: Wallet = Wallet::new(subject.clone(), preferred_did_method).map_err(OID4VCWalletError)?;
let provider_manager = ProviderManager::new(
subject.clone(),
preferred_did_method,
Vec::from(SUPPORTED_SIGNING_ALGORITHMS),
)
.map_err(OID4VCProviderManagerError)?;
let wallet: Wallet = Wallet::new(
subject.clone(),
preferred_did_method,
Vec::from(SUPPORTED_SIGNING_ALGORITHMS),
)
.map_err(OID4VCWalletError)?;

info!("loading credentials from stronghold");
let credentials = stronghold_manager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,17 @@ pub fn get_siopv2_client_name_and_logo_uri(
let client_id = siopv2_authorization_request.body.client_id.clone();

// Get the client_name and logo_uri from the client_metadata if it exists.
siopv2_authorization_request
.body
.extension
.client_metadata
.as_ref()
.and_then(|client_metadata| match client_metadata {
ClientMetadataResource::ClientMetadata {
client_name, logo_uri, ..
} => {
let client_name = client_name.as_ref().cloned().unwrap_or(connection_url.to_string());
let logo_uri = logo_uri.as_ref().map(|logo_uri| logo_uri.to_string());
Some((client_name, logo_uri, connection_url.to_string(), client_id.clone()))
}
_ => None,
})
// Otherwise use the connection_url as the client_name.
.unwrap_or((connection_url.to_string(), None, connection_url.to_string(), client_id))
match &siopv2_authorization_request.body.extension.client_metadata {
ClientMetadataResource::ClientMetadata {
client_name, logo_uri, ..
} => {
let client_name = client_name.as_ref().cloned().unwrap_or(connection_url.to_string());
let logo_uri = logo_uri.as_ref().map(|logo_uri| logo_uri.to_string());
Some((client_name, logo_uri, connection_url.to_string(), client_id.clone()))
}
// TODO: support `client_metadata_uri`
ClientMetadataResource::ClientMetadataUri(_) => None,
}
// Otherwise use the connection_url as the client_name.
.unwrap_or((connection_url.to_string(), None, connection_url.to_string(), client_id))
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ use crate::{

use identity_credential::{credential::Jwt, presentation::Presentation};
use identity_iota::did::CoreDID;
use jsonwebtoken::Algorithm;
use log::info;
use oid4vc::oid4vc_core::{
authorization_request::{AuthorizationRequest, Object},
client_metadata::ClientMetadataResource,
};
use oid4vc::oid4vc_manager::managers::presentation::create_presentation_submission;
use oid4vc::oid4vp::oid4vp;
use oid4vc::oid4vp::oid4vp::OID4VP;
use oid4vc::{
oid4vc_core::{
authorization_request::{AuthorizationRequest, Object},
client_metadata::ClientMetadataResource,
},
oid4vp::{ClaimFormatDesignation, ClaimFormatProperty},
};

// Sends the authorization response including the verifiable credentials.
pub async fn handle_oid4vp_authorization_request(mut state: AppState, action: Action) -> Result<AppState, AppError> {
Expand Down Expand Up @@ -84,9 +88,12 @@ pub async fn handle_oid4vp_authorization_request(mut state: AppState, action: Ac
.as_ref()
.ok_or(MissingManagerError("identity"))?;

let (client_name, logo_uri, connection_url, client_id, algorithm) =
get_oid4vp_client_name_and_logo_uri(&oid4vp_authorization_request);

let subject_did = identity_manager
.subject
.identifier(&state.profile_settings.preferred_did_method)
.identifier(&state.profile_settings.preferred_did_method, algorithm)
.await
.expect("No default DID method");

Expand Down Expand Up @@ -125,9 +132,6 @@ pub async fn handle_oid4vp_authorization_request(mut state: AppState, action: Ac
}
info!("response successfully sent");

let (client_name, logo_uri, connection_url, client_id) =
get_oid4vp_client_name_and_logo_uri(&oid4vp_authorization_request);

let did = CoreDID::parse(client_id).ok();

let previously_connected = state.connections.contains(connection_url.as_str(), &client_name);
Expand Down Expand Up @@ -174,7 +178,7 @@ pub async fn handle_oid4vp_authorization_request(mut state: AppState, action: Ac
/// Returns (client_name, logo_uri, connection_url, client_id)
pub fn get_oid4vp_client_name_and_logo_uri(
oid4vp_authorization_request: &AuthorizationRequest<Object<OID4VP>>,
) -> (String, Option<String>, String, String) {
) -> (String, Option<String>, String, String, Algorithm) {
daniel-mader marked this conversation as resolved.
Show resolved Hide resolved
// Get the connection url from the redirect url host (or use the redirect url if it does not
// contain a host).
let redirect_uri = oid4vp_authorization_request.body.redirect_uri.clone();
Expand All @@ -183,21 +187,44 @@ pub fn get_oid4vp_client_name_and_logo_uri(
let client_id = oid4vp_authorization_request.body.client_id.clone();

// Get the client_name and logo_uri from the client_metadata if it exists.
oid4vp_authorization_request
.body
.extension
.client_metadata
.as_ref()
.and_then(|client_metadata| match client_metadata {
ClientMetadataResource::ClientMetadata {
client_name, logo_uri, ..
} => {
let client_name = client_name.as_ref().cloned().unwrap_or(connection_url.to_string());
let logo_uri = logo_uri.as_ref().map(|logo_uri| logo_uri.to_string());
Some((client_name, logo_uri, connection_url.to_string(), client_id.clone()))
}
_ => None,
})
// Otherwise use the connection_url as the client_name.
.unwrap_or((connection_url.to_string(), None, connection_url.to_string(), client_id))
match &oid4vp_authorization_request.body.extension.client_metadata {
ClientMetadataResource::ClientMetadata {
client_name,
logo_uri,
extension: oid4vc::oid4vp::authorization_request::ClientMetadataParameters { vp_formats },
daniel-mader marked this conversation as resolved.
Show resolved Hide resolved
} => {
let client_name = client_name.as_ref().cloned().unwrap_or(connection_url.to_string());
let logo_uri = logo_uri.as_ref().map(|logo_uri| logo_uri.to_string());

// TODO: These helper functions become more and more complicated. This functionality needs to be implemented
// in oid4vc-manager soon.
// Get the algorithm from the client_metadata if it exists or default to EdDSA.
let algorithm = vp_formats
.get(&ClaimFormatDesignation::JwtVcJson)
.and_then(|claim_format_property| match claim_format_property {
ClaimFormatProperty::Alg(alg) => alg.first().cloned(),
// TODO: implement `ProofType`.
ClaimFormatProperty::ProofType(_) => None,
})
.unwrap_or(Algorithm::EdDSA);

Some((
client_name,
logo_uri,
connection_url.to_string(),
client_id.clone(),
algorithm,
))
}
// TODO: support `client_metadata_uri`
ClientMetadataResource::ClientMetadataUri(_) => None,
}
// Otherwise use the connection_url as the client_name.
.unwrap_or((
connection_url.to_string(),
None,
connection_url.to_string(),
client_id,
Algorithm::EdDSA,
))
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,17 +135,16 @@ pub async fn send_credential_request(mut state: AppState, action: Action) -> Res
0 => vec![],
1 => {
let credential_configuration_id = credential_configuration_ids[0].clone();
let credential_format = credential_configurations_supported

let credential_configuration = credential_configurations_supported
.get(&credential_configuration_id)
.ok_or(UnknownCredentialConfigurationIdError(
credential_configuration_id.clone(),
))?
.credential_format
.to_owned();
))?;

// Get the credential.
let credential_response = wallet
.get_credential(credential_issuer_metadata, &token_response, credential_format)
.get_credential(credential_issuer_metadata, &token_response, credential_configuration)
.await
.map_err(GetCredentialError)?;

Expand All @@ -157,16 +156,11 @@ pub async fn send_credential_request(mut state: AppState, action: Action) -> Res
vec![(credential_configuration_id, credential)]
}
_batch => {
let (credential_configuration_ids, credential_formats): (Vec<_>, Vec<_>) =
credential_configurations_supported
.into_iter()
.map(|(credential_configuration_id, credential_configuration)| {
(credential_configuration_id, credential_configuration.credential_format)
})
.unzip();
let (credential_configuration_ids, credential_configurations): (Vec<_>, Vec<_>) =
credential_configurations_supported.into_iter().unzip();

let batch_credential_response = wallet
.get_batch_credential(credential_issuer_metadata, &token_response, credential_formats)
.get_batch_credential(credential_issuer_metadata, &token_response, &credential_configurations)
.await
.map_err(GetBatchCredentialError)?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ use crate::{
dev_mode::DevMode,
profile_settings::{AppTheme, Profile},
user_prompt::CurrentUserPrompt,
AppState,
AppState, SUPPORTED_SIGNING_ALGORITHMS,
},
stronghold::StrongholdManager,
subject::subject,
};

use jsonwebtoken::Algorithm;
use lazy_static::lazy_static;
use log::info;
use oid4vc::{oid4vc_core::Subject, oid4vc_manager::ProviderManager, oid4vci::Wallet};
Expand Down Expand Up @@ -68,9 +69,18 @@ pub async fn load_ferris_profile() -> Result<AppState, AppError> {
};
state.profile_settings.profile.replace(profile);

let provider_manager =
ProviderManager::new(subject.clone(), preferred_did_method).map_err(OID4VCProviderManagerError)?;
let wallet: Wallet = Wallet::new(subject.clone(), preferred_did_method).map_err(OID4VCWalletError)?;
let provider_manager = ProviderManager::new(
subject.clone(),
preferred_did_method,
Vec::from(SUPPORTED_SIGNING_ALGORITHMS),
)
.map_err(OID4VCProviderManagerError)?;
let wallet: Wallet = Wallet::new(
subject.clone(),
preferred_did_method,
Vec::from(SUPPORTED_SIGNING_ALGORITHMS),
)
.map_err(OID4VCWalletError)?;
let identity_manager = IdentityManager {
subject: subject.clone(),
provider_manager,
Expand All @@ -86,10 +96,18 @@ pub async fn load_ferris_profile() -> Result<AppState, AppError> {
.replace(identity_manager);

// Producing DIDs (`did:jwk`, `did:key`)
let did_jwk = subject.identifier("did:jwk").await.map_err(|e| Error(e.to_string()))?;
let did_jwk = subject
// TODO: make distinction between keys using the same DID Method but different algorithms.
.identifier("did:jwk", Algorithm::EdDSA)
.await
.map_err(|e| Error(e.to_string()))?;
state.dids.insert("did:jwk".to_string(), did_jwk);

let did_key = subject.identifier("did:key").await.map_err(|e| Error(e.to_string()))?;
let did_key = subject
// TODO: make distinction between keys using the same DID Method but different algorithms.
.identifier("did:key", Algorithm::EdDSA)
.await
.map_err(|e| Error(e.to_string()))?;
state.dids.insert("did:key".to_string(), did_key);

vec![
Expand Down
3 changes: 3 additions & 0 deletions identity-wallet/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use derivative::Derivative;
use downcast_rs::{impl_downcast, DowncastSync};
use dyn_clone::DynClone;
use futures::Future;
use jsonwebtoken::Algorithm;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::{collections::VecDeque, pin::Pin};
Expand Down Expand Up @@ -73,6 +74,8 @@ impl AppStateContainer {
}
}

pub const SUPPORTED_SIGNING_ALGORITHMS: &[Algorithm] = &[Algorithm::EdDSA, Algorithm::ES256];

/// The inner state of the application managed by Tauri. When the state is serialized in order to be sent to the
/// frontend, the `managers` and `active_connection_request` fields are skipped.
#[derive(Default, Serialize, Deserialize, Derivative, TS, Clone)]
Expand Down
Loading
Loading