FidoMetadataService.java

1
// Copyright (c) 2015-2021, Yubico AB
2
// All rights reserved.
3
//
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are met:
6
//
7
// 1. Redistributions of source code must retain the above copyright notice, this
8
//    list of conditions and the following disclaimer.
9
//
10
// 2. Redistributions in binary form must reproduce the above copyright notice,
11
//    this list of conditions and the following disclaimer in the documentation
12
//    and/or other materials provided with the distribution.
13
//
14
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25
package com.yubico.fido.metadata;
26
27
import com.yubico.fido.metadata.FidoMetadataService.Filters.AuthenticatorToBeFiltered;
28
import com.yubico.internal.util.CertificateParser;
29
import com.yubico.internal.util.OptionalUtil;
30
import com.yubico.webauthn.RegistrationResult;
31
import com.yubico.webauthn.RelyingParty;
32
import com.yubico.webauthn.RelyingParty.RelyingPartyBuilder;
33
import com.yubico.webauthn.attestation.AttestationTrustSource;
34
import com.yubico.webauthn.data.ByteArray;
35
import com.yubico.webauthn.data.exception.Base64UrlException;
36
import java.io.IOException;
37
import java.security.DigestException;
38
import java.security.InvalidAlgorithmParameterException;
39
import java.security.InvalidKeyException;
40
import java.security.NoSuchAlgorithmException;
41
import java.security.SignatureException;
42
import java.security.cert.CertPathValidatorException;
43
import java.security.cert.CertStore;
44
import java.security.cert.CertificateException;
45
import java.security.cert.X509Certificate;
46
import java.util.Arrays;
47
import java.util.Collection;
48
import java.util.Collections;
49
import java.util.HashMap;
50
import java.util.HashSet;
51
import java.util.List;
52
import java.util.Map;
53
import java.util.Optional;
54
import java.util.Set;
55
import java.util.function.Consumer;
56
import java.util.function.Predicate;
57
import java.util.stream.Collectors;
58
import java.util.stream.Stream;
59
import lombok.AccessLevel;
60
import lombok.AllArgsConstructor;
61
import lombok.NonNull;
62
import lombok.RequiredArgsConstructor;
63
import lombok.Value;
64
import lombok.extern.slf4j.Slf4j;
65
66
/**
67
 * Utility for filtering and querying <a
68
 * href="https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html#metadata-blob-payload-entry-dictionary">Fido
69
 * Metadata Service BLOB entries</a>.
70
 *
71
 * <p>This class implements {@link AttestationTrustSource}, so it can be configured as the {@link
72
 * RelyingPartyBuilder#attestationTrustSource(AttestationTrustSource) attestationTrustSource}
73
 * setting in {@link RelyingParty}. This implementation always sets {@link
74
 * com.yubico.webauthn.attestation.AttestationTrustSource.TrustRootsResult.TrustRootsResultBuilder#enableRevocationChecking(boolean)
75
 * enableRevocationChecking(false)}, because the FIDO MDS has its own revocation procedures and not
76
 * all attestation certificates provide CRLs; and always sets {@link
77
 * com.yubico.webauthn.attestation.AttestationTrustSource.TrustRootsResult.TrustRootsResultBuilder#policyTreeValidator(Predicate)
78
 * policyTreeValidator} to accept any policy tree, because a Windows Hello attestation certificate
79
 * is known to include a critical certificate policies extension.
80
 *
81
 * <p>The metadata service may be configured with two stages of filters to select trusted
82
 * authenticators. The first stage is the {@link FidoMetadataServiceBuilder#prefilter(Predicate)
83
 * prefilter} setting, which is executed once when the {@link FidoMetadataService} instance is
84
 * constructed. The second stage is the {@link FidoMetadataServiceBuilder#filter(Predicate) filter}
85
 * setting, which is executed whenever metadata or trust roots are to be looked up for a given
86
 * authenticator. Any metadata entry that satisfies both filters will be considered trusted.
87
 *
88
 * <p>Use the {@link #builder() builder} to configure settings, then use the {@link
89
 * #findEntries(List, AAGUID)} method or its overloads to retrieve metadata entries.
90
 *
91
 * @since 2.0.0
92
 */
