mirror of https://github.com/helm/helm
Merge 276fea0121 into a572f23b82
commit
c61ec0d90a
@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package provenance
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// GnuPG 2.1+ stores public keys in a "keybox" (pubring.kbx) — a container
|
||||
// format that interleaves OpenPGP keyblocks with GnuPG-specific metadata. It
|
||||
// is not an OpenPGP packet stream, so it cannot be handed to
|
||||
// openpgp.ReadKeyRing directly. A keybox is a sequence of blobs, each starting
|
||||
// with:
|
||||
//
|
||||
// byte 0..3 u32 blob length, big endian, including this header
|
||||
// byte 4 u8 blob type (0 empty, 1 header, 2 OpenPGP, 3 X.509)
|
||||
// byte 5 u8 blob version
|
||||
//
|
||||
// The first blob is a header carrying the "KBXf" magic at offset 8. OpenPGP
|
||||
// blobs (type 2) record where the raw keyblock lives inside the blob:
|
||||
//
|
||||
// byte 8..11 u32 keyblock offset, relative to the blob start
|
||||
// byte 12..15 u32 keyblock length
|
||||
//
|
||||
// Reference: kbx/keybox-blob.c in the GnuPG source tree.
|
||||
const (
|
||||
kbxBlobTypeHeader = 1
|
||||
kbxBlobTypeOpenPGP = 2
|
||||
|
||||
// kbxBlobFlagEphemeral marks a blob GnuPG considers not (yet) part of
|
||||
// the keyring, e.g. written during an interrupted keyserver operation
|
||||
// (KEYBOX_FLAG_BLOB_EPHEMERAL in kbx/keybox.h). GnuPG skips such blobs
|
||||
// on every normal read (kbx/keybox-search.c), and so do we.
|
||||
kbxBlobFlagEphemeral = 0x0002
|
||||
|
||||
// kbxMinBlobLen covers the length and type fields present in every blob.
|
||||
kbxMinBlobLen = 5
|
||||
|
||||
// kbxOpenPGPHeaderLen is how much of an OpenPGP blob header must be
|
||||
// present for the flags, keyblock offset and keyblock length fields to
|
||||
// be readable.
|
||||
kbxOpenPGPHeaderLen = 16
|
||||
)
|
||||
|
||||
// isKeybox reports whether data looks like a GnuPG keybox (pubring.kbx)
|
||||
// image, identified by the "KBXf" magic in the mandatory first header blob.
|
||||
func isKeybox(data []byte) bool {
|
||||
return len(data) >= 12 && data[4] == kbxBlobTypeHeader && string(data[8:12]) == "KBXf"
|
||||
}
|
||||
|
||||
// isArmored reports whether data looks like an ASCII-armored keyring, as
|
||||
// produced by `gpg --export --armor`.
|
||||
func isArmored(data []byte) bool {
|
||||
return bytes.HasPrefix(bytes.TrimSpace(data), []byte("-----BEGIN PGP"))
|
||||
}
|
||||
|
||||
// keyboxPublicKeys extracts the OpenPGP keyblocks embedded in a keybox image
|
||||
// and returns them concatenated, ready for openpgp.ReadKeyRing. Blobs of any
|
||||
// other type (header, X.509, empty) are skipped, as are blobs flagged
|
||||
// ephemeral, which GnuPG itself ignores when reading the keyring. Malformed
|
||||
// input yields an error, never a panic.
|
||||
func keyboxPublicKeys(data []byte) ([]byte, error) {
|
||||
var keyblocks bytes.Buffer
|
||||
for offset := 0; offset < len(data); {
|
||||
rest := data[offset:]
|
||||
if len(rest) < kbxMinBlobLen {
|
||||
return nil, fmt.Errorf("truncated blob header at offset %d", offset)
|
||||
}
|
||||
blobLen := binary.BigEndian.Uint32(rest)
|
||||
if blobLen < kbxMinBlobLen {
|
||||
return nil, fmt.Errorf("invalid blob length %d at offset %d", blobLen, offset)
|
||||
}
|
||||
if uint64(blobLen) > uint64(len(rest)) {
|
||||
return nil, fmt.Errorf("blob at offset %d has length %d exceeding the %d remaining bytes", offset, blobLen, len(rest))
|
||||
}
|
||||
blob := rest[:blobLen]
|
||||
if blob[4] == kbxBlobTypeOpenPGP {
|
||||
if len(blob) < kbxOpenPGPHeaderLen {
|
||||
return nil, fmt.Errorf("OpenPGP blob at offset %d is too short", offset)
|
||||
}
|
||||
flags := binary.BigEndian.Uint16(blob[6:])
|
||||
keyblockOffset := binary.BigEndian.Uint32(blob[8:])
|
||||
keyblockLen := binary.BigEndian.Uint32(blob[12:])
|
||||
if uint64(keyblockOffset)+uint64(keyblockLen) > uint64(len(blob)) {
|
||||
return nil, fmt.Errorf("OpenPGP blob at offset %d has an out-of-range keyblock", offset)
|
||||
}
|
||||
if flags&kbxBlobFlagEphemeral == 0 {
|
||||
keyblocks.Write(blob[keyblockOffset : keyblockOffset+keyblockLen])
|
||||
}
|
||||
}
|
||||
offset += int(blobLen)
|
||||
}
|
||||
if keyblocks.Len() == 0 {
|
||||
return nil, errors.New("keybox contains no OpenPGP keys")
|
||||
}
|
||||
return keyblocks.Bytes(), nil
|
||||
}
|
||||
@ -0,0 +1,188 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package provenance
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
// testKeybox is a GnuPG keybox (pubring.kbx) containing the helm-test
|
||||
// public key. Regenerate with testdata/regen-keyring-formats.sh.
|
||||
testKeybox = "testdata/helm-test-key.kbx"
|
||||
|
||||
// testMixedKeybox is a keybox containing the RSA and Ed25519 test keys.
|
||||
testMixedKeybox = "testdata/helm-mixed-keyring.kbx"
|
||||
|
||||
// testArmoredPubfile is the ASCII-armored export of the helm-test key.
|
||||
testArmoredPubfile = "testdata/helm-test-key.asc"
|
||||
|
||||
// testMultiBlockArmored is two concatenated single-key armored exports
|
||||
// (cat key1.asc key2.asc), covering the RSA and Ed25519 test keys.
|
||||
testMultiBlockArmored = "testdata/helm-mixed-keyring.asc"
|
||||
)
|
||||
|
||||
func TestIsKeybox(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
file string
|
||||
want bool
|
||||
}{
|
||||
{"keybox", testKeybox, true},
|
||||
{"mixed keybox", testMixedKeybox, true},
|
||||
{"legacy binary keyring", testPubfile, false},
|
||||
{"armored keyring", testArmoredPubfile, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data, err := os.ReadFile(tt.file)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.want, isKeybox(data))
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("degenerate inputs", func(t *testing.T) {
|
||||
assert.False(t, isKeybox(nil))
|
||||
assert.False(t, isKeybox([]byte{}))
|
||||
assert.False(t, isKeybox([]byte("KBXf")))
|
||||
assert.False(t, isKeybox([]byte("garbage that is longer than twelve bytes")))
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsArmored(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
file string
|
||||
want bool
|
||||
}{
|
||||
{"armored keyring", testArmoredPubfile, true},
|
||||
{"legacy binary keyring", testPubfile, false},
|
||||
{"keybox", testKeybox, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data, err := os.ReadFile(tt.file)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.want, isArmored(data))
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("degenerate inputs", func(t *testing.T) {
|
||||
assert.False(t, isArmored(nil))
|
||||
assert.False(t, isArmored([]byte("not a key")))
|
||||
assert.True(t, isArmored([]byte("\n\t -----BEGIN PGP PUBLIC KEY BLOCK-----")))
|
||||
})
|
||||
}
|
||||
|
||||
func TestKeyboxPublicKeys(t *testing.T) {
|
||||
data, err := os.ReadFile(testKeybox)
|
||||
require.NoError(t, err)
|
||||
|
||||
keys, err := keyboxPublicKeys(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
ring, err := openpgp.ReadKeyRing(bytes.NewReader(keys))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, ring, 1)
|
||||
_, ok := ring[0].Identities[testKeyName]
|
||||
assert.True(t, ok, "expected keybox to contain %q", testKeyName)
|
||||
}
|
||||
|
||||
func TestKeyboxPublicKeysEphemeral(t *testing.T) {
|
||||
// GnuPG flags in-progress key material as ephemeral (bit 0x0002 of the
|
||||
// blob flags at blob offset 6) and hides it from every normal read; the
|
||||
// parser must do the same.
|
||||
setFlags := func(t *testing.T, data []byte, blobStart int, flags uint16) []byte {
|
||||
t.Helper()
|
||||
require.Equal(t, byte(kbxBlobTypeOpenPGP), data[blobStart+4])
|
||||
mutated := bytes.Clone(data)
|
||||
binary.BigEndian.PutUint16(mutated[blobStart+6:], flags)
|
||||
return mutated
|
||||
}
|
||||
|
||||
t.Run("all blobs ephemeral means no keys", func(t *testing.T) {
|
||||
valid, err := os.ReadFile(testKeybox)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = keyboxPublicKeys(setFlags(t, valid, 32, kbxBlobFlagEphemeral))
|
||||
assert.ErrorContains(t, err, "no OpenPGP keys")
|
||||
})
|
||||
|
||||
t.Run("ephemeral blob is skipped, others kept", func(t *testing.T) {
|
||||
valid, err := os.ReadFile(testMixedKeybox)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Flag only the first OpenPGP blob (the RSA helm-test key).
|
||||
keys, err := keyboxPublicKeys(setFlags(t, valid, 32, kbxBlobFlagEphemeral))
|
||||
require.NoError(t, err)
|
||||
|
||||
ring, err := openpgp.ReadKeyRing(bytes.NewReader(keys))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, ring, 1)
|
||||
_, ok := ring[0].Identities[testKeyName]
|
||||
assert.False(t, ok, "expected the ephemeral-flagged %q blob to be skipped", testKeyName)
|
||||
})
|
||||
}
|
||||
|
||||
func TestKeyboxPublicKeysMalformed(t *testing.T) {
|
||||
valid, err := os.ReadFile(testKeybox)
|
||||
require.NoError(t, err)
|
||||
|
||||
// The mutations below rely on the fixture layout: a 32-byte header blob
|
||||
// followed by an OpenPGP blob.
|
||||
const blobStart = 32
|
||||
require.Greater(t, len(valid), blobStart+16)
|
||||
require.Equal(t, byte(kbxBlobTypeOpenPGP), valid[blobStart+4])
|
||||
|
||||
mutate := func(offset int, value uint32) []byte {
|
||||
data := bytes.Clone(valid)
|
||||
binary.BigEndian.PutUint32(data[offset:], value)
|
||||
return data
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
data []byte
|
||||
}{
|
||||
{"header only, no keys", valid[:blobStart]},
|
||||
{"truncated inside blob header", valid[:blobStart+2]},
|
||||
{"truncated inside blob body", valid[:blobStart+16]},
|
||||
{"zero blob length", mutate(blobStart, 0)},
|
||||
{"blob length below minimum", mutate(blobStart, 4)},
|
||||
{"blob length past end of data", mutate(blobStart, uint32(len(valid))+1)},
|
||||
{"keyblock offset out of range", mutate(blobStart+8, uint32(len(valid)))},
|
||||
{"keyblock length out of range", mutate(blobStart+12, uint32(len(valid)))},
|
||||
{"keyblock offset overflow", mutate(blobStart+8, ^uint32(0))},
|
||||
{"keyblock length overflow", mutate(blobStart+12, ^uint32(0))},
|
||||
{"openpgp blob shorter than its header", append(bytes.Clone(valid[:blobStart]), 0, 0, 0, 8, kbxBlobTypeOpenPGP, 1, 0, 0)},
|
||||
{"empty input", nil},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := keyboxPublicKeys(tt.data)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFeWbZ4BCADIsgNRyVBSWJkbH6h3UWWXsA9ce1u+YKvaCYFSjIujKycTAqCC
|
||||
P7qUV2Oj/4E2zUcOD1/8/meDwuTnNTLzdSw4ujtFlKRSw7zelQE6sxvID0KM0pQK
|
||||
7AxDTXsm/7Afd/fg4WNW0/hcbeiNz4TVmSWAnbqeLg8o8eljR5QhTk47H6Glo4hV
|
||||
raeLCKG77qm2qOQ/m38ec+L5n9iUpoZZu1S5RXPUIanV5pLlx2rQsooIQEdJbTRF
|
||||
Iv3+2Nj/56PFVdrw7E5ARqCD4PpzzYV7uj8vKumOp+VivFj95Ze6DFENh1WWy336
|
||||
jQEj0uTolgOYeQ6AdJobwSPUeYXGV6Sf2vwXABEBAAG0XUhlbG0gVGVzdGluZyAo
|
||||
VGhpcyBrZXkgc2hvdWxkIG9ubHkgYmUgdXNlZCBmb3IgdGVzdGluZy4gRE8gTk9U
|
||||
IFRSVVNULikgPGhlbG0tdGVzdGluZ0BoZWxtLnNoPokBNwQTAQoAIQUCV5ZtngIb
|
||||
AwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRCEO7+YH8GHYolFCAC0+ejT5dIX
|
||||
0juRl5AdG6XAlEf9IrehkVlo0s5bG1Ucea9jjNRafmmHyMravrxZVI9zGFhaNpxA
|
||||
+McnnWAO8lx5yTgnGW269qvFBsj5n0ItPewILQZjTEgwLYf1oc2qCFpk+8ovBnxZ
|
||||
Kaz3J5QKqU09zLO2yALuI5FTCCUupJ3OGIrKvLJ4H2jsRk/5jgqIgqJotW/4Baza
|
||||
4zemFdQHj9FPvq9sVeW5lyxM48i638GtslIgc0y2Yd/bfiy0tfIkskWz/kS1U6c9
|
||||
Utr3UPwpBqHjXnakmpK7GMGlp5eDXgr63BEdLKxJJWWxIys35fR19XZXcAELrwMh
|
||||
zkTzB/dvI375uQENBFeWbZ4BCADB6a8oiF2royWbvwmujBxSmD68QWziNZbSCuRs
|
||||
M4WM1iy69kspJHRwJEVIE5pkoVfV6tIcwQQ0VkJmq6Pf/pyKeMAXp0u8bp5K0mVE
|
||||
Yio1/adiLM3kX1yleoXLNUb1gNvsk6Kp6BZCUNRmjKlbKxapJKHmL+opX8UoeLeE
|
||||
KSgJNL8jvo3nRgg+wIPnVDoizz7y03F0k4SbgNGdoA/FtZs/vcSrEfzOLgI2RxQS
|
||||
dj/ePkxg9TvQygUSYgAVbYlASw6XMmd/zTjkfD9qa0l3WSejTisn85b611WryDpA
|
||||
iYkYC3GzK8g7S9VwkAbtr79cbG+1djlA4aHASpil+zR12yEhABEBAAGJAR8EGAEK
|
||||
AAkFAleWbZ4CGwwACgkQhDu/mB/Bh2LbNQgAiOOMNzmKzY4A7/ra8ppaH9oL8XIa
|
||||
WvInivOsx22K09PPuPVqi/ooBiRGyRqhdVS4ShPOoOTR5tOsdfPpEMTHnGQ1+jW+
|
||||
Tw5MXv3oMckWw3YEYptnuvon3wT4bOXLr+eYlY4Z1ONs+pAXwMiQ2zXNuKHpA2fR
|
||||
HsF8Wyw57rCVn7K5nQgZCbVxasYlzvFGnmt/itSC5w/AnIvICDOWcoGFKTieqhME
|
||||
IkCyvu+DNrMAumnD2fqF2olsM4IzCEPSMEQqJIGzZTtQTseS8NSDioRGnG1AJQ94
|
||||
BssQVmTh0/hlpoTqXY803lR5wb1fr3RRnkOu+lbEI6AAUj51j5TAAo/1dA==
|
||||
=bvcV
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEaMzP2xYJKwYBBAHaRw8BAQdAXkL0KKTOZoMaM+6HsrkWv93zmLmnMiIoQvR2
|
||||
F+bjx7G0KEhlbG0gRWQyNTUxOSBUZXN0IDxoZWxtLWVkMjU1MTlAaGVsbS5zaD6I
|
||||
mQQTFgoAQRYhBEy+dUwlWAxsh43nEfuFaBLOL8tkBQJozM/bAhsDBQkFo5qABQsJ
|
||||
CAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEPuFaBLOL8tktBYA/2cclE0N+BZV
|
||||
Wymk6XfwFMjErM6olWAfwA8DfAGQ55+lAQCqSa+Tkjd4dmToVHcb0QAm+zwklAY4
|
||||
e6qWgGiivn77AA==
|
||||
=wJ7K
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
Binary file not shown.
@ -0,0 +1,30 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFeWbZ4BCADIsgNRyVBSWJkbH6h3UWWXsA9ce1u+YKvaCYFSjIujKycTAqCC
|
||||
P7qUV2Oj/4E2zUcOD1/8/meDwuTnNTLzdSw4ujtFlKRSw7zelQE6sxvID0KM0pQK
|
||||
7AxDTXsm/7Afd/fg4WNW0/hcbeiNz4TVmSWAnbqeLg8o8eljR5QhTk47H6Glo4hV
|
||||
raeLCKG77qm2qOQ/m38ec+L5n9iUpoZZu1S5RXPUIanV5pLlx2rQsooIQEdJbTRF
|
||||
Iv3+2Nj/56PFVdrw7E5ARqCD4PpzzYV7uj8vKumOp+VivFj95Ze6DFENh1WWy336
|
||||
jQEj0uTolgOYeQ6AdJobwSPUeYXGV6Sf2vwXABEBAAG0XUhlbG0gVGVzdGluZyAo
|
||||
VGhpcyBrZXkgc2hvdWxkIG9ubHkgYmUgdXNlZCBmb3IgdGVzdGluZy4gRE8gTk9U
|
||||
IFRSVVNULikgPGhlbG0tdGVzdGluZ0BoZWxtLnNoPokBNwQTAQoAIQUCV5ZtngIb
|
||||
AwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRCEO7+YH8GHYolFCAC0+ejT5dIX
|
||||
0juRl5AdG6XAlEf9IrehkVlo0s5bG1Ucea9jjNRafmmHyMravrxZVI9zGFhaNpxA
|
||||
+McnnWAO8lx5yTgnGW269qvFBsj5n0ItPewILQZjTEgwLYf1oc2qCFpk+8ovBnxZ
|
||||
Kaz3J5QKqU09zLO2yALuI5FTCCUupJ3OGIrKvLJ4H2jsRk/5jgqIgqJotW/4Baza
|
||||
4zemFdQHj9FPvq9sVeW5lyxM48i638GtslIgc0y2Yd/bfiy0tfIkskWz/kS1U6c9
|
||||
Utr3UPwpBqHjXnakmpK7GMGlp5eDXgr63BEdLKxJJWWxIys35fR19XZXcAELrwMh
|
||||
zkTzB/dvI375uQENBFeWbZ4BCADB6a8oiF2royWbvwmujBxSmD68QWziNZbSCuRs
|
||||
M4WM1iy69kspJHRwJEVIE5pkoVfV6tIcwQQ0VkJmq6Pf/pyKeMAXp0u8bp5K0mVE
|
||||
Yio1/adiLM3kX1yleoXLNUb1gNvsk6Kp6BZCUNRmjKlbKxapJKHmL+opX8UoeLeE
|
||||
KSgJNL8jvo3nRgg+wIPnVDoizz7y03F0k4SbgNGdoA/FtZs/vcSrEfzOLgI2RxQS
|
||||
dj/ePkxg9TvQygUSYgAVbYlASw6XMmd/zTjkfD9qa0l3WSejTisn85b611WryDpA
|
||||
iYkYC3GzK8g7S9VwkAbtr79cbG+1djlA4aHASpil+zR12yEhABEBAAGJAR8EGAEK
|
||||
AAkFAleWbZ4CGwwACgkQhDu/mB/Bh2LbNQgAiOOMNzmKzY4A7/ra8ppaH9oL8XIa
|
||||
WvInivOsx22K09PPuPVqi/ooBiRGyRqhdVS4ShPOoOTR5tOsdfPpEMTHnGQ1+jW+
|
||||
Tw5MXv3oMckWw3YEYptnuvon3wT4bOXLr+eYlY4Z1ONs+pAXwMiQ2zXNuKHpA2fR
|
||||
HsF8Wyw57rCVn7K5nQgZCbVxasYlzvFGnmt/itSC5w/AnIvICDOWcoGFKTieqhME
|
||||
IkCyvu+DNrMAumnD2fqF2olsM4IzCEPSMEQqJIGzZTtQTseS8NSDioRGnG1AJQ94
|
||||
BssQVmTh0/hlpoTqXY803lR5wb1fr3RRnkOu+lbEI6AAUj51j5TAAo/1dA==
|
||||
=bvcV
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
Binary file not shown.
@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
# Regenerate the modern-GnuPG keyring fixtures from the committed binary
|
||||
# keyrings. Requires GnuPG 2.1+ (keybox support).
|
||||
#
|
||||
# helm-test-key.kbx keybox (pubring.kbx) containing the helm-test key
|
||||
# helm-mixed-keyring.kbx keybox containing the RSA and Ed25519 test keys
|
||||
# helm-test-key.asc ASCII-armored export of the helm-test key
|
||||
# helm-mixed-keyring.asc two concatenated single-key armored exports
|
||||
set -e
|
||||
|
||||
GNUPGHOME=$(mktemp -d)
|
||||
export GNUPGHOME
|
||||
chmod 700 "$GNUPGHOME"
|
||||
gpg --batch --no-tty --quiet --import helm-test-key.pub
|
||||
cp "$GNUPGHOME/pubring.kbx" helm-test-key.kbx
|
||||
gpg --batch --no-tty --export --armor helm-testing@helm.sh > helm-test-key.asc
|
||||
rm -rf "$GNUPGHOME"
|
||||
|
||||
GNUPGHOME=$(mktemp -d)
|
||||
export GNUPGHOME
|
||||
chmod 700 "$GNUPGHOME"
|
||||
gpg --batch --no-tty --quiet --import helm-mixed-keyring.pub
|
||||
cp "$GNUPGHOME/pubring.kbx" helm-mixed-keyring.kbx
|
||||
gpg --batch --no-tty --export --armor helm-testing@helm.sh > helm-mixed-keyring.asc
|
||||
gpg --batch --no-tty --export --armor helm-ed25519@helm.sh >> helm-mixed-keyring.asc
|
||||
rm -rf "$GNUPGHOME"
|
||||
Loading…
Reference in new issue