From cc192b4a9cf83f7efe6dbdca40ffb00ad4795738 Mon Sep 17 00:00:00 2001 From: Nander Stabel Date: Thu, 4 Apr 2024 21:54:17 +0200 Subject: [PATCH] fix: remove `Subjects` type --- oid4vc-core/src/authentication/sign.rs | 4 +- oid4vc-core/src/authentication/subject.rs | 24 ++---------- oid4vc-core/src/authentication/validator.rs | 20 +--------- oid4vc-core/src/collection.rs | 37 ------------------- oid4vc-core/src/jwt.rs | 8 ++-- oid4vc-core/src/lib.rs | 9 +---- oid4vc-core/src/openid4vc_extension.rs | 4 +- oid4vc-core/src/subject_syntax_type.rs | 17 +++++++++ oid4vc-core/src/test_utils.rs | 2 +- .../src/managers/credential_issuer.rs | 17 +++------ oid4vc-manager/src/managers/provider.rs | 11 +++--- oid4vc-manager/src/managers/relying_party.rs | 15 ++------ oid4vc-manager/src/methods/key_method.rs | 6 +-- oid4vc-manager/tests/common/mod.rs | 2 +- .../tests/oid4vci/authorization_code.rs | 4 +- .../tests/oid4vci/pre_authorized_code.rs | 4 +- oid4vc-manager/tests/oid4vp/implicit.rs | 4 +- oid4vc-manager/tests/siopv2/implicit.rs | 20 +++++----- oid4vci/src/proof.rs | 10 +++-- oid4vci/src/wallet/mod.rs | 16 ++++---- oid4vp/src/oid4vp.rs | 17 +++++++-- siopv2/src/provider.rs | 14 ++++--- siopv2/src/relying_party.rs | 8 ++-- siopv2/src/siopv2.rs | 17 +++++++-- siopv2/src/test_utils.rs | 2 +- 25 files changed, 119 insertions(+), 173 deletions(-) delete mode 100644 oid4vc-core/src/collection.rs diff --git a/oid4vc-core/src/authentication/sign.rs b/oid4vc-core/src/authentication/sign.rs index 021987d0..6284a6dd 100644 --- a/oid4vc-core/src/authentication/sign.rs +++ b/oid4vc-core/src/authentication/sign.rs @@ -4,8 +4,8 @@ use std::sync::Arc; pub trait Sign: Send + Sync { // TODO: add this? // fn jwt_alg_name() -> &'static str; - fn key_id(&self, did_method: &str) -> Option; - fn sign(&self, message: &str, did_method: &str) -> Result>; + fn key_id(&self, subject_syntax_type: &str) -> Option; + fn sign(&self, message: &str, subject_syntax_type: &str) -> Result>; fn external_signer(&self) -> Option>; } diff --git a/oid4vc-core/src/authentication/subject.rs b/oid4vc-core/src/authentication/subject.rs index 8830fa89..54ddc2fc 100644 --- a/oid4vc-core/src/authentication/subject.rs +++ b/oid4vc-core/src/authentication/subject.rs @@ -1,29 +1,11 @@ -use crate::{Collection, Sign, SubjectSyntaxType, Verify}; +use crate::{Sign, Verify}; use anyhow::Result; -use std::{str::FromStr, sync::Arc}; +use std::sync::Arc; pub type SigningSubject = Arc; // TODO: Use a URI of some sort. /// This [`Subject`] trait is used to sign and verify JWTs. pub trait Subject: Sign + Verify + Send + Sync { - fn identifier(&self, did_method: &str) -> Result; - fn type_(&self) -> Result { - SubjectSyntaxType::from_str(&self.identifier("FIX_THIS")?) - } -} - -pub type Subjects = Collection; - -impl TryFrom<[Arc; N]> for Subjects { - type Error = anyhow::Error; - - fn try_from(subjects: [Arc; N]) -> Result { - Ok(Self::from( - subjects - .iter() - .map(|subject| subject.type_().map(|subject_type| (subject_type, subject.clone()))) - .collect::>>()?, - )) - } + fn identifier(&self, subject_syntax_type: &str) -> Result; } diff --git a/oid4vc-core/src/authentication/validator.rs b/oid4vc-core/src/authentication/validator.rs index effd5164..4bb6678e 100644 --- a/oid4vc-core/src/authentication/validator.rs +++ b/oid4vc-core/src/authentication/validator.rs @@ -1,26 +1,8 @@ -use crate::{jwt, Collection, Subject, Subjects, Verify}; +use crate::{jwt, Subject, Verify}; use anyhow::Result; use serde::de::DeserializeOwned; use std::sync::Arc; -pub type Validators = Collection; - -impl From<&Subjects> for Validators { - fn from(subjects: &Subjects) -> Self { - Self::from( - subjects - .iter() - .map(|(subject_syntax_type, subject)| { - ( - subject_syntax_type.clone(), - Arc::new(Validator::Subject(subject.clone())), - ) - }) - .collect::>(), - ) - } -} - pub enum Validator { Subject(Arc), Verifier(Arc), diff --git a/oid4vc-core/src/collection.rs b/oid4vc-core/src/collection.rs deleted file mode 100644 index e7d76c29..00000000 --- a/oid4vc-core/src/collection.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::SubjectSyntaxType; -use std::{collections::HashMap, sync::Arc}; - -#[derive(Clone)] -pub struct Collection(pub HashMap>); - -impl Collection { - pub fn get(&self, subject_syntax_type: &SubjectSyntaxType) -> Option<&Arc> { - self.0.get(subject_syntax_type) - } - - pub fn add(&mut self, subject_syntax_type: SubjectSyntaxType, subject: Arc) { - self.0.insert(subject_syntax_type, subject); - } - - pub fn iter(&self) -> impl Iterator)> { - self.0.iter() - } -} - -impl Default for Collection { - fn default() -> Self { - Collection(HashMap::new()) - } -} - -impl From<[(SubjectSyntaxType, Arc); N]> for Collection { - fn from(items: [(SubjectSyntaxType, Arc); N]) -> Self { - Collection(items.iter().cloned().collect()) - } -} - -impl From)>> for Collection { - fn from(items: Vec<(SubjectSyntaxType, Arc)>) -> Self { - Collection(items.iter().cloned().collect()) - } -} diff --git a/oid4vc-core/src/jwt.rs b/oid4vc-core/src/jwt.rs index a5f27942..c0c2c640 100644 --- a/oid4vc-core/src/jwt.rs +++ b/oid4vc-core/src/jwt.rs @@ -50,18 +50,20 @@ where Ok(jsonwebtoken::decode::(jwt, &key, &validation)?.claims) } -pub fn encode(signer: Arc, header: Header, claims: C, did_method: &str) -> Result +pub fn encode(signer: Arc, header: Header, claims: C, subject_syntax_type: &str) -> Result where C: Serialize, S: Sign + ?Sized, { - let kid = signer.key_id(did_method).ok_or(anyhow!("No key identifier found."))?; + let kid = signer + .key_id(subject_syntax_type) + .ok_or(anyhow!("No key identifier found."))?; let jwt = JsonWebToken::new(header, claims).kid(kid); let message = [base64_url_encode(&jwt.header)?, base64_url_encode(&jwt.payload)?].join("."); - let proof_value = signer.sign(&message, did_method)?; + let proof_value = signer.sign(&message, subject_syntax_type)?; let signature = base64_url::encode(proof_value.as_slice()); let message = [message, signature].join("."); Ok(message) diff --git a/oid4vc-core/src/lib.rs b/oid4vc-core/src/lib.rs index fabd704e..fa3b6205 100644 --- a/oid4vc-core/src/lib.rs +++ b/oid4vc-core/src/lib.rs @@ -2,20 +2,13 @@ pub mod authentication; pub mod authorization_request; pub mod authorization_response; pub mod client_metadata; -pub mod collection; pub mod jwt; pub mod openid4vc_extension; pub mod rfc7519_claims; pub mod scope; pub mod subject_syntax_type; -pub use authentication::{ - sign::Sign, - subject::{Subject, Subjects}, - validator::{Validator, Validators}, - verify::Verify, -}; -pub use collection::Collection; +pub use authentication::{sign::Sign, subject::Subject, validator::Validator, verify::Verify}; use rand::{distributions::Alphanumeric, Rng}; pub use rfc7519_claims::RFC7519Claims; use serde::Serialize; diff --git a/oid4vc-core/src/openid4vc_extension.rs b/oid4vc-core/src/openid4vc_extension.rs index 1859a498..3c46c947 100644 --- a/oid4vc-core/src/openid4vc_extension.rs +++ b/oid4vc-core/src/openid4vc_extension.rs @@ -1,4 +1,4 @@ -use crate::{authorization_response::AuthorizationResponse, Subject, Validator}; +use crate::{authorization_response::AuthorizationResponse, Subject, SubjectSyntaxType, Validator}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{future::Future, sync::Arc}; @@ -28,7 +28,7 @@ pub trait Extension: Serialize + PartialEq + Sized + std::fmt::Debug + Clone + S _client_id: &str, _extension_parameters: &::Parameters, _user_input: &::Input, - _did_method: &str, + _subject_syntax_type: impl TryInto, ) -> anyhow::Result> { // Will be overwritten by the extension. Err(anyhow::anyhow!("Not implemented.")) diff --git a/oid4vc-core/src/subject_syntax_type.rs b/oid4vc-core/src/subject_syntax_type.rs index 0727bc03..50fc1950 100644 --- a/oid4vc-core/src/subject_syntax_type.rs +++ b/oid4vc-core/src/subject_syntax_type.rs @@ -21,6 +21,23 @@ impl FromStr for SubjectSyntaxType { } } +impl Display for SubjectSyntaxType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SubjectSyntaxType::JwkThumbprint => write!(f, "urn:ietf:params:oauth:jwk-thumbprint"), + SubjectSyntaxType::Did(did_method) => write!(f, "{}", did_method), + } + } +} + +impl TryFrom<&str> for SubjectSyntaxType { + type Error = anyhow::Error; + + fn try_from(value: &str) -> Result { + SubjectSyntaxType::from_str(value) + } +} + impl From for SubjectSyntaxType { fn from(did_method: DidMethod) -> Self { SubjectSyntaxType::Did(did_method) diff --git a/oid4vc-core/src/test_utils.rs b/oid4vc-core/src/test_utils.rs index 436d1d29..97bc9f3f 100644 --- a/oid4vc-core/src/test_utils.rs +++ b/oid4vc-core/src/test_utils.rs @@ -53,7 +53,7 @@ impl Verify for TestSubject { } impl Subject for TestSubject { - fn identifier(&self, _default_did_method: &str) -> Result { + fn identifier(&self, _subject_syntax_type: &str) -> Result { Ok(self.did.to_string()) } } diff --git a/oid4vc-manager/src/managers/credential_issuer.rs b/oid4vc-manager/src/managers/credential_issuer.rs index 2a2f24a9..1fed9430 100644 --- a/oid4vc-manager/src/managers/credential_issuer.rs +++ b/oid4vc-manager/src/managers/credential_issuer.rs @@ -1,6 +1,6 @@ use crate::storage::Storage; use anyhow::Result; -use oid4vc_core::{Subject, Subjects}; +use oid4vc_core::Subject; use oid4vci::{ credential_format_profiles::CredentialFormatCollection, credential_issuer::{ @@ -15,26 +15,19 @@ use std::{net::TcpListener, sync::Arc}; #[derive(Clone)] pub struct CredentialIssuerManager, CFC: CredentialFormatCollection> { pub credential_issuer: CredentialIssuer, - pub subjects: Arc, + pub subject: Arc, pub storage: S, pub listener: Arc, } impl, CFC: CredentialFormatCollection> CredentialIssuerManager { - pub fn new( - listener: Option, - storage: S, - subjects: [Arc; N], - ) -> Result { + pub fn new(listener: Option, storage: S, subject: Arc) -> Result { // `TcpListener::bind("127.0.0.1:0")` will bind to a random port. let listener = listener.unwrap_or_else(|| TcpListener::bind("127.0.0.1:0").unwrap()); let issuer_url: Url = format!("http://{:?}", listener.local_addr()?).parse()?; Ok(Self { credential_issuer: CredentialIssuer { - subject: subjects - .first() - .ok_or_else(|| anyhow::anyhow!("No subjects found."))? - .clone(), + subject: subject.clone(), metadata: CredentialIssuerMetadata { credential_issuer: issuer_url.clone(), authorization_servers: vec![], @@ -56,7 +49,7 @@ impl, CFC: CredentialFormatCollection> CredentialIssuerManager(subjects: [Arc; N], default_did_method: String) -> Result { + pub fn new( + subject: Arc, + default_subject_syntax_type: impl TryInto, + ) -> Result { Ok(Self { - provider: Provider::new(subjects[0].clone(), default_did_method)?, + provider: Provider::new(subject, default_subject_syntax_type)?, }) } @@ -39,8 +42,4 @@ impl ProviderManager { ) -> Result { self.provider.send_response(authorization_response).await } - - pub fn current_subject_syntax_type(&self) -> Result { - self.provider.subject.type_() - } } diff --git a/oid4vc-manager/src/managers/relying_party.rs b/oid4vc-manager/src/managers/relying_party.rs index ac0d5fbc..4f38a8d8 100644 --- a/oid4vc-manager/src/managers/relying_party.rs +++ b/oid4vc-manager/src/managers/relying_party.rs @@ -1,9 +1,9 @@ -use anyhow::{anyhow, Result}; +use anyhow::Result; use oid4vc_core::{ authorization_request::{AuthorizationRequest, Object}, authorization_response::AuthorizationResponse, openid4vc_extension::{Extension, ResponseHandle}, - Subject, SubjectSyntaxType, + Subject, }; use siopv2::RelyingParty; use std::sync::Arc; @@ -14,12 +14,9 @@ pub struct RelyingPartyManager { } impl RelyingPartyManager { - pub fn new(subjects: [Arc; N], default_did_method: String) -> Result { + pub fn new(subject: Arc, subject_syntax_type: String) -> Result { Ok(Self { - relying_party: RelyingParty::new( - subjects.get(0).ok_or_else(|| anyhow!("No subjects found."))?.clone(), - default_did_method, - )?, + relying_party: RelyingParty::new(subject, subject_syntax_type)?, }) } @@ -33,8 +30,4 @@ impl RelyingPartyManager { ) -> Result<::ResponseItem> { self.relying_party.validate_response(authorization_response).await } - - pub fn current_subject_syntax_type(&self) -> Result { - self.relying_party.subject.type_() - } } diff --git a/oid4vc-manager/src/methods/key_method.rs b/oid4vc-manager/src/methods/key_method.rs index e1f787c7..4fba6f48 100644 --- a/oid4vc-manager/src/methods/key_method.rs +++ b/oid4vc-manager/src/methods/key_method.rs @@ -70,7 +70,7 @@ impl Verify for KeySubject { } impl Subject for KeySubject { - fn identifier(&self, _did_method: &str) -> Result { + fn identifier(&self, _subject_syntax_type: &str) -> Result { Ok(self.document.id.clone()) } } @@ -120,7 +120,7 @@ mod tests { let subject = KeySubject::new(); // Create a new provider manager. - let provider_manager = ProviderManager::new([Arc::new(subject)], "did:key".to_string()).unwrap(); + let provider_manager = ProviderManager::new(Arc::new(subject), "did:key").unwrap(); // Get a new SIOP authorization_request with response mode `direct_post` for cross-device communication. let request_url = "\ @@ -152,7 +152,7 @@ mod tests { // Let the relying party validate the authorization_response. let relying_party_manager = - RelyingPartyManager::new([Arc::new(KeySubject::new())], "did:key".to_string()).unwrap(); + RelyingPartyManager::new(Arc::new(KeySubject::new()), "did:key".to_string()).unwrap(); assert!(relying_party_manager .validate_response(&authorization_response) .await diff --git a/oid4vc-manager/tests/common/mod.rs b/oid4vc-manager/tests/common/mod.rs index 1276e0fe..9c6068c5 100644 --- a/oid4vc-manager/tests/common/mod.rs +++ b/oid4vc-manager/tests/common/mod.rs @@ -59,7 +59,7 @@ impl Verify for TestSubject { } impl Subject for TestSubject { - fn identifier(&self, _did_method: &str) -> Result { + fn identifier(&self, _subject_syntax_type: &str) -> Result { Ok(self.did.to_string()) } } diff --git a/oid4vc-manager/tests/oid4vci/authorization_code.rs b/oid4vc-manager/tests/oid4vci/authorization_code.rs index 9f922ad1..4d6bc891 100644 --- a/oid4vc-manager/tests/oid4vci/authorization_code.rs +++ b/oid4vc-manager/tests/oid4vci/authorization_code.rs @@ -22,12 +22,12 @@ async fn test_authorization_code_flow() { CredentialIssuerManager::<_, CredentialFormats>::new( None, MemoryStorage, - [Arc::new(KeySubject::from_keypair( + Arc::new(KeySubject::from_keypair( generate::(Some( "this-is-a-very-UNSAFE-issuer-secret-key".as_bytes().try_into().unwrap(), )), None, - ))], + )), ) .unwrap(), None, diff --git a/oid4vc-manager/tests/oid4vci/pre_authorized_code.rs b/oid4vc-manager/tests/oid4vci/pre_authorized_code.rs index c18cb32a..05d21a0f 100644 --- a/oid4vc-manager/tests/oid4vci/pre_authorized_code.rs +++ b/oid4vc-manager/tests/oid4vci/pre_authorized_code.rs @@ -26,12 +26,12 @@ async fn test_pre_authorized_code_flow(#[case] batch: bool, #[case] by_reference CredentialIssuerManager::new( None, MemoryStorage, - [Arc::new(KeySubject::from_keypair( + Arc::new(KeySubject::from_keypair( generate::(Some( "this-is-a-very-UNSAFE-issuer-secret-key".as_bytes().try_into().unwrap(), )), None, - ))], + )), ) .unwrap(), None, diff --git a/oid4vc-manager/tests/oid4vp/implicit.rs b/oid4vc-manager/tests/oid4vp/implicit.rs index e4ca8628..316105ee 100644 --- a/oid4vc-manager/tests/oid4vp/implicit.rs +++ b/oid4vc-manager/tests/oid4vp/implicit.rs @@ -89,7 +89,7 @@ async fn test_implicit_flow() { // Create a new relying party. let relying_party = Arc::new(KeySubject::new()); let relying_party_did = relying_party.identifier("did:key").unwrap(); - let relying_party_manager = RelyingPartyManager::new([relying_party], "did:key".to_string()).unwrap(); + let relying_party_manager = RelyingPartyManager::new(relying_party, "did:key".to_string()).unwrap(); // Create authorization request with response_type `id_token vp_token` let authorization_request = AuthorizationRequest::>::builder() @@ -101,7 +101,7 @@ async fn test_implicit_flow() { .unwrap(); // Create a provider manager and validate the authorization request. - let provider_manager = ProviderManager::new([subject], "did:key".to_string()).unwrap(); + let provider_manager = ProviderManager::new(subject, "did:key").unwrap(); // Create a new verifiable credential. let verifiable_credential = VerifiableCredentialJwt::builder() diff --git a/oid4vc-manager/tests/siopv2/implicit.rs b/oid4vc-manager/tests/siopv2/implicit.rs index 6aacda83..79a56f2a 100644 --- a/oid4vc-manager/tests/siopv2/implicit.rs +++ b/oid4vc-manager/tests/siopv2/implicit.rs @@ -30,10 +30,10 @@ pub struct MultiDidMethodSubject { } impl Sign for MultiDidMethodSubject { - fn key_id(&self, did_method: &str) -> Option { - match did_method { - "did:test" => self.test_subject.key_id(did_method), - "did:key" => self.key_subject.key_id(did_method), + fn key_id(&self, subject_syntax_type: &str) -> Option { + match subject_syntax_type { + "did:test" => self.test_subject.key_id(subject_syntax_type), + "did:key" => self.key_subject.key_id(subject_syntax_type), _ => None, } } @@ -59,10 +59,10 @@ impl Verify for MultiDidMethodSubject { } impl Subject for MultiDidMethodSubject { - fn identifier(&self, did_method: &str) -> anyhow::Result { - match did_method { - "did:test" => self.test_subject.identifier(did_method), - "did:key" => self.key_subject.identifier(did_method), + fn identifier(&self, subject_syntax_type: &str) -> anyhow::Result { + match subject_syntax_type { + "did:test" => self.test_subject.identifier(subject_syntax_type), + "did:key" => self.key_subject.identifier(subject_syntax_type), _ => Err(anyhow::anyhow!("Unsupported DID method.")), } } @@ -112,7 +112,7 @@ async fn test_implicit_flow() { }; // Create a new relying party manager. - let relying_party_manager = RelyingPartyManager::new([Arc::new(subject)], "did:test".to_string()).unwrap(); + let relying_party_manager = RelyingPartyManager::new(Arc::new(subject), "did:test".to_string()).unwrap(); // Create a new RequestUrl with response mode `direct_post` for cross-device communication. let authorization_request: AuthorizationRequest> = AuthorizationRequest::>::builder() @@ -166,7 +166,7 @@ async fn test_implicit_flow() { let subject = TestSubject::new("did:test:subject".to_string(), "did:test:subject#key_id".to_string()).unwrap(); // Create a new provider manager. - let provider_manager = ProviderManager::new([Arc::new(subject)], "did:test".to_string()).unwrap(); + let provider_manager = ProviderManager::new(Arc::new(subject), "did:test").unwrap(); // Create a new RequestUrl which includes a `request_uri` pointing to the mock server's `request_uri` endpoint. let authorization_request = AuthorizationRequest:: { diff --git a/oid4vci/src/proof.rs b/oid4vci/src/proof.rs index 7b78f510..c3f7e7b0 100644 --- a/oid4vci/src/proof.rs +++ b/oid4vci/src/proof.rs @@ -38,7 +38,7 @@ pub struct ProofBuilder { rfc7519_claims: RFC7519Claims, nonce: Option, signer: Option>, - did_method: Option, + subject_syntax_type: Option, } #[derive(Debug, Serialize, Deserialize)] @@ -54,7 +54,9 @@ impl ProofBuilder { anyhow::ensure!(self.rfc7519_claims.iat.is_some(), "iat claim is required"); anyhow::ensure!(self.nonce.is_some(), "nonce claim is required"); - let did_method = self.did_method.ok_or(anyhow::anyhow!("did_method is required"))?; + let subject_syntax_type = self + .subject_syntax_type + .ok_or(anyhow::anyhow!("subject_syntax_type is required"))?; match self.proof_type { Some(ProofType::Jwt) => Ok(KeyProofType::Jwt { @@ -69,7 +71,7 @@ impl ProofBuilder { rfc7519_claims: self.rfc7519_claims, nonce: self.nonce.ok_or(anyhow::anyhow!("No nonce found"))?, }, - &did_method, + &subject_syntax_type, )?, }), Some(ProofType::Cwt) => todo!(), @@ -89,5 +91,5 @@ impl ProofBuilder { builder_fn!(rfc7519_claims, exp, i64); builder_fn!(rfc7519_claims, iat, i64); builder_fn!(nonce, String); - builder_fn!(did_method, String); + builder_fn!(subject_syntax_type, String); } diff --git a/oid4vci/src/wallet/mod.rs b/oid4vci/src/wallet/mod.rs index 2067c628..2f913860 100644 --- a/oid4vci/src/wallet/mod.rs +++ b/oid4vci/src/wallet/mod.rs @@ -23,20 +23,20 @@ where CFC: CredentialFormatCollection, { pub subject: SigningSubject, - pub default_did_method: String, + pub default_subject_syntax_type: String, pub client: ClientWithMiddleware, phantom: std::marker::PhantomData, } impl Wallet { - pub fn new(subject: SigningSubject, default_did_method: String) -> Self { + pub fn new(subject: SigningSubject, default_subject_syntax_type: String) -> Self { let retry_policy = ExponentialBackoff::builder().build_with_max_retries(5); let client = ClientBuilder::new(reqwest::Client::new()) .with(RetryTransientMiddleware::new_with_policy(retry_policy)) .build(); Self { subject, - default_did_method, + default_subject_syntax_type, client, phantom: std::marker::PhantomData, } @@ -107,7 +107,7 @@ impl Wallet { // TODO: must be `form`, but `AuthorizationRequest needs to be able to serilalize properly. .json(&AuthorizationRequest { response_type: "code".to_string(), - client_id: self.subject.identifier(&self.default_did_method)?, + client_id: self.subject.identifier(&self.default_subject_syntax_type)?, redirect_uri: None, scope: None, state: None, @@ -143,7 +143,7 @@ impl Wallet { KeyProofType::builder() .proof_type(ProofType::Jwt) .signer(self.subject.clone()) - .iss(self.subject.identifier(&self.default_did_method)?) + .iss(self.subject.identifier(&self.default_subject_syntax_type)?) .aud(credential_issuer_metadata.credential_issuer) .iat(1571324800) .exp(9999999999i64) @@ -155,7 +155,7 @@ impl Wallet { .ok_or(anyhow::anyhow!("No c_nonce found."))? .clone(), ) - .did_method(&self.default_did_method) + .subject_syntax_type(&self.default_subject_syntax_type) .build()?, ), }; @@ -181,7 +181,7 @@ impl Wallet { KeyProofType::builder() .proof_type(ProofType::Jwt) .signer(self.subject.clone()) - .iss(self.subject.identifier(&self.default_did_method)?) + .iss(self.subject.identifier(&self.default_subject_syntax_type)?) .aud(credential_issuer_metadata.credential_issuer) .iat(1571324800) .exp(9999999999i64) @@ -193,7 +193,7 @@ impl Wallet { .ok_or(anyhow::anyhow!("No c_nonce found."))? .clone(), ) - .did_method(&self.default_did_method) + .subject_syntax_type(&self.default_subject_syntax_type) .build()?, ); diff --git a/oid4vp/src/oid4vp.rs b/oid4vp/src/oid4vp.rs index ecd6c12d..57bc668a 100644 --- a/oid4vp/src/oid4vp.rs +++ b/oid4vp/src/oid4vp.rs @@ -10,8 +10,8 @@ use futures::{executor::block_on, future::join_all}; use identity_credential::{credential::Jwt, presentation::Presentation}; use jsonwebtoken::{Algorithm, Header}; use oid4vc_core::openid4vc_extension::{OpenID4VC, RequestHandle, ResponseHandle}; -use oid4vc_core::Validator; use oid4vc_core::{authorization_response::AuthorizationResponse, jwt, openid4vc_extension::Extension, Subject}; +use oid4vc_core::{SubjectSyntaxType, Validator}; use oid4vci::VerifiableCredentialJwt; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -46,9 +46,13 @@ impl Extension for OID4VP { client_id: &str, extension_parameters: &::Parameters, user_input: &::Input, - did_method: &str, + subject_syntax_type: impl TryInto, ) -> anyhow::Result> { - let subject_identifier = subject.identifier(did_method)?; + let subject_syntax_type_string = subject_syntax_type + .try_into() + .map_err(|_| anyhow::anyhow!("Failed to convert the subject syntax type"))? + .to_string(); + let subject_identifier = subject.identifier(&subject_syntax_type_string)?; let vp_token = VpToken::builder() .iss(subject_identifier.clone()) @@ -61,7 +65,12 @@ impl Extension for OID4VP { .verifiable_presentation(user_input.verifiable_presentation.clone()) .build()?; - let jwt = jwt::encode(subject.clone(), Header::new(Algorithm::EdDSA), vp_token, did_method)?; + let jwt = jwt::encode( + subject.clone(), + Header::new(Algorithm::EdDSA), + vp_token, + &subject_syntax_type_string, + )?; Ok(vec![jwt]) } diff --git a/siopv2/src/provider.rs b/siopv2/src/provider.rs index 8dddec09..b9482d62 100644 --- a/siopv2/src/provider.rs +++ b/siopv2/src/provider.rs @@ -6,7 +6,7 @@ use oid4vc_core::{ authorization_request::{AuthorizationRequest, Body, ByReference, ByValue, Object}, authorization_response::AuthorizationResponse, openid4vc_extension::{Extension, ResponseHandle}, - Validator, + SubjectSyntaxType, Validator, }; use reqwest::StatusCode; use reqwest_middleware::{ClientBuilder, ClientWithMiddleware}; @@ -17,13 +17,13 @@ use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware}; /// the user who is trying to authenticate. pub struct Provider { pub subject: SigningSubject, - pub default_did_method: String, + pub default_subject_syntax_type: SubjectSyntaxType, client: ClientWithMiddleware, } impl Provider { // TODO: Use ProviderBuilder instead. - pub fn new(subject: SigningSubject, default_did_method: String) -> Result { + pub fn new(subject: SigningSubject, default_subject_syntax_type: impl TryInto) -> Result { let retry_policy = ExponentialBackoff::builder().build_with_max_retries(5); let client = ClientBuilder::new(reqwest::Client::new()) .with(RetryTransientMiddleware::new_with_policy(retry_policy)) @@ -31,7 +31,9 @@ impl Provider { Ok(Provider { subject, client, - default_did_method, + default_subject_syntax_type: default_subject_syntax_type + .try_into() + .map_err(|_| anyhow::anyhow!("Invalid did method."))?, }) } @@ -93,7 +95,7 @@ impl Provider { &authorization_request.body.client_id, &authorization_request.body.extension, &input, - &self.default_did_method, + self.default_subject_syntax_type.clone(), )?; E::build_authorization_response(jwts, input, redirect_uri, state) @@ -125,7 +127,7 @@ mod tests { let subject = TestSubject::new("did:test:123".to_string(), "key_id".to_string()).unwrap(); // Create a new provider. - let provider = Provider::new(Arc::new(subject), "did:test".to_string()).unwrap(); + let provider = Provider::new(Arc::new(subject), "did:test").unwrap(); // Get a new SIOP authorization_request with response mode `direct_post` for cross-device communication. let request_url = "\ diff --git a/siopv2/src/relying_party.rs b/siopv2/src/relying_party.rs index 12de5aa2..a965d6d9 100644 --- a/siopv2/src/relying_party.rs +++ b/siopv2/src/relying_party.rs @@ -15,16 +15,16 @@ pub struct RelyingParty { // TODO: Strictly speaking a relying party doesn't need to have a [`Subject`]. It just needs methods to // sign and verify tokens. For simplicity we use a [`Subject`] here for now but we should consider a cleaner solution. pub subject: SigningSubject, - pub default_did_method: String, + pub default_subject_syntax_type: String, pub sessions: HashMap<(String, String), AuthorizationRequest>>, } impl RelyingParty { // TODO: Use RelyingPartyBuilder instead. - pub fn new(subject: SigningSubject, default_did_method: String) -> Result { + pub fn new(subject: SigningSubject, default_subject_syntax_type: String) -> Result { Ok(RelyingParty { subject, - default_did_method, + default_subject_syntax_type, sessions: HashMap::new(), }) } @@ -34,7 +34,7 @@ impl RelyingParty { self.subject.clone(), Header::new(Algorithm::EdDSA), authorization_request, - &self.default_did_method, + &self.default_subject_syntax_type, ) } diff --git a/siopv2/src/siopv2.rs b/siopv2/src/siopv2.rs index 7b58ab02..fe875035 100644 --- a/siopv2/src/siopv2.rs +++ b/siopv2/src/siopv2.rs @@ -4,8 +4,8 @@ use crate::token::id_token::IdToken; use chrono::{Duration, Utc}; use jsonwebtoken::{Algorithm, Header}; use oid4vc_core::openid4vc_extension::{OpenID4VC, RequestHandle, ResponseHandle}; -use oid4vc_core::Validator; use oid4vc_core::{authorization_response::AuthorizationResponse, jwt, openid4vc_extension::Extension, Subject}; +use oid4vc_core::{SubjectSyntaxType, Validator}; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -39,9 +39,13 @@ impl Extension for SIOPv2 { client_id: &str, extension_parameters: &::Parameters, user_input: &::Input, - did_method: &str, + subject_syntax_type: impl TryInto, ) -> anyhow::Result> { - let subject_identifier = subject.identifier(did_method)?; + let subject_syntax_type_string = subject_syntax_type + .try_into() + .map_err(|_| anyhow::anyhow!("Failed to convert the subject syntax type"))? + .to_string(); + let subject_identifier = subject.identifier(&subject_syntax_type_string)?; let id_token = IdToken::builder() .iss(subject_identifier.clone()) @@ -54,7 +58,12 @@ impl Extension for SIOPv2 { .claims(user_input.clone()) .build()?; - let jwt = jwt::encode(subject.clone(), Header::new(Algorithm::EdDSA), id_token, did_method)?; + let jwt = jwt::encode( + subject.clone(), + Header::new(Algorithm::EdDSA), + id_token, + &subject_syntax_type_string, + )?; Ok(vec![jwt]) } diff --git a/siopv2/src/test_utils.rs b/siopv2/src/test_utils.rs index 40fad0a6..08a863a0 100644 --- a/siopv2/src/test_utils.rs +++ b/siopv2/src/test_utils.rs @@ -53,7 +53,7 @@ impl Verify for TestSubject { } impl Subject for TestSubject { - fn identifier(&self, _did_method: &str) -> Result { + fn identifier(&self, _subject_syntax_type: &str) -> Result { Ok(self.did.to_string()) } }