Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

crates/gunnar-grpc/tests/security_key.rs

//! **A FIDO2 security key (`sk-ssh-ed25519`) signs for the CLI — with a touch**
//! (5.4 §3b passkey-cli, owner 2026-10-10: "CLI uses a FIDO2 sk-ssh key or a
//! `gunnar login` browser device flow").
//!
//! An sk key's private half never leaves the authenticator, and the signature
//! carries the authenticator's flags. ssh-key verifies the signature over
//! those flags but does not READ them: a credential the key produced without
//! anybody touching it (`no-touch-required`, or malware driving a key left
//! plugged in) would verify. gunnar's one verifier refuses it.

mod security_key_common;

use security_key_common::{SecurityKey, USER_PRESENT};

const NONCE: &str = "0123456789abcdef0123456789abcdef";

#[test]
fn an_sk_credential_signed_with_a_touch_verifies() {
    let mut key = SecurityKey::new(0x21);
    let credential = key.credential(1_700_000_000_000, NONCE, "Repos.List", USER_PRESENT);
    assert!(
        gunnar_grpc::auth::verify_signature(&key.openssh(), &credential),
        "an sk-ssh-ed25519 key the person touched is a credential gunnar accepts"
    );
}

#[test]
fn an_sk_credential_signed_without_a_touch_is_refused() {
    let mut key = SecurityKey::new(0x22);
    let credential = key.credential(1_700_000_000_000, NONCE, "Repos.List", 0x00);
    assert!(
        !gunnar_grpc::auth::verify_signature(&key.openssh(), &credential),
        "a security key that signed with nobody present is not the person"
    );
    // Not a dead check: the same key, touched, verifies.
    let touched = key.credential(1_700_000_000_000, NONCE, "Repos.List", USER_PRESENT | 0x04);
    assert!(gunnar_grpc::auth::verify_signature(
        &key.openssh(),
        &touched
    ));
}

#[test]
fn an_sk_credential_is_bound_to_its_method_like_any_other() {
    let mut key = SecurityKey::new(0x23);
    let mut credential = key.credential(1_700_000_000_000, NONCE, "Repos.List", USER_PRESENT);
    credential.method = Some("Admin.Shutdown".to_owned());
    assert!(!gunnar_grpc::auth::verify_signature(
        &key.openssh(),
        &credential
    ));
}