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

minio return SignatureDoesNotMatch error when trying to upload large file using iOS AWS SDK 2.5.8 #4731

Closed
liuxuan30 opened this issue Jul 28, 2017 · 19 comments

Comments

@liuxuan30
Copy link

liuxuan30 commented Jul 28, 2017

minio return SignatureDoesNotMatch error when trying to upload large file using iOS AWS SDK 2.5.8 in Objective-C

Expected Behavior

upload success and signature verify pass

Current Behavior

The file upload requests returns status 200, for each part number.
However, when start verifying, it return SignatureDoesNotMatch

Request header for signature verify:

POST /dumped-binaries/test.bin.decrypted?uploadId=1ba6e111-e332-434d-87a3-79e6fe26f318 HTTP/1.1
Host: 192.168.1.198
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Accept: */*
User-Agent: aws-sdk-iOS/2.5.8 iPhone-OS/9.0.2 en_US transfer-manager
Authorization: AWS4-HMAC-SHA256 Credential=M29O5VEJHNUJILWR1IJA/20170728/us-east-1/s3/aws4_request, SignedHeaders=host;user-agent;x-amz-date, Signature=cd58883d0638ad2cbeb45dcd0908971804672affb596eabe9eed2a6daa4711c8
Content-Length: 843
X-Amz-Date: 20170728T093957Z


<CompleteMultipartUpload xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
	<Part>
		<ETag>&quot;16421f6fb5d7974d5d9a49046f7cd271&quot;</ETag>
		<PartNumber>1</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;b2d1236c286a3c0704224fe4105eca49&quot;</ETag>
		<PartNumber>2</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;e03df5f9ed54359babbbb54086c280b3&quot;</ETag>
		<PartNumber>3</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;b2d1236c286a3c0704224fe4105eca49&quot;</ETag>
		<PartNumber>4</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;09004852a7d7e8eeb22d7aa1f4396d13&quot;</ETag>
		<PartNumber>5</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;b2d1236c286a3c0704224fe4105eca49&quot;</ETag>
		<PartNumber>6</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;4d811e2584cdb41d9ec2814f2778a475&quot;</ETag>
		<PartNumber>7</PartNumber>
	</Part>
</CompleteMultipartUpload>

response:

HTTP/1.1 403 Forbidden
Accept-Ranges: bytes
Content-Type: application/xml
Server: Minio/RELEASE.2017-06-13T19-01-01Z (linux; amd64)
Vary: Origin
X-Amz-Bucket-Region: us-east-1
X-Amz-Request-Id: 14D575182FB9CCDD
Date: Fri, 28 Jul 2017 09:39:57 GMT
Transfer-Encoding: chunked
Proxy-Connection: Keep-alive

<Error>
	<Code>SignatureDoesNotMatch</Code>
	<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
	<Key />
	<BucketName />
	<Resource>/dumped-binaries/test.bin.decrypted</Resource>
	<RequestId>3L137</RequestId>
	<HostId>3L137</HostId>
</Error>

Possible Solution

No idea

Steps to Reproduce (for bugs)

  1. deploy minio at http://192.168.1.198:9000
  2. download iOS AWS SDK 2.5.8, write a function to upload like:
static NSString *uploaderURLString = @"http://192.168.1.198:9000";
static NSString *UploaderAccessKey = @"M29O5VEJHNUJILWR1IJA";
static NSString *UploaderSecKey = @"xn7sETYYHMJtqHpT2K91llGljBuwmQg2cY1GH0C7";

- (MITaskStatus)uploadToAWSBucketName:(NSString *)bucketName key:(NSString *)key filePath:(NSString *)filePath {
    if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        DDLog(@"Cannot find dumped binary at: %@", filePath);
        return S3_UPLOAD_FILE_NOT_EXIST;
    }

    NSURL *uploadingFileURL = [NSURL fileURLWithPath: filePath];
    // AWS
    AWSStaticCredentialsProvider *s3CredentialsProvider =
    [[AWSStaticCredentialsProvider alloc] initWithAccessKey:UploaderAccessKey
                                                  secretKey:UploaderSecKey];

    NSURL *s3Url = [NSURL URLWithString:uploaderURLString];
    AWSEndpoint *s3Endpoint = [[AWSEndpoint alloc] initWithRegion:AWSRegionUSEast1 service:AWSServiceS3 URL:s3Url];
    AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1
                                                                                    endpoint:s3Endpoint
                                                                         credentialsProvider:s3CredentialsProvider];
    // regsiter TransferManager with custom configuration
    [AWSS3TransferManager registerS3TransferManagerWithConfiguration:configuration forKey:@"StaticAnalysis-S3"];
    // get our TransferManager instance
    AWSS3TransferManager *s3TransferManager = [AWSS3TransferManager S3TransferManagerForKey:@"StaticAnalysis-S3"];
    AWSS3TransferManagerUploadRequest *s3UploadRequest = [AWSS3TransferManagerUploadRequest new];
    s3UploadRequest.bucket = bucketName;
    s3UploadRequest.key = [NSString stringWithFormat:@"%@.%@", key, @"decrypted"];
    s3UploadRequest.body = uploadingFileURL;

    // we need to block the upload process to make sure only one download at a time
    __block MITaskStatus uploadResult = S3_UPLOAD_FAILED;
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    DDLog(@"Starting S3 rquest %@", s3UploadRequest);

    [[s3TransferManager upload:s3UploadRequest] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) {
        DDLog(@"S3 uploader starts to upload...");
        if (task.error) {
            if ([task.error.domain isEqualToString:AWSS3TransferManagerErrorDomain]) {
                switch (task.error.code) {
                    case AWSS3TransferManagerErrorCancelled:
                    case AWSS3TransferManagerErrorPaused:
                    default:
                        DDLog(@"S3 upload AWS Error Domain: %@", task.error);
                        break;
                }
            } else {
                // unknown error
                DDLog(@"S3 upload Unknown Error: %@", task.error);
            }
        }
        if (task.result) {
            AWSS3TransferManagerUploadOutput *uploadOutput = task.result;
            DDLog(@"S3 upload Success: %@", uploadOutput);
            uploadResult = S3_UPLOAD_SUCCESS;
        }
        return nil;
    }];
}
  1. set up minio server Version: 2017-07-24, with below config:
{
        "version": "18",
        "credential": {
                "accessKey": "M29O5VEJHNUJILWR1IJA",
                "secretKey": "xn7sETYYHMJtqHpT2K91llGljBuwmQg2cY1GH0C7"
        },
        "region": "us-east-1",
        "browser": "on",
        "logger": {
                "console": {
                        "enable": true
                },
                "file": {
                        "enable": false,
                        "filename": ""
                }
        },
        "notify": {
                "redis": {
                        "1": {
                                "enable": true,
                                "format": "namespace",
                                "address": "192.168.65.1:6379",
                                "key": "bucket_events"
                        }
                }
        }
}
  1. upload a large file > 10M, to trigger multiple part upload
  2. wait for the result

Minio reports:

time="2017-07-28T09:39:57Z" level=error msg="{"method":"POST","reqURI":"/dumped-binaries/test.bin.decrypted?uploadId=1ba6e111-e332-434d-87a3-79e6fe26f318","header":{"Accept":["/"],"Accept-Encoding":["gzip, deflate"],"Accept-Language":["en-us"],"Authorization":["AWS4-HMAC-SHA256 Credential=M29O5VEJHNUJILWR1IJA/20170728/us-east-1/s3/aws4_request, SignedHeaders=host;user-agent;x-amz-date, Signature=cd58883d0638ad2cbeb45dcd0908971804672affb596eabe9eed2a6daa4711c8"],"Connection":["keep-alive"],"Content-Length":["843"],"Content-Type":["application/x-www-form-urlencoded"],"Host":["192.168.1.198"],"User-Agent":["aws-sdk-iOS/2.5.8 iPhone-OS/9.0.2 en_US transfer-manager"],"X-Amz-Date":["20170728T093957Z"]}}" cause="Signature does not match" source="[auth-handler.go:122:checkRequestAuthType()]"

Context

full charles trace:

s3fail_github.chls.zip

minio server launch info:

bjb2cproxysMini:minio bj-b2c-proxy$ bash -x start.sh
+ docker run --rm -p 9000:9000 --name myminio -v /Volumes/WDRED:/export -v /Users/bj-b2c-proxy/minio/config:/root/.minio minio/minio server /export

Endpoint:  http://172.17.0.2:9000  http://127.0.0.1:9000
AccessKey: M29O5VEJHNUJILWR1IJA 
SecretKey: xn7sETYYHMJtqHpT2K91llGljBuwmQg2cY1GH0C7 
Region:    us-east-1
SQS ARNs:  arn:minio:sqs:us-east-1:1:redis

Browser Access:
   http://172.17.0.2:9000  http://127.0.0.1:9000

Command-line Access: https://docs.minio.io/docs/minio-client-quickstart-guide
   $ mc config host add myminio http://172.17.0.2:9000 M29O5VEJHNUJILWR1IJA xn7sETYYHMJtqHpT2K91llGljBuwmQg2cY1GH0C7

Object API (Amazon S3 compatible):
   Go:         https://docs.minio.io/docs/golang-client-quickstart-guide
   Java:       https://docs.minio.io/docs/java-client-quickstart-guide
   Python:     https://docs.minio.io/docs/python-client-quickstart-guide
   JavaScript: https://docs.minio.io/docs/javascript-client-quickstart-guide
   .NET:       https://docs.minio.io/docs/dotnet-client-quickstart-guide

Drive Capacity: 2.7 TiB Free, 2.7 TiB Total

Your Environment

  • Version used (minio version): 2017-07-24T18:27:35Z
  • Environment name and version (e.g. nginx 1.9.1): Docker version 17.03.1-ce, build c6d412e
  • Server type and version: mac mini
  • Operating System and version (uname -a):Darwin 16.7.0 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 x86_64
  • Link to your project: https://pan.baidu.com/s/1hsGc0rM
@liuxuan30
Copy link
Author

liuxuan30 commented Jul 28, 2017

Update:

I followed #4039, and run minio at port 80, still, it does not work.

minio server is running at http://192.168.1.198, port should be 80.

full charles log:
charles_80_fail.chls.zip

as a compare, I tested a small file, which is 4M, it can upload successfully without issue.
charles log:
minio_80_4Mfile.chls.zip

request:

POST /dumped-binaries/test.bin.decrypted?uploadId=312fa637-b71f-45fd-91d5-26521e48c226 HTTP/1.1
Host: 192.168.1.198
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Accept: */*
User-Agent: aws-sdk-iOS/2.5.8 iPhone-OS/9.0.2 en_US transfer-manager
Authorization: AWS4-HMAC-SHA256 Credential=M29O5VEJHNUJILWR1IJA/20170728/us-east-1/s3/aws4_request, SignedHeaders=host;user-agent;x-amz-date, Signature=20dfd8ddc9c24b68b48e9b30ca2aa357cf4fd2710ebc8b471f4d53a0f55e88a3
Content-Length: 843
X-Amz-Date: 20170728T105247Z


