identity_verification/verification_method/
method.rs

1// Copyright 2020-2023 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use core::fmt::Display;
5use core::fmt::Formatter;
6use std::borrow::Cow;
7
8use identity_did::DIDJwk;
9use identity_jose::jwk::Jwk;
10use serde::de;
11use serde::Deserialize;
12use serde::Serialize;
13
14use identity_core::common::KeyComparable;
15use identity_core::common::Object;
16use identity_core::convert::FmtJson;
17
18use crate::error::Error;
19use crate::error::Result;
20use crate::verification_method::MethodBuilder;
21use crate::verification_method::MethodData;
22use crate::verification_method::MethodRef;
23use crate::verification_method::MethodType;
24use crate::CustomMethodData;
25use identity_did::CoreDID;
26use identity_did::DIDUrl;
27use identity_did::DID;
28
29/// A DID Document Verification Method.
30///
31/// [Specification](https://www.w3.org/TR/did-core/#verification-method-properties)
32#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
33#[serde(from = "_VerificationMethod")]
34pub struct VerificationMethod {
35  pub(crate) id: DIDUrl,
36  pub(crate) controller: CoreDID,
37  #[serde(rename = "type")]
38  pub(crate) type_: MethodType,
39  #[serde(flatten)]
40  pub(crate) data: MethodData,
41  #[serde(flatten)]
42  pub(crate) properties: Object,
43}
44
45/// Deserializes an [`DIDUrl`] while enforcing that its fragment is non-empty.
46fn deserialize_id_with_fragment<'de, D>(deserializer: D) -> Result<DIDUrl, D::Error>
47where
48  D: de::Deserializer<'de>,
49{
50  let did_url: DIDUrl = DIDUrl::deserialize(deserializer)?;
51  if did_url.fragment().unwrap_or_default().is_empty() {
52    return Err(de::Error::custom("method id missing fragment"));
53  }
54  Ok(did_url)
55}
56
57impl VerificationMethod {
58  // ===========================================================================
59  // Builder
60  // ===========================================================================
61
62  /// Creates a `MethodBuilder` to configure a new `Method`.
63  ///
64  /// This is the same as `MethodBuilder::new()`.
65  pub fn builder(properties: Object) -> MethodBuilder {
66    MethodBuilder::new(properties)
67  }
68
69  /// Returns a new `Method` based on the `MethodBuilder` configuration.
70  pub fn from_builder(builder: MethodBuilder) -> Result<Self> {
71    let id: DIDUrl = builder.id.ok_or(Error::InvalidMethod("missing id"))?;
72    if id.fragment().unwrap_or_default().is_empty() {
73      return Err(Error::InvalidMethod("empty id fragment"));
74    }
75
76    if let Some(MethodData::PublicKeyJwk(ref jwk)) = builder.data {
77      if !jwk.is_public() {
78        return Err(crate::error::Error::PrivateKeyMaterialExposed);
79      }
80    };
81
82    Ok(VerificationMethod {
83      id,
84      controller: builder.controller.ok_or(Error::InvalidMethod("missing controller"))?,
85      type_: builder.type_.ok_or(Error::InvalidMethod("missing type"))?,
86      data: builder.data.ok_or(Error::InvalidMethod("missing data"))?,
87      properties: builder.properties,
88    })
89  }
90
91  // ===========================================================================
92  // Properties
93  // ===========================================================================
94
95  /// Returns a reference to the `VerificationMethod` id.
96  pub fn id(&self) -> &DIDUrl {
97    &self.id
98  }
99
100  /// Sets the `VerificationMethod` id.
101  ///
102  /// # Errors
103  /// [`Error::MissingIdFragment`] if there is no fragment on the [`DIDUrl`].
104  pub fn set_id(&mut self, id: DIDUrl) -> Result<()> {
105    if id.fragment().unwrap_or_default().is_empty() {
106      return Err(Error::MissingIdFragment);
107    }
108    self.id = id;
109    Ok(())
110  }
111
112  /// Returns a reference to the `VerificationMethod` controller.
113  pub fn controller(&self) -> &CoreDID {
114    &self.controller
115  }
116
117  /// Returns a mutable reference to the `VerificationMethod` controller.
118  pub fn controller_mut(&mut self) -> &mut CoreDID {
119    &mut self.controller
120  }
121
122  /// Returns a reference to the `VerificationMethod` type.
123  pub fn type_(&self) -> &MethodType {
124    &self.type_
125  }
126
127  /// Returns a mutable reference to the `VerificationMethod` type.
128  pub fn type_mut(&mut self) -> &mut MethodType {
129    &mut self.type_
130  }
131
132  /// Returns a reference to the `VerificationMethod` data.
133  pub fn data(&self) -> &MethodData {
134    &self.data
135  }
136
137  /// Returns a mutable reference to the `VerificationMethod` data.
138  pub fn data_mut(&mut self) -> &mut MethodData {
139    &mut self.data
140  }
141
142  /// Returns a reference to the custom `VerificationMethod` properties.
143  pub fn properties(&self) -> &Object {
144    &self.properties
145  }
146
147  /// Returns a mutable reference to the custom `VerificationMethod` properties.
148  pub fn properties_mut(&mut self) -> &mut Object {
149    &mut self.properties
150  }
151
152  /// Creates a new [`MethodRef`] from `self`.
153  pub fn into_method_ref(self) -> MethodRef {
154    MethodRef::Embed(self)
155  }
156
157  /// Maps the [`VerificationMethod`] by applying a function `f` to
158  /// the [`CoreDID`] components of id and controller. Useful when working with DID methods where the identifier
159  /// is not known before publishing.
160  pub fn map<F>(self, mut f: F) -> VerificationMethod
161  where
162    F: FnMut(CoreDID) -> CoreDID,
163  {
164    VerificationMethod {
165      id: self.id.map(&mut f),
166      controller: f(self.controller),
167      type_: self.type_,
168      data: self.data,
169      properties: self.properties,
170    }
171  }
172
173  /// Fallible version of [`VerificationMethod::map`].
174  pub fn try_map<F, E>(self, mut f: F) -> Result<VerificationMethod, E>
175  where
176    F: FnMut(CoreDID) -> Result<CoreDID, E>,
177  {
178    Ok(VerificationMethod {
179      id: self.id.try_map(&mut f)?,
180      controller: f(self.controller)?,
181      type_: self.type_,
182      data: self.data,
183      properties: self.properties,
184    })
185  }
186}
187
188impl VerificationMethod {
189  // ===========================================================================
190  // Constructors
191  // ===========================================================================
192
193  /// Creates a new [`VerificationMethod`] from the given `did` and [`Jwk`]. If `fragment` is not given
194  /// the `kid` value of the given `key` will be used, if present, otherwise an error is returned.
195  ///
196  /// # Recommendations
197  /// The following recommendations are essentially taken from the `publicKeyJwk` description from
198  /// the [DID specification](https://www.w3.org/TR/did-core/#dfn-publickeyjwk):
199  /// - It is recommended that verification methods that use [`Jwks`](Jwk) to represent their public keys use the value
200  ///   of `kid` as their fragment identifier. This is done automatically if `None` is passed in as the fragment.
201  /// - It is recommended that [`Jwk`] kid values are set to the public key fingerprint. See
202  ///   [`Jwk::thumbprint_sha256_b64`](Jwk::thumbprint_sha256_b64).
203  pub fn new_from_jwk<D: DID>(did: D, key: Jwk, fragment: Option<&str>) -> Result<Self> {
204    // If a fragment is given use that, otherwise use the JWK's `kid` if it is set.
205    let fragment: Cow<'_, str> = {
206      let given_fragment: &str = fragment
207        .or_else(|| key.kid())
208        .ok_or(crate::error::Error::InvalidMethod(
209          "an explicit fragment or JWK kid is required",
210        ))?;
211      // Make sure the fragment starts with "#"
212      if given_fragment.starts_with('#') {
213        Cow::Borrowed(given_fragment)
214      } else {
215        Cow::Owned(format!("#{given_fragment}"))
216      }
217    };
218
219    let id: DIDUrl = did.to_url().join(fragment).map_err(Error::DIDUrlConstructionError)?;
220
221    MethodBuilder::default()
222      .id(id)
223      .controller(did.into())
224      .type_(MethodType::JSON_WEB_KEY_2020)
225      .data(MethodData::PublicKeyJwk(key))
226      .build()
227  }
228}
229
230impl Display for VerificationMethod {
231  fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
232    self.fmt_json(f)
233  }
234}
235
236impl AsRef<DIDUrl> for VerificationMethod {
237  fn as_ref(&self) -> &DIDUrl {
238    self.id()
239  }
240}
241
242impl KeyComparable for VerificationMethod {
243  type Key = DIDUrl;
244
245  #[inline]
246  fn key(&self) -> &Self::Key {
247    self.id()
248  }
249}
250
251impl TryFrom<DIDJwk> for VerificationMethod {
252  type Error = Error;
253  fn try_from(did: DIDJwk) -> Result<Self, Self::Error> {
254    let jwk = did.jwk();
255    Self::new_from_jwk(did, jwk, Some("0"))
256  }
257}
258
259// Horrible workaround for a tracked serde issue https://github.com/serde-rs/serde/issues/2200. Serde doesn't "consume"
260// the input when deserializing flattened enums (MethodData in this case) causing duplication of data (in this case
261// it ends up in the properties object). This workaround simply removes the duplication.
262#[derive(Deserialize)]
263struct _VerificationMethod {
264  #[serde(deserialize_with = "deserialize_id_with_fragment")]
265  pub(crate) id: DIDUrl,
266  pub(crate) controller: CoreDID,
267  #[serde(rename = "type")]
268  pub(crate) type_: MethodType,
269  #[serde(flatten)]
270  pub(crate) data: MethodData,
271  #[serde(flatten)]
272  pub(crate) properties: Object,
273}
274
275impl From<_VerificationMethod> for VerificationMethod {
276  fn from(value: _VerificationMethod) -> Self {
277    let _VerificationMethod {
278      id,
279      controller,
280      type_,
281      data,
282      mut properties,
283    } = value;
284    let key = match &data {
285      MethodData::PublicKeyBase58(_) => "publicKeyBase58",
286      MethodData::PublicKeyJwk(_) => "publicKeyJwk",
287      MethodData::PublicKeyMultibase(_) => "publicKeyMultibase",
288      MethodData::Custom(CustomMethodData { name, .. }) => name.as_str(),
289    };
290    properties.remove(key);
291
292    VerificationMethod {
293      id,
294      controller,
295      type_,
296      data,
297      properties,
298    }
299  }
300}