Compare commits
2 Commits
zeroized-b
...
terminate-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a30bef11da | ||
| 357726bc5d |
@@ -11,7 +11,7 @@ use arbiter_crypto::safecell::{SafeCell, SafeCellHandle as _};
|
||||
use state::State;
|
||||
|
||||
use chacha20poly1305::{AeadInPlace, KeyInit as _, XChaCha20Poly1305, XNonce};
|
||||
use kameo::{Actor, error::SendError, messages, prelude::Message};
|
||||
use kameo::{Actor, error::SendError, messages, prelude::{Context, Message}};
|
||||
use kameo_actors::message_bus::Register;
|
||||
use tokio::sync::oneshot;
|
||||
use tracing::{error, info};
|
||||
@@ -143,12 +143,13 @@ impl VaultGate {
|
||||
})
|
||||
}
|
||||
|
||||
#[message]
|
||||
#[message(ctx)]
|
||||
pub async fn handle_unseal_encrypted_key(
|
||||
&mut self,
|
||||
nonce: Vec<u8>,
|
||||
ciphertext: Vec<u8>,
|
||||
associated_data: Vec<u8>,
|
||||
ctx: &mut Context<Self, Result<(), Error>>,
|
||||
) -> Result<(), Error> {
|
||||
let State::ReadyForExchange { secret, .. } = &self.state else {
|
||||
return Err(Error::State);
|
||||
@@ -172,7 +173,12 @@ impl VaultGate {
|
||||
Ok(())
|
||||
}
|
||||
Err(SendError::HandlerError(vault::Error::InvalidKey)) => Err(Error::InvalidKey),
|
||||
Err(SendError::HandlerError(vault::Error::LockedOut)) => Err(Error::LockedOut),
|
||||
Err(SendError::HandlerError(vault::Error::LockedOut)) => {
|
||||
// Vault is permanently locked — terminate this gate so the
|
||||
// run_vault_gate loop breaks and the connection is closed.
|
||||
ctx.stop();
|
||||
Err(Error::LockedOut)
|
||||
}
|
||||
Err(SendError::HandlerError(err)) => {
|
||||
error!(?err, "Vault failed to unseal key");
|
||||
Err(Error::InvalidKey)
|
||||
@@ -245,7 +251,7 @@ impl Message<events::Bootstrapped> for VaultGate {
|
||||
async fn handle(
|
||||
&mut self,
|
||||
_: events::Bootstrapped,
|
||||
ctx: &mut kameo::prelude::Context<Self, Self::Reply>,
|
||||
ctx: &mut Context<Self, Self::Reply>,
|
||||
) -> Self::Reply {
|
||||
let result = async {
|
||||
let mut conn = self
|
||||
@@ -281,7 +287,7 @@ impl Message<events::Unsealed> for VaultGate {
|
||||
async fn handle(
|
||||
&mut self,
|
||||
_: events::Unsealed,
|
||||
ctx: &mut kameo::prelude::Context<Self, Self::Reply>,
|
||||
ctx: &mut Context<Self, Self::Reply>,
|
||||
) -> Self::Reply {
|
||||
if let Some(tx) = self.promotion_tx.take() {
|
||||
let _ = tx.send(Ok(()));
|
||||
|
||||
@@ -140,6 +140,47 @@ pub async fn unseal_corrupted_ciphertext() {
|
||||
));
|
||||
}
|
||||
|
||||
/// After MAX_UNSEAL_ATTEMPTS wrong keys, the vault locks and the VaultGate
|
||||
/// must stop itself so the connection is dropped.
|
||||
#[tokio::test]
|
||||
#[test_log::test]
|
||||
pub async fn lockout_stops_vault_gate() {
|
||||
use kameo::error::SendError;
|
||||
|
||||
let seal_key = b"real-seal-key";
|
||||
let (_db, gate, _promotion_rx) = setup_sealed_gate(seal_key).await;
|
||||
|
||||
// Exhaust all MAX_UNSEAL_ATTEMPTS (5) with wrong keys; each returns InvalidKey.
|
||||
for _ in 0..5 {
|
||||
let encrypted_key = client_dh_encrypt(&gate, b"wrong-key").await;
|
||||
assert!(matches!(
|
||||
gate.ask(encrypted_key).await,
|
||||
Err(SendError::HandlerError(VaultGateError::InvalidKey))
|
||||
));
|
||||
}
|
||||
|
||||
// Sixth attempt: vault is now locked, returns LockedOut, and the gate stops itself.
|
||||
let encrypted_key = client_dh_encrypt(&gate, b"wrong-key").await;
|
||||
assert!(matches!(
|
||||
gate.ask(encrypted_key).await,
|
||||
Err(SendError::HandlerError(VaultGateError::LockedOut))
|
||||
));
|
||||
|
||||
// Give the actor scheduler time to process the stop signal.
|
||||
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
|
||||
|
||||
// Any subsequent message must be rejected because the gate is stopped.
|
||||
let client_secret = EphemeralSecret::random();
|
||||
let client_public = PublicKey::from(&client_secret);
|
||||
assert!(
|
||||
matches!(
|
||||
gate.ask(HandleHandshake { client_pubkey: client_public }).await,
|
||||
Err(SendError::ActorNotRunning(_))
|
||||
),
|
||||
"VaultGate must be stopped after LockedOut"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[test_log::test]
|
||||
pub async fn unseal_retry_after_invalid_key() {
|
||||
|
||||
Reference in New Issue
Block a user