93
@Slf4j
94
public final class FidoMetadataService implements AttestationTrustSource {
95
96
  private final HashMap<String, HashSet<MetadataBLOBPayloadEntry>>
97
      prefilteredEntriesByCertificateKeyIdentifier;
98
  private final HashMap<AAGUID, HashSet<MetadataBLOBPayloadEntry>> prefilteredEntriesByAaguid;
99
  private final HashSet<MetadataBLOBPayloadEntry> prefilteredUnindexedEntries;
100
101
  private final Predicate<AuthenticatorToBeFiltered> filter;
102
  private final CertStore certStore;
103
104
  private FidoMetadataService(
105 1 1. <init> : negated conditional → KILLED
      @NonNull MetadataBLOBPayload blob,
106 1 1. <init> : negated conditional → KILLED
      @NonNull Predicate<MetadataBLOBPayloadEntry> prefilter,
107 1 1. <init> : negated conditional → KILLED
      @NonNull Predicate<AuthenticatorToBeFiltered> filter,
108
      CertStore certStore) {
109
    final List<MetadataBLOBPayloadEntry> prefilteredEntries =
110
        blob.getEntries().stream()
111
            .filter(FidoMetadataService::ignoreInvalidUpdateAvailableAuthenticatorVersion)
112
            .filter(prefilter)
113
            .collect(Collectors.toList());
114
115
    this.prefilteredEntriesByCertificateKeyIdentifier = buildCkiMap(prefilteredEntries);
116
    this.prefilteredEntriesByAaguid = buildAaguidMap(prefilteredEntries);
117
118
    this.prefilteredUnindexedEntries = new HashSet<>(prefilteredEntries);
119
    for (HashSet<MetadataBLOBPayloadEntry> byAaguid : prefilteredEntriesByAaguid.values()) {
120
      prefilteredUnindexedEntries.removeAll(byAaguid);
121
    }
122
    for (HashSet<MetadataBLOBPayloadEntry> byCski :
123
        prefilteredEntriesByCertificateKeyIdentifier.values()) {
124
      prefilteredUnindexedEntries.removeAll(byCski);
125
    }
126
127
    this.filter = filter;
128
    this.certStore = certStore;
129
  }
130
131
  private static boolean ignoreInvalidUpdateAvailableAuthenticatorVersion(
132
      MetadataBLOBPayloadEntry metadataBLOBPayloadEntry) {
133 2 1. ignoreInvalidUpdateAvailableAuthenticatorVersion : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::ignoreInvalidUpdateAvailableAuthenticatorVersion → KILLED
2. ignoreInvalidUpdateAvailableAuthenticatorVersion : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService::ignoreInvalidUpdateAvailableAuthenticatorVersion → KILLED
    return metadataBLOBPayloadEntry
134
        .getMetadataStatement()
135
        .map(MetadataStatement::getAuthenticatorVersion)
136
        .map(
137
            authenticatorVersion ->
138 2 1. lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$3 : replaced Boolean return with True for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$3 → KILLED
2. lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$3 : replaced Boolean return with False for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$3 → KILLED
                metadataBLOBPayloadEntry.getStatusReports().stream()
139
                    .filter(
140
                        statusReport ->
141 2 1. lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$0 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$0 → SURVIVED
2. lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$0 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$0 → KILLED
                            AuthenticatorStatus.UPDATE_AVAILABLE.equals(statusReport.getStatus()))
142
                    .noneMatch(
143
                        statusReport ->
144
                            statusReport
145
                                .getAuthenticatorVersion()
146 3 1. lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$1 : changed conditional boundary → KILLED
2. lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$1 : replaced Boolean return with True for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$1 → KILLED
3. lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$1 : negated conditional → KILLED
                                .map(av -> av > authenticatorVersion)
147 2 1. lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$2 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$2 → KILLED
2. lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$2 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$2 → KILLED
                                .orElse(false)))
148
        .orElse(true);
149
  }
150
151
  private static HashMap<String, HashSet<MetadataBLOBPayloadEntry>> buildCkiMap(
152 1 1. buildCkiMap : negated conditional → KILLED
      @NonNull List<MetadataBLOBPayloadEntry> entries) {
153
154 1 1. buildCkiMap : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::buildCkiMap → KILLED
    return entries.stream()
155
        .collect(
156
            HashMap::new,
157
            (result, metadataBLOBPayloadEntry) -> {
158
              for (String acki :
159
                  metadataBLOBPayloadEntry.getAttestationCertificateKeyIdentifiers()) {
160 1 1. lambda$buildCkiMap$4 : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::lambda$buildCkiMap$4 → KILLED
                result.computeIfAbsent(acki, o -> new HashSet<>()).add(metadataBLOBPayloadEntry);
161
              }
162
              for (String acki :
163
                  metadataBLOBPayloadEntry
164
                      .getMetadataStatement()
165
                      .map(MetadataStatement::getAttestationCertificateKeyIdentifiers)
166
                      .orElseGet(Collections::emptySet)) {
167 1 1. lambda$buildCkiMap$5 : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::lambda$buildCkiMap$5 → KILLED
                result.computeIfAbsent(acki, o -> new HashSet<>()).add(metadataBLOBPayloadEntry);
168
              }
169
            },
170
            (mapA, mapB) -> {
171
              for (Map.Entry<String, HashSet<MetadataBLOBPayloadEntry>> e : mapB.entrySet()) {
172
                mapA.merge(
173
                    e.getKey(),
174
                    e.getValue(),
175
                    (entriesA, entriesB) -> {
176
                      entriesA.addAll(entriesB);
177 1 1. lambda$buildCkiMap$7 : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::lambda$buildCkiMap$7 → NO_COVERAGE
                      return entriesA;
178
                    });
179
              }
180
            });
181
  }
182
183
  private static HashMap<AAGUID, HashSet<MetadataBLOBPayloadEntry>> buildAaguidMap(
184 1 1. buildAaguidMap : negated conditional → KILLED
      @NonNull List<MetadataBLOBPayloadEntry> entries) {
185
186 1 1. buildAaguidMap : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::buildAaguidMap → KILLED
    return entries.stream()
187
        .collect(
188
            HashMap::new,
189
            (result, metadataBLOBPayloadEntry) -> {
190
              final Consumer<AAGUID> appendToAaguidEntry =
191
                  aaguid ->
192
                      result
193 1 1. lambda$buildAaguidMap$9 : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::lambda$buildAaguidMap$9 → KILLED
                          .computeIfAbsent(aaguid, o -> new HashSet<>())
194
                          .add(metadataBLOBPayloadEntry);
195
              metadataBLOBPayloadEntry
196
                  .getAaguid()
197 2 1. lambda$buildAaguidMap$11 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$buildAaguidMap$11 → SURVIVED
2. lambda$buildAaguidMap$11 : negated conditional → KILLED
                  .filter(aaguid -> !aaguid.isZero())
198 1 1. lambda$buildAaguidMap$13 : removed call to java/util/Optional::ifPresent → KILLED
                  .ifPresent(appendToAaguidEntry);
199
              metadataBLOBPayloadEntry
200
                  .getMetadataStatement()
201
                  .flatMap(MetadataStatement::getAaguid)
202 2 1. lambda$buildAaguidMap$12 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$buildAaguidMap$12 → SURVIVED
2. lambda$buildAaguidMap$12 : negated conditional → SURVIVED
                  .filter(aaguid -> !aaguid.isZero())
203 1 1. lambda$buildAaguidMap$13 : removed call to java/util/Optional::ifPresent → SURVIVED
                  .ifPresent(appendToAaguidEntry);
204
            },
205
            (mapA, mapB) -> {
206
              for (Map.Entry<AAGUID, HashSet<MetadataBLOBPayloadEntry>> e : mapB.entrySet()) {
207
                mapA.merge(
208
                    e.getKey(),
209
                    e.getValue(),
210
                    (entriesA, entriesB) -> {
211
                      entriesA.addAll(entriesB);
212 1 1. lambda$buildAaguidMap$14 : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::lambda$buildAaguidMap$14 → NO_COVERAGE
                      return entriesA;
213
                    });
214
              }
215
            });
216
  }
217
218
  public static FidoMetadataServiceBuilder.Step1 builder() {
219 1 1. builder : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::builder → KILLED
    return new FidoMetadataServiceBuilder.Step1();
220
  }
221
222
  @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
223
  public static class FidoMetadataServiceBuilder {
224
    @NonNull private final MetadataBLOBPayload blob;
225
226
    private Predicate<MetadataBLOBPayloadEntry> prefilter = Filters.notRevoked();
227
    private Predicate<AuthenticatorToBeFiltered> filter = Filters.noAttestationKeyCompromise();
228
    private CertStore certStore = null;
229
230
    public static class Step1 {
231
      /**
232
       * Use payload of the given <code>blob</code> as the data source.
233
       *
234
       * <p>The {@link FidoMetadataDownloader#loadCachedBlob()} method returns a value suitable for
235
       * use here.
236
       *
237
       * <p>This is an alias of <code>useBlob(blob.getPayload()</code>.
238
       *
239
       * @since 2.0.0
240
       * @see FidoMetadataDownloader#loadCachedBlob()
241
       * @see #useBlob(MetadataBLOBPayload)
242
       */
243 1 1. useBlob : negated conditional → KILLED
      public FidoMetadataServiceBuilder useBlob(@NonNull MetadataBLOB blob) {
244 1 1. useBlob : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder$Step1::useBlob → KILLED
        return useBlob(blob.getPayload());
245
      }
246
247
      /**
248
       * Use the given <code>blobPayload</code> as the data source.
249
       *
250
       * <p>The {@link FidoMetadataDownloader#loadCachedBlob()} method returns a value whose {@link
251
       * MetadataBLOB#getPayload() .getPayload()} result is suitable for use here.
252
       *
253
       * @since 2.0.0
254
       * @see FidoMetadataDownloader#loadCachedBlob()
255
       * @see #useBlob(MetadataBLOB)
256
       */
257 1 1. useBlob : negated conditional → KILLED
      public FidoMetadataServiceBuilder useBlob(@NonNull MetadataBLOBPayload blobPayload) {
258 1 1. useBlob : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder$Step1::useBlob → KILLED
        return new FidoMetadataServiceBuilder(blobPayload);
259
      }
260
    }
261
262
    /**
263
     * Set a first-stage filter for which metadata entries to include in the data source.
264
     *
265
     * <p>This prefilter is executed once for each metadata entry during initial construction of a
266
     * {@link FidoMetadataService} instance.
267
     *
268
     * <p>The default is {@link Filters#notRevoked() Filters.notRevoked()}. Setting a different
269
     * filter overrides this default; to preserve the "not revoked" condition in addition to the new
270
     * filter, you must explicitly include the condition in the new filter, for example by using
271
     * {@link Filters#allOf(Predicate[]) Filters.allOf(Predicate...)}. To add the {@link
272
     * Filters#notRetired() Filters.notRetired()} filter, use: <code>
273
     * .prefilter(Filters.allOf(Filters.notRevoked(), Filters.notRetired()))</code>.
274
     *
275
     * @since 2.0.0
276
     * @param prefilter a {@link Predicate} which returns <code>true</code> for metadata entries to
277
     *     include in the data source.
278
     * @see #filter(Predicate)
279
     * @see Filters#allOf(Predicate[])
280
     */
281
    public FidoMetadataServiceBuilder prefilter(
282 1 1. prefilter : negated conditional → KILLED
        @NonNull Predicate<MetadataBLOBPayloadEntry> prefilter) {
283
      this.prefilter = prefilter;
284 1 1. prefilter : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder::prefilter → KILLED
      return this;
285
    }
286
287
    /**
288
     * Set a filter for which metadata entries to allow for a given authenticator during credential
289
     * registration and metadata lookup.
290
     *
291
     * <p>This filter is executed during each execution of {@link #findEntries(List, AAGUID)}, its
292
     * overloads, and {@link #findTrustRoots(List, Optional)}.
293
     *
294
     * <p>The default is {@link Filters#noAttestationKeyCompromise()
295
     * Filters.noAttestationKeyCompromise()}. Setting a different filter overrides this default; to
296
     * preserve this condition in addition to the new filter, you must explicitly include the
297
     * condition in the few filter. For example, by using {@link Filters#allOf(Predicate[])
298
     * Filters.allOf(Predicate...)}.
299
     *
300
     * <p>Note: Returning <code>true</code> in the filter predicate does not automatically make the
301
     * authenticator trusted, as its attestation certificate must also correctly chain to a trusted
302
     * attestation root. Rather, returning <code>true</code> in the filter predicate allows the
303
     * corresponding metadata entry to be used for further trust assessment for that authenticator,
304
     * while returning <code>false</code> eliminates the metadata entry (and thus any associated
305
     * trust roots) for the ongoing query.
306
     *
307
     * @param filter a {@link Predicate} which returns <code>true</code> for metadata entries to
308
     *     allow for the corresponding authenticator during credential registration and metadata
309
     *     lookup.
310
     * @since 2.0.0
311
     * @see #prefilter(Predicate)
312
     * @see AuthenticatorToBeFiltered
313
     * @see Filters#allOf(Predicate[])
314
     */
315
    public FidoMetadataServiceBuilder filter(
316 1 1. filter : negated conditional → KILLED
        @NonNull Predicate<FidoMetadataService.Filters.AuthenticatorToBeFiltered> filter) {
317
      this.filter = filter;
318 1 1. filter : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder::filter → KILLED
      return this;
319
    }
320
321
    /**
322
     * Set a {@link CertStore} of additional CRLs and/or intermediate certificates to use while
323
     * validating attestation certificate paths.
324
     *
325
     * <p>This setting is most likely useful for tests.
326
     *
327
     * @param certStore a {@link CertStore} of additional CRLs and/or intermediate certificates to
328
     *     use while validating attestation certificate paths.
329
     * @since 2.0.0
330
     */
331 1 1. certStore : negated conditional → KILLED
    public FidoMetadataServiceBuilder certStore(@NonNull CertStore certStore) {
332
      this.certStore = certStore;
333 1 1. certStore : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder::certStore → KILLED
      return this;
334
    }
335
336
    public FidoMetadataService build()
337
        throws CertPathValidatorException,
338
            InvalidAlgorithmParameterException,
339
            Base64UrlException,
340
            DigestException,
341
            FidoMetadataDownloaderException,
342
            CertificateException,
343
            UnexpectedLegalHeader,
344
            IOException,
345
            NoSuchAlgorithmException,
346
            SignatureException,
347
            InvalidKeyException {
348 1 1. build : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder::build → KILLED
      return new FidoMetadataService(blob, prefilter, filter, certStore);
349
    }
350
  }
351
352
  /**
353
   * Preconfigured filters and utilities for combining filters. See the {@link
354
   * FidoMetadataServiceBuilder#prefilter(Predicate) prefilter} and {@link
355
   * FidoMetadataServiceBuilder#filter(Predicate) filter} settings.
356
   *
357
   * @since 2.0.0
358
   * @see FidoMetadataServiceBuilder#prefilter(Predicate)
359
   * @see FidoMetadataServiceBuilder#filter(Predicate)
360
   */
361
  public static class Filters {
362
363
    /**
364
     * Combine a set of filters into a filter that requires inputs to satisfy ALL of those filters.
365
     *
366
     * <p>If <code>filters</code> is empty, then all inputs will satisfy the resulting filter.
367
     *
368
     * @param filters A set of filters.
369
     * @return A filter which only accepts inputs that satisfy ALL of the given <code>
370
     *     filters</code>.
371
     * @since 2.0.0
372
     */
373
    @SafeVarargs
374
    public static <T> Predicate<T> allOf(Predicate<T>... filters) {
375 5 1. lambda$allOf$0 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$allOf$0 → NO_COVERAGE
2. lambda$allOf$0 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$allOf$0 → NO_COVERAGE
3. allOf : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$Filters::allOf → NO_COVERAGE
4. lambda$allOf$1 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$allOf$1 → NO_COVERAGE
5. lambda$allOf$1 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$allOf$1 → NO_COVERAGE
      return (entry) -> Stream.of(filters).allMatch(filter -> filter.test(entry));
376
    }
377
378
    /**
379
     * Include any metadata entry whose {@link MetadataBLOBPayloadEntry#getStatusReports()
380
     * statusReports} array contains no entry with {@link AuthenticatorStatus#REVOKED REVOKED}
381
     * status.
382
     *
383
     * @since 2.0.0
384
     * @see AuthenticatorStatus#REVOKED
385
     */
386
    public static Predicate<MetadataBLOBPayloadEntry> notRevoked() {
387 1 1. notRevoked : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$Filters::notRevoked → KILLED
      return (entry) ->
388 2 1. lambda$notRevoked$3 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRevoked$3 → KILLED
2. lambda$notRevoked$3 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRevoked$3 → KILLED
          entry.getStatusReports().stream()
389
              .noneMatch(
390 2 1. lambda$notRevoked$2 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRevoked$2 → KILLED
2. lambda$notRevoked$2 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRevoked$2 → KILLED
                  statusReport -> AuthenticatorStatus.REVOKED.equals(statusReport.getStatus()));
391
    }
392
393
    /**
394
     * Include any metadata entry whose {@link MetadataBLOBPayloadEntry#getStatusReports()
395
     * statusReports} array contains no entry with {@link AuthenticatorStatus#RETIRED RETIRED}
396
     * status.
397
     *
398
     * @since 2.9.0
399
     * @see AuthenticatorStatus#RETIRED
400
     */
401
    public static Predicate<MetadataBLOBPayloadEntry> notRetired() {
402 1 1. notRetired : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$Filters::notRetired → KILLED
      return (entry) ->
403 2 1. lambda$notRetired$5 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRetired$5 → KILLED
2. lambda$notRetired$5 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRetired$5 → KILLED
          entry.getStatusReports().stream()
404
              .noneMatch(
405 2 1. lambda$notRetired$4 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRetired$4 → SURVIVED
2. lambda$notRetired$4 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRetired$4 → KILLED
                  statusReport -> AuthenticatorStatus.RETIRED.equals(statusReport.getStatus()));
406
    }
407
408
    /**
409
     * Accept any authenticator whose matched metadata entry does NOT indicate a compromised
410
     * attestation key.
411
     *
412
     * <p>A metadata entry indicates a compromised attestation key if any of its {@link
413
     * MetadataBLOBPayloadEntry#getStatusReports() statusReports} entries has {@link
414
     * AuthenticatorStatus#ATTESTATION_KEY_COMPROMISE ATTESTATION_KEY_COMPROMISE} status and either
415
     * an empty {@link StatusReport#getCertificate() certificate} field or a {@link
416
     * StatusReport#getCertificate() certificate} whose public key appears in the authenticator's
417
     * {@link AuthenticatorToBeFiltered#getAttestationCertificateChain() attestation certificate
418
     * chain}.
419
     *
420
     * @since 2.0.0
421
     * @see AuthenticatorStatus#ATTESTATION_KEY_COMPROMISE
422
     */
423
    public static Predicate<AuthenticatorToBeFiltered> noAttestationKeyCompromise() {
424 1 1. noAttestationKeyCompromise : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$Filters::noAttestationKeyCompromise → KILLED
      return (params) ->
425 2 1. lambda$noAttestationKeyCompromise$9 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$9 → KILLED
2. lambda$noAttestationKeyCompromise$9 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$9 → KILLED
          params.getMetadataEntry().getStatusReports().stream()
426
              .filter(
427
                  statusReport ->
428 2 1. lambda$noAttestationKeyCompromise$6 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$6 → KILLED
2. lambda$noAttestationKeyCompromise$6 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$6 → KILLED
                      AuthenticatorStatus.ATTESTATION_KEY_COMPROMISE.equals(
429
                          statusReport.getStatus()))
430
              .noneMatch(
431
                  statusReport ->
432 2 1. lambda$noAttestationKeyCompromise$8 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$8 → SURVIVED
2. lambda$noAttestationKeyCompromise$8 : negated conditional → KILLED
                      !statusReport.getCertificate().isPresent()
433
                          || (params.getAttestationCertificateChain().stream()
434 1 1. lambda$noAttestationKeyCompromise$8 : negated conditional → KILLED
                              .anyMatch(
435
                                  cert ->
436 2 1. lambda$noAttestationKeyCompromise$7 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$7 → SURVIVED
2. lambda$noAttestationKeyCompromise$7 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$7 → KILLED
                                      Arrays.equals(
437
                                          statusReport
438
                                              .getCertificate()
439
                                              .get()
440
                                              .getPublicKey()
441
                                              .getEncoded(),
442
                                          cert.getPublicKey().getEncoded()))));
443
    }
444
445
    /**
446
     * This class encapsulates parameters for filtering authenticators in the {@link
447
     * FidoMetadataServiceBuilder#filter(Predicate) filter} setting of {@link FidoMetadataService}.
448
     *
449
     * @since 2.0.0
450
     */
451
    @Value
452
    @AllArgsConstructor(access = AccessLevel.PRIVATE)
453
    public static class AuthenticatorToBeFiltered {
454
455
      /**
456
       * The attestation certificate chain from the <a
457
       * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#attestation-statement">attestation
458
       * statement</a> from an authenticator about ot be registered.
459
       *
460
       * @since 2.0.0
461
       */
462
      @NonNull List<X509Certificate> attestationCertificateChain;
463
464
      /**
465
       * A metadata BLOB entry that matches the {@link #getAttestationCertificateChain()} and {@link
466
       * #getAaguid()} in this same {@link AuthenticatorToBeFiltered} object.
467
       *
468
       * @since 2.0.0
469
       */
470
      @NonNull MetadataBLOBPayloadEntry metadataEntry;
471
472
      AAGUID aaguid;
473
474
      /**
475
       * The AAGUID from the <a
476
       * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-attested-credential-data">attested
477
       * credential data</a> of a credential about ot be registered.
478
       *
479
       * <p>This will not be present if the attested credential data contained an AAGUID of all
480
       * zeroes.
481
       *
482
       * @since 2.0.0
483
       */
484
      public Optional<AAGUID> getAaguid() {
485 1 1. getAaguid : replaced return value with Optional.empty for com/yubico/fido/metadata/FidoMetadataService$Filters$AuthenticatorToBeFiltered::getAaguid → SURVIVED
        return Optional.ofNullable(aaguid);
486
      }
487
    }
488
  }
489
490
  /**
491
   * Look up metadata entries matching a given attestation certificate chain or AAGUID.
492
   *
493
   * @param attestationCertificateChain an attestation certificate chain, presumably from a WebAuthn
494
   *     attestation statement.
495
   * @param aaguid the AAGUID of the authenticator to look up, if available.
496
   * @return All metadata entries which satisfy ALL of the following:
497
   *     <ul>
498
   *       <li>It satisfies the {@link FidoMetadataServiceBuilder#prefilter(Predicate) prefilter}.
499
   *       <li>It satisfies AT LEAST ONE of the following:
500
   *           <ul>
501
   *             <li><code>_aaguid</code> is present and equals the {@link
502
   *                 MetadataBLOBPayloadEntry#getAaguid() AAGUID} of the metadata entry.
503
   *             <li><code>_aaguid</code> is present and equals the {@link
504
   *                 MetadataStatement#getAaguid() AAGUID} of the {@link
505
   *                 MetadataBLOBPayloadEntry#getMetadataStatement() metadata statement}, if any, in
506
   *                 the metadata entry.
507
   *             <li>The certificate subject key identifier of any certificate in <code>
508
   *                 attestationCertificateChain</code> matches any element of {@link
509
   *                 MetadataBLOBPayloadEntry#getAttestationCertificateKeyIdentifiers()
510
   *                 attestationCertificateKeyIdentifiers} in the metadata entry.
511
   *             <li>The certificate subject key identifier of any certificate in <code>
512
   *                 attestationCertificateChain</code> matches any element of {@link
513
   *                 MetadataStatement#getAttestationCertificateKeyIdentifiers()
514
   *                 attestationCertificateKeyIdentifiers} in the {@link
515
   *                 MetadataBLOBPayloadEntry#getMetadataStatement() metadata statement}, if any, in
516
   *                 the metadata entry.
517
   *           </ul>
518
   *       <li>It satisfies the {@link FidoMetadataServiceBuilder#filter(Predicate) filter} together
519
   *           with <code>attestationCertificateChain</code> and <code>_aaguid</code>.
520
   *     </ul>
521
   *     In the above, <code>_aaguid</code> is the first of the following that is {@link
522
   *     Optional#isPresent() present} and not {@link AAGUID#isZero() zero}, or empty otherwise:
523
   *     <ul>
524
   *       <li>The <code>aaguid</code> argument.
525
   *       <li>The value of the X.509 extension with OID 1.3.6.1.4.1.45724.1.1.4
526
   *           (id-fido-gen-ce-aaguid), if any, in the first certificate in <code>
527
   *                             attestationCertificateChain</code>, if any.
528
   *     </ul>
529
   *
530
   * @since 2.0.0
531
   * @see #findEntries(List)
532
   * @see #findEntries(List, AAGUID)
533
   */
534
  public Set<MetadataBLOBPayloadEntry> findEntries(
535 1 1. findEntries : negated conditional → KILLED
      @NonNull final List<X509Certificate> attestationCertificateChain,
536 1 1. findEntries : negated conditional → KILLED
      @NonNull final Optional<AAGUID> aaguid) {
537
538
    final Set<String> certSubjectKeyIdentifiers =
539
        attestationCertificateChain.stream()
540
            .map(
541
                cert -> {
542
                  try {
543 1 1. lambda$findEntries$16 : replaced return value with "" for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$16 → KILLED
                    return new ByteArray(CertificateParser.computeSubjectKeyIdentifier(cert))
544
                        .getHex();
545
                  } catch (NoSuchAlgorithmException e) {
546
                    throw new RuntimeException(
547
                        "SHA-1 hash algorithm is not available in JCA context.", e);
548
                  }
549
                })
550
            .collect(Collectors.toSet());
551
552
    final Optional<AAGUID> nonzeroAaguid =
553
        OptionalUtil.orElseOptional(
554 2 1. lambda$findEntries$17 : negated conditional → KILLED
2. lambda$findEntries$17 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$17 → KILLED
            aaguid.filter(a -> !a.isZero()),
555
            () -> {
556
              log.debug("findEntries: attempting to look up AAGUID from certificate");
557 1 1. lambda$findEntries$18 : negated conditional → KILLED
              if (attestationCertificateChain.isEmpty()) {
558
                return Optional.empty();
559
              } else {
560 1 1. lambda$findEntries$18 : replaced return value with Optional.empty for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$18 → SURVIVED
                return CertificateParser.parseFidoAaguidExtension(
561
                        attestationCertificateChain.get(0))
562
                    .map(ByteArray::new)
563
                    .map(AAGUID::new);
564
              }
565
            });
566
567
    log.debug(
568
        "findEntries(certSubjectKeyIdentifiers = {}, aaguid = {}, nonzeroAaguid= {})",
569
        certSubjectKeyIdentifiers,
570
        aaguid,
571
        nonzeroAaguid);
572
573
    final Set<MetadataBLOBPayloadEntry> result =
574
        Stream.concat(
575
                nonzeroAaguid
576
                    .map(prefilteredEntriesByAaguid::get)
577
                    .map(Collection::stream)
578
                    .orElseGet(Stream::empty),
579
                certSubjectKeyIdentifiers.stream()
580
                    .flatMap(
581
                        cski ->
582
                            Optional.ofNullable(
583
                                    prefilteredEntriesByCertificateKeyIdentifier.get(cski))
584
                                .map(Collection::stream)
585 1 1. lambda$findEntries$19 : replaced return value with Stream.empty for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$19 → KILLED
                                .orElseGet(Stream::empty)))
586
            .filter(
587
                metadataBLOBPayloadEntry ->
588 2 1. lambda$findEntries$20 : replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$20 → KILLED
2. lambda$findEntries$20 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$20 → KILLED
                    this.filter.test(
589
                        new AuthenticatorToBeFiltered(
590
                            attestationCertificateChain,
591
                            metadataBLOBPayloadEntry,
592
                            nonzeroAaguid.orElse(null))))
593
            .collect(Collectors.toSet());
594
595
    log.debug(
596
        "findEntries(certSubjectKeyIdentifiers = {}, aaguid = {}) => {} matches",
597
        certSubjectKeyIdentifiers,
598
        aaguid,
599
        result.size());
600 1 1. findEntries : replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → KILLED
    return result;
601
  }
602
603
  /**
604
   * Alias of <code>findEntries(attestationCertificateChain, Optional.empty())</code>.
605
   *
606
   * @since 2.0.0
607
   * @see #findEntries(List, Optional)
608
   */
609
  public Set<MetadataBLOBPayloadEntry> findEntries(
610 1 1. findEntries : negated conditional → NO_COVERAGE
      @NonNull List<X509Certificate> attestationCertificateChain) {
611 1 1. findEntries : replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → NO_COVERAGE
    return findEntries(attestationCertificateChain, Optional.empty());
612
  }
613
614
  /**
615
   * Alias of <code>findEntries(attestationCertificateChain, Optional.of(aaguid))</code>.
616
   *
617
   * @since 2.0.0
618
   * @see #findEntries(List, Optional)
619
   */
620
  public Set<MetadataBLOBPayloadEntry> findEntries(
621 2 1. findEntries : negated conditional → KILLED
2. findEntries : negated conditional → KILLED
      @NonNull List<X509Certificate> attestationCertificateChain, @NonNull AAGUID aaguid) {
622 1 1. findEntries : replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → KILLED
    return findEntries(attestationCertificateChain, Optional.of(aaguid));
623
  }
624
625
  /**
626
   * Find metadata entries matching the credential represented by <code>registrationResult</code>.
627
   *
628
   * <p>This is an alias of:
629
   *
630
   * <pre>
631
   * registrationResult.getAttestationTrustPath()
632
   *   .map(atp -&gt; this.findEntries(atp, new AAGUID(registrationResult.getAaguid())))
633
   *   .orElseGet(Collections::emptySet)
634
   * </pre>
635
   *
636
   * @since 2.0.0
637
   * @see #findEntries(List, Optional)
638
   */
639 1 1. findEntries : negated conditional → NO_COVERAGE
  public Set<MetadataBLOBPayloadEntry> findEntries(@NonNull RegistrationResult registrationResult) {
640 1 1. findEntries : replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → NO_COVERAGE
    return registrationResult
641
        .getAttestationTrustPath()
642 1 1. lambda$findEntries$21 : replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$21 → NO_COVERAGE
        .map(atp -> findEntries(atp, new AAGUID(registrationResult.getAaguid())))
643
        .orElseGet(Collections::emptySet);
644
  }
645
646
  /**
647
   * Find metadata entries matching the given AAGUID.
648
   *
649
   * @since 2.0.0
650
   * @see #findEntries(List, Optional)
651
   */
652 1 1. findEntries : negated conditional → KILLED
  public Set<MetadataBLOBPayloadEntry> findEntries(@NonNull AAGUID aaguid) {
653 1 1. findEntries : replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → KILLED
    return findEntries(Collections.emptyList(), aaguid);
654
  }
655
656
  /**
657
   * Retrieve metadata entries matching the given filter.
658
   *
659
   * <p>Note: The result MAY include fewer results than the number of times the <code>filter</code>
660
   * returned <code>true</code>, because of possible duplication in the underlying data store.
661
   *
662
   * @param filter a {@link Predicate} which returns <code>true</code> for metadata entries to
663
   *     include in the result.
664
   * @return All metadata entries which satisfy the {@link
665
   *     FidoMetadataServiceBuilder#prefilter(Predicate) prefilter} AND for which the <code>filter
666
   *     </code> returns <code>true</code>.
667
   * @since 2.0.0
668
   * @see #findEntries(List, Optional)
669
   */
670
  public Set<MetadataBLOBPayloadEntry> findEntries(
671 1 1. findEntries : negated conditional → KILLED
      @NonNull Predicate<MetadataBLOBPayloadEntry> filter) {
672 1 1. findEntries : replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → KILLED
    return Stream.concat(
673
            Stream.concat(
674
                prefilteredEntriesByAaguid.values().stream().flatMap(Collection::stream),
675
                prefilteredEntriesByCertificateKeyIdentifier.values().stream()
676
                    .flatMap(Collection::stream)),
677
            prefilteredUnindexedEntries.stream())
678
        .filter(filter)
679
        .collect(Collectors.toSet());
680
  }
681
682
  /**
683
   * @since 2.0.0
684
   */
685
  @Override
686
  public TrustRootsResult findTrustRoots(
687
      List<X509Certificate> attestationCertificateChain, Optional<ByteArray> aaguid) {
688 1 1. findTrustRoots : replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::findTrustRoots → KILLED
    return TrustRootsResult.builder()
689
        .trustRoots(
690
            findEntries(attestationCertificateChain, aaguid.map(AAGUID::new)).stream()
691
                .map(MetadataBLOBPayloadEntry::getMetadataStatement)
692
                .flatMap(OptionalUtil::stream)
693
                .flatMap(
694
                    metadataStatement ->
695 1 1. lambda$findTrustRoots$22 : replaced return value with Stream.empty for com/yubico/fido/metadata/FidoMetadataService::lambda$findTrustRoots$22 → KILLED
                        metadataStatement.getAttestationRootCertificates().stream())
696
                .collect(Collectors.toSet()))
697
        .certStore(certStore)
698
        .enableRevocationChecking(false)
699 1 1. lambda$findTrustRoots$23 : replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService::lambda$findTrustRoots$23 → KILLED
        .policyTreeValidator(policyNode -> true)
700
        .build();
701
  }
702
}

