1#[cfg(debug_assertions)]
6use rand_core::CryptoRngCore;
7use reach_proc_macros::{communicable, prosted};
8
9#[cfg(debug_assertions)]
10use ecdh_omr::Decoy;
11use reach_aliases::*;
12use reach_signatures::{Digestible, Signatures, Verifiable, Verifies};
13
14#[cfg(feature = "websocket")]
15use crate::macros::from_generic_websocket_error;
16#[cfg(any(feature = "attestant", feature = "server"))]
17use crate::storage::Storable;
18use crate::{communication::*, error, traits::*};
19
20#[cfg(any(feature = "reaching", feature = "reachable", feature = "server"))]
21mod macros;
22#[cfg(any(feature = "reaching", feature = "reachable", feature = "server"))]
23pub(crate) use macros::*;
24
25#[cfg(any(feature = "reaching", feature = "reachable", feature = "server"))]
26mod envelope;
27#[cfg(any(feature = "reaching", feature = "reachable", feature = "server"))]
28pub use envelope::*;
29
30#[cfg(any(feature = "reaching", feature = "reachable", feature = "server"))]
31mod message_vault;
32#[cfg(any(feature = "reaching", feature = "reachable", feature = "server"))]
33pub use message_vault::*;
34
35mod reach;
36pub use reach::*;
37
38mod v0 {
39 include!(concat!(env!("OUT_DIR"), "/reach.wire_v0.rs"));
40
41 pub(crate) mod communication {
42 include!(concat!(env!("OUT_DIR"), "/reach.wire_communication_v0.rs"));
43 }
44}
45
46pub(crate) mod proto {
47 use super::v0;
48
49 #[cfg(any(feature = "reaching", feature = "reachable", feature = "server"))]
50 pub(crate) use v0::{
51 CredentialVault, Envelope, EnvelopeId, EnvelopeSeed, MessageVault, MessageVaultId,
52 MessageVaultSeed, Reach, ReachableSignedKeys, RemoveEnvelopeIdHint, SealedEnvelopeId,
53 SealedMessageVaultId,
54 };
55
56 #[cfg(any(feature = "reachable", feature = "server"))]
57 pub(crate) use v0::{EnvelopeIds, RemoveReachablePublicKeys};
58
59 #[cfg(any(feature = "attestant", feature = "server"))]
60 pub(crate) use v0::RemoveReachableVerifyingKeys;
61
62 #[cfg(any(feature = "attestant", feature = "reachable", feature = "server"))]
63 pub(crate) use v0::{AuthenticationAssurance, AuthenticationChallenge};
64
65 pub(crate) use v0::{
66 AttestantVerifyingKeys, ReachablePublicKeys, ReachableVerifyingKeys, Salts,
67 SharedPublicKeys, SharedVerifyingKeys,
68 };
69
70 pub use v0::communication::{Request, Response};
71}
72
73pub use proto::{Request, Response};
74
75impl CommunicableType for Request {}
76impl CommunicableType for Response {}
77
78#[cfg(feature = "websocket")]
79from_generic_websocket_error!(Response);
80
81#[derive(Debug, Clone, Copy)]
82pub enum ErrorResponse {
83 Unsupported,
84 Internal,
85 Decode,
86}
87
88impl From<ErrorResponse> for Response {
89 fn from(value: ErrorResponse) -> Self {
90 match value {
91 ErrorResponse::Unsupported => Response::ErrorUnsupported,
92 ErrorResponse::Internal => Response::ErrorInternal,
93 ErrorResponse::Decode => Response::ErrorDecode,
94 }
95 }
96}
97
98impl ErrorSubset for Response {
99 type Error = ErrorResponse;
100}
101
102pub struct ReachCommunication {}
103
104impl CommunicableTypes for ReachCommunication {
105 type Req = Request;
106 type Resp = Response;
107 type Variant = RemoteCommunication;
108}
109
110#[cfg(any(feature = "reaching", feature = "reachable", feature = "server"))]
111mod reaching_reachable_server {
112 use super::*;
113
114 #[derive(Debug)]
115 pub struct Init(pub u8);
116
117 impl Communicable<Request> for Init {
118 fn to_communication(&self) -> Communication<Request> {
119 Communication::from(Request::Init, vec![self.0], None)
120 }
121
122 fn try_from_communication(
123 communication: &Communication<Request>,
124 ) -> Result<Self, error::DecodeError> {
125 if communication.r#type != Request::Init || communication.inner.len() != 1 {
126 return Err(error::DecodeError);
127 }
128
129 Ok(Init(communication.inner[0]))
130 }
131 }
132
133 impl MatchResponse<Request> for Init {
134 type Resp = ReachOk;
135 }
136}
137
138#[cfg(any(feature = "reaching", feature = "reachable", feature = "server"))]
139pub use reaching_reachable_server::*;
140
141#[cfg(any(feature = "reachable", feature = "attestant", feature = "server"))]
142mod reachable_attestant_server {
143 use super::*;
144
145 pub struct InitAuthenticatedSession(pub u8);
146
147 impl Communicable<Request> for InitAuthenticatedSession {
148 fn to_communication(&self) -> Communication<Request> {
149 Communication::from(Request::InitAuthenticatedSession, vec![self.0], None)
150 }
151
152 fn try_from_communication(
153 communication: &Communication<Request>,
154 ) -> Result<Self, error::DecodeError> {
155 if communication.r#type != Request::InitAuthenticatedSession
156 || communication.inner.len() != 1
157 {
158 return Err(error::DecodeError);
159 }
160
161 Ok(InitAuthenticatedSession(communication.inner[0]))
162 }
163 }
164
165 impl MatchResponse<Request> for InitAuthenticatedSession {
166 type Resp = AuthenticationChallenge;
167 }
168}
169
170#[cfg(any(feature = "reachable", feature = "attestant", feature = "server"))]
171pub use reachable_attestant_server::*;
172
173#[cfg(any(feature = "reachable", feature = "server"))]
174pub struct ListEnvelopeIds;
175
176#[cfg(any(feature = "reachable", feature = "server"))]
177pub struct GetSharedSecretKeys;
178
179#[derive(Debug)]
180#[communicable(Response::Ok, marker)]
181pub struct ReachOk;
182
183#[prosted(proto::Salts, Decode, Encode, ProstTraits)]
184#[derive(Debug, Clone, Copy)]
185pub struct Salts {
186 pub attestant_identity: ThreeTwo,
187 pub shared_secret: ThreeTwo,
188 pub reaching_static: ThreeTwo,
189 pub verifying_keys_mac: ThreeTwo,
190 pub reaching_current: ThreeTwo,
191 pub reaching_previous: ThreeTwo,
192 pub attestant_ec_signature: Ed25519Signature,
193 pub attestant_pq_signature: FnDsaSignature,
194}
195
196#[cfg(any(feature = "attestant", feature = "server"))]
197impl Storable for Salts {}
198
199#[cfg(debug_assertions)]
200impl Decoy for Salts {
201 fn random_decoy(csprng: &mut impl CryptoRngCore) -> Salts {
202 let mut attestant_pq_signature = reach_signatures::FN_DSA_SIGNATURE_EMPTY;
203 csprng.fill_bytes(&mut attestant_pq_signature);
204
205 Salts {
206 attestant_identity: ThreeTwo::random_from_rng(csprng),
207 shared_secret: ThreeTwo::random_from_rng(csprng),
208 reaching_static: ThreeTwo::random_from_rng(csprng),
209 verifying_keys_mac: ThreeTwo::random_from_rng(csprng),
210 reaching_current: ThreeTwo::random_from_rng(csprng),
211 reaching_previous: ThreeTwo::random_from_rng(csprng),
212 attestant_ec_signature: Ed25519Signature::from_bytes(&SixFour::random_from_rng(csprng)),
213 attestant_pq_signature,
214 }
215 }
216}
217
218impl Digestible for Salts {
219 fn hashable_bytes(&self) -> Vec<Box<dyn AsRef<[u8]> + '_>> {
220 vec![
221 Box::new(&self.attestant_identity),
222 Box::new(&self.shared_secret),
223 Box::new(&self.reaching_static),
224 Box::new(&self.verifying_keys_mac),
225 ]
226 }
227}
228
229impl Signatures for Salts {
230 fn ec_signature(&self) -> &Ed25519Signature {
231 &self.attestant_ec_signature
232 }
233
234 fn pq_signature(&self) -> &FnDsaSignature {
235 &self.attestant_pq_signature
236 }
237}
238
239impl Verifies<Salts> for AttestantVerifyingKeys {}
240
241impl Verifiable for Salts {}