cipherrun 0.3.0

A fast, modular, and scalable TLS/SSL security scanner written in Rust
// Vulnerability Testing Phase - Tests for known SSL/TLS vulnerabilities
//
// This phase is responsible for testing the target server for known
// cryptographic vulnerabilities and protocol weaknesses.
//
// Responsibilities (Single Responsibility Principle):
// - Configure vulnerability scanner with CLI arguments
// - Execute vulnerability tests (FREAK, Logjam, POODLE, etc.)
// - Store vulnerability test results in scan context
//
// Dependencies:
// - VulnerabilityScanner (domain logic for vulnerability testing)
// - Args (CLI configuration for test selection)
// - Target (server information)
//
// Vulnerabilities tested:
// - FREAK (Factoring RSA Export Keys)
// - Logjam (Diffie-Hellman downgrade)
// - POODLE (Padding Oracle On Downgraded Legacy Encryption)
// - BEAST (Browser Exploit Against SSL/TLS)
// - CRIME/BREACH (Compression attacks)
// - Heartbleed (OpenSSL memory disclosure)
// - CCS Injection (ChangeCipherSpec injection)
// - Sweet32 (Birthday attacks on 64-bit block ciphers)
// - ROBOT (Return Of Bleichenbacher's Oracle Threat)
// - Renegotiation attacks (secure/insecure renegotiation)
// - TLS_FALLBACK_SCSV (downgrade protection)

use super::{ScanContext, ScanPhase};
use crate::vulnerabilities::tester::VulnerabilityScanner;
use crate::{Args, Result};
use async_trait::async_trait;

/// Vulnerability testing phase
///
/// Tests the target server for known SSL/TLS vulnerabilities.
/// This is a critical security assessment phase that identifies
/// exploitable weaknesses in the server's TLS configuration.
///
/// Configuration sources (from Args):
/// - Test selection (--vulnerabilities enables all tests)
/// - STARTTLS protocol (--starttls-*)
/// - Connection timeouts (--connect-timeout, --socket-timeout)
/// - Protocol versions (affects POODLE, BEAST tests)
pub struct VulnerabilityPhase;

impl VulnerabilityPhase {
    /// Create a new vulnerability testing phase
    pub fn new() -> Self {
        Self
    }

    /// Configure VulnerabilityScanner with CLI arguments
    ///
    /// The VulnerabilityScanner is configured via the with_args constructor
    /// which automatically applies:
    /// - STARTTLS protocol selection
    /// - Connection timeouts
    /// - SNI configuration
    /// - Protocol version filters
    /// - Bug workarounds mode
    fn configure_scanner(&self, context: &ScanContext) -> VulnerabilityScanner {
        let target = context.target();

        // Create scanner with Args-based configuration
        // The with_args method applies all relevant CLI flags automatically
        VulnerabilityScanner::with_args(target, &context.args)
    }
}

impl Default for VulnerabilityPhase {
    fn default() -> Self {
        Self::new()
    }
}

#[async_trait]
impl ScanPhase for VulnerabilityPhase {
    fn name(&self) -> &'static str {
        "Testing Vulnerabilities"
    }

    fn should_run(&self, args: &Args) -> bool {
        // Run if:
        // - Explicit vulnerability testing requested (--vulnerabilities)
        // - Full scan mode (--all)
        // - Default scan (target specified without other flags)
        args.scan.vulnerabilities || args.scan.all || args.target.is_some()
    }

    async fn execute(&self, context: &mut ScanContext) -> Result<()> {
        // Configure scanner with all CLI options
        let scanner = self.configure_scanner(context);

        // Execute all vulnerability tests
        // The test_all() method runs a comprehensive suite:
        // 1. Protocol-level vulnerabilities (POODLE, BEAST)
        // 2. Cipher-level vulnerabilities (FREAK, Logjam, Sweet32)
        // 3. Implementation bugs (Heartbleed, CCS Injection)
        // 4. Renegotiation attacks
        // 5. Compression attacks (CRIME, BREACH)
        // 6. Padding oracle attacks (ROBOT)
        let vulnerability_results = scanner.test_all().await?;

        // Store results in context
        context.results.vulnerabilities = vulnerability_results;

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::Arc;

    #[test]
    fn test_vulnerability_phase_should_run() {
        let phase = VulnerabilityPhase::new();

        // Test with --vulnerabilities flag
        let mut args = Args::default();
        args.scan.vulnerabilities = true;
        assert!(phase.should_run(&args));

        // Test with --all flag
        let mut args = Args::default();
        args.scan.all = true;
        assert!(phase.should_run(&args));

        // Test with target specified (default scan)
        let mut args = Args::default();
        args.target = Some("example.com".to_string());
        assert!(phase.should_run(&args));

        // Test with no relevant flags
        let args = Args::default();
        assert!(!phase.should_run(&args));
    }

    #[test]
    fn test_vulnerability_phase_name() {
        let phase = VulnerabilityPhase::new();
        assert_eq!(phase.name(), "Testing Vulnerabilities");
    }
}