//! `test_pki_mutual_auth` — the server must reject a client whose certificate was issued by a //! different CA, and must reject a client that presents a valid certificate but a forged signature //! (one made with a key that does not match the certificate). mod common; use aura_pki::AuraCa; use aura_proto::{client_handshake, server_handshake, ClientConfig, ProtoError}; use tokio::io::split; /// Run a handshake and return both sides' results. async fn run( client_cfg: ClientConfig, server_cfg: aura_proto::ServerConfig, ) -> (Result<(), ProtoError>, Result, ProtoError>) { let (client_end, server_end) = tokio::io::duplex(64 * 1024); let (c_read, c_write) = split(client_end); let (s_read, s_write) = split(server_end); let client = tokio::spawn(async move { client_handshake(c_read, c_write, &client_cfg) .await .map(|_| ()) }); let server = tokio::spawn(async move { server_handshake(s_read, s_write, &server_cfg) .await .map(|s| s.peer_id().map(str::to_string)) }); let (c, s) = tokio::join!(client, server); (c.expect("client task"), s.expect("server task")) } #[tokio::test] async fn wrong_ca_client_cert_is_rejected() { // The legitimate server-side PKI. let pki = common::mint_pki("vpn.aura.example", "client-alpha"); // An attacker CA issues a client cert with a plausible CN, but it does NOT chain to the // server's trusted CA. let rogue_ca = AuraCa::generate("Rogue CA").expect("rogue CA"); let rogue_client = rogue_ca .issue_client_cert("client-alpha") .expect("rogue client cert"); let client_cfg = ClientConfig { ca_cert_pem: pki.ca_cert_pem.clone(), client_cert_pem: rogue_client.cert_pem, client_key_pem: rogue_client.key_pem, server_name: pki.server_name.clone(), }; let (_client_res, server_res) = run(client_cfg, pki.server_config()).await; // The server must fail verifying the client chain against its trusted CA. assert!( matches!(server_res, Err(ProtoError::Pki(_))), "expected a PKI verification failure, got {server_res:?}" ); } #[tokio::test] async fn forged_client_signature_is_rejected() { let pki = common::mint_pki("vpn.aura.example", "client-alpha"); // Mint an unrelated P-256 keypair (via a throwaway issued cert) to use as the WRONG signing // key. We pair the legitimate client's certificate with this mismatched private key: the chain // verifies fine, but the signature over the transcript is made with a key that does not match // the certificate's public key, so signature verification must fail. let throwaway_ca = AuraCa::generate("throwaway").expect("throwaway CA"); let mismatched = throwaway_ca .issue_client_cert("mismatched") .expect("throwaway cert"); let client_cfg = ClientConfig { ca_cert_pem: pki.ca_cert_pem.clone(), client_cert_pem: pki.client_cert_pem.clone(), // valid cert (chains to trusted CA) client_key_pem: mismatched.key_pem, // WRONG key -> forged signature server_name: pki.server_name.clone(), }; let (_client_res, server_res) = run(client_cfg, pki.server_config()).await; assert!( matches!(server_res, Err(ProtoError::Signature(_))), "expected a signature verification failure, got {server_res:?}" ); }