Mutations

105

1.1
Location : <init>
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

106

1.1
Location : <init>
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

107

1.1
Location : <init>
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

133

1.1
Location : ignoreInvalidUpdateAvailableAuthenticatorVersion
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::ignoreInvalidUpdateAvailableAuthenticatorVersion → KILLED

2.2
Location : ignoreInvalidUpdateAvailableAuthenticatorVersion
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService::ignoreInvalidUpdateAvailableAuthenticatorVersion → KILLED

138

1.1
Location : lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$3
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced Boolean return with True for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$3 → KILLED

2.2
Location : lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$3
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced Boolean return with False for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$3 → KILLED

141

1.1
Location : lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$0
Killed by : none
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$0 → SURVIVED

2.2
Location : lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$0
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$0 → KILLED

146

1.1
Location : lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$1
Killed by : com.yubico.fido.metadata.FidoMds3Spec
changed conditional boundary → KILLED

2.2
Location : lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$1
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced Boolean return with True for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$1 → KILLED

3.3
Location : lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$1
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

147

1.1
Location : lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$2
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$2 → KILLED

2.2
Location : lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$2
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService::lambda$ignoreInvalidUpdateAvailableAuthenticatorVersion$2 → KILLED

152

1.1
Location : buildCkiMap
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

