From: Amélia Coutard-Sander Date: Thu, 5 Dec 2024 09:21:12 +0000 (+0100) Subject: Authenticated pushing via the identity service X-Git-Url: https://git.ameliathe1st.gay/?a=commitdiff_plain;h=6723bd0623acd426dcb9ab6d0e1d8f6dfc0059f7;p=git-over-gnunet.git Authenticated pushing via the identity service --- diff --git a/README.txt b/README.txt index 12ba422..9ca31aa 100644 --- a/README.txt +++ b/README.txt @@ -1,4 +1,4 @@ -This set of bash scripts allows one to clone/fetch/pull git repositories using gnunet, specifically the GNS and the GNUnet VPN. +This set of bash scripts allows one to use remote git repositories via gnunet, specifically the GNS, GNUnet VPN, and gnunet-identity. In the interest of demonstrating that it works, all the repos on my server are available at `gnunet://git.serv.amelia.gnunet.gns.alt/.git` (see gitweb for the specific URIs). Try cloning them ! (And do tell me if it fails, or if it works.) @@ -6,8 +6,8 @@ In the interest of demonstrating that it works, all the repos on my server are a Usage: Client: You must add the repo folder to the GIT_EXEC_PATH (for example by prepending - `GIT_EXEC_PATH=$GIT_EXEC_PATH:` before every git command that uses remotes). - The URL to give to git is `gnunet:///`. + `GIT_EXEC_PATH=$GIT_EXEC_PATH:/path/to/git/over/gnunet/repo` before every git command that uses remotes). + The URL to give to git is `gnunet://[gnunet-identity@]gns.location.of.the.repo[/path/to/the/repo]`. Server: - To serve repos, you have to setup a gnunet-vpn exit service. ``` @@ -20,16 +20,18 @@ Server: - You should also add a gns VPN record containing the required information to connect to the exit service. `gnunet-namestore -a -t VPN -e 1d -n -V '1 ' -z -p` - Next, you need to run the daemon: it needs to run `handle-request.sh` in the parent folder of all the repos every time someone connects to it. - For example, with socat: `socat tcp4-listen:9418,bind=169.254.86.1,fork exec:'/path/to/handle-request.sh /path/to/repos'` - - This will open the repos for pulling on the url `gnunet:///`. + For example, with socat: `socat tcp4-listen:9418,bind=169.254.86.1,fork exec:'/path/to/handle-request.sh /path/to/repos /path/to/list/of/pkeys'` + - This will open the repos for pulling on the url `gnunet://[gnunet-identity@]gns-name.public-key[/path/to/the/repo]`. + - Additionally, any owner of a public key listed in /path/to/list/of/pkeys (each line should be a pkey on its own) will be allowed push access + (by specifying the corresponding identity before the @). Features: - Clone repo ! - Fetch repo ! - Pull repo ! + - Authenticated push to repo ! TODO: - - Pushing, and a gnunet-identity verification system ? - Pulling from anyone using a commit hash ? - DHT to figure out who has what commits ? - Question of trust for pulling from peers ? @@ -37,9 +39,18 @@ TODO: How it works: Client: - Uses a git remote helper to give git the ability to interpet the gnunet:// scheme. - - Gets the VPN record associated with the GNS name given in gnunet:///. - - Connects to the exit service, give it the name of the repo and the command required (e.g. `git-upload-pack`). + - Gets the VPN record associated with the GNS name given in the scheme. + - Connects to the exit service, give it the name of the repo and the command required + (e.g. `git-upload-pack`) (and the public key if an identity was specified). Server: - Reads the path and the command. - - Checks that the command is git-upload-pack and the path isn't malicious. + - Checks that the the path isn't malicious. + - Checks that the command is git-upload-pack, or that the client is authenticated and the command is git-receive-pack. - Executes the command and connects it to the client. +Authentication (also done when pulling): + - The server receives the public key. + - It checks the key is allowed. + - It sends a randomly-generated passphrase to the client, encrypted to the public key. + - The client decyphers and hashes the passphrase, and sends the hash back. + - This avoids the request by a malicious server of decyphering of arbitrary strings. + - The server checks the correctness of the hash. diff --git a/git-remote-gnunet b/git-remote-gnunet index edccd49..b01e65a 100755 --- a/git-remote-gnunet +++ b/git-remote-gnunet @@ -43,4 +43,19 @@ echo >&2 "Trying service \`$service' on peer \`$peer'." ip="$(gnunet-vpn -s "$service" -p "$peer" -t)" echo >&2 "Using tunnel ip \`$ip'." -{ printf '%s\n' "$path" "$arg" "$pkey"; cat; } | socat stdio tcp4:"$ip":9418 +case "$username" in +"") + { printf '%s\n' "$path" "$arg" "$pkey"; cat; } | socat stdio tcp4:"$ip":9418 + ;; +*) + fifo="$(mktemp -u)" + mkfifo "$fifo" || { echo 2>&1 "Failed to create the fifo."; exit 1; } + { printf '%s\n' "$path" "$arg" "$pkey"; head -n1 "$fifo"; cat; } \ + | socat stdio tcp4:"$ip":9418 \ + | { head -n 1 \ + | { xargs gnunet-identity -e "$username" -R || { echo >&2 'Error !'; exit 1; }; } \ + | sha256sum > "$fifo"; + cat; } + rm "$fifo" + ;; +esac diff --git a/handle-request.sh b/handle-request.sh index 4894910..e47975b 100755 --- a/handle-request.sh +++ b/handle-request.sh @@ -1,10 +1,11 @@ #!/usr/bin/env bash -if test -z $1 || ! test -z $2; then - echo >&2 "Usage: $0 /base/path" +if test -z "$1" || test -z "$2" || ! test -z "$3"; then + echo >&2 "Usage: $0 /base/path /file/containing/list/of/allowed/pkeys" exit 1 fi base_path="$1" +pkeys="$2" read -r path || { echo "No path specified." | tee /dev/stderr; exit 1; } read -r comm || { echo "No command specified." | tee /dev/stderr; exit 1; } @@ -19,14 +20,32 @@ case "$full_path" in ;; esac +if test "" != "$pkey"; then + pkey="$(grep -xm1 -- "$pkey" < "$pkeys")" || { echo "Unknown public key." | tee /dev/stderr; exit 1; } + keyphrase="$( /dev/null | head -c 64)" + hashed="$(printf '%s\n' "$keyphrase" | sha256sum)" + encrypted="$(gnunet-identity -k "$pkey" -W "$keyphrase")" + printf '%s\n' "$encrypted" + read -r returned_hash + case "$returned_hash" in + "$hashed") + ;; + *) + echo "Incorrect passphrase decryption." | tee /dev/stderr + exit 1 + ;; + esac +fi + case "$comm" in git-upload-pack) - # No pkey checking. + # Unidentified pull is allowed. ;; git-receive-pack) - # Accept any valid pkey. FIXME - echo "Command \`$comm' not supported yet." | tee /dev/stderr - exit 1 + if test "" = "$pkey"; then + echo "Unidentified push is not allowed." | tee /dev/stderr + exit 1 + fi ;; *) echo "Unknown command: \`$comm'." | tee /dev/stderr