Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 89 additions & 4 deletions crates/rustirc-core/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
//! implementing PLAIN, EXTERNAL, and SCRAM-SHA-256 mechanisms as specified
//! in Phase 2 requirements.

#![allow(unused_assignments)] // Zeroize derive generates field assignments for security

use anyhow::Result;
use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
use std::collections::HashMap;
Expand All @@ -28,16 +26,18 @@ pub enum AuthState {
/// SASL credentials with secure password storage
#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop)]
pub struct SaslCredentials {
#[allow(unused_assignments)] // Zeroize derive generates field assignments for security
pub username: String,
#[zeroize(skip)]
#[allow(unused_assignments)] // Zeroize derive generates field assignments for security
pub password: SecureString,
#[allow(unused_assignments)] // Zeroize derive generates field assignments for security
pub authzid: Option<String>,
}

/// Secure string that automatically zeroes memory on drop
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct SecureString {
#[zeroize(skip)]
#[allow(unused_assignments)] // Zeroize derive generates field assignments for security
inner: Vec<u8>,
}

Expand Down Expand Up @@ -332,4 +332,89 @@ mod tests {
auth.handle_success();
assert_eq!(auth.state(), &AuthState::Success);
}

#[test]
fn test_secure_string_zeroization() {
use std::mem::ManuallyDrop;
use zeroize::Zeroize;

// Create a SecureString with sensitive data
let sensitive_data = "password123".to_string();
let mut secure_str = ManuallyDrop::new(SecureString::new(sensitive_data.clone()));

// Verify the data is present before zeroization
assert_eq!(secure_str.as_str(), "password123");

// Manually call zeroize (this is what ZeroizeOnDrop does in Drop)
secure_str.zeroize();

// After zeroization, the inner bytes should be zeroed
assert!(
secure_str.inner.iter().all(|&b| b == 0),
"SecureString memory should be zeroed after calling zeroize()"
);

// Clean up the ManuallyDrop wrapper
unsafe { ManuallyDrop::drop(&mut secure_str); }
}

#[test]
fn test_sasl_credentials_zeroization() {
use std::mem::ManuallyDrop;
use zeroize::Zeroize;

// Create SaslCredentials with sensitive data
let username = "testuser".to_string();
let password = SecureString::new("secretpass".to_string());
let authzid = Some("admin".to_string());

let mut creds = ManuallyDrop::new(SaslCredentials {
username: username.clone(),
password: password.clone(),
authzid: authzid.clone(),
});

// Verify the data is present before zeroization
assert_eq!(creds.username, "testuser");
assert_eq!(creds.password.as_str(), "secretpass");
assert_eq!(creds.authzid.as_deref(), Some("admin"));

// Manually call zeroize (this is what ZeroizeOnDrop does in Drop)
creds.zeroize();

// After zeroization, all string fields should be zeroed
assert!(
creds.username.as_bytes().iter().all(|&b| b == 0),
"SaslCredentials username should be zeroed after calling zeroize()"
);
assert!(
creds.password.inner.iter().all(|&b| b == 0),
"SaslCredentials password should be zeroed after calling zeroize()"
);
if let Some(ref authzid_val) = creds.authzid {
assert!(
authzid_val.as_bytes().iter().all(|&b| b == 0),
"SaslCredentials authzid should be zeroed after calling zeroize()"
);
}

// Clean up the ManuallyDrop wrapper
unsafe { ManuallyDrop::drop(&mut creds); }
}

#[test]
fn test_secure_string_zeroize_on_drop() {
// This test verifies that ZeroizeOnDrop is properly derived
// by ensuring the struct implements the trait
fn assert_zeroize_on_drop<T: zeroize::ZeroizeOnDrop>() {}
assert_zeroize_on_drop::<SecureString>();
}

#[test]
fn test_sasl_credentials_zeroize_on_drop() {
// This test verifies that ZeroizeOnDrop is properly derived
// by ensuring the struct implements the trait
fn assert_zeroize_on_drop<T: zeroize::ZeroizeOnDrop>() {}
assert_zeroize_on_drop::<SaslCredentials>();
}
}