This script only check for the hash and not the whole receipt signature validity. This work is left to Apple by sending them the receipt as documented.
The hash check is directly adapted from the Apple documented example code in C. The tricky task here being to find the right pieces of information out of the binary receipt.
This code is using an ASN1 parser by Kris Bailey, link is also in the source code.
You need to change one comment in the parser script code: comment line #189 and uncomment #190. Also the last function in the parser script is unused and can be deleted.
<?php
//$vendID should be a binary string. If you have the vendorID as an ASCII string, convert it back
// $vendID = hex2bin(str_replace('-', '', $vendID_string)); //PHP 5.4+
$vendID = hextobin(str_replace('-', '', $vendID_string)); //PHP 5.3- function below
require_once 'ans1.php'; //donwnload from http://www.phpkode.com/source/s/mistpark-server/library/asn1.php
$asn_parser = new ASN_BASE;
//parse the receipt binary string
$pkcs7 = $asn_parser->parseASNString($receipt->bin);
// $asn_parser->printASN($pkcs7); //uncomment this line to print and inspect PKCS7 container
//target the payload object inside the container
$payload_sequence = $pkcs7[0]->asnData[1]->asnData[0]->asnData[2]->asnData;
//control the OID of payload
if ($payload_sequence[0]->asnData != '1.2.840.113549.1.7.1') {
echo "invalide payload OID";
exit;
}
//the payload octet_string is itself an ASN1 structure. Parse it.
$payload = $asn_parser->parseASNString($payload_sequence[1]->asnData[0]->asnData);
// $asn_parser->printASN($payload); //uncomment this line to print and inspect payload ASN structure
$payload_attributes = $payload[0]->asnData; //array of ASN_SEQUENCE
foreach ($payload_attributes as $attr) {
$type = $attr->asnData[0]->asnData;
switch ($type) {
case 2:
$bundle_id = $attr->asnData[2]->asnData;
break;
// case 3:
// $bundle_version = $attr->asnData[2]->asnData;
// break;
case 4:
$opaque = $attr->asnData[2]->asnData;
break;
case 5:
$hash = $attr->asnData[2]->asnData;
break;
default:
break;
}
}
//compute the hash
$hash_loc = sha1($vendID . $opaque . $bundle_id, true);
//control hash equality
if ($hash_loc == $hash) {
echo "OK
";
}
else {
echo "KO
";
}
echo "</pre>
";
//*******************************************************
function hextobin($hexstr) {
$n = strlen($hexstr);
$sbin = '';
for ($i = 0; $i < $n; $i += 2) $sbin .= pack("H*", substr($hexstr,$i,2));
return $sbin;
}
?>