mirror of
https://github.com/FiloSottile/age.git
synced 2026-09-04 07:07:16 +00:00
internal/bech32: avoid panic on Unicode input
Reported by Joe Doyle of Trail of Bits.
This commit is contained in:
+28
@@ -18,6 +18,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"filippo.io/age"
|
||||
"filippo.io/age/plugin"
|
||||
)
|
||||
|
||||
func ExampleEncrypt() {
|
||||
@@ -549,3 +550,30 @@ func TestEncryptReader(t *testing.T) {
|
||||
t.Errorf("wrong data: %q, excepted %q", outBytes, helloWorld)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseUnicode(t *testing.T) {
|
||||
// U+212A folds to "k", shrinking the data part below the checksum.
|
||||
w := "AA3100AC" + string(rune(0x212A))
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
fn func(string) error
|
||||
}{
|
||||
{"age.ParseX25519Recipient", func(s string) error { _, err := age.ParseX25519Recipient(s); return err }},
|
||||
{"age.ParseX25519Identity", func(s string) error { _, err := age.ParseX25519Identity(s); return err }},
|
||||
{"age.ParseHybridRecipient", func(s string) error { _, err := age.ParseHybridRecipient(s); return err }},
|
||||
{"age.ParseHybridIdentity", func(s string) error { _, err := age.ParseHybridIdentity(s); return err }},
|
||||
{"plugin.ParseIdentity", func(s string) error { _, _, err := plugin.ParseIdentity(s); return err }},
|
||||
{"plugin.ParseRecipient", func(s string) error { _, _, err := plugin.ParseRecipient(s); return err }},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Errorf("%s panicked on malformed input: %v", tc.name, r)
|
||||
}
|
||||
}()
|
||||
if err := tc.fn(w); err == nil {
|
||||
t.Errorf("%s returned nil error, want error", tc.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,14 +154,21 @@ func Decode(s string) (hrp string, data []byte, err error) {
|
||||
return "", nil, fmt.Errorf("invalid character human-readable part: s[%d]=%d", p, c)
|
||||
}
|
||||
}
|
||||
s = strings.ToLower(s)
|
||||
for p, c := range s[pos+1:] {
|
||||
// Fold ASCII explicitly. Unicode case folding can turn a non-ASCII
|
||||
// rune into a shorter valid charset member.
|
||||
if c >= 'A' && c <= 'Z' {
|
||||
c += 'a' - 'A'
|
||||
}
|
||||
d := strings.IndexRune(charset, c)
|
||||
if d == -1 {
|
||||
return "", nil, fmt.Errorf("invalid character data part: s[%d]=%v", p, c)
|
||||
}
|
||||
data = append(data, byte(d))
|
||||
}
|
||||
if len(data) < 6 {
|
||||
return "", nil, fmt.Errorf("data part too short")
|
||||
}
|
||||
if !verifyChecksum(hrp, data) {
|
||||
return "", nil, fmt.Errorf("invalid checksum")
|
||||
}
|
||||
|
||||
@@ -93,3 +93,23 @@ func TestBech32(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeShortDataPart(t *testing.T) {
|
||||
kelvin := string(rune(0x212A))
|
||||
for _, s := range []string{
|
||||
"AA3100AC" + kelvin,
|
||||
"BK1" + kelvin + "0JFM",
|
||||
"AQM1KZCML",
|
||||
} {
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Errorf("Decode(%+q) panicked: %v", s, r)
|
||||
}
|
||||
}()
|
||||
if _, _, err := bech32.Decode(s); err == nil {
|
||||
t.Errorf("Decode(%+q) = nil error, want error", s)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user