141 lines
3.9 KiB
Rust
141 lines
3.9 KiB
Rust
use dosh::auth::{
|
|
build_bootstrap, decode_bootstrap, encode_bootstrap, load_or_create_server_secret,
|
|
open_attach_ticket, verify_attach_ticket, verify_bootstrap,
|
|
};
|
|
use dosh::config::ServerConfig;
|
|
use dosh::crypto;
|
|
use dosh::protocol::{self, CLIENT_TO_SERVER, PacketKind, ReplayWindow};
|
|
|
|
#[test]
|
|
fn bootstrap_round_trips_and_verifies() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let config = ServerConfig {
|
|
secret_path: dir.path().join("secret").display().to_string(),
|
|
..ServerConfig::default()
|
|
};
|
|
let secret = load_or_create_server_secret(&config).unwrap();
|
|
let nonce = crypto::random_12();
|
|
let resp = build_bootstrap(
|
|
&config,
|
|
&secret,
|
|
"user".to_string(),
|
|
"default".to_string(),
|
|
"read-write".to_string(),
|
|
(80, 24),
|
|
nonce,
|
|
"127.0.0.1".to_string(),
|
|
)
|
|
.unwrap();
|
|
assert!(verify_bootstrap(&resp, &secret).unwrap());
|
|
let encoded = encode_bootstrap(&resp).unwrap();
|
|
let decoded = decode_bootstrap(&encoded).unwrap();
|
|
assert_eq!(decoded.session, "default");
|
|
assert_eq!(decoded.session_key, resp.session_key);
|
|
}
|
|
|
|
#[test]
|
|
fn encrypted_packet_round_trips() {
|
|
let key = crypto::random_32();
|
|
let conn_id = crypto::random_16();
|
|
let packet = protocol::encode_encrypted(
|
|
PacketKind::Input,
|
|
conn_id,
|
|
7,
|
|
0,
|
|
&key,
|
|
CLIENT_TO_SERVER,
|
|
b"hello",
|
|
)
|
|
.unwrap();
|
|
let decoded = protocol::decode(&packet).unwrap();
|
|
assert_eq!(decoded.header.kind, PacketKind::Input);
|
|
assert_eq!(decoded.header.conn_id, conn_id);
|
|
assert_eq!(
|
|
decoded.header.session_key_id,
|
|
protocol::session_key_id(&key)
|
|
);
|
|
let plain = protocol::decrypt_body(&decoded, &key, CLIENT_TO_SERVER).unwrap();
|
|
assert_eq!(plain, b"hello");
|
|
}
|
|
|
|
#[test]
|
|
fn encrypted_packet_rejects_wrong_session_key_id_before_decrypt() {
|
|
let key = crypto::random_32();
|
|
let wrong_key = crypto::random_32();
|
|
let packet = protocol::encode_encrypted(
|
|
PacketKind::Input,
|
|
crypto::random_16(),
|
|
1,
|
|
0,
|
|
&key,
|
|
CLIENT_TO_SERVER,
|
|
b"hello",
|
|
)
|
|
.unwrap();
|
|
let decoded = protocol::decode(&packet).unwrap();
|
|
let err = protocol::decrypt_body(&decoded, &wrong_key, CLIENT_TO_SERVER).unwrap_err();
|
|
assert!(err.to_string().contains("session key id"));
|
|
}
|
|
|
|
#[test]
|
|
fn attach_ticket_is_sealed_and_verifies_scope() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let config = ServerConfig {
|
|
secret_path: dir.path().join("secret").display().to_string(),
|
|
..ServerConfig::default()
|
|
};
|
|
let secret = load_or_create_server_secret(&config).unwrap();
|
|
let resp = build_bootstrap(
|
|
&config,
|
|
&secret,
|
|
"user".to_string(),
|
|
"work".to_string(),
|
|
"view-only".to_string(),
|
|
(100, 30),
|
|
crypto::random_12(),
|
|
"127.0.0.1".to_string(),
|
|
)
|
|
.unwrap();
|
|
|
|
let opened = open_attach_ticket(&secret, &resp.attach_ticket).unwrap();
|
|
assert_eq!(opened.session, "work");
|
|
assert_eq!(opened.mode, "view-only");
|
|
assert_eq!(opened.psk, resp.attach_ticket_psk);
|
|
|
|
assert!(
|
|
verify_attach_ticket(
|
|
&secret,
|
|
&resp.attach_ticket,
|
|
&resp.attach_ticket_psk,
|
|
"work",
|
|
"view-only",
|
|
)
|
|
.unwrap()
|
|
.is_some()
|
|
);
|
|
assert!(
|
|
verify_attach_ticket(
|
|
&secret,
|
|
&resp.attach_ticket,
|
|
&resp.attach_ticket_psk,
|
|
"default",
|
|
"view-only",
|
|
)
|
|
.unwrap()
|
|
.is_none()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn replay_window_rejects_duplicates_but_allows_bounded_out_of_order() {
|
|
let mut replay = ReplayWindow::new(8);
|
|
assert!(replay.accept(10));
|
|
assert!(!replay.accept(10));
|
|
assert!(replay.accept(12));
|
|
assert!(replay.accept(11));
|
|
assert!(!replay.accept(11));
|
|
assert!(replay.accept(18));
|
|
assert!(!replay.accept(9));
|
|
assert!(!replay.accept(0));
|
|
}
|