XAmzContentSHA256Mismatch using MBS Curls S3 upload example with Contabo

I’m using the MBS sample projects for CURLS Amazon S3 download and upload projects to connect to S3 compatible cloud storage of Contabo (Contabo Cloud Object Storage).

https://www.monkeybreadsoftware.net/curl-curlmbs-shared-method.shtml

Download is working as expected, but upload throws an error:

<?xml version="1.0" encoding="UTF-8"?><Error><Code>XAmzContentSHA256Mismatch</Code><Message></Message><BucketName>nwscloudbackup</BucketName><RequestId>tx00000932f36a9b4a12da8-00673f4e84-199f7a4-eu2</RequestId><HostId>199f7a4-eu2-eu</HostId></Error>

I’m stuck here. Anybody has a clue how to overcome this error?
I could privat mail the modified upload project with current Contabo keys, for testing …

More debug data from the plugin:

MBS Xojo Plugins 21.3 with CURL 7.77.0 on macOS.

Trying 173.249.62.84:443…
Connected to eu2.contabostorage.com (173.249.62.84) port 443 (#0)
ALPN, offering http/1.1
TLSv1.3 (OUT), TLS handshake, Client hello (1):
TLSv1.3 (IN), TLS handshake, Server hello (2):
TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
TLSv1.3 (IN), TLS handshake, Certificate (11):
TLSv1.3 (IN), TLS handshake, CERT verify (15):
TLSv1.3 (IN), TLS handshake, Finished (20):
TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
TLSv1.3 (OUT), TLS handshake, Finished (20):
SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
ALPN, server did not agree to a protocol
Server certificate:
subject: CN=*.contabostorage.com
start date: Nov 14 00:00:00 2024 GMT
expire date: Feb 12 23:59:59 2025 GMT
issuer: C=AT; O=ZeroSSL; CN=ZeroSSL RSA Domain Secure Site CA
SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
PUT /nwscloudbackup/test.png HTTP/1.1
Host: eu2.contabostorage.com
Authorization: AWS4-HMAC-SHA256 Credential=20b8dabcf0ac059091b4499e407417b1/20241121/eu-central-1/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date,Signature=1274e971f1c8922e3c9151e7b596b5c4eabded3249d51114d1518c66f671e23f
Date: Thu, 21 Nov 2024 15:31:37 GMT
x-amz-content-sha256: BEC4E802F22B31B3DD4C4DE4BD1966F6E389F7327506BD114B18CEB3C22BE84F
x-amz-date: 20241121T153137Z
Content-Length: 23266

We are completely uploaded and fine
TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
old SSL session ID is stale, removing
Mark bundle as not supporting multiuse
HTTP/1.1 400 Bad Request
content-type: application/xml
content-length: 249
ratelimit-reset: 1
x-ratelimit-remaining-second: 249
x-ratelimit-limit-second: 250
ratelimit-limit: 250
ratelimit-remaining: 249
x-amz-request-id: tx000008bb8571337da3f59-00673f5259-19b6f8b-eu2
accept-ranges: bytes
date: Thu, 21 Nov 2024 15:31:38 GMT
access-control-allow-origin: *
access-control-expose-headers: *
strict-transport-security: max-age=16000000; includeSubDomains; preload;

Connection #0 to host eu2.contabostorage.com left intact

How do you make the upload?
The plugin calculates the hash. So do you put data in OptionPostfields or InputData properties?

I modified your CURLS example project for Amazon S3 upload:

Private Sub DoUpload()
  
  Dim e As Integer
  dim d as new UploadCURL
  
  Dim p As Picture = LogoMBS
  
  Dim file As FolderItem = SpecialFolder.Desktop.Child("test.png")
  Call d.OpenMTInputFile(file)
  
  //Contabo Cloud Storage
  Const AWSAccessKeyId = "20b8dabcf0ac059091b4499e*******"
  Const AWSSecretAccessKey = "b919da1c6204b9a30db5f*******"
  Const Region = "eu-central-1"
  Const Service = "s3"
  Const Domain = "eu2.contabostorage.com" // auto
  Const Verb = "PUT"
  Dim BucketName As String = "nwscloudbackup"
  Dim FileName As String = "test.png"
  Dim Path As String = "/" + BucketName + "/" + EncodeURLComponent(Filename)
  Dim HashedPayload As String // empty for auto
  
  
  HashedPayload = SHA256MBS.HashFile(file, True)
  
  call d.SetupAWS(AWSAccessKeyId, AWSSecretAccessKey, Region, Service, Path, Domain, Verb, HashedPayload)
  
  e=d.Perform
  
  listbox1.addrow "Result: "+str(e)
  
  dim DebugMessage as string = d.DebugData // check in debugger on error
  dim OutputData as string = d.OutputData
  dim HTTPResult as integer = d.GetInfoResponseCode
  if e <> 0 or HTTPResult <> 200 then
    break
  end if
  
  
End Sub

Could you try with LowerCase() for the HashedPayload?

I think our functions returns upper case, but AWS needs it lowercase.

1 Like

Yes, lowercase made it work! Thanks for the hint!

1 Like