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.