gpg-check-pattern reads a passphrase from standard input and tests it against a policy file you control. The examples use GnuPG 2.4.4 from the gpg-agent package, version 2.4.4-2ubuntu17.6 on this machine. Allow about fifteen minutes.
This tool does not create a passphrase, change an account, or alter an agent. Use only dummy passphrases while following the examples: a passphrase written directly in a shell command can end up in shell history, logs or copied terminal output.
The package installs the helper in GnuPG's private binary directory here, rather than in the ordinary command search path. Check the path and version before building scripts around it:
$ command -v gpg-check-pattern || true
$ /usr/lib/gnupg/gpg-check-pattern --version
gpg-check-pattern (@GnuPG@) 2.4.4
Set a shell variable so the remaining commands are easier to read:
CHECK_PATTERN=/usr/lib/gnupg/gpg-check-pattern
$CHECK_PATTERN --help
Checkpoint: the help output should show the syntax gpg-check-pattern [options] patternfile and the three options used by this guide: --verbose, --check and --null.
The package includes a useful example policy. Read it without elevating privileges:
$ sed -n '1,120p' /usr/share/doc/gpg-agent/examples/pwpattern.list
# in the first column; blank lines are ignored./ is an extended regular expression ending at the next / or at the end of the line. Prefixing it with !/ reverses the result.[icase] and [case] select the comparison mode for following patterns.[reject] and [accept] select the policy mode. Keep tags exactly as written, with no leading or trailing non-whitespace characters.A plain pattern beginning with [ is a poor idea because it can be mistaken for a future tag.
Use --check as the cheap checkpoint after editing or deploying a policy:
$ $CHECK_PATTERN --check /usr/share/doc/gpg-agent/examples/pwpattern.list
$ printf 'syntax status: %s\n' "$?"
syntax status: 0
Status 0 means the syntax check succeeded. It does not test whether a particular passphrase will be accepted. Treat a non-zero result as a policy deployment failure and inspect the file before running the normal check.
Reject mode is the default. The pattern list describes values that must not be used. The command exits with status 1 as soon as a pattern matches; if the input reaches the end of the list without a match, it exits with status 0.
$ printf '%s\n' 'password' | $CHECK_PATTERN /usr/share/doc/gpg-agent/examples/pwpattern.list
$ printf 'status: %s\n' "$?"
status: 1
$ printf '%s\n' 'a-longer-dummy-value-123' | $CHECK_PATTERN /usr/share/doc/gpg-agent/examples/pwpattern.list
$ printf 'status: %s\n' "$?"
status: 0
The first value is listed and is rejected. The second is only a demonstration value, not a recommendation for real authentication. The exit status is the interface scripts should consume; do not parse normal output to decide what happened.
Accept mode changes the meaning of the patterns. A block begins after an [accept] tag and ends before the next [accept] or [reject] tag, or at end of file. Every pattern in a block must match; if a block fails, the next block is tried. If no block succeeds, the command exits with status 1.
This small policy accepts a value with at least twelve characters that does not contain the word password, ignoring case:
[accept]
/^.{12,}$/
!/password/
Save that content as a policy file under a directory with suitable access controls, then validate it:
$ $CHECK_PATTERN --check /path/to/passphrase.policy
$ printf 'status: %s\n' "$?"
status: 0
Do not assume this is a complete password policy. Length and a substring exclusion are deliberately simple examples. Add rules only when you can explain their effect and test them with non-secret fixtures.
Normal input is line based. If the caller supplies several passphrases or needs embedded newlines, --null changes the input delimiter to NUL. This is useful for a controlled pipeline, but it does not make an unsafe source safe:
$ printf '%s\0' 'a-longer-dummy-value-123' | \
$CHECK_PATTERN --null /usr/share/doc/gpg-agent/examples/pwpattern.list
$ printf 'status: %s\n' "$?"
status: 0
Keep the pipe private and avoid --verbose in automated checks until you have confirmed exactly what your installed build writes. Never put a real secret in a command example, a test fixture committed to source control, or a world-readable policy file.
--check.