0

I am trying to use DCAppAttestService in Xamarin.iOS to attest a key generatd with GenerateKeyAsync() in a real iOS device, but it is failing with this error:

The operation couldn’t be completed. (com.apple.devicecheck.error error 2.) Specified argument was out of the range of valid values. (Parameter 'Platform name: 5.')

Here is my code:

public async Task<byte[]> GetAttestObject(string Challenge)
        {
            DCAppAttestService atserv = DCAppAttestService.SharedService;
            try
            {
                if (atserv.Supported)
                {
                    var keyId = await atserv.GenerateKeyAsync();
                    var Sha256Challenge=Sha256(Challenge);//custom metod to hash.
                    var HashValue = NSData.FromString(Sha256Challenge);
                    var vas = await atserv.AttestKeyAsync(keyId, HashValue); //Error thrown here
                    MemoryStream ms = new MemoryStream();
                    vas.AsStream().CopyTo(ms);
                    return ms.ToArray();
                }
                else
                    return null;

            }
            catch (Exception ex)
            {
                var S = ex.Message;
                return null;
            }

        }

I cannot find any example of using this service in Xamarin.iOS anywhere.

I can generate a device token without problems using: var tkn = await DCDevice.CurrentDevice.GenerateTokenAsync();

Can anyone tell me what I am doing wrong or show me a sample code to obtain the attest object?

RADU
  • 78
  • 1
  • 8

1 Answers1

0

Apple's docs indicate that com.apple.devicecheck.error error 2 is an issue with the input being invalid. https://developer.apple.com/documentation/devicecheck/dcerror/code/invalidinput

Check your SHA256() method. Are you using System.Security.Cryptography.SHA256, or something else to generate the hash? Is there are reason you're returning a string instead of a byte[]?


I'm not sure this will exactly help you in your specific case, however in my case, it was an issue with the keyId having been generated from a previous install of the app (Apple's docs say it should only be generated once per account per app and then stored and then reused, and we were putting it in Xamarin.Essentials.SecureStorage (which equates to the KeyChain on iOS, which can persist between installs due to iCloud) to be retrieved when next required). So DCAppAttestService considers the keyId to be invalid when the same one is used across app installs.

Because you asked for a sample, here is the core parts of what I'm successfully using (leaving out the check that DCAppAttestService is supported on the device, and handling an exponential backoff when Apple's server is unavailable due to e.g. network conditions)

using (SHA256 sha256 = SHA256.Create())
{
    byte[] clientDataHash = sha256.ComputeHash(Encoding.UTF8.GetBytes(challenge));

    try
    {
        NSData attestation = await _appAttestService.AttestKeyAsync(keyId, NSData.FromArray(clientDataHash));

        return attestation.GetBase64EncodedString(NSDataBase64EncodingOptions.None);
    }
    catch (NSErrorException errEx) when (errEx.Code == (long)DCError.InvalidInput)
    {
        // if keyId was previously stored in SecureStorage/KeyChain before reinstalling, it might now be invalid
        // we can remove the value and regenerate it and attestation should suceed
        SecureStorage.Remove("AppAttestKeyId");
        
        // try retrieving the challenge again
    }
}