Skip to content

Instantly share code, notes, and snippets.

@samj
Created August 21, 2024 14:57
Show Gist options
  • Save samj/80d0972cc2b4f6100d94e7a8b7b62e87 to your computer and use it in GitHub Desktop.
Save samj/80d0972cc2b4f6100d94e7a8b7b62e87 to your computer and use it in GitHub Desktop.
gpg pinentry protocol implementation for 1Password
#!/bin/bash
# gpg pinentry protocol implementation for 1Password
# expects gpg passphrase to be the password of a login item
# with username containing the gpg key id (eg 188E5DC27A54FA25)
# and a 'gpg-key' tag
#
# add to ~/.gnupg/gpg-agent.conf:
# pinentry-program /path/to/gpg-pinentry-1password.sh
# Log to a file, but keep stdout open
exec 2> ~/.gnupg/gpg-pinentry-debug.log
log() {
echo "$@" >&2
}
mask_passphrase() {
local passphrase="$1"
local length=${#passphrase}
if [ $length -le 4 ]; then
echo "****"
else
echo "${passphrase:0:2}$( printf '%0.s*' $(seq 1 $((length-4))) )${passphrase: -2}"
fi
}
log "Script started at $(date)"
log "Current user: $USER"
log "Current PATH: $PATH"
log "Current HOME: $HOME"
# Function to get passphrase from 1Password
get_passphrase() {
local key_id="$1"
log "Searching for item with key ID: $key_id"
# Get the list of items and log it for debugging
local items_json=$(op item list --tags="gpg-key" --format=json)
log "Items JSON: $items_json"
# Try to find the item ID
local item_id=$(echo "$items_json" | jq -r ".[] | select(.additional_information == \"$key_id\") | .id")
if [ -z "$item_id" ]; then
log "No matching item found in 1Password"
return 1
fi
log "Found item ID: $item_id"
local passphrase=$(op item get "$item_id" --fields password --reveal)
local masked_passphrase=$(mask_passphrase "$passphrase")
log "Retrieved passphrase (masked): $masked_passphrase"
echo "$passphrase"
}
# Pinentry protocol implementation
echo "OK Pleased to meet you"
while IFS= read -r cmd; do
log "Received command: $cmd"
case "$cmd" in
OPTION*)
echo "OK"
;;
GETPIN)
if [ -z "$KEY_ID" ]; then
log "No KEY_ID set, attempting to use last part of SETKEYINFO"
KEY_ID="${SETKEYINFO##*/}"
fi
if [ -z "$KEY_ID" ]; then
log "ERROR: No KEY_ID set"
echo "ERR 83886179 No key ID set"
else
passphrase=$(get_passphrase "$KEY_ID")
if [ $? -eq 0 ] && [ ! -z "$passphrase" ]; then
local masked_passphrase=$(mask_passphrase "$passphrase")
log "Passphrase retrieved successfully. Sending passphrase (masked): $masked_passphrase"
echo "D $passphrase"
echo "OK"
else
log "ERROR: Failed to retrieve passphrase"
echo "ERR 83886179 Failed to retrieve passphrase"
fi
fi
;;
SETDESC*)
KEY_ID=$(echo "$cmd" | sed -n 's/.*ID \([A-F0-9]\{16\}\).*/\1/p')
if [ -z "$KEY_ID" ]; then
KEY_ID=$(echo "$cmd" | sed -n 's/.*ID \([A-F0-9]\{8\}\).*/\1/p')
fi
log "Extracted KEY_ID: $KEY_ID"
echo "OK"
;;
SETPROMPT* | SETERROR* | SETOK* | SETCANCEL* | SETHEX*)
echo "OK"
;;
GETINFO*)
case "$cmd" in
"GETINFO flavor")
echo "D custom-1password"
;;
"GETINFO version")
echo "D 1.0.0"
;;
"GETINFO ttyinfo")
echo "D - - -"
;;
"GETINFO pid")
echo "D $$"
;;
*)
echo "D - none -"
;;
esac
echo "OK"
;;
SETKEYINFO*)
SETKEYINFO="$cmd"
echo "OK"
;;
BYE)
log "Received BYE command"
echo "OK"
exit 0
;;
*)
log "Unknown command: $cmd"
echo "OK"
;;
esac
done
log "Script ended at $(date)"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment