How to Authenticate the Gklocalplayer on My 'Third Party Server'

How to authenticate the GKLocalPlayer on my 'third party server'?

Here is how you can authenticate using objective c. If you need it in another language should be trivial to translate.

-(void)authenticate
{
__weak GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error)
{
if(viewController)
{
[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController:viewController animated:YES completion:nil];
}
else if(localPlayer.isAuthenticated == YES)
{
[localPlayer generateIdentityVerificationSignatureWithCompletionHandler:^(NSURL *publicKeyUrl, NSData *signature, NSData *salt, uint64_t timestamp, NSError *error) {

if(error != nil)
{
return; //some sort of error, can't authenticate right now
}

[self verifyPlayer:localPlayer.playerID publicKeyUrl:publicKeyUrl signature:signature salt:salt timestamp:timestamp];


}];
}
else
{
NSLog(@"game center disabled");
}
};
}

-(void)verifyPlayer:(NSString *)playerID publicKeyUrl:(NSURL *)publicKeyUrl signature:(NSData *)signature salt:(NSData *)salt timestamp:(uint64_t)timestamp
{
//get certificate
NSData *certificateData = [NSData dataWithContentsOfURL:publicKeyUrl];

//build payload
NSMutableData *payload = [[NSMutableData alloc] init];
[payload appendData:[playerID dataUsingEncoding:NSASCIIStringEncoding]];
[payload appendData:[[[NSBundle mainBundle] bundleIdentifier] dataUsingEncoding:NSASCIIStringEncoding]];

uint64_t timestampBE = CFSwapInt64HostToBig(timestamp);
[payload appendBytes:×tampBE length:sizeof(timestampBE)];
[payload appendData:salt];

//sign
SecCertificateRef certificateFromFile = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData); // load the certificate
SecPolicyRef secPolicy = SecPolicyCreateBasicX509();

SecTrustRef trust;
OSStatus statusTrust = SecTrustCreateWithCertificates( certificateFromFile, secPolicy, &trust);
if(statusTrust != errSecSuccess)
{
NSLog(@"could not create trust");
return;
}

SecTrustResultType resultType;
OSStatus statusTrustEval = SecTrustEvaluate(trust, &resultType);
if(statusTrustEval != errSecSuccess)
{
NSLog(@"could not evaluate trust");
return;
}

if(resultType != kSecTrustResultProceed && resultType != kSecTrustResultRecoverableTrustFailure)
{
NSLog(@"server can not be trusted");
return;
}

SecKeyRef publicKey = SecTrustCopyPublicKey(trust);
uint8_t sha256HashDigest[CC_SHA256_DIGEST_LENGTH];
CC_SHA256([payload bytes], (CC_LONG)[payload length], sha256HashDigest);

//check to see if its a match
OSStatus verficationResult = SecKeyRawVerify(publicKey, kSecPaddingPKCS1SHA256, sha256HashDigest, CC_SHA256_DIGEST_LENGTH, (const uint8_t *)[signature bytes], [signature length]);

CFRelease(publicKey);
CFRelease(trust);
CFRelease(secPolicy);
CFRelease(certificateFromFile);
if (verficationResult == errSecSuccess)
{
NSLog(@"Verified");
}
else
{
NSLog(@"Danger!!!");
}
}

EDIT:

as of March 2nd 2015, apple now uses SHA256 instead of SHA1 on the certificate. https://devforums.apple.com/thread/263789?tstart=0

How to authenticate GKLocalPlayer on my third-party-server using Java JDK 1.7?

The problem appears to be with the ByteBuffer you're passing to Signature.update(). If you pass the underlying array by changing

sig.update(dataBuffer);

to

sig.update(dataBuffer.array());

the verification appears to succeed. Based on the documentation for Signature.update(ByteBuffer), I suspect it's because it's trying to read from the last position you wrote to in the buffer, and not finding any data.

Setting up third-party server to interact with Game Center

Looks like as of iOS 7, this is possible with Game Center using:

[localPlayer generateIdentityVerificationSignatureWithCompletionHandler]

Once you have verified the identity of the player using the generateIdentity call,

  • Associate the player id with a user on your server's db
  • Use whatever access token / authentication pattern your REST framework provides for subsequent calls

https://developer.apple.com/library/ios/documentation/GameKit/Reference/GKLocalPlayer_Ref/Reference/Reference.html

Also for reference, here is the dictionary that we end up sending off to our server based on the response from generateIdentityVerificationSignatureWithCompletionHandler

NSDictionary *paramsDict = @{
@"publicKeyUrl":[publicKeyUrl absoluteString],
@"timestamp":[NSString stringWithFormat:@"%llu", timestamp],
@"signature":[signature base64EncodedStringWithOptions:0],
@"salt":[salt base64EncodedStringWithOptions:0],
@"playerID":localPlayer.playerID,
@"bundleID":[[NSBundle mainBundle] bundleIdentifier]
};

Where to obtain public key for GameCenter 3rd party authentication on a server

To avoid CSRF attack I just check the url with uri.DnsSafeHost.EndsWith(".gc.apple.com", StringComparison.OrdinalIgnoreCase).



Related Topics



Leave a reply



Submit