154

1.1
Location : buildCkiMap
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::buildCkiMap → KILLED

160

1.1
Location : lambda$buildCkiMap$4
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::lambda$buildCkiMap$4 → KILLED

167

1.1
Location : lambda$buildCkiMap$5
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::lambda$buildCkiMap$5 → KILLED

177

1.1
Location : lambda$buildCkiMap$7
Killed by : none
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::lambda$buildCkiMap$7 → NO_COVERAGE

184

1.1
Location : buildAaguidMap
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

186

1.1
Location : buildAaguidMap
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::buildAaguidMap → KILLED

193

1.1
Location : lambda$buildAaguidMap$9
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::lambda$buildAaguidMap$9 → KILLED

197

1.1
Location : lambda$buildAaguidMap$11
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

2.2
Location : lambda$buildAaguidMap$11
Killed by : none
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$buildAaguidMap$11 → SURVIVED

198

1.1
Location : lambda$buildAaguidMap$13
Killed by : com.yubico.fido.metadata.FidoMds3Spec
removed call to java/util/Optional::ifPresent → KILLED

202

1.1
Location : lambda$buildAaguidMap$12
Killed by : none
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$buildAaguidMap$12 → SURVIVED

2.2
Location : lambda$buildAaguidMap$12
Killed by : none
negated conditional → SURVIVED

