From 33bd2c81bf2403d47ee6f6c60b383c4b668db177 Mon Sep 17 00:00:00 2001 From: Sindre Myren Date: Thu, 10 Mar 2022 19:39:00 +0100 Subject: [PATCH] fix: let decode look for additional base32 padding Update FromString and XID.TextUnmarshal so that it looks for discarded bits in the final source character. This fixes an issue where XIDs that have been manually tampered with in a way that's ignored by base32 decode, will not pass as valid. --- id.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/id.go b/id.go index 17a4721..97c6065 100644 --- a/id.go +++ b/id.go @@ -238,7 +238,9 @@ func (id *ID) UnmarshalText(text []byte) error { return ErrInvalidID } } - decode(id, text) + if !decode(id, text) { + return ErrInvalidID + } return nil } @@ -256,8 +258,8 @@ func (id *ID) UnmarshalJSON(b []byte) error { return id.UnmarshalText(b[1 : len(b)-1]) } -// decode by unrolling the stdlib base32 algorithm + removing all safe checks -func decode(id *ID, src []byte) { +// decode by unrolling the stdlib base32 algorithm + customized safe check. +func decode(id *ID, src []byte) bool { _ = src[19] _ = id[11] @@ -273,6 +275,19 @@ func decode(id *ID, src []byte) { id[2] = dec[src[3]]<<4 | dec[src[4]]>>1 id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4 id[0] = dec[src[0]]<<3 | dec[src[1]]>>2 + + // Validate that there are no discarer bits (padding) in src that would + // cause the string-encoded id not to equal src. + var check [4]byte + + check[3] = encoding[(id[11]<<4)&0x1F] + check[2] = encoding[(id[11]>>1)&0x1F] + check[1] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F] + check[0] = encoding[id[10]>>3] + if !bytes.Equal([]byte(src[16:20]), check[:]) { + return false + } + return true } // Time returns the timestamp part of the id.