1
#![allow(clippy::module_name_repetitions)]
2

            
3
//! OPAQUE server side handling.
4

            
5
use serde::{Deserialize, Serialize};
6

            
7
use crate::{
8
	cipher_suite::{self, ServerSetup},
9
	Config, Error, LoginFinalization, LoginRequest, LoginResponse, PublicKey,
10
	RegistrationFinalization, RegistrationRequest, RegistrationResponse, Result,
11
};
12

            
13
/// Server configuration. This contains the secret key needed to create and use
14
/// [`ServerFile`]s, if it is lost, all corresponding [`ServerFile`]s become
15
/// unusable.
16
288
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
17
pub struct ServerConfig {
18
	/// [`Config`] of this [`ServerConfig`].
19
	config: Config,
20
	/// Holds the private key and OPRF seed.
21
	setup: ServerSetup,
22
}
23

            
24
impl Default for ServerConfig {
25
15
	fn default() -> Self {
26
15
		let config = Config::default();
27
15

            
28
15
		Self {
29
15
			config,
30
15
			setup: ServerSetup::new(config.cipher_suite),
31
15
		}
32
15
	}
33
}
34

            
35
impl ServerConfig {
36
	/// Create a new [`ServerConfig`]. This contains the secret key needed to
37
	/// create and use [`ServerFile`]s, if it is lost, all corresponding
38
	/// [`ServerFile`]s become unusable.
39
	#[must_use]
40
219
	pub fn new(config: Config) -> Self {
41
219
		Self {
42
219
			config,
43
219
			setup: ServerSetup::new(config.cipher_suite),
44
219
		}
45
219
	}
46

            
47
	/// Returns the [`Config`] associated with this [`ServerConfig`].
48
	#[must_use]
49
687
	pub const fn config(&self) -> Config {
50
687
		self.config
51
687
	}
52

            
53
	/// Returns the [`PublicKey`] associated with this [`ServerConfig`].
54
	#[must_use]
55
686
	pub fn public_key(&self) -> PublicKey {
56
686
		PublicKey::new(self.config(), self.setup.public_key())
57
686
	}
58
}
59

            
60
/// Holds the state of a registration process. See [`register`](Self::register).
61
#[must_use = "Does nothing if not `finish`ed"]
62
288
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
63
pub struct ServerRegistration {
64
	/// [`Config`] of the corresponding [`ServerConfig`].
65
	config: Config,
66
	/// Public key of the corresponding [`ServerConfig`].
67
	public_key: PublicKey,
68
	/// Registration process sate.
69
	state: cipher_suite::ServerRegistration,
70
}
71

            
72
impl ServerRegistration {
73
	/// Returns the [`Config`] associated with this [`ServerRegistration`].
74
	#[must_use]
75
1
	pub const fn config(&self) -> Config {
76
1
		self.config
77
1
	}
78

            
79
	/// Returns the [`PublicKey`] associated with this [`ServerRegistration`].
80
	#[must_use]
81
1
	pub const fn public_key(&self) -> PublicKey {
82
1
		self.public_key
83
1
	}
84

            
85
	/// Starts the registration process. The returned [`RegistrationResponse`]
86
	/// has to be send back to the client to drive the registration process. See
87
	/// [`ClientRegistration::finish()`](crate::ClientRegistration::finish).
88
	///
89
	/// # Errors
90
	/// - [`Error::Config`] if [`ServerConfig`] and [`RegistrationRequest`] were
91
	///   not created with the same [`Config`]
92
	/// - [`Error::Opaque`] on internal OPAQUE error
93
232
	pub fn register(
94
232
		config: &ServerConfig,
95
232
		request: RegistrationRequest,
96
232
	) -> Result<(Self, RegistrationResponse)> {
97
232
		if config.config != request.config {
98
2
			return Err(Error::Config);
99
230
		}
100

            
101
230
		let (state, message) =
102
230
			cipher_suite::ServerRegistration::register(&config.setup, request.message)?;
103

            
104
230
		Ok((
105
230
			Self {
106
230
				config: config.config,
107
230
				public_key: config.public_key(),
108
230
				state,
109
230
			},
110
230
			RegistrationResponse {
111
230
				config: config.config,
112
230
				message,
113
230
			},
114
230
		))
115
232
	}
116

            
117
	/// Finishes the registration process. The returned [`ServerFile`] is
118
	/// needed for the client to login. See [`ServerLogin::login()`].
119
	///
120
	/// # Errors
121
	/// [`Error::Config`] if [`ServerConfig`] and [`RegistrationRequest`] were
122
	/// not created with the same [`Config`].
123
231
	pub fn finish(self, finalization: RegistrationFinalization) -> Result<ServerFile> {
124
231
		if self.config != finalization.config {
125
2
			return Err(Error::Config);
126
229
		}
127

            
128
229
		let file = self.state.finish(finalization.message)?;
129

            
130
229
		Ok(ServerFile {
131
229
			config: self.config,
132
229
			public_key: self.public_key,
133
229
			file,
134
229
		})
135
231
	}
136
}
137

            
138
/// Represents a registered client, this is needed for the client to login. See
139
/// [`ServerLogin::login()`].
140
#[must_use = "Without this the client can't login"]
141
288
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
142
pub struct ServerFile {
143
	/// [`Config`] of the corresponding [`ServerConfig`].
144
	config: Config,
145
	/// Public key of the corresponding [`ServerConfig`].
146
	public_key: PublicKey,
147
	/// Password envelope.
148
	file: cipher_suite::ServerFile,
149
}
150

            
151
impl ServerFile {
152
	/// Returns the [`Config`] associated with this [`ServerFile`].
153
	#[must_use]
154
1
	pub const fn config(&self) -> Config {
155
1
		self.config
156
1
	}
157

            
158
	/// Returns the [`PublicKey`] associated with this [`ServerFile`].
159
	#[must_use]
160
145
	pub const fn public_key(&self) -> PublicKey {
161
145
		self.public_key
162
145
	}
163
}
164

            
165
/// Starts the login process on the server.
166
288
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
167
#[must_use = "Does nothing if not `finish`ed"]
168
pub struct ServerLogin {
169
	/// [`Config`] of the corresponding [`ServerConfig`].
170
	config: Config,
171
	/// Public key of the corresponding [`ServerConfig`].
172
	public_key: PublicKey,
173
	/// Login process state.
174
	state: cipher_suite::ServerLogin,
175
}
176

            
177
impl ServerLogin {
178
	/// Returns the [`Config`] associated with this [`ServerLogin`].
179
	#[must_use]
180
1
	pub const fn config(&self) -> Config {
181
1
		self.config
182
1
	}
183

            
184
	/// Returns the [`PublicKey`] associated with this [`ServerLogin`].
185
	#[must_use]
186
	pub const fn public_key(&self) -> PublicKey {
187
		self.public_key
188
	}
189

            
190
	/// Starts the login process. The returned [`LoginResponse`] has to
191
	/// be send back to the client to drive the login process. See
192
	/// [`ClientLogin::finish()`](crate::ClientLogin::finish).
193
	///
194
	/// If a client is registered, pass the appropriate [`ServerFile`], pass
195
	/// [`None`] otherwise. Passing [`None`] simulates a login attempt in a way
196
	/// that doesn't let an attacker determine if a corresponding client is
197
	/// registered or not.
198
	///
199
	/// # Errors
200
	/// - [`Error::Config`] if [`ServerConfig`], [`ServerFile`] or
201
	///   [`LoginRequest`] were not created with the same [`Config`]
202
	/// - [`Error::ServerFile`] if [`ServerFile`] was not created with the same
203
	///   [`ServerConfig`]
204
	/// - [`Error::Opaque`] on internal OPAQUE error
205
231
	pub fn login(
206
231
		config: &ServerConfig,
207
231
		file: Option<ServerFile>,
208
231
		request: LoginRequest,
209
231
	) -> Result<(Self, LoginResponse)> {
210
231
		if config.config != request.config {
211
2
			return Err(Error::Config);
212
229
		}
213

            
214
229
		let (state, message) = cipher_suite::ServerLogin::login(
215
229
			&config.setup,
216
229
			file.map(|file| (file.file, file.public_key.key)),
217
229
			request.message,
218
229
		)?;
219

            
220
227
		Ok((
221
227
			Self {
222
227
				config: config.config,
223
227
				public_key: config.public_key(),
224
227
				state,
225
227
			},
226
227
			LoginResponse {
227
227
				config: config.config,
228
227
				message,
229
227
			},
230
227
		))
231
231
	}
232

            
233
	/// Finishes the login process.
234
	///
235
	/// # Errors
236
	/// [`Error::Opaque`] on internal OPAQUE error.
237
226
	pub fn finish(self, finalization: LoginFinalization) -> Result<()> {
238
226
		if self.config != finalization.config {
239
2
			return Err(Error::Config);
240
224
		}
241
224

            
242
224
		self.state.finish(finalization.message)
243
226
	}
244
}