203

1.1
Location : lambda$buildAaguidMap$13
Killed by : none
removed call to java/util/Optional::ifPresent → SURVIVED

212

1.1
Location : lambda$buildAaguidMap$14
Killed by : none
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::lambda$buildAaguidMap$14 → NO_COVERAGE

219

1.1
Location : builder
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::builder → KILLED

243

1.1
Location : useBlob
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

244

1.1
Location : useBlob
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder$Step1::useBlob → KILLED

257

1.1
Location : useBlob
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

258

1.1
Location : useBlob
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder$Step1::useBlob → KILLED

282

1.1
Location : prefilter
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

284

1.1
Location : prefilter
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder::prefilter → KILLED

316

1.1
Location : filter
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

318

1.1
Location : filter
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder::filter → KILLED

331

1.1
Location : certStore
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

333

1.1
Location : certStore
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder::certStore → KILLED

348

1.1
Location : build
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$FidoMetadataServiceBuilder::build → KILLED

375

1.1
Location : lambda$allOf$0
Killed by : none
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$allOf$0 → NO_COVERAGE

2.2
Location : lambda$allOf$0
Killed by : none
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$allOf$0 → NO_COVERAGE

3.3
Location : allOf
Killed by : none
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$Filters::allOf → NO_COVERAGE

