From cdb30a188bcdc8b58365934588bac18020252b9b Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sat, 29 Aug 2026 18:37:03 +0200 Subject: [PATCH] cmd/age: recognize armored identity files after whitespace Reported by Joe Doyle of Trail of Bits. --- cmd/age/parse.go | 13 ++++++++----- cmd/age/testdata/encrypted_keys.txt | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/cmd/age/parse.go b/cmd/age/parse.go index d83a0cc..e0f2baa 100644 --- a/cmd/age/parse.go +++ b/cmd/age/parse.go @@ -6,6 +6,7 @@ package main import ( "bufio" + "bytes" "crypto/rsa" "encoding/base64" "fmt" @@ -179,14 +180,16 @@ func parseIdentitiesFile(name string) ([]age.Identity, error) { } b := bufio.NewReader(f) - p, _ := b.Peek(14) // length of "age-encryption" and "-----BEGIN AGE" - peeked := string(p) + const maxWhitespace = 1024 + p, _ := b.Peek(maxWhitespace + len(armor.Header)) + trimmed := bytes.TrimSpace(p) switch { // An age encrypted file, plain or armored. - case peeked == "age-encryption" || peeked == "-----BEGIN AGE": + case bytes.HasPrefix(p, []byte("age-encryption")) || + bytes.HasPrefix(trimmed, []byte(armor.Header)): var r io.Reader = b - if peeked == "-----BEGIN AGE" { + if bytes.HasPrefix(trimmed, []byte(armor.Header)) { r = armor.NewReader(r) } const privateKeySizeLimit = 1 << 24 // 16 MiB @@ -212,7 +215,7 @@ func parseIdentitiesFile(name string) ([]age.Identity, error) { }}, nil // Another PEM file, possibly an SSH private key. - case strings.HasPrefix(peeked, "-----BEGIN"): + case bytes.HasPrefix(trimmed, []byte("-----BEGIN")): const privateKeySizeLimit = 1 << 14 // 16 KiB contents, err := io.ReadAll(io.LimitReader(b, privateKeySizeLimit)) if err != nil { diff --git a/cmd/age/testdata/encrypted_keys.txt b/cmd/age/testdata/encrypted_keys.txt index 050bf13..58a4e10 100644 --- a/cmd/age/testdata/encrypted_keys.txt +++ b/cmd/age/testdata/encrypted_keys.txt @@ -60,10 +60,26 @@ ttyout 'Enter passphrase' ! stderr . cmp stdout input +# armored identity files accept leading whitespace +exec age-keygen -o key.txt +age -e -i key.txt -o test.age input +ttyin newpass +age -p -a -o key.age key.txt +exec cat blank key.age +cp stdout key-with-blank.age +ttyin terminal +age -d -i key-with-blank.age test.age +cmp stdout input + -- input -- test -- terminal -- password +-- newpass -- +password +password +-- blank -- + -- key_ed25519 -- -----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCuvb97i7