1#[cfg(feature = "ecdsa")]
11pub mod ecdsa;
12pub mod hash_eddsa;
13mod message;
14pub mod pure_eddsa;
15pub(super) mod shared;
16
17use core::iter;
18use core::marker::PhantomData;
19use core::ops::Add;
20
21use derive_where::derive_where;
22use digest::block_api::{BlockSizeUser, CoreProxy, SmallBlockSizeUser};
23use digest::{Mac, Output, OutputSizeUser};
24use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
25use generic_array::{ArrayLength, GenericArray};
26use hmac::{KeyInit, SimpleHmac};
27use rand::{CryptoRng, Rng};
28use subtle::{ConstantTimeEq, CtOption};
29use zeroize::Zeroize;
30
31use self::message::Role;
32pub use self::message::{CachedMessage, HashOutput, Message, MessageBuilder, VerifyMessage};
33use super::{
34 Deserialize, GenerateKe1Result, GenerateKe2Result, GenerateKe3Result, KeyExchange, Serialize,
35 SerializedContext, SerializedCredentialRequest, SerializedCredentialResponse,
36 SerializedIdentifier, SerializedIdentifiers,
37};
38use crate::ciphersuite::{CipherSuite, KeGroup, KeHash};
39use crate::envelope::NonceLen;
40use crate::errors::{InternalError, ProtocolError};
41use crate::hash::{Hash, OutputSize, ProxyHash};
42use crate::key_exchange::group::Group;
43pub use crate::key_exchange::shared::{DiffieHellman, Ke1Message, Ke1State};
44use crate::key_exchange::shared::{derive_keys, generate_ke1, generate_nonce, transcript};
45use crate::keypair::{KeyPair, PrivateKey, PublicKey};
46use crate::opaque::Identifiers;
47use crate::serialization::{ConcatExt, SliceExt, UpdateExt};
48
49pub struct SigmaI<SIG, KE, KEH>(PhantomData<(SIG, KE, KEH)>);
70
71pub trait SignatureProtocol {
88 type Group: Group;
90 type Signature: Clone + Zeroize;
92 type SignatureLen: ArrayLength;
94 type VerifyState<CS: CipherSuite, KE: Group>: Clone + Zeroize;
98
99 fn sign<R: CryptoRng + Rng, CS: CipherSuite, KE: Group>(
110 sk: &<Self::Group as Group>::Sk,
111 rng: &mut R,
112 message: &Message<CS, KE>,
113 ) -> (Self::Signature, Self::VerifyState<CS, KE>);
114
115 fn verify<CS: CipherSuite, KE: Group>(
123 pk: &<Self::Group as Group>::Pk,
124 message_builder: MessageBuilder<'_, CS>,
125 state: Self::VerifyState<CS, KE>,
126 signature: &Self::Signature,
127 ) -> Result<(), ProtocolError>;
128
129 fn serialize_signature(signature: &Self::Signature) -> GenericArray<u8, Self::SignatureLen>;
131
132 fn deserialize_take_signature(bytes: &mut &[u8]) -> Result<Self::Signature, ProtocolError>;
136}
137
138#[cfg_attr(
140 feature = "serde",
141 derive(serde::Deserialize, serde::Serialize),
142 serde(bound(
143 deserialize = "'de: 'a, <KeGroup<CS> as Group>::Pk: serde::Deserialize<'de>, KE::Pk: \
144 serde::Deserialize<'de>",
145 serialize = "<KeGroup<CS> as Group>::Pk: serde::Serialize, KE::Pk: serde::Serialize"
146 ))
147)]
148#[derive_where(Clone, ZeroizeOnDrop)]
149#[derive_where(Debug, Eq, Hash, PartialEq; <KeGroup<CS> as Group>::Pk, KE::Pk)]
150pub struct Ke2Builder<'a, CS: CipherSuite, KE: Group> {
151 transcript: Message<'a, CS, KE>,
152 server_nonce: GenericArray<u8, NonceLen>,
153 #[derive_where(skip(Zeroize))]
154 client_s_pk: PublicKey<KeGroup<CS>>,
155 #[derive_where(skip(Zeroize))]
156 server_e_pk: PublicKey<KE>,
157 expected_mac: Output<KeHash<CS>>,
158 session_key: Output<KeHash<CS>>,
159 #[cfg(test)]
160 handshake_secret: Output<KeHash<CS>>,
161 #[cfg(test)]
162 km2: Output<KeHash<CS>>,
163}
164
165#[cfg_attr(
167 feature = "serde",
168 derive(serde::Deserialize, serde::Serialize),
169 serde(bound(
170 deserialize = "<SIG::Group as Group>::Pk: serde::Deserialize<'de>, SIG::VerifyState<CS, \
171 KE>: serde::Deserialize<'de>",
172 serialize = "<SIG::Group as Group>::Pk: serde::Serialize, SIG::VerifyState<CS, KE>: \
173 serde::Serialize"
174 ))
175)]
176#[derive_where(Clone, ZeroizeOnDrop)]
177#[derive_where(Debug, Eq, Hash, PartialEq; <SIG::Group as Group>::Pk, SIG::VerifyState<CS, KE>)]
178pub struct Ke2State<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> {
179 #[derive_where(skip(Zeroize))]
180 client_s_pk: PublicKey<SIG::Group>,
181 session_key: Output<KeHash<CS>>,
182 verify_state: SIG::VerifyState<CS, KE>,
183 expected_mac: Output<KeHash<CS>>,
184}
185
186#[cfg_attr(
188 feature = "serde",
189 derive(serde::Deserialize, serde::Serialize),
190 serde(bound(
191 deserialize = "KE::Pk: serde::Deserialize<'de>, SIG::Signature: serde::Deserialize<'de>",
192 serialize = "KE::Pk: serde::Serialize, SIG::Signature: serde::Serialize"
193 ))
194)]
195#[derive_where(Clone, ZeroizeOnDrop)]
196#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KE::Pk, SIG::Signature)]
197pub struct Ke2Message<SIG: SignatureProtocol, KE: Group, KEH: Hash>
198where
199 KEH::Core: ProxyHash,
200 <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
201 Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
202 OutputSize<KEH>: ArrayLength,
203{
204 server_nonce: GenericArray<u8, NonceLen>,
205 #[derive_where(skip(Zeroize))]
206 server_e_pk: PublicKey<KE>,
207 signature: SIG::Signature,
208 mac: Output<KEH>,
209}
210
211#[cfg_attr(
213 feature = "serde",
214 derive(serde::Deserialize, serde::Serialize),
215 serde(bound(
216 deserialize = "SIG::Signature: serde::Deserialize<'de>",
217 serialize = "SIG::Signature: serde::Serialize"
218 ))
219)]
220#[derive_where(Clone, ZeroizeOnDrop)]
221#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; SIG::Signature)]
222pub struct Ke3Message<SIG: SignatureProtocol, KEH: OutputSizeUser>
223where
224 <KEH as OutputSizeUser>::OutputSize: ArrayLength,
225{
226 signature: SIG::Signature,
227 mac: Output<KEH>,
228}
229
230impl<SIG: SignatureProtocol, KE: 'static + Group, KEH: Hash + BlockSizeUser> KeyExchange
231 for SigmaI<SIG, KE, KEH>
232where
233 KE::Sk: DiffieHellman<KE>,
234 KEH::Core: ProxyHash,
235 <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
236 Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
237 OutputSize<KEH>: ArrayLength,
238{
239 type Group = SIG::Group;
240 type Hash = KEH;
241
242 type KE1State = Ke1State<KE>;
243 type KE2State<CS: CipherSuite> = Ke2State<CS, SIG, KE>;
244 type KE1Message = Ke1Message<KE>;
245 type KE2Builder<'a, CS: CipherSuite<KeyExchange = Self>> = Ke2Builder<'a, CS, KE>;
246 type KE2BuilderData<'a, CS: 'static + CipherSuite> = &'a Message<'a, CS, KE>;
247 type KE2BuilderInput<CS: CipherSuite> = (SIG::Signature, SIG::VerifyState<CS, KE>);
248 type KE2Message = Ke2Message<SIG, KE, KEH>;
249 type KE3Message = Ke3Message<SIG, KEH>;
250
251 fn generate_ke1<R: Rng + CryptoRng>(
252 rng: &mut R,
253 ) -> Result<GenerateKe1Result<Self>, ProtocolError> {
254 generate_ke1(rng)
255 }
256
257 fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: Rng + CryptoRng>(
258 rng: &mut R,
259 credential_request: SerializedCredentialRequest<CS>,
260 ke1_message: Self::KE1Message,
261 credential_response: SerializedCredentialResponse<CS>,
262 client_s_pk: PublicKey<Self::Group>,
263 identifiers: SerializedIdentifiers<'a, KeGroup<CS>>,
264 context: SerializedContext<'a>,
265 ) -> Result<Self::KE2Builder<'a, CS>, ProtocolError> {
266 let server_e = KeyPair::<KE>::derive_random(rng);
267 let server_nonce = generate_nonce::<R>(rng);
268
269 let ke1_message_iter = ke1_message.to_iter();
270 let server_e_pk = server_e.public().serialize();
271
272 let transcript_hasher = transcript(
273 &context,
274 &identifiers,
275 &credential_request,
276 &ke1_message_iter,
277 &credential_response,
278 server_nonce,
279 &server_e_pk,
280 );
281
282 let shared_secret = server_e
283 .private()
284 .ke_diffie_hellman(&ke1_message.client_e_pk);
285
286 let derived_keys = derive_keys::<KEH>(
287 iter::once(shared_secret.as_slice()),
288 &transcript_hasher.finalize(),
289 )?;
290
291 let mut server_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km2)
292 .map_err(|_| InternalError::HmacError)?;
293 server_mac.update_iter(identifiers.server.iter());
294 let server_mac = server_mac.finalize().into_bytes();
295
296 let mut client_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km3)
297 .map_err(|_| InternalError::HmacError)?;
298 client_mac.update_iter(identifiers.client.iter());
299 let client_mac = client_mac.finalize().into_bytes();
300
301 let message = Message {
302 role: Role::Server,
303 context,
304 identifiers,
305 cache: CachedMessage {
306 credential_request,
307 ke1_message: ke1_message_iter,
308 credential_response,
309 server_nonce,
310 server_e_pk,
311 server_mac,
312 },
313 };
314
315 Ok(Ke2Builder {
316 transcript: message,
317 server_nonce,
318 client_s_pk,
319 server_e_pk: server_e.public().clone(),
320 expected_mac: client_mac,
321 session_key: derived_keys.session_key,
322 #[cfg(test)]
323 handshake_secret: derived_keys.handshake_secret,
324 #[cfg(test)]
325 km2: derived_keys.km2,
326 })
327 }
328
329 fn ke2_builder_data<'a, CS: 'static + CipherSuite<KeyExchange = Self>>(
330 builder: &'a Self::KE2Builder<'_, CS>,
331 ) -> Self::KE2BuilderData<'a, CS> {
332 &builder.transcript
333 }
334
335 fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
336 builder: &Self::KE2Builder<'_, CS>,
337 rng: &mut R,
338 server_s_sk: &PrivateKey<Self::Group>,
339 ) -> Self::KE2BuilderInput<CS> {
340 server_s_sk.sign::<_, CS, SIG, KE>(rng, &builder.transcript)
341 }
342
343 fn build_ke2<CS: CipherSuite<KeyExchange = Self>>(
344 builder: Self::KE2Builder<'_, CS>,
345 input: Self::KE2BuilderInput<CS>,
346 ) -> Result<GenerateKe2Result<CS>, ProtocolError> {
347 Ok(GenerateKe2Result {
348 state: Ke2State {
349 client_s_pk: builder.client_s_pk.clone(),
350 session_key: builder.session_key.clone(),
351 verify_state: input.1,
352 expected_mac: builder.expected_mac.clone(),
353 },
354 message: Ke2Message {
355 server_nonce: builder.server_nonce,
356 server_e_pk: builder.server_e_pk.clone(),
357 signature: input.0,
358 mac: builder.transcript.cache.server_mac.clone(),
359 },
360 #[cfg(test)]
361 handshake_secret: builder.handshake_secret.clone(),
362 #[cfg(test)]
363 km2: builder.km2.clone(),
364 })
365 }
366
367 fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
368 rng: &mut R,
369 credential_request: SerializedCredentialRequest<CS>,
370 ke1_message: Self::KE1Message,
371 credential_response: SerializedCredentialResponse<CS>,
372 ke1_state: &Self::KE1State,
373 ke2_message: Self::KE2Message,
374 server_s_pk: PublicKey<Self::Group>,
375 client_s_sk: PrivateKey<Self::Group>,
376 identifiers: SerializedIdentifiers<'_, KeGroup<CS>>,
377 context: SerializedContext<'_>,
378 ) -> Result<GenerateKe3Result<Self>, ProtocolError> {
379 let ke1_message_iter = ke1_message.to_iter();
380 let server_e_pk = ke2_message.server_e_pk.serialize();
381
382 let transcript_hasher = transcript(
383 &context,
384 &identifiers,
385 &credential_request,
386 &ke1_message_iter,
387 &credential_response,
388 ke2_message.server_nonce,
389 &server_e_pk,
390 );
391
392 let shared_secret = ke1_state
393 .client_e_sk
394 .ke_diffie_hellman(&ke2_message.server_e_pk);
395
396 let derived_keys = derive_keys::<KEH>(
397 iter::once(shared_secret.as_slice()),
398 &transcript_hasher.finalize(),
399 )?;
400
401 let mut server_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km2)
402 .map_err(|_| InternalError::HmacError)?;
403 server_mac.update_iter(identifiers.server.iter());
404 let server_mac = server_mac.finalize().into_bytes();
405
406 bool::from(server_mac.ct_eq(&ke2_message.mac))
407 .then_some(())
408 .ok_or(ProtocolError::InvalidLoginError)?;
409
410 let mut client_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km3)
411 .map_err(|_| InternalError::HmacError)?;
412 client_mac.update_iter(identifiers.client.iter());
413 let client_mac = client_mac.finalize().into_bytes();
414
415 let message = Message {
416 role: Role::Client,
417 context: context.clone(),
418 identifiers: identifiers.clone(),
419 cache: CachedMessage {
420 credential_request,
421 ke1_message: ke1_message_iter,
422 credential_response,
423 server_nonce: ke2_message.server_nonce,
424 server_e_pk,
425 server_mac,
426 },
427 };
428
429 let (signature, state) = client_s_sk.sign::<_, CS, SIG, KE>(rng, &message);
430
431 server_s_pk.verify::<CS, SIG, KE>(
432 MessageBuilder {
433 role: Role::Client,
434 context,
435 identifier: identifiers.server,
436 },
437 state,
438 &ke2_message.signature,
439 )?;
440
441 Ok(GenerateKe3Result {
442 session_key: derived_keys.session_key,
443 message: Ke3Message {
444 signature,
445 mac: client_mac,
446 },
447 #[cfg(test)]
448 handshake_secret: derived_keys.handshake_secret,
449 #[cfg(test)]
450 km3: derived_keys.km3,
451 })
452 }
453
454 fn finish_ke<CS: CipherSuite<KeyExchange = Self>>(
455 ke2_state: &Self::KE2State<CS>,
456 ke3_message: Self::KE3Message,
457 identifiers: Identifiers<'_>,
458 context: SerializedContext<'_>,
459 ) -> Result<Output<KEH>, ProtocolError> {
460 ke2_state.client_s_pk.verify::<CS, SIG, KE>(
461 MessageBuilder {
462 role: Role::Server,
463 context,
464 identifier: SerializedIdentifier::from_identifier(
465 identifiers.client,
466 ke2_state.client_s_pk.serialize(),
467 )?,
468 },
469 ke2_state.verify_state.clone(),
470 &ke3_message.signature,
471 )?;
472
473 CtOption::new(
474 ke2_state.session_key.clone(),
475 ke2_state.expected_mac.ct_eq(&ke3_message.mac),
476 )
477 .into_option()
478 .ok_or(ProtocolError::InvalidLoginError)
479 }
480}
481
482impl<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> Deserialize for Ke2State<CS, SIG, KE>
483where
484 SIG::VerifyState<CS, KE>: Deserialize,
485 OutputSize<KeHash<CS>>: ArrayLength,
486{
487 fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
488 Ok(Self {
489 client_s_pk: PublicKey::deserialize_take(input)?,
490 session_key: input.take_array("session key")?.into_ha0_4(),
491 verify_state: SIG::VerifyState::<CS, KE>::deserialize_take(input)?,
492 expected_mac: input.take_array("expected mac")?.into_ha0_4(),
493 })
494 }
495}
496
497type Ke2StateLen<CS, SIG: SignatureProtocol, KE> = Sum<
498 Sum<Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>, VerifyStateLen<CS, SIG, KE>>,
499 OutputSize<KeHash<CS>>,
500>;
501
502type VerifyStateLen<CS, SIG: SignatureProtocol, KE> = <SIG::VerifyState<CS, KE> as Serialize>::Len;
503
504impl<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> Serialize for Ke2State<CS, SIG, KE>
505where
506 SIG::VerifyState<CS, KE>: Serialize,
507 OutputSize<KeHash<CS>>: ArrayLength,
508 <SIG::Group as Group>::PkLen: Add<OutputSize<KeHash<CS>>>,
510 Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>:
511 ArrayLength + Add<VerifyStateLen<CS, SIG, KE>>,
512 Sum<Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>, VerifyStateLen<CS, SIG, KE>>:
513 ArrayLength + Add<OutputSize<KeHash<CS>>>,
514 Ke2StateLen<CS, SIG, KE>: ArrayLength,
515{
516 type Len = Ke2StateLen<CS, SIG, KE>;
517
518 fn serialize(&self) -> GenericArray<u8, Self::Len> {
519 self.client_s_pk
520 .serialize()
521 .cat(GenericArray::from_slice(self.session_key.as_slice()).clone())
522 .cat(self.verify_state.serialize())
523 .cat(GenericArray::from_slice(self.expected_mac.as_slice()).clone())
524 }
525}
526
527impl<SIG: SignatureProtocol, KE: Group, KEH: Hash> Deserialize for Ke2Message<SIG, KE, KEH>
528where
529 KEH::Core: ProxyHash,
530 <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
531 Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
532 OutputSize<KEH>: ArrayLength,
533{
534 fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
535 Ok(Self {
536 server_nonce: input.take_array("server nonce")?,
537 server_e_pk: PublicKey::deserialize_take(input)?,
538 signature: SIG::deserialize_take_signature(input)?,
539 mac: input.take_array("mac")?.into_ha0_4(),
540 })
541 }
542}
543
544impl<SIG: SignatureProtocol, KE: Group, KEH: Hash> Serialize for Ke2Message<SIG, KE, KEH>
545where
546 KEH::Core: ProxyHash,
547 <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
548 Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
549 OutputSize<KEH>: ArrayLength,
550 NonceLen: Add<KE::PkLen>,
552 Sum<NonceLen, KE::PkLen>: ArrayLength + Add<SIG::SignatureLen>,
553 Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>: ArrayLength + Add<OutputSize<KEH>>,
554 Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>: ArrayLength,
555{
556 type Len = Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>;
557
558 fn serialize(&self) -> GenericArray<u8, Self::Len> {
559 self.server_nonce
560 .cat(self.server_e_pk.serialize())
561 .cat(SIG::serialize_signature(&self.signature))
562 .cat(GenericArray::from_slice(self.mac.as_slice()).clone())
563 }
564}
565
566impl<SIG: SignatureProtocol, KEH: Hash> Deserialize for Ke3Message<SIG, KEH>
567where
568 KEH::Core: ProxyHash,
569 <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
570 Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
571 OutputSize<KEH>: ArrayLength,
572{
573 fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
574 Ok(Self {
575 signature: SIG::deserialize_take_signature(input)?,
576 mac: input.take_array("mac")?.into_ha0_4(),
577 })
578 }
579}
580
581impl<SIG: SignatureProtocol, KEH: Hash> Serialize for Ke3Message<SIG, KEH>
582where
583 KEH::Core: ProxyHash,
584 <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
585 Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
586 OutputSize<KEH>: ArrayLength,
587 SIG::SignatureLen: Add<OutputSize<KEH>>,
589 Sum<SIG::SignatureLen, OutputSize<KEH>>: ArrayLength,
590{
591 type Len = Sum<SIG::SignatureLen, OutputSize<KEH>>;
592
593 fn serialize(&self) -> GenericArray<u8, Self::Len> {
594 SIG::serialize_signature(&self.signature)
595 .cat(GenericArray::from_slice(self.mac.as_slice()).clone())
596 }
597}