iosauthenticationios7game-center

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


iOS7 introduced new GKLocalPlayer method generateIdentityVerificationSignatureWithCompletionHandler().

Does anyone know how to use it for good? I assume there will be some public API at Apple server-side..


Solution

  • 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:&timestampBE 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