burrito_secrets/
signing.rs1use crate::database::Metadata;
7use anyhow::bail;
8use bson::spec::BinarySubtype;
9use bson::Bson;
10use dryoc::auth::protected::Key;
11use dryoc::protected::HeapByteArray;
12use dryoc::sign::protected::{PublicKey, SecretKey};
13use serde::Serialize;
14
15pub trait Signing: Metadata + Serialize {
16 fn sign_sym(self, secret_key: Key) -> Self
18 {
19 use dryoc::auth::Auth;
20 use dryoc::constants::CRYPTO_AUTH_BYTES;
21
22 let out = self.with_meta(("modified", bson::DateTime::now()));
23
24 let self_bytes = bson::to_vec(&out).expect("Failed to serialize entry");
27 let signature: [u8; CRYPTO_AUTH_BYTES] = Auth::compute(secret_key, &self_bytes);
28 let signature = bson::Binary {
29 subtype: BinarySubtype::Sensitive,
30 bytes: Vec::from(signature),
31 };
32
33 out
34 .with_meta(("signature_sym", signature))
35 }
36
37 fn verify_sym(self, secret_key: Key) -> anyhow::Result<Self>
38 {
39 use dryoc::auth::Auth;
40
41 let mut self_entries = bson::to_document(&self)?;
42 let Some(Bson::Binary(signature)) = self_entries.remove("signature_sym") else { bail!("Entry does not contain valid signature") };
43 let signature = signature.bytes;
44 let self_bytes = bson::to_vec(&self_entries).expect("Failed to serialize entry");
47 Auth::compute_and_verify(&signature.as_slice(), secret_key, &self_bytes)?;
48
49 Ok(self)
50 }
51
52 fn sign(self, key: SecretKey) -> Self {
53 use dryoc::sign::SigningKeyPair;
54 use dryoc::sign::protected::PublicKey;
55 use dryoc::sign::protected::SecretKey;
56
57 let keypair: SigningKeyPair<PublicKey, SecretKey> = SigningKeyPair::from_secret_key(key);
58 let public_key = bson::Binary {
59 subtype: BinarySubtype::Sensitive,
60 bytes: keypair.public_key.to_vec(),
61 };
62
63 let out = self
64 .with_meta(("modified", bson::DateTime::now()))
65 .with_meta(("signing_public_key", public_key));
66
67 let self_bytes = bson::to_vec(&out).expect("Failed to serialize entry");
68 let (signature, _data): (HeapByteArray<64>, _) = keypair.sign(self_bytes).expect("Failed to sign entry").into_parts();
69 let signature = bson::Binary {
70 subtype: BinarySubtype::Sensitive,
71 bytes: signature.to_vec(),
72 };
73
74
75 out
76 .with_meta(("signature", signature))
77 }
78
79 fn verify(self) -> anyhow::Result<Self> {
80 let self_entries = bson::to_document(&self)?;
81
82 let Some(Bson::Binary(public_key)) = self_entries.get_meta("signing_public_key") else { bail!("Entry does not contain valid signature") };
83 let public_key = &public_key.bytes;
84 let public_key = PublicKey::try_from(public_key.as_slice())?;
85
86 self.verify_with(public_key)
87 }
88
89 fn verify_with(self, public_key: PublicKey) -> anyhow::Result<Self> {
90 use dryoc::sign::SignedMessage;
91
92 let mut self_entries = bson::to_document(&self)?;
93
94 let Some(Bson::Binary(signature)) = self_entries.remove("signature") else { bail!("Entry does not contain valid signature") };
95 let signature = signature.bytes;
96
97
98 let self_signed = bson::to_vec(&self_entries)?;
99 let self_signed = SignedMessage::from_parts(signature, self_signed);
100
101 self_signed.verify(&public_key)?;
102
103 Ok(self)
104 }
105
106 const SECURITY_PADDING: &'static [u8] = b"This is some extra data to ensure that the signature is different, instead of being simply copy-pastable if the owner of the document did not also sign the document BEFORE adding a security attestation.";
107
108 fn with_security(self, key: SecretKey) -> Self {
109 use dryoc::sign::SigningKeyPair;
110 use dryoc::sign::protected::PublicKey;
111 use dryoc::sign::protected::SecretKey;
112
113 let keypair: SigningKeyPair<PublicKey, SecretKey> = SigningKeyPair::from_secret_key(key);
114 let public_key = bson::Binary {
115 subtype: BinarySubtype::Sensitive,
116 bytes: keypair.public_key.to_vec(),
117 };
118
119 let out = self
120 .with_meta(("modified", bson::DateTime::now()))
121 .with_meta(("security_signing_public_key", public_key));
122
123 let mut self_bytes = bson::to_vec(&out).expect("Failed to serialize entry");
124 self_bytes.extend_from_slice(Self::SECURITY_PADDING);
125 let (signature, _data): (HeapByteArray<64>, _) = keypair.sign(self_bytes).expect("Failed to sign entry").into_parts();
126 let signature = bson::Binary {
127 subtype: BinarySubtype::Sensitive,
128 bytes: signature.to_vec(),
129 };
130
131
132 out
133 .with_meta(("assumed_secure", signature))
134 }
135
136 fn is_secure(&self) -> bool {
137 let Ok(self_entries) = bson::to_document(&self) else { return false };
138 let Some(Bson::Binary(public_key)) = self_entries.get("security_signing_public_key") else { return false };
139 let public_key = &public_key.bytes;
140 let Ok(public_key) = PublicKey::try_from(public_key.as_slice()) else { return false };
141
142 self.is_secure_with(public_key)
143 }
144
145 fn is_secure_with(&self, public_key: PublicKey) -> bool {
146 use dryoc::sign::SignedMessage;
147
148 let Ok(mut self_entries) = bson::to_document(&self) else { return false };
149 let Some(Bson::Binary(signature)) = self_entries.remove("assumed_secure") else { return false };
150 let signature = signature.bytes;
151
152 let Ok(mut self_bytes) = bson::to_vec(&self_entries) else { return false };
153 self_bytes.extend_from_slice(Self::SECURITY_PADDING);
154 let self_signed = SignedMessage::from_parts(signature, self_bytes);
155
156 let Ok(()) = self_signed.verify(&public_key) else { return false };
157
158 true
159 }
160}
161
162impl<T: Metadata + Serialize> Signing for T {}