Handle cookie signing errors

This commit is contained in:
Nick Meves
2020-08-09 07:55:40 -07:00
parent 65c228394f
commit 1c8c5b08d7
6 changed files with 64 additions and 39 deletions
+19 -18
View File
@@ -2,19 +2,16 @@ package encryption
import (
"crypto/hmac"
"crypto/rand"
// TODO (@NickMeves): Remove SHA1 signed cookie support in V7
"crypto/sha1" // #nosec G505
"crypto/sha256"
"encoding/base64"
"fmt"
"hash"
"io"
"net/http"
"strconv"
"strings"
"time"
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
)
// SecretBytes attempts to base64 decode the secret, if that fails it treats the secret as binary
@@ -69,40 +66,44 @@ func Validate(cookie *http.Cookie, seed string, expiration time.Duration) (value
}
// SignedValue returns a cookie that is signed and can later be checked with Validate
func SignedValue(seed string, key string, value []byte, now time.Time) string {
func SignedValue(seed string, key string, value []byte, now time.Time) (string, error) {
encodedValue := base64.URLEncoding.EncodeToString(value)
timeStr := fmt.Sprintf("%d", now.Unix())
sig := cookieSignature(sha256.New, seed, key, encodedValue, timeStr)
sig, err := cookieSignature(sha256.New, seed, key, encodedValue, timeStr)
if err != nil {
return "", err
}
cookieVal := fmt.Sprintf("%s|%s|%s", encodedValue, timeStr, sig)
return cookieVal
return cookieVal, nil
}
func cookieSignature(signer func() hash.Hash, args ...string) string {
func cookieSignature(signer func() hash.Hash, args ...string) (string, error) {
h := hmac.New(signer, []byte(args[0]))
for _, arg := range args[1:] {
_, err := h.Write([]byte(arg))
// If signing fails, fail closed and return something that won't validate
if err != nil {
garbage := make([]byte, 16)
if _, err := io.ReadFull(rand.Reader, garbage); err != nil {
logger.Fatal("HMAC & RNG functions both failing. Shutting down for security")
}
return base64.URLEncoding.EncodeToString(garbage)
return "", err
}
}
var b []byte
b = h.Sum(b)
return base64.URLEncoding.EncodeToString(b)
return base64.URLEncoding.EncodeToString(b), nil
}
func checkSignature(signature string, args ...string) bool {
checkSig := cookieSignature(sha256.New, args...)
checkSig, err := cookieSignature(sha256.New, args...)
if err != nil {
return false
}
if checkHmac(signature, checkSig) {
return true
}
// TODO: After appropriate rollout window, remove support for SHA1
legacySig := cookieSignature(sha1.New, args...)
// TODO (@NickMeves): Remove SHA1 signed cookie support in V7
legacySig, err := cookieSignature(sha1.New, args...)
if err != nil {
return false
}
return checkHmac(signature, legacySig)
}
+4 -2
View File
@@ -88,8 +88,10 @@ func TestSignAndValidate(t *testing.T) {
value := base64.URLEncoding.EncodeToString([]byte("I am soooo encoded"))
epoch := "123456789"
sha256sig := cookieSignature(sha256.New, seed, key, value, epoch)
sha1sig := cookieSignature(sha1.New, seed, key, value, epoch)
sha256sig, err := cookieSignature(sha256.New, seed, key, value, epoch)
assert.NoError(t, err)
sha1sig, err := cookieSignature(sha1.New, seed, key, value, epoch)
assert.NoError(t, err)
assert.True(t, checkSignature(sha256sig, seed, key, value, epoch))
// This should be switched to False after fully deprecating SHA1