4.4
Location : lambda$allOf$1
Killed by : none
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$allOf$1 → NO_COVERAGE

5.5
Location : lambda$allOf$1
Killed by : none
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$allOf$1 → NO_COVERAGE

387

1.1
Location : notRevoked
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$Filters::notRevoked → KILLED

388

1.1
Location : lambda$notRevoked$3
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRevoked$3 → KILLED

2.2
Location : lambda$notRevoked$3
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRevoked$3 → KILLED

390

1.1
Location : lambda$notRevoked$2
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRevoked$2 → KILLED

2.2
Location : lambda$notRevoked$2
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRevoked$2 → KILLED

402

1.1
Location : notRetired
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$Filters::notRetired → KILLED

403

1.1
Location : lambda$notRetired$5
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRetired$5 → KILLED

2.2
Location : lambda$notRetired$5
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRetired$5 → KILLED

405

1.1
Location : lambda$notRetired$4
Killed by : none
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRetired$4 → SURVIVED

2.2
Location : lambda$notRetired$4
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$notRetired$4 → KILLED

424

1.1
Location : noAttestationKeyCompromise
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService$Filters::noAttestationKeyCompromise → KILLED

425

1.1
Location : lambda$noAttestationKeyCompromise$9
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$9 → KILLED

2.2
Location : lambda$noAttestationKeyCompromise$9
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$9 → KILLED

