Skip to content

Commit

Permalink
Release 1.0.1
Browse files Browse the repository at this point in the history
Bugfixes:

- Registration no longer fails for unimplemented attestation statement
  formats if `allowUnknownAttestation` is set to `true`.
  - Registration still fails for attestation statement formats not
    defined in the WebAuthn Level 1 spec.
  • Loading branch information
emlun committed Mar 1, 2019
2 parents 42f5a2d + 1c0737f commit 8aaf483
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 96 deletions.
4 changes: 0 additions & 4 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
[submodule "lombok"]
path = lombok
url = https://github.com/emlun/lombok.git
branch = builder-javadoc
29 changes: 20 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,24 @@ jdk:
script:
- ./gradlew check assembleJavadoc

after_success:
- ./gradlew coveralls
stages:
- test
- mutation-test
- deploy

deploy:
provider: pages
skip-cleanup: true
github-token: $PAGES_DEPLOY_KEY
on:
branch: master
local-dir: 'build/javadoc'
jobs:
include:
- stage: mutation-test
jdk: oraclejdk8
script: ./gradlew pitest coveralls

- stage: deploy
jdk: oraclejdk8
script: ./gradlew assembleJavadoc
deploy:
provider: pages
skip-cleanup: true
github-token: $PAGES_DEPLOY_KEY
on:
branch: master
local-dir: 'build/javadoc'
10 changes: 10 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
== Version 1.0.1 ==

Bugfixes:

* Registration no longer fails for unimplemented attestation statement formats
if `allowUnknownAttestation` is set to `true`.
** Registration still fails for attestation statement formats not defined in
the WebAuthn Level 1 spec.


== Version 1.0.0 ==

* Fixed URL in artifact POM
Expand Down
22 changes: 18 additions & 4 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ Maven:
<dependency>
<groupId>com.yubico</groupId>
<artifactId>webauthn-server-core</artifactId>
<version>1.0.0-RC2</version>
<version>1.0.0</version>
<scope>compile</scope>
</dependency>
----------

Gradle:

----------
compile 'com.yubico:webauthn-server-core:1.0.0-RC2'
compile 'com.yubico:webauthn-server-core:1.0.0'
----------


Expand All @@ -60,6 +60,20 @@ and other higher level concepts can make use of this authentication mechanism,
but the authentication mechanism alone does not make a security system.


== Known issues

- In the link:webauthn-server-demo[example app], authentication does not work in
Chrome as of version 70. This is due to a
link:https://bugs.chromium.org/p/chromium/issues/detail?id=847878[bug in
Chrome] which will not be worked around here. To work around this in
application code, you can omit the
link:https://yubico.github.io/java-webauthn-server/webauthn-server-core/com/yubico/webauthn/data/AuthenticatorAssertionResponse.AuthenticatorAssertionResponseBuilder.html#userHandle-java.util.Optional[`userHandle`]
when constructing an
link:https://yubico.github.io/java-webauthn-server/webauthn-server-core/com/yubico/webauthn/data/AuthenticatorAssertionResponse.html[`AuthenticatorAssertionResponse`]
value if the `userHandle` is empty. See
https://github.com/Yubico/java-webauthn-server/issues/12 .


== Documentation

See the
Expand Down Expand Up @@ -204,14 +218,14 @@ effects, and does not directly interact with any database. This means it is
database agnostic and thread safe. The following diagram illustrates an example
architecture for an application using the library.

image::https://raw.githubusercontent.com/Yubico/java-webauthn-server/master/docs/img/demo-architecture.svg["Example application architecture",align="center"]
image::https://raw.githubusercontent.com/Yubico/java-webauthn-server/master/docs/img/demo-architecture.svg?sanitize=true["Example application architecture",align="center"]

The application manages all state and database access, and communicates with the
library via POJO representations of requests and responses. The following
diagram illustrates the data flow during a WebAuthn registration or
authentication ceremony.

image::https://raw.githubusercontent.com/Yubico/java-webauthn-server/master/docs/img/demo-sequence-diagram.svg["WebAuthn ceremony sequence diagram",align="center"]
image::https://raw.githubusercontent.com/Yubico/java-webauthn-server/master/docs/img/demo-sequence-diagram.svg?sanitize=true["WebAuthn ceremony sequence diagram",align="center"]

In this diagram, the *Client* is the user's browser and the application's
client-side scripts. The *Server* is the application and its business logic, the
Expand Down
12 changes: 2 additions & 10 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,8 @@ allprojects {
targetCompatibility = 1.8

lombok {
version '1.18.4'
sha256 = '39f3922deb679b1852af519eb227157ef2dd0a21eec3542c8ce1b45f2df39742'
}
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module('org.projectlombok:lombok') with module('com.yubico:lombok:1.18.5-custom')
}
}
version '1.18.6'
sha256 = '6373d9ade79efdc028cd48d40a9af9ac6a090dbcfaec55b438ec49556a4e92fb'
}

tasks.withType(JavaCompile) {
Expand All @@ -73,7 +66,6 @@ allprojects {
repositories {
mavenLocal()

maven { url uri("${rootProject.projectDir}/lib") }
maven { url "http://repo.maven.apache.org/maven2" }
}

Expand Down
17 changes: 0 additions & 17 deletions lib/com/yubico/lombok/1.18.5-custom/README.md

This file was deleted.

Binary file not shown.
1 change: 0 additions & 1 deletion lombok
Submodule lombok deleted from 2a2350
2 changes: 1 addition & 1 deletion webauthn-server-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jar {
manifest {
attributes([
'Specification-Title': 'Web Authentication: An API for accessing Public Key Credentials',
'Specification-Version': 'Level 1 Candidate Recommendation 2018-03-20',
'Specification-Version': 'Level 1 Proposed Recommendation 2019-01-17',
'Specification-Vendor': 'World Wide Web Consortium',
'Implementation-Id': 'java-webauthn-server',
'Implementation-Title': 'Yubico Web Authentication server library',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
import lombok.extern.slf4j.Slf4j;

import static com.yubico.internal.util.ExceptionUtil.assure;
import static com.yubico.webauthn.data.AttestationType.NONE;

@Builder
@Slf4j
Expand Down Expand Up @@ -373,24 +372,18 @@ class Step13 implements Step<Step14> {
private final List<String> prevWarnings;

@Override
public void validate() {
assure(formatSupported(), "Unsupported attestation statement format: %s", format());
}
public void validate() {}

@Override
public Step14 nextStep() {
return new Step14(clientDataJsonHash, attestation, attestationStatementVerifier().get(), allWarnings());
return new Step14(clientDataJsonHash, attestation, attestationStatementVerifier(), allWarnings());
}

public String format() {
return attestation.getFormat();
}

public boolean formatSupported() {
return attestationStatementVerifier().isPresent();
}

private Optional<AttestationStatementVerifier> attestationStatementVerifier() {
public Optional<AttestationStatementVerifier> attestationStatementVerifier() {
switch (format()) {
case "fido-u2f":
return Optional.of(new FidoU2fAttestationStatementVerifier());
Expand All @@ -410,15 +403,19 @@ private Optional<AttestationStatementVerifier> attestationStatementVerifier() {
class Step14 implements Step<Step15> {
private final ByteArray clientDataJsonHash;
private final AttestationObject attestation;
private final AttestationStatementVerifier attestationStatementVerifier;
private final Optional<AttestationStatementVerifier> attestationStatementVerifier;
private final List<String> prevWarnings;

@Override
public void validate() {
assure(
attestationStatementVerifier.verifyAttestationSignature(attestation, clientDataJsonHash),
"Invalid attestation signature."
);
attestationStatementVerifier.ifPresent(verifier -> {
assure(
verifier.verifyAttestationSignature(attestation, clientDataJsonHash),
"Invalid attestation signature."
);
});

assure(attestationType() != null, "Failed to determine attestation type");
}

@Override
Expand All @@ -428,18 +425,40 @@ public Step15 nextStep() {

public AttestationType attestationType() {
try {
return attestationStatementVerifier.getAttestationType(attestation);
if (attestationStatementVerifier.isPresent()) {
return attestationStatementVerifier.get().getAttestationType(attestation);
} else {
switch (attestation.getFormat()) {
case "android-key":
// TODO delete this once android-key attestation verification is implemented
return AttestationType.BASIC;
case "tpm":
// TODO delete this once tpm attestation verification is implemented
if (attestation.getAttestationStatement().has("x5c")) {
return AttestationType.ATTESTATION_CA;
} else {
return AttestationType.ECDAA;
}
default:
throw new IllegalArgumentException("Failed to resolve attestation type; unknown attestation statement format: " + attestation.getFormat());
}
}
} catch (IOException | CoseException | CertificateException e) {
throw new IllegalArgumentException("Failed to resolve attestation type.", e);
}
}

public Optional<List<X509Certificate>> attestationTrustPath() {
if (attestationStatementVerifier instanceof X5cAttestationStatementVerifier) {
try {
return ((X5cAttestationStatementVerifier) attestationStatementVerifier).getAttestationTrustPath(attestation);
} catch (CertificateException e) {
throw new IllegalArgumentException("Failed to resolve attestation trust path.", e);
if (attestationStatementVerifier.isPresent()) {
AttestationStatementVerifier verifier = attestationStatementVerifier.get();
if (verifier instanceof X5cAttestationStatementVerifier) {
try {
return ((X5cAttestationStatementVerifier) verifier).getAttestationTrustPath(attestation);
} catch (CertificateException e) {
throw new IllegalArgumentException("Failed to resolve attestation trust path.", e);
}
} else {
return Optional.empty();
}
} else {
return Optional.empty();
Expand All @@ -456,10 +475,6 @@ class Step15 implements Step<Step16> {

@Override
public void validate() {
assure(
attestationType == AttestationType.SELF_ATTESTATION || attestationType == NONE || trustResolver().isPresent(),
"Failed to obtain attestation trust anchors."
);
}

@Override
Expand Down Expand Up @@ -504,6 +519,11 @@ class Step16 implements Step<Step17> {

@Override
public void validate() {
assure(
trustResolver.isPresent() || allowUntrustedAttestation,
"Failed to obtain attestation trust anchors."
);

switch (attestationType) {
case SELF_ATTESTATION:
assure(allowUntrustedAttestation, "Self attestation is not allowed.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,12 @@ public class RelyingParty {
* attestation and none attestation.
*
* <p>
* Regardless of the value of this option, invalid attestation statements of supported formats will always be
* rejected. For example, a "packed" attestation statement with an invalid signature will be rejected even if this
* option is set to <code>true</code>.
* </p>
*
* <p>
* The default is <code>true</code>.
* </p>
*/
Expand Down
Loading

0 comments on commit 8aaf483

Please sign in to comment.