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 all 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
1,856 changes: 1,025 additions & 831 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 @@ -3,19 +3,20 @@ resolver = "2"
members = ["identity-wallet", "unime/src-tauri"]

[workspace.dependencies]
tauri = { version = "=2.0.0-beta.19", features = [
tauri = { version = "=2.0.0-beta.24", features = [
"protocol-asset",
"rustls-tls",
] }

oid4vc = { git = "https://git@github.com/impierce/openid4vc.git", rev = "7c6a6eb" }
did_manager = { git = "https://github.com/impierce/did-manager.git", rev = "fa48f4c" }
jsonwebtoken = "9.3"
log = "^0.4"
serde_json = "1.0"
did_manager = { git = "https://github.com/impierce/did-manager.git", rev = "b38a9c4" }
oid4vc = { git = "https://git@github.com/impierce/openid4vc.git", rev = "d095db0" }
rand = "0.8"
wiremock = "0.5"
serde_json = "1.0"
serial_test = "2.0"
tempfile = "3.5.0"
wiremock = "0.5"

[workspace.package]
name = "unime"
Expand Down
34 changes: 18 additions & 16 deletions identity-wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,39 @@ 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.3.0", default-features = false, features = [
"credential",
"domain-linkage",
"presentation",
"validator",
] }
identity_eddsa_verifier = { version = "1.3.0" }
identity_iota = { version = "1.3.0" }
iota_stronghold = { version = "=2.1.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.3", default-features = false, features = [
"credential",
"domain-linkage",
"presentation",
"validator",
] }
identity_eddsa_verifier = { version = "1.3" }
identity_iota = { version = "1.3" }
iota_stronghold = { version = "2.1" }
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 = { version = "2.0.1" }
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 All @@ -53,4 +55,4 @@ rand.workspace = true
wiremock.workspace = true
serial_test.workspace = true
tempfile.workspace = true
tauri = { version = "=2.0.0-beta.19", features = ["rustls-tls", "test"] }
tauri = { version = "=2.0.0-beta.24", features = ["rustls-tls", "test"] }
3 changes: 2 additions & 1 deletion identity-wallet/bindings/actions/Action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import type { QrCodeScanned } from "./QrCodeScanned";
import type { SearchQuery } from "./SearchQuery";
import type { SetLocale } from "./SetLocale";
import type { SetPreferredDidMethod } from "./SetPreferredDidMethod";
import type { SetPreferredKeyType } from "./SetPreferredKeyType";
import type { UnlockStorage } from "./UnlockStorage";
import type { UpdateCredentialMetadata } from "./UpdateCredentialMetadata";
import type { UpdateProfileSettings } from "./UpdateProfileSettings";
import type { UpdateSortingPreference } from "./UpdateSortingPreference";

export type Action = { "type": "[App] Get state" } | { "type": "[Storage] Unlock", payload: UnlockStorage, } | { "type": "[App] Reset" } | { "type": "[DID] Create new", payload: CreateNew, } | { "type": "[Settings] Set locale", payload: SetLocale, } | { "type": "[Settings] Update profile", payload: UpdateProfileSettings, } | { "type": "[QR Code] Scanned", payload: QrCodeScanned, } | { "type": "[Authenticate] Connection accepted" } | { "type": "[User Flow] Cancel", payload?: CancelUserFlow, } | { "type": "[DEV] Load DEV profile", payload: DevProfile, } | { "type": "[DEV] Toggle DEV mode" } | { "type": "[Authenticate] Credentials selected", payload: CredentialsSelected, } | { "type": "[Credential Offer] Selected", payload: CredentialOffersSelected, } | { "type": "[Credential Metadata] Update", payload: UpdateCredentialMetadata, } | { "type": "[User Journey] Cancel" } | { "type": "[Settings] Update sorting preference", payload: UpdateSortingPreference, } | { "type": "[Search] Query", payload: SearchQuery, } | { "type": "[Search] Add recent", payload: AddRecentSearch, } | { "type": "[Search] Delete recent", payload: DeleteRecentSearch, } | { "type": "[DID] Set preferred method", payload: SetPreferredDidMethod, };
export type Action = { "type": "[App] Get state" } | { "type": "[Storage] Unlock", payload: UnlockStorage, } | { "type": "[App] Reset" } | { "type": "[DID] Create new", payload: CreateNew, } | { "type": "[Settings] Set locale", payload: SetLocale, } | { "type": "[Settings] Update profile", payload: UpdateProfileSettings, } | { "type": "[QR Code] Scanned", payload: QrCodeScanned, } | { "type": "[Authenticate] Connection accepted" } | { "type": "[User Flow] Cancel", payload?: CancelUserFlow, } | { "type": "[DEV] Load DEV profile", payload: DevProfile, } | { "type": "[DEV] Toggle DEV mode" } | { "type": "[Authenticate] Credentials selected", payload: CredentialsSelected, } | { "type": "[Credential Offer] Selected", payload: CredentialOffersSelected, } | { "type": "[Credential Metadata] Update", payload: UpdateCredentialMetadata, } | { "type": "[User Journey] Cancel" } | { "type": "[Settings] Update sorting preference", payload: UpdateSortingPreference, } | { "type": "[Search] Query", payload: SearchQuery, } | { "type": "[Search] Add recent", payload: AddRecentSearch, } | { "type": "[Search] Delete recent", payload: DeleteRecentSearch, } | { "type": "[DID] Set preferred method", payload: SetPreferredDidMethod, } | { "type": "[Keys] Set preferred key type", payload: SetPreferredKeyType, };
3 changes: 3 additions & 0 deletions identity-wallet/bindings/actions/SetPreferredKeyType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

