Skip to content

Commit 1d69b2d

Browse files
committed
Implement and test subkey matching in SigningMechanism
Document how the key identities from NewEphemeralGPGSigningMechanism and SigningMechanism should relate. For the GPGME implementation where the relationship isn't as desired, introduce signingMechanismWithVerificationIdentityLookup . For the openpgp implementation, just fix the returned value to match new expecations. Currently, the simple signing verifyAndExtractSignature rejects subkey signatures for both mechanism implementations, so this does not change behavior for any previously-accepted signatures (but it might affect theoretical external direct callers of SigningMechanism). We will actually use this in the next commit. WARNING: Adding support for subkeys makes subkey revocation relevant. Revocation is always messy - to support long-term signature validity (which is very relevant for container image signing), smooth handling of revocation might require trusted timestamps (not natively supported in OpenPGP). In practice, this library (partially out of necessity) lets the underlying OpenPGP implementations impose their own policy, and that handling DIFFERS between various SigningMechanism implementations: it seems that GnuPG and refuses to use a revoked subkey regardless of revocation time, while Sequoia-PGP decides based on the revocation reason whether the revocation applies to all signatures or only to signatures (supposedly!!) made after the revocation happened. It is STRONGLY recommended to avoid all of this complexity, and to plan for workflows where subkey revocation never happens. Just revoke and reissue the whole key - either way you'll need to distribute an updated key to all consumers. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
1 parent d84101b commit 1d69b2d

14 files changed

+354
-5
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
-----BEGIN PGP PUBLIC KEY BLOCK-----
2+
Version: GnuPG v2.0.22 (GNU/Linux)
3+
4+
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
57+
=k/PT
58+
-----END PGP PUBLIC KEY BLOCK-----
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
-----BEGIN PGP PUBLIC KEY BLOCK-----
2+
Version: GnuPG v2.0.22 (GNU/Linux)
3+
4+
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
48+
=1ZyP
49+
-----END PGP PUBLIC KEY BLOCK-----

signature/fixtures/pubring.gpg

