title: putObject via presigned url on encrypted S3 bucket returns signature does not match
body: <p>I have serverless aws lambda that will get/put object onto encrypted S3 buckets via presigned urls. getObject works perfectly. putObject generates <code>SignatureDoesNotMatch</code> error once I encrypt the bucket and I cannot understand why. I have played with headers and such, but still cannot get it to work. Code / policies below:</p>
  
  <p><strong>lambda</strong></p>
  
  <pre><code>    const generatepresignedurl = (req, res, callback) =&gt; {
  
      var fileurls = [];
      const body = JSON.parse(req.body);
      const theBucket = body['theBucket'];
      const theKey = body['theKey'];
      const theContentType = body['theContentType'];
      const theOperation = body['theOperation'];
  
      /*setting the presigned url expiry time in seconds, also check if user making the request is an authorized user
       for your app (this will be specific to your app’s auth mechanism so i am skipping it)*/
      const signedUrlExpireSeconds = 60 * 60;
  
      if (theOperation == 'getObject') {
          var params = {
              Bucket: theBucket,
              Key: theKey,
              Expires: signedUrlExpireSeconds
          };
      } else {
          var params = {
              Bucket: theBucket,
              Key: theKey,
              Expires: signedUrlExpireSeconds,
              ACL: 'bucket-owner-full-control',
              ContentType: theContentType,
              ServerSideEncryption: 'AES256'
          };
      }
  
      s3.getSignedUrl(theOperation, params, function (err, url) {
          if (err) {
              console.log('Error Getting Presigned URL from AWS S3');
              // callback(null, ({ success: false, message: 'Pre-Signed URL error', urls: fileurls }));
              callback(null, {error: err});
          }
          else {
              fileurls[0] = url;
              console.log('Presigned URL: ', fileurls[0]);
              callback(null, { success: true, message: 'AWS SDK S3 Pre-signed urls generated successfully.', urls: fileurls });
          }
      });
  
  }
  </code></pre>
  
  <p>Calling code is here:</p>
  
  <p><strong>Generate PreSigned Url</strong></p>
  
  <pre><code>Function callStandAloneAWSService(lambda As String, request As String, contentType As String) As String
  
      Dim httpserver As New MSXML2.XMLHTTP
  
      With httpserver
  
          Dim theURL As String
          theURL = AWS_WEBSERVICE_URL_DEV
  
          .Open "POST", theURL &amp; lambda 'variable that contains generatepresignedurl
  
          .setRequestHeader "Content-type", contentType
  
          .send request
  
          Do: DoEvents: Loop Until .readyState = 4 'make sure we are ready to recieve response
  
          callStandAloneAWSService = .responseText
  
      End With
  
  End Function
  </code></pre>
  
  <p><strong>Upload to PreSigned URL</strong> (original question did not have serversidencryption header)</p>
  
  <pre><code>Function uploadToPreSignedURL(url As String, whichFile As String, contentType) As Boolean
  
      'code to create binaryFile
  
      Dim httpserver As New MSXML2.XMLHTTP
  
      With httpserver
  
          .Open "POST", url
          .setRequestHeader "Content-type", "text/plain" 'contentType
          .send binaryFile
          Do: DoEvents: Loop Until .readyState = 4 'make sure we are ready to recieve response
  
          If Len(.responseText) = 0 Then
  
              uploadToPreSignedURL = True
  
          Else
  
              'extract error message from xml and write to report mail
  
          End If
  
      End With
  
  End Function
  </code></pre>
  
  <p><strong>bucket policy</strong></p>
  
  <pre><code>{
      "Version": "2012-10-17",
      "Id": "S3PolicyId1",
      "Statement": [
          {
              "Sid": "DenyIncorrectEncryptionHeader",
              "Effect": "Deny",
              "Principal": "*",
              "Action": "s3:PutObject",
              "Resource": "arn:aws:s3:::mybiggetybucket/*",
              "Condition": {
                  "StringNotEquals": {
                      "s3:x-amz-server-side-encryption": "AES256"
                  }
              }
          },
          {
              "Sid": "DenyUnEncryptedObjectUploads",
              "Effect": "Deny",
              "Principal": "*",
              "Action": "s3:PutObject",
              "Resource": "arn:aws:s3:::mybiggetybucket/*",
              "Condition": {
                  "Null": {
                      "s3:x-amz-server-side-encryption": "true"
                  }
              }
          }
      ]
  }
  </code></pre>
  
  <p>FWIW, I can run this via aws cli and get it to work:</p>
  
  <blockquote>
    <p>aws s3api put-object --bucket mybiggetybucket --key test.json --body package-lock.json --server-side-encryption "AES256"</p>
  </blockquote>