<CompleteMultipartUpload xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
	<Part>
		<ETag>&quot;16421f6fb5d7974d5d9a49046f7cd271&quot;</ETag>
		<PartNumber>1</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;b2d1236c286a3c0704224fe4105eca49&quot;</ETag>
		<PartNumber>2</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;e03df5f9ed54359babbbb54086c280b3&quot;</ETag>
		<PartNumber>3</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;b2d1236c286a3c0704224fe4105eca49&quot;</ETag>
		<PartNumber>4</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;09004852a7d7e8eeb22d7aa1f4396d13&quot;</ETag>
		<PartNumber>5</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;b2d1236c286a3c0704224fe4105eca49&quot;</ETag>
		<PartNumber>6</PartNumber>
	</Part>
	<Part>
		<ETag>&quot;4d811e2584cdb41d9ec2814f2778a475&quot;</ETag>
		<PartNumber>7</PartNumber>
	</Part>
</CompleteMultipartUpload>

response

HTTP/1.1 403 Forbidden
Accept-Ranges: bytes
Content-Type: application/xml
Server: Minio/RELEASE.2017-07-24T18-27-35Z (darwin; amd64)
Vary: Origin
X-Amz-Bucket-Region: us-east-1
X-Amz-Request-Id: 14D5791185E94920
Date: Fri, 28 Jul 2017 10:52:46 GMT
Transfer-Encoding: chunked
Proxy-Connection: Keep-alive

