Skip to content

Commit

Permalink
add Support enum to CredentialManagement
Browse files Browse the repository at this point in the history
  • Loading branch information
AdamVe committed Oct 18, 2023
1 parent ad8025b commit 98c3614
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,32 @@ public CredentialManagement(
PinUvAuthProtocol pinUvAuth,
byte[] pinUvToken
) {
if (!ctap.isCredentialManagerSupported()) {
if (Support.fromInfo(ctap.getCachedInfo()) == Support.NONE) {
throw new IllegalStateException("Credential manager not supported");
}
this.ctap = ctap;
this.pinUvAuth = pinUvAuth;
this.pinUvToken = pinUvToken;
}

public enum Support {
NONE,
PREVIEW,
FULL;

public static Support fromInfo(Ctap2Session.InfoData info) {
final Map<String, ?> options = info.getOptions();
if (Boolean.TRUE.equals(options.get("credMgmt"))) {
return FULL;
} else if (info.getVersions().contains("FIDO_2_1_PRE") &&
Boolean.TRUE.equals(options.get("credentialMgmtPreview"))) {
return PREVIEW;
}

return NONE;
}
}

private Map<Integer, ?> call(
byte subCommand,
@Nullable Map<?, ?> subCommandParams,
Expand Down
52 changes: 12 additions & 40 deletions fido/src/main/java/com/yubico/yubikit/fido/ctap/Ctap2Session.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,12 @@ public class Ctap2Session extends ApplicationSession<Ctap2Session> {
private static final byte CMD_BIO_ENROLLMENT_PRE = 0x40;
private static final byte CMD_CREDENTIAL_MANAGEMENT_PRE = 0x41;

private enum CredentialManagerSupport {
NONE((byte) 0x00),
PREVIEW(CMD_CREDENTIAL_MANAGEMENT_PRE),
FULL(CMD_CREDENTIAL_MANAGEMENT);

final byte command;

CredentialManagerSupport(byte command) {
this.command = command;
}
}

private final Version version;
private final Backend<?> backend;
private final InfoData info;
private final CredentialManagerSupport credentialManagerSupport;
@Nullable
private final Byte credentialManagerCommand;

private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Ctap2Session.class);

Expand Down Expand Up @@ -136,7 +126,13 @@ private Ctap2Session(Version version, Backend<?> backend)
this.version = version;
this.backend = backend;
this.info = getInfo();
this.credentialManagerSupport = getCredentialManagementSupport(info);
final CredentialManagement.Support cmSupport = CredentialManagement.Support.fromInfo(info);
this.credentialManagerCommand =
cmSupport == CredentialManagement.Support.FULL
? Byte.valueOf(CMD_CREDENTIAL_MANAGEMENT)
: cmSupport == CredentialManagement.Support.PREVIEW
? Byte.valueOf(CMD_CREDENTIAL_MANAGEMENT_PRE)
: (Byte) null;
}

private static Backend<SmartCardProtocol> getSmartCardBackend(SmartCardConnection connection)
Expand Down Expand Up @@ -202,30 +198,6 @@ byte[] sendCbor(byte[] data, @Nullable CommandState state) throws IOException {
}
}

private CredentialManagerSupport getCredentialManagementSupport(InfoData info) {
final Map<String, ?> options = info.getOptions();
if (Boolean.TRUE.equals(options.get("credMgmt"))) {
return CredentialManagerSupport.FULL;
} else if (info.getVersions().contains("FIDO_2_1_PRE") &&
Boolean.TRUE.equals(options.get("credentialMgmtPreview"))) {
return CredentialManagerSupport.PREVIEW;
}

return CredentialManagerSupport.NONE;
}

/**
* Get information about authenticator support of credential manager commands.
*
* @return true if the authenticator supports credential manager or credential manager preview
* commands are supported.
* @see <a href="https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#ref-for-getinfo-credmgmt">credMgmt option</a>
* @see <a href="https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#ref-for-getinfo-credentialmgmtpreview">credentialMgmtPreview option</a>
*/
public boolean isCredentialManagerSupported() {
return credentialManagerSupport != CredentialManagerSupport.NONE;
}

