1. Introduction

1.1. Web Authentication

Web Authentication is a new, secure web application authentication specification standardized under W3C. By combining local authentication, public-key authentication, per-origin key management, it provides strong authentication to web sites against authentication process attacks like phishing. Implementation is in progress in major browsers, and the specification offers excellent choices for users who place importance on security and convenience. Initially, the specification was developed as FIDO 2.0 by the FIDO Alliance, but it has been transferred to W3C.

1.2. WebAuthn4J

WebAuthn4J is a portable Java library for WebAuthn server side verification

1.3. Spring Security WebAuthn

As a related project of WebAuthn4J, we are developing a wrapper library named Spring Security WebAuthn to support WebAuthn with Spring Security. To introduce WebAuthn in an application built with Spring Security, it is better to use Spring Security WebAuthn rather than directly using WebAuthn4J. Spring Security WebAuthn also provides an implementation of the REST API of FIDO2 transporting binding profile.

1.4. Feature

1.4.1. Supported Attestation Statement Formats

All attestation statement formats are supported:

  • Packed attestation

  • FIDO U2F attestation

  • Android Key attestation

  • Android SafetyNet attestation

  • TPM attestation

  • None attestation

1.4.2. Conformance

All mandatory test cases and optional Android Key attestation test cases of FIDO2 Test Tools provided by FIDO Alliance are all passed.

Since FIDO2 Test Tools runs the test via the REST API of FIDO2 Transport Binding Profile, it is executed through the REST API implementation provided by Spring Security WebAuthn.

1.5. Requirements

1.5.1. Language & Framework

  • Java8 or later

1.5.2. Environment

  • SecureContext (https or the localhost)

1.6. Getting from Maven Central

If you are using Maven, just add the webauthn4j as a dependency:

<properties>
  ...
  <!-- Use the latest version whenever possible. -->
  <webauthn4j.version>0.9.10.RELEASE</webauthn4j.version>
  ...
</properties>

<dependencies>
  ...
  <dependency>
    <groupId>com.webauthn4j</groupId>
    <artifactId>webauthn4j-core</artifactId>
    <version>${webauthn4j.version}</version>
  </dependency>
  ...
</dependencies>

1.7. Source code

Source code for this project is hosted on Github.

git clone git@github.com:webauthn4j/webauthn4j.git

1.8. License

WebAuthn4J is an open source software licensed under Apache 2.0 license.

1.9. Contributing

Interested in helping out with WebAuthn4J? Great! Your participation in the community is much appreciated! Please feel free to open issues and send pull-requests.

2. Quick Start

WebAuthn is an authentication method that a user registers a public key generated by an authenticator to the server in advance and the server verifies the signature generated by the authenticator with the public key at the time of authentication. The data which contains public key and authenticator configuration and is sent at registration is called "attestation", and the data which contains signature and is sent at authentication is called "assertion".

2.1. Attestation verification

To verify an attestation on authenticator registration, call WebAuthnRegistrationContextValidator#validate. When invoking, you need to specify an instance of WebAuthnRegistrationContext as an argument.

ClientDataJSON and attestationObject, specified as the argument of the constructor of WebAuthnRegistrationContext are the value obtained by the WebAuthn JS API in the front end side. serverProperty is a parameter that houses values obtained from the server side. Please specify the following values​ when calling the constructor.

  • For origin, please specify Origin of the site that provides WebAuthn authentication. WebAuthn specification tells that the authenticator signs the data including Origin recognized by the browser. WebAuthn4J verifies whether the written Origin (namely, recognized by the browser) matches the specified Origin in serverProperty to prevent phishing attacks, which is a behavior required in WebAuthn specification.

  • For rpId, please set the rpId of the site that provides WebAuthn authentication. rpId is a parameter that specifies the scope of credentials. For more details, please refer to WebAuthn specification rpId definition.

  • For challenge, please specify the Challenge issued on WebAuthn JS API call. challenge is a parameter to prevent replay attacks. By issuing the random byte sequence challenge on server side, signing it with WebAuthn JS API, and verifying the signature on server side, users are protected from the replay attack. It is the application’s responsibility for retaining the issued Challenge.

  • tokenBindingId is a parameter for Token binding. If you do not want to use it please specify null.