<Error>
	<Code>SignatureDoesNotMatch</Code>
	<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
	<Key />
	<BucketName />
	<Resource>/dumped-binaries/test.bin.decrypted</Resource>
	<RequestId>3L137</RequestId>
	<HostId>3L137</HostId>
</Error>

@liuxuan30
Copy link
Author

I upload a test demo app for iOS (Xcode 8.3) https://pan.baidu.com/s/1hsGc0rM

@deekoder deekoder added this to the Edge cache milestone Jul 28, 2017
@harshavardhana
Copy link
Member

@liuxuan30
Copy link
Author

liuxuan30 commented Jul 28, 2017

@harshavardhana No, it does not work.

Actually, your mentioned function is not getting called at all. Please check my full charles log you can see the uploading requests are fine. But after uploading requests finished, there are more requests sent and failed.

Instead, it's calling:

- (NSString *)signRequestV4:(NSMutableURLRequest *)request credentials:(AWSCredentials *)credentials

not

- (NSString *)signS3RequestV4:(NSMutableURLRequest *)urlRequest
credentials:(AWSCredentials *)credentials

why it's signRequestV4 rather than signS3RequestV4 is here:

if ([hostArray firstObject] && [[hostArray firstObject] rangeOfString:@"s3"].location != NSNotFound) {
                //If it is a S3 Request
                authorization = [self signS3RequestV4:request
                                         credentials:credentials];
            } else {
                authorization = [self signRequestV4:request
                                       credentials:credentials];
            }

