Home / Alt manpages / gpg-check-pattern(1)

  • gpg-check-pattern(1)
  • User command
  • linux

Test Passphrases with gpg-check-pattern

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.

1. Find the installed helper

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.

2. Inspect the supplied policy example

The package includes a useful example policy. Read it without elevating privileges:

$ sed -n '1,120p' /usr/share/doc/gpg-agent/examples/pwpattern.list
  • Comments start with # in the first column; blank lines are ignored.
  • A plain line is matched as text, with trailing spaces ignored.
  • A line beginning with / is an extended regular expression ending at the next / or at the end of the line. Prefixing it with !/ reverses the result.
  • Comparisons are case insensitive by default. The tags [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.

3. Validate the pattern file before using it

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.

4. Understand the default reject mode

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.

5. Build an allow policy with accept blocks

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.

6. Handle input boundaries deliberately

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.

Done means

  • Found the real path. The installed 2.4.4 helper and its actual path are known.
  • Validated the syntax. Your pattern file passes --check.
  • Understand the exit codes. Reject mode returns 1 on a match and 0 when no reject pattern matches.
  • Tested with safe input. Any accept block has been tested with harmless, non-secret input.
  • Scripted it safely. Scripts use the exit status and keep passphrases out of history and logs.