fix timing oracle attack against signature V2/V4 verification (#5335)

This change replaces the non-constant time comparison of
request signatures with a constant time implementation. This
prevents a timing attack which can be used to learn a valid 
signature for a request without knowing the secret key.

Fixes #5334
This commit is contained in:
Andreas Auernhammer
2018-01-02 07:30:02 +01:00
committed by Nitish Tiwari
parent e39d7ddb0f
commit a6318dbdaf
4 changed files with 52 additions and 16 deletions

View File

@@ -26,6 +26,7 @@ package cmd
import (
"bytes"
"crypto/subtle"
"encoding/hex"
"net/http"
"net/url"
@@ -34,7 +35,7 @@ import (
"strings"
"time"
"github.com/minio/sha256-simd"
sha256 "github.com/minio/sha256-simd"
)
// AWS Signature Version '4' constants.
@@ -146,6 +147,15 @@ func doesPolicySignatureMatch(formValues http.Header) APIErrorCode {
return doesPolicySignatureV4Match(formValues)
}
// compareSignatureV4 returns true if and only if both signatures
// are equal. The signatures are expected to be HEX encoded strings
// according to the AWS S3 signature V4 spec.
func compareSignatureV4(sig1, sig2 string) bool {
// The CTC using []byte(str) works because the hex encoding
// is unique for a sequence of bytes. See also compareSignatureV2.
return subtle.ConstantTimeCompare([]byte(sig1), []byte(sig2)) == 1
}
// doesPolicySignatureMatch - Verify query headers with post policy
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
// returns ErrNone if the signature matches.
@@ -180,7 +190,7 @@ func doesPolicySignatureV4Match(formValues http.Header) APIErrorCode {
newSignature := getSignature(signingKey, formValues.Get("Policy"))
// Verify signature.
if newSignature != formValues.Get("X-Amz-Signature") {
if !compareSignatureV4(newSignature, formValues.Get("X-Amz-Signature")) {
return ErrSignatureDoesNotMatch
}
@@ -301,7 +311,7 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s
newSignature := getSignature(presignedSigningKey, presignedStringToSign)
// Verify signature.
if req.URL.Query().Get("X-Amz-Signature") != newSignature {
if !compareSignatureV4(req.URL.Query().Get("X-Amz-Signature"), newSignature) {
return ErrSignatureDoesNotMatch
}
return ErrNone
@@ -380,7 +390,7 @@ func doesSignatureMatch(hashedPayload string, r *http.Request, region string) AP
newSignature := getSignature(signingKey, stringToSign)
// Verify if signature match.
if newSignature != signV4Values.Signature {
if !compareSignatureV4(newSignature, signV4Values.Signature) {
return ErrSignatureDoesNotMatch
}