1 | package com.yubico.webauthn.data; | |
2 | ||
3 | import com.fasterxml.jackson.annotation.JsonCreator; | |
4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | |
5 | import com.fasterxml.jackson.annotation.JsonProperty; | |
6 | import com.fasterxml.jackson.annotation.JsonValue; | |
7 | import com.upokecenter.cbor.CBORObject; | |
8 | import com.upokecenter.cbor.CBORType; | |
9 | import com.yubico.webauthn.AssertionResult; | |
10 | import com.yubico.webauthn.AssertionResultV2; | |
11 | import com.yubico.webauthn.RegistrationResult; | |
12 | import com.yubico.webauthn.StartRegistrationOptions; | |
13 | import com.yubico.webauthn.extension.uvm.KeyProtectionType; | |
14 | import com.yubico.webauthn.extension.uvm.MatcherProtectionType; | |
15 | import com.yubico.webauthn.extension.uvm.UserVerificationMethod; | |
16 | import java.util.List; | |
17 | import java.util.Optional; | |
18 | import java.util.Set; | |
19 | import java.util.stream.Collectors; | |
20 | import java.util.stream.Stream; | |
21 | import lombok.Builder; | |
22 | import lombok.NonNull; | |
23 | import lombok.Value; | |
24 | import lombok.experimental.UtilityClass; | |
25 | import lombok.extern.slf4j.Slf4j; | |
26 | ||
27 | /** Definitions for WebAuthn extensions. */ | |
28 | @Slf4j | |
29 | @UtilityClass | |
30 | public class Extensions { | |
31 | ||
32 | /** | |
33 | * Definitions for the FIDO AppID Extension (<code>appid</code>). | |
34 | * | |
35 | * @see <a href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-appid-extension">§10.1. | |
36 | * FIDO AppID Extension (appid)</a> | |
37 | */ | |
38 | public static class Appid { | |
39 | static final String EXTENSION_ID = "appid"; | |
40 | } | |
41 | ||
42 | /** | |
43 | * Definitions for the 10.2. FIDO AppID Exclusion Extension (<code>appidExclude</code>). | |
44 | * | |
45 | * @see <a | |
46 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-appid-exclude-extension">10.2. | |
47 | * FIDO AppID Exclusion Extension (appidExclude)</a> | |
48 | */ | |
49 | public static class AppidExclude { | |
50 | static final String EXTENSION_ID = "appidExclude"; | |
51 | } | |
52 | ||
53 | /** | |
54 | * Definitions for the Credential Properties Extension (<code>credProps</code>). | |
55 | * | |
56 | * @see <a | |
57 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-authenticator-credential-properties-extension">§10.4. | |
58 | * Credential Properties Extension (credProps)</a> | |
59 | */ | |
60 | public static class CredentialProperties { | |
61 | static final String EXTENSION_ID = "credProps"; | |
62 | ||
63 | /** | |
64 | * Extension outputs for the Credential Properties Extension (<code>credProps</code>). | |
65 | * | |
66 | * @see <a | |
67 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-authenticator-credential-properties-extension">§10.4. | |
68 | * Credential Properties Extension (credProps)</a> | |
69 | */ | |
70 | @Value | |
71 | @Builder | |
72 | @JsonIgnoreProperties(ignoreUnknown = true) | |
73 | public static class CredentialPropertiesOutput { | |
74 | @JsonProperty("rk") | |
75 | private final Boolean rk; | |
76 | ||
77 | @JsonProperty("authenticatorDisplayName") | |
78 | private final String authenticatorDisplayName; | |
79 | ||
80 | @JsonCreator | |
81 | private CredentialPropertiesOutput( | |
82 | @JsonProperty("rk") Boolean rk, | |
83 | @JsonProperty("authenticatorDisplayName") String authenticatorDisplayName) { | |
84 | this.rk = rk; | |
85 | this.authenticatorDisplayName = authenticatorDisplayName; | |
86 | } | |
87 | ||
88 | /** | |
89 | * This OPTIONAL property, known abstractly as the <b>resident key credential property</b> | |
90 | * (i.e., <b>client-side discoverable credential property</b>), is a Boolean value indicating | |
91 | * whether the {@link PublicKeyCredential} returned as a result of a registration ceremony is | |
92 | * a <i>client-side discoverable credential</i> (passkey). | |
93 | * | |
94 | * <p>If this is <code>true</code>, the credential is a <i>discoverable credential</i> | |
95 | * (passkey). | |
96 | * | |
97 | * <p>If this is <code>false</code>, the credential is a <i>server-side credential</i>. | |
98 | * | |
99 | * <p>If this is not present, it is not known whether the credential is a discoverable | |
100 | * credential or a server-side credential. | |
101 | * | |
102 | * @see <a | |
103 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dom-credentialpropertiesoutput-rk">§10.4. | |
104 | * Credential Properties Extension (credProps)</a> | |
105 | * @see <a | |
106 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#client-side-discoverable-credential">Client-side | |
107 | * discoverable Credential</a> | |
108 | * @see <a | |
109 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#server-side-credential">Server-side | |
110 | * Credential</a> | |
111 | * @see <a href="https://passkeys.dev/docs/reference/terms/#passkey">Passkey</a> in <a | |
112 | * href="https://passkeys.dev">passkeys.dev</a> reference | |
113 | */ | |
114 | public Optional<Boolean> getRk() { | |
115 |
1
1. getRk : replaced return value with Optional.empty for com/yubico/webauthn/data/Extensions$CredentialProperties$CredentialPropertiesOutput::getRk → KILLED |
return Optional.ofNullable(rk); |
116 | } | |
117 | ||
118 | /** | |
119 | * This OPTIONAL property is a human-palatable description of the credential's managing | |
120 | * authenticator, chosen by the user. | |
121 | * | |
122 | * <p>If the application supports setting "nicknames" for registered credentials, then this | |
123 | * value may be a suitable default value for such a nickname. | |
124 | * | |
125 | * <p>In an authentication ceremony, if this value is different from the stored nickname, then | |
126 | * the application may want to offer the user to update the stored nickname to match this | |
127 | * value. | |
128 | * | |
129 | * @return A user-chosen or vendor-default display name for the credential, if available. | |
130 | * Otherwise empty. | |
131 | * @see <a | |
132 | * href="https://w3c.github.io/webauthn/#dom-credentialpropertiesoutput-authenticatordisplayname"> | |
133 | * <code>authenticatorDisplayName</code> in §10.1.3. Credential Properties Extension | |
134 | * (credProps)</a> | |
135 | * @see RegistrationResult#getAuthenticatorDisplayName() | |
136 | * @see AssertionResult#getAuthenticatorDisplayName() | |
137 | * @see AssertionResultV2#getAuthenticatorDisplayName() | |
138 | * @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change | |
139 | * as the standard matures. | |
140 | */ | |
141 | @Deprecated | |
142 | public Optional<String> getAuthenticatorDisplayName() { | |
143 |
1
1. getAuthenticatorDisplayName : replaced return value with Optional.empty for com/yubico/webauthn/data/Extensions$CredentialProperties$CredentialPropertiesOutput::getAuthenticatorDisplayName → KILLED |
return Optional.ofNullable(authenticatorDisplayName); |
144 | } | |
145 | } | |
146 | } | |
147 | ||
148 | /** | |
149 | * Definitions for the Large blob storage extension (<code>largeBlob</code>). | |
150 | * | |
151 | * @see <a | |
152 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-large-blob-extension">§10.5. | |
153 | * Large blob storage extension (largeBlob)</a> | |
154 | */ | |
155 | public static class LargeBlob { | |
156 | static final String EXTENSION_ID = "largeBlob"; | |
157 | ||
158 | /** | |
159 | * Extension inputs for the Large blob storage extension (<code>largeBlob</code>) in | |
160 | * registration ceremonies. | |
161 | * | |
162 | * @see <a | |
163 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-large-blob-extension">§10.5. | |
164 | * Large blob storage extension (largeBlob)</a> | |
165 | */ | |
166 | @Value | |
167 | public static class LargeBlobRegistrationInput { | |
168 | /** | |
169 | * The Relying Party's preference of whether the created credential should support the <code> | |
170 | * largeBlob</code> extension. | |
171 | */ | |
172 | @JsonProperty private final LargeBlobSupport support; | |
173 | ||
174 | @JsonCreator | |
175 | public LargeBlobRegistrationInput( | |
176 | /** | |
177 | * The Relying Party's preference of whether the created credential should support the | |
178 | * <code> | |
179 | * largeBlob</code> extension. | |
180 | * | |
181 | * <p>Currently the only valid values are {@link LargeBlobSupport#REQUIRED} and {@link | |
182 | * LargeBlobSupport#PREFERRED}, but custom values MAY be constructed in case more values | |
183 | * are added in future revisions of the extension. | |
184 | */ | |
185 | @JsonProperty("support") LargeBlobSupport support) { | |
186 | this.support = support; | |
187 | } | |
188 | ||
189 | /** | |
190 | * The known valid arguments for the Large blob storage extension (<code>largeBlob</code>) | |
191 | * input in registration ceremonies. | |
192 | * | |
193 | * <p>Currently the only valid values are {@link LargeBlobSupport#REQUIRED} and {@link | |
194 | * LargeBlobSupport#PREFERRED}, but custom values MAY be constructed in case more values are | |
195 | * added in future revisions of the extension. | |
196 | * | |
197 | * @see #REQUIRED | |
198 | * @see #PREFERRED | |
199 | * @see <a | |
200 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-large-blob-extension">§10.5. | |
201 | * Large blob storage extension (largeBlob)</a> | |
202 | */ | |
203 | @Value | |
204 | public static class LargeBlobSupport { | |
205 | /** | |
206 | * The authenticator used for registration MUST support the <code>largeBlob</code> | |
207 | * extension. | |
208 | * | |
209 | * <p>Note: If the client does not support the <code>largeBlob</code> extension, this | |
210 | * requirement MAY be ignored. | |
211 | * | |
212 | * <p>Note: CTAP authenticators only support <code>largeBlob</code> in combination with | |
213 | * {@link AuthenticatorSelectionCriteria#getResidentKey()} set to <code>REQUIRED</code> in | |
214 | * {@link StartRegistrationOptions#getAuthenticatorSelection()}. | |
215 | * | |
216 | * @see <a | |
217 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-large-blob-extension">§10.5. | |
218 | * Large blob storage extension (largeBlob)</a> | |
219 | */ | |
220 | public static final LargeBlobSupport REQUIRED = new LargeBlobSupport("required"); | |
221 | ||
222 | /** | |
223 | * If the authenticator used for registration supports the <code>largeBlob</code> extension, | |
224 | * it will be enabled for the created credential. If not supported, the credential will be | |
225 | * created without large blob support. | |
226 | * | |
227 | * <p>Note: CTAP authenticators only support <code>largeBlob</code> in combination with | |
228 | * {@link AuthenticatorSelectionCriteria#getResidentKey()} set to <code>REQUIRED</code> in | |
229 | * {@link StartRegistrationOptions#getAuthenticatorSelection()}. | |
230 | * | |
231 | * @see <a | |
232 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-large-blob-extension">§10.5. | |
233 | * Large blob storage extension (largeBlob)</a> | |
234 | */ | |
235 | public static final LargeBlobSupport PREFERRED = new LargeBlobSupport("preferred"); | |
236 | ||
237 | /** | |
238 | * The underlying string value of this {@link LargeBlobSupport} value. | |
239 | * | |
240 | * @see #REQUIRED | |
241 | * @see #PREFERRED | |
242 | */ | |
243 | @JsonValue private final String value; | |
244 | ||
245 | /** | |
246 | * Returns a new {@link Set} containing the {@link #REQUIRED} and {@link #PREFERRED} values. | |
247 | */ | |
248 | public static Set<LargeBlobSupport> values() { | |
249 |
1
1. values : replaced return value with Collections.emptySet for com/yubico/webauthn/data/Extensions$LargeBlob$LargeBlobRegistrationInput$LargeBlobSupport::values → KILLED |
return Stream.of(REQUIRED, PREFERRED).collect(Collectors.toSet()); |
250 | } | |
251 | } | |
252 | } | |
253 | ||
254 | /** | |
255 | * Extension inputs for the Large blob storage extension (<code>largeBlob</code>) in | |
256 | * authentication ceremonies. | |
257 | * | |
258 | * <p>Use the {@link #read()} and {@link #write(ByteArray)} factory functions to construct this | |
259 | * type. | |
260 | * | |
261 | * @see <a | |
262 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-large-blob-extension">§10.5. | |
263 | * Large blob storage extension (largeBlob)</a> | |
264 | */ | |
265 | @Value | |
266 | public static class LargeBlobAuthenticationInput { | |
267 | /** | |
268 | * If <code>true</code>, indicates that the Relying Party would like to fetch the | |
269 | * previously-written blob associated with the asserted credential. | |
270 | * | |
271 | * @see #read() | |
272 | * @see <a | |
273 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dom-authenticationextensionslargeblobinputs-read">§10.5. | |
274 | * Large blob storage extension (largeBlob)</a> | |
275 | */ | |
276 | @JsonProperty private final boolean read; | |
277 | ||
278 | /** | |
279 | * An opaque byte string that the Relying Party wishes to store with the existing credential. | |
280 | * | |
281 | * @see #write(ByteArray) | |
282 | * @see <a | |
283 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dom-authenticationextensionslargeblobinputs-write">§10.5. | |
284 | * Large blob storage extension (largeBlob)</a> | |
285 | */ | |
286 | @JsonProperty private final ByteArray write; | |
287 | ||
288 | @JsonCreator | |
289 | private LargeBlobAuthenticationInput( | |
290 | @JsonProperty("read") final Boolean read, @JsonProperty("write") final ByteArray write) { | |
291 |
3
1. <init> : negated conditional → KILLED 2. <init> : negated conditional → KILLED 3. <init> : negated conditional → KILLED |
if (read != null && read && write != null) { |
292 | throw new IllegalArgumentException( | |
293 | "Parameters \"read\" and \"write\" of largeBlob extension must not both be present."); | |
294 | } | |
295 | ||
296 |
2
1. <init> : negated conditional → KILLED 2. <init> : negated conditional → KILLED |
this.read = read != null && read; |
297 | this.write = write; | |
298 | } | |
299 | ||
300 | /** | |
301 | * Configure the Large blob storage extension (<code>largeBlob</code>) to fetch the | |
302 | * previously-written blob associated with the asserted credential. | |
303 | * | |
304 | * <p>Mutually exclusive with {@link #write(ByteArray)}. | |
305 | * | |
306 | * @see <a | |
307 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dom-authenticationextensionslargeblobinputs-read">§10.5. | |
308 | * Large blob storage extension (largeBlob)</a> | |
309 | */ | |
310 | public static LargeBlobAuthenticationInput read() { | |
311 |
1
1. read : replaced return value with null for com/yubico/webauthn/data/Extensions$LargeBlob$LargeBlobAuthenticationInput::read → KILLED |
return new LargeBlobAuthenticationInput(true, null); |
312 | } | |
313 | ||
314 | /** | |
315 | * Configure the Large blob storage extension (<code>largeBlob</code>) to store the given byte | |
316 | * array with the existing credential. | |
317 | * | |
318 | * <p>Mutually exclusive with {@link #read()}. | |
319 | * | |
320 | * @see <a | |
321 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dom-authenticationextensionslargeblobinputs-write">§10.5. | |
322 | * Large blob storage extension (largeBlob)</a> | |
323 | */ | |
324 |
1
1. write : negated conditional → KILLED |
public static LargeBlobAuthenticationInput write(@NonNull final ByteArray write) { |
325 |
1
1. write : replaced return value with null for com/yubico/webauthn/data/Extensions$LargeBlob$LargeBlobAuthenticationInput::write → SURVIVED |
return new LargeBlobAuthenticationInput(false, write); |
326 | } | |
327 | ||
328 | /** | |
329 | * @return <code>true</code> if the <code>read</code> property is set to <code>true</code>, | |
330 | * <code>false</code> otherwise. | |
331 | * @see #read() | |
332 | * @see <a | |
333 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dom-authenticationextensionslargeblobinputs-read">§10.5. | |
334 | * Large blob storage extension (largeBlob)</a> | |
335 | */ | |
336 | public boolean getRead() { | |
337 |
2
1. getRead : replaced boolean return with true for com/yubico/webauthn/data/Extensions$LargeBlob$LargeBlobAuthenticationInput::getRead → KILLED 2. getRead : replaced boolean return with false for com/yubico/webauthn/data/Extensions$LargeBlob$LargeBlobAuthenticationInput::getRead → KILLED |
return read; |
338 | } | |
339 | ||
340 | /** | |
341 | * @return The value of the <code>write</code> property if configured, empty otherwise. | |
342 | * @see #write(ByteArray) | |
343 | * @see <a | |
344 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dom-authenticationextensionslargeblobinputs-read">§10.5. | |
345 | * Large blob storage extension (largeBlob)</a> | |
346 | */ | |
347 | public Optional<ByteArray> getWrite() { | |
348 |
1
1. getWrite : replaced return value with Optional.empty for com/yubico/webauthn/data/Extensions$LargeBlob$LargeBlobAuthenticationInput::getWrite → SURVIVED |
return Optional.ofNullable(write); |
349 | } | |
350 | } | |
351 | ||
352 | /** | |
353 | * Extension outputs for the Large blob storage extension (<code>largeBlob</code>) in | |
354 | * registration ceremonies. | |
355 | * | |
356 | * <p>Use the {@link #supported(boolean)} factory function to construct this type. | |
357 | * | |
358 | * @see <a | |
359 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-large-blob-extension">§10.5. | |
360 | * Large blob storage extension (largeBlob)</a> | |
361 | */ | |
362 | @Value | |
363 | public static class LargeBlobRegistrationOutput { | |
364 | /** | |
365 | * <code>true</code> if, and only if, the created credential supports storing large blobs. | |
366 | * | |
367 | * @see <a | |
368 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dom-authenticationextensionslargebloboutputs-supported">§10.5. | |
369 | * Large blob storage extension (largeBlob)</a> | |
370 | * @see LargeBlobRegistrationInput#getSupport() | |
371 | */ | |
372 | @JsonProperty private final boolean supported; | |
373 | ||
374 | @JsonCreator | |
375 | private LargeBlobRegistrationOutput(@JsonProperty("supported") boolean supported) { | |
376 | this.supported = supported; | |
377 | } | |
378 | ||
379 | /** | |
380 | * Create a Large blob storage extension output with the <code>supported</code> output set to | |
381 | * the given value. | |
382 | * | |
383 | * @see <a | |
384 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dictdef-authenticationextensionslargebloboutputs"> | |
385 | * dictionary AuthenticationExtensionsLargeBlobOutputs</a> | |
386 | */ | |
387 | public static LargeBlobRegistrationOutput supported(boolean supported) { | |
388 |
1
1. supported : replaced return value with null for com/yubico/webauthn/data/Extensions$LargeBlob$LargeBlobRegistrationOutput::supported → KILLED |
return new LargeBlobRegistrationOutput(supported); |
389 | } | |
390 | } | |
391 | ||
392 | /** | |
393 | * Extension outputs for the Large blob storage extension (<code>largeBlob</code>) in | |
394 | * authentication ceremonies. | |
395 | * | |
396 | * @see <a | |
397 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-large-blob-extension">§10.5. | |
398 | * Large blob storage extension (largeBlob)</a> | |
399 | */ | |
400 | @Value | |
401 | public static class LargeBlobAuthenticationOutput { | |
402 | @JsonProperty private final ByteArray blob; | |
403 | @JsonProperty private final Boolean written; | |
404 | ||
405 | @JsonCreator | |
406 | private LargeBlobAuthenticationOutput( | |
407 | @JsonProperty("blob") ByteArray blob, @JsonProperty("written") Boolean written) { | |
408 | this.blob = blob; | |
409 | this.written = written; | |
410 | } | |
411 | ||
412 | /** | |
413 | * Create a Large blob storage extension output with the <code>blob</code> output set to the | |
414 | * given value. | |
415 | * | |
416 | * <p>This corresponds to the extension input {@link LargeBlobAuthenticationInput#read() | |
417 | * LargeBlobAuthenticationInput.read()}. | |
418 | * | |
419 | * @see <a | |
420 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dictdef-authenticationextensionslargebloboutputs"> | |
421 | * dictionary AuthenticationExtensionsLargeBlobOutputs</a> | |
422 | */ | |
423 | public static LargeBlobAuthenticationOutput read(final ByteArray blob) { | |
424 |
1
1. read : replaced return value with null for com/yubico/webauthn/data/Extensions$LargeBlob$LargeBlobAuthenticationOutput::read → KILLED |
return new LargeBlobAuthenticationOutput(blob, null); |
425 | } | |
426 | ||
427 | /** | |
428 | * Create a Large blob storage extension output with the <code>written</code> output set to | |
429 | * the given value. | |
430 | * | |
431 | * <p>This corresponds to the extension input {@link | |
432 | * LargeBlobAuthenticationInput#write(ByteArray) | |
433 | * LargeBlobAuthenticationInput.write(ByteArray)}. | |
434 | * | |
435 | * @see <a | |
436 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dictdef-authenticationextensionslargebloboutputs"> | |
437 | * dictionary AuthenticationExtensionsLargeBlobOutputs</a> | |
438 | */ | |
439 | public static LargeBlobAuthenticationOutput write(final boolean write) { | |
440 |
1
1. write : replaced return value with null for com/yubico/webauthn/data/Extensions$LargeBlob$LargeBlobAuthenticationOutput::write → KILLED |
return new LargeBlobAuthenticationOutput(null, write); |
441 | } | |
442 | ||
443 | /** | |
444 | * The opaque byte string that was associated with the credential identified by {@link | |
445 | * PublicKeyCredential#getId()}. Only valid if {@link LargeBlobAuthenticationInput#getRead()} | |
446 | * was <code>true</code>. | |
447 | * | |
448 | * @return A present {@link Optional} if {@link LargeBlobAuthenticationInput#getRead()} was | |
449 | * <code>true</code> and the blob content was successfully read. Otherwise (if {@link | |
450 | * LargeBlobAuthenticationInput#getRead()} was <code>false</code> or the content failed to | |
451 | * be read) an empty {@link Optional}. | |
452 | * @see <a | |
453 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dom-authenticationextensionslargebloboutputs-blob">§10.5. | |
454 | * Large blob storage extension (largeBlob)</a> | |
455 | */ | |
456 | public Optional<ByteArray> getBlob() { | |
457 |
1
1. getBlob : replaced return value with Optional.empty for com/yubico/webauthn/data/Extensions$LargeBlob$LargeBlobAuthenticationOutput::getBlob → KILLED |
return Optional.ofNullable(blob); |
458 | } | |
459 | ||
460 | /** | |
461 | * A boolean that indicates that the contents of {@link | |
462 | * LargeBlob.LargeBlobAuthenticationInput#write(ByteArray) | |
463 | * LargeBlobAuthenticationInput#write(ByteArray)} were successfully stored on the | |
464 | * authenticator, associated with the specified credential. | |
465 | * | |
466 | * @return Empty if {@link LargeBlobAuthenticationInput#getWrite()} was not present. Otherwise | |
467 | * <code>true</code> if and only if the value of {@link | |
468 | * LargeBlobAuthenticationInput#getWrite()} was successfully stored by the authenticator. | |
469 | * @see <a | |
470 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#dom-authenticationextensionslargebloboutputs-written">§10.5. | |
471 | * Large blob storage extension (largeBlob)</a> | |
472 | */ | |
473 | public Optional<Boolean> getWritten() { | |
474 |
1
1. getWritten : replaced return value with Optional.empty for com/yubico/webauthn/data/Extensions$LargeBlob$LargeBlobAuthenticationOutput::getWritten → KILLED |
return Optional.ofNullable(written); |
475 | } | |
476 | } | |
477 | } | |
478 | ||
479 | /** | |
480 | * Definitions for the User Verification Method (<code>uvm</code>) Extension. | |
481 | * | |
482 | * @see <a href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-uvm-extension">§10.3. | |
483 | * User Verification Method Extension (uvm)</a> | |
484 | */ | |
485 | public static class Uvm { | |
486 | static final String EXTENSION_ID = "uvm"; | |
487 | ||
488 | /** | |
489 | * A <code>uvmEntry</code> as defined in <a | |
490 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-uvm-extension">§10.3. User | |
491 | * Verification Method Extension (uvm)</a>. | |
492 | * | |
493 | * @see <a href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-uvm-extension">§10.3. | |
494 | * User Verification Method Extension (uvm)</a> | |
495 | * @see UserVerificationMethod | |
496 | * @see KeyProtectionType | |
497 | * @see MatcherProtectionType | |
498 | */ | |
499 | @Value | |
500 | public static class UvmEntry { | |
501 | private final UserVerificationMethod userVerificationMethod; | |
502 | private final KeyProtectionType keyProtectionType; | |
503 | private final MatcherProtectionType matcherProtectionType; | |
504 | ||
505 | public UvmEntry( | |
506 | @JsonProperty("userVerificationMethod") UserVerificationMethod userVerificationMethod, | |
507 | @JsonProperty("keyProtectionType") KeyProtectionType keyProtectionType, | |
508 | @JsonProperty("matcherProtectionType") MatcherProtectionType matcherProtectionType) { | |
509 | this.userVerificationMethod = userVerificationMethod; | |
510 | this.keyProtectionType = keyProtectionType; | |
511 | this.matcherProtectionType = matcherProtectionType; | |
512 | } | |
513 | } | |
514 | ||
515 | static Optional<List<UvmEntry>> parseAuthenticatorExtensionOutput(CBORObject cbor) { | |
516 |
1
1. parseAuthenticatorExtensionOutput : negated conditional → KILLED |
if (validateAuthenticatorExtensionOutput(cbor)) { |
517 |
1
1. parseAuthenticatorExtensionOutput : replaced return value with Optional.empty for com/yubico/webauthn/data/Extensions$Uvm::parseAuthenticatorExtensionOutput → KILLED |
return Optional.of( |
518 | cbor.get(EXTENSION_ID).getValues().stream() | |
519 | .map( | |
520 | uvmEntry -> | |
521 |
1
1. lambda$parseAuthenticatorExtensionOutput$0 : replaced return value with null for com/yubico/webauthn/data/Extensions$Uvm::lambda$parseAuthenticatorExtensionOutput$0 → KILLED |
new UvmEntry( |
522 | UserVerificationMethod.fromValue(uvmEntry.get(0).AsInt32Value()), | |
523 | KeyProtectionType.fromValue( | |
524 | uvmEntry.get(1).AsNumber().ToInt16IfExact()), | |
525 | MatcherProtectionType.fromValue( | |
526 | uvmEntry.get(2).AsNumber().ToInt16IfExact()))) | |
527 | .collect(Collectors.toList())); | |
528 | } else { | |
529 | return Optional.empty(); | |
530 | } | |
531 | } | |
532 | ||
533 | private static boolean validateAuthenticatorExtensionOutput(CBORObject extensions) { | |
534 |
1
1. validateAuthenticatorExtensionOutput : negated conditional → KILLED |
if (!extensions.ContainsKey(EXTENSION_ID)) { |
535 |
1
1. validateAuthenticatorExtensionOutput : replaced boolean return with true for com/yubico/webauthn/data/Extensions$Uvm::validateAuthenticatorExtensionOutput → NO_COVERAGE |
return false; |
536 | } | |
537 | ||
538 | CBORObject uvm = extensions.get(EXTENSION_ID); | |
539 |
1
1. validateAuthenticatorExtensionOutput : negated conditional → KILLED |
if (uvm.getType() != CBORType.Array) { |
540 | log.debug( | |
541 | "Invalid CBOR type for \"{}\" extension output: expected array, was: {}", | |
542 | EXTENSION_ID, | |
543 | uvm.getType()); | |
544 |
1
1. validateAuthenticatorExtensionOutput : replaced boolean return with true for com/yubico/webauthn/data/Extensions$Uvm::validateAuthenticatorExtensionOutput → NO_COVERAGE |
return false; |
545 | } | |
546 | ||
547 |
4
1. validateAuthenticatorExtensionOutput : changed conditional boundary → SURVIVED 2. validateAuthenticatorExtensionOutput : changed conditional boundary → SURVIVED 3. validateAuthenticatorExtensionOutput : negated conditional → KILLED 4. validateAuthenticatorExtensionOutput : negated conditional → KILLED |
if (uvm.size() < 1 || uvm.size() > 3) { |
548 | log.debug( | |
549 | "Invalid length \"{}\" extension output array: expected 1 to 3 (inclusive), was: {}", | |
550 | EXTENSION_ID, | |
551 | uvm.size()); | |
552 |
1
1. validateAuthenticatorExtensionOutput : replaced boolean return with true for com/yubico/webauthn/data/Extensions$Uvm::validateAuthenticatorExtensionOutput → NO_COVERAGE |
return false; |
553 | } | |
554 | ||
555 | for (CBORObject entry : uvm.getValues()) { | |
556 |
1
1. validateAuthenticatorExtensionOutput : negated conditional → KILLED |
if (entry.getType() != CBORType.Array) { |
557 | log.debug("Invalid CBOR type for uvmEntry: expected array, was: {}", entry.getType()); | |
558 |
1
1. validateAuthenticatorExtensionOutput : replaced boolean return with true for com/yubico/webauthn/data/Extensions$Uvm::validateAuthenticatorExtensionOutput → NO_COVERAGE |
return false; |
559 | } | |
560 | ||
561 |
1
1. validateAuthenticatorExtensionOutput : negated conditional → KILLED |
if (entry.size() != 3) { |
562 | log.debug("Invalid length for uvmEntry: expected 3, was: {}", entry.size()); | |
563 |
1
1. validateAuthenticatorExtensionOutput : replaced boolean return with true for com/yubico/webauthn/data/Extensions$Uvm::validateAuthenticatorExtensionOutput → NO_COVERAGE |
return false; |
564 | } | |
565 | ||
566 | for (CBORObject i : entry.getValues()) { | |
567 |
2
1. validateAuthenticatorExtensionOutput : negated conditional → KILLED 2. validateAuthenticatorExtensionOutput : negated conditional → KILLED |
if (!(i.isNumber() && i.AsNumber().IsInteger())) { |
568 | log.debug("Invalid type for uvmEntry element: expected integer, was: {}", i.getType()); | |
569 |
1
1. validateAuthenticatorExtensionOutput : replaced boolean return with true for com/yubico/webauthn/data/Extensions$Uvm::validateAuthenticatorExtensionOutput → NO_COVERAGE |
return false; |
570 | } | |
571 | } | |
572 | } | |
573 | ||
574 |
1
1. validateAuthenticatorExtensionOutput : replaced boolean return with false for com/yubico/webauthn/data/Extensions$Uvm::validateAuthenticatorExtensionOutput → KILLED |
return true; |
575 | } | |
576 | } | |
577 | } | |
Mutations | ||
115 |
1.1 |
|
143 |
1.1 |
|
249 |
1.1 |
|
291 |
1.1 2.2 3.3 |
|
296 |
1.1 2.2 |
|
311 |
1.1 |
|
324 |
1.1 |
|
325 |
1.1 |
|
337 |
1.1 2.2 |
|
348 |
1.1 |
|
388 |
1.1 |
|
424 |
1.1 |
|
440 |
1.1 |
|
457 |
1.1 |
|
474 |
1.1 |
|
516 |
1.1 |
|
517 |
1.1 |
|
521 |
1.1 |
|
534 |
1.1 |
|
535 |
1.1 |
|
539 |
1.1 |
|
544 |
1.1 |
|
547 |
1.1 2.2 3.3 4.4 |
|
552 |
1.1 |
|
556 |
1.1 |
|
558 |
1.1 |
|
561 |
1.1 |
|
563 |
1.1 |
|
567 |
1.1 2.2 |
|
569 |
1.1 |
|
574 |
1.1 |