The hostArray right now is:

(lldb) po hostArray
<__NSArrayM 0x608000050590>(
192,
168,
100,
8
)

This is how I specify s3, you can see I aleady specify service:AWSServiceS3

    // AWS
    AWSStaticCredentialsProvider *s3CredentialsProvider =
    [[AWSStaticCredentialsProvider alloc] initWithAccessKey:UploaderAccessKey
                                                  secretKey:UploaderSecKey];

    NSURL *s3Url = [NSURL URLWithString:uploaderURLString];
    AWSEndpoint *s3Endpoint = [[AWSEndpoint alloc] initWithRegion:AWSRegionUSEast1 service:AWSServiceS3 URL:s3Url];
    AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1
                                                                                    endpoint:s3Endpoint
                                                                         credentialsProvider:s3CredentialsProvider];
    // regsiter TransferManager with custom configuration
    [AWSS3TransferManager registerS3TransferManagerWithConfiguration:configuration forKey:@"StaticAnalysis-S3"];
    // get our TransferManager instance
    AWSS3TransferManager *s3TransferManager = [AWSS3TransferManager S3TransferManagerForKey:@"StaticAnalysis-S3"];
    AWSS3TransferManagerUploadRequest *s3UploadRequest = [AWSS3TransferManagerUploadRequest new];
    s3UploadRequest.bucket = bucketName;
    s3UploadRequest.key = [NSString stringWithFormat:@"%@.%@", key, @"decrypted"];
    s3UploadRequest.body = uploadingFileURL;

I think it's a new bug? Because what I search and found previously does not involves multi part upload (the file must be > 5M) You can try my demo project if you have Xcode installed, I already put AWSCore and AWSS3 in the app, so you can directly break at where you want.

Here's the string to sign which is failing:

