Hello,
I'm implementing AppAttest for one of our apps. Though the Attestation procedure works fine, the assertion signed by the private key on the device (via generateAssertion) can't be verified at the server with the public key saved during the attestation.
Environment
AppAttest entitlement: development
iOS 14
Server: Nodejs
The client (app) and server code specific to assertion is below.
Client side code (app)
Server side Assertion verification code
The verifier.verify() call always results in 'false'.
I've tried 'hex' and 'base64' variations on the signature, but didn't work.
I've verified that the sha256(publicKey) received at the server is equal to the keyId.
Also verified that the clientDataHash generated at the server is the same as clientDataHash generated within the app.
Does crypto Verify not compatible with the generated signatures? If not, what's the suggested way to do it?
I've tried all the encodings supported by crypto Verify.verify but none of those worked.
Please help.
I'm implementing AppAttest for one of our apps. Though the Attestation procedure works fine, the assertion signed by the private key on the device (via generateAssertion) can't be verified at the server with the public key saved during the attestation.
Environment
AppAttest entitlement: development
iOS 14
Server: Nodejs
The client (app) and server code specific to assertion is below.
Client side code (app)
Code Block if let clientData = self.prepareClientData(withChallenge: challenge) { // generate assertion let clientDataHash = Data(SHA256.hash(data: clientData)) DCAppAttestService.shared.generateAssertion(keyId!, clientDataHash: clientDataHash) { assertion, error in guard error == nil else { print ("ERROR: Assertion not available right now") return } // create assertion request var urlRequest = URLRequest(url: URL(string: self.assertEP)!) urlRequest.httpMethod = "POST" urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type") let clientDataString = clientData.base64EncodedString() let assertionString = assertion!.base64EncodedString() let assertRequest: [String: Any] = ["clientData": clientDataString, "assertion": assertionString] let jsonData: Data do { jsonData = try JSONSerialization.data(withJSONObject: assertRequest, options: []) urlRequest.httpBody = jsonData } catch { print (error) return } // send assertion request to server let task = URLSession.shared.dataTask(with: urlRequest) { data, response, error in guard error == nil else { // request sending failed, try again later print (error!) return } self.extractAssertionResponse(withData: data) } task.resume() } }
Server side Assertion verification code
Code Block function verifyAssertion(clientDataBuffer, assertionBuffer) { try { let assert = cbor.decodeAllSync(assertionBuffer)[0]; let authData = assert.authenticatorData; // buffer let signature = assert.signature; // buffer // compute client Data Hash let clientDataHash = crypto.createHash('sha256').update(clientDataBuffer).digest('base64'); let clientDataHashBuffer = Buffer.from(clientDataHash, 'base64'); // compute composite hash let compositeBuffer = Buffer.concat([authData, clientDataHashBuffer]); let nonce = crypto.createHash('sha256').update(compositeBuffer).digest('base64'); // base64 string let nonceBuffer = Buffer.from(nonce, 'base64'); // load public key let keyObj = crypto.createPublicKey(k_publicKeyPem); // verify signature let verifier = crypto.createVerify('sha256').update(nonceBuffer); let sign_verify = verifier.verify(keyObj, signature); console.log("sign_verify: ", sign_verify); } catch (e) { console.log(e); } }
The verifier.verify() call always results in 'false'.
I've tried 'hex' and 'base64' variations on the signature, but didn't work.
I've verified that the sha256(publicKey) received at the server is equal to the keyId.
Code Block let keybuf = Buffer.from(k_publicKeyRaw, 'base64'); let keySHA = crypto.createHash('sha256').update(keybuf).digest('base64'); let keyVerified = (keySHA === k_keyId);
Also verified that the clientDataHash generated at the server is the same as clientDataHash generated within the app.
Does crypto Verify not compatible with the generated signatures? If not, what's the suggested way to do it?
I've tried all the encodings supported by crypto Verify.verify but none of those worked.
Code Block crypto.getHashes();
Please help.