0

trying to prevent rooted devices to run my app.

What i want to do is to verify the signature of my signed attestation i got using safety net api on my app :

    SafetyNet.getClient(context).attest(byteArrayNonce, "MYAPIKEY")
            .addOnSuccessListener {

I have managed to verify the signature of the jwt received using google api calling:

https://www.googleapis.com/androidcheck/v1/attestations/verify?key=${safetyAPIKey} (with signedAttestation in the request body)

Everything is fine and google tell me that verification succeeded, thing is that this service is only made for testing, i should be able to verify the signature on my server. From what i understand to verify the jwt signature i need a public key. I use https://www.npmjs.com/package/jws

I'm supposed to verify the signature like so :

jwt.verify(signedAttestation, key)

Thing is i have no idea where to find this key, it is clearly not the APIKey, there is some sample code provided by Google but it is in Java or C# and i'm clearly no capable of translating it into node js. It is available here: https://github.com/googlesamples/android-play-safetynet/ and i'm trying to focus on the offline verification : https://github.com/googlesamples/android-play-safetynet/blob/master/server/java/src/main/java/OfflineVerify.java Any help is welcome, thank you very much.

1 Answers1

2

Basically, there are a series of steps that you need to perform for proper validation. Here are the steps

The 3rd step is what you need to be doing.

I would definitely urge you to go through all the reference link to understand the process better and do look into each library functions used here to know what they are doing and if that's what you want them to be doing. I've written pseudocode to explain the steps

// following steps should be performed
// 1. decode the jws
// 2. verify the source of the first certificate in x5c array of jws header 
//    to be attest.google.com
// 3. now to be sure if the jws was not tampered with, validate the signature of jws 
//    with the certificate whose source we validated
// 4. if the signature was valid, we need to know if the certificate was valid by 
//    explicitly checking the certificate chain
// 5. Validate the payload by matching the package name, apkCertificateDigest(base64 encoding of hashed your apps signing certificate)
//    and nonce value
// 6. and now you can trust the ctsProfileMatch and BasicIntegrity flags
// let's see some code in node, though this will not run as-is, 
// but it provides an outline on how to do it and which functions to consider

const pki = require('node-forge').pki;
const jws = require('jws');
const pem = require("pem");
const forge = require('node-forge');

const signedAttestation = "Your signed attestation here";

function deviceAttestationCheck(signedAttestation) {
  // 1. decode the jws
  const decodedJws = jws.decode(signedAttestation);
  const payload = JSON.parse(decodedJws.payload);

  // convert the certificate received in the s5c array into valid certificates by adding 
  // '-----BEGIN CERTIFICATE-----\n' and '-----END CERTIFICATE-----'
  // at the start and the end respectively for each element in the array
  // and by adding '\n' at every 64 char
  // you'll have to write your own function to do the simple string conversion
  // get the x5c certificate array
  const x5cArray = decodedJws.header.x5c;
  updatedX5cArray = doTheReformatting(x5cArray);

  // 2. verify the source to be attest.google.com
  certToVerify = updatedX5cArray[0];
  const details = pem.readCertificateInfo(certToVerify);
  // check if details.commanName === "attest.google.com"

  const certs = updatedX5cArray.map((cert) => pki.certificateFromPem(cert));

  // 3. Verify the signature with the certificate that we received
  // the first element of the certificate(certs array) is the one that was issued to us, so we should use that to verify the signature
  const isSignatureValid = jws.verify(signedAttestation, 'RS256', certs[0]);

}

All the articles that helped me:

  1. Quick summary - Here
  2. explanation for the process - Here
Aditya Kumar
  • 71
  • 1
  • 6