LCOV - code coverage report
Current view: top level - proxy/src/scram - signature.rs (source / functions) Coverage Total Hit
Test: 2b0730d767f560e20b6748f57465922aa8bb805e.info Lines: 100.0 % 33 33
Test Date: 2024-09-25 14:04:07 Functions: 100.0 % 4 4

            Line data    Source code
       1              : //! Tools for client/server signature management.
       2              : 
       3              : use super::key::{ScramKey, SCRAM_KEY_LEN};
       4              : 
       5              : /// A collection of message parts needed to derive the client's signature.
       6              : #[derive(Debug)]
       7              : pub(crate) struct SignatureBuilder<'a> {
       8              :     pub(crate) client_first_message_bare: &'a str,
       9              :     pub(crate) server_first_message: &'a str,
      10              :     pub(crate) client_final_message_without_proof: &'a str,
      11              : }
      12              : 
      13              : impl SignatureBuilder<'_> {
      14           15 :     pub(crate) fn build(&self, key: &ScramKey) -> Signature {
      15           15 :         let parts = [
      16           15 :             self.client_first_message_bare.as_bytes(),
      17           15 :             b",",
      18           15 :             self.server_first_message.as_bytes(),
      19           15 :             b",",
      20           15 :             self.client_final_message_without_proof.as_bytes(),
      21           15 :         ];
      22           15 : 
      23           15 :         super::hmac_sha256(key.as_ref(), parts).into()
      24           15 :     }
      25              : }
      26              : 
      27              : /// A computed value which, when xored with `ClientProof`,
      28              : /// produces `ClientKey` that we need for authentication.
      29              : #[derive(Debug)]
      30              : #[repr(transparent)]
      31              : pub(crate) struct Signature {
      32              :     bytes: [u8; SCRAM_KEY_LEN],
      33              : }
      34              : 
      35              : impl Signature {
      36              :     /// Derive `ClientKey` from client's signature and proof.
      37            8 :     pub(crate) fn derive_client_key(&self, proof: &[u8; SCRAM_KEY_LEN]) -> ScramKey {
      38            8 :         // This is how the proof is calculated:
      39            8 :         //
      40            8 :         // 1. sha256(ClientKey) -> StoredKey
      41            8 :         // 2. hmac_sha256(StoredKey, [messages...]) -> ClientSignature
      42            8 :         // 3. ClientKey ^ ClientSignature -> ClientProof
      43            8 :         //
      44            8 :         // Step 3 implies that we can restore ClientKey from the proof
      45            8 :         // by xoring the latter with the ClientSignature. Afterwards we
      46            8 :         // can check that the presumed ClientKey meets our expectations.
      47            8 :         let mut signature = self.bytes;
      48          256 :         for (i, x) in proof.iter().enumerate() {
      49          256 :             signature[i] ^= x;
      50          256 :         }
      51              : 
      52            8 :         signature.into()
      53            8 :     }
      54              : }
      55              : 
      56              : impl From<[u8; SCRAM_KEY_LEN]> for Signature {
      57           15 :     fn from(bytes: [u8; SCRAM_KEY_LEN]) -> Self {
      58           15 :         Self { bytes }
      59           15 :     }
      60              : }
      61              : 
      62              : impl AsRef<[u8]> for Signature {
      63            7 :     fn as_ref(&self) -> &[u8] {
      64            7 :         &self.bytes
      65            7 :     }
      66              : }
        

Generated by: LCOV version 2.1-beta