Fido auth with Android SDK. Error from a server: invalid origin

1k Views Asked by At

I use a FIDO android SDK https://developers.google.com/android/reference/com/google/android/gms/fido/package-summary and web FIDO lib https://github.com/lbuchs/WebAuthn as a server

To complete authentication I send to the server the following payload:

{"authenticatorData":"uGLTOEtQtBsB4wjhEvR0ZVayRWn/3mhUyp6dqFFY0a8BAAABDQ==","clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiLW9zc3JiYXY3SmhmUWlQY1ZlMzFkdDQxMG5ZWHVvWW9kM1FYdHc5VmlIUSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmZiRU5UdkNTZVItQXdKVjVycnJCc2I5OHAtakV3MGM1U1NPTXVsX0t3YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uYWZ0ZXJsb2dpYy5hdXJvcmEubWFpbCIsInRva2VuQmluZGluZyI6eyJzdGF0dXMiOiJwcmVzZW50IiwiaWQiOiJodHRwczpcL1wvdGVzdC5hZnRlcmxvZ2ljLmNvbSJ9fQ==","id":"LEBlQOlamqsmKzRBPQe9y0BFN5IaQ5BBB1ByiDH85HulzCYQTffqeK0RQDoZqUO7syGZY+hkfWf9P2FiQQ3eVA==","signature":"MEUCICFf8qFGiXxGTBokpstfUsCwbd7JTsLlDrFZoGMi3tZzAiEA0zAXxFDeqA7gF6YahudK+LD2gDUPtAnXqgAvvhVc/vE="}

The field clientDataJSON contains a base64-encrypted JSON object that has property "origin":"android:apk-key-hash:fbENTvCSeR-AwJV5rrrBsb98p-jEw0c5SSOMul_KwaI"

But the server responds with an error "invalid origin".

At the same time, my web FIDO auth implementation sends clientDataJSON with "origin":"https://test.afterlogic.com" and everything is working fine in this case.

How I can verify origin with android:apk-key-hash on the webserver? I will be appreciated any other ideas on how to deal with this.

2

There are 2 best solutions below

0
On

I think Android's FIDO sdk is a client that mimics the WebAuthn API.

Other specifications mimicking the WebAuthn API to enable WebAuthn public key credentials on non-Web platforms (e.g. native mobile applications), MAY define different rules for binding a caller to a Relying Party Identifier. 

refs: https://www.w3.org/TR/webauthn-3/#relying-party-identifier

Someone also raised this up to W3C: https://github.com/w3c/webauthn/issues/1297

https://github.com/lbuchs/WebAuthn could be following the WebAuthn spec, but doesn't support such clients that have different way of binding the caller to the RPID.

0
On

The origin passed as part of the Webauthn payload is known as a FacetID. In the browser, it's a Web Origin. On Android, it uses a Base64URL encoded form of the application signing certificate's SHA1 hash. On iOS, it's the app's bundle ID.

  • Web: https://example.com
  • Android: android:apk-key-hash:<sha1_hash-of-apk-signing-cert>
  • iOS: ios:bundle-id:<ios-bundle-id-of-app>

See this spec for a more in-depth explanation: https://fidoalliance.org/specs/uaf-v1.0-id-20141122/fido-appid-and-facets-v1.0-id-20141122.html#the-appid-and-facetid-assertions

The spec provides the following Android code sample:

private String getFacetID(Context aContext, int callingUid) {

    String packageNames[] = aContext.getPackageManager().getPackagesForUid(callingUid);

    if (packageNames == null) {
        return null;
    }

    try {
        PackageInfo info = aContext.getPackageManager().getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);

        byte[] cert = info.signatures[0].toByteArray();
        InputStream input = new ByteArrayInputStream(cert);

        CertificateFactory cf = CertificateFactory.getInstance("X509");
        X509Certificate c = (X509Certificate) cf.generateCertificate(input);

        MessageDigest md = MessageDigest.getInstance("SHA1");

        return "android:apk-key-hash:" +
                  Base64.encodeToString(md.digest(c.getEncoded()), Base64.DEFAULT | Base64.NO_WRAP | Base64.NO_PADDING);
    }
    catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
    catch (CertificateException e) {
        e.printStackTrace();
    }
    catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    catch (CertificateEncodingException e) {
        e.printStackTrace();
    }

    return null;
}