4.63 KB
Binary file not shown.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#! /bin/bash
2+
3+
# NOTE: To generate v3 signatures, this MUST be run on a system with GPG < 2.1, e.g. a RHEL 7.
4+
# WARNING: This lazily writes to $(pwd). It is best run on a short-term VM.
5+
6+
# This is only a fragment of the ideal script; as you regenerate any other keys, please work on improving it.
7+
8+
set -x
9+
10+
dest=$(pwd)/new-fixtures
11+
mkdir -p "$dest"
12+
13+
function resign() {
14+
local key_id=$1
15+
local signature=$2
16+
local other_opts=$3
17+
18+
(GNUPGHOME= gpg -d "signature/fixtures/$signature"; true) | gpg --sign --digest-algo SHA256 --default-key "$key_id" $other_opts - > "$dest/$signature"
19+
}
20+
21+
export GNUPGHOME=$(mktemp -d -t regenerate-keys.XXXXXX)
22+
echo "GNUPGHOME: $GNUPGHOME" # Don't set up trap(1) to delete it, to allow inspection / debugging.
23+
24+
# Key-Usage: auth is used because "cert" is implied, and the only one we want, but an empty value is not accepted
25+
# by gpg.
26+
cat >batch-input <<EOF
27+
Key-Type: RSA
28+
Key-Length: 3072
29+
Key-Usage: auth
30+
Subkey-Type: RSA
31+
Subkey-Length: 3072
32+
Subkey-Usage: sign
33+
%no-protection
34+
Name-Real: c/image test key with subkey
35+
Expire-Date: 0
36+
%commit
37+
EOF
38+
out=$(gpg --batch --gen-key --cert-digest-algo SHA256 < batch-input --status-fd 1 --with-colons)
39+
echo "$out" | grep -v ' PROGRESS '
40+
41+
fingerprint=$(echo "$out" | awk '$2 == "KEY_CREATED" { print $4 }')
42+
# Yes, --fingerprint is used twice, to include the subkey fingerprint.
43+
subkey_fingerprint=$(gpg --list-keys --fingerprint --fingerprint --with-colon "$fingerprint" | awk -F ':' '$1 == "fpr" { fp = $10 } END { print fp }')
44+
echo "TestKeyFingerprintPrimaryWithSubkey = \"$fingerprint\"" > fixtures_info
45+
echo "TestKeyFingerprintSubkeyWithSubkey = \"$subkey_fingerprint\"" >> fixtures_info
46+
47+
resign $subkey_fingerprint subkey.signature
48+
resign $subkey_fingerprint subkey.signature-v3 --force-v3-sigs
49+
gpg --export --armor "$fingerprint" > $dest/public-key-with-subkey.gpg
50+
51+
# Key-Usage: auth is used because "cert" is implied, and the only one we want, but an empty value is not accepted
52+
# by gpg.
53+
cat >batch-input <<EOF
54+
Key-Type: RSA
55+
Key-Length: 3072
56+
Key-Usage: auth
57+
Subkey-Type: RSA
58+
Subkey-Length: 3072
59+
Subkey-Usage: sign
60+
%no-protection
61+
Name-Real: c/image test key with a REVOKED subkey
62+
Expire-Date: 0
63+
%commit
64+
EOF
65+
out=$(gpg --batch --gen-key --cert-digest-algo SHA256 < batch-input --status-fd 1 --with-colons)
66+
echo "$out" | grep -v ' PROGRESS '
67+
68+
fingerprint=$(echo "$out" | awk '$2 == "KEY_CREATED" { print $4 }')
69+
# Yes, --fingerprint is used twice, to include the subkey fingerprint.
70+
subkey_fingerprint=$(gpg --list-keys --fingerprint --fingerprint --with-colon "$fingerprint" | awk -F ':' '$1 == "fpr" { fp = $10 } END { print fp }')
71+
echo "TestKeyFingerprintPrimaryWithRevokedSubkey = \"$fingerprint\"" >> fixtures_info
72+
echo "TestKeyFingerprintSubkeyWithRevokedSubkey = \"$subkey_fingerprint\"" >> fixtures_info
73+
74+
resign $subkey_fingerprint subkey-revoked.signature
75+
resign $subkey_fingerprint subkey-revoked.signature-v3 --force-v3-sigs
76+
77+
# FIXME? Can this be fully automated? --batch alone doesn't work, --yes seems to be ignored.
78+
# Answer "yes", "key is compromised" (NOT "no longer used", to break the subkey-revoked.signature* files created above),
79+
# an empty message, and finally, "save"
80+
gpg --yes --cert-digest-algo SHA256 --edit-key "$fingerprint" 'key 1' 'revkey'
81+
82+
gpg --export --armor "$fingerprint" > $dest/public-key-with-revoked-subkey.gpg
83+
84+
85+
86+
87+
# EVENTUALLY, rebuild signature/fixtures/pubring.gpg from all keys (currently impossible because this script
88+
# does not regenerate all keys that should be present there):
89+
# GNUPGHOME=$dest gpg --import "$dest/public-key-with-subkey.gpg"
90+
91+
# === We are done. Show how the regenerated files differ.
92+
for i in "$dest"/*; do
93+
(echo "==== $i"; diff -u <(gpg --list-packets < "signature/fixtures/${i#$dest/}") <(gpg --list-packets < "$i")) |& less
94+
done
95+
96+
cat fixtures_info
658 Bytes
Binary file not shown.
649 Bytes
Binary file not shown.
657 Bytes
Binary file not shown.
650 Bytes
Binary file not shown.

signature/fixtures_info_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ const (
1717
TestKeyShortID = "E932F44B23E8DD43"
1818
// TestKeyFingerprintWithPassphrase is the fingerprint of the private key with passphrase in this directory.
1919
TestKeyFingerprintWithPassphrase = "F2B501009F78B0B340221A12A3CD242DA6028093"
20+
// TestKeyFingerprintPrimaryWithSubkey is the primary key fingerprint of signature/fixtures/public-key-with-subkey.gpg.
21+
TestKeyFingerprintPrimaryWithSubkey = "B9F4CDB9FD8C475BFA340AC38D54A947EE396F36"
22+
// TestKeyFingerprintSubkeyWithSubkey is the subkey fingerprint of signature/fixtures/public-key-with-subkey.gpg.
23+
TestKeyFingerprintSubkeyWithSubkey = "57D1D95BBC53BA0EAFF0718CD75B3109B3BAAEAF"
24+
// TestKeyFingerprintPrimaryWithRevokedSubkey is the primary key fingerprint of signature/fixtures/public-key-with-revoked-subkey.gpg.
25+
TestKeyFingerprintPrimaryWithRevokedSubkey = "6D88C5A1993648A17B2BB0DC6B8499AF63388D63"
26+
// TestKeyFingerprintSubkeyWithRevokedSubkey is the subkey fingerprint of signature/fixtures/public-key-with-revoked-subkey.gpg.
27+
TestKeyFingerprintSubkeyWithRevokedSubkey = "4D33404E00B470050709F3233EF0F93A1F602997"
2028
// TestPassphrase is the passphrase for TestKeyFingerprintWithPassphrase.
2129
TestPassphrase = "WithPassphrase123"
2230
)

signature/mechanism.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ type SigningMechanism interface {
2727
// Sign creates a (non-detached) signature of input using keyIdentity.
2828
// Fails with a SigningNotSupportedError if the mechanism does not support signing.
2929
Sign(input []byte, keyIdentity string) ([]byte, error)
30-
// Verify parses unverifiedSignature and returns the content and the signer's identity
30+
// Verify parses unverifiedSignature and returns the content and the signer's identity.
31+
// For mechanisms created using NewEphemeralGPGSigningMechanism, the returned key identity
32+
// is expected to be one of the values returned by NewEphemeralGPGSigningMechanism,
33+
// or the mechanism should implement signingMechanismWithVerificationIdentityLookup.
3134
Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error)
3235
// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
3336
// along with a short identifier of the key used for signing.
@@ -46,6 +49,16 @@ type signingMechanismWithPassphrase interface {
4649
SignWithPassphrase(input []byte, keyIdentity string, passphrase string) ([]byte, error)
4750
}
4851

52+
// signingMechanismWithVerificationIdentityLookup is an internal extension of SigningMechanism.
53+
type signingMechanismWithVerificationIdentityLookup interface {
54+
SigningMechanism
55+
// keyIdentityForVerificationKeyIdentity re-checks the key identity returned by Verify
56+
// if it doesn't match an identity returned by NewEphemeralGPGSigningMechanism, trying to match it.
57+
// (To be more specific, for mechanisms which return a subkey fingerprint from Verify,
58+
// this converts the subkey fingerprint into the corresponding primary key fingerprint.)
59+
keyIdentityForVerificationKeyIdentity(keyIdentity string) (string, error)
60+
}
61+
4962
// SigningNotSupportedError is returned when trying to sign using a mechanism which does not support that.
5063
type SigningNotSupportedError string
5164

0 commit comments

Comments
 (0)