App Attest server implementation

I'm trying to verify attestations from Apple devices on my server, and I'm finding it difficult to implement some of the steps outlined here.

This is the current state of my implementation. I'm stuck on the step where the credCert extension is decoded and compared with the nonce. I'd be grateful for any help anyone can provide.

Replies

I'm stuck on the step where the credCert extension is decoded and compared with the nonce.

Do you mean that your comparison returns false at that point?

  • I haven't been able to figure out how to do this part at all (line 75 in the example I linked to):

    Decode the sequence and extract the single octet string that it contains. Verify that the string equals nonce.

Add a Comment

I haven't been able to figure out how to do this part at all

The hex that you print in line 69 is itself an ASN.1-encoded value. The details of how to decode that depend on the particular libraries that you are using, which I'm not familiar with. FYI here is my code - C++ using Botan - for this step. I wrote it a while ago, and I think an element of trial-and-error was needed. It does help if you have an ASN.1 "pretty printer" for debugging.

  // 4. Obtain the value of the credCert extension with OID 1.2.840.113635.100.8.2, which
  //    is a DER-encoded ASN.1 sequence. Decode the sequence and extract the single octet
  //    string that it contains. Verify that the string equals nonce.

  auto extensions = leaf_cert.v3_extensions();
  auto extn = extensions.extensions_raw()[Botan::OID{"1.2.840.113635.100.8.2"}] .first;
//  Botan::ASN1_Pretty_Printer pp;
//  log(pp.print(extn), "");
  Botan::BER_Decoder decoder(extn);
  auto seq = decoder.get_next_object();
  check(seq.type() == Botan::SEQUENCE);
  Botan::BER_Decoder decoder2(seq.bits(),seq.length());
  auto cons = decoder2.get_next_object();
  check(cons.get_class() & Botan::CONSTRUCTED);
  Botan::BER_Decoder decoder3(cons.bits(),cons.length());
  auto expected_nonce = decoder3.get_next_octet_string();

  check(std::equal(expected_nonce.begin(), expected_nonce.end(), nonce.begin(), nonce.end()));

Thanks, but I'm completely out of my depth at this point. I don't know how to do this step in TypeScript or any other language, and everything I've tried with GPT-4 hasn't worked.