/**
* This method is invoked by the host to request generation of a new credential in the
* authenticator.
Expand Down Expand Up @@ -436,11 +408,11 @@ public void reset(@Nullable CommandState state) throws IOException, CommandExcep
@Nullable Integer pinUvAuthProtocol,
@Nullable byte[] pinUvAuthParam
) throws IOException, CommandException {
if (!isCredentialManagerSupported()) {
throw new IllegalStateException("Authenticator does not support credential manager");
if (credentialManagerCommand == null) {
throw new IllegalStateException("Credential manager not supported");
}
return sendCbor(
credentialManagerSupport.command,
credentialManagerCommand,
args(
subCommand,
subCommandParams,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,10 @@ public void testClientPinManagement() throws Throwable {
public void testClientCredentialManagement() throws Throwable {
withCtap2Session(
"Credential management or PIN/UV Auth protocol not supported",
(device, session) -> session.isCredentialManagerSupported() &&
supportsPinUvAuthProtocol(session, pinUvAuthProtocol),
(device, session) ->
Ctap2CredentialManagementInstrumentedTests
.isCredentialManagementSupported(session) &&
supportsPinUvAuthProtocol(session, pinUvAuthProtocol),
BasicWebAuthnClientTests::testClientCredentialManagement,
pinUvAuthProtocol);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static boolean supportsPinUvAuthProtocol(
int pinUvAuthProtocolVersion) {
final List<Integer> pinUvAuthProtocols =
session.getCachedInfo().getPinUvAuthProtocols();
return pinUvAuthProtocols != null && pinUvAuthProtocols.contains(pinUvAuthProtocolVersion);
return pinUvAuthProtocols.contains(pinUvAuthProtocolVersion);
}

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

import androidx.test.filters.LargeTest;

import com.yubico.yubikit.fido.ctap.CredentialManagement;
import com.yubico.yubikit.fido.ctap.Ctap2Session;
import com.yubico.yubikit.fido.ctap.PinUvAuthProtocol;
import com.yubico.yubikit.fido.ctap.PinUvAuthProtocolV1;
import com.yubico.yubikit.fido.ctap.PinUvAuthProtocolV2;
Expand All @@ -35,6 +37,13 @@

@RunWith(Enclosed.class)
public class Ctap2CredentialManagementInstrumentedTests {

static boolean isCredentialManagementSupported(Ctap2Session session) {
final Ctap2Session.InfoData info = session.getCachedInfo();
return CredentialManagement.Support.fromInfo(info) !=
CredentialManagement.Support.NONE;
}

@LargeTest
@RunWith(Parameterized.class)
public static class ParametrizedCtap2CredentialManagementTests extends FidoInstrumentedTests {
Expand All @@ -53,7 +62,7 @@ public static Collection<PinUvAuthProtocol> data() {
public void testReadMetadata() throws Throwable {
withCtap2Session(
"Credential management or PIN/UV Auth protocol not supported",
(device, session) -> session.isCredentialManagerSupported() &&
(device, session) -> isCredentialManagementSupported(session) &&
supportsPinUvAuthProtocol(session, pinUvAuthProtocol),
Ctap2CredentialManagementTests::testReadMetadata,
pinUvAuthProtocol);
Expand All @@ -63,7 +72,7 @@ public void testReadMetadata() throws Throwable {
public void testManagement() throws Throwable {
withCtap2Session(
"Credential management or PIN/UV Auth protocol not supported",
(device, session) -> session.isCredentialManagerSupported() &&
(device, session) -> isCredentialManagementSupported(session) &&
supportsPinUvAuthProtocol(session, pinUvAuthProtocol),
Ctap2CredentialManagementTests::testManagement,
pinUvAuthProtocol);
Expand Down

0 comments on commit 98c3614

Please sign in to comment.