1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
#!/bin/bash
# This script aims to run gpg in a number of standard ways to try to
# ensure that by default it only generates OpenPGP-compatible
# artifacts.
# Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
# License: GPL-3+
if [ -n "$AUTOPKGTEST_ARTIFACTS" ]; then
WORKDIR="$AUTOPKGTEST_ARTIFACTS/workdir"
mkdir -p "$WORKDIR" || exit 1
else
WORKDIR=$(mktemp -d)
cleanup() {
rm -rf "$WORKDIR"
}
trap cleanup EXIT
fi
errors=''
add_error() {
printf "FAILURE: %s\n" "$@" >&2
errors="$errors$*
"
}
GPG() {
# printf "GPG: %s\n" "$@"
gpg --no-tty --pinentry-mode loopback --quiet --passphrase '' --batch --fixed-list-mode "$@"
}
mkdir "$WORKDIR/certs"
# generate keys in a dedicated homedir:
genkey() {
local profile="$1"
local expected="$2"
local GNUPGHOME="$WORKDIR/$profile"
export GNUPGHOME
mkdir -p -m 0700 "$GNUPGHOME"
if [[ "$profile" =~ default ]]; then
algo="$profile"
# this is a dummy placeholder:
extra_arg="--fixed-list-mode"
else
algo="default"
extra_arg="--default-new-key-algo=$profile"
fi
if GPG "$extra_arg" --quick-gen-key "$profile" "$algo"; then
if [ "$expected" = "fail" ]; then
add_error "Should have failed to generate key $1"
return
fi
fprs=$(GPG --list-keys | awk -F: '/^fpr:/{print $10 }')
for fpr in $fprs; do
fprlen=$(printf "%s" "$fpr" | wc -c)
if [ "$fprlen" -ne 40 ]; then
add_error "Generated fingerprint ($fpr) should have had 40 chars, got $fprlen"
fi
done
mkdir -p "$(dirname "$WORKDIR/certs/$profile.cert")"
GPG --export > "$WORKDIR/certs/$profile.cert"
else
if [ "$expected" != "fail" ]; then
add_error "Should not have failed when generating $1"
fi
fi
}
# this is really gross and unprincipled. We treat the output of
# --list-packets as a machine-readable format, which upstream always
# says we should not do. Alas, without better inspection tooling
# (which probably means an external dependency), this is the best i
# can do for now.
test_generated_key() {
local profile="$1"
local GNUPGHOME="$WORKDIR/$profile"
export GNUPGHOME
local dump="$WORKDIR/dumps/$profile.dump"
mkdir -p "$(dirname "$dump")"
GPG --list-packets > "$dump" < "$WORKDIR/certs/$profile.cert"
# FIXME Verify: that no advertising preferences for the
# LibrePGP bits are set on the new certs
# no 'version 4'
# known hashed subpackets:
# 2 (sig created)
# 9 (key expires)
# 11 (pref-sym-algos)
# 21 (pref-hash-algos)
# 22 (pref-zip-algos)
# 23 (keyserver preferences) -- accept only 80 (no-modify)
# 27 (key flags) -- accept only 03 (SC) and 0C (E)
# 30 (features) -- accept only 01 (v1 SEIPD)
# 33 (issuer fpr) -- look for v4
# Outright reject:
# 34 (pref-aead-algos)
local unknown_subpacket_types="$( < "$dump" awk '/hashed subpkt/ { print $3 }' | sort -n | uniq | egrep -v '^(2|9|11|21|22|23|27|30|33)$' )"
for p in $unknown_subpacket_types; do
add_error "Unknown Hashed Subpacket type $p emitted by profile $profile"
done
local bad_key_flags="$( < "$dump" awk '/hashed subpkt 27/ { print $8 }' | sort | uniq | egrep -v '^(03\)|0C\))$' )"
for k in $bad_key_flags; do
add_error "Unexpected key flags settings $k by profile $profile"
done
local bad_features="$( < "$dump" awk '/hashed subpkt 30/ { print $7 }' | sort | uniq | egrep -v '^01\)$' )"
for f in $bad_features; do
add_error "Unexpected feature flags $f by profile $profile"
done
local bad_fpr_versions="$(< "$dump" awk '/hashed subpkt 33/ { print $8 }' | sort | uniq | egrep -v '^v4$' )"
for f in $bad_fpr_versions; do
add_error "Unexpected issuer fingerprint $f by profile $profile"
done
local bad_versions="$(< "$dump" awk '/^[[:space:]]*version/ { print $2 }' | sort | uniq | egrep -v '^4,$')"
for f in $bad_versions; do
add_error "unexpected version $f in profile $profile"
done
}
librepgp() {
local profile="$1"
local GNUPGHOME="$WORKDIR/librepgp-$profile"
export GNUPGHOME
mkdir -p -m 0700 "$GNUPGHOME"
if [[ "$profile" =~ default ]]; then
algo="$profile"
# this is a dummy placeholder:
extra_arg="--fixed-list-mode"
else
algo="default"
extra_arg="--default-new-key-algo=$profile"
fi
if ! GPG --compliance=gnupg "$extra_arg" --quick-gen-key "librepgp-$profile" "$algo"; then
add_error "Failed to generate --compliance=gnupg $profile"
return
fi
mkdir -p "$(dirname "$WORKDIR/certs/librepgp-$profile.cert")"
GPG --export "$profile" > "$WORKDIR/certs/librepgp-$profile.cert"
}
# try encrypting to keys with LibrePGP settings set.
test_encrypt() {
local profile="$1"
local GNUPGHOME="$WORKDIR/default"
export GNUPGHOME
GPG --import < "$WORKDIR/certs/librepgp-$profile.cert"
# --- OpenPGP encryption output
# +++ LibrePGP encryption output
# @@ -2,7 +2,6 @@
# :pubkey enc packet: version 3, algo 18, keyid XXXX
# data: [263 bits]
# data: [392 bits]
# -# off=96 ctb=d2 tag=18 hlen=2 plen=64 new-ctb
# -:encrypted data packet:
# - length: 64
# - mdc_method: 2
# +# off=96 ctb=d4 tag=20 hlen=2 plen=74 new-ctb
# +:aead encrypted packet: cipher=9 aead=2 cb=16
# + length: 74
# diff -u <(echo test | GPG --trust-model=always -r "librepgp-$profile" --encrypt | GPG --list-packets) \
# <(echo test | GPG --trust-model=always --compliance=gnupg -r "librepgp-$profile" --encrypt | GPG --list-packets)
if echo test | GPG --trust-model=always -r "librepgp-$profile" --encrypt | \
GPG --list-packets 2>/dev/null | grep ':aead encrypted packet:'; then
add_error "generated AEAD packets when encrypting to librepgp-$profile"
fi
}
test_symmetric_encryption() {
mkdir -m 0700 -p "$WORKDIR/symmetric"
local GNUPGHOME="$WORKDIR/symmetric"
export GNUPGHOME
if echo test | GPG --passphrase abc123 "$@" --symmetric | \
GPG --list-packets 2>/dev/null | grep ':aead encrypted packet:'; then
add_error "generated AEAD packets from ($* --symmetric)"
fi
}
for x in default future-default rsa3072+rsa3072 ed25519+cv25519; do
genkey "$x" succeed
test_generated_key "$x"
done
for x in ed448 ed25519/v5+cv25519/v5 rsa/v5+rsa/v5; do
genkey "$x" fail
done
for x in default future-default ed25519/v5+cv25519/v5 ed448+cv448; do
librepgp "$x"
# uncomment the lines below to see non-OpenPGP artifacts produces with --compliance=gnupg
# test_generated_key "librepgp-$x"
test_encrypt "$x"
done
test_symmetric_encryption
test_symmetric_encryption --compliance=gnupg
if [ -n "$errors" ]; then
printf "=== Errors ====\n%s" "$errors"
exit 1
fi
printf "Success!\n"
|