Master side of the mutual authentication. Called on the TCP stream immediately after connection, before any Cake protocol messages.
(stream: &mut S, key: &str)
| 52 | /// Called on the TCP stream immediately after connection, before any Cake |
| 53 | /// protocol messages. |
| 54 | pub async fn authenticate_as_master<S>(stream: &mut S, key: &str) -> Result<()> |
| 55 | where |
| 56 | S: AsyncReadExt + AsyncWriteExt + Unpin, |
| 57 | { |
| 58 | let key_bytes = key.as_bytes(); |
| 59 | |
| 60 | // Step 1: send nonce to worker |
| 61 | let master_nonce = random_nonce(); |
| 62 | stream.write_all(&master_nonce).await?; |
| 63 | stream.flush().await?; |
| 64 | |
| 65 | // Step 2: read worker's HMAC response + worker's nonce in one call |
| 66 | let mut response = [0u8; HMAC_SIZE + NONCE_SIZE]; |
| 67 | stream.read_exact(&mut response).await?; |
| 68 | let worker_hmac = &response[..HMAC_SIZE]; |
| 69 | let worker_nonce = &response[HMAC_SIZE..]; |
| 70 | |
| 71 | // Step 3: verify worker's HMAC |
| 72 | let expected = compute_hmac(key_bytes, &master_nonce); |
| 73 | if !constant_time_eq(worker_hmac, &expected) { |
| 74 | return Err(anyhow!("worker authentication failed: invalid HMAC")); |
| 75 | } |
| 76 | |
| 77 | // Step 4: send master's HMAC response |
| 78 | let master_hmac = compute_hmac(key_bytes, worker_nonce); |
| 79 | stream.write_all(&master_hmac).await?; |
| 80 | stream.flush().await?; |
| 81 | |
| 82 | Ok(()) |
| 83 | } |
| 84 | |
| 85 | /// Worker side of the mutual authentication. |
| 86 | /// |