Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(middleware-ssec): add logic to handle string input as specified b… #5676

Merged
merged 7 commits into from
Jan 22, 2024

Conversation

RanVaknin
Copy link
Contributor

@RanVaknin RanVaknin commented Jan 11, 2024

Background:

middleware-ssec was ported over from v2, however the implementation prevents from customer to supply SSECustomerKey in a string format which is problematic as putObject#SSECustomerKey as modeled as a string. Instead customer are required to provide SSECustomerKey as binary. The middleware logic does not cover cases in which customers want to supply SSECustomerKey as a base 64 string directly as the S3 docs suggest.

Issue

#5651 #4736

Reproduction:

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import * as crypto from 'crypto';
import { promisify } from 'util';

const randomBytes = promisify(crypto.randomBytes);

const client = new S3Client({region: "us-east-1"});

async function putWithSSECInBinaryFormat(){
  try {
    const key = await randomBytes(32);
    const response = await client.send(new PutObjectCommand({
      Bucket: 'testbucket',
      Body: 'This is a test',
      Key: "foo",
      SSECustomerKey: key,
      SSECustomerAlgorithm: 'AES256'
    }));
    console.log('PutObject with SSEC in binary format successful:', response.$metadata.httpStatusCode);
  } catch (error) {
    console.error('PutObject with SSEC in binary format failed:', error);
  }

}

async function putWithSSECInBase64StringFormat(){
  try {
    const key = await randomBytes(32);
    const response = await client.send(new PutObjectCommand({
      Bucket: 'testbucket',
      Body: 'This is a test',
      Key: "foo",
      SSECustomerKey: key.toString('base64'),
      SSECustomerAlgorithm: 'AES256'
    }));
    console.log('PutObject with SSEC in base64 string format successful:', response.$metadata.httpStatusCode);
  } catch (error) {
    console.error('PutObject with SSEC in base64 string format failed:', error);
  }
}

putWithSSECInBinaryFormat();
putWithSSECInBase64StringFormat();

Will Result in:

PutObject with SSEC in binary format successful: 200
PutObject with SSEC in base64 string format failed: InvalidArgument: The secret key was invalid for the specified algorithm.

Changes Made:

Middleware Logic Update:

  • Regex Adjustment for Base64 Detection: now using a regular expression used to determine if a string is base64-encoded.
  • Handling of Different Input Types: Modified the logic to distinguish between base64-encoded strings, non-base64 strings, and binary data. Each type is now appropriately handled:
    • Base64 strings are directly converted to binary for MD5 hashing without re-encoding.
      Non-base64 strings are decoded to binary, encoded to base64, and their MD5 hashes are calculated.
    • Binary data is directly used for MD5 hashing and then encoded to base64.

Test Suite Enhancement:

  • Test for Base64-Encoded Key Processing: This test confirms that the middleware correctly handles base64-encoded keys by verifying that it properly maintains the key in base64 format and accurately calculates and sets the corresponding base64-encoded MD5 hash.

Behavior after change

PutObject with SSEC in binary format successful: 200
PutObject with SSEC in base64 string format successful: 200

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@RanVaknin RanVaknin requested a review from a team as a code owner January 11, 2024 21:48
Copy link
Contributor

@kuhe kuhe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix commit metadata

@RanVaknin RanVaknin force-pushed the fix-ssec-middleware branch 4 times, most recently from d41374e to 7402486 Compare January 16, 2024 19:54
@RanVaknin RanVaknin force-pushed the fix-ssec-middleware branch from 7402486 to 4efdb7e Compare January 16, 2024 20:04
@@ -1,4 +1,6 @@
import { S3 } from "@aws-sdk/client-s3";
import * as crypto from "crypto";
import { isMainThread } from "worker_threads";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this

@kuhe kuhe merged commit 5a19a33 into aws:main Jan 22, 2024
3 checks passed
let valueForHash: Uint8Array;
if (typeof value === "string") {
const isBase64Encoded = /^(?:[A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
if (isBase64Encoded) {
Copy link

@tmccombs tmccombs Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the value is a valid base64 string, but isn't actually a base64 encoded value?

I think probably the best way to check this would be to look at the length of the string. If the length of the string is 44 characters, then it is probably a base64 encoded value (for 32 bytes of data). Assuming that AES256 is the encryption algorithm.

Copy link

github-actions bot commented Feb 7, 2024

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants