()
| 742 | |
| 743 | #[tokio::test] |
| 744 | async fn test_reload_mtls_ca_rotation() { |
| 745 | install_rustls_provider(); |
| 746 | |
| 747 | let dir = tempfile::tempdir().expect("failed to create tempdir"); |
| 748 | let (initial_ca_cert, initial_ca_key) = generate_test_certs_with_ca(dir.path()); |
| 749 | |
| 750 | let acceptor = TlsAcceptor::from_files( |
| 751 | &dir.path().join("server-cert.pem"), |
| 752 | &dir.path().join("server-key.pem"), |
| 753 | Some(&dir.path().join("ca.pem")), |
| 754 | true, // require mTLS |
| 755 | ) |
| 756 | .expect("failed to build acceptor with mTLS"); |
| 757 | |
| 758 | // Generate new CA and overwrite ca.pem |
| 759 | let mut new_ca_params = |
| 760 | CertificateParams::new(Vec::<String>::new()).expect("failed to create CA params"); |
| 761 | new_ca_params.is_ca = IsCa::Ca(rcgen::BasicConstraints::Unconstrained); |
| 762 | new_ca_params |
| 763 | .distinguished_name |
| 764 | .push(rcgen::DnType::CommonName, "new-ca"); |
| 765 | let new_ca_key = KeyPair::generate().expect("failed to generate new CA key"); |
| 766 | let new_ca_cert = new_ca_params |
| 767 | .self_signed(&new_ca_key) |
| 768 | .expect("failed to sign new CA cert"); |
| 769 | std::fs::write(dir.path().join("ca.pem"), new_ca_cert.pem().as_bytes()) |
| 770 | .expect("failed to write new CA"); |
| 771 | |
| 772 | // Generate new server cert signed by new CA and reload |
| 773 | generate_server_cert(&new_ca_cert, &new_ca_key, dir.path()); |
| 774 | acceptor |
| 775 | .reload() |
| 776 | .expect("reload with new CA should succeed"); |
| 777 | |
| 778 | // Generate client cert signed by new CA, write to files |
| 779 | let client_key = KeyPair::generate().expect("failed to generate client key"); |
| 780 | let mut client_params = |
| 781 | CertificateParams::new(Vec::<String>::new()).expect("failed to create client params"); |
| 782 | client_params |
| 783 | .distinguished_name |
| 784 | .push(rcgen::DnType::CommonName, "test-client"); |
| 785 | client_params.key_usages = vec![ |
| 786 | KeyUsagePurpose::DigitalSignature, |
| 787 | KeyUsagePurpose::KeyEncipherment, |
| 788 | ]; |
| 789 | let client_cert = client_params |
| 790 | .signed_by(&client_key, &new_ca_cert, &new_ca_key) |
| 791 | .expect("failed to sign client cert"); |
| 792 | |
| 793 | // Write client cert + key as PEM files and load via load_certs/load_key |
| 794 | let client_cert_path = dir.path().join("client-cert.pem"); |
| 795 | let client_key_path = dir.path().join("client-key.pem"); |
| 796 | std::fs::write(&client_cert_path, client_cert.pem().as_bytes()) |
| 797 | .expect("failed to write client cert"); |
| 798 | std::fs::write(&client_key_path, client_key.serialize_pem().as_bytes()) |
| 799 | .expect("failed to write client key"); |
| 800 | |
| 801 | let client_cert_chain = load_certs(&client_cert_path).expect("failed to load client cert"); |
nothing calls this directly
no test coverage detected