Load certificates from byte slice (auto-detects PEM vs DER format) Tries to parse as PEM first, falls back to DER if that fails. Duplicate certificates are detected and only counted once. If `treat_all_as_ca` is true, all certificates are counted as CA certificates regardless of their Basic Constraints (this matches load_verify_locations with cadata parameter). If `pem_only` is true, only PEM p
(
&mut self,
data: &[u8],
treat_all_as_ca: bool,
pem_only: bool,
)
| 719 | /// |
| 720 | /// If `pem_only` is true, only PEM parsing is attempted (for string input) |
| 721 | pub fn load_from_bytes_ex( |
| 722 | &mut self, |
| 723 | data: &[u8], |
| 724 | treat_all_as_ca: bool, |
| 725 | pem_only: bool, |
| 726 | ) -> Result<CertStats, std::io::Error> { |
| 727 | let mut stats = CertStats::default(); |
| 728 | |
| 729 | // Try to parse as PEM first |
| 730 | let mut cursor = std::io::Cursor::new(data); |
| 731 | let certs_iter = rustls_pemfile::certs(&mut cursor); |
| 732 | |
| 733 | let mut found_any = false; |
| 734 | let mut first_pem_error = None; // Store first PEM parsing error |
| 735 | for cert_result in certs_iter { |
| 736 | match cert_result { |
| 737 | Ok(cert) => { |
| 738 | found_any = true; |
| 739 | let cert_bytes = cert.to_vec(); |
| 740 | |
| 741 | // Validate that this is actually a valid X.509 certificate |
| 742 | // rustls_pemfile only does base64 decoding, not X.509 validation |
| 743 | if let Err(e) = X509Certificate::from_der(&cert_bytes) { |
| 744 | // Invalid X.509 certificate |
| 745 | return Err(cert_error::pem::parse_failed_debug(e)); |
| 746 | } |
| 747 | |
| 748 | // Add certificate using helper method (handles duplicates) |
| 749 | self.add_cert_to_store(cert_bytes, cert, treat_all_as_ca, &mut stats); |
| 750 | // Helper returns false for duplicates (skip counting) |
| 751 | } |
| 752 | Err(e) if !found_any => { |
| 753 | // PEM parsing failed on first certificate |
| 754 | if pem_only { |
| 755 | // For string input (PEM only), return "no start line" error |
| 756 | return Err(cert_error::pem::no_start_line( |
| 757 | "cadata does not contain a certificate", |
| 758 | )); |
| 759 | } |
| 760 | // Store the error and break to try DER format below |
| 761 | first_pem_error = Some(e); |
| 762 | break; |
| 763 | } |
| 764 | Err(e) => { |
| 765 | // PEM parsing failed after some certs were loaded |
| 766 | return Err(cert_error::pem::parse_failed(e)); |
| 767 | } |
| 768 | } |
| 769 | } |
| 770 | |
| 771 | // If PEM parsing found nothing, try DER format (unless pem_only) |
| 772 | // DER can have multiple certificates concatenated, so parse them sequentially |
| 773 | if !found_any && stats.total_certs == 0 { |
| 774 | // If we had a PEM parsing error, return it instead of trying DER fallback |
| 775 | // This ensures that malformed PEM files (like badcert.pem) raise an error |
| 776 | if let Some(e) = first_pem_error { |
| 777 | return Err(cert_error::pem::parse_failed(e)); |
| 778 | } |
no test coverage detected