From 60155a5530bf737a281e527575c02b32065fe930 Mon Sep 17 00:00:00 2001 From: wucke13 Date: Wed, 8 Mar 2023 22:33:13 +0100 Subject: [PATCH] add first draft of rp rust binary --- Cargo.lock | 82 +++++++++++- Cargo.toml | 1 + rp | 352 ------------------------------------------------- rp/Cargo.toml | 13 ++ rp/src/main.rs | 55 ++++++++ 5 files changed, 150 insertions(+), 353 deletions(-) delete mode 100755 rp create mode 100644 rp/Cargo.toml create mode 100644 rp/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 40b315b5..59a591d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,7 +186,7 @@ checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", "bitflags", - "clap_lex", + "clap_lex 0.2.4", "indexmap", "strsim", "termcolor", @@ -194,6 +194,34 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "clap" +version = "4.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" +dependencies = [ + "bitflags", + "clap_derive", + "clap_lex 0.3.2", + "is-terminal", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "clap_lex" version = "0.2.4" @@ -203,6 +231,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clap_lex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "cmake" version = "0.1.49" @@ -429,6 +466,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -776,6 +819,30 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.51" @@ -883,6 +950,13 @@ dependencies = [ "thiserror", ] +[[package]] +name = "rp" +version = "0.1.0" +dependencies = [ + "clap 4.1.8", +] + [[package]] name = "rustc-demangle" version = "0.1.21" @@ -1176,6 +1250,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "walkdir" version = "2.3.2" diff --git a/Cargo.toml b/Cargo.toml index 392c751d..89b8e987 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,4 +2,5 @@ members = [ "rosenpass", + "rp", ] \ No newline at end of file diff --git a/rp b/rp deleted file mode 100755 index ce57675b..00000000 --- a/rp +++ /dev/null @@ -1,352 +0,0 @@ -#!/usr/bin/env bash - -set -e - -# String formatting subsystem - -formatting_init() { - endl=$'\n' -} - -enquote() { - while (( $# > 1 )); do - printf "%q " "${1}"; shift - done - if (( $# == 1 )); then - printf "%q" "${1}"; shift - fi -} - -multiline() { - # shellcheck disable=SC1004 - echo "${1} " | awk ' - function pm(a, b, l) { - return length(a) > l \ - && length(b) > l \ - && substr(a, 1, l+1) == substr(b, 1, l+1) \ - ? pm(a, b, l+1) : l; - } - - !started && $0 !~ /^[ \t]*$/ { - started=1 - match($0, /^[ \t]*/) - prefix=substr($0, 1, RLENGTH) - } - - started { - print(substr($0, 1 + pm($0, prefix))); - } - ' -} - -dbg() { - echo >&2 "$@" -} - -# Cleanup subsystem (sigterm) - -cleanup_init() { - cleanup_actions=() - trap cleanup_apply exit -} - -cleanup_apply() { - local f - for f in "${cleanup_actions[@]}"; do - eval "${f}" - done -} - -cleanup() { - cleanup_actions+=("$(multiline "${1}")") -} - -# Transactional execution subsystem - -frag_init() { - explain=0 - frag_transaction=() - frag " - #! /bin/bash - set -e" -} - -frag_apply() { - local f - for f in "${frag_transaction[@]}"; do - if (( explain == 1 )); then - dbg "${f}" - fi - eval "${f}" - done -} - -frag() { - frag_transaction+=("$(multiline "${1}")") -} - -frag_append() { - local len; len="${#frag_transaction[@]}" - frag_transaction=("${frag_transaction[@]:0:len-1}" "${frag_transaction[len-1]}${1}") -} - -frag_append_esc() { - frag_append " \\${endl}${1}" -} - -# Usage documentation subsystem -usage_init() { - usagestack=("${script}") -} - -usage_snap() { - echo "${#usagestack}" -} - -usage_restore() { - local n; n="${1}" - dbg REST "${1}" - usagestack=("${usagestack[@]:0:n-2}") -} - - -usage() { - dbg "Usage: ${usagestack[*]}" -} - -fatal() { - dbg "FATAL: $*" - usage - exit 1 -} - -genkey() { - usagestack+=("PRIVATE_KEYS_DIR") - local skdir - skdir="${1%/}"; shift || fatal "Required positional argument: PRIVATE_KEYS_DIR" - - while (( $# > 0 )); do - local arg; arg="$1"; shift - case "${arg}" in - -h | -help | --help | help) usage; return 0 ;; - *) fatal "Unknown option ${arg}";; - esac - done - - if test -e "${skdir}"; then - fatal "PRIVATE_KEYS_DIR \"${skdir}\" already exists" - fi - - frag " - umask 077 - mkdir -p $(enquote "${skdir}") - wg genkey > $(enquote "${skdir}"/wgsk) - $(enquote "${binary}") keygen \\ - private-key $(enquote "${skdir}"/pqsk) \\ - public-key $(enquote "${skdir}"/pqpk)" -} - -pubkey() { - usagestack+=("PRIVATE_KEYS_DIR" "PUBLIC_KEYS_DIR") - local skdir pkdir - skdir="${1%/}"; shift || fatal "Required positional argument: PRIVATE_KEYS_DIR" - pkdir="${1%/}"; shift || fatal "Required positional argument: PUBLIC_KEYS_DIR" - - while (( $# > 0 )); do - local arg; arg="$1"; shift - case "${arg}" in - -h | -help | --help | help) usage; exit 0;; - *) fatal "Unknown option ${arg}";; - esac - done - - if test -e "${pkdir}"; then - fatal "PUBLIC_KEYS_DIR \"${pkdir}\" already exists" - fi - - frag " - mkdir -p $(enquote "${pkdir}") - wg pubkey < $(enquote "${skdir}"/wgsk) > $(enquote "${pkdir}/wgpk") - cp $(enquote "${skdir}"/pqpk) $(enquote "${pkdir}/pqpk")" -} - -exchange() { - usagestack+=("PRIVATE_KEYS_DIR" "[dev ]" "[listen :]" "[peer PUBLIC_KEYS_DIR [endpoint :] [persistent-keepalive ] [allowed-ips /[,/]...]]...") - local skdir dev lport - dev="${project_name}0" - skdir="${1%/}"; shift || fatal "Required positional argument: PRIVATE_KEYS_DIR" - - while (( $# > 0 )); do - local arg; arg="$1"; shift - case "${arg}" in - dev) dev="${1}"; shift || fatal "dev option requires parameter";; - peer) set -- "peer" "$@"; break;; # Parsed down below - listen) - local listen; listen="${1}"; - lip="${listen%:*}"; - lport="${listen/*:/}"; - if [[ "$lip" = "$lport" ]]; then - lip="[0::0]" - fi - shift;; - -h | -help | --help | help) usage; return 0;; - *) fatal "Unknown option ${arg}";; - esac - done - - if (( $# == 0 )); then - fatal "Needs at least one peer specified" - fi - - frag " - # Create the Wireguard interface - ip link add dev $(enquote "${dev}") type wireguard || true" - - cleanup " - ip link del dev $(enquote "${dev}") || true" - - frag " - ip link set dev $(enquote "${dev}") up" - - frag " - # Deploy the classic wireguard private key - wg set $(enquote "${dev}") private-key $(enquote "${skdir}/wgsk")" - - - if test -n "${lport}"; then - frag_append "listen-port $(enquote "$(( lport + 1 ))")" - fi - - frag " - # Launch the post quantum wireguard exchange daemon - $(enquote "${binary}") exchange" - - if (( verbose == 1 )); then - frag_append "verbose" - fi - - frag_append_esc " private-key $(enquote "${skdir}/pqsk")" - frag_append_esc " public-key $(enquote "${skdir}/pqpk")" - - if test -n "${lport}"; then - frag_append_esc " listen $(enquote "${lip}:${lport}")" - fi - - usagestack+=("peer" "PUBLIC_KEYS_DIR endpoint IP:PORT") - - while (( $# > 0 )); do - shift; # Skip "peer" argument - - local peerdir ip port keepalive allowedips - peerdir="${1%/}"; shift || fatal "Required peer argument: PUBLIC_KEYS_DIR" - - while (( $# > 0 )); do - local arg; arg="$1"; shift - case "${arg}" in - peer) set -- "peer" "$@"; break;; # Next peer - endpoint) ip="${1%:*}"; port="${1/*:/}"; shift;; - persistent-keepalive) keepalive="${1}"; shift;; - allowed-ips) allowedips="${1}"; shift;; - -h | -help | --help | help) usage; return 0;; - *) fatal "Unknown option ${arg}";; - esac - done - - # Public key - frag_append_esc " peer public-key $(enquote "${peerdir}/pqpk")" - - # PSK - local pskfile; pskfile="${peerdir}/psk" - if test -f "${pskfile}"; then - frag_append_esc " preshared-key $(enquote "${pskfile}")" - fi - - - if test -n "${ip}"; then - frag_append_esc " endpoint $(enquote "${ip}:${port}")" - fi - - frag_append_esc " wireguard $(enquote "${dev}") $(enquote "$(cat "${peerdir}/wgpk")")" - - if test -n "${ip}"; then - frag_append_esc " endpoint $(enquote "${ip}:$(( port + 1 ))")" - fi - - if test -n "${keepalive}"; then - frag_append_esc " persistent-keepalive $(enquote "${keepalive}")" - fi - - if test -n "${allowedips}"; then - frag_append_esc " allowed-ips $(enquote "${allowedips}")" - fi - done -} - -find_rosenpass_binary() { - local binary; binary="" - if [[ -n "${gitdir}" ]]; then - # If rp is run from the git repo, use the newest build artifact - binary=$( - find "${gitdir}/result/bin/${project_name}" \ - "${gitdir}"/target/{release,debug}/"${project_name}" \ - -printf "%T@ %p\n" 2>/dev/null \ - | sort -nr \ - | awk 'NR==1 { print($2) }' - ) - elif [[ -n "${nixdir}" ]]; then - # If rp is run from nix, use the nix-installed rosenpass version - binary="${nixdir}/bin/${project_name}" - fi - - if [[ -z "${binary}" ]]; then - binary="${project_name}" - fi - - echo "${binary}" -} - -main() { - formatting_init - cleanup_init - usage_init - frag_init - - project_name="rosenpass" - verbose=0 - scriptdir="$(dirname "${script}")" - gitdir="$(git -C "${scriptdir}" rev-parse --show-toplevel 2>/dev/null)" || true - nixdir="$(readlink -f result/bin/rp | grep -Pio '^/nix/store/[^/]+(?=/bin/[^/]+)')" || true - binary="$(find_rosenpass_binary)" - - # Parse command - - usagestack+=("[explain]" "[verbose]" "genkey|pubkey|exchange" "[ARGS]...") - - local cmd - while (( $# > 0 )); do - local arg; arg="$1"; shift - case "${arg}" in - genkey|pubkey|exchange) cmd="${arg}"; break;; - explain) explain=1;; - verbose) verbose=1;; - -h | -help | --help | help) usage; return 0 ;; - *) fatal "Unknown command ${arg}";; - esac - done - - test -n "${cmd}" || fatal "No command supplied" - usagestack=("${script}") - - # Execute command - - usagestack+=("${cmd}") - "${cmd}" "$@" - usagestack=("${script}") - - # Apply transaction - - frag_apply -} - -script="$0" -main "$@" diff --git a/rp/Cargo.toml b/rp/Cargo.toml new file mode 100644 index 00000000..39088617 --- /dev/null +++ b/rp/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "rp" +version = "0.1.0" +edition = "2021" +authors = ["wucke13 ", "Karolin Varner "] +license = "MIT OR Apache-2.0" +description = "Build post-quantum-secure VPNs with WireGuard!" +homepage = "https://rosenpass.eu/" +repository = "https://github.com/rosenpass/rosenpass" +readme = "../readme.md" + +[dependencies] +clap = { version = "4.1.8", features = ["derive"] } diff --git a/rp/src/main.rs b/rp/src/main.rs new file mode 100644 index 00000000..c1c23b14 --- /dev/null +++ b/rp/src/main.rs @@ -0,0 +1,55 @@ +use std::path::PathBuf; + +use clap::{Parser, Subcommand}; + +// Usage: ../rp-old [explain] [verbose] genkey|pubkey|exchange [ARGS]... + +/// Simple program to greet a person +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Cli { + /// Explain what is done + #[arg(short, long)] + explain: bool, + + /// Be verbose about what's going on + #[arg(short, long)] + verbose: bool, + + #[command(subcommand)] + command: Command, +} + +/// Doc comment +#[derive(Subcommand, Debug)] +// #[command(PARENT CMD ATTRIBUTE)] +enum Command { + /// Generate a keypair + // --- Requirements --- + // requires wireguard + // should not exist before + // should be dir after + // should contain three files after pqpk, pqsk, wgsk + Genkey { + private_keys_dir: PathBuf, + }, + + /// Generate public keys + // --- Requirements --- + // requires wireguard + // requires private_keys_dir to exist + // should create public_keys_dir + // should copy pqpk from private_ to public_keys_dir + // should generate wgpk to public_keys_dir + Pubkey { + private_keys_dir: PathBuf, + public_keys_dir: PathBuf, + }, + + Exchange {}, +} +fn main() { + let args = Cli::parse(); + + println!("{args:#?}"); +}