Complete handshake and create session Track which CA certificate from capath was used to verify peer This simulates lazy loading behavior: capath certificates are only added to get_ca_certs() after they're actually used in a handshake.
(&self)
| 2499 | /// This simulates lazy loading behavior: capath certificates |
| 2500 | /// are only added to get_ca_certs() after they're actually used in a handshake. |
| 2501 | fn track_used_ca_from_capath(&self) -> Result<(), String> { |
| 2502 | // Extract capath_certs, releasing context lock quickly |
| 2503 | let capath_certs = { |
| 2504 | let context = self.context.read(); |
| 2505 | let certs = context.capath_certs_der.read(); |
| 2506 | if certs.is_empty() { |
| 2507 | return Ok(()); |
| 2508 | } |
| 2509 | certs.clone() |
| 2510 | }; |
| 2511 | |
| 2512 | // Extract peer certificates, releasing connection lock quickly |
| 2513 | let top_cert_der = { |
| 2514 | let conn_guard = self.connection.lock(); |
| 2515 | let conn = conn_guard.as_ref().ok_or("No connection")?; |
| 2516 | let peer_certs = conn.peer_certificates().ok_or("No peer certificates")?; |
| 2517 | if peer_certs.is_empty() { |
| 2518 | return Ok(()); |
| 2519 | } |
| 2520 | peer_certs |
| 2521 | .iter() |
| 2522 | .map(|c| c.as_ref().to_vec()) |
| 2523 | .next_back() |
| 2524 | .expect("is_empty checked above") |
| 2525 | }; |
| 2526 | |
| 2527 | // Get the top certificate in the chain (closest to root) |
| 2528 | // Note: Server usually doesn't send the root CA, so we check the last cert's issuer |
| 2529 | let (_, top_cert) = x509_parser::parse_x509_certificate(&top_cert_der) |
| 2530 | .map_err(|e| format!("Failed to parse top cert: {e}"))?; |
| 2531 | |
| 2532 | let top_issuer = top_cert.issuer(); |
| 2533 | |
| 2534 | // Find matching CA in capath certs (skip unparseable certificates) |
| 2535 | let matching_ca = capath_certs.iter().find_map(|ca_der| { |
| 2536 | let (_, ca) = x509_parser::parse_x509_certificate(ca_der).ok()?; |
| 2537 | // Check if this CA is self-signed (root CA) and matches the issuer |
| 2538 | (ca.subject() == ca.issuer() && ca.subject() == top_issuer).then(|| ca_der.clone()) |
| 2539 | }); |
| 2540 | |
| 2541 | // Update ca_certs_der if we found a match |
| 2542 | if let Some(ca_der) = matching_ca { |
| 2543 | let context = self.context.read(); |
| 2544 | let mut ca_certs_der = context.ca_certs_der.write(); |
| 2545 | if !ca_certs_der.iter().any(|c| c == &ca_der) { |
| 2546 | ca_certs_der.push(ca_der); |
| 2547 | } |
| 2548 | } |
| 2549 | |
| 2550 | Ok(()) |
| 2551 | } |
| 2552 | |
| 2553 | fn complete_handshake(&self, vm: &VirtualMachine) -> PyResult<()> { |
| 2554 | *self.handshake_done.lock() = true; |
no test coverage detected