Parse OpenSSL cipher string to rustls SupportedCipherSuite list Supports patterns like: - "AES128" → filters for AES_128 - "AES256" → filters for AES_256 - "AES128:AES256" → both - "ECDHE+AESGCM" → ECDHE AND AESGCM (both conditions must match) - "ALL" or "DEFAULT" → all available - "!MD5" → exclusion (ignored, rustls doesn't support weak ciphers anyway)
(cipher_str: &str)
| 608 | /// - "ALL" or "DEFAULT" → all available |
| 609 | /// - "!MD5" → exclusion (ignored, rustls doesn't support weak ciphers anyway) |
| 610 | fn parse_cipher_string(cipher_str: &str) -> Result<Vec<rustls::SupportedCipherSuite>, String> { |
| 611 | if cipher_str.is_empty() { |
| 612 | return Err("No cipher can be selected".to_string()); |
| 613 | } |
| 614 | |
| 615 | let all_suites = ALL_CIPHER_SUITES; |
| 616 | let mut selected = Vec::new(); |
| 617 | |
| 618 | for part in cipher_str.split(':') { |
| 619 | let part = part.trim(); |
| 620 | |
| 621 | // Skip exclusions (rustls doesn't support these) |
| 622 | if part.starts_with('!') { |
| 623 | continue; |
| 624 | } |
| 625 | |
| 626 | // Skip priority markers starting with + |
| 627 | if part.starts_with('+') { |
| 628 | continue; |
| 629 | } |
| 630 | |
| 631 | // Match pattern |
| 632 | match part { |
| 633 | "ALL" | "DEFAULT" | "HIGH" => { |
| 634 | // Add all available cipher suites |
| 635 | selected.extend_from_slice(all_suites); |
| 636 | } |
| 637 | _ => { |
| 638 | // Check if this is a compound pattern with + (AND condition) |
| 639 | // e.g., "ECDHE+AESGCM" means ECDHE AND AESGCM |
| 640 | let patterns: Vec<&str> = part.split('+').collect(); |
| 641 | |
| 642 | let mut found_any = false; |
| 643 | for suite in all_suites { |
| 644 | let name = format!("{:?}", suite.suite()); |
| 645 | |
| 646 | // Check if all patterns match (AND condition) |
| 647 | let matches = patterns.iter().all(|&pattern| { |
| 648 | // Handle common OpenSSL pattern variations |
| 649 | if pattern.contains("AES128") { |
| 650 | name.contains("AES_128") |
| 651 | } else if pattern.contains("AES256") { |
| 652 | name.contains("AES_256") |
| 653 | } else if pattern == "AESGCM" { |
| 654 | // AESGCM: AES with GCM mode |
| 655 | name.contains("AES") && name.contains("GCM") |
| 656 | } else if pattern == "AESCCM" { |
| 657 | // AESCCM: AES with CCM mode |
| 658 | name.contains("AES") && name.contains("CCM") |
| 659 | } else if pattern == "CHACHA20" { |
| 660 | name.contains("CHACHA20") |
| 661 | } else if pattern == "ECDHE" { |
| 662 | name.contains("ECDHE") |
| 663 | } else if pattern == "DHE" { |
| 664 | // DHE but not ECDHE |
| 665 | name.contains("DHE") && !name.contains("ECDHE") |
| 666 | } else if pattern == "ECDH" { |
| 667 | // ECDH but not ECDHE |
no test coverage detected