I am trying to write a service in Go that takes the parameters given by GameCenter in
//GKLocalPlayer
- (void)generateIdentityVerificationSignatureWithCompletionHandler:(void (^)(NSURL *publicKeyUrl, NSData *signature, NSData *salt, uint64_t timestamp, NSError *error))completionHandler
Inside the completionHandler
of the method, I am sending the public key URL, base 64 encoded signature, base 64 encoded salt, timestamp and the user's game center ID to my Go service. Inside my Go (in Google App Engine), this is what I am doing:
*I know that I still need to verify with the certificate authority but I am skipping that for now (if you know how to do that in Go for this case, please please please share!)
Problem: CheckSignature
is returning crypto/rsa: verification error
and I really think that I am doing everything as instructed by Apple
And the code that I have so far:
func (v *ValidationRequest) ValidateGameCenter(publicKeyUrl string, playerId string, bundleId string, signature string, salt string, timestamp uint64) error {
client := urlfetch.Client(v.Context)
resp, err := client.Get(publicKeyUrl)
if err != nil {
v.Context.Errorf("%v", err.Error())
return err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
v.Context.Errorf("%v", err.Error())
return err
}
cert, err := x509.ParseCertificate(body)
if err != nil {
v.Context.Errorf("%v", err.Error())
return err
}
signatureBytes, err := base64.StdEncoding.DecodeString(signature)
saltBytes, err:= base64.StdEncoding.DecodeString(salt)
payload, err := formPayload(v, playerId, bundleId, timestamp, saltBytes)
if err != nil {
v.Context.Errorf("%v", err.Error())
return err
}
err = cert.CheckSignature(cert.SignatureAlgorithm, payload, signatureBytes)
if err != nil {
v.Context.Errorf("%v", err.Error())
return err
}
return nil
}
func formPayload(v *ValidationRequest, playerId string, bundleId string, timestamp uint64, salt []byte) ([]byte, error) {
bundleIdBytes := []byte(bundleId)
playerIdBytes := []byte(playerId)
payloadBuffer := new(bytes.Buffer)
written, err := payloadBuffer.Write(playerIdBytes)
if err != nil {
return nil, err
}
written, err = payloadBuffer.Write(bundleIdBytes)
if err != nil {
return nil, err
}
var bigEndianTimestamp []byte = make([]byte, 8)
binary.BigEndian.PutUint64(bigEndianTimestamp, timestamp)
if written != len(bundleIdBytes) {
return nil, errors.New(fmt.Sprintf("Failed writing all bytes. Written: %d Length: %d", written, len(bundleIdBytes)))
}
written, err = payloadBuffer.Write(bigEndianTimestamp)
if err != nil {
return nil, err
}
if written != len(bigEndianTimestamp) {
return nil, errors.New(fmt.Sprintf("Failed writing all bytes. Written: %d Length: %d", written, len(bigEndianTimestamp)))
}
written, err = payloadBuffer.Write(salt)
if err != nil {
return nil, err
}
if written != len(salt) {
return nil, errors.New(fmt.Sprintf("Failed writing all bytes. Written: %d Length: %d", written, len(salt)))
}
return payloadBuffer.Bytes(), nil
}