fido2-net-lib icon indicating copy to clipboard operation
fido2-net-lib copied to clipboard

"AttestationObject invalid CBOR" with integrated iOS Passkeys Attestation function

Open androidseb25 opened this issue 3 years ago • 15 comments

Hi I'm trying to use the lib with the integrated passkey function from Apple under iOS. Every time I try to complete the registration I get a CBOR error from the lib with following response "AttestationObject invalid CBOR (Declared definite length of CBOR data item exceeds available buffer size.)" When I try this in the browser it works.

Is there a solution for this or does this library not work with the iOS passkeys?

androidseb25 avatar Dec 19 '22 18:12 androidseb25

While I haven't tried it myself, I don't see any reason why it wouldn't work as is right now. I'm curious what you mean by When I try this in the browser it works.. What exactly are you doing when it doesn't work? Are you able to provide a sample of the AttestationObject?

aseigler avatar Dec 20 '22 15:12 aseigler

Of course here are a example of my credential option that I get from server with the challenge and the Payload I sent to the server with the AttestationObject from the Passkey verification.

CredentialOption:

{"rp":{"id":"localhost","name":"Fido2 Test"},"user":{"name":"Test","id":"VGVzdA","displayName":"Display Test"},"challenge":"aDL84n7ODBul0JIeriAvqa4Q9n0eR06k7pFZjksdDfK7GQtLD3MoU3EADA9TmPzS24cIN72MuMFlLruj4pL9aA","pubKeyCredParams":[{"type":"public-key","alg":-7},{"type":"public-key","alg":-257},{"type":"public-key","alg":-37},{"type":"public-key","alg":-35},{"type":"public-key","alg":-258},{"type":"public-key","alg":-38},{"type":"public-key","alg":-36},{"type":"public-key","alg":-259},{"type":"public-key","alg":-39},{"type":"public-key","alg":-8}],"timeout":30000,"attestation":"none","authenticatorSelection":{"authenticatorAttachment":"cross-platform","requireResidentKey":false,"userVerification":"preferred"},"excludeCredentials":[],"extensions":{"exts":true,"uvm":true},"status":"ok","errorMessage":""}

Payload (like the object in the api):

{ "rawId" : "m0YHSxE\/3j483XnoGgNLE0Z+fUI=", "id" : "m0YHSxE\/3j483XnoGgNLE0Z+fUI=", "extensions" : { "appid" : false, "authnSel" : false }, "response" : { "attestationObject" : "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViY34zVTIo5whmj4gmSk5rN+JXS7PPo2o1ADVHU6UeNq+FdAAAAAAAAAAAAAAAAAAAAAAAAAAAAFJtGB0sRP94+PN156BoDSxNGfn1CpQECAyYgASFYIA3+DhW9g6WqPnV86oKlHt3MRBJiozU7tdRe56zy0NKYIlggogy23\/bQCr6mhr5x46wnBGCuXbhwt7sAhjQNd+WG3A4=", "clientDataJSON" : "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiWVVSTU9EUnVOMDlFUW5Wc01FcEpaWEpwUVhaeFlUUlJPVzR3WlZJd05tczNjRVphYW10elpFUm1TemRIVVhSTVJETk5iMVV6UlVGRVFUbFViVkI2VXpJMFkwbE9OekpOZFUxR2JFeHlkV28wY0V3NVlVRSIsIm9yaWdpbiI6Imh0dHBzOi8vc2ViYXN0aWFucmFuay5kZSJ9" }, "type" : "public-key" }

And that's the error message that I receive:

{"Result":null,"status":"error","errorMessage":"AttestationObject invalid CBOR (Declared definite length of CBOR data item exceeds available buffer size.)"}

androidseb25 avatar Dec 20 '22 16:12 androidseb25

That attestation object certainly seems malformed at first glance. See https://cyberchef.org/#recipe=URL_Decode()From_Base64('A-Za-z0-9%2B/%3D',true,false)To_Hex('None',0)CBOR_Decode()&input=bzJObWJYUmtibTl1WldkaGRIUlRkRzEwb0doaGRYUm9SR0YwWVZpWTM0elZUSW81d2htajRnbVNrNXJOK0pYUzdQUG8ybzFBRFZIVTZVZU5xK0ZkQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUZKdEdCMHNSUDk0K1BOMTU2Qm9EU3hOR2ZuMUNwUUVDQXlZZ0FTRllJQTMrRGhXOWc2V3FQblY4Nm9LbEh0M01SQkppb3pVN3RkUmU1Nnp5ME5LWUlsZ2dvZ3kyM1wvYlFDcjZtaHI1eDQ2d25CR0N1WGJod3Q3c0FoalFOZCtXRzNBND0

aseigler avatar Dec 20 '22 16:12 aseigler

I know, but why the apple function ASAuthorizationPlatformPublicKeyCredentialRegistration send's me this invalid credential in the app as a rawAttestationObject (this Object contains only bytes) that I convert to a base64 string.

I followed the guidelines from here: https://developer.apple.com/documentation/authenticationservices/public-private_key_authentication/supporting_passkeys

