@@ -62,23 +62,35 @@ public class Ctap2Session extends ApplicationSession<Ctap2Session> {
62
62
63
63
private static final byte NFCCTAP_MSG = 0x10 ;
64
64
65
- public static final byte CMD_MAKE_CREDENTIAL = 0x01 ;
66
- public static final byte CMD_GET_ASSERTION = 0x02 ;
67
- public static final byte CMD_GET_INFO = 0x04 ;
68
- public static final byte CMD_CLIENT_PIN = 0x06 ;
69
- public static final byte CMD_RESET = 0x07 ;
70
- public static final byte CMD_GET_NEXT_ASSERTION = 0x08 ;
71
- public static final byte CMD_BIO_ENROLLMENT = 0x09 ;
72
- public static final byte CMD_CREDENTIAL_MANAGEMENT = 0x0A ;
73
- public static final byte CMD_SELECTION = 0x0B ;
74
- public static final byte CMD_LARGE_BLOBS = 0x0C ;
75
- public static final byte CMD_CONFIG = 0x0D ;
76
- public static final byte CMD_BIO_ENROLLMENT_PRE = 0x40 ;
77
- public static final byte CMD_CREDENTIAL_MANAGEMENT_PRE = 0x41 ;
65
+ private static final byte CMD_MAKE_CREDENTIAL = 0x01 ;
66
+ private static final byte CMD_GET_ASSERTION = 0x02 ;
67
+ private static final byte CMD_GET_INFO = 0x04 ;
68
+ private static final byte CMD_CLIENT_PIN = 0x06 ;
69
+ private static final byte CMD_RESET = 0x07 ;
70
+ private static final byte CMD_GET_NEXT_ASSERTION = 0x08 ;
71
+ private static final byte CMD_BIO_ENROLLMENT = 0x09 ;
72
+ private static final byte CMD_CREDENTIAL_MANAGEMENT = 0x0A ;
73
+ private static final byte CMD_SELECTION = 0x0B ;
74
+ private static final byte CMD_LARGE_BLOBS = 0x0C ;
75
+ private static final byte CMD_CONFIG = 0x0D ;
76
+ private static final byte CMD_BIO_ENROLLMENT_PRE = 0x40 ;
77
+ private static final byte CMD_CREDENTIAL_MANAGEMENT_PRE = 0x41 ;
78
+
79
+ private enum CredentialManagerSupport {
80
+ NONE ((byte ) 0x00 ),
81
+ PREVIEW (CMD_CREDENTIAL_MANAGEMENT_PRE ),
82
+ FULL (CMD_CREDENTIAL_MANAGEMENT );
83
+
84
+ final byte command ;
85
+ CredentialManagerSupport (byte command ) {
86
+ this .command = command ;
87
+ }
88
+ }
78
89
79
90
private final Version version ;
80
91
private final Backend <?> backend ;
81
92
private final InfoData info ;
93
+ private final CredentialManagerSupport credentialManagerSupport ;
82
94
83
95
private static final org .slf4j .Logger logger = LoggerFactory .getLogger (Ctap2Session .class );
84
96
@@ -99,36 +111,47 @@ public static void create(YubiKeyDevice device, Callback<Result<Ctap2Session, Ex
99
111
}
100
112
101
113
public Ctap2Session (SmartCardConnection connection )
102
- throws IOException , ApplicationNotAvailableException , CommandException {
103
- SmartCardProtocol protocol = new SmartCardProtocol (connection );
114
+ throws IOException , CommandException {
115
+ this (new Version (0 , 0 , 0 ), getSmartCardBackend (connection ));
116
+ Logger .debug (logger , "Ctap2Session session initialized for connection={}" ,
117
+ connection .getClass ().getSimpleName ());
118
+ }
119
+
120
+ public Ctap2Session (FidoConnection connection ) throws IOException , CommandException {
121
+ this (new FidoProtocol (connection ));
122
+ Logger .debug (logger , "Ctap2Session session initialized for connection={}, version={}" ,
123
+ connection .getClass ().getSimpleName (),
124
+ version );
125
+ }
126
+
127
+ private Ctap2Session (Version version , Backend <?> backend )
128
+ throws IOException , CommandException {
129
+ this .version = version ;
130
+ this .backend = backend ;
131
+ this .info = getInfo ();
132
+ this .credentialManagerSupport = getCredentialManagementSupport (info );
133
+ }
134
+
135
+ private static Backend <SmartCardProtocol > getSmartCardBackend (SmartCardConnection connection )
136
+ throws IOException , ApplicationNotAvailableException {
137
+ final SmartCardProtocol protocol = new SmartCardProtocol (connection );
104
138
protocol .select (AppId .FIDO );
105
- // it is not possible to get the applet version over NFC/CCID
106
- version = new Version (0 , 0 , 0 );
107
- backend = new Backend <SmartCardProtocol >(protocol ) {
108
- @ Override
109
- byte [] sendCbor (byte [] data , @ Nullable CommandState state ) throws IOException , CommandException {
139
+ return new Backend <SmartCardProtocol >(protocol ) {
140
+ byte [] sendCbor (byte [] data , @ Nullable CommandState state )
141
+ throws IOException , CommandException {
110
142
//Cancellation is not implemented for NFC, and most likely not needed.
111
143
return delegate .sendAndReceive (new Apdu (0x80 , NFCCTAP_MSG , 0x00 , 0x00 , data ));
112
144
}
113
145
};
114
- info = getInfo ();
115
- Logger .debug (logger , "Ctap2Session session initialized for connection={}" ,
116
- connection .getClass ().getSimpleName ());
117
146
}
118
147
119
- public Ctap2Session (FidoConnection connection ) throws IOException , CommandException {
120
- FidoProtocol protocol = new FidoProtocol (connection );
121
- version = protocol .getVersion ();
122
- backend = new Backend <FidoProtocol >(protocol ) {
148
+ private Ctap2Session (FidoProtocol protocol ) throws IOException , CommandException {
149
+ this (protocol .getVersion (), new Backend <FidoProtocol >(protocol ) {
123
150
@ Override
124
151
byte [] sendCbor (byte [] data , @ Nullable CommandState state ) throws IOException {
125
152
return delegate .sendAndReceive (FidoProtocol .CTAPHID_CBOR , data , state );
126
153
}
127
- };
128
- info = getInfo ();
129
- Logger .debug (logger , "Ctap2Session session initialized for connection={}, version={}" ,
130
- connection .getClass ().getSimpleName (),
131
- version );
154
+ });
132
155
}
133
156
134
157
/**
@@ -172,6 +195,29 @@ byte[] sendCbor(byte[] data, @Nullable CommandState state) throws IOException {
172
195
}
173
196
}
174
197
198
+ private CredentialManagerSupport getCredentialManagementSupport (InfoData info ) {
199
+ final Map <String , ?> options = info .getOptions ();
200
+ if (Boolean .TRUE .equals (options .get ("credMgmt" ))) {
201
+ return CredentialManagerSupport .FULL ;
202
+ } else if (info .getVersions ().contains ("FIDO_2_1_PRE" ) &&
203
+ Boolean .TRUE .equals (options .get ("credentialMgmtPreview" ))) {
204
+ return CredentialManagerSupport .PREVIEW ;
205
+ }
206
+
207
+ return CredentialManagerSupport .NONE ;
208
+ }
209
+
210
+ /**
211
+ * Get information about authenticator support of credential manager commands.
212
+ * @return true if the authenticator supports credential manager or credential manager preview
213
+ * commands are supported.
214
+ * @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>
215
+ * @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>
216
+ */
217
+ public boolean isCredentialManagerSupported () {
218
+ return credentialManagerSupport != CredentialManagerSupport .NONE ;
219
+ }
220
+
175
221
/**
176
222
* This method is invoked by the host to request generation of a new credential in the
177
223
* authenticator.
@@ -368,7 +414,6 @@ public void reset(@Nullable CommandState state) throws IOException, CommandExcep
368
414
* This command is used by the platform to manage discoverable credentials on the
369
415
* authenticator.
370
416
*
371
- * @param command either CMD_CREDENTIAL_MANAGEMENT or CMD_CREDENTIAL_MANAGEMENT_PRE
372
417
* @param subCommand the subCommand currently being requested
373
418
* @param subCommandParams a map of subCommands parameters
374
419
* @param pinUvAuthProtocol PIN/UV protocol version chosen by the platform
@@ -378,17 +423,22 @@ public void reset(@Nullable CommandState state) throws IOException, CommandExcep
378
423
* @see <a href="https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#authenticatorCredentialManagement">authenticatorCredentialManagement</a>
379
424
*/
380
425
Map <Integer , ?> credentialManagement (
381
- byte command ,
382
426
int subCommand ,
383
427
@ Nullable Map <?, ?> subCommandParams ,
384
428
@ Nullable Integer pinUvAuthProtocol ,
385
429
@ Nullable byte [] pinUvAuthParam
386
430
) throws IOException , CommandException {
387
- return sendCbor (command , args (
388
- subCommand ,
389
- subCommandParams ,
390
- pinUvAuthProtocol ,
391
- pinUvAuthParam ), null );
431
+ if (!isCredentialManagerSupported ()) {
432
+ throw new IllegalStateException ("Authenticator does not support credential manager" );
433
+ }
434
+ return sendCbor (
435
+ credentialManagerSupport .command ,
436
+ args (
437
+ subCommand ,
438
+ subCommandParams ,
439
+ pinUvAuthProtocol ,
440
+ pinUvAuthParam ),
441
+ null );
392
442
}
393
443
394
444
/**
@@ -669,7 +719,7 @@ public List<Integer> getPinUvAuthProtocols() {
669
719
}
670
720
671
721
/**
672
- * Get the aximum number of credentials supported in credentialID list
722
+ * Get the maximum number of credentials supported in credentialID list
673
723
* at a time by the authenticator.
674
724
*
675
725
* @return maximum number of credentials
0 commit comments