How to authenticate Game Center User from 3rd part

2020-02-09 15:13发布

I've been trying to get the new iOS Game Center GKPlayer method, generateIdentityVerificationSignatureWithCompletionHandler, working so we can securely rely on the Game Center credentials for authentication. We're using Node.js as the backend server, and I've been trying to verify the signature but to no avail.

Here is the code on the server side that I have - if there's anyone who can chime in on what's missing, that'd be appreciated. The question has been answered somewhat here: How to authenticate the GKLocalPlayer on my 'third party server'?, but Node.js hasn't specifically been tackled. Note that the code below doesn't ensures the validity of the certificate with a signing authority (yet).

    //Client sends the payload below
    //json.playerId - UTF-8 string
    //json.bundleId - UTF-8 string
    //json.timestamp - Hex string
    //json.salt - base64 encoded
    //json.publicKeyURL - UTF-8 string
    //json.signature - base64 encoded
    var json = JSON.parse(req.body);
    console.log(JSON.stringify(json));
    //get the certificate
    getCertificate(json.publicKeyURL, function(cert){
        //read file from fs for now, since getCertificate returns cert in DER format
        fs = require('fs');
        fs.readFile('/gc-sb.pem', 'utf8', function (err,data) {
            if (err) {
                console.log(err);
            } else {
                console.log(data);
            var verifier = crypto.createVerify("sha1WithRSAEncryption");
            verifier.write(json.playerId, "utf8");
            verifier.write(json.bundleId, "utf8");
            verifier.write(json.hexTimestamp, "hex");
            verifier.write(json.salt, "base64");
            var isValid = verifier.verify(data, json.signature, "base64");

            console.log("isvalid: " + isValid);
            }
        });
    });

One thing I've found using the crypto module in node.js is that it seems to want the certificate in PEM format, and I believe the format retrieved from Apple is DER. Until I figure out how to convert the DER file to PEM, I've temporarily converted it using

openssl x509 -in gc-sb.cer -inform der -outform pem -out gc-sb.pem

The main thing for me is being able to validate the signature first. Conversion of the certificate and verifying it against a signing authority will come later :)

EDIT: I've figured it out - I was hashing the playerId, bundleId, timestamp and salt, and then using the hashed value as information to verify. I needed to just put those pieces of information into the verifier to verify without the SHA-1 hash (since the verifier will be taking care of it). I've modified the code above to "make it work". Hope this helps anyone that comes across this.

3条回答
走好不送
2楼-- · 2020-02-09 15:47
对你真心纯属浪费
3楼-- · 2020-02-09 15:59

SO today we noticed that SHA256 is needed to verify the user, SHA1 fails.

查看更多
冷血范
4楼-- · 2020-02-09 16:04

Here is how you can validate gamecenter identity using nodejs. It convert also the der certificate format to pem on the fly.

var crypto = require('crypto');
var request = require('request');
var ref = require('ref');

var token = require('./test.json');

request({url: token.publicKeyURL, encoding: null}, function (error, response, body) {
    if (!error && response.statusCode == 200) {

        var verifier = crypto.createVerify("sha1");
        verifier.update(token.playerId, "utf8");
        verifier.update(token.bundleId, "utf8");

        var buf = ref.alloc('uint64');
        ref.writeUInt64BE(buf, 0, token.timestamp.toString());

        verifier.update(buf);
        verifier.update(token.salt, 'base64');

        var pmd = '-----BEGIN CERTIFICATE-----';

        var base64 = body.toString('base64');
        var size = base64.length;

        for (var i = 0; i < size; i = i + 64) {
            var end = i + 64 < size ? i + 64 : size;
            pmd = pmd + '\n' + base64.substring(i, end);
        }

        pmd = pmd + '\n-----END CERTIFICATE-----';

        var valid = verifier.verify(pmd, token.signature, "base64");

        console.log(valid);

    }
});
查看更多
登录 后发表回答