Created
August 21, 2024 14:57
-
-
Save samj/80d0972cc2b4f6100d94e7a8b7b62e87 to your computer and use it in GitHub Desktop.
gpg pinentry protocol implementation for 1Password
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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