我问这个问题是为了分享一个解决方案代码。
上下文: Apple在iOS 7中引入了AppReceipt。它也存在于OS X IAP中。此收据是pkcs# 7集装箱(asn.1),其有效载荷也是asn。1的结构。来自Apple的文档指导如何控制设备上收据的有效性,并解析它以检查是否已为当前设备发出收据。也有说明,通过应用服务器通过联系苹果服务器验证收据。在后一种情况下,苹果返回的json数据不包括识别原始设备的信息。以前的带有transactionReceipt的IAP协议模型在json中包含了identifierForVendor UID。
问题:如何在服务器上解析二进制收据,使用PHP检查UID哈希值,以确保该收据属于该设备?这可以在将收据发送到Apple服务器之前或之后进行。
此脚本仅检查哈希值,而不检查整个收据签名的有效性。这项工作交给苹果公司,把收据发给他们。
哈希检查直接改编自Apple文档中的c语言示例代码,这里的棘手任务是从二进制收据中找到正确的信息片段。
这个代码是使用ASN1解析器由Kris Bailey,链接也在源代码。
您需要更改解析器脚本代码中的一条注释:注释行#189和取消注释行#190。此外,解析器脚本中的最后一个函数是未使用的,可以删除。
<?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'n";
}
else {
echo "KO'n";
}
echo "</pre>'n";
//*******************************************************
function hextobin($hexstr) {
$n = strlen($hexstr);
$sbin = '';
for ($i = 0; $i < $n; $i += 2) $sbin .= pack("H*", substr($hexstr,$i,2));
return $sbin;
}
?>