1use sqlx::encode::IsNull;
2use sqlx::error::BoxDynError;
3use sqlx::*;
4use sqlx_core::any::AnyArgumentBuffer;
5use std::sync::Arc;
6use tracing::debug;
7use zeroize::{Zeroize, ZeroizeOnDrop};
8
9use crate::storage::secrets_repository::SecretsRepository;
10use ockam_core::async_trait;
11use ockam_core::compat::vec::Vec;
12use ockam_core::errcode::{Kind, Origin};
13use ockam_core::Result;
14use ockam_node::database::AutoRetry;
15use ockam_node::database::{FromSqlxError, SqlxDatabase, ToVoid};
16
17use crate::{
18 AeadSecret, AeadSecretKeyHandle, ECDSASHA256CurveP256SecretKey, EdDSACurve25519SecretKey,
19 HandleToSecret, SigningSecret, SigningSecretKeyHandle, X25519SecretKey, X25519SecretKeyHandle,
20 AEAD_TYPE,
21};
22
23#[derive(Clone)]
25pub struct SecretsSqlxDatabase {
26 database: SqlxDatabase,
27}
28
29impl SecretsSqlxDatabase {
30 pub fn new(database: SqlxDatabase) -> Self {
32 debug!("create a repository for secrets");
33 Self { database }
34 }
35
36 pub fn make_repository(database: SqlxDatabase) -> Arc<dyn SecretsRepository> {
38 if database.needs_retry() {
39 Arc::new(AutoRetry::new(Self::new(database)))
40 } else {
41 Arc::new(Self::new(database))
42 }
43 }
44
45 pub async fn create() -> Result<Self> {
47 Ok(Self::new(SqlxDatabase::in_memory("secrets").await?))
48 }
49}
50
51const ED_DSA_CURVE_25519: &str = "EdDSACurve25519";
52const EC_DSA_SHA256_CURVE_P256: &str = "ECDSASHA256CurveP256";
53
54#[async_trait]
55impl SecretsRepository for SecretsSqlxDatabase {
56 async fn store_signing_secret(
57 &self,
58 handle: &SigningSecretKeyHandle,
59 secret: SigningSecret,
60 ) -> Result<()> {
61 let secret_type: String = match handle {
62 SigningSecretKeyHandle::EdDSACurve25519(_) => ED_DSA_CURVE_25519.into(),
63 SigningSecretKeyHandle::ECDSASHA256CurveP256(_) => EC_DSA_SHA256_CURVE_P256.into(),
64 };
65
66 let query = query(
67 r#"
68 INSERT INTO signing_secret (handle, secret_type, secret)
69 VALUES ($1, $2, $3)
70 ON CONFLICT (handle)
71 DO UPDATE SET secret_type = $2, secret = $3"#,
72 )
73 .bind(handle)
74 .bind(secret_type)
75 .bind(secret);
76 query.execute(&*self.database.pool).await.void()
77 }
78
79 async fn delete_signing_secret(&self, handle: &SigningSecretKeyHandle) -> Result<bool> {
80 let query = query("DELETE FROM signing_secret WHERE handle = $1").bind(handle);
81 let res = query.execute(&*self.database.pool).await.into_core()?;
82
83 Ok(res.rows_affected() != 0)
84 }
85
86 async fn get_signing_secret(
87 &self,
88 handle: &SigningSecretKeyHandle,
89 ) -> Result<Option<SigningSecret>> {
90 let query =
91 query_as("SELECT handle, secret_type, secret FROM signing_secret WHERE handle = $1")
92 .bind(handle);
93 let row: Option<SigningSecretRow> = query
94 .fetch_optional(&*self.database.pool)
95 .await
96 .into_core()?;
97 Ok(row.map(|r| r.signing_secret()).transpose()?)
98 }
99
100 async fn get_signing_secret_handles(&self) -> Result<Vec<SigningSecretKeyHandle>> {
101 let query = query_as("SELECT handle, secret_type, secret FROM signing_secret");
102 let rows: Vec<SigningSecretRow> =
103 query.fetch_all(&*self.database.pool).await.into_core()?;
104 Ok(rows
105 .iter()
106 .map(|r| r.handle())
107 .collect::<Result<Vec<_>>>()?)
108 }
109
110 async fn store_x25519_secret(
111 &self,
112 handle: &X25519SecretKeyHandle,
113 secret: X25519SecretKey,
114 ) -> Result<()> {
115 let query = query(
116 r#"
117 INSERT INTO x25519_secret (handle, secret)
118 VALUES ($1, $2)
119 ON CONFLICT (handle)
120 DO UPDATE SET secret = $2"#,
121 )
122 .bind(handle)
123 .bind(secret);
124 query.execute(&*self.database.pool).await.void()
125 }
126
127 async fn delete_x25519_secret(&self, handle: &X25519SecretKeyHandle) -> Result<bool> {
128 let query = query("DELETE FROM x25519_secret WHERE handle = $1").bind(handle);
129 let res = query.execute(&*self.database.pool).await.into_core()?;
130
131 Ok(res.rows_affected() != 0)
132 }
133
134 async fn get_x25519_secret(
135 &self,
136 handle: &X25519SecretKeyHandle,
137 ) -> Result<Option<X25519SecretKey>> {
138 let query =
139 query_as("SELECT handle, secret FROM x25519_secret WHERE handle = $1").bind(handle);
140 let row: Option<X25519SecretRow> = query
141 .fetch_optional(&*self.database.pool)
142 .await
143 .into_core()?;
144 Ok(row.map(|r| r.x25519_secret()).transpose()?)
145 }
146
147 async fn get_x25519_secret_handles(&self) -> Result<Vec<X25519SecretKeyHandle>> {
148 let query = query_as("SELECT handle, secret FROM x25519_secret");
149 let rows: Vec<X25519SecretRow> = query.fetch_all(&*self.database.pool).await.into_core()?;
150 Ok(rows
151 .iter()
152 .map(|r| r.handle())
153 .collect::<Result<Vec<_>>>()?)
154 }
155
156 async fn store_aead_secret(
157 &self,
158 handle: &AeadSecretKeyHandle,
159 secret: AeadSecret,
160 ) -> Result<()> {
161 let query = query(
162 r#"
163 INSERT INTO aead_secret (handle, type, secret)
164 VALUES ($1, $2, $3)
165 ON CONFLICT (handle)
166 DO UPDATE SET type = $2, secret = $3"#,
167 )
168 .bind(handle)
169 .bind(AEAD_TYPE)
170 .bind(secret);
171 query.execute(&*self.database.pool).await.void()
172 }
173
174 async fn delete_aead_secret(&self, handle: &AeadSecretKeyHandle) -> Result<bool> {
175 let query = query("DELETE FROM aead_secret WHERE handle = $1").bind(handle);
176 let res = query.execute(&*self.database.pool).await.into_core()?;
177
178 Ok(res.rows_affected() != 0)
179 }
180
181 async fn get_aead_secret(&self, handle: &AeadSecretKeyHandle) -> Result<Option<AeadSecret>> {
182 let query = query_as("SELECT secret FROM aead_secret WHERE handle = $1 AND type = $2")
183 .bind(handle)
184 .bind(AEAD_TYPE);
185 let row: Option<AeadSecretRow> = query
186 .fetch_optional(&*self.database.pool)
187 .await
188 .into_core()?;
189 Ok(row.map(|r| r.aead_secret()).transpose()?)
190 }
191
192 async fn delete_all(&self) -> Result<()> {
193 let mut transaction = self.database.begin().await.into_core()?;
194 let query1 = query("DELETE FROM signing_secret");
195 query1.execute(&mut *transaction).await.void()?;
196
197 let query2 = query("DELETE FROM x25519_secret");
198 query2.execute(&mut *transaction).await.void()?;
199
200 let query3 = query("DELETE FROM aead_secret");
201 query3.execute(&mut *transaction).await.void()?;
202
203 transaction.commit().await.void()
204 }
205}
206
207impl Type<Any> for SigningSecret {
208 fn type_info() -> <Any as Database>::TypeInfo {
209 <Vec<u8> as Type<Any>>::type_info()
210 }
211}
212
213impl Encode<'_, Any> for SigningSecret {
214 fn encode_by_ref(&self, buf: &mut AnyArgumentBuffer) -> Result<IsNull, BoxDynError> {
215 <Vec<u8> as Encode<'_, Any>>::encode_by_ref(&self.key().to_vec(), buf)
216 }
217}
218
219impl Type<Any> for SigningSecretKeyHandle {
220 fn type_info() -> <Any as Database>::TypeInfo {
221 <HandleToSecret as Type<Any>>::type_info()
222 }
223}
224
225impl Encode<'_, Any> for SigningSecretKeyHandle {
226 fn encode_by_ref(&self, buf: &mut AnyArgumentBuffer) -> Result<IsNull, BoxDynError> {
227 <HandleToSecret as Encode<'_, Any>>::encode_by_ref(self.handle(), buf)
228 }
229}
230
231impl Type<Any> for HandleToSecret {
232 fn type_info() -> <Any as Database>::TypeInfo {
233 <Vec<u8> as Type<Any>>::type_info()
234 }
235}
236
237impl Encode<'_, Any> for HandleToSecret {
238 fn encode_by_ref(&self, buf: &mut AnyArgumentBuffer) -> Result<IsNull, BoxDynError> {
239 <Vec<u8> as Encode<'_, Any>>::encode_by_ref(self.value(), buf)
240 }
241}
242
243impl Type<Any> for X25519SecretKeyHandle {
244 fn type_info() -> <Any as Database>::TypeInfo {
245 <HandleToSecret as Type<Any>>::type_info()
246 }
247}
248
249impl Encode<'_, Any> for X25519SecretKeyHandle {
250 fn encode_by_ref(&self, buf: &mut AnyArgumentBuffer) -> Result<IsNull, BoxDynError> {
251 <HandleToSecret as Encode<'_, Any>>::encode_by_ref(&self.0, buf)
252 }
253}
254
255impl Type<Any> for AeadSecretKeyHandle {
256 fn type_info() -> <Any as Database>::TypeInfo {
257 <HandleToSecret as Type<Any>>::type_info()
258 }
259}
260
261impl Encode<'_, Any> for AeadSecretKeyHandle {
262 fn encode_by_ref(&self, buf: &mut AnyArgumentBuffer) -> Result<IsNull, BoxDynError> {
263 <HandleToSecret as Encode<'_, Any>>::encode_by_ref(&self.0 .0, buf)
264 }
265}
266
267impl Type<Any> for X25519SecretKey {
268 fn type_info() -> <Any as Database>::TypeInfo {
269 <Vec<u8> as Type<Any>>::type_info()
270 }
271}
272
273impl Encode<'_, Any> for X25519SecretKey {
274 fn encode_by_ref(&self, buf: &mut AnyArgumentBuffer) -> Result<IsNull, BoxDynError> {
275 <Vec<u8> as Encode<'_, Any>>::encode_by_ref(&self.key().to_vec(), buf)
276 }
277}
278
279impl Type<Any> for AeadSecret {
280 fn type_info() -> <Any as Database>::TypeInfo {
281 <Vec<u8> as Type<Any>>::type_info()
282 }
283}
284
285impl Encode<'_, Any> for AeadSecret {
286 fn encode_by_ref(&self, buf: &mut AnyArgumentBuffer) -> Result<IsNull, BoxDynError> {
287 <Vec<u8> as Encode<'_, Any>>::encode_by_ref(&self.0.to_vec(), buf)
288 }
289}
290
291#[derive(FromRow, Zeroize, ZeroizeOnDrop)]
292struct SigningSecretRow {
293 handle: Vec<u8>,
294 secret_type: String,
295 secret: Vec<u8>,
296}
297
298impl SigningSecretRow {
299 fn signing_secret(&self) -> Result<SigningSecret> {
300 let secret = self.secret.clone().try_into().map_err(|_| {
301 ockam_core::Error::new(
302 Origin::Api,
303 Kind::Serialization,
304 "cannot convert a signing secret to [u8; 32]",
305 )
306 })?;
307 match self.secret_type.as_str() {
308 "EdDSACurve25519" => Ok(SigningSecret::EdDSACurve25519(
309 EdDSACurve25519SecretKey::new(secret),
310 )),
311 "ECDSASHA256CurveP256" => Ok(SigningSecret::ECDSASHA256CurveP256(
312 ECDSASHA256CurveP256SecretKey::new(secret),
313 )),
314 _ => Err(ockam_core::Error::new(
315 Origin::Api,
316 Kind::Serialization,
317 "cannot deserialize a signing secret",
318 )),
319 }
320 }
321
322 fn handle(&self) -> Result<SigningSecretKeyHandle> {
323 match self.secret_type.as_str() {
324 "EdDSACurve25519" => Ok(SigningSecretKeyHandle::EdDSACurve25519(
325 HandleToSecret::new(self.handle.clone()),
326 )),
327 "ECDSASHA256CurveP256" => Ok(SigningSecretKeyHandle::ECDSASHA256CurveP256(
328 HandleToSecret::new(self.handle.clone()),
329 )),
330 _ => Err(ockam_core::Error::new(
331 Origin::Api,
332 Kind::Serialization,
333 "cannot deserialize a signing secret handle",
334 )),
335 }
336 }
337}
338
339#[derive(FromRow, Zeroize, ZeroizeOnDrop)]
340struct X25519SecretRow {
341 handle: Vec<u8>,
342 secret: Vec<u8>,
343}
344
345impl X25519SecretRow {
346 fn x25519_secret(&self) -> Result<X25519SecretKey> {
347 let secret = self.secret.as_slice().try_into().map_err(|_| {
348 ockam_core::Error::new(
349 Origin::Api,
350 Kind::Serialization,
351 "cannot convert a X25519 secret to [u8; 32]",
352 )
353 })?;
354 Ok(X25519SecretKey::new(secret))
355 }
356
357 fn handle(&self) -> Result<X25519SecretKeyHandle> {
358 Ok(X25519SecretKeyHandle(HandleToSecret::new(
359 self.handle.clone(),
360 )))
361 }
362}
363
364#[derive(FromRow, Zeroize, ZeroizeOnDrop)]
365struct AeadSecretRow {
366 secret: Vec<u8>,
367}
368
369impl AeadSecretRow {
370 fn aead_secret(&self) -> Result<AeadSecret> {
371 let secret = self.secret.as_slice().try_into().map_err(|_| {
372 ockam_core::Error::new(
373 Origin::Api,
374 Kind::Serialization,
375 "cannot convert an AEAD secret to array",
376 )
377 })?;
378
379 Ok(AeadSecret(secret))
380 }
381}
382
383#[cfg(test)]
384mod test {
385 use super::*;
386
387 use ockam_core::compat::sync::Arc;
388
389 #[tokio::test]
390 async fn test_signing_secrets_repository() -> Result<()> {
391 let repository = create_repository().await?;
392
393 let handle1 =
394 SigningSecretKeyHandle::ECDSASHA256CurveP256(HandleToSecret::new(vec![1, 2, 3]));
395 let secret1 =
396 SigningSecret::ECDSASHA256CurveP256(ECDSASHA256CurveP256SecretKey::new([1; 32]));
397
398 let handle2 = SigningSecretKeyHandle::EdDSACurve25519(HandleToSecret::new(vec![4, 5, 6]));
399 let secret2 = SigningSecret::EdDSACurve25519(EdDSACurve25519SecretKey::new([1; 32]));
400
401 repository
402 .store_signing_secret(&handle1, secret1.clone())
403 .await?;
404 repository
405 .store_signing_secret(&handle2, secret2.clone())
406 .await?;
407
408 let result = repository.get_signing_secret(&handle1).await?;
409 assert!(result == Some(secret1));
410
411 let result = repository.get_signing_secret_handles().await?;
412 assert_eq!(result, vec![handle1.clone(), handle2]);
413
414 repository.delete_signing_secret(&handle1).await?;
415
416 let result = repository.get_signing_secret(&handle1).await?;
417 assert!(result.is_none());
418
419 Ok(())
420 }
421
422 #[tokio::test]
423 async fn test_x25519_secrets_repository() -> Result<()> {
424 let repository = create_repository().await?;
425
426 let handle1 = X25519SecretKeyHandle(HandleToSecret::new(vec![1, 2, 3]));
427 let secret1 = X25519SecretKey::new([1; 32]);
428
429 let handle2 = X25519SecretKeyHandle(HandleToSecret::new(vec![4, 5, 6]));
430 let secret2 = X25519SecretKey::new([1; 32]);
431
432 repository
433 .store_x25519_secret(&handle1, secret1.clone())
434 .await?;
435 repository
436 .store_x25519_secret(&handle2, secret2.clone())
437 .await?;
438
439 let result = repository.get_x25519_secret(&handle1).await?;
440 assert!(result == Some(secret1));
441
442 let result = repository.get_x25519_secret_handles().await?;
443 assert_eq!(result, vec![handle1.clone(), handle2]);
444
445 repository.delete_x25519_secret(&handle1).await?;
446
447 let result = repository.get_x25519_secret(&handle1).await?;
448 assert!(result.is_none());
449
450 Ok(())
451 }
452
453 #[tokio::test]
454 async fn test_aead_secrets_repository() -> Result<()> {
455 let repository = create_repository().await?;
456
457 let handle1 = AeadSecretKeyHandle::new(HandleToSecret::new(vec![1, 2, 3]));
458 let secret1 = AeadSecret([1; 32]);
459
460 let handle2 = AeadSecretKeyHandle::new(HandleToSecret::new(vec![4, 5, 6]));
461 let secret2 = AeadSecret([2; 32]);
462
463 repository
464 .store_aead_secret(&handle1, secret1.clone())
465 .await?;
466 repository
467 .store_aead_secret(&handle2, secret2.clone())
468 .await?;
469
470 let result = repository.get_aead_secret(&handle1).await?;
471 assert!(result == Some(secret1));
472
473 let result = repository.get_aead_secret(&handle2).await?;
474 assert!(result == Some(secret2));
475
476 repository.delete_aead_secret(&handle1).await?;
477
478 let result = repository.get_aead_secret(&handle1).await?;
479 assert!(result.is_none());
480
481 Ok(())
482 }
483
484 async fn create_repository() -> Result<Arc<dyn SecretsRepository>> {
486 Ok(Arc::new(SecretsSqlxDatabase::create().await?))
487 }
488}