ioswebauthnpasskey

Challenge mismatch during authenticator attestion on iOS


I am implementing a simple PoC application in React Native for iOS and trying to attest an authenticator using react-native-passkey library, however, I am struggling to verify the attestation response I am getting from my client to my Nest.JS server that utilizes @simplewebauthn/server dependency for generating responses. The issue appears to be a mismatch in the provided clientDataJSON challenge field and the one generated on the server.

Here's the challenge I am generating:

i-1E5Fhg0so0Xd3CInFzHG7EVQfWqazTgf-m26flrsQ

And here's the client data challenge that I've extracted by first converting the base64 string to a utf8 one and parsed it via JSON.parse:

{
  type: 'webauthn.create',
  challenge: 'aS0xRTVGaGcwc28wWGQzQ0luRnpIRzdFVlFmV3FhelRnZi1tMjZmbHJzUQ',
  origin: <redacted>
}

The origin is redacted on purpose. It is a valid domain that is used by my EC2 instance and has all of the endpoints needed for proper attestation/assertion flows.

I have read on the W3C spec that Apple inject some sort of client data hash in the challenge before signing it. I am not sure what to make of those specification details as they are simply too high tech for my dumbass to understand.

So, my question would be, what bytes do I need to concatenate to my challenge to make it appear the same as the one returned by my iOS app?

I tried fetching an endpoint on my server, getting that information to the iOS authenticator, and returning its response back to the server. I expected the challenge returned in client data to match the one generated by the server.


Down in the comments to the correct answer of this particular question I have spawned a conversation about verification difficulties of the assertion signature.

Here's the new question for it.


Solution

  • In your response you have

    {
      type: 'webauthn.create',
      challenge: 'aS0xRTVGaGcwc28wWGQzQ0luRnpIRzdFVlFmV3FhelRnZi1tMjZmbHJzUQ',
      origin: <redacted>
    }
    

    And here, the aS0xRTVGaGcwc28wWGQzQ0luRnpIRzdFVlFmV3FhelRnZi1tMjZmbHJzUQ would be base64 encoded.

    If I decode it I get i-1E5Fhg0so0Xd3CInFzHG7EVQfWqazTgf-m26flrsQ which is the same as you pasted in as i-1E5Fhg0so0Xd3CInFzHG7EVQfWqazTgf-m26flrsQ and you say you generated.

    Update as per the comment

    So, the problem according to the comment the question also seems to included how to validate a Apple Anonymous Attestation Statement so including this as part of the answer.

    As per Webauthn Apple is validated a bit differently than your standard cryptographic signature, or as per the step list

    1. Verify that attStmt is valid CBOR conforming to the syntax defined above and perform CBOR decoding on it to extract the contained fields.
    2. Concatenate authenticatorData and clientDataHash to form nonceToHash.
    3. Perform SHA-256 hash of nonceToHash to produce nonce.
    4. Verify that nonce equals the value of the extension with OID 1.2.840.113635.100.8.2 in credCert.
    5. Verify that the credential public key equals the Subject Public Key of credCert.
    6. If successful, return implementation-specific values representing attestation type Anonymization CA and attestation trust path x5c.

    So from the list we can see that we need to get a hold of authenticatorData, which is part of the response, and the clientDataHash, which is part of the request. Both are accessible through fields in Webauthn as per your comment. So for you the concat would be correct and you would then check the hash value of it versus the credCert part of the x5c in the attStmt of the response as per step 3 and 4.