//! Server-side SRP implementation //! //! Contains the `ServerAuthenticationWorkflow` for implementing the server //! side of the SRP authentication. use digest::Digest; use serde::Serialize; use srp::server::{SrpServer, SrpServerVerifier}; use getrandom::getrandom; use crate::types::Result; /// Server-side of the authentication workflow /// /// This struct should be used on the server side to authenticate a /// compatible SRP6a client. /// Digest `D` specifies the digest algorithm used and therefore also implicitly /// defines the key size of the common secret key. pub struct ServerAuthenticationWorkflow<'s, D: Digest> { delegate: SrpServer<'s, D>, } impl<'s, D: Digest> ServerAuthenticationWorkflow<'s, D> { pub fn new(group: &'s crate::groups::SrpGroup) -> Self { return Self { delegate: SrpServer::<'s, D>::new(group), }; } /// step2: server creates ephemeral key from random bytes and stored verifier /// /// The private key `server_private_b` must not be exposed, but needs to /// be stored for future steps. /// The public key `server_public_b` and the `salt` must be sent to the /// client. /// /// receive: `client_public_a` from client /// keep: `server_private_a`, `client_public_b` /// send: `server_public_a`, `salt` to client pub fn step2(&self, params: ServerStep2Params) -> Result { let mut server_private_b = vec![0 as u8; 128]; getrandom(server_private_b.as_mut_slice())?; let server_public_b = self.delegate.compute_public_ephemeral( server_private_b.as_slice(), params.stored_verifier); return Ok(ServerStep2Result { server_private_b, server_public_b }); } /// step4: server-side: generate verifier /// /// the `proof()` of the result should be sent to the client pub fn step4(&self, params: ServerStep4Params) -> Result> { let verifier = self.delegate.process_reply( params.server_private_b, params.stored_verifier, params.client_public_a)?; verifier.verify_client(params.client_proof)?; return Ok(ServerStep4Result { verifier }); } // step 6: client verifies proof } /// Parameters for step 2 #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(Serialize))] pub struct ServerStep2Params<'p> { /// The verifier stored for the given user /// /// Contains the verifier that has been stored for the given user during /// user registration. #[serde(with = "crate::util::base64_u8")] pub stored_verifier: &'p [u8], } // Result of step 2 #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(Serialize))] pub struct ServerStep2Result { /// The server's private ephemeral key /// /// This must be kept secret. #[serde(with = "crate::util::base64_vec_u8")] pub server_private_b: Vec, /// The server's public ephemeral key /// /// This must be sent to the client. #[serde(with = "crate::util::base64_vec_u8")] pub server_public_b: Vec, } /// Parameters for step 4 /// /// Step 4 verifies the client proof. #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(Serialize))] pub struct ServerStep4Params<'p> { /// The server's private ephemeral key generated in step 2 #[serde(with = "crate::util::base64_u8")] pub server_private_b: &'p [u8], /// The verifier stored for the user during user registration #[serde(with = "crate::util::base64_u8")] pub stored_verifier: &'p [u8], /// The client's public key received as part of step 2 #[serde(with = "crate::util::base64_u8")] pub client_public_a: &'p [u8], /// The client's proof /// /// Verifying the client proof is a prerequesite for sending any encrypted /// data (including the server proof) to the client. Not verifying the /// client proof may enable brute force attacks on the user credentials. #[serde(with = "crate::util::base64_u8")] pub client_proof: &'p [u8], } /// Result of step 4 /// /// The result of step 4 can be used to verify the client's proof and /// to generate a client proof, as well as to generate the common key. pub struct ServerStep4Result { verifier: SrpServerVerifier, } impl ServerStep4Result { /// Get the common secret key /// /// SRP6a authentication results in a secret key shared by the client /// and server. pub fn key(&self) -> &[u8] { return self.verifier.key(); } /// Generate a server proof /// /// The generated value can be used to proof to the client that the server /// is using the same secret key. pub fn proof(&self) -> &[u8] { return self.verifier.proof(); } /// Verify the client's proof /// /// This method verifies the the client's `proof` is correct, thereby /// verifying that the client uses the same secret key as the server. pub fn verify_client(&self, reply: &[u8]) -> Result<()> { return self.verifier.verify_client(reply) .or_else(|err| Err(err.into())); } }