androidseb25 avatar Dec 20 '22 16:12 androidseb25

I've posted the question on the Apple developer forum now, let's see if there are some ideas why it's not working and the CBOR object is malformed

https://developer.apple.com/forums/thread/722225

androidseb25 avatar Dec 21 '22 16:12 androidseb25

So i decoded the object now by myself, maybe it help to find out why it not work. That's the results:

The decoded attestationObject: { fmt: "none", attStmt: nil, authData: [223, 140, 213, 76, 138, 57, 194, 25, 163, 226, 9, 146, 147, 154, 205, 248, 149, 210, 236, 243, 232, 218, 141, 64, 13, 81, 212, 233, 71, 141, 171, 225, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 155, 70, 7, 75, 17, 63, 222, 62, 60, 221, 121, 232, 26, 3, 75, 19, 70, 126, 125, 66, 165, 1, 2, 3, 38, 32, 1, 33, 88, 32, 13, 254, 14, 21, 189, 131, 165, 170, 62, 117, 124, 234, 130, 165, 30, 221, 204, 68, 18, 98, 163, 53, 59, 181, 212, 94, 231, 172, 242, 208, 210, 152, 34, 88, 32, 162, 12, 182, 223, 246, 208, 10, 190, 166, 134, 190, 113, 227, 172, 39, 4, 96, 174, 93, 184, 112, 183, 187, 0, 134, 52, 13, 119, 229, 134, 220, 14] // <-- Byte Array }

decoded authData:

Is that the publickey?

{ "3": -6, "-2": "ogy23/bQCr6mhr5x46wnBGCuXbhwt7sAhjQNd+WG3A4=", // <-- Byte array as Base64 "-0": 1, "1": 2, "-1": "Df4OFb2Dpao+dXzqgqUe3cxEEmKjNTu11F7nrPLQ0pg=" // <-- Byte array as Base64 }

The rest of the authData Object: { "rpIdHash": "34zVTIo5whmj4gmSk5rN+JXS7PPo2o1ADVHU6UeNq+E=", // <-- Byte array as Base64 "counterBuffer": 0, "flags": { "UserPresence": true, "UserVerification": true, "AttestationData": true, "ExtensionData": false, "flagsInt": 93 }, "counterBuffer": "AAAAAA==", // <-- Byte array as Base64 "AAGUID"; "00000000-0000-0000-0000-000000000000", "cosePublicKeyBuffer": nil, "coseExtensionsDataBuffer": nil, "restOfDatainBufferAvailable": "pQECAyYgASFYIA3+DhW9g6WqPnV86oKlHt3MRBJiozU7tdRe56zy0NKYIlggogy23/bQCr6mhr5x46wnBGCuXbhwt7sAhjQNd+WG3A4=" //<-- Byte Count (77); Byte array as Base64 }

androidseb25 avatar Dec 23 '22 12:12 androidseb25

By padding out the end with zeroes until the decoder is happy I can see we have format none, no attestation statement, then this for the authData:

DF8CD54C8A39C219A3E20992939ACD2574BB3CFA36A3500354753A51E36A15D000000000000000000000000000000000000000000149B46074B113FDE0F375E7A0680D2C4D19F9F50A9404080C988004856080370E15BD83A5AA3E757CEA82A51EDDCC441262A3353BB5D45EE7ACF2D0D298225820A20CB6DFF6D00ABEA686BE71E3AC270460AE5DB870B7BB0086340D7561B70300000000

Further tearing that apart, the first 32 bytes are the rpId hash:

DF8CD54C8A39C219A3E20992939ACD2574BB3CFA36A3500354753A51E36A15D0

That much looks reasonable, then everything goes sideways, because flags is zero and that doesn't make sense because there is more stuff at the end. I can't spot anything in there that resembles a passable credential public key.

aseigler avatar Dec 23 '22 22:12 aseigler

mmmmh that's not good 😅 In the Apple Developer forum, no one reports on this either :/

What can I do so that we can find a solution to this problem? I really want it to work from the app with the API ^^

androidseb25 avatar Dec 23 '22 22:12 androidseb25

@aseigler I got a response on the apple developer forum, can you please take a look?

He is saying that when we disable the "URL Decode" and "To Hex" steps in the cyberchef test, the attestation object return correct.

result from cyberchef:

{ "fmt": "none", "attStmt": {}, "authData": { "type": "Buffer", "data": [ 223, 140, 213, 76, 138, 57, 194, 25, 163, 226, 9, 146, 147, 154, 205, 248, 149, 210, 236, 243, 232, 218, 141, 64, 13, 81, 212, 233, 71, 141, 171, 225, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 155, 70, 7, 75, 17, 63, 222, 62, 60, 221, 121, 232, 26, 3, 75, 19, 70, 126, 125, 66, 165, 1, 2, 3, 38, 32, 1, 33, 88, 32, 13, 254, 14, 21, 189, 131, 165, 170, 62, 117, 124, 234, 130, 165, 30, 221, 204, 68, 18, 98, 163, 53, 59, 181, 212, 94, 231, 172, 242, 208, 210, 152, 34, 88, 32, 162, 12, 182, 223, 246, 208, 10, 190, 166, 134, 190, 113, 227, 172, 39, 4, 96, 174, 93, 184, 112, 183, 187, 0, 134, 52, 13, 119, 229, 134, 220, 14 ] } }

It look the same that I have decoded above.

androidseb25 avatar Jan 09 '23 20:01 androidseb25

Looking at it again now the problem is obvious: all of the various fields that are required by spec to be base64 URL encoded are all standard base64 encoded instead. No clue why I didn't see that before.

aseigler avatar Jan 09 '23 21:01 aseigler

@aseigler I will try to figure out a way to discover this and help users figure it out. This is such a source of confusion and so easy to get wrong.

abergs avatar Jan 16 '23 17:01 abergs

@abergs have you already found something how to get it working in my iOS project?

androidseb25 avatar Feb 07 '23 09:02 androidseb25

@androidseb25 Actually @aseigler already found your problem, the data is base64 encoded when it should be base64url encoded.

My comment was rather a way for us to discover this on the server and return a better error message.

abergs avatar Feb 07 '23 10:02 abergs

thank you for this thread. I ran into the exact same invalid CBOR problem when integrating iOS, and indeed switching from base64 to base64urlencoded resolved the issue!

filipw avatar Apr 05 '23 14:04 filipw

@abergs @aseigler , somehow after encoding id, attestationObject, and clientDataJSON to base64url, the library fails to decode them properly, returning null. However, when I encode them using regular base64, the library decodes the values correctly. Could there have been any changes in the library that might explain this behavior?

when input encoded base64URL:

{
    "rawResponse": {
        "id": "PA6k_8VV3vnJe_V9H0X3JBbCOzs",
        "type": "public-key",
        "rawId": "PA6k_8VV3vnJe_V9H0X3JBbCOzs",
        "response": {
            "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViYra9cdqYkFw67A8S9tFPG-3U_xVtGc-73TXCUa3NTV4ldAAAAAPv8MAcVTk7MjAtuAgVX170AFDwOpP_FVd75yXv1fR9F9yQWwjs7pQECAyYgASFYICIe1vMM7DVvLMqo7EHaNapOA-Z2BltMnLh3ZQsBPCzJIlggpaVjARhkBERA8QUMWFAHQZv0AUxHARS2zHHe7XjpVSg",
            "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoibHoySE12YTlxRVBpeFhZazBKM1dDQSIsIm9yaWdpbiI6Imh0dHBzOi8vaWRlbnRpdHkyLmRldi51a2xvbi5uZXQifQ"
        }
    }
}

How library sees:

Attestation response: AuthenticatorAttestationRawResponse { Id: null, RawId: null, Type: PublicKey, Response: AttestationResponse { AttestationObject: null, ClientDataJson: null, Transports: null }

when input encodedbase64:

{
  "rawResponse": {
    "rawId": "++q7tjTVzozrwPxa1xyZNkHTdDE=",
    "id": "++q7tjTVzozrwPxa1xyZNkHTdDE=",
    "type": "public-key",
    "response": {
      "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiWjBEem1HeERmYzZBTWluRFhGc3pldyIsIm9yaWdpbiI6Imh0dHBzOi8vaWRlbnRpdHkyLmRldi51a2xvbi5uZXQifQ==",
      "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViYra9cdqYkFw67A8S9tFPG+3U/xVtGc+73TXCUa3NTV4ldAAAAAPv8MAcVTk7MjAtuAgVX170AFPvqu7Y01c6M68D8WtccmTZB03QxpQECAyYgASFYILVVkFwEuQS/lzx78T8202Y3F/YE5aaUBcoCS0p/YlibIlggxh3HV60e195uYNyQb8mKgtfPckGVeeI1knmYilYkx/s="
    }
  }
}

how library sees:

AuthenticatorAttestationRawResponse { Id: \"FBEABBB634D5CE8CEBC0FC5AD71C993641D37431\", RawId: \"FBEABBB634D5CE8CEBC0FC5AD71C993641D37431\", Type: PublicKey, Response: AttestationResponse { AttestationObject: \"A363666D74646E6F6E656761747453746D74A06861757468446174615898ADAF5C76A624170EBB03C4BDB453C6FB753FC55B4673EEF74D70946B735357895D00000000FBFC3007154E4ECC8C0B6E020557D7BD0014FBEABBB634D5CE8CEBC0FC5AD71C993641D37431A5010203262001215820B555905C04B904BF973C7BF13F36D3663717F604E5A69405CA024B4A7F62589B225820C61DC757AD1ED7DE6E60DC906FC98A82D7CF72419579E2359279988A5624C7FB\", ClientDataJson: \"7B2274797065223A22776562617574686E2E637265617465222C226368616C6C656E6765223A225A30447A6D477844666336414D696E445846737A6577222C226F726967696E223A2268747470733A2F2F6964656E74697479322E6465762E756B6C6F6E2E6E6574227D\", Transports: null }, Extensions: null, ClientExtensionResults: null }

@androidseb25 May be you can share your IOS project with me, if it is still workable?

sluzhynskyi avatar Aug 09 '24 10:08 sluzhynskyi