identity_storage/storage/
storage_signer.rs1use anyhow::anyhow;
5use async_trait::async_trait;
6use fastcrypto::hash::Blake2b256;
7use fastcrypto::traits::ToFromBytes;
8
9use identity_did::CoreDID;
10use identity_document::document::CoreDocument;
11use identity_verification::jwk::FromJwk as _;
12use identity_verification::jwk::Jwk;
13use identity_verification::MethodData;
14
15use iota_interaction::types::crypto::PublicKey;
16use iota_interaction::types::crypto::Signature;
17use iota_sdk_types::crypto::Intent;
18
19use iota_interaction::types::transaction::TransactionData;
20use iota_interaction::IotaKeySignature;
21use iota_interaction::OptionalSync;
22use secret_storage::Error as SecretStorageError;
23use secret_storage::Signer;
24
25use crate::JwkStorage;
26use crate::KeyId;
27use crate::KeyIdStorage;
28use crate::KeyIdStorageErrorKind;
29use crate::KeyStorageErrorKind;
30use crate::MethodDigest;
31use crate::MethodDigestConstructionError;
32use crate::Storage;
33
34pub struct StorageSigner<'a, K, I> {
37 key_id: KeyId,
38 public_key: Jwk,
39 storage: &'a Storage<K, I>,
40}
41
42impl<K, I> Clone for StorageSigner<'_, K, I> {
43 fn clone(&self) -> Self {
44 StorageSigner {
45 key_id: self.key_id.clone(),
46 public_key: self.public_key.clone(),
47 storage: self.storage,
48 }
49 }
50}
51
52impl<'a, K, I> StorageSigner<'a, K, I> {
53 pub fn new(storage: &'a Storage<K, I>, key_id: KeyId, public_key: Jwk) -> Self {
55 Self {
56 key_id,
57 public_key,
58 storage,
59 }
60 }
61
62 pub fn key_id(&self) -> &KeyId {
64 &self.key_id
65 }
66
67 pub fn public_key_jwk(&self) -> &Jwk {
69 &self.public_key
70 }
71
72 pub fn storage(&self) -> &Storage<K, I> {
74 self.storage
75 }
76}
77
78#[derive(Debug, thiserror::Error)]
80#[error("failed to create signer for '{did}#{fragment}'")]
81#[non_exhaustive]
82pub struct StorageSignerFromVmError {
83 pub did: CoreDID,
85 pub fragment: Box<str>,
87 pub kind: StorageSignerFromVmErrorKind,
89}
90
91#[derive(Debug, thiserror::Error)]
93#[non_exhaustive]
94pub enum StorageSignerFromVmErrorKind {
95 #[error("verification method not found")]
97 VmNotFound,
98 #[error("corresponding private key not found in storage")]
100 KeyNotFound,
101 #[error(transparent)]
103 StorageError(#[from] Box<dyn std::error::Error + Send + Sync>),
104 #[error(transparent)]
106 MethodDigestConstruction(#[from] MethodDigestConstructionError),
107 #[error("unsupported verification method type '{0}'")]
109 UnsupportedVmType(Box<str>),
110}
111
112impl<'a, K, I> StorageSigner<'a, K, I>
113where
114 K: JwkStorage + OptionalSync,
115 I: KeyIdStorage + OptionalSync,
116{
117 pub async fn new_from_vm_fragment<D>(
121 storage: &'a Storage<K, I>,
122 document: &D,
123 fragment: &str,
124 ) -> Result<Self, StorageSignerFromVmError>
125 where
126 D: AsRef<CoreDocument>,
127 {
128 use StorageSignerFromVmError as Error;
129 use StorageSignerFromVmErrorKind as ErrorKind;
130
131 let document = document.as_ref();
132 let make_err = |kind| Error {
133 did: document.id().clone(),
134 fragment: fragment.into(),
135 kind,
136 };
137
138 let vm = document
140 .resolve_method(fragment, None)
141 .ok_or_else(|| make_err(ErrorKind::VmNotFound))?;
142 let MethodData::PublicKeyJwk(jwk) = vm.data() else {
144 return Err(make_err(ErrorKind::UnsupportedVmType(vm.type_().as_str().into())));
145 };
146
147 let method_digest = MethodDigest::new(vm).map_err(|e| make_err(e.into()))?;
149 let key_id = storage
150 .key_id_storage
151 .get_key_id(&method_digest)
152 .await
153 .map_err(|e| match e.kind() {
154 KeyIdStorageErrorKind::KeyIdNotFound => make_err(ErrorKind::KeyNotFound),
155 _ => make_err(ErrorKind::StorageError(e.into())),
156 })?;
157
158 Ok(Self::new(storage, key_id, jwk.clone()))
159 }
160}
161
162#[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))]
163#[cfg_attr(feature = "send-sync-storage", async_trait)]
164impl<K, I> Signer<IotaKeySignature> for StorageSigner<'_, K, I>
165where
166 K: JwkStorage + OptionalSync,
167 I: KeyIdStorage + OptionalSync,
168{
169 type KeyId = KeyId;
170
171 fn key_id(&self) -> KeyId {
172 self.key_id.clone()
173 }
174
175 async fn public_key(&self) -> Result<PublicKey, SecretStorageError> {
176 PublicKey::from_jwk(&self.public_key)
177 .map_err(|e| SecretStorageError::Other(anyhow!("failed to convert public key: {e}")))
178 }
179 async fn sign(&self, data: &TransactionData) -> Result<Signature, SecretStorageError> {
180 use fastcrypto::hash::HashFunction;
181
182 let tx_data_bcs =
183 bcs::to_bytes(data).map_err(|e| SecretStorageError::Other(anyhow!("bcs deserialization failed: {e}")))?;
184 let intent_bytes = Intent::iota_transaction().to_bytes();
185 let mut hasher = Blake2b256::default();
186 hasher.update(intent_bytes);
187 hasher.update(&tx_data_bcs);
188 let digest = hasher.finalize().digest;
189
190 let signature_bytes = self
191 .storage
192 .key_storage()
193 .sign(&self.key_id, &digest, &self.public_key)
194 .await
195 .map_err(|e| match e.kind() {
196 KeyStorageErrorKind::KeyNotFound => SecretStorageError::KeyNotFound(e.to_string()),
197 KeyStorageErrorKind::RetryableIOFailure => SecretStorageError::StoreDisconnected(e.to_string()),
198 _ => SecretStorageError::Other(anyhow::anyhow!(e)),
199 })?;
200
201 let public_key = Signer::public_key(self).await?;
202
203 let iota_signature_bytes = [[public_key.flag()].as_slice(), &signature_bytes, public_key.as_ref()].concat();
204
205 Signature::from_bytes(&iota_signature_bytes)
206 .map_err(|e| SecretStorageError::Other(anyhow!("failed to create valid IOTA signature: {e}")))
207 }
208}
209
210#[cfg(feature = "sd-jwt-signer")]
211mod sd_jwt_signer_integration {
212 use crate::KeyStorageError;
213
214 use super::*;
215 use identity_verification::jwu::encode_b64;
216 use identity_verification::jwu::encode_b64_json;
217 use sd_jwt::JsonObject;
218 use sd_jwt::JwsSigner;
219
220 #[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))]
221 #[cfg_attr(feature = "send-sync-storage", async_trait)]
222 impl<K, I> JwsSigner for StorageSigner<'_, K, I>
223 where
224 K: JwkStorage + OptionalSync,
225 I: OptionalSync,
226 {
227 type Error = KeyStorageError;
228 async fn sign(&self, header: &JsonObject, payload: &JsonObject) -> Result<Vec<u8>, Self::Error> {
229 let header_json = encode_b64_json(header)
230 .map_err(|e| KeyStorageError::new(KeyStorageErrorKind::SerializationError).with_source(e))?;
231 let payload_json = encode_b64_json(payload)
232 .map_err(|e| KeyStorageError::new(KeyStorageErrorKind::SerializationError).with_source(e))?;
233
234 let mut signing_input = format!("{header_json}.{payload_json}");
235
236 let signature_bytes = self
237 .storage
238 .key_storage()
239 .sign(&self.key_id, signing_input.as_bytes(), &self.public_key)
240 .await?;
241
242 signing_input.push('.');
243 signing_input.push_str(&encode_b64(signature_bytes));
244
245 Ok(signing_input.into_bytes())
246 }
247 }
248}