如何使用 php 从应用证明对象中提取证书?

How to extract certificates from app attestation object using php?

我尝试在我的应用程序和 php 之间设置应用程序证明,但除了 Apple 自己的文档外,我很少找到任何其他解释来源,这让我陷入了早期状态。到目前为止,我得到了以下步骤:

在客户端,按照 https://developer.apple.com/documentation/devicecheck/establishing_your_app_s_integrity,我将我的证明创建为 base64 编码字符串:

attestation.base64EncodedString()

然后我将该字符串发送到服务器,从现在开始跟随https://developer.apple.com/documentation/devicecheck/validating_apps_that_connect_to_your_server

文档说,证明是 CBOR 格式。因此,我首先解码 base64 编码的字符串并使用 (https://github.com/Spomky-Labs/cbor-php).

解析它
<?php
use CBOR\Decoder;
use CBOR\OtherObject;
use CBOR\Tag;
use CBOR\StringStream;

$otherObjectManager = new OtherObject\OtherObjectManager();
$tagManager = new Tag\TagObjectManager();

$decoder = new Decoder($tagManager, $otherObjectManager);
$data = base64_decode(/* .. base64 encoded attestation string as send from the client (see swift snippet above) */);

$stream = new StringStream($data);
$object = $decoder->decode($stream);

$norm = $object->getNormalizedData();
$fmt = $norm['fmt'];
$x5c = $norm['attStmt']['x5c'];

根据文档,规范化对象应具有以下格式:

{
   fmt: 'apple-appattest',
   attStmt: {
     x5c: [
       <Buffer 30 82 02 cc ... >,
       <Buffer 30 82 02 36 ... >
     ],
     receipt: <Buffer 30 80 06 09 ... >
   },
   authData: <Buffer 21 c9 9e 00 ... >
 }

它的作用:

$fmt == "apple-appattest" // true

那么接下来根据文档描述为:

Verify that the x5c array contains the intermediate and leaf certificates for App Attest, starting from the credential certificate in the first data buffer in the array (credcert). Verify the validity of the certificates using Apple’s App Attest root certificate.

但是,我不知道如何进一步处理这个问题。例如的内容$norm['attStmt']['x5c'][0] 是可读字符和字形的混合体。为了给您一个概念,这是 $norm['attStmt']['x5c'][0] 内容中的随机子字符串:“Certification Authority10U Apple Inc.10 UUS0Y0*��H��=*��H��=B��c��}��”。这就是为什么我不确定是否必须执行任何进一步的 encodeing/decoding 步骤。

我尝试解析证书但没有任何运气(var_dump return false):

 $cert = openssl_x509_read($x5c[0]);
 var_dump($cert); // false - indicating that reading the cert failed
 
 $parsedCert = openssl_x509_parse($cert, false);
 var_dump($parsedCert); // false - of course, since the prior step did not succeed

非常感谢任何想法、指导或替代资源。谢谢!

过了一会儿,我想到了以下解决方案。 $x5c 字段包含一个证书列表,全部为二进制形式。我编写了以下转换器来创建 PEM 格式的即用型证书,它执行以下操作:

  1. base64编码二进制数据
  2. 64 字节后换行
  3. 添加 BEGIN 和 END 标记(还要注意结尾证书行的尾随换行符)

function makeCert($bindata) {
     $beginpem = "-----BEGIN CERTIFICATE-----\n";
    $endpem = "-----END CERTIFICATE-----\n";

    $pem = $beginpem;
    $cbenc = base64_encode($bindata);
    for($i = 0; $i < strlen($cbenc); $i++) {
        $pem .= $cbenc[$i];
        if (($i + 1) % 64 == 0)
            $pem .= "\n";
    }
    $pem .= "\n".$endpem;

    return $pem;
}

接下来的工作:

openssl_x509_read(makeCert($x5c[0]))