Bug#1060117: pass-otp: oathtool safety: avoid argument splitting, send secrets via stdin instead of arguments

2024-01-17 Thread Philip Rinn

Hi Paul,

thanks, I'll have a look next week and prepare an upload.

Best,
Philip


OpenPGP_signature.asc
Description: OpenPGP digital signature


Bug#1060117: pass-otp: oathtool safety: avoid argument splitting, send secrets via stdin instead of arguments

2024-01-05 Thread Paul Wise
Package: pass-otp
Version: 1.2.0-9
Severity: normal
Tags: security patch
Forwarded: https://github.com/tadfisher/pass-otp/issues/167 
https://github.com/tadfisher/pass-otp/pulls/182
X-Debbugs-Cc: Debian Security Team 

Since upstream seems to be undermaintained, could you add the attached
patches to the Debian package for slightly more oathtool safety?

The first one uses bash arrays to separate command-line arguments,
instead of fragile shell string splitting.

The second one passes OTP secrets to oathtool on stdin instead
of command-line arguments, when it is new enough to support that.

These have been backported from my pull request linked above
and resolve the upstream bug report linked above. 

-- 
bye,
pabs

https://wiki.debian.org/PaulWise
From 41c60cb5a128da006a8b474b58550a95aa4b33a8 Mon Sep 17 00:00:00 2001
From: Paul Wise 
Date: Fri, 12 May 2023 13:39:53 +0800
Subject: [PATCH 1/2] Use bash arrays to separate arguments to oathtool and
 otptool

Also use long version of oathtool -b/--base32 option.
---
 otp.bash | 19 ++-
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/otp.bash b/otp.bash
index d4c7756..7702c07 100755
--- a/otp.bash
+++ b/otp.bash
@@ -334,18 +334,19 @@ cmd_otp_code() {
   local cmd
   case "$otp_type" in
 totp)
-  cmd="$OATH -b --totp"
-  [[ -n "$otp_algorithm" ]] && cmd+=$(echo "=${otp_algorithm}"|tr "[:upper:]" "[:lower:]")
-  [[ -n "$otp_period" ]] && cmd+=" --time-step-size=$otp_period"s
-  [[ -n "$otp_digits" ]] && cmd+=" --digits=$otp_digits"
-  cmd+=" $otp_secret"
+  cmd=("$OATH" --base32)
+  [[ -z "$otp_algorithm" ]] && cmd+=(--totp)
+  [[ -n "$otp_algorithm" ]] && cmd+=(--totp="$(echo "${otp_algorithm}"|tr "[:upper:]" "[:lower:]")")
+  [[ -n "$otp_period" ]] && cmd+=(--time-step-size="$otp_period"s)
+  [[ -n "$otp_digits" ]] && cmd+=(--digits="$otp_digits")
+  cmd+=("$otp_secret")
   ;;
 
 hotp)
   local counter=$((otp_counter+1))
-  cmd="$OATH -b --hotp --counter=$counter"
-  [[ -n "$otp_digits" ]] && cmd+=" --digits=$otp_digits"
-  cmd+=" $otp_secret"
+  cmd=("$OATH" --base32 --hotp --counter="$counter")
+  [[ -n "$otp_digits" ]] && cmd+=(--digits="$otp_digits")
+  cmd+=("$otp_secret")
   ;;
 
 *)
@@ -353,7 +354,7 @@ cmd_otp_code() {
   ;;
   esac
 
-  local out; out=$($cmd) || die "$path: failed to generate OTP code."
+  local out; out=$("${cmd[@]}") || die "$path: failed to generate OTP code."
 
   if [[ "$otp_type" == "hotp" ]]; then
 # Increment HOTP counter in-place
-- 
2.43.0

From cff06cc3abf97665e5997a41c0aab26808ad3ad8 Mon Sep 17 00:00:00 2001
From: Paul Wise 
Date: Fri, 12 May 2023 14:14:04 +0800
Subject: [PATCH 2/2] Send secrets to oathtool via stdin instead of
 command-line arguments

Check if the oathtool version supports this first.

Fixes: https://github.com/tadfisher/pass-otp/issues/167
---
 otp.bash | 25 ++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/otp.bash b/otp.bash
index 7702c07..86344aa 100755
--- a/otp.bash
+++ b/otp.bash
@@ -331,6 +331,12 @@ cmd_otp_code() {
 fi
   done < <(echo "$contents")
 
+  # Check oathtool for stdin secrets feature
+  OATH_SAFE_VERSION=2.6.5
+  OATH_VERSION=$("$OATH" --version | head -n1 | tr ' ' '\n' | tail -n1)
+  printf -v OATH_VERSIONS '%s\n%s' "$OATH_SAFE_VERSION" "$OATH_VERSION"
+  [[ "$OATH_VERSIONS" = "$(sort -n <<< "$OATH_VERSIONS")" ]] && OATH_SAFE=1
+
   local cmd
   case "$otp_type" in
 totp)
@@ -339,14 +345,22 @@ cmd_otp_code() {
   [[ -n "$otp_algorithm" ]] && cmd+=(--totp="$(echo "${otp_algorithm}"|tr "[:upper:]" "[:lower:]")")
   [[ -n "$otp_period" ]] && cmd+=(--time-step-size="$otp_period"s)
   [[ -n "$otp_digits" ]] && cmd+=(--digits="$otp_digits")
-  cmd+=("$otp_secret")
+  if [[ -n "$OATH_SAFE" ]] ; then
+cmd+=(-) # secrets on stdin
+  else
+cmd+=("$otp_secret")
+  fi
   ;;
 
 hotp)
   local counter=$((otp_counter+1))
   cmd=("$OATH" --base32 --hotp --counter="$counter")
   [[ -n "$otp_digits" ]] && cmd+=(--digits="$otp_digits")
-  cmd+=("$otp_secret")
+  if [[ -n "$OATH_SAFE" ]] ; then
+cmd+=(-) # secrets on stdin
+  else
+cmd+=("$otp_secret")
+  fi
   ;;
 
 *)
@@ -354,7 +368,12 @@ cmd_otp_code() {
   ;;
   esac
 
-  local out; out=$("${cmd[@]}") || die "$path: failed to generate OTP code."
+  local out
+  if [[ -n "$OATH" && -n "$OATH_SAFE" ]] ; then
+out=$("${cmd[@]}" <<< "$otp_secret") || die "$path: failed to generate OTP code."
+  else
+out=$("${cmd[@]}") || die "$path: failed to generate OTP code."
+  fi
 
   if [[ "$otp_type" == "hotp" ]]; then
 # Increment HOTP counter in-place
-- 
2.43.0



signature.asc
Description: This is a digitally signed message part