(lldb) po stringToSign
AWS4-HMAC-SHA256
20170728T215715Z
20170728/us-east-1/s3/aws4_request
939e06f4b469681b5c32121e3a90cd5689c6c7d6bc133b68f69b5b7c45b4b880

and 939e06f4b469681b5c32121e3a90cd5689c6c7d6bc133b68f69b5b7c45b4b880 came from canonicalRequest:

(lldb) po canonicalRequest
POST
/bins/test.bin.decrypted
uploadId=92da7661-8c93-4d0b-b6b7-e9c5c4953df2
host:192.168.100.8
user-agent:aws-sdk-iOS/2.5.8 iOS/10.3.1 en_US transfer-manager
x-amz-date:20170728T215715Z

host;user-agent;x-amz-date
83eb01962d21e7183915f8632ce87f858f8b9ee2d44f0c708c0fabbea4e381a7

and canonicalRequest came from:

(lldb) po request.HTTPMethod
POST

(lldb) po path
/bins/test.bin.decrypted

(lldb) po request.allHTTPHeaderFields
{
    Host = "192.168.100.8";
    "User-Agent" = "aws-sdk-iOS/2.5.8 iOS/10.3.1 en_US transfer-manager";
    "X-Amz-Date" = 20170728T215715Z;
}

(lldb) po contentSha256
83eb01962d21e7183915f8632ce87f858f8b9ee2d44f0c708c0fabbea4e381a7

final authorization field:

(lldb) po authorization
AWS4-HMAC-SHA256 Credential=LMZ781MR41764B6P2HRM/20170728/us-east-1/s3/aws4_request, SignedHeaders=host;user-agent;x-amz-date, Signature=fad4301085226080e8084e1cec4f692aa726db02c5866bdcd81fc108fe417d0e
 

@liuxuan30
Copy link
Author

liuxuan30 commented Jul 28, 2017

Another thing to heads up is, I tried both server 192.168.100.8:9000 and 192.168.100.8 without port (sorry I am at home right now so the IP changed), it both fails for the same reason. So I think it's irrelevant to port issue?

I also tried to modify S3 SDK to append port after host like below but does not help as well

(lldb) po canonicalRequest
POST
/bins/test.bin.decrypted
uploads=
host:192.168.100.8:9000
user-agent:aws-sdk-iOS/2.5.8 iOS/10.3.1 en_US transfer-manager
x-amz-date:20170728T223307Z

Right now minio server is black box to me as I don't know which part goes off when calculating the signature. Ideally I would like to start a debugger server of minio so I know where it fails. But I don't know how to run minio from source code and add breakpoints.

@harshavardhana
Copy link
Member

Another thing to heads up is, I tried both server 192.168.1.198:9000 and 192.168.1.198 without port, it both fails for the same reason. So I think it's irrelevant to port issue?

Unless port is included in the canonicalRequest its not a problem with or without.

Right now minio server is black box to me as I don't know which part goes off when calculating the signature. Ideally I would like to start a debugger server of minio so I know where it fails. But I don't know how to run minio from source code and add breakpoints.

This is not a problem we will work on it and fix it if there is an interaction issue. Thanks for putting up the project and doing the hard work here - really appreciate your help.

I think it's a new bug? Because what I search and found previously does not involves multi part upload (the file must be > 5M) You can try my demo project if you have Xcode installed, I already put AWSCore and AWSS3 in the app, so you can directly break at where you want.

This seems a new interaction bug perhaps same type of fix is required. Can you use simple PutObject instead of multipart operation for now?

@krishnasrinivas
Copy link
Contributor

Also SignedHeaders=host;user-agent;x-amz-date S3 docs say that user-agent should not be signed. But it does not seem to cause this bug because on the server side we include user-agent for signature calculation if it is part of SignedHeaders list.

@harshavardhana
Copy link
Member

Also SignedHeaders=host;user-agent;x-amz-date S3 docs say that user-agent should not be signed. But it does not seem to cause this bug because on the server side we include user-agent for signature calculation if it is part of SignedHeaders list.

The previous PR we sent is still not accepted and there are perhaps more issues.. @krishnasrinivas