428

1.1
Location : lambda$noAttestationKeyCompromise$6
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$6 → KILLED

2.2
Location : lambda$noAttestationKeyCompromise$6
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$6 → KILLED

432

1.1
Location : lambda$noAttestationKeyCompromise$8
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

2.2
Location : lambda$noAttestationKeyCompromise$8
Killed by : none
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$8 → SURVIVED

434

1.1
Location : lambda$noAttestationKeyCompromise$8
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

436

1.1
Location : lambda$noAttestationKeyCompromise$7
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$7 → KILLED

2.2
Location : lambda$noAttestationKeyCompromise$7
Killed by : none
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService$Filters::lambda$noAttestationKeyCompromise$7 → SURVIVED

485

1.1
Location : getAaguid
Killed by : none
replaced return value with Optional.empty for com/yubico/fido/metadata/FidoMetadataService$Filters$AuthenticatorToBeFiltered::getAaguid → SURVIVED

535

1.1
Location : findEntries
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

536

1.1
Location : findEntries
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

543

1.1
Location : lambda$findEntries$16
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with "" for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$16 → KILLED

554

1.1
Location : lambda$findEntries$17
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

2.2
Location : lambda$findEntries$17
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$17 → KILLED

557

1.1
Location : lambda$findEntries$18
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

