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

后端 未结 10 414
鱼传尺愫
鱼传尺愫 2020-11-30 02:53

iOS7 introduced new GKLocalPlayer method generateIdentityVerificationSignatureWithCompletionHandler().

Does anyone know how to use it for good? I assum

10条回答
  •  一生所求
    2020-11-30 03:28

    It took me a lot of time to implement it in PHP. Now I would like to share my result.

    Documentation

    You can find a very simple documentation at Apple: https://developer.apple.com/library/ios/documentation/GameKit/Reference/GKLocalPlayer_Ref/index.html#//apple_ref/occ/instm/GKLocalPlayer/generateIdentityVerificationSignatureWithCompletionHandler

    [...]

    1. Use the publicKeyURL on the third party server to download the public key.
    2. Verify with the appropriate signing authority that the public key is signed by Apple.
    3. Retrieve the player’s playerID and bundleID.
    4. Concatenate into a data buffer the following information, in the order listed:
      • The playerID parameter in UTF-8 format
      • The bundleID parameter in UTF-8 format
      • The timestamp parameter in Big-Endian UInt-64 format
      • The salt parameter
    5. Generate a SHA-256 hash value for the buffer.
    6. Using the public key downloaded in step 3, verify that the hash value generated in step 7 matches the signature parameter provided by the API.

    Notice! Number 7 is a trap in PHP that cost me hours. You have to pass only the raw concatenated string to the openssl_verify() function.

    The update from Jul 9 2014 in the question How to authenticate the GKLocalPlayer on my 'third party server' using PHP? helped me to find the problem.

    Final Source

    >32;
    $lower = $timestamp & $lowMap;
    $timestamp = pack('NN', $higher, $lower);
    
    // Concatenate the string
    $data = $user_id . $bundle_id . $timestamp . $salt;
    
    // ATTENTION!!! Do not hash it! $data = hash("sha256", $packed);
    
    // Fetch the certificate. This is dirty because it is neither cached nor verified that the url belongs to Apple.
    $ssl_certificate = file_get_contents($public_key_url);
    
    $pem = chunk_split(base64_encode($ssl_certificate), 64, "\n");
    $pem = "-----BEGIN CERTIFICATE-----\n" . $pem . "-----END CERTIFICATE-----\n";
    
    // it is also possible to pass the $pem string directly to openssl_verify
    if (($pubkey_id = openssl_pkey_get_public($pem)) === false) {
        echo "invalid public key\n";
        exit;
    }
    
    // Verify that the signature is correct for $data
    $verify_result = openssl_verify($data, $signature, $pubkey_id, OPENSSL_ALGO_SHA256);
    
    openssl_free_key($pubkey_id);
    
    switch($verify_result) {
      case 1:
        echo "Signature is ok.\n";
        break;
      case 0:
        echo "Signature is wrong.\n";
        break;
      default:
        echo "An error occurred.\n";
        break;
    }
    

提交回复
热议问题