• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![allow(missing_docs)]
2 // Copyright 2023 Google LLC
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 pub(crate) use crate::proto_adapter::{
17     CipherCommitment, ClientFinished, ClientInit, GenericPublicKey, HandshakeCipher,
18     IntoAdapter as _, ServerInit, ToWrappedMessage as _,
19 };
20 use crypto_provider::elliptic_curve::EphemeralSecret;
21 use crypto_provider::p256::{P256EcdhProvider, P256PublicKey, P256};
22 use crypto_provider::x25519::X25519;
23 use crypto_provider::CryptoProvider;
24 use crypto_provider::{
25     elliptic_curve::{EcdhProvider, PublicKey},
26     hkdf::Hkdf,
27     sha2::{Sha256, Sha512},
28     CryptoRng,
29 };
30 use std::{
31     collections::hash_set,
32     fmt::{self, Formatter},
33     marker::PhantomData,
34 };
35 use ukey2_proto::protobuf::Message;
36 use ukey2_proto::ukey2_all_proto::{securemessage, ukey};
37 
38 pub trait WireCompatibilityLayer {
encode_public_key<C: CryptoProvider>( &self, key: Vec<u8>, cipher: HandshakeCipher, ) -> Option<Vec<u8>>39     fn encode_public_key<C: CryptoProvider>(
40         &self,
41         key: Vec<u8>,
42         cipher: HandshakeCipher,
43     ) -> Option<Vec<u8>>;
decode_public_key<C: CryptoProvider>( &self, key: Vec<u8>, cipher: HandshakeCipher, ) -> Option<Vec<u8>>44     fn decode_public_key<C: CryptoProvider>(
45         &self,
46         key: Vec<u8>,
47         cipher: HandshakeCipher,
48     ) -> Option<Vec<u8>>;
49 }
50 
51 #[derive(Clone)]
52 pub enum HandshakeImplementation {
53     /// Implementation of ukey2 exchange handshake according to the specs in
54     /// <https://github.com/google/ukey2/blob/master/README.md>.
55     ///
56     /// In particular, when encoding for the P256 public key, this uses the standardized encoding
57     /// described in [SEC 1](https://www.secg.org/sec1-v2.pdf).
58     ///
59     /// For X25519, the public key is the x-coordinate in little endian per RFC 7748.
60     Spec,
61     /// Implementation of ukey2 exchange handshake that matches
62     /// [the Java implementation](https://github.com/google/ukey2/blob/master/src/main/java/com/google/security/cryptauth/lib/securegcm/Ukey2Handshake.java),
63     /// but different from what the specs says.
64     ///
65     /// In particular, when encoding for the P256 curve, the public key is represented as serialized
66     /// bytes of the following proto:
67     /// ```text
68     /// message EcP256PublicKey {
69     ///     // x and y are encoded in big-endian two's complement (slightly wasteful)
70     ///     // Client MUST verify (x,y) is a valid point on NIST P256
71     ///     required bytes x = 1;
72     ///     required bytes y = 2;
73     /// }
74     /// ```
75     ///
76     /// Encoding for X25519 is not supported in this mode.
77     PublicKeyInProtobuf,
78 }
79 
80 impl WireCompatibilityLayer for HandshakeImplementation {
encode_public_key<C: CryptoProvider>( &self, key: Vec<u8>, cipher: HandshakeCipher, ) -> Option<Vec<u8>>81     fn encode_public_key<C: CryptoProvider>(
82         &self,
83         key: Vec<u8>,
84         cipher: HandshakeCipher,
85     ) -> Option<Vec<u8>> {
86         match self {
87             HandshakeImplementation::Spec => Some(key),
88             HandshakeImplementation::PublicKeyInProtobuf => match cipher {
89                 HandshakeCipher::P256Sha512 => {
90                     let p256_key =
91                         <C::P256 as P256EcdhProvider>::PublicKey::from_bytes(key.as_slice())
92                             .unwrap();
93                     let (x, y) = p256_key.to_affine_coordinates().unwrap();
94                     let bigboi_x = num_bigint::BigInt::from_biguint(
95                         num_bigint::Sign::Plus,
96                         num_bigint::BigUint::from_bytes_be(x.to_vec().as_slice()),
97                     );
98                     let bigboi_y = num_bigint::BigInt::from_biguint(
99                         num_bigint::Sign::Plus,
100                         num_bigint::BigUint::from_bytes_be(y.to_vec().as_slice()),
101                     );
102                     let proto_key = securemessage::EcP256PublicKey {
103                         x: Some(bigboi_x.to_signed_bytes_be()),
104                         y: Some(bigboi_y.to_signed_bytes_be()),
105                         ..Default::default()
106                     };
107                     let key = securemessage::GenericPublicKey {
108                         type_: Some(securemessage::PublicKeyType::EC_P256.into()),
109                         ec_p256_public_key: Some(proto_key).into(),
110                         ..Default::default()
111                     };
112                     key.write_to_bytes().ok()
113                 }
114                 HandshakeCipher::Curve25519Sha512 => None,
115             },
116         }
117     }
118 
decode_public_key<C: CryptoProvider>( &self, key: Vec<u8>, cipher: HandshakeCipher, ) -> Option<Vec<u8>>119     fn decode_public_key<C: CryptoProvider>(
120         &self,
121         key: Vec<u8>,
122         cipher: HandshakeCipher,
123     ) -> Option<Vec<u8>> {
124         match self {
125             HandshakeImplementation::Spec => Some(key),
126             HandshakeImplementation::PublicKeyInProtobuf => {
127                 // key will be wrapped in a genericpublickey
128                 let public_key: GenericPublicKey<C> =
129                     securemessage::GenericPublicKey::parse_from_bytes(key.as_slice())
130                         .ok()?
131                         .into_adapter()
132                         .ok()?;
133                 match public_key {
134                     GenericPublicKey::Ec256(key) => {
135                         debug_assert_eq!(cipher, HandshakeCipher::P256Sha512);
136                         Some(key.to_bytes())
137                     }
138                 }
139             }
140         }
141     }
142 }
143 
144 pub struct Ukey2ServerStage1<C: CryptoProvider> {
145     pub(crate) next_protocols: hash_set::HashSet<String>,
146     pub(crate) handshake_impl: HandshakeImplementation,
147     _marker: PhantomData<C>,
148 }
149 
150 impl<C: CryptoProvider> fmt::Debug for Ukey2ServerStage1<C> {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result151     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
152         write!(f, "Ukey2ServerS1")
153     }
154 }
155 
156 impl<C: CryptoProvider> Ukey2ServerStage1<C> {
from( next_protocols: hash_set::HashSet<String>, handshake_impl: HandshakeImplementation, ) -> Self157     pub fn from(
158         next_protocols: hash_set::HashSet<String>,
159         handshake_impl: HandshakeImplementation,
160     ) -> Self {
161         Self {
162             next_protocols,
163             handshake_impl,
164             _marker: PhantomData,
165         }
166     }
167 
handle_client_init<R: rand::Rng + rand::CryptoRng>( self, rng: &mut R, client_init: ClientInit, client_init_msg_bytes: Vec<u8>, ) -> Result<Ukey2ServerStage2<C>, ClientInitError>168     pub(crate) fn handle_client_init<R: rand::Rng + rand::CryptoRng>(
169         self,
170         rng: &mut R,
171         client_init: ClientInit,
172         client_init_msg_bytes: Vec<u8>,
173     ) -> Result<Ukey2ServerStage2<C>, ClientInitError> {
174         if client_init.version() != &1 {
175             return Err(ClientInitError::BadVersion);
176         }
177 
178         let next_protocol = client_init.next_protocol();
179         if !self.next_protocols.contains(next_protocol) {
180             return Err(ClientInitError::BadNextProtocol);
181         }
182 
183         // nothing to check here about client_init.random -- already been validated as 32 bytes
184 
185         // all cipher types are supported, so no BAD_HANDSHAKE_CIPHER case
186         let commitment = client_init
187             .commitments()
188             .iter()
189             // we want to get the first matching cipher, but max_by_key returns the last max,
190             // so iterate in reverse direction
191             .rev()
192             // proto enum uses the priority as the numeric value
193             .max_by_key(|c| c.cipher().as_proto() as i32)
194             .ok_or(ClientInitError::BadHandshakeCipher)?;
195         match *commitment.cipher() {
196             // pick in priority order
197             HandshakeCipher::Curve25519Sha512 => {
198                 let secret = ServerKeyPair::Curve25519(
199                     <C::X25519 as EcdhProvider<X25519>>::EphemeralSecret::generate_random(&mut
200                         <<<C::X25519 as EcdhProvider<X25519>>::EphemeralSecret as EphemeralSecret<
201                             X25519,
202                         >>::Rng as CryptoRng>::new(),
203                     ),
204                 );
205                 Ok(Ukey2ServerStage2::from(
206                     &mut *rng,
207                     client_init_msg_bytes,
208                     commitment.clone(),
209                     secret,
210                     self.handshake_impl,
211                     next_protocol.to_string(),
212                 ))
213             }
214             HandshakeCipher::P256Sha512 => {
215                 let secret = ServerKeyPair::P256(
216                     <C::P256 as EcdhProvider<P256>>::EphemeralSecret::generate_random(
217                         &mut<<<C::P256 as EcdhProvider<P256>>::EphemeralSecret as EphemeralSecret<
218                             P256,
219                         >>::Rng as CryptoRng>::new(),
220                     ),
221                 );
222                 Ok(Ukey2ServerStage2::from(
223                     &mut *rng,
224                     client_init_msg_bytes,
225                     commitment.clone(),
226                     secret,
227                     self.handshake_impl,
228                     next_protocol.to_string(),
229                 ))
230             }
231         }
232     }
233 }
234 
235 enum ServerKeyPair<C: CryptoProvider> {
236     Curve25519(<C::X25519 as EcdhProvider<X25519>>::EphemeralSecret),
237     P256(<C::P256 as EcdhProvider<P256>>::EphemeralSecret),
238 }
239 
240 pub struct Ukey2ServerStage2<C: CryptoProvider> {
241     client_init_msg: Vec<u8>,
242     server_init_msg: Vec<u8>,
243     commitment: CipherCommitment,
244     key_pair: ServerKeyPair<C>,
245     pub(crate) handshake_impl: HandshakeImplementation,
246     next_protocol: String,
247     _marker: PhantomData<C>,
248 }
249 
250 impl<C: CryptoProvider> fmt::Debug for Ukey2ServerStage2<C> {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result251     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
252         write!(f, "Ukey2ServerS2")
253     }
254 }
255 
256 const HKDF_SALT_AUTH: &[u8] = b"UKEY2 v1 auth";
257 const HKDF_SALT_NEXT: &[u8] = b"UKEY2 v1 next";
258 
259 impl<C: CryptoProvider> Ukey2ServerStage2<C> {
from<R: rand::Rng + rand::CryptoRng>( rng: &mut R, client_init_msg: Vec<u8>, commitment: CipherCommitment, key_pair: ServerKeyPair<C>, handshake_impl: HandshakeImplementation, next_protocol: String, ) -> Self260     fn from<R: rand::Rng + rand::CryptoRng>(
261         rng: &mut R,
262         client_init_msg: Vec<u8>,
263         commitment: CipherCommitment,
264         key_pair: ServerKeyPair<C>,
265         handshake_impl: HandshakeImplementation,
266         next_protocol: String,
267     ) -> Self {
268         let random: [u8; 32] = rng.gen();
269         let mut server_init = ukey::Ukey2ServerInit::default();
270         server_init.set_version(1);
271         server_init.set_random(random.to_vec());
272         server_init.set_handshake_cipher(commitment.cipher().as_proto());
273         server_init.set_public_key(match &key_pair {
274             ServerKeyPair::Curve25519(es) => es.public_key_bytes(),
275             ServerKeyPair::P256(es) => handshake_impl
276                 .encode_public_key::<C>(es.public_key_bytes(), HandshakeCipher::P256Sha512)
277                 .unwrap(),
278         });
279 
280         Self {
281             client_init_msg,
282             server_init_msg: server_init.to_wrapped_msg().write_to_bytes().unwrap(),
283             commitment,
284             key_pair,
285             handshake_impl,
286             next_protocol,
287             _marker: PhantomData,
288         }
289     }
290 
server_init_msg(&self) -> &[u8]291     pub fn server_init_msg(&self) -> &[u8] {
292         &self.server_init_msg
293     }
294 
handle_client_finished_msg( self, msg: ClientFinished, client_finished_msg_bytes: &[u8], ) -> Result<Ukey2Server, ClientFinishedError>295     pub(crate) fn handle_client_finished_msg(
296         self,
297         msg: ClientFinished,
298         client_finished_msg_bytes: &[u8],
299     ) -> Result<Ukey2Server, ClientFinishedError> {
300         let hash_bytes = C::Sha512::sha512(client_finished_msg_bytes);
301         // must be constant time to avoid timing attack on hash equality
302         if C::constant_time_eq(hash_bytes.as_slice(), self.commitment.commitment()) {
303             // handshake is complete
304             // independently derive shared DH key
305             let shared_secret_bytes = match self.key_pair {
306                 ServerKeyPair::Curve25519(es) => {
307                     let buf = msg.public_key.into_iter().collect::<Vec<u8>>();
308                     let public_key: [u8; 32] = (&buf[..])
309                         .try_into()
310                         .map_err(|_| ClientFinishedError::BadEd25519Key)?;
311                     es.diffie_hellman(
312                         &<C::X25519 as EcdhProvider<X25519>>::PublicKey::from_bytes(&public_key)
313                             .map_err(|_| ClientFinishedError::BadEd25519Key)?,
314                     )
315                     .map_err(|_| ClientFinishedError::BadKeyExchange)?
316                     .into()
317                 }
318                 ServerKeyPair::P256(es) => {
319                     let other_public_key =
320                         &<C::P256 as P256EcdhProvider>::PublicKey::from_sec1_bytes(
321                             self.handshake_impl
322                                 .decode_public_key::<C>(msg.public_key, HandshakeCipher::P256Sha512)
323                                 .ok_or(ClientFinishedError::BadP256Key)?
324                                 .as_slice(),
325                         )
326                         .map_err(|_| ClientFinishedError::BadP256Key)?;
327                     es.diffie_hellman(other_public_key)
328                         .map_err(|_| ClientFinishedError::BadKeyExchange)?
329                         .into()
330                 }
331             };
332             let shared_secret_sha256 = C::Sha256::sha256(&shared_secret_bytes).to_vec();
333             Ok(Ukey2Server {
334                 completed_handshake: CompletedHandshake::new(
335                     self.client_init_msg,
336                     self.server_init_msg,
337                     shared_secret_sha256,
338                     self.next_protocol,
339                 ),
340             })
341         } else {
342             Err(ClientFinishedError::UnknownCommitment)
343         }
344     }
345 }
346 
347 /// Representation of the UKEY2 server information after the handshake has been completed. An
348 /// instance of this can be created by going through the handshake state machine (starting from
349 /// [`Ukey2ServerStage1`]).
350 pub struct Ukey2Server {
351     completed_handshake: CompletedHandshake,
352 }
353 
354 impl fmt::Debug for Ukey2Server {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result355     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
356         write!(f, "Ukey2Server")
357     }
358 }
359 
360 impl Ukey2Server {
completed_handshake(&self) -> &CompletedHandshake361     pub fn completed_handshake(&self) -> &CompletedHandshake {
362         &self.completed_handshake
363     }
364 }
365 
366 pub struct Ukey2ClientStage1<C: CryptoProvider> {
367     curve25519_secret: <C::X25519 as EcdhProvider<X25519>>::EphemeralSecret,
368     p256_secret: <C::P256 as EcdhProvider<P256>>::EphemeralSecret,
369     curve25519_client_finished_bytes: Vec<u8>,
370     p256_client_finished_bytes: Vec<u8>,
371     client_init_bytes: Vec<u8>,
372     commitment_ciphers: Vec<HandshakeCipher>,
373     handshake_impl: HandshakeImplementation,
374     next_protocol: String,
375     _marker: PhantomData<C>,
376 }
377 
378 impl<C: CryptoProvider> fmt::Debug for Ukey2ClientStage1<C> {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result379     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
380         write!(f, "Ukey2Client1")
381     }
382 }
383 
384 impl<C: CryptoProvider> Ukey2ClientStage1<C> {
from<R: rand::Rng + rand::SeedableRng + rand::CryptoRng>( rng: &mut R, next_protocol: String, handshake_impl: HandshakeImplementation, ) -> Self385     pub fn from<R: rand::Rng + rand::SeedableRng + rand::CryptoRng>(
386         rng: &mut R,
387         next_protocol: String,
388         handshake_impl: HandshakeImplementation,
389     ) -> Self {
390         let random = rng.gen::<[u8; 32]>().to_vec();
391         // Curve25519 ClientFinished Message
392         let curve25519_secret =
393             <C::X25519 as EcdhProvider<X25519>>::EphemeralSecret::generate_random(
394                 &mut <<<C::X25519 as EcdhProvider<X25519>>::EphemeralSecret as EphemeralSecret<
395                     X25519,
396                 >>::Rng as CryptoRng>::new(),
397             );
398         let curve25519_client_finished_bytes = {
399             let client_finished = ukey::Ukey2ClientFinished {
400                 public_key: Some(curve25519_secret.public_key_bytes()),
401                 ..Default::default()
402             };
403             client_finished.to_wrapped_msg().write_to_bytes().unwrap()
404         };
405         let curve25519_client_finished_hash =
406             C::Sha512::sha512(&curve25519_client_finished_bytes).to_vec();
407 
408         // P256 ClientFinished Message
409         let p256_secret = <C::P256 as EcdhProvider<P256>>::EphemeralSecret::generate_random(
410                         &mut<<<C::P256 as EcdhProvider<P256>>::EphemeralSecret as EphemeralSecret<
411                             P256,
412                         >>::Rng as CryptoRng>::new(),
413                     );
414         let p256_client_finished_bytes = {
415             let client_finished = ukey::Ukey2ClientFinished {
416                 public_key: Some(
417                     handshake_impl
418                         .encode_public_key::<C>(
419                             p256_secret.public_key_bytes(),
420                             HandshakeCipher::P256Sha512,
421                         )
422                         .expect("Output of p256_secret.public_key_bytes should always be valid input for encode_public_key"),
423                 ),
424                 ..Default::default()
425             };
426             client_finished.to_wrapped_msg().write_to_bytes().unwrap()
427         };
428         let p256_client_finished_hash = C::Sha512::sha512(&p256_client_finished_bytes).to_vec();
429 
430         // ClientInit Message
431         let client_init_bytes = {
432             let curve25519_commitment = ukey::ukey2client_init::CipherCommitment {
433                 handshake_cipher: Some(HandshakeCipher::Curve25519Sha512.as_proto().into()),
434                 commitment: Some(curve25519_client_finished_hash),
435                 ..Default::default()
436             };
437 
438             let p256_commitment = ukey::ukey2client_init::CipherCommitment {
439                 handshake_cipher: Some(HandshakeCipher::P256Sha512.as_proto().into()),
440                 commitment: Some(p256_client_finished_hash),
441                 ..Default::default()
442             };
443 
444             let client_init = ukey::Ukey2ClientInit {
445                 version: Some(1),
446                 random: Some(random),
447                 cipher_commitments: vec![curve25519_commitment, p256_commitment],
448                 next_protocol: Some(next_protocol.to_string()),
449                 ..Default::default()
450             };
451             client_init.to_wrapped_msg().write_to_bytes().unwrap()
452         };
453 
454         Self {
455             curve25519_secret,
456             p256_secret,
457             curve25519_client_finished_bytes,
458             p256_client_finished_bytes,
459             client_init_bytes,
460             commitment_ciphers: vec![
461                 HandshakeCipher::Curve25519Sha512,
462                 HandshakeCipher::P256Sha512,
463             ],
464             handshake_impl,
465             next_protocol,
466             _marker: PhantomData,
467         }
468     }
469 
client_init_msg(&self) -> &[u8]470     pub fn client_init_msg(&self) -> &[u8] {
471         &self.client_init_bytes
472     }
473 
handle_server_init( self, server_init: ServerInit, server_init_bytes: Vec<u8>, ) -> Result<Ukey2Client, ServerInitError>474     pub(crate) fn handle_server_init(
475         self,
476         server_init: ServerInit,
477         server_init_bytes: Vec<u8>,
478     ) -> Result<Ukey2Client, ServerInitError> {
479         if server_init.version() != &1 {
480             return Err(ServerInitError::BadVersion);
481         }
482 
483         // loop over all commitments every time for a semblance of constant time-ness
484         let server_cipher = self
485             .commitment_ciphers
486             .iter()
487             .fold(None, |accum, c| {
488                 if server_init.handshake_cipher() == c {
489                     match accum {
490                         None => Some(c),
491                         Some(_) => accum,
492                     }
493                 } else {
494                     accum
495                 }
496             })
497             .ok_or(ServerInitError::BadHandshakeCipher)?;
498         let (server_shared_secret, client_finished_bytes) = match server_cipher {
499             HandshakeCipher::P256Sha512 => {
500                 let other_public_key = &<C::P256 as P256EcdhProvider>::PublicKey::from_sec1_bytes(
501                     self.handshake_impl
502                         .decode_public_key::<C>(
503                             server_init.public_key.to_vec(),
504                             HandshakeCipher::P256Sha512,
505                         )
506                         .ok_or(ServerInitError::BadPublicKey)?
507                         .as_slice(),
508                 )
509                 .map_err(|_| ServerInitError::BadPublicKey)?;
510                 let shared_secret = self
511                     .p256_secret
512                     .diffie_hellman(other_public_key)
513                     .map_err(|_| ServerInitError::BadKeyExchange)?;
514                 let shared_secret_bytes: [u8; 32] = shared_secret.into();
515                 (shared_secret_bytes, self.p256_client_finished_bytes)
516             }
517             HandshakeCipher::Curve25519Sha512 => {
518                 let pub_key: [u8; 32] = server_init
519                     .public_key
520                     .try_into()
521                     .map_err(|_| ServerInitError::BadPublicKey)?;
522                 (
523                     self.curve25519_secret
524                         .diffie_hellman(
525                             &<C::X25519 as EcdhProvider<X25519>>::PublicKey::from_bytes(&pub_key)
526                                 .map_err(|_| ServerInitError::BadPublicKey)?,
527                         )
528                         .map_err(|_| ServerInitError::BadKeyExchange)?
529                         .into(),
530                     self.curve25519_client_finished_bytes,
531                 )
532             }
533         };
534         let shared_secret_bytes = C::Sha256::sha256(&server_shared_secret).to_vec();
535         Ok(Ukey2Client {
536             client_finished_bytes,
537             completed_handshake: CompletedHandshake::new(
538                 self.client_init_bytes,
539                 server_init_bytes.to_vec(),
540                 shared_secret_bytes,
541                 self.next_protocol,
542             ),
543         })
544     }
545 }
546 
547 #[derive(Debug)]
548 #[allow(clippy::enum_variant_names)]
549 pub(crate) enum ServerInitError {
550     BadVersion,
551     BadHandshakeCipher,
552     BadPublicKey,
553     /// The diffie-hellman key exchange failed to generate a shared secret
554     BadKeyExchange,
555 }
556 
557 #[derive(Clone)]
558 pub struct Ukey2Client {
559     completed_handshake: CompletedHandshake,
560     client_finished_bytes: Vec<u8>,
561 }
562 
563 impl fmt::Debug for Ukey2Client {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result564     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
565         write!(f, "Ukey2Client")
566     }
567 }
568 
569 impl Ukey2Client {
client_finished_msg(&self) -> &[u8]570     pub fn client_finished_msg(&self) -> &[u8] {
571         &self.client_finished_bytes
572     }
573 
completed_handshake(&self) -> &CompletedHandshake574     pub fn completed_handshake(&self) -> &CompletedHandshake {
575         &self.completed_handshake
576     }
577 }
578 
579 #[allow(clippy::enum_variant_names)]
580 pub enum ClientInitError {
581     BadVersion,
582     BadHandshakeCipher,
583     BadNextProtocol,
584 }
585 
586 pub enum ClientFinishedError {
587     BadEd25519Key,
588     BadP256Key,
589     UnknownCommitment,
590     /// The diffie-hellman key exchange failed to generate a shared secret
591     BadKeyExchange,
592 }
593 
594 /// The result of completing the UKEY2 handshake.
595 #[derive(Clone)]
596 pub struct CompletedHandshake {
597     client_init_bytes: Vec<u8>,
598     server_init_bytes: Vec<u8>,
599     shared_secret: Vec<u8>,
600     pub next_protocol: String,
601 }
602 
603 impl CompletedHandshake {
new( client_init_bytes: Vec<u8>, server_init_bytes: Vec<u8>, shared_secret: Vec<u8>, next_protocol: String, ) -> Self604     fn new(
605         client_init_bytes: Vec<u8>,
606         server_init_bytes: Vec<u8>,
607         shared_secret: Vec<u8>,
608         next_protocol: String,
609     ) -> Self {
610         Self {
611             client_init_bytes,
612             server_init_bytes,
613             shared_secret,
614             next_protocol,
615         }
616     }
617 
618     /// Returns an HKDF for the UKEY2 `AUTH_STRING`.
auth_string<C: CryptoProvider>(&self) -> HandshakeHkdf<C>619     pub fn auth_string<C: CryptoProvider>(&self) -> HandshakeHkdf<C> {
620         HandshakeHkdf::new(
621             &self.client_init_bytes,
622             &self.server_init_bytes,
623             C::HkdfSha256::new(Some(HKDF_SALT_AUTH), &self.shared_secret),
624         )
625     }
626 
627     /// Returns an HKDF for the UKEY2 `NEXT_SECRET`.
next_protocol_secret<C: CryptoProvider>(&self) -> HandshakeHkdf<C>628     pub fn next_protocol_secret<C: CryptoProvider>(&self) -> HandshakeHkdf<C> {
629         HandshakeHkdf::new(
630             &self.client_init_bytes,
631             &self.server_init_bytes,
632             C::HkdfSha256::new(Some(HKDF_SALT_NEXT), &self.shared_secret),
633         )
634     }
635 }
636 
637 /// A UKEY2 handshake secret that can derive output at the caller's preferred length.
638 pub struct HandshakeHkdf<'a, C: CryptoProvider> {
639     client_init_bytes: &'a [u8],
640     server_init_bytes: &'a [u8],
641     hkdf: C::HkdfSha256,
642 }
643 
644 impl<'a, C: CryptoProvider> HandshakeHkdf<'a, C> {
645     /// Returns `None` if the requested size > 255 * 512 bytes.
derive_array<const N: usize>(&self) -> Option<[u8; N]>646     pub fn derive_array<const N: usize>(&self) -> Option<[u8; N]> {
647         let mut buf = [0; N];
648         self.derive_slice(&mut buf).map(|_| buf)
649     }
650 
651     /// Returns `None` if the requested `length` > 255 * 512 bytes.
derive_vec(&self, length: usize) -> Option<Vec<u8>>652     pub fn derive_vec(&self, length: usize) -> Option<Vec<u8>> {
653         let mut buf = vec![0; length];
654         self.derive_slice(&mut buf).map(|_| buf)
655     }
656 
657     /// Returns `None` if the provided `buf` has size > 255 * 512 bytes.
derive_slice(&self, buf: &mut [u8]) -> Option<()>658     pub fn derive_slice(&self, buf: &mut [u8]) -> Option<()> {
659         self.hkdf
660             .expand_multi_info(&[self.client_init_bytes, self.server_init_bytes], buf)
661             .ok()
662     }
663 
new(client_init_bytes: &'a [u8], server_init_bytes: &'a [u8], hkdf: C::HkdfSha256) -> Self664     fn new(client_init_bytes: &'a [u8], server_init_bytes: &'a [u8], hkdf: C::HkdfSha256) -> Self {
665         Self {
666             client_init_bytes,
667             server_init_bytes,
668             hkdf,
669         }
670     }
671 }
672