Initial version of whck
This commit is contained in:
commit
510a0b13b9
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
.*.sw*
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "spec"]
|
||||||
|
path = spec
|
||||||
|
url = https://tildegit.org/forge/endpoints
|
117
Cargo.lock
generated
Normal file
117
Cargo.lock
generated
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.118"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "whck"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"hex",
|
||||||
|
"hmac",
|
||||||
|
"sha2",
|
||||||
|
]
|
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "whck"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
hmac = "0.12"
|
||||||
|
sha2 = "0.10"
|
||||||
|
hex = "0.4"
|
1
spec
Submodule
1
spec
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 7eb833a59e7987bc73d303a1a261a0a664c791cc
|
51
src/helpers.rs
Normal file
51
src/helpers.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
use std::env::var as env_var;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub fn whck_dir() -> PathBuf {
|
||||||
|
whck_dir_from_env()
|
||||||
|
.unwrap_or(
|
||||||
|
whck_dir_from_xdg_config()
|
||||||
|
.unwrap_or(
|
||||||
|
whck_dir_from_home()
|
||||||
|
.unwrap_or(
|
||||||
|
whck_dir_from_exe()
|
||||||
|
.expect("Exhausted all methods to find ~/.config/whck/")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn whck_dir_from_env() -> Option<PathBuf> {
|
||||||
|
env_var("WHCK_DIR").ok().map(|x| PathBuf::from(x))
|
||||||
|
}
|
||||||
|
pub fn whck_dir_from_xdg_config() -> Option<PathBuf> {
|
||||||
|
env_var("XDG_CONFIG_HOME").ok().map(|x| PathBuf::from(x).join("whck"))
|
||||||
|
}
|
||||||
|
pub fn whck_dir_from_home() -> Option<PathBuf> {
|
||||||
|
env_var("HOME").ok().map(|x| PathBuf::from(x).join(".config/whck"))
|
||||||
|
}
|
||||||
|
pub fn whck_dir_from_exe() -> Option<PathBuf> {
|
||||||
|
//std::env::current_exe().ok().and_then(|x| {
|
||||||
|
println!("{:?}", std::env::current_exe());
|
||||||
|
std::env::current_exe().ok().and_then(|x| {
|
||||||
|
// Canonicalize (resolve symlinks) in case we have a symlink from webdir
|
||||||
|
let basepath = x.canonicalize().unwrap();
|
||||||
|
let mut components = basepath.components();
|
||||||
|
println!("{:?}", components);
|
||||||
|
// We have canonicalized so component 0 is "RootDir"
|
||||||
|
if let Some(dir) = components.nth(1) {
|
||||||
|
if dir.as_os_str().to_str().unwrap() == "home" {
|
||||||
|
if let Some(user) = components.next() {
|
||||||
|
return Some(PathBuf::from("/home")
|
||||||
|
.join(user)
|
||||||
|
.join(".config/whck"));
|
||||||
|
} else {
|
||||||
|
println!("no user");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Not home");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
})
|
||||||
|
}
|
122
src/main.rs
Normal file
122
src/main.rs
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
use std::convert::From;
|
||||||
|
use std::env::args;
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
use std::io::{Read, stdin};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::process::exit;
|
||||||
|
use sha2::Sha256;
|
||||||
|
use hmac::{Hmac, Mac};
|
||||||
|
type HmacSha256 = Hmac<Sha256>;
|
||||||
|
|
||||||
|
mod helpers;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
WrongKind(String),
|
||||||
|
WrongClaim(String),
|
||||||
|
IOError(std::io::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for Error {
|
||||||
|
fn from(error: std::io::Error) -> Error {
|
||||||
|
Error::IOError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SigType {
|
||||||
|
SHA256HMAC,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Kind {
|
||||||
|
Sig(String, SigType),
|
||||||
|
Token,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Kind {
|
||||||
|
type Err = Error;
|
||||||
|
fn from_str(s: &str) -> Result<Kind, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"hmac-sha256" => {
|
||||||
|
let mut body = String::new();
|
||||||
|
let mut input = stdin();
|
||||||
|
input.read_to_string(&mut body)?;
|
||||||
|
println!("Body size: {}", body.len());
|
||||||
|
Ok(Kind::Sig(body, SigType::SHA256HMAC))
|
||||||
|
},
|
||||||
|
"token" => {
|
||||||
|
Ok(Kind::Token)
|
||||||
|
},
|
||||||
|
"help" | "-h" | "--help" => {
|
||||||
|
help();
|
||||||
|
exit(0);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
Err(Error::WrongKind(s.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kind {
|
||||||
|
// Returns true if the check succeeded, false otherwise
|
||||||
|
pub fn check(&self, secret: &str, claim: &str) -> bool {
|
||||||
|
match self {
|
||||||
|
Kind::Sig(body, sigtype) => {
|
||||||
|
println!("|{}|", &body);
|
||||||
|
match sigtype {
|
||||||
|
SigType::SHA256HMAC => {
|
||||||
|
let mut mac = HmacSha256::new_from_slice(secret.as_bytes()).unwrap();
|
||||||
|
mac.update(body.as_bytes());
|
||||||
|
let computed_sig = hex::encode(mac.finalize().into_bytes());
|
||||||
|
println!("Computed: {}", &computed_sig);
|
||||||
|
return computed_sig == claim;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Kind::Token => {
|
||||||
|
return secret == claim;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn help() {
|
||||||
|
println!("whck KIND IDENTIFIER CLAIM BODY");
|
||||||
|
println!(" KIND: sig/token");
|
||||||
|
println!(" IDENTIFIER: the unique identifier for the stored secret in $XDG_CONFIG_DIR/whck/ folder");
|
||||||
|
println!(" CLAIM: the claimed sig/token to verify");
|
||||||
|
println!("");
|
||||||
|
println!("If you're checking a signature, don't forget to pass the body as STDIN");
|
||||||
|
println!("NOTE: If you're protecting secrets from other users (chmod -R 700 $XDG_CONFIG_HOME/whck),");
|
||||||
|
println!("don't forget to set the suid bit on the program (chmod u+s $(which whck)).")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panic on malformed $XDG_CONFIG_DIR
|
||||||
|
fn read_secret(id: &str) -> String {
|
||||||
|
if id.starts_with("/") || id.contains("/../") {
|
||||||
|
println!("Malformed identifier");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// $WHCK_DIR is used for tests
|
||||||
|
// Otherwise, try $XDG_CONFIG_HOME/whck or $HOME/.config/whck
|
||||||
|
// When home isn't defined try to check if $0 starts with /home and if so assume $HOME is there
|
||||||
|
let mut secret_path = helpers::whck_dir();
|
||||||
|
secret_path.push(id);
|
||||||
|
let secret = read_to_string(&secret_path).expect(&format!("Failed to read secret from: {}", &secret_path.to_str().unwrap()));
|
||||||
|
return secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
let mut cli_args = args();
|
||||||
|
let arg_kind = cli_args.nth(1).expect("Missing argument: KIND");
|
||||||
|
let kind = Kind::from_str(&arg_kind)?;
|
||||||
|
let id = cli_args.nth(0).expect("Missing argument: IDENTIFIER");
|
||||||
|
let claim = cli_args.nth(0).expect("Missing argument: CLAIM");
|
||||||
|
|
||||||
|
let secret = read_secret(&id);
|
||||||
|
if ! kind.check(&secret, &claim) {
|
||||||
|
return Err(Error::WrongClaim(claim.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
24
test.sh
Executable file
24
test.sh
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
SCRIPTDIR="$(dirname "$0")"
|
||||||
|
ORIGDIR="$(pwd)"
|
||||||
|
|
||||||
|
if [ ! -f "$SCRIPTDIR"/spec/test_cli.sh ]; then
|
||||||
|
echo "Submodule not cloned yet. Doing it now"
|
||||||
|
cd $SCRIPTDIR
|
||||||
|
git submodule init
|
||||||
|
if ! git submodule update; then
|
||||||
|
echo "Failed to download submodules. Are you connected to the internet?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$SCRIPTDIR"/target/release/whck ]; then
|
||||||
|
cargo build --release
|
||||||
|
"$SCRIPTDIR"/spec/test_cli.sh "$SCRIPTDIR"/target/release/whck
|
||||||
|
else
|
||||||
|
cargo build
|
||||||
|
"$SCRIPTDIR"/spec/test_cli.sh "$SCRIPTDIR"/target/debug/whck
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$ORIGDIR"
|
Loading…
Reference in New Issue
Block a user