Conversation
The last commit refused SSE-C everywhere because honoring a caller's key means carrying it on every read and copy, not echoing it back on the write that supplied it. This carries it. The frontend admits the customer-key triple and its copy-source variants onto requests it already builds -- put, get, head, copy, the multipart create, part and completion, the part-copy in both its native and streamed forms, and the POST form fields -- and the aws-s3 store forwards them verbatim like everything else, its service judging the values. The transient store is its own service, so it judges. A write vets the triple -- all three fields together, AES256, a 256-bit key, an MD5 that matches -- and the object comes to rest under the key's MD5 and never the key, which is no more than S3 itself echoes on responses. SSE-C has an observable half SSE-S3 does not: the object answers only to its key. A read presenting none or the wrong one is 400 -- the wrong one too, which the suite pins where AWS's documentation suggests 403 -- and every later request of a multipart upload, each part and the completion alike, must present the create-time key again. The completion response echoes the algorithm and MD5 from the request it judged, the SDK's response type modeling no field for them. Reads are judged in the frontend rather than the store, whose getBlob and blobMetadata also serve the frontend's own bookkeeping -- the stub consulted before a completion, the ETag before a conditional write -- which reads without a key the way S3's own internals do. The stores vet what is always a caller's act: writes, parts, and the copy's source, read inside copyBlob. What both judge the same way lives in CustomerKeys. uploadMultipartPart takes the SDK's UploadPartRequest now, the one call whose carrier had no room for a part's key, presented again on every part as S3 requires. The aws-s3 store forwarding the request instead of rebuilding it also stops dropping the Content-MD5 a part arrived with. The encryption tag admitted whole brings the SSE-KMS conformance tests with it, and they found two holes beside SSE-C. The frontend refuses what is malformed wherever it lands -- an algorithm S3 does not have, a KMS key under an algorithm that does not name one -- because LocalStack accepts both and the pass-through lane has to answer as S3 does; and it refuses the write-side family on GET and HEAD, where an object's encryption is reported, not asked for. The transient store further requires a key id with aws:kms, the way rgw does. kms_keyid becomes an ARN in the lane config for the same reason kms_keyid2 already was: that is what a response carries. Both lanes whose store encrypts run the full tag now and pass -- 659 tests on the transient store, 658 through LocalStack -- and the filesystem lane still refuses the family whole, 501 on every header of it, reporting no encryption it does not perform. Unlike S3, S3Proxy accepts SSE-C over plain HTTP, its TLS commonly terminating elsewhere. See #402. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Owner
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The last commit refused SSE-C everywhere because honoring a caller's key means carrying it on every read and copy, not echoing it back on the write that supplied it. This carries it. The frontend admits the customer-key triple and its copy-source variants onto requests it already builds -- put, get, head, copy, the multipart create, part and completion, the part-copy in both its native and streamed forms, and the POST form fields -- and the aws-s3 store forwards them verbatim like everything else, its service judging the values.
The transient store is its own service, so it judges. A write vets the triple -- all three fields together, AES256, a 256-bit key, an MD5 that matches -- and the object comes to rest under the key's MD5 and never the key, which is no more than S3 itself echoes on responses. SSE-C has an observable half SSE-S3 does not: the object answers only to its key. A read presenting none or the wrong one is 400 -- the wrong one too, which the suite pins where AWS's documentation suggests 403 -- and every later request of a multipart upload, each part and the completion alike, must present the create-time key again. The completion response echoes the algorithm and MD5 from the request it judged, the SDK's response type modeling no field for them.
Reads are judged in the frontend rather than the store, whose getBlob and blobMetadata also serve the frontend's own bookkeeping -- the stub consulted before a completion, the ETag before a conditional write -- which reads without a key the way S3's own internals do. The stores vet what is always a caller's act: writes, parts, and the copy's source, read inside copyBlob. What both judge the same way lives in CustomerKeys.
uploadMultipartPart takes the SDK's UploadPartRequest now, the one call whose carrier had no room for a part's key, presented again on every part as S3 requires. The aws-s3 store forwarding the request instead of rebuilding it also stops dropping the Content-MD5 a part arrived with.
The encryption tag admitted whole brings the SSE-KMS conformance tests with it, and they found two holes beside SSE-C. The frontend refuses what is malformed wherever it lands -- an algorithm S3 does not have, a KMS key under an algorithm that does not name one -- because LocalStack accepts both and the pass-through lane has to answer as S3 does; and it refuses the write-side family on GET and HEAD, where an object's encryption is reported, not asked for. The transient store further requires a key id with aws:kms, the way rgw does. kms_keyid becomes an ARN in the lane config for the same reason kms_keyid2 already was: that is what a response carries.
Both lanes whose store encrypts run the full tag now and pass -- 659 tests on the transient store, 658 through LocalStack -- and the filesystem lane still refuses the family whole, 501 on every header of it, reporting no encryption it does not perform. Unlike S3, S3Proxy accepts SSE-C over plain HTTP, its TLS commonly terminating elsewhere.
See #402.