1

I tried to set up app attestation between my app and php but I rarely find any other source of explaination than Apple's own documentation, which let me stuck quite at an early state. So far I got the following steps:

On the client side, following https://developer.apple.com/documentation/devicecheck/establishing_your_app_s_integrity, I creted my attestation as a base64 encoded string:

attestation.base64EncodedString()

I then send that string to the server, following https://developer.apple.com/documentation/devicecheck/validating_apps_that_connect_to_your_server from now on.

The documentation says, that the attestation is in the CBOR format. I therefor first decode the base64 encoded string and parse it using (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'];

From the documentation, the normalized object should have the following format:

{
   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 ... >
 }

which it does:

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

Then the next according to the documentation is described as:

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.

However, I don't know how to proceed further on this. The content of e.g. $norm['attStmt']['x5c'][0] is a mix of readable chars and glyphs. To give you an idea, this is a random substring from the content of $norm['attStmt']['x5c'][0]: "Certification Authority10U Apple Inc.10 UUS0Y0*�H�=*�H�=B��c�}�". That's why I'm not really sure wheather I have to perform any further encodeing/decoding steps.

I tried parsing the certificate but without any luck (both 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

Any ideas, guidance or alternative ressources are highly appreciated. Thank you!

Leo
  • 1,508
  • 13
  • 27
  • Please leave me a comment which details / clarification is required - I will then do my best to update my question with the requested information. However, from the close request alone I don't know what you're looking for since I already tried to compress it as much as possible without leaving any important step. – Leo Oct 09 '21 at 13:37
  • 1
    This question is close to be a debugging one, however a [mcve] is hard to provide for this. It's also close to needing more details, as it's not clear if you ask for a Swift or a PHP fix. – Cristik Oct 09 '21 at 17:08
  • One more thing, as this is a niche domain, likely only someone with app attestation experience can help you here, in which case the first part of the question, before the `Verify that the x5c array contains...` quote, is not necessary. – Cristik Oct 09 '21 at 17:09
  • There is some Java code [here](https://software-factotum.medium.com/validating-rsa-signature-for-a-jws-more-about-jwk-and-certificates-e8a3932669f1) that may help. Essentially you have a binary DER encoded certificate. You need to use that with a crypto library to verify the contents of the certificate are 1) what you expect by verifying against Apple's root certificate and 2) that the whole signature is valid – Paulw11 Oct 09 '21 at 20:24
  • Thank you both, I already figured out my issue. The certs are binary, I had to convert them in base64, break lines after 64 chars and add the header and footer to convert the cert into pem format. – Leo Oct 10 '21 at 08:50

1 Answers1

1

After a while I came up with the following solution. The $x5c field contains a list of certificates, all in binary form. I wrote the folowing converter to create a ready-to-use certificate in PEM format, which does the following:

  1. base64 encode the binary data
  2. break lines after 64 bytes
  3. add BEGIN and END markers (also note the trailing line-break on the end certificate line)

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;
}

the following then works:

openssl_x509_read(makeCert($x5c[0]))
Leo
  • 1,508
  • 13
  • 27