identity_kit/methods/
jwk.rs1use crate::did::{
12 Context, DEFAULT_MAX_LEN, Did, DidDocument, DidError, DocumentError, MethodType,
13 ResolutionError, ResolutionOptions, ResolutionResult, VerificationMaterial, VerificationMethod,
14 VerificationRelationship,
15};
16use crate::jose::Jwk;
17use crate::resolver::{DidProducer, DidResolver, Hosting, MethodCapabilities, ProduceError};
18
19use super::check_accept;
20
21#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
44pub struct DidJwk;
45
46impl DidJwk {
47 pub const METHOD: &'static str = "jwk";
49
50 pub const FRAGMENT: &'static str = "0";
52
53 pub const MAX_DID_LEN: usize = DEFAULT_MAX_LEN - 1 - Self::FRAGMENT.len();
56
57 pub const CONTEXT: [&'static str; 2] = [
59 Context::DID_V1,
60 "https://w3id.org/security/suites/jws-2020/v1",
61 ];
62
63 pub fn did(jwk: &Jwk) -> Result<Did, DidError> {
72 let json = serde_json::to_vec(&jwk.public()).expect("a JWK serializes");
73 let id = crate::jose::base64url::encode(&json);
74 Did::parse_with_max_len(&format!("did:jwk:{id}"), Self::MAX_DID_LEN)
75 }
76
77 pub fn document(did: &Did) -> Result<DidDocument, ResolutionError> {
86 if did.method() != Self::METHOD {
87 return Err(ResolutionError::MethodNotSupported);
88 }
89 if did.as_str().len() > Self::MAX_DID_LEN {
90 return Err(ResolutionError::InvalidDid);
91 }
92 let json = crate::jose::base64url::decode(did.method_specific_id())
93 .map_err(|_| ResolutionError::InvalidDid)?;
94 let jwk: Jwk = serde_json::from_slice(&json).map_err(|_| ResolutionError::InvalidDid)?;
95 if jwk.is_private() {
96 return Err(ResolutionError::InvalidDid);
97 }
98 build(did, jwk).map_err(|_| ResolutionError::InvalidDid)
99 }
100}
101
102fn build(did: &Did, jwk: Jwk) -> Result<DidDocument, DocumentError> {
104 let relationships: &[VerificationRelationship] = match jwk.key_use() {
105 Some("sig") => &[
106 VerificationRelationship::Authentication,
107 VerificationRelationship::AssertionMethod,
108 VerificationRelationship::CapabilityInvocation,
109 VerificationRelationship::CapabilityDelegation,
110 ],
111 Some("enc") => &[VerificationRelationship::KeyAgreement],
112 _ => VerificationRelationship::ALL,
113 };
114 let method = VerificationMethod::new(
115 did.to_url().with_fragment(DidJwk::FRAGMENT),
116 MethodType::JSON_WEB_KEY_2020,
117 did.clone(),
118 VerificationMaterial::PublicKeyJwk(Box::new(jwk)),
119 );
120 DidDocument::builder(did.clone())
121 .context(Context::uris(DidJwk::CONTEXT))
122 .verification_method(method, relationships.iter().copied())
123 .build()
124}
125
126#[async_trait::async_trait]
127impl DidResolver for DidJwk {
128 fn method(&self) -> &'static str {
129 Self::METHOD
130 }
131
132 async fn resolve(
135 &self,
136 did: &Did,
137 options: &ResolutionOptions,
138 ) -> Result<ResolutionResult, ResolutionError> {
139 check_accept(options)?;
140 Self::document(did).map(ResolutionResult::new)
141 }
142}
143
144#[async_trait::async_trait]
145impl DidProducer for DidJwk {
146 type Params = ();
147
148 fn method(&self) -> &'static str {
149 Self::METHOD
150 }
151
152 fn capabilities(&self) -> MethodCapabilities {
154 MethodCapabilities::new(Hosting::Embedded)
155 .with_single_key(true)
156 .with_fixed_fragment(Self::FRAGMENT)
157 }
158
159 async fn produce(&self, keys: &[Jwk], _: ()) -> Result<DidDocument, ProduceError> {
161 let jwk = super::single_key(keys)?;
162 let did = Self::did(jwk).map_err(|error| ProduceError::UnsupportedKey {
163 index: 0,
164 reason: error.to_string(),
165 })?;
166 Ok(build(&did, jwk.public())?)
167 }
168}