S3 API: unsigned streaming (no cred) but chunks contain signatures (#7118)

* This handles the case where we have unsigned streaming (no cred) but chunks contain signatures

* Update chunked_reader_v4.go

* address comments
This commit is contained in:
Chris Lu
2025-08-11 10:31:01 -07:00
committed by GitHub
parent a265a07922
commit 9265e81fe9
2 changed files with 86 additions and 13 deletions

View File

@@ -440,18 +440,35 @@ func (cr *s3ChunkedReader) Read(buf []byte) (n int, err error) {
continue
}
case verifyChunk:
// Calculate the hashed chunk.
hashedChunk := hex.EncodeToString(cr.chunkSHA256Writer.Sum(nil))
// Calculate the chunk signature.
newSignature := cr.getChunkSignature(hashedChunk)
if !compareSignatureV4(cr.chunkSignature, newSignature) {
// Chunk signature doesn't match we return signature does not match.
cr.err = errors.New(s3err.ErrMsgChunkSignatureMismatch)
return 0, cr.err
// Check if we have credentials for signature verification
// This handles the case where we have unsigned streaming (no cred) but chunks contain signatures
//
// BUG FIX for GitHub issue #6847:
// Some AWS SDK versions (Java 3.7.412+, .NET 4.0.0-preview.6+) send mixed format:
// - HTTP headers indicate unsigned streaming (STREAMING-UNSIGNED-PAYLOAD-TRAILER)
// - But chunk data contains chunk-signature headers (normally only for signed streaming)
// This causes a nil pointer dereference when trying to verify signatures without credentials
if cr.cred != nil {
// Normal signed streaming - verify the chunk signature
// Calculate the hashed chunk.
hashedChunk := hex.EncodeToString(cr.chunkSHA256Writer.Sum(nil))
// Calculate the chunk signature.
newSignature := cr.getChunkSignature(hashedChunk)
if !compareSignatureV4(cr.chunkSignature, newSignature) {
// Chunk signature doesn't match we return signature does not match.
cr.err = errors.New(s3err.ErrMsgChunkSignatureMismatch)
return 0, cr.err
}
// Newly calculated signature becomes the seed for the next chunk
// this follows the chaining.
cr.seedSignature = newSignature
} else {
// For unsigned streaming, we should not verify chunk signatures even if they are present
// This fixes the bug where AWS SDKs send chunk signatures with unsigned streaming headers
glog.V(3).Infof("Skipping chunk signature verification for unsigned streaming")
}
// Newly calculated signature becomes the seed for the next chunk
// this follows the chaining.
cr.seedSignature = newSignature
// Common cleanup and state transition for both signed and unsigned streaming
cr.chunkSHA256Writer.Reset()
if cr.lastChunk {
cr.state = eofChunk
@@ -513,9 +530,10 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) {
if err != nil {
// We always know when EOF is coming.
// If the caller asked for a line, there should be a line.
if err == io.EOF {
switch err {
case io.EOF:
err = io.ErrUnexpectedEOF
} else if err == bufio.ErrBufferFull {
case bufio.ErrBufferFull:
err = errLineTooLong
}
return nil, err