userVerificationRequired is a parameter that indicates whether the user verification on the authenticator is required.

If validation fails, an exception inheriting ValidationException is thrown. If validation succeeds, WebAuthnRegistrationContextValidationResponse is returned. Please create an Authenticator instance from the returned value and persist it to the database or something in your application manner. The instance is required at the time of authentication.

// Client properties
byte[] clientDataJSON = null /* set clientDataJSON */;
byte[] attestationObject = null /* set attestationObject */;

// Server properties
Origin origin = null /* set origin */;
String rpId = null /* set rpId */;
Challenge challenge = null /* set challenge */;
byte[] tokenBindingId = null /* set tokenBindingId */;
ServerProperty serverProperty = new ServerProperty(origin, rpId, challenge, tokenBindingId);
boolean userVerificationRequired = false;

WebAuthnRegistrationContext registrationContext = new WebAuthnRegistrationContext(clientDataJSON, attestationObject, serverProperty, userVerificationRequired);

// WebAuthnRegistrationContextValidator.createNonStrictRegistrationContextValidator() returns a WebAuthnRegistrationContextValidator instance
// which doesn't validate an attestation statement. It is recommended configuration for most web application.
// If you are building enterprise web application and need to validate the attestation statement, use the constructor of
// WebAuthnRegistrationContextValidator and provide validators you like
WebAuthnRegistrationContextValidator webAuthnRegistrationContextValidator =
        WebAuthnRegistrationContextValidator.createNonStrictRegistrationContextValidator();


WebAuthnRegistrationContextValidationResponse response = webAuthnRegistrationContextValidator.validate(registrationContext);

// please persist Authenticator object, which will be used in the authentication process.
Authenticator authenticator =
        new AuthenticatorImpl( // You may create your own Authenticator implementation to save friendly authenticator name
                response.getAttestationObject().getAuthenticatorData().getAttestedCredentialData(),
                response.getAttestationObject().getAttestationStatement(),
                response.getAttestationObject().getAuthenticatorData().getSignCount()
        );
save(authenticator); // please persist authenticator in your manner

2.2. Assertion verification

To verify an assertion on authentication, call WebAuthnAuthenticationContextValidator#validate.

// Client properties
byte[] credentialId = null /* set credentialId */;
byte[] clientDataJSON = null /* set clientDataJSON */;
byte[] authenticatorData = null /* set authenticatorData */;
byte[] signature = null /* set signature */;

// Server properties
Origin origin = null /* set origin */;
String rpId = null /* set rpId */;
Challenge challenge = null /* set challenge */;
byte[] tokenBindingId = null /* set tokenBindingId */;
ServerProperty serverProperty = new ServerProperty(origin, rpId, challenge, tokenBindingId);
boolean userVerificationRequired = true;

WebAuthnAuthenticationContext authenticationContext =
        new WebAuthnAuthenticationContext(
                credentialId,
                clientDataJSON,
                authenticatorData,
                signature,
                serverProperty,
                userVerificationRequired
        );
Authenticator authenticator = load(credentialId); // please load authenticator object persisted in the registration process in your manner

WebAuthnAuthenticationContextValidator webAuthnAuthenticationContextValidator =
        new WebAuthnAuthenticationContextValidator();

WebAuthnAuthenticationContextValidationResponse response = webAuthnAuthenticationContextValidator.validate(authenticationContext, authenticator);

// please update the counter of the authenticator record
updateCounter(
        response.getAuthenticatorData().getAttestedCredentialData().getCredentialId(),
        response.getAuthenticatorData().getSignCount()
);

3. Configuration

There are two main classes when using WebAuthn4J. One is WebAuthnRegistrationContextValidator class, which is used to verify the credentials at the time of registration, and the other is WebAuthnAuthenticationContextValidator class, which is used to verify the credentials during authentication.

