TonyG
TonyG

Reputation: 101

SignatureDoesNotMatch error with Amazon S3 and ColdFusion PutObject request

Probably simple issue but pulling hair out trying to figure it out. This code to generate a signature and make a rest post to s3 works perfectly:

    <cfset cs = "PUT\n\n#arguments.contentType#\n#dateTimeString#\nx-amz-acl:#arguments.acl#\nx-amz-storage-class:#arguments.storageClass#\n/#arguments.bucketName#/#arguments.keyName#">
...
<cfhttp method="PUT" url="https://s3.amazonaws.com/#arguments.bucketName#/#arguments.keyName#" timeout="#arguments.HTTPtimeout#">   
    <cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
    <cfhttpparam type="header" name="Content-Type" value="#arguments.contentType#">
    <cfhttpparam type="header" name="Date" value="#dateTimeString#">
    <cfhttpparam type="header" name="x-amz-acl" value="#arguments.acl#">
    <cfhttpparam type="header" name="x-amz-storage-class" value="#arguments.storageClass#">
    <cfhttpparam type="body" value="#binaryFileData#">
</cfhttp>

But I want to add s3 managed AES256 encryption which if I understand right should be as simple as adding the x-amz-server-side​-encryption header with the value of AES256 but this does not work:

<cfset cs = "PUT\n\n#arguments.contentType#\n#dateTimeString#\nx-amz-acl:#arguments.acl#\nx-amz-storage-class:#arguments.storageClass#\nx-amz-server-side​-encryption:aes256\n/#arguments.bucketName#/#arguments.keyName#">
    ...
    <cfhttp method="PUT" url="https://s3.amazonaws.com/#arguments.bucketName#/#arguments.keyName#" timeout="#arguments.HTTPtimeout#">   
        <cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
        <cfhttpparam type="header" name="Content-Type" value="#arguments.contentType#">
        <cfhttpparam type="header" name="Date" value="#dateTimeString#">
        <cfhttpparam type="header" name="x-amz-acl" value="#arguments.acl#">
        <cfhttpparam type="header" name="x-amz-storage-class" value="#arguments.storageClass#">
        <cfhttpparam type="header" name="x-amz-server-side​-encryption" value="aes256">
        <cfhttpparam type="body" value="#binaryFileData#">
    </cfhttp>

The signature method is:

<cffunction name="createSignature" returntype="string" access="public" output="false">
    <cfargument name="stringIn" type="string" required="true" />
    <!--- Replace "\n" with "chr(10) to get a correct digest --->
    <cfset var fixedData = replace(arguments.stringIn,"\n","#chr(10)#","all")>
    <!--- Calculate the hash of the information --->
    <cfset var digest = HMac(fixedData, variables.secretAccessKey, "HMACSHA1", "utf-8")>
    <!--- fix the returned data to be a proper signature --->
    <cfset var signature = ToBase64( binaryDecode(digest, "hex" ) )>
    <cfreturn signature>
</cffunction>

When trying to use encryption I get "The request signature we calculated does not match the signature you provided. Check your key and signing method."

Its not the keys themselves since I can add/remove/list just fine. I just can't add the encryption header.

Anybody tell me what is wrong?

...And I tried both 'AES256' and 'aes256' as values.

Upvotes: 2

Views: 644

Answers (1)

TonyG
TonyG

Reputation: 101

Turns out it was stupid...and it took much digging to find a single line mention it in the docs.

The Amazon headers need to be listed in alphabetical order.

Moving x-amz-server-side​-encryption above x-amz-storage-class and using AES256 solved the problem.

Upvotes: 3

Related Questions