You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[SDK CPP] WHEN_REQUIRED drops the checksum body/trailer even when SetChecksumAlgorithm is called explicitly, producing a malformed signed request (400 InvalidRequest) #3859
When S3ClientConfiguration::checksumConfig.requestChecksumCalculation is set
to RequestChecksumCalculation::WHEN_REQUIREDand the caller explicitly
calls SetChecksumAlgorithm(CRC32) on a non-multipart PutObjectRequest,
the SDK still signs the request as if a checksum algorithm was supplied
(x-amz-sdk-checksum-algorithm ends up in the signed headers), but does not actually attach the checksum — neither as an inline x-amz-checksum-crc32 header (non-chunked path) nor as an x-amz-trailer/aws-chunked trailer (streaming path).
The resulting request is malformed and S3 correctly rejects it with a 400 InvalidRequest:
x-amz-sdk-checksum-algorithm specified, but no corresponding x-amz-checksum-*
or x-amz-trailer headers were found.
This defeats the documented purpose of WHEN_REQUIRED. Per AWS's own
documentation (Data Integrity Protections for Amazon S3 / docs.aws.amazon.com/sdkref/latest/guide/feature-dataintegrity.html) and the
equivalent Java SDK docs, WHEN_REQUIRED is meant to suppress the SDK's unsolicited default checksum for operations that don't strictly require
one — it should still honor a checksum the caller explicitly asked for via SetChecksumAlgorithm. Right now it does neither correctly: it signs as if
the checksum were present, but omits it.
Select this option if this issue appears to be a regression: Yes — checksumConfig (and this WHEN_REQUIRED/WHEN_SUPPORTED distinction) didn't
exist prior to 1.11.486 (the "default integrity protections" / DIP release).
Pre-486 SDKs (tested: 1.11.421) always compute and attach the checksum when SetChecksumAlgorithm is called explicitly, regardless of any "required vs
supported" concept, so this is a regression introduced by the DIP rollout
and its ChecksumInterceptor (introduced in commit ac9296d7a0b, refactored
further in faa33a61862 / PR #3500).
Regression Issue
Select this option if this issue appears to be a regression.
Expected Behavior
With requestChecksumCalculation = WHEN_REQUIRED and an explicit SetChecksumAlgorithm(CRC32) call, the SDK should still compute and attach
the CRC32 checksum (either inline or via trailer, following the same
streaming/non-streaming logic used under WHEN_SUPPORTED), because the
caller explicitly requested it. WHEN_REQUIRED should only change behavior
for the unsolicited/default checksum case (i.e., when the caller does not call SetChecksumAlgorithm at all).
Current Behavior
PutObject succeeds when requestChecksumCalculation is left at its
default (WHEN_SUPPORTED) or explicitly set to WHEN_SUPPORTED, with SetChecksumAlgorithm(CRC32) set on the request.
PutObjectfails with a 400 InvalidRequest when requestChecksumCalculation is explicitly set to WHEN_REQUIRED, with the
exact same SetChecksumAlgorithm(CRC32) call on the request. Error:
PutObject FAILED
ExceptionName: InvalidRequest
Message: x-amz-sdk-checksum-algorithm specified, but no corresponding
x-amz-checksum-* or x-amz-trailer headers were found.
RequestId: NQDF14VJ7M6SSFPY
ResponseCode: 400
Confirmed reproducible on:
1.11.712
main @ 1.11.840 (current HEAD as of this report) — not fixed
upstream
Confirmed not reproducible / not applicable on:
1.11.421 (pre-DIP; checksumConfig doesn't exist, SetChecksumAlgorithm
always results in a computed+attached checksum)
Toggling only config.checksumConfig.requestChecksumCalculation between WHEN_SUPPORTED (or leaving it unset, which defaults to WHEN_SUPPORTED)
and WHEN_REQUIRED is the only variable — everything else (SDK version,
client, bucket, algorithm, body) is held constant.
A full, version-parameterized repro harness (build script + test app that
can be linked against multiple aws-sdk-cpp versions) is available on
request / can be attached to this issue.
Possible Solution
In src/aws-cpp-sdk-core/include/smithy/client/features/ChecksumInterceptor.h,
the branch that resolves whether to attach a checksum appears to gate solely
on m_requestChecksumCalculation without independently checking whether the
caller already provided an explicit checksum algorithm/value
(checksumValueAndAlgorithmProvided / handleProvidedChecksum in the
current refactor from PR #3500). The fix likely needs handleProvidedChecksum (or its caller) to always run when the caller
explicitly set an algorithm, independent of the WHEN_REQUIRED/WHEN_SUPPORTED gate — that gate should only affect whether calculateAndSetChecksum (the unsolicited/default path) runs.
Separately, whatever adds x-amz-sdk-checksum-algorithm to the
signed-headers set (likely in the signer, not this file) should be
conditioned on the same "did we actually attach a checksum" outcome, so the
signed-headers claim and the actual request body never disagree.
Additional Information/Context
This is the same class of bug that's been reported against other AWS
SDKs/tools for the WHEN_REQUIRED setting, just manifesting differently
each time — e.g. boto/s3transfer#327 (CLI ignores WHEN_REQUIRED
entirely and sends the checksum anyway) and the Akamai/OUTSCALE
compatibility notes documenting WHEN_REQUIRED as the standard workaround
for third-party S3-compatible endpoints that don't support the newer
checksum trailer format. In our case it's the opposite failure mode: WHEN_REQUIRED is honored too aggressively and drops a checksum the
caller explicitly asked for.
Possibly related: Checksum verification fails for composite checkum types #3496 (composite checksum response validation failing,
also in ChecksumInterceptor.h, also worked around via WHEN_REQUIRED/responseChecksumValidation) — suggests the WHEN_REQUIRED/WHEN_SUPPORTED resolution logic in this file may have
more than one edge case around explicit-vs-default checksum handling.
We hit this against a non-AWS, S3-compatible portal, initially trying to
use WHEN_REQUIRED specifically as the documented workaround for
compatibility with that portal — this bug means that workaround is
unusable for any call that also sets an explicit checksum algorithm.
AWS CPP SDK version: 1.11.712 and main @ 1.11.840 (both reproduce);
1.11.421 does not (feature doesn't exist pre-486)
Compiler and Version: g++ 13.3.0
Operating System: Ubuntu 24.04
Region: us-west-1
AWS CPP SDK version used
1.11.712 and main @ 1.11.840 (both reproduce); 1.11.421 does not (feature doesn't exist pre-486)
Describe the bug
When
S3ClientConfiguration::checksumConfig.requestChecksumCalculationis setto
RequestChecksumCalculation::WHEN_REQUIREDand the caller explicitlycalls
SetChecksumAlgorithm(CRC32)on a non-multipartPutObjectRequest,the SDK still signs the request as if a checksum algorithm was supplied
(
x-amz-sdk-checksum-algorithmends up in the signed headers), but doesnot actually attach the checksum — neither as an inline
x-amz-checksum-crc32header (non-chunked path) nor as anx-amz-trailer/aws-chunkedtrailer (streaming path).The resulting request is malformed and S3 correctly rejects it with a
400 InvalidRequest:This defeats the documented purpose of
WHEN_REQUIRED. Per AWS's owndocumentation (Data Integrity Protections for Amazon S3 /
docs.aws.amazon.com/sdkref/latest/guide/feature-dataintegrity.html) and theequivalent Java SDK docs,
WHEN_REQUIREDis meant to suppress the SDK'sunsolicited default checksum for operations that don't strictly require
one — it should still honor a checksum the caller explicitly asked for via
SetChecksumAlgorithm. Right now it does neither correctly: it signs as ifthe checksum were present, but omits it.
Select this option if this issue appears to be a regression: Yes —
checksumConfig(and this WHEN_REQUIRED/WHEN_SUPPORTED distinction) didn'texist prior to 1.11.486 (the "default integrity protections" / DIP release).
Pre-486 SDKs (tested: 1.11.421) always compute and attach the checksum when
SetChecksumAlgorithmis called explicitly, regardless of any "required vssupported" concept, so this is a regression introduced by the DIP rollout
and its
ChecksumInterceptor(introduced in commitac9296d7a0b, refactoredfurther in
faa33a61862/ PR #3500).Regression Issue
Expected Behavior
With
requestChecksumCalculation = WHEN_REQUIREDand an explicitSetChecksumAlgorithm(CRC32)call, the SDK should still compute and attachthe CRC32 checksum (either inline or via trailer, following the same
streaming/non-streaming logic used under
WHEN_SUPPORTED), because thecaller explicitly requested it.
WHEN_REQUIREDshould only change behaviorfor the unsolicited/default checksum case (i.e., when the caller does
not call
SetChecksumAlgorithmat all).Current Behavior
PutObjectsucceeds whenrequestChecksumCalculationis left at itsdefault (
WHEN_SUPPORTED) or explicitly set toWHEN_SUPPORTED, withSetChecksumAlgorithm(CRC32)set on the request.PutObjectfails with a 400InvalidRequestwhenrequestChecksumCalculationis explicitly set toWHEN_REQUIRED, with theexact same
SetChecksumAlgorithm(CRC32)call on the request. Error:Confirmed reproducible on:
main@ 1.11.840 (current HEAD as of this report) — not fixedupstream
Confirmed not reproducible / not applicable on:
checksumConfigdoesn't exist,SetChecksumAlgorithmalways results in a computed+attached checksum)
Reproduction Steps
Toggling only
config.checksumConfig.requestChecksumCalculationbetweenWHEN_SUPPORTED(or leaving it unset, which defaults toWHEN_SUPPORTED)and
WHEN_REQUIREDis the only variable — everything else (SDK version,client, bucket, algorithm, body) is held constant.
A full, version-parameterized repro harness (build script + test app that
can be linked against multiple
aws-sdk-cppversions) is available onrequest / can be attached to this issue.
Possible Solution
In
src/aws-cpp-sdk-core/include/smithy/client/features/ChecksumInterceptor.h,the branch that resolves whether to attach a checksum appears to gate solely
on
m_requestChecksumCalculationwithout independently checking whether thecaller already provided an explicit checksum algorithm/value
(
checksumValueAndAlgorithmProvided/handleProvidedChecksumin thecurrent refactor from PR #3500). The fix likely needs
handleProvidedChecksum(or its caller) to always run when the callerexplicitly set an algorithm, independent of the
WHEN_REQUIRED/WHEN_SUPPORTEDgate — that gate should only affect whethercalculateAndSetChecksum(the unsolicited/default path) runs.Separately, whatever adds
x-amz-sdk-checksum-algorithmto thesigned-headers set (likely in the signer, not this file) should be
conditioned on the same "did we actually attach a checksum" outcome, so the
signed-headers claim and the actual request body never disagree.
Additional Information/Context
This is the same class of bug that's been reported against other AWS
SDKs/tools for the
WHEN_REQUIREDsetting, just manifesting differentlyeach time — e.g.
boto/s3transfer#327(CLI ignoresWHEN_REQUIREDentirely and sends the checksum anyway) and the Akamai/OUTSCALE
compatibility notes documenting
WHEN_REQUIREDas the standard workaroundfor third-party S3-compatible endpoints that don't support the newer
checksum trailer format. In our case it's the opposite failure mode:
WHEN_REQUIREDis honored too aggressively and drops a checksum thecaller explicitly asked for.
Possibly related: Checksum verification fails for composite checkum types #3496 (composite checksum response validation failing,
also in
ChecksumInterceptor.h, also worked around viaWHEN_REQUIRED/responseChecksumValidation) — suggests theWHEN_REQUIRED/WHEN_SUPPORTEDresolution logic in this file may havemore than one edge case around explicit-vs-default checksum handling.
We hit this against a non-AWS, S3-compatible portal, initially trying to
use
WHEN_REQUIREDspecifically as the documented workaround forcompatibility with that portal — this bug means that workaround is
unusable for any call that also sets an explicit checksum algorithm.
AWS CPP SDK version: 1.11.712 and
main@ 1.11.840 (both reproduce);1.11.421 does not (feature doesn't exist pre-486)
Compiler and Version: g++ 13.3.0
Operating System: Ubuntu 24.04
Region: us-west-1
AWS CPP SDK version used
1.11.712 and
main@ 1.11.840 (both reproduce); 1.11.421 does not (feature doesn't exist pre-486)Compiler and Version used
gcc 11.4.0
Operating System and version
Ubuntu 22.04.5 LTS (Jammy Jellyfish)