目录

FIDO2 provides the WebAuthn-based FIDO2 client. This document only describes how to use FIDO2 client APIs. For details about operations related to the app server and FIDO server, please refer to related standards.

FIDO2 includes two operations: registration and authentication. The processes are similar for the two operations.

  1. Create an activity.

  2. Obtain the challenge value and related policy from the FIDO server, and initiate a request. (Only the FIDO client APIs are provided here. For details about the interaction with the FIDO server, please refer to related specifications and contact the FIDO server vendor to obtain the related API description.)

  3. Call Fido2Client.getRegistrationIntent() to initiate registration, or call Fido2Client.getAuthenticationIntent() to initiate authentication.

  4. Call Fido2Intent.launchFido2Activity() in the callback to start registration (requestCode is Fido2Client.REGISTRATION_REQUEST) or authentication (requestCode is Fido2Client.AUTHENTICATION_REQUEST). The callback will be executed in the main thread.

  5. Call Fido2Client.getFido2RegistrationResponse() or Fido2Client.getFido2AuthenticationResponse() in the callback Activity.onActivityResult() to obtain the registration or authentication result.

  6. Send the registration or authentication result to the FIDO server for verification. (Only the FIDO client APIs are provided here. For details about the interaction with the FIDO server, please refer to related specifications and contact the FIDO server vendor to obtain the related API description.)

Notice:

Only EMUI 4.0 (API level 23) and later versions support FIDO2.

