From 4e6f2d8e7be40e86766ce33808e8768fa240e303 Mon Sep 17 00:00:00 2001 From: Vladislav Yarmak Date: Sun, 1 Dec 2024 16:42:47 +0200 Subject: [PATCH 1/4] strict option --- README.md | 2 ++ cmd/main.go | 2 ++ handler/handler.go | 3 ++- hmac/hmac.go | 20 +++++++++++--------- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 9446276..feeed96 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ Usage of /usr/local/bin/basic_hmac_auth: hex-encoded HMAC secret value -secret-file string file containing single line with hex-encoded secret + -strict + require shortest possible, invariant form of encoding -version show program version and exit ``` diff --git a/cmd/main.go b/cmd/main.go index b57486f..abfc9fa 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -22,6 +22,7 @@ const ( var ( bufferSize = flag.Int("buffer-size", 0, "initial buffer size for stream parsing") + strict = flag.Bool("strict", false, "require shortest possible, invariant form of encoding") hexSecret = flag.String("secret", "", "hex-encoded HMAC secret value") hexSecretFile = flag.String("secret-file", "", "file containing single line with hex-encoded secret") showVersion = flag.Bool("version", false, "show program version and exit") @@ -80,6 +81,7 @@ func run() int { err = (&handler.BasicHMACAuthHandler{ Secret: secret, BufferSize: *bufferSize, + Strict: *strict, }).Run(os.Stdin, os.Stdout) if err != nil { log.Printf("auth handler terminated with error: %v", err) diff --git a/handler/handler.go b/handler/handler.go index d24ab91..c49d7e2 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -18,6 +18,7 @@ const ( type BasicHMACAuthHandler struct { Secret []byte BufferSize int + Strict bool } func (a *BasicHMACAuthHandler) Run(input io.Reader, output io.Writer) error { @@ -28,7 +29,7 @@ func (a *BasicHMACAuthHandler) Run(input io.Reader, output io.Writer) error { rd := bufio.NewReaderSize(input, bufSize) scanner := proto.NewElasticLineScanner(rd, '\n') - verifier := hmac.NewVerifier(a.Secret) + verifier := hmac.NewVerifier(a.Secret, a.Strict) emitter := proto.NewResponseEmitter(output) diff --git a/hmac/hmac.go b/hmac/hmac.go index 3e96a8b..97518e9 100644 --- a/hmac/hmac.go +++ b/hmac/hmac.go @@ -12,7 +12,6 @@ import ( const ( HMACSignaturePrefix = "dumbproxy grant token v1" HMACExpireSize = 8 - passwordBufferSize = HMACExpireSize + 64 // for worst case if 512-bit hash is used for some reason ) var hmacSignaturePrefix = []byte(HMACSignaturePrefix) @@ -22,13 +21,15 @@ func NewHasher(secret []byte) hash.Hash { } type Verifier struct { - mac hash.Hash - buf []byte + mac hash.Hash + buf []byte + strict bool } -func NewVerifier(secret []byte) *Verifier { +func NewVerifier(secret []byte, strict bool) *Verifier { return &Verifier{ - mac: hmac.New(sha256.New, secret), + mac: hmac.New(sha256.New, secret), + strict: strict, } } @@ -39,12 +40,13 @@ func (v *Verifier) ensureBufferSize(size int) { } func (v *Verifier) VerifyLoginAndPassword(login, password []byte) bool { - v.ensureBufferSize(base64.RawURLEncoding.DecodedLen(len(password))) - buf := v.buf - n, err := base64.RawURLEncoding.Decode(buf, password) - if err != nil { + if v.strict && len(password) != base64.RawURLEncoding.EncodedLen(HMACExpireSize+v.mac.Size()) { return false } + + v.ensureBufferSize(base64.RawURLEncoding.DecodedLen(len(password))) + buf := v.buf + n, _ := base64.RawURLEncoding.Decode(buf, password) buf = buf[:n] var expire int64 From d789cd52ccc54118769f6e178164084aa71c7914 Mon Sep 17 00:00:00 2001 From: Vladislav Yarmak Date: Sun, 1 Dec 2024 17:12:39 +0200 Subject: [PATCH 2/4] use strict base64 decoder for strict mode --- hmac/hmac.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hmac/hmac.go b/hmac/hmac.go index 97518e9..61eb952 100644 --- a/hmac/hmac.go +++ b/hmac/hmac.go @@ -23,13 +23,19 @@ func NewHasher(secret []byte) hash.Hash { type Verifier struct { mac hash.Hash buf []byte + dec *base64.Encoding strict bool } func NewVerifier(secret []byte, strict bool) *Verifier { + dec := base64.RawURLEncoding + if strict { + dec = dec.Strict() + } return &Verifier{ mac: hmac.New(sha256.New, secret), strict: strict, + dec: dec, } } @@ -40,13 +46,13 @@ func (v *Verifier) ensureBufferSize(size int) { } func (v *Verifier) VerifyLoginAndPassword(login, password []byte) bool { - if v.strict && len(password) != base64.RawURLEncoding.EncodedLen(HMACExpireSize+v.mac.Size()) { + if v.strict && len(password) != v.dec.EncodedLen(HMACExpireSize+v.mac.Size()) { return false } - v.ensureBufferSize(base64.RawURLEncoding.DecodedLen(len(password))) + v.ensureBufferSize(v.dec.DecodedLen(len(password))) buf := v.buf - n, _ := base64.RawURLEncoding.Decode(buf, password) + n, _ := v.dec.Decode(buf, password) buf = buf[:n] var expire int64 From 5775e83c0a20c3acb8aa93ed757f9d30f2c199e3 Mon Sep 17 00:00:00 2001 From: Vladislav Yarmak Date: Sun, 1 Dec 2024 17:13:10 +0200 Subject: [PATCH 3/4] strict mode by default --- README.md | 2 +- cmd/main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index feeed96..64628d6 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Usage of /usr/local/bin/basic_hmac_auth: -secret-file string file containing single line with hex-encoded secret -strict - require shortest possible, invariant form of encoding + require shortest possible, invariant form of encoding (default true) -version show program version and exit ``` diff --git a/cmd/main.go b/cmd/main.go index abfc9fa..75d5311 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -22,7 +22,7 @@ const ( var ( bufferSize = flag.Int("buffer-size", 0, "initial buffer size for stream parsing") - strict = flag.Bool("strict", false, "require shortest possible, invariant form of encoding") + strict = flag.Bool("strict", true, "require shortest possible, invariant form of encoding") hexSecret = flag.String("secret", "", "hex-encoded HMAC secret value") hexSecretFile = flag.String("secret-file", "", "file containing single line with hex-encoded secret") showVersion = flag.Bool("version", false, "show program version and exit") From c9169bba5d8c26ea85fb85c7a9c12115ac4e5107 Mon Sep 17 00:00:00 2001 From: Vladislav Yarmak Date: Sun, 1 Dec 2024 17:15:19 +0200 Subject: [PATCH 4/4] explicit error handling for strict decoding --- hmac/hmac.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hmac/hmac.go b/hmac/hmac.go index 61eb952..28b9cfd 100644 --- a/hmac/hmac.go +++ b/hmac/hmac.go @@ -52,7 +52,10 @@ func (v *Verifier) VerifyLoginAndPassword(login, password []byte) bool { v.ensureBufferSize(v.dec.DecodedLen(len(password))) buf := v.buf - n, _ := v.dec.Decode(buf, password) + n, err := v.dec.Decode(buf, password) + if v.strict && err != nil { + return false + } buf = buf[:n] var expire int64