fix(provenance): fix multi-block armored keyring parsing on arbitrary alignments

Signed-off-by: Raphael Zanarelli <zanarelli.dev@gmail.com>
pull/32610/head
Raphael Zanarelli 1 week ago
parent 67946bb22e
commit cc799c9dfd

@ -394,12 +394,30 @@ func loadKeyRing(ringpath string) (openpgp.EntityList, error) {
// way GnuPG imports them.
func loadArmoredKeyRing(data []byte) (openpgp.EntityList, error) {
var ring openpgp.EntityList
r := bytes.NewReader(data)
for {
block, err := armor.Decode(r)
if errors.Is(err, io.EOF) {
for offset := 0; offset < len(data); {
start := bytes.Index(data[offset:], []byte("-----BEGIN "))
if start == -1 {
break
}
blockStart := offset + start
var blockBytes []byte
end := bytes.Index(data[blockStart:], []byte("-----END "))
if end == -1 {
blockBytes = data[blockStart:]
offset = len(data)
} else {
blockEnd := blockStart + end
if lineEnd := bytes.IndexByte(data[blockEnd:], '\n'); lineEnd == -1 {
blockBytes = data[blockStart:]
offset = len(data)
} else {
blockBytes = data[blockStart : blockEnd+lineEnd+1]
offset = blockEnd + lineEnd + 1
}
}
block, err := armor.Decode(bytes.NewReader(blockBytes))
if err != nil {
return nil, err
}

@ -19,6 +19,7 @@ import (
"bytes"
"crypto"
"errors"
"fmt"
"io"
"os"
"path/filepath"
@ -199,6 +200,77 @@ func TestLoadKeyRingArmoredMultiBlock(t *testing.T) {
assert.Contains(t, names, testKeyName)
}
func rewrapArmoredKey(armored []byte, lineLen int) []byte {
lines := strings.Split(string(armored), "\n")
var out []string
var b64 strings.Builder
inBody := false
for _, line := range lines {
trimmed := strings.TrimRight(line, "\r")
if strings.HasPrefix(trimmed, "-----BEGIN ") {
out = append(out, trimmed)
inBody = false
continue
}
if strings.HasPrefix(trimmed, "-----END ") {
if b64.Len() > 0 {
raw := b64.String()
for i := 0; i < len(raw); i += lineLen {
end := i + lineLen
if end > len(raw) {
end = len(raw)
}
out = append(out, raw[i:end])
}
b64.Reset()
}
out = append(out, trimmed)
inBody = false
continue
}
if !inBody {
out = append(out, trimmed)
if trimmed == "" {
inBody = true
}
continue
}
if strings.HasPrefix(trimmed, "=") {
if b64.Len() > 0 {
raw := b64.String()
for i := 0; i < len(raw); i += lineLen {
end := i + lineLen
if end > len(raw) {
end = len(raw)
}
out = append(out, raw[i:end])
}
b64.Reset()
}
out = append(out, trimmed)
continue
}
b64.WriteString(trimmed)
}
return []byte(strings.Join(out, "\n") + "\n")
}
func TestLoadKeyRingArmoredMultiBlockLineAlignments(t *testing.T) {
raw, err := os.ReadFile(testMultiBlockArmored)
require.NoError(t, err)
for _, lineLen := range []int{32, 36, 40, 44, 48, 52, 56, 64} {
t.Run(fmt.Sprintf("lineLen_%d", lineLen), func(t *testing.T) {
rewrapped := rewrapArmoredKey(raw, lineLen)
k, err := loadArmoredKeyRing(rewrapped)
require.NoError(t, err)
require.Len(t, k, 2, "expected both keys to be loaded for line length %d", lineLen)
})
}
}
func TestLoadArmoredKeyRingRejectsNonKeyBlocks(t *testing.T) {
var buf bytes.Buffer
w, err := armor.Encode(&buf, "PGP MESSAGE", nil)

Loading…
Cancel
Save