The following is the sample code for using FIDO2-related APIs:

  1. package com.huawei.hms.kit.fidocp;
  2. import android.app.Activity;
  3. import android.app.AlertDialog;
  4. import android.content.Intent;
  5. import android.os.Bundle;
  6. import android.view.View;
  7. import android.widget.TextView;
  8. import androidx.appcompat.app.AppCompatActivity;
  9. import com.huawei.hms.fidocp.R;
  10. import com.huawei.hms.support.api.fido.fido2.Algorithm;
  11. import com.huawei.hms.support.api.fido.fido2.AttestationConveyancePreference;
  12. import com.huawei.hms.support.api.fido.fido2.AuthenticatorSelectionCriteria;
  13. import com.huawei.hms.support.api.fido.fido2.Fido2;
  14. import com.huawei.hms.support.api.fido.fido2.Fido2AuthenticationRequest;
  15. import com.huawei.hms.support.api.fido.fido2.Fido2AuthenticationResponse;
  16. import com.huawei.hms.support.api.fido.fido2.Fido2Client;
  17. import com.huawei.hms.support.api.fido.fido2.Fido2Intent;
  18. import com.huawei.hms.support.api.fido.fido2.Fido2IntentCallback;
  19. import com.huawei.hms.support.api.fido.fido2.Fido2RegistrationRequest;
  20. import com.huawei.hms.support.api.fido.fido2.Fido2RegistrationResponse;
  21. import com.huawei.hms.support.api.fido.fido2.Fido2Response;
  22. import com.huawei.hms.support.api.fido.fido2.NativeFido2AuthenticationOptions;
  23. import com.huawei.hms.support.api.fido.fido2.NativeFido2RegistrationOptions;
  24. import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialCreationOptions;
  25. import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialDescriptor;
  26. import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialParameters;
  27. import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialRequestOptions;
  28. import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialRpEntity;
  29. import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialType;
  30. import com.huawei.hms.support.api.fido.fido2.PublicKeyCredentialUserEntity;
  31. import java.security.SecureRandom;
  32. import java.util.ArrayList;
  33. import java.util.Arrays;
  34. import java.util.List;
  35. import java.util.Locale;
  36. public class Fido2DemoActivity extends AppCompatActivity {
  37.    private TextView reusltView;
  38.    private Fido2Client fido2Client;
  39.    private byte[] regCredentialId = null;
  40.    private String rpId = "com.huawei.hms.fido2.test";
  41.    private String user = "fidoCp";
  42.    @Override
  43.    protected void onCreate(Bundle savedInstanceState) {
  44.        super.onCreate(savedInstanceState);
  45.        setContentView(R.layout.activity_fido2_demo);
  46.        reusltView = findViewById(R.id.reusltView);
  47.        fido2Client = Fido2.getFido2Client(this);
  48.    }
  49.    // Obtain the challenge value and related policy from the FIDO server, and initiate a Fido2RegistrationRequest request.
  50.    private Fido2RegistrationRequest assembleFido2RegistrationRequest() {
  51.        // TODO: Obtain the challenge value and related policy from the FIDO server.
  52.        byte[] challengeBytes = getChallege();
  53.        // Initiate the Fido2RegistrationRequest request.
  54.        PublicKeyCredentialCreationOptions.Builder builder = new PublicKeyCredentialCreationOptions.Builder();
  55.        builder.setRp(new PublicKeyCredentialRpEntity(rpId, rpId, null))
  56.            .setUser(new PublicKeyCredentialUserEntity(user, user.getBytes()))
  57.            .setChallenge(challengeBytes)
  58.            .setAttestation(AttestationConveyancePreference.DIRECT)
  59.            .setAuthenticatorSelection(new AuthenticatorSelectionCriteria(null, null, null))
  60.            .setPubKeyCredParams(new ArrayList<PublicKeyCredentialParameters>(
  61.                Arrays.asList(
  62.    new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, Algorithm.ES256),
  63.    new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, Algorithm.RS256))))
  64.            .setTimeoutSeconds(60L);
  65.        if (regCredentialId != null) {
  66.            builder.setExcludeList(new ArrayList<PublicKeyCredentialDescriptor>(
  67.                Arrays.asList(
  68.    new PublicKeyCredentialDescriptor(PublicKeyCredentialType.PUBLIC_KEY, regCredentialId))));
  69.        }
  70.        return new Fido2RegistrationRequest(builder.build(), null);
  71.    }
  72.    public void btnRegistrationClicked(View view) {
  73.        if (!fido2Client.isSupported()) {
  74.            showMsg("FIDO2 is not supported.");
  75.            return;
  76.        }
  77.        Fido2RegistrationRequest request = assembleFido2RegistrationRequest();
  78.        // Call Fido2Client.getRegistrationIntent to obtain a Fido2Intent instance and start the FIDO client registration process.
  79.        fido2Client.getRegistrationIntent(request, NativeFido2RegistrationOptions.DEFAULT_OPTIONS,
  80.            new Fido2IntentCallback() {
  81.                @Override
  82.                public void onSuccess(Fido2Intent fido2Intent) {
  83.                    // Start the FIDO client registration process through Fido2Client.REGISTRATION_REQUEST.
  84.                    fido2Intent.launchFido2Activity(Fido2DemoActivity.this, Fido2Client.REGISTRATION_REQUEST);
  85.                }
  86.                @Override
  87.                public void onFailure(int errorCode, CharSequence errString) {
  88.                    showError("Registration failed." + errorCode + "=" + errString);
  89.                }
  90.            });
  91.    }
  92.    // Obtain the challenge value and related policy from the FIDO server, and initiate a Fido2AuthenticationRequest request.
  93.    private Fido2AuthenticationRequest assembleFido2AuthenticationRequest() {
  94.        // TODO: Obtain the challenge value and related policy from the FIDO server.
  95.        byte[] challengeBytes = getChallege();
  96.        // Initiate the Fido2RegistrationRequest request.
  97.        List<PublicKeyCredentialDescriptor> allowList = new ArrayList<>();
  98.        allowList.add(new PublicKeyCredentialDescriptor(PublicKeyCredentialType.PUBLIC_KEY, regCredentialId));
  99.        PublicKeyCredentialRequestOptions.Builder builder = new PublicKeyCredentialRequestOptions.Builder();
  100.       builder.setRpId(rpId).setChallenge(challengeBytes).setAllowList(allowList).setTimeoutSeconds(60L);
  101.        return new Fido2AuthenticationRequest(builder.build(), null);
  102.    }
  103.    public void btnAuthenticationClicked(View view) {
  104.        if (regCredentialId == null) {
  105.            showMsg("Please register first.");
  106.            return;
  107.        }
  108.        if (!fido2Client.isSupported()) {
  109.            showMsg("FIDO2 is not supported.");
  110.            return;
  111.        }
  112.        Fido2AuthenticationRequest request = assembleFido2AuthenticationRequest();
  113.        // Call Fido2Client.getAuthenticationIntent to obtain a Fido2Intent instance and start the FIDO client authentication process.
  114.        fido2Client.getAuthenticationIntent(request, NativeFido2AuthenticationOptions.DEFAULT_OPTIONS,
  115.            new Fido2IntentCallback() {
  116.                @Override
  117.                public void onSuccess(Fido2Intent fido2Intent) {
  118.                    // Start the FIDO client authentication process through Fido2Client.AUTHENTICATION_REQUEST.
  119.                    fido2Intent.launchFido2Activity(Fido2DemoActivity.this, Fido2Client.AUTHENTICATION_REQUEST);
  120.                }
  121.                @Override
  122.                public void onFailure(int errorCode, CharSequence errString) {
  123.                    showError("Authentication failed." + errorCode + "=" + errString);
  124.                }
  125.            });
  126.    }
  127.    @Override
  128.    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  129.        super.onActivityResult(requestCode, resultCode, data);
  130.        if (resultCode != Activity.RESULT_OK) {
  131.            showMsg("Unknown error.");
  132.            return;
  133.        }
  134.        switch (requestCode) {
  135.            // Receive the registration response.
  136.            case Fido2Client.REGISTRATION_REQUEST:
  137.                Fido2RegistrationResponse fido2RegistrationResponse = fido2Client.getFido2RegistrationResponse(data);
  138.                if (fido2RegistrationResponse.isSuccess()) {
  139.                reusltView.append("Registration\n");
  140.     reusltView.append(fido2RegistrationResponse.getAuthenticatorAttestationResponse()
  141.     .toJson());
  142.                    reusltView.append("\n");
  143.                    // Save the credential ID.
  144.                    regCredentialId = fido2RegistrationResponse.getAuthenticatorAttestationResponse().getCredentialId();
  145.                    showMsg("Registration successful.");
  146.                } else {
  147.                    showError("Registration failed.", fido2RegistrationResponse);
  148.                }
  149.                break;
  150.            // Receive the authentication response.
  151.            case Fido2Client.AUTHENTICATION_REQUEST:
  152.                Fido2AuthenticationResponse fido2AuthenticationResponse =
  153.                    fido2Client.getFido2AuthenticationResponse(data);
  154.                if (fido2AuthenticationResponse.isSuccess()) {
  155.                    reusltView.append("Authentication\n");
  156.                    reusltView.append(fido2AuthenticationResponse.getAuthenticatorAssertionResponse().toJson());
  157.                    reusltView.append("\n");
  158.                    showMsg("Authentication successful.");
  159.                } else {
  160.                    showError("Authentication failed.", fido2AuthenticationResponse);
  161.                }
  162.        }
  163.    }
  164.    private void showError(String message) {
  165.        AlertDialog.Builder builder = new AlertDialog.Builder(Fido2DemoActivity.this);
  166.        builder.setTitle("Error");
  167.        builder.setMessage(message);
  168.        builder.setPositiveButton("OK", null);
  169.        builder.show();
  170.    }
  171.    private void showError(String message, Fido2Response fido2Response) {
  172.        StringBuilder errMsgBuilder = new StringBuilder();
  173.        errMsgBuilder.append(message)
  174.            .append(fido2Response.getFido2ResultCode())
  175.            .append("=")
  176.            .append(fido2Response.getFido2ResultMessage())
  177.            .append(String.format(Locale.getDefault(), "(Ctap error: 0x%x=%s)", fido2Response.getCtapResultCode(),
  178.                fido2Response.getCtapResultMessage()));
  179.        showError(errMsgBuilder.toString());
  180.    }
  181.    public void showMsg(String message) {
  182.        AlertDialog.Builder builder = new AlertDialog.Builder(Fido2DemoActivity.this);
  183.        builder.setTitle("Information");
  184.        builder.setMessage(message);
  185.        builder.setPositiveButton("OK", null);
  186.        builder.show();
  187.    }
  188.    public void btnClearLogClicked(View view) {
  189.        reusltView.setText("");
  190.        regCredentialId = null;
  191.    }
  192.    private byte[] getChallege() {
  193.        return SecureRandom.getSeed(16);
  194.    }
  195. }
Note:

For more sample information, click fido2-sample.zip to download the sample code.