WebAuthnRegistrationContextValidator delegates attestation statements validation to an implementation of AttestationStatementValidator and attestation statements trustworthiness validation to an implementation of CertPathTrustworthinessValidator.

Since most sites don’t require strict attestation statement validation (WebAuthn Spec related topic ), WebAuthn4J provides WebAuthnRegistrationContextValidator.createNonStrictRegistrationContextValidator factory method that returns an instance configured CertPathTrustworthinessValidator and WebAuthnRegistrationContextValidator not to validate attestation statements.

If you are engaging an enterprise use case and strict verification of an authenticator is a requirement, Use the constructor of the WebAuthnRegistrationContextValidator class and inject validators.

3.1. Attestation statement validation

Attestation statement validation is provided by the implementation of AttestationStatementValidator interface. For each attestation statement format, corresponding validator classes are provided. Please specify its list at the first argument of the constructor of WebAuthnRegistrationContextValidator class. For example, if you would like to limit the supported format to packed only, make the List only with PackedAttestationStatementValidator, and if you would like to support packed and tpm format, make the List with PackedAttestationStatementValidator and TPMAttestationStatementValidator.

3.1.1. Attestation statement trustworthiness validation

Attestation statement trustworthiness validation has three patterns: certificate path validation, ecdaa validation, and self attestation. Certificate path validation is delegated via CertPathTrustworthinessValidator interface, and ECDAA is delegated via ECDAATrustworthinessValidator interface. WebAuthn4J provides some CertPathTrustworthinessValidator implementations. For example, TrustAnchorCertPathTrustworthinessValidator verifies trustworthiness by checking the attestation certificate chains to the root certificate provided as TrustAnchor via TrustAnchorResolver interface.

Attestation statement trustworthiness validation using FIDO Metadata Service

FIDO Alliance offers FIDO Metadata Service, which delivers Authenticator metadata. With this service, Relying Party can judge whether a security issue is reported for the authenticator trying to register. When verifying the reliability of the attestation statement with this service, MetadataItemsCertPathTrustworthinessValidator in webauthn4j-metadata module can be used for it. As MetadataItemsCertPathTrustworthinessValidator resolves the MetadataItem list corresponding to the AAGUID of the authenticator through the MetadataItemsResolver interface, we can verify the reliability with the service by a combination of MetadataItemsResolverImpl and FidoMdsMetadataItemsProvider.

3.2. Representation of an authenticator

WebAuthn4j provides Authenticator interface as a representation of an authenticator.

On registering the authenticator, you need to persist its representation by creating the instance implementing Authenticator interface in your application manner because it is used afterwards on authentication verification. It might be better to use credentialId as a search key for this persisted instance.

You can freely enhance the class implementing Authenticator interface in order to meet your application’s requirements. For example, you can add the field for your application’s user to identify the authenticator.

3.3. What WebAuthn4J doesn’t offer

In order to realize framework independence, WebAuthn4J intentionally scopes functions to WebAuthn Assertion / Attestation verification. Fetching parameters from HTTP request, issuing and saving Challenge in session, counter Value validation are not provided. Please implement in your caller code. If you are using Spring Security, consider using Spring Security WebAuthn as it provides these implementations of authentication framework specific parts.

4. Deep-Dive

4.1. Project Modules

WebAuthn4J consists of the following four modules.

4.1.1. Core webauthn4j-core.jar

Provides core features for attestation and assertion verification.

4.1.2. Metadata webauthn4j-metadata.jar

Provides additional features regarding FIDO Metadata Service.

4.1.3. Test webauthn4j-test.jar

Internal library for WebAuthn4J testing. The included classes don’t follow semantic versioning and the design may be changed even though it is public.

4.1.4. Util webauthn4j-util.jar

Contains utility classes used in WebAuthn4J library.

4.2. Classes

4.2.1. Data Transfer Objects

Classes under com.webauthn4j.data package are designed as immutable DTO.

4.2.2. Converter, Jackson Modules for WebAuthn

Classes under com.webauthn4j.data package are designed as being serializable and deserializable.

Some Classes under converter package needs custom serializer and deserializer. Jackson’s module named WebAuthnJSONModule and WebAuthnCBORModule consolidate these custom serializer and deserializer. WebAuthn4J’s validators register these modules onto Jackson’s ObjectMapper automatically.

If you want to use WebAuthn4J’s serializer and deserializer outside these WebAuthn4J’s validators, you can register these modules onto Jackson’s ObjectMapper.

If you want to use your custom serializer and deserializer for WebAuthn4J’s validators for parsing custom extensions, you can register your custom serializer and deserializer onto ObjectMapper and pass it onto WebAuthn4J' validators via those constructors.

4.2.3. TrustAnchorsResolver

TrustAnchorsResolver interface is used by TrustAnchorCertPathTrustworthinessValidator to explore root certificates in the verification of the authenticity of the attestation statements.

4.2.4. TrustAnchorsProvider

TrustAnchorsProvider is an interface that TrustAnchorsResolverImpl delegates TrustAnchor load operation to. KeyStoreFileTrustAnchorsProvider is provided as an implementation for loading TrustAnchor from Java Key Store file. Spring Security WebAuthn also provides CertFileResourcesTrustAnchorProvider to load TrustAnchor from Spring Resource.

4.2.5. Exceptions

If some verification fails, WebAuthn4J throws an exception class inheriting ValidationException.

4.3. Logging

WebAuthn4J uses SLF4J as log interface library. You can use any kind of this implementation like Logback as you want.

5. Known Issues

WebAuthn is state of the art technology. Therefore, there are still some limitations products utilizing it have. This section tells you issues known at the time of Feb 2019 that might be encountered if you try to use products utilizing WebAuthn technology.

5.1. Safari’s WebAuthn support

Safari has not yet supported WebAuthn, which means that you cannot use iPhone/iPad to experience authentication utilizing WebAuthn technology.

Safari’s Technology Preview version has supported WebAuthn using CTAP2 Authenticator, but it has not yet integrated Face ID and Touch ID. However, it seems to be expected to integrate them sooner or later.

5.2. Chrome’s ResidentKey support

Chrome has not yet supported ResidentKey, which means that you cannot use Chrome to experience authentication utilizing WebAuthn technology without entering your account’s ID

You can mimic such the experience by storing credentialId onto LocalStorage on registration and read it on authentication. However, it doesn’t works if a user uses Roaming Authenticator for authentication.

5.3. Firefox’s WebAuthn support

Firefox has supported WebAuthn using FIDO U2F Authenticator, and not CTAP2 Authenticator.

However, Windows' Firefox implementation plans to use FIDO2 API provided by Windows OS, which will makes users to experience authentication utilizing WebAuthn technology with CTAP2 Authenticator and Windows Hello.

5.4. Supporting features' difference between browsers

Browser vendors has been struggling to support WebAuthn. However, it is nothing unusual that the feature supported by some platforms are not supported by other platforms. Considering it, it is recommended to prepare some fallback mechanism for your users using platforms not supporting the feature you expected to support.

For example, if you utilize ResidentKey to omit entering user account’s ID, it might be better to support two-factor authentication requiring password authentication for users using Chrome and Firefox, and two-factor authentication without WebAuthn for users using Safari.

5.5. WebAuthn4J’s ECDAA support

WebAuthn4J has not yet supported ECDAA (Elliptic Curve based Direct Anonymous Attestation) algorithm. There is no plan to support it for the time being because ECDAA algorithm support is optional by WebAuthn specification and major browsers have not yet supported it.

5.6. WebAuthn4J’s PS256/PS384/PS512 support

WebAuthn4J has not yet supported PS256, PS384, and PS512 algorithms. There is no plan to support it for the time being because these algorithms support is optional by WebAuthn specification and standard Providers of Java Crypto API have not yet supported it.