diff options
author | John Jannotti <jannotti@gmail.com> | 2022-05-21 23:38:15 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-21 23:38:15 -0400 |
commit | 4a922c405f6847854e569a2624c97b7549078091 (patch) | |
tree | ce698fe9f47c94e085b38a3f4c9e19cd6afe0f60 | |
parent | d06c9aa33d7cfdf55174dcc76b9465407fb05de9 (diff) |
base64_decode can decode padded or unpadded encodings (#4015)2062-on-chain-warning-scenario-3
-rw-r--r-- | data/transactions/logic/eval.go | 22 | ||||
-rw-r--r-- | data/transactions/logic/eval_test.go | 24 |
2 files changed, 27 insertions, 19 deletions
diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index e621ef38e..2a2614b94 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -4716,6 +4716,21 @@ func base64Decode(encoded []byte, encoding *base64.Encoding) ([]byte, error) { return decoded[:n], err } +// base64padded returns true iff `encoded` has padding chars at the end +func base64padded(encoded []byte) bool { + for i := len(encoded) - 1; i > 0; i-- { + switch encoded[i] { + case '=': + return true + case '\n', '\r': + /* nothing */ + default: + return false + } + } + return false +} + func opBase64Decode(cx *EvalContext) error { last := len(cx.stack) - 1 encodingField := Base64Encoding(cx.program[cx.pc+1]) @@ -4728,8 +4743,11 @@ func opBase64Decode(cx *EvalContext) error { if encodingField == StdEncoding { encoding = base64.StdEncoding } - encoding = encoding.Strict() - bytes, err := base64Decode(cx.stack[last].Bytes, encoding) + encoded := cx.stack[last].Bytes + if !base64padded(encoded) { + encoding = encoding.WithPadding(base64.NoPadding) + } + bytes, err := base64Decode(encoded, encoding.Strict()) if err != nil { return err } diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go index 04b3741eb..9e54e7b29 100644 --- a/data/transactions/logic/eval_test.go +++ b/data/transactions/logic/eval_test.go @@ -4649,12 +4649,12 @@ By Herman Melville`, "", {"cGFk=", "StdEncoding", "pad", "input byte 4"}, {"cGFk==", "StdEncoding", "pad", "input byte 4"}, {"cGFk===", "StdEncoding", "pad", "input byte 4"}, - // Ensures that even correct padding is illegal if not needed + // Ensures that extra padding, even if 0%4 {"cGFk====", "StdEncoding", "pad", "input byte 4"}, - // Test that padding must be present to make len = 0 mod 4. + // Test that padding must be correct or absent {"bm9wYWQ=", "StdEncoding", "nopad", ""}, - {"bm9wYWQ", "StdEncoding", "nopad", "illegal"}, + {"bm9wYWQ", "StdEncoding", "nopad", ""}, {"bm9wYWQ==", "StdEncoding", "nopad", "illegal"}, {"YWJjMTIzIT8kKiYoKSctPUB+", "StdEncoding", "abc123!?$*&()'-=@~", ""}, @@ -4690,15 +4690,15 @@ By Herman Melville`, "", {"\rS\r\nQ=\n=\r\r\n", "StdEncoding", "I", ""}, {"\rS\r\nQ=\n=\r\r\n", "URLEncoding", "I", ""}, - // Padding necessary? - Yes it is! And exactly the expected place and amount. + // If padding is there, it must be correct, but if absent, that's fine. {"SQ==", "StdEncoding", "I", ""}, {"SQ==", "URLEncoding", "I", ""}, {"S=Q=", "StdEncoding", "", "byte 1"}, {"S=Q=", "URLEncoding", "", "byte 1"}, {"=SQ=", "StdEncoding", "", "byte 0"}, {"=SQ=", "URLEncoding", "", "byte 0"}, - {"SQ", "StdEncoding", "", "byte 0"}, - {"SQ", "URLEncoding", "", "byte 0"}, + {"SQ", "StdEncoding", "I", ""}, + {"SQ", "URLEncoding", "I", ""}, {"SQ=", "StdEncoding", "", "byte 3"}, {"SQ=", "URLEncoding", "", "byte 3"}, {"SQ===", "StdEncoding", "", "byte 4"}, @@ -4721,17 +4721,6 @@ By Herman Melville`, "", if LogicVersion < fidoVersion { testProg(t, source, AssemblerMaxVersion, Expect{0, "unknown opcode..."}) } else { - // sanity check - test the helper function first: - encoding := base64.URLEncoding - if tc.alph == "StdEncoding" { - encoding = base64.StdEncoding - } - encoding = encoding.Strict() - decoded, err := base64Decode([]byte(tc.encoded), encoding) - require.NoError(t, err) - require.Equal(t, string(decoded), tc.decoded) - - // now check eval: testAccepts(t, source, fidoVersion) } } else { @@ -4739,6 +4728,7 @@ By Herman Melville`, "", testProg(t, source, AssemblerMaxVersion, Expect{0, "unknown opcode..."}) } else { err := testPanics(t, source, fidoVersion) + require.Error(t, err) require.Contains(t, err.Error(), tc.error) } } |