Skip to content

Instantly share code, notes, and snippets.

@zx0r
Last active January 30, 2025 20:51
Show Gist options
  • Save zx0r/843298b67cd91a0835dcf36aada529d5 to your computer and use it in GitHub Desktop.
Save zx0r/843298b67cd91a0835dcf36aada529d5 to your computer and use it in GitHub Desktop.
GnuPG (GPG) for macOS
# $HOME/.ssh/config
# Global Settings
Host *
AddKeysToAgent yes
UseKeychain yes
IdentitiesOnly yes
#IdentityFile ~/.ssh/id_ed25519
# Performance
Compression yes
TCPKeepAlive yes
ServerAliveInterval 60
ServerAliveCountMax 30
# Security
HashKnownHosts yes
PasswordAuthentication no
PubkeyAuthentication yes
IdentitiesOnly yes
# Modern Crypto
KexAlgorithms [email protected],diffie-hellman-group-exchange-sha256
Ciphers [email protected],[email protected]
MACs [email protected],[email protected]
# GitHub
Host github.com
User git
IdentityFile ~/.ssh/github_ed25519
# GitLab
Host gitlab.com
User git
IdentityFile ~/.ssh/gitlab_ed25519
# Custom Server Example
Host dev
HostName dev.example.com
User developer
Port 2222
IdentityFile ~/.ssh/dev_ed25519
# Script: setup-gpg-git-macos.sh
# Author: zx0r
# Date: 2025-01-30
# Description: This script installs and configures GnuPG (GPG) for macOS, sets up Git to use GPG for signing commits,
# and ensures security settings are applied. It also auto-detects the user's shell, configures VSCode/VSCodium
# to use GPG for commits, and sets up a launch agent for gpg-agent.
# Set cache times for normal and SSH keys (in seconds)
default-cache-ttl 3600
max-cache-ttl 7200
default-cache-ttl-ssh 3600
max-cache-ttl-ssh 7200
# Enable SSH support
enable-ssh-support
# Set pinentry program for macOS
pinentry-program /usr/local/bin/pinentry-mac
# Set TTY
ttyname $GPG_TTY
# Write environment file
write-env-file ~/.gnupg/gpg-agent.env
# Keyboard control settings
no-grab
# Allow preset passphrases
allow-preset-passphrase
# Enable loopback for better integration
allow-loopback-pinentry
# Set longer key grace period
ignore-cache-for-signing
# Script: setup-gpg-git-macos.sh
# Author: zx0r
# Date: 2025-01-30
# Description: This script installs and configures GnuPG (GPG) for macOS, sets up Git to use GPG for signing commits,
# and ensures security settings are applied. It also auto-detects the user's shell, configures VSCode/VSCodium
# to use GPG for commits, and sets up a launch agent for gpg-agent.
# ┌───────────────────────────────────────────────────────────────────────────┐
# │ Setting defaults │
# └───────────────────────────────────────────────────────────────────────────┘
# Default/trusted key ID to use (helpful with throw-keyids)
# $ gpg --list-secret-keys --with-keygrip --with-colons | grep '^sec:' | awk -F: '{print $5}'
default-key <YOUR-KEY>
# Automatically encrypt replies to encrypted messages to yourself as well
default-recipient-self
# UTF-8 support for compatibility
charset utf-8
# when outputting certificates, view user IDs distinctly from keys:
fixed-list-mode
# Use the GPG agent for passphrase caching
use-agent
# Disable recipient key ID in messages
throw-keyids
# default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed
armor
# include an unambiguous indicator of which key made a signature:
# (see http://thread.gmane.org/gmane.mail.notmuch.general/3721/focus=7234)
# (and http://www.ietf.org/mail-archive/web/openpgp/current/msg00405.html)
# sig-notation [email protected]=%g
# ┌───────────────────────────────────────────────────────────────────────────┐
# │ Algorithms & Ciphers │
# └───────────────────────────────────────────────────────────────────────────┘
# SHA512 as digest to sign keys
cert-digest-algo SHA512
# SHA512 as digest for symmetric ops
s2k-digest-algo SHA512
# AES256 as cipher for symmetric ops
s2k-cipher-algo AES256
# Set default key generation algorithm to RSA with 4096-bit length [strong protection]
default-new-key-algo rsa4096
# Use AES256, 192, or 128 as cipher
personal-cipher-preferences AES256 AES192 AES
# Use SHA512, 384, or 256 as digest
personal-digest-preferences SHA512 SHA384 SHA256
# Use ZLIB, BZIP2, ZIP, or no compression
personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed
# Default preferences for new keys
default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed
# ┌───────────────────────────────────────────────────────────────────────────┐
# │ Behavior of GnuPG │
# └───────────────────────────────────────────────────────────────────────────┘
# Repair legacy PGP subkey bug during import
import-options repair-pks-subkey-bug
# Remove all signatures from imported keys that are not usable
import-options import-clean
# Remove all non-exportable signatures during export
export-options export-clean
# Display Options
# Show validity of user IDs during key listings
list-options show-uid-validity
# Show validity of user IDs during signature verification
verify-options show-uid-validity
# Show Unix timestamps
fixed-list-mode
# Disable caching of passphrase for symmetrical ops
no-symkey-cache
# Disable banner Interface Options
no-greeting
# No comments on signatures
no-comments
# No version in signatures
no-emit-version
# Show unix timestamps
fixed-list-mode
# Long hexadecimal key format
keyid-format 0xlong
# Display fingerprint
with-fingerprint
# Disable caching of passphrasae for symmetrical encryption
no-symkey-cache
# Disable recipient key ID in messages
# throw-keyids
trust-model always
# Skip time conflict warnings during signature verification
# This is useful when system clock differences might cause issues
ignore-time-conflict
# Ensure cross-certification on signing subkeys
# This enhances security by requiring signatures between primary and subkeys
require-cross-certification
# Commented out: Allow non-standard UIDs during key generation
# Enabling this would allow creation of UIDs without email addresses
# allow-freeform-uid
# Display all keys and their fingerprints
with-fingerprint
# Display key origins and updates
#with-key-origin
# Cross-certify subkeys are present and valid
require-cross-certification
# no-tty
# pinentry-mode loopback
# ┌───────────────────────────────────────────────────────────────────────────┐
# │ Keyring & Keyserver │
# └───────────────────────────────────────────────────────────────────────────┘
# Disable the use of the default public and secret keyrings
# This allows explicit specification of which keyrings to use
no-default-keyring
# Keyring Options
# Specify the primary public keyring
# keyring ~/.gnupg/pubring.kbx
# trustdb-name ~/.gnupg/trustdb.gpg
# primary-keyring ~/.gnupg/pubring.kbx
# Automatically retrieve missing keys from keyserver when verifying signatures
# This makes signature verification more seamless by fetching required keys
auto-key-retrieve
# Keyserver Options
# Don't add additional comments in downloaded certificates
keyserver-options no-include-attributes
# Honor the preferred keyserver URL from the key
keyserver-options honor-keyserver-url
# Do not include key signatures from keyserver responses
keyserver-options no-include-revoked
# Include subkeys when downloading keys from keyserver
keyserver-options include-subkeys
# Automatically fetch keys from keyserver when verifying signatures
keyserver-options auto-key-retrieve
# Include revoked keys in search results
keyserver-options include-revoked
# Number of seconds to wait for a keyserver response
keyserver-options timeout=10
# Default keyserver to use
keyserver hkps://keys.openpgp.org
keyserver hkp://zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad.onion
# keyserver hkp://pgp.mit.edu
# keyserver hkp://pool.sks-keyservers.net
# keyserver hkp://keys.gnupg.net
# keyserver hkps://keyserver.ubuntu.com
# keyserver hkps://pgp.mit.edu
# keyserver hkp://keyoxide.org
# keyserver hkp://na.pool.sks-keyservers.net
# keyserver https://sks-keyservers.net/status/
# keyserver hkp://keyserver.ubuntu.com
# keyserver hkp://keybase.io
# keyserver hkp://keyserver.undergrid.net
# keyserver hkp://keyring.debian.org
# keyserver hkp://hkps.pool.sks-keyservers.net
# Define a keygroup named 'purse_keygroup'
# This allows you to refer to multiple keys as a single group
# group purse_keygroup = 0xFF123456 0xABCDEF01 0x12345678
# $HOME/.config/fish/functions/gpg_ssh_agent.fish
function gpg_ssh_agent --description "Start and manage GPG agent"
# Skip for root user
test $USER = root; and return
# Early return if gpgconf is not available
command -q gpgconf; or return 1
# Determine GPG directory
set -l GPG_DIR (test -n "$GNUPGHOME"; and echo $GNUPGHOME; or echo "$HOME/.gnupg")
# Ensure GPG directory exists with secure permissions
if not test -d $GPG_DIR
mkdir -p $GPG_DIR
chmod 700 $GPG_DIR
end
# Set GPG environment file path
set -l GPG_ENV "$GPG_DIR/gpg-agent.env"
# Create or update GPG environment file with secure permissions
if not test -f $GPG_ENV
touch $GPG_ENV
chmod 600 $GPG_ENV
end
# Source existing environment variables if the file is not empty
test -s $GPG_ENV; and source $GPG_ENV ^/dev/null
# Clear SSH_AUTH_SOCK
set -e SSH_AUTH_SOCK
# Set curses for SSH connections if active
test -n "$SSH_CONNECTION"; and set -x PINENTRY_USER_DATA "USE_CURSES=1"
# Set GPG and SSH environment variables
set -gx GPG_TTY (tty)
set -gx GPG_AGENT_INFO (gpgconf --list-dirs agent-socket)
set -gx SSH_AUTH_SOCK (gpgconf --list-dirs agent-ssh-socket)
# Initialize GPG agent
gpg-connect-agent updatestartuptty /bye ^/dev/null
gpgconf --launch gpg-agent
return 0
end
# Call the function to initialize GPG agent at startup
gpg_ssh_agent
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.gnupg.gpg-agent</string>
<key>ProgramArguments</key>
<array>
<string>$HOME/.local/bin/start-gpg-agent.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardErrorPath</key>
<string>~/.gnupg/gpg-agent.log</string>
<key>StandardOutPath</key>
<string>~/.gnupg/gpg-agent.log</string>
</plist>
# Configure your SSH client to automatically add keys to the SSH agent
# $HOME/.ssh/config
# Host *
# AddKeysToAgent yes
# UseKeychain yes # Optional: This is useful on macOS to use the keychain.
# $HOME/.config/fish/functions/ssh_agent.fish
function ssh_agent --description "Start and manage SSH agent"
set -l SSH_ENV "$HOME/.ssh/ssh-agent.env"
# Check if the SSH agent environment file exists
if test -f $SSH_ENV; and test -z "$SSH_AGENT_PID"
source $SSH_ENV >/dev/null
end
# If the SSH agent is not running, start it
if test -z "$SSH_AGENT_PID"
eval (ssh-agent -c) >$SSH_ENV
chmod 600 $SSH_ENV
echo "SSH agent started."
else
echo "Using existing SSH agent."
end
# Add SSH keys
set -l SSH_KEYS (fd '^id_' $HOME/.ssh --type f --exclude '*.pub')
for KEY in $SSH_KEYS
ssh-add $KEY
end
end
# Automatically start the ssh-agent on shell initialization
ssh_agent
# https://github.com/ivakyb/fish_ssh_agent
#
# function ssh_agent_is_started -d "check if ssh agent is already started"
# if begin
# test -f $SSH_ENV; and test -z "$SSH_AGENT_PID"
# end
# source $SSH_ENV >/dev/null
# end
#
# if test -z "$SSH_AGENT_PID"
# return 1
# end
#
# ps -ef | grep $SSH_AGENT_PID | grep -v grep | grep -q ssh-agent
# return $status
# end
#
# function ssh_agent_start -d "start a new ssh agent"
# ssh-agent -c | sed 's/^echo/#echo/' >$SSH_ENV
# chmod 600 $SSH_ENV
# source $SSH_ENV >/dev/null
# true # suppress errors from setenv, i.e. set -gx
# end
#
# function fish_ssh_agent --description "Start ssh-agent if not started yet, or uses already started ssh-agent."
# if test -z "$SSH_ENV"
# set -xg SSH_ENV $HOME/.ssh/ssh-agent.env
# end
#
# if not ssh_agent_is_started
# ssh_agent_start
# end
# end
# Automatically start the ssh-agent on shell initialization
# fish_ssh_agent
# Using a PGP key for SSH authentication
# List of allowed ssh keys. Only keys present in this file are used
# in the SSH protocol. The ssh-add tool may add new entries to this
# file to enable them; you may also add them manually. Comment
# lines, like this one, as well as empty lines are ignored. Lines do
# have a certain length limit but this is not serious limitation as
# the format of the entries is fixed and checked by gpg-agent. A
# non-comment line starts with optional white spaces, followed by the
# keygrip of the key given as 40 hex digits, optionally followed by a
# caching TTL in seconds, and another optional field for arbitrary
# flags. Prepend the keygrip with an '!' mark to disable it.
# gpg --list-keys --with-keygrip | awk '/^sub/{p=1;next} /Keygrip/{if(p){print $3;p=0}}' >> $HOME/.gnupg/sshcontrol
# FF8852FA7D6ED25CF4169132698BBA5536A68134
#!/usr/bin/env bash
# The configuration will keep your GPG agent running smoothly across all applications!
if [ -f $HOME/.gnupg/.gpg-agent-info ] && [ -n "$(pgrep gpg-agent)" ]; then
source $HOME/.gnupg/.gpg-agent-info
export GPG_AGENT_INFO
else
eval $(gpg-agent --daemon --write-env-file $HOME/.gnupg/.gpg-agent-info)
fi
# This line is important for GUI tools to also find it
launchctl setenv GPG_AGENT_INFO $GPG_AGENT_INFO
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment