Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement HMAC-Secret extension #5

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ allprojects {

ext {
compileSdkVersion = 29
hwSdkVersionName = '4.4.0'
hwSdkVersionName = '4.5.0'
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change doesn't break any non-"internal" classes, per se, but it does add fields and features.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2018-2021 Confidential Technologies GmbH
*
* You can purchase a commercial license at https://hwsecurity.dev.
* Buying such a license is mandatory as soon as you develop commercial
* activities involving this program without disclosing the source code
* of your own applications.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package de.cotech.hw.fido2.domain;

import com.google.auto.value.AutoValue;

@AutoValue
public abstract class BooleanExtensionParameterValue implements ExtensionParameter.ExtensionParameterValue {
public abstract boolean value();

public static BooleanExtensionParameterValue create(boolean value) {
return new AutoValue_BooleanExtensionParameterValue(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2018-2021 Confidential Technologies GmbH
*
* You can purchase a commercial license at https://hwsecurity.dev.
* Buying such a license is mandatory as soon as you develop commercial
* activities involving this program without disclosing the source code
* of your own applications.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package de.cotech.hw.fido2.domain;

import com.google.auto.value.AutoValue;

@AutoValue
public abstract class ByteArrayExtensionParameterValue implements ExtensionParameter.ExtensionParameterValue {
@SuppressWarnings("mutable")
public abstract byte[] value();

public static ByteArrayExtensionParameterValue create(byte[] value) {
return new AutoValue_ByteArrayExtensionParameterValue(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2018-2021 Confidential Technologies GmbH
*
* You can purchase a commercial license at https://hwsecurity.dev.
* Buying such a license is mandatory as soon as you develop commercial
* activities involving this program without disclosing the source code
* of your own applications.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package de.cotech.hw.fido2.domain;
import android.os.Parcelable;
import com.google.auto.value.AutoValue;

@AutoValue
public abstract class ExtensionParameter implements Parcelable {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class (and change) lays the groundwork for supporting other extensions such as CredProtect, mandatory in CTAP2.1 and quite desirable for an application using resident keys.


public interface ExtensionParameterValue extends Parcelable {
}

public abstract String key();
@SuppressWarnings("mutable")
public abstract ExtensionParameterValue value();

public static ExtensionParameter create(String key, ExtensionParameterValue value) {
return new AutoValue_ExtensionParameter(key, value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2018-2021 Confidential Technologies GmbH
*
* You can purchase a commercial license at https://hwsecurity.dev.
* Buying such a license is mandatory as soon as you develop commercial
* activities involving this program without disclosing the source code
* of your own applications.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package de.cotech.hw.fido2.domain;

import androidx.annotation.Nullable;

import com.google.auto.value.AutoValue;

@AutoValue
public abstract class HmacSecretExtensionParameterValue implements ExtensionParameter.ExtensionParameterValue {
@SuppressWarnings("mutable")
public abstract byte[] salt1();

@Nullable
@SuppressWarnings("mutable")
public abstract byte[] salt2();

public static HmacSecretExtensionParameterValue create(byte[] salt1, @Nullable byte[] salt2) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the unencrypted values so they must always be 32 bytes long - even when PIN Protocol 2 will add a 16-byte IV to the front, that happens around these values and not within them.

if (salt1.length != 32) {
throw new IllegalArgumentException("HMAC salt1 must be 32 bytes in length exactly");
}
if (salt2 != null && salt2.length != 32) {
throw new IllegalArgumentException("HMAC salt2 must be 32 bytes in length exactly");
}
return new AutoValue_HmacSecretExtensionParameterValue(salt1, salt2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import androidx.annotation.Nullable;
import com.google.auto.value.AutoValue;
import de.cotech.hw.fido2.internal.cbor_java.model.Map;


@AutoValue
Expand Down Expand Up @@ -69,7 +70,7 @@ public abstract class AuthenticatorData {
// extensions variable (if present) Extension-defined authenticator data. This is a CBOR [RFC7049] map with extension identifiers as keys, and authenticator extension outputs as values. See §9 WebAuthn Extensions for details.
@Nullable
@SuppressWarnings("mutable")
public abstract byte[] extensions();
public abstract Map extensions();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not useful to have the extensions type (never actually exposed in app-visible objects) be a byte array because some of its contents depend on authenticator state objects like the shared secret :-(.


public boolean hasAttestedCredentialData() {
return (flags() & FLAG_ATTESTED_CREDENTIAL_DATA) != 0;
Expand All @@ -80,7 +81,7 @@ public boolean hasExtensionData() {
}

public static AuthenticatorData create(byte[] rpIdHash, byte flags, int sigCounter,
AttestedCredentialData credentialData, byte[] extensions) {
AttestedCredentialData credentialData, Map extensions) {
return new AutoValue_AuthenticatorData(rpIdHash, flags, sigCounter, credentialData, extensions);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@

import androidx.annotation.Nullable;
import com.google.auto.value.AutoValue;

import de.cotech.hw.fido2.domain.ExtensionParameter;
import de.cotech.hw.fido2.domain.PublicKeyCredentialDescriptor;
import de.cotech.hw.fido2.domain.PublicKeyCredentialParameters;
import de.cotech.hw.fido2.domain.PublicKeyCredentialRpEntity;
Expand All @@ -50,6 +52,8 @@ public abstract class PublicKeyCredentialCreationOptions implements Parcelable {
@Nullable
public abstract List<PublicKeyCredentialDescriptor> excludeCredentials();
public abstract AttestationConveyancePreference attestation();
@Nullable
public abstract List<ExtensionParameter> extensionParameters();

public static PublicKeyCredentialCreationOptions create(
PublicKeyCredentialRpEntity rp,
Expand All @@ -60,9 +64,23 @@ public static PublicKeyCredentialCreationOptions create(
AuthenticatorSelectionCriteria authenticatorSelection,
@Nullable List<PublicKeyCredentialDescriptor> excludeCredentials,
AttestationConveyancePreference attestation
) {
return create(rp, user, challenge, pubKeyCredParams, timeout, authenticatorSelection, excludeCredentials, attestation);
}

public static PublicKeyCredentialCreationOptions create(
PublicKeyCredentialRpEntity rp,
PublicKeyCredentialUserEntity user,
byte[] challenge,
List<PublicKeyCredentialParameters> pubKeyCredParams,
@Nullable Long timeout,
AuthenticatorSelectionCriteria authenticatorSelection,
@Nullable List<PublicKeyCredentialDescriptor> excludeCredentials,
AttestationConveyancePreference attestation,
@Nullable List<ExtensionParameter> extensionParameters
) {
return new AutoValue_PublicKeyCredentialCreationOptions(
rp, user, challenge, pubKeyCredParams, timeout,
authenticatorSelection, excludeCredentials, attestation);
authenticatorSelection, excludeCredentials, attestation, extensionParameters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ public abstract class AuthenticatorAssertionResponse extends AuthenticatorRespon
@Nullable
@SuppressWarnings("mutable")
public abstract byte[] userHandle();
@Nullable
@SuppressWarnings("mutable")
public abstract byte[] hmacSecretData();

public static AuthenticatorAssertionResponse create(byte[] clientDataJson, byte[] authenticatorData, byte[] signature, @Nullable byte[] userHandle) {
return new AutoValue_AuthenticatorAssertionResponse(clientDataJson, authenticatorData, signature, userHandle);
public static AuthenticatorAssertionResponse create(byte[] clientDataJson, byte[] authenticatorData, byte[] signature, @Nullable byte[] userHandle, @Nullable byte[] hmacSecretData) {
return new AutoValue_AuthenticatorAssertionResponse(clientDataJson, authenticatorData, signature, userHandle, hmacSecretData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@

import androidx.annotation.Nullable;
import com.google.auto.value.AutoValue;

import de.cotech.hw.fido2.domain.ExtensionParameter;
import de.cotech.hw.fido2.domain.PublicKeyCredentialDescriptor;
import de.cotech.hw.fido2.domain.UserVerificationRequirement;

Expand All @@ -47,15 +49,30 @@ public abstract class PublicKeyCredentialRequestOptions implements Parcelable {
public abstract List<PublicKeyCredentialDescriptor> allowCredentials();
@Nullable
public abstract UserVerificationRequirement userVerification();
@Nullable
public abstract List<ExtensionParameter> extensionParameters();

public static PublicKeyCredentialRequestOptions create(
byte[] challenge,
Long timeout,
String rpId,
List<PublicKeyCredentialDescriptor> allowCredentials,
UserVerificationRequirement userVerification
) {
return create(challenge, timeout, rpId, allowCredentials, userVerification, null);
}

public static PublicKeyCredentialRequestOptions create(
byte[] challenge,
Long timeout,
String rpId,
List<PublicKeyCredentialDescriptor> allowCredentials,
UserVerificationRequirement userVerification,
@Nullable
List<ExtensionParameter> extensionParameters
) {
return new AutoValue_PublicKeyCredentialRequestOptions(
challenge, timeout, rpId, allowCredentials, userVerification);
challenge, timeout, rpId, allowCredentials, userVerification,
extensionParameters);
}
}
Loading