From c20c402492d30a46ad33cb6a613fcb38dd2886e2 Mon Sep 17 00:00:00 2001 From: InnovativeUS <86477631+InnovativeUS@users.noreply.github.com> Date: Fri, 17 Jan 2025 18:16:34 +0000 Subject: [PATCH] add support for passing a1 into the digest --- digest.go | 14 +++++++++++--- digest_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/digest.go b/digest.go index f7deef1..6fe6b4f 100644 --- a/digest.go +++ b/digest.go @@ -27,6 +27,7 @@ type Options struct { URI string GetBody func() (io.ReadCloser, error) Count int + A1 string Username string Password string @@ -76,11 +77,18 @@ func Digest(chal *Challenge, o Options) (*Credentials, error) { if cred.Userhash { cred.Username = hashf(h, "%s:%s", o.Username, cred.Realm) } + + a1 := o.A1 + + if a1 == "" { + a1 = hashf(h, "%s:%s:%s", o.Username, cred.Realm, o.Password) + } + // generate the response switch { case len(chal.QOP) == 0: cred.Response = hashf(h, "%s:%s:%s", - hashf(h, "%s:%s:%s", o.Username, cred.Realm, o.Password), // A1 + a1, // A1 cred.Nonce, hashf(h, "%s:%s", o.Method, o.URI), // A2 ) @@ -93,7 +101,7 @@ func Digest(chal *Challenge, o Options) (*Credentials, error) { cred.Nc = 1 } cred.Response = hashf(h, "%s:%s:%08x:%s:%s:%s", - hashf(h, "%s:%s:%s", o.Username, cred.Realm, o.Password), // A1 + a1, // A1 cred.Nonce, cred.Nc, cred.Cnonce, @@ -113,7 +121,7 @@ func Digest(chal *Challenge, o Options) (*Credentials, error) { return nil, fmt.Errorf("digest: failed to read body for auth-int: %w", err) } cred.Response = hashf(h, "%s:%s:%08x:%s:%s:%s", - hashf(h, "%s:%s:%s", o.Username, cred.Realm, o.Password), // A1 + a1, // A1 cred.Nonce, cred.Nc, cred.Cnonce, diff --git a/digest_test.go b/digest_test.go index 282afcc..4ea1233 100644 --- a/digest_test.go +++ b/digest_test.go @@ -1,6 +1,9 @@ package digest import ( + "crypto/sha256" + "encoding/hex" + "fmt" "testing" "gotest.tools/v3/assert" @@ -108,6 +111,35 @@ func TestDigestSHA256(t *testing.T) { }) } +func TestDigestA1(t *testing.T) { + opt := Options{ + Method: "GET", + URI: "/dir/index.html", + A1: sha265Hash("%s:%s:%s", "Mufasa", "http-auth@example.org", "Circle of Life"), + Cnonce: "f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ", + } + chal := &Challenge{ + Realm: "http-auth@example.org", + Nonce: "7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", + Algorithm: "SHA-256", + Opaque: "FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS", + QOP: []string{"auth", "auth-int"}, + } + cred, err := Digest(chal, opt) + assert.NilError(t, err) + assert.DeepEqual(t, cred, &Credentials{ + Realm: "http-auth@example.org", + Nonce: "7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", + URI: "/dir/index.html", + Response: "753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1", + Algorithm: "SHA-256", + Cnonce: "f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ", + Opaque: "FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS", + QOP: "auth", + Nc: 1, + }) +} + func TestDigestUserhash(t *testing.T) { opt := Options{ Method: "GET", @@ -172,3 +204,9 @@ func TestDigestAuthInt(t *testing.T) { Nc: 1, }) } + +func sha265Hash(format string, args ...interface{}) string { + h := sha256.New() + fmt.Fprintf(h, format, args...) + return hex.EncodeToString(h.Sum(nil)) +}