560

1.1
Location : lambda$findEntries$18
Killed by : none
replaced return value with Optional.empty for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$18 → SURVIVED

585

1.1
Location : lambda$findEntries$19
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with Stream.empty for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$19 → KILLED

588

1.1
Location : lambda$findEntries$20
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with true for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$20 → KILLED

2.2
Location : lambda$findEntries$20
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$20 → KILLED

600

1.1
Location : findEntries
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → KILLED

610

1.1
Location : findEntries
Killed by : none
negated conditional → NO_COVERAGE

611

1.1
Location : findEntries
Killed by : none
replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → NO_COVERAGE

621

1.1
Location : findEntries
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

2.2
Location : findEntries
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

622

1.1
Location : findEntries
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → KILLED

639

1.1
Location : findEntries
Killed by : none
negated conditional → NO_COVERAGE

640

1.1
Location : findEntries
Killed by : none
replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → NO_COVERAGE

642

1.1
Location : lambda$findEntries$21
Killed by : none
replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::lambda$findEntries$21 → NO_COVERAGE

652

1.1
Location : findEntries
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

653

1.1
Location : findEntries
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → KILLED

671

1.1
Location : findEntries
Killed by : com.yubico.fido.metadata.FidoMds3Spec
negated conditional → KILLED

672

1.1
Location : findEntries
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with Collections.emptySet for com/yubico/fido/metadata/FidoMetadataService::findEntries → KILLED

688

1.1
Location : findTrustRoots
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with null for com/yubico/fido/metadata/FidoMetadataService::findTrustRoots → KILLED

695

1.1
Location : lambda$findTrustRoots$22
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with Stream.empty for com/yubico/fido/metadata/FidoMetadataService::lambda$findTrustRoots$22 → KILLED

699

1.1
Location : lambda$findTrustRoots$23
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced boolean return with false for com/yubico/fido/metadata/FidoMetadataService::lambda$findTrustRoots$23 → KILLED

Active mutators

Tests examined


Report generated by PIT 1.15.0