export interface SetPreferredKeyType { key_type: string, }
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ import type { Locale } from "./Locale";
import type { Profile } from "./Profile";
import type { SortingPreferences } from "./SortingPreferences";

export interface ProfileSettings { locale: Locale, profile: Profile | null, preferred_did_method: string, sorting_preferences: SortingPreferences, }
export interface ProfileSettings { locale: Locale, profile: Profile | null, preferred_did_methods: Array<string>, preferred_key_types: Array<string>, sorting_preferences: SortingPreferences, }
2 changes: 1 addition & 1 deletion identity-wallet/bindings/user_prompt/CurrentUserPrompt.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ValidationResult } from "./ValidationResult";

export type CurrentUserPrompt = { "type": "redirect", target: string, } | { "type": "password-required" } | { "type": "accept-connection", client_name: string, logo_uri?: string, redirect_uri: string, previously_connected: boolean, domain_validation: ValidationResult, } | { "type": "credential-offer", issuer_name: string, logo_uri?: string, credential_configurations: Record<string, any>, } | { "type": "share-credentials", client_name: string, logo_uri?: string, options: Array<string>, };
export type CurrentUserPrompt = { "type": "redirect", target: string, } | { "type": "password-required" } | { "type": "accept-connection", client_name: string, logo_uri?: string, redirect_uri: string, previously_connected: boolean, domain_validation: ValidationResult, } | { "type": "credential-offer", issuer_name: string, logo_uri?: string, credential_configurations: Record<string, any>, } | { "type": "share-credentials", client_name: string, logo_uri?: string, options: Array<string>, };
2 changes: 1 addition & 1 deletion identity-wallet/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use futures::StreamExt;
use itertools::Itertools;
use log::{debug, error, info};
use std::time::Duration;
use tauri::Manager;
use tauri::Emitter;

// The command.rs holds the functions through which the front and backend communicate using actions and reducers.

Expand Down
4 changes: 3 additions & 1 deletion identity-wallet/src/state/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ mod bindings {
update_credential_metadata::UpdateCredentialMetadata,
},
dev_mode::actions::dev_profile::DevProfile,
did::actions::set_preferred_method::SetPreferredDidMethod,
did::actions::{set_preferred_keytype::SetPreferredKeyType, set_preferred_method::SetPreferredDidMethod},
profile_settings::actions::{
create_new::CreateNew, set_locale::SetLocale, update_profile_settings::UpdateProfileSettings,
update_sorting_preference::UpdateSortingPreference,
Expand Down Expand Up @@ -129,5 +129,7 @@ mod bindings {
DeleteRecentSearch { payload: DeleteRecentSearch },
#[serde(rename = "[DID] Set preferred method")]
SetPreferredDidMethod { payload: SetPreferredDidMethod },
#[serde(rename = "[Keys] Set preferred key type")]
SetPreferredKeyType { payload: SetPreferredKeyType },
}
}
18 changes: 13 additions & 5 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_DID_METHODS, SUPPORTED_SIGNING_ALGORITHMS};
use crate::stronghold::StrongholdManager;
use crate::subject::subject;

Expand All @@ -15,15 +15,23 @@ use std::sync::Arc;
pub async fn unlock_storage(state: AppState, action: Action) -> Result<AppState, AppError> {
if let Some(password) = listen::<UnlockStorage>(action).map(|payload| payload.password) {
let mut state_guard = state.core_utils.managers.lock().await;
let preferred_did_method = state.profile_settings.preferred_did_method.as_str();

let stronghold_manager = Arc::new(StrongholdManager::load(&password).map_err(StrongholdLoadingError)?);

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(),
Vec::from(SUPPORTED_DID_METHODS),
Vec::from(SUPPORTED_SIGNING_ALGORITHMS),
)
.map_err(OID4VCProviderManagerError)?;
let wallet: Wallet = Wallet::new(
subject.clone(),
Vec::from(SUPPORTED_DID_METHODS),
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,19 @@ 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::authorization_request::ClientMetadataParameters;
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 +89,17 @@ pub async fn handle_oid4vp_authorization_request(mut state: AppState, action: Ac
.as_ref()
.ok_or(MissingManagerError("identity"))?;

let OID4VPClientMetadata {
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_methods.first().unwrap(), algorithm)
.await
.expect("No default DID method");

Expand Down Expand Up @@ -125,9 +138,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 @@ -170,11 +180,19 @@ pub async fn handle_oid4vp_authorization_request(mut state: AppState, action: Ac

// Helper

pub struct OID4VPClientMetadata {
pub client_name: String,
pub logo_uri: Option<String>,
pub connection_url: String,
pub client_id: String,
pub algorithm: Algorithm,
}

// TODO: move this functionality to the oid4vc-manager crate.
/// Returns (client_name, logo_uri, connection_url, client_id)
/// Returns (client_name, logo_uri, connection_url, client_id, algorithm)
pub fn get_oid4vp_client_name_and_logo_uri(
oid4vp_authorization_request: &AuthorizationRequest<Object<OID4VP>>,
) -> (String, Option<String>, String, String) {
) -> OID4VPClientMetadata {
// 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 +201,45 @@ 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: ClientMetadataParameters { vp_formats },
other: _,
} => {
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(OID4VPClientMetadata {
client_name,
logo_uri,
connection_url: connection_url.to_string(),
client_id: client_id.clone(),
algorithm,
})
}
// TODO: support `client_metadata_uri`
ClientMetadataResource::ClientMetadataUri(_) => None,
}
// Otherwise use the connection_url as the client_name.
.unwrap_or(OID4VPClientMetadata {
client_name: connection_url.to_string(),
logo_uri: None,
connection_url: connection_url.to_string(),
client_id,
algorithm: Algorithm::EdDSA,
})
}
Loading
Loading