@krishnasrinivas
Copy link
Contributor

Another weird thing to note is:

(lldb) po contentSha256
83eb01962d21e7183915f8632ce87f858f8b9ee2d44f0c708c0fabbea4e381a7

This is not the sha256 of the body of <CompleteMultipartUpload>...</CompleteMultipartUpload>

Also in canonical request:

POST
/bins/test.bin.decrypted
uploadId=92da7661-8c93-4d0b-b6b7-e9c5c4953df2
host:192.168.100.8
user-agent:aws-sdk-iOS/2.5.8 iOS/10.3.1 en_US transfer-manager
x-amz-date:20170728T215715Z

host;user-agent;x-amz-date
83eb01962d21e7183915f8632ce87f858f8b9ee2d44f0c708c0fabbea4e381a7

Instead of 83eb01962d21e7183915f8632ce87f858f8b9ee2d44f0c708c0fabbea4e381a7 it should use e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 as the request does not contain the http header X-Amz-Content-Sha256

@liuxuan30
Copy link
Author

liuxuan30 commented Jul 29, 2017

@krishnasrinivas 83eb01962d21e7183915f8632ce87f858f8b9ee2d44f0c708c0fabbea4e381a7 maybe comes from different request on my home mac, body could be different, sorry if any misunderstanding.

Are you able to run the iOS app demo? Or any chance you are familiar with Objective-C? You can then add break points to print anything you want.
This is the code calculating contentSha256:

NSString *contentSha256 = [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:[AWSSignatureSignerUtility hash:request.HTTPBody] encoding:NSASCIIStringEncoding]];

it's doing sha256 hash of the HTTPBody first and then hex encode the sha256 string.

Have you looked at my charles logs? The first several requests that uploading each part of the file is success, it's the last 4 requests failed. I am confused why some requests work and some fails as the signing method should be consistent...

@liuxuan30
Copy link
Author

liuxuan30 commented Jul 29, 2017

@harshavardhana

This seems a new interaction bug perhaps same type of fix is required. Can you use simple PutObject instead of multipart operation for now?

For small files I could change AWSS3TransferManagerMinimumPartSize to 20M or whatever within the iOS memory limit, but for files like 100M or even 1G+ then we have to use multi part upload. We have files that large, so can't only use put.

I wish you have hands on experience for Xcode or Objective-C, so you can directly add breakpoints and point out all values that are used to hash or sha256? I'm not sure if it's iOS SDK issue not following S3 doc. But if you are not, I could offer help, just tell me what data you need so I can input the data and generate the signature along with the string to sign and other useful output

I can take that to modify iOS SDK code to be compatible with minio, since we only use minio. But I need to know how to make it work, currently it's blocking issue. Thank you! The file multi part upload already succeeded.. Just the following rquests failed 😂 So I think we are really closing to solve it

@liuxuan30
Copy link
Author

liuxuan30 commented Jul 31, 2017

New update

I managed to run minio from source code and add some logs to print out the strings to sign.

It turned out that the contentSHA256 is not correct.

On iOS, it's using HTTP body to generate:

NSString *contentSha256 = [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:[AWSSignatureSignerUtility hash:request.HTTPBody] encoding:NSASCIIStringEncoding]];

These requests have body <CompleteMultipartUpload>...</CompleteMultipartUpload> can generate unique contentSha256
However in minio, it is using

emptySHA256  = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

I don't know why but X-Amz-Content-Sha256 is missing in the request:

	contentCkSum := r.Header.Get("X-Amz-Content-Sha256")
	if contentCkSum == "" {
		// If not set content checksum is defaulted to sha256([]byte("")).
		contentCkSum = emptySHA256
	}

its calling sequence is

reqSignatureV4Verify(r *http.Request, region string) (s3Error APIErrorCode) -> doesSignatureMatch(sha256sum, r, region)

If I manually add X-Amz-Content-Sha256 in every request, minio will report

level=error msg="Unable to create object part." cause="sha256 computed does not match with what is expected" source="[object-handlers.go:817:objectAPIHandlers.PutObjectPartHandler()]"

I also notice, for requests have partNumber= like {http://192.168.1.124:9000/bins/test.bin.decrypted?partNumber=1&uploadId=b1aec2dc-257f-42e5-a357-59e057afef65}

The HTTP Body at that time is empty, but later minio will report "Unable to create object part", I guess I can't force to set computed sha256 into X-Amz-Content-Sha256 in header at the beginning.

I wish to file a PR for you guys but right now I don't have the context which is the correct way, but this should leave you enough to fix it. Thanks.

@krishnasrinivas
Copy link
Contributor

@liuxuan30 can you check if this works with ios-sdk? https://github.com/krishnasrinivas/minio/tree/ios-signature-check

@liuxuan30
Copy link
Author

liuxuan30 commented Aug 1, 2017

@krishnasrinivas looks like it's working, cheers!

----------------------------------
calcuating body sha256...
body sha256:83eb01962d21e7183915f8632ce87f858f8b9ee2d44f0c708c0fabbea4e381a7
----------------------------------
stringToSign:
AWS4-HMAC-SHA256
20170801T005656Z
20170801/us-east-1/s3/aws4_request
0859a1cedb7c3d1dae5f1b3a50473dd62e275f31dfdbc15318407001ef26e13f
----------------------------------
signingKey:
[%x] [111 76 49 79 229 97 239 143 15 128 30 92 127 223 84 152 230 186 212 255 91 65 175 167 73 74 104 50 82 201 102 91]
----------------------------------
canonical request:
POST
/bins/test.bin.decrypted
uploadId=7ea51543-1918-4c34-86e3-3e322e721f4d
host:192.168.1.124
user-agent:aws-sdk-iOS/2.5.8 iOS/10.3.2 zh_CN transfer-manager
x-amz-date:20170801T005656Z

host;user-agent;x-amz-date
83eb01962d21e7183915f8632ce87f858f8b9ee2d44f0c708c0fabbea4e381a7
----------------------------------
signV4Values.Signature:
1721aedbe17a801da7633f40ed4e14137b774f5d3c5d2a41fdb184b48303ed28
----------------------------------
newSignature:
1721aedbe17a801da7633f40ed4e14137b774f5d3c5d2a41fdb184b48303ed28
----------------------------------

@krishnasrinivas
Copy link
Contributor

@liuxuan30 this is a bug in IOS SDK, this AWS Signature V4 spec http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html says:

The x-amz-content-sha256 header is required for all AWS Signature Version 4 requests. It provides a hash of the request payload. If there is no payload, you must provide the hash of an empty string.

i.e x-amz-content-sha256 is mandatory.

Your earlier observation is also correct regarding:

if ([hostArray firstObject] && [[hostArray firstObject] rangeOfString:@"s3"].location != NSNotFound) {
                //If it is a S3 Request
                authorization = [self signS3RequestV4:request
                                         credentials:credentials];
            } else {
                authorization = [self signRequestV4:request
                                       credentials:credentials];
            }

i.e it is calling signRequestV4 instead of signS3RequestV4.
signRequestV4 does not add x-amz-content-sha256 header but signS3RequestV4 does.

Can you raise an issue with IOS SDK saying that x-amz-content-sha256 is missing and giving a reference to the spec doc?

@liuxuan30
Copy link
Author

Filed one. However, what confuses me is that, when use multi upload to AWS S3, it works without problem. Why Amazon S3 server works though..

@harshavardhana
Copy link
Member

Filed one. However, what confuses me is that, when use multi upload to AWS S3, it works without problem. Why Amazon S3 server works though..

Amazon S3 is notorious in not following their own spec @liuxuan30

@harshavardhana
Copy link
Member

All other SDKs other than iOS work fine with Minio. Closing this bug as non issue for Minio is following AWS s3 spec properly.

@lock
Copy link

lock bot commented May 5, 2020

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.

@lock lock bot locked as resolved and limited conversation to collaborators May 5, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants