TpmAttestationStatementVerifier.java

1
// Copyright (c) 2018, 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.webauthn;
26
27
import com.fasterxml.jackson.databind.JsonNode;
28
import com.fasterxml.jackson.databind.node.ObjectNode;
29
import com.upokecenter.cbor.CBORObject;
30
import com.yubico.internal.util.BinaryUtil;
31
import com.yubico.internal.util.ByteInputStream;
32
import com.yubico.internal.util.CertificateParser;
33
import com.yubico.internal.util.ExceptionUtil;
34
import com.yubico.webauthn.data.AttestationObject;
35
import com.yubico.webauthn.data.AttestationType;
36
import com.yubico.webauthn.data.ByteArray;
37
import com.yubico.webauthn.data.COSEAlgorithmIdentifier;
38
import java.io.IOException;
39
import java.math.BigInteger;
40
import java.security.KeyFactory;
41
import java.security.NoSuchAlgorithmException;
42
import java.security.PublicKey;
43
import java.security.cert.CertificateException;
44
import java.security.cert.CertificateParsingException;
45
import java.security.cert.X509Certificate;
46
import java.security.spec.InvalidKeySpecException;
47
import java.security.spec.RSAPublicKeySpec;
48
import java.util.Arrays;
49
import java.util.List;
50
import javax.naming.InvalidNameException;
51
import javax.naming.ldap.LdapName;
52
import javax.naming.ldap.Rdn;
53
import lombok.Value;
54
import lombok.extern.slf4j.Slf4j;
55
56
@Slf4j
57
final class TpmAttestationStatementVerifier
58
    implements AttestationStatementVerifier, X5cAttestationStatementVerifier {
59
60
  private static final String TPM_VER = "2.0";
61
  static final ByteArray TPM_GENERATED_VALUE = ByteArray.fromBase64("/1RDRw==");
62
  static final ByteArray TPM_ST_ATTEST_CERTIFY = ByteArray.fromBase64("gBc=");
63
64
  static final int TPM_ALG_NULL = 0x0010;
65
66
  private static final String OID_TCG_AT_TPM_MANUFACTURER = "2.23.133.2.1";
67
  private static final String OID_TCG_AT_TPM_MODEL = "2.23.133.2.2";
68
  private static final String OID_TCG_AT_TPM_VERSION = "2.23.133.2.3";
69
70
  /**
71
   * Object attributes
72
   *
73
   * <p>see section 8.3 of
74
   * https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
75
   */
76
  static final class Attributes {
77
    static final int SIGN_ENCRYPT = 1 << 18;
78
79
    private static final int SHALL_BE_ZERO =
80
        (1 << 0) // 0 Reserved
81
            | (1 << 3) // 3 Reserved
82
            | (0x3 << 8) // 9:8 Reserved
83
            | (0xF << 12) // 15:12 Reserved
84
            | ((0xFFFFFFFF << 19) & ((1 << 31) | ((1 << 31) - 1))) // 31:19 Reserved
85
        ;
86
  }
87
88
  @Override
89
  public AttestationType getAttestationType(AttestationObject attestation) {
90 1 1. getAttestationType : replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier::getAttestationType → KILLED
    return AttestationType.ATTESTATION_CA;
91
  }
92
93
  @Override
94
  public boolean verifyAttestationSignature(
95
      AttestationObject attestationObject, ByteArray clientDataJsonHash) {
96
97
    // Step 1: Verify that attStmt is valid CBOR conforming to the syntax defined above and perform
98
    // CBOR decoding on it to extract the contained fields.
99
100
    ObjectNode attStmt = attestationObject.getAttestationStatement();
101
102
    JsonNode verNode = attStmt.get("ver");
103 2 1. verifyAttestationSignature : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
2. verifyAttestationSignature : negated conditional → KILLED
    ExceptionUtil.assertTrue(
104 2 1. verifyAttestationSignature : negated conditional → KILLED
2. verifyAttestationSignature : negated conditional → KILLED
        verNode != null && verNode.isTextual() && verNode.textValue().equals(TPM_VER),
105
        "attStmt.ver must equal \"%s\", was: %s",
106
        TPM_VER,
107
        verNode);
108
109
    JsonNode algNode = attStmt.get("alg");
110 2 1. verifyAttestationSignature : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED
2. verifyAttestationSignature : negated conditional → KILLED
    ExceptionUtil.assertTrue(
111 1 1. verifyAttestationSignature : negated conditional → KILLED
        algNode != null && algNode.canConvertToLong(),
112
        "attStmt.alg must be set to an integer value, was: %s",
113
        algNode);
114
    final COSEAlgorithmIdentifier alg =
115
        COSEAlgorithmIdentifier.fromId(algNode.longValue())
116
            .orElseThrow(
117
                () ->
118 1 1. lambda$verifyAttestationSignature$0 : replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier::lambda$verifyAttestationSignature$0 → NO_COVERAGE
                    new IllegalArgumentException("Unknown COSE algorithm identifier: " + algNode));
119
120
    JsonNode x5cNode = attStmt.get("x5c");
121 2 1. verifyAttestationSignature : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED
2. verifyAttestationSignature : negated conditional → KILLED
    ExceptionUtil.assertTrue(
122 1 1. verifyAttestationSignature : negated conditional → KILLED
        x5cNode != null && x5cNode.isArray(),
123
        "attStmt.x5c must be set to an array value, was: %s",
124
        x5cNode);
125
    final List<X509Certificate> x5c;
126
    try {
127
      x5c =
128
          getAttestationTrustPath(attestationObject)
129
              .orElseThrow(
130
                  () ->
131 1 1. lambda$verifyAttestationSignature$1 : replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier::lambda$verifyAttestationSignature$1 → NO_COVERAGE
                      new IllegalArgumentException(
132
                          "Failed to parse \"x5c\" attestation certificate chain in \"tpm\" attestation statement."));
133
    } catch (CertificateException e) {
134
      throw new RuntimeException(e);
135
    }
136
    final X509Certificate aikCert = x5c.get(0);
137
138
    JsonNode sigNode = attStmt.get("sig");
139 2 1. verifyAttestationSignature : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED
2. verifyAttestationSignature : negated conditional → KILLED
    ExceptionUtil.assertTrue(
140 1 1. verifyAttestationSignature : negated conditional → KILLED
        sigNode != null && sigNode.isBinary(),
141
        "attStmt.sig must be set to a binary value, was: %s",
142
        sigNode);
143
    final ByteArray sig;
144
    try {
145
      sig = new ByteArray(sigNode.binaryValue());
146
    } catch (IOException e) {
147
      throw new RuntimeException(e);
148
    }
149
150
    JsonNode certInfoNode = attStmt.get("certInfo");
151 2 1. verifyAttestationSignature : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED
2. verifyAttestationSignature : negated conditional → KILLED
    ExceptionUtil.assertTrue(
152 1 1. verifyAttestationSignature : negated conditional → KILLED
        certInfoNode != null && certInfoNode.isBinary(),
153
        "attStmt.certInfo must be set to a binary value, was: %s",
154
        certInfoNode);
155
156
    JsonNode pubAreaNode = attStmt.get("pubArea");
157 2 1. verifyAttestationSignature : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED
2. verifyAttestationSignature : negated conditional → KILLED
    ExceptionUtil.assertTrue(
158 1 1. verifyAttestationSignature : negated conditional → KILLED
        pubAreaNode != null && pubAreaNode.isBinary(),
159
        "attStmt.pubArea must be set to a binary value, was: %s",
160
        pubAreaNode);
161
162
    final TpmtPublic pubArea;
163
    try {
164
      pubArea = TpmtPublic.parse(pubAreaNode.binaryValue());
165
    } catch (IOException e) {
166
      throw new RuntimeException("Failed to parse TPMT_PUBLIC data structure.", e);
167
    }
168
169
    final TpmsAttest certInfo;
170
    try {
171
      certInfo = TpmsAttest.parse(certInfoNode.binaryValue());
172
    } catch (IOException e) {
173
      throw new RuntimeException("Failed to parse TPMS_ATTEST data structure.", e);
174
    }
175
176
    // Step 2: Verify that the public key specified by the parameters and unique fields of pubArea
177
    // is identical to the credentialPublicKey in the attestedCredentialData in authenticatorData.
178
    try {
179 1 1. verifyAttestationSignature : removed call to com/yubico/webauthn/TpmAttestationStatementVerifier::verifyPublicKeysMatch → KILLED
      verifyPublicKeysMatch(attestationObject, pubArea);
180
    } catch (IOException | InvalidKeySpecException | NoSuchAlgorithmException e) {
181
      throw new RuntimeException(
182
          "Failed to verify that public key in TPM attestation matches public key in authData.", e);
183
    }
184
185
    // Step 3: Concatenate authenticatorData and clientDataHash to form attToBeSigned.
186
    final ByteArray attToBeSigned =
187
        attestationObject.getAuthenticatorData().getBytes().concat(clientDataJsonHash);
188
189
    // Step 4: Validate that certInfo is valid:
190
    try {
191 1 1. verifyAttestationSignature : removed call to com/yubico/webauthn/TpmAttestationStatementVerifier::validateCertInfo → KILLED
      validateCertInfo(alg, aikCert, sig, pubArea, certInfo, attToBeSigned, attestationObject);
192
    } catch (CertificateParsingException e) {
193
      throw new RuntimeException("Failed to verify TPM attestation.", e);
194
    }
195
196 1 1. verifyAttestationSignature : replaced boolean return with false for com/yubico/webauthn/TpmAttestationStatementVerifier::verifyAttestationSignature → KILLED
    return true;
197
  }
198
199
  private void validateCertInfo(
200
      COSEAlgorithmIdentifier alg,
201
      X509Certificate aikCert,
202
      ByteArray sig,
203
      TpmtPublic pubArea,
204
      TpmsAttest certInfo,
205
      ByteArray attToBeSigned,
206
      AttestationObject attestationObject)
207
      throws CertificateParsingException {
208
    // Sub-steps 1-2 handled in TpmsAttest.parse()
209
    // Sub-step 3: Verify that extraData is set to the hash of attToBeSigned using the hash
210
    // algorithm employed in "alg".
211
    final ByteArray expectedExtraData;
212
    switch (alg) {
213
      case ES256:
214
      case RS256:
215
        expectedExtraData = Crypto.sha256(attToBeSigned);
216
        break;
217
218
      case ES384:
219
      case RS384:
220
        expectedExtraData = Crypto.sha384(attToBeSigned);
221
        break;
222
223
      case ES512:
224
      case RS512:
225
        expectedExtraData = Crypto.sha512(attToBeSigned);
226
        break;
227
228
      case RS1:
229
        try {
230
          expectedExtraData = Crypto.sha1(attToBeSigned);
231
        } catch (NoSuchAlgorithmException e) {
232
          throw new RuntimeException("Failed to hash attToBeSigned to verify TPM attestation.", e);
233
        }
234
        break;
235
236
      default:
237
        throw new UnsupportedOperationException("Signing algorithm not implemented: " + alg);
238
    }
239 1 1. validateCertInfo : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
    ExceptionUtil.assertTrue(
240
        certInfo.extraData.equals(expectedExtraData), "Incorrect certInfo.extraData.");
241
242
    // Sub-step 4: Verify that attested contains a TPMS_CERTIFY_INFO structure as specified in
243
    // [TPMv2-Part2] section 10.12.3, whose name field contains a valid Name for pubArea, as
244
    // computed using the algorithm in the nameAlg field of pubArea using the procedure specified in
245
    // [TPMv2-Part1] section 16.
246 1 1. validateCertInfo : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
    ExceptionUtil.assertTrue(
247
        certInfo.attestedName.equals(pubArea.name()), "Incorrect certInfo.attestedName.");
248
249
    // Sub-step 5 handled by parsing above
250
    // Sub-step 6: Nothing to do
251
252
    // Sub-step 7: Verify the sig is a valid signature over certInfo using the attestation public
253
    // key in aikCert with the algorithm specified in alg.
254 1 1. validateCertInfo : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
    ExceptionUtil.assertTrue(
255
        Crypto.verifySignature(aikCert, certInfo.getRawBytes(), sig, alg),
256
        "Incorrect TPM attestation signature.");
257
258
    // Sub-step 8: Verify that aikCert meets the requirements in § 8.3.1 TPM Attestation Statement
259
    // Certificate Requirements.
260
    // Sub-step 9: If aikCert contains an extension with OID 1.3.6.1.4.1.45724.1.1.4
261
    // (id-fido-gen-ce-aaguid) verify that the value of this extension matches the aaguid in
262
    // authenticatorData.
263 1 1. validateCertInfo : removed call to com/yubico/webauthn/TpmAttestationStatementVerifier::verifyX5cRequirements → KILLED
    verifyX5cRequirements(
264
        aikCert,
265
        attestationObject.getAuthenticatorData().getAttestedCredentialData().get().getAaguid());
266
  }
267
268
  private void verifyPublicKeysMatch(AttestationObject attestationObject, TpmtPublic pubArea)
269
      throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
270
    final PublicKey credentialPubKey =
271
        WebAuthnCodecs.importCosePublicKey(
272
            attestationObject
273
                .getAuthenticatorData()
274
                .getAttestedCredentialData()
275
                .get()
276
                .getCredentialPublicKey());
277
278
    final PublicKey signedCredentialPublicKey;
279
    switch (pubArea.signAlg) {
280
      case TpmAlgAsym.RSA:
281
        {
282
          TpmsRsaParms params = (TpmsRsaParms) pubArea.parameters;
283
          Tpm2bPublicKeyRsa unique = (Tpm2bPublicKeyRsa) pubArea.unique;
284
          RSAPublicKeySpec spec =
285
              new RSAPublicKeySpec(
286
                  new BigInteger(1, unique.bytes.getBytes()), BigInteger.valueOf(params.exponent));
287
          KeyFactory kf = KeyFactory.getInstance("RSA");
288
          signedCredentialPublicKey = kf.generatePublic(spec);
289
        }
290
291 1 1. verifyPublicKeysMatch : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
        ExceptionUtil.assertTrue(
292
            Arrays.equals(credentialPubKey.getEncoded(), signedCredentialPublicKey.getEncoded()),
293
            "Signed public key in TPM attestation is not identical to credential public key in authData.");
294
        break;
295
296
      case TpmAlgAsym.ECC:
297
        {
298
          TpmsEccParms params = (TpmsEccParms) pubArea.parameters;
299
          TpmsEccPoint unique = (TpmsEccPoint) pubArea.unique;
300
301
          final COSEAlgorithmIdentifier algId =
302
              COSEAlgorithmIdentifier.fromPublicKey(
303
                      attestationObject
304
                          .getAuthenticatorData()
305
                          .getAttestedCredentialData()
306
                          .get()
307
                          .getCredentialPublicKey())
308
                  .get();
309
          final COSEAlgorithmIdentifier tpmAlgId;
310
          final CBORObject cosePubkey =
311
              CBORObject.DecodeFromBytes(
312
                  attestationObject
313
                      .getAuthenticatorData()
314
                      .getAttestedCredentialData()
315
                      .get()
316
                      .getCredentialPublicKey()
317
                      .getBytes());
318
319
          switch (params.curve_id) {
320
            case TpmEccCurve.NIST_P256:
321
              tpmAlgId = COSEAlgorithmIdentifier.ES256;
322
              break;
323
324
            case TpmEccCurve.NIST_P384:
325
              tpmAlgId = COSEAlgorithmIdentifier.ES384;
326
              break;
327
328
            case TpmEccCurve.NIST_P521:
329
              tpmAlgId = COSEAlgorithmIdentifier.ES512;
330
              break;
331
332
            default:
333
              throw new UnsupportedOperationException(
334
                  "Unsupported elliptic curve: " + params.curve_id);
335
          }
336
337 1 1. verifyPublicKeysMatch : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
          ExceptionUtil.assertTrue(
338
              algId.equals(tpmAlgId),
339
              "Signed public key in TPM attestation is not identical to credential public key in authData; elliptic curve differs: %s != %s",
340
              tpmAlgId,
341
              algId);
342
          byte[] cosePubkeyX = cosePubkey.get(CBORObject.FromObject(-2)).GetByteString();
343
          byte[] cosePubkeyY = cosePubkey.get(CBORObject.FromObject(-3)).GetByteString();
344 1 1. verifyPublicKeysMatch : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
          ExceptionUtil.assertTrue(
345
              new BigInteger(1, unique.x.getBytes()).equals(new BigInteger(1, cosePubkeyX)),
346
              "Signed public key in TPM attestation is not identical to credential public key in authData; EC X coordinate differs: %s != %s",
347
              unique.x,
348
              new ByteArray(cosePubkeyX));
349 1 1. verifyPublicKeysMatch : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
          ExceptionUtil.assertTrue(
350
              new BigInteger(1, unique.y.getBytes()).equals(new BigInteger(1, cosePubkeyY)),
351
              "Signed public key in TPM attestation is not identical to credential public key in authData; EC Y coordinate differs: %s != %s",
352
              unique.y,
353
              new ByteArray(cosePubkeyY));
354
        }
355
        break;
356
357
      default:
358
        throw new UnsupportedOperationException(
359
            "Unsupported algorithm for credential public key: " + pubArea.signAlg);
360
    }
361
  }
362
363
  static final class TpmAlgAsym {
364
    static final int RSA = 0x0001;
365
    static final int ECC = 0x0023;
366
  }
367
368
  private interface Parameters {}
369
370
  private interface Unique {}
371
372
  @Value
373
  private static class TpmtPublic {
374
    int signAlg;
375
    int nameAlg;
376
    Parameters parameters;
377
    Unique unique;
378
    ByteArray rawBytes;
379
380
    private static TpmtPublic parse(byte[] pubArea) throws IOException {
381
      try (ByteInputStream reader = new ByteInputStream(pubArea)) {
382
        final int signAlg = reader.readUnsignedShort();
383
        final int nameAlg = reader.readUnsignedShort();
384
385
        final int attributes = reader.readInt();
386 3 1. parse : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED
2. parse : negated conditional → KILLED
3. parse : Replaced bitwise AND with OR → KILLED
        ExceptionUtil.assertTrue(
387
            (attributes & Attributes.SHALL_BE_ZERO) == 0,
388
            "Attributes contains 1 bits in reserved position(s): 0x%08x",
389
            attributes);
390
391
        // authPolicy is not used by this implementation
392
        reader.skipBytes(reader.readUnsignedShort());
393
394
        final Parameters parameters;
395
        final Unique unique;
396
397 3 1. parse : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
2. parse : negated conditional → KILLED
3. parse : Replaced bitwise AND with OR → KILLED
        ExceptionUtil.assertTrue(
398
            (attributes & Attributes.SIGN_ENCRYPT) == Attributes.SIGN_ENCRYPT,
399
            "Public key is expected to have the SIGN_ENCRYPT attribute set, attributes were: 0x%08x",
400
            attributes);
401
402 1 1. parse : negated conditional → KILLED
        if (signAlg == TpmAlgAsym.RSA) {
403
          parameters = TpmsRsaParms.parse(reader);
404
          unique = Tpm2bPublicKeyRsa.parse(reader);
405 1 1. parse : negated conditional → KILLED
        } else if (signAlg == TpmAlgAsym.ECC) {
406
          parameters = TpmsEccParms.parse(reader);
407
          unique = TpmsEccPoint.parse(reader);
408
        } else {
409
          throw new UnsupportedOperationException("Signing algorithm not implemented: " + signAlg);
410
        }
411
412 1 1. parse : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED
        ExceptionUtil.assertTrue(
413 1 1. parse : negated conditional → KILLED
            reader.available() == 0,
414
            "%d remaining bytes in TPMT_PUBLIC buffer",
415
            reader.available());
416
417
        return new TpmtPublic(signAlg, nameAlg, parameters, unique, new ByteArray(pubArea));
418
      }
419
    }
420
421
    /**
422
     * Computing Entity Names
423
     *
424
     * <p>see:
425
     * https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-1-Architecture-01.38.pdf
426
     * section 16 Names
427
     *
428
     * <pre>
429
     * Name ≔ nameAlg || HnameAlg (handle→nvPublicArea)
430
     * where
431
     * nameAlg algorithm used to compute Name
432
     * HnameAlg hash using the nameAlg parameter in the NV Index location
433
     * associated with handle
434
     * nvPublicArea contents of the TPMS_NV_PUBLIC associated with handle
435
     * </pre>
436
     */
437
    private ByteArray name() {
438
      final ByteArray hash;
439
      switch (this.nameAlg) {
440
        case TpmAlgHash.SHA1:
441
          try {
442
            hash = Crypto.sha1(this.rawBytes);
443
          } catch (NoSuchAlgorithmException e) {
444
            throw new RuntimeException("Failed to hash TPMU_ATTEST name.", e);
445
          }
446
          break;
447
448
        case TpmAlgHash.SHA256:
449
          hash = Crypto.sha256(this.rawBytes);
450
          break;
451
452
        case TpmAlgHash.SHA384:
453
          hash = Crypto.sha384(this.rawBytes);
454
          break;
455
456
        case TpmAlgHash.SHA512:
457
          hash = Crypto.sha512(this.rawBytes);
458
          break;
459
460
        default:
461
          throw new IllegalArgumentException("Unknown hash algorithm identifier: " + this.nameAlg);
462
      }
463 1 1. name : replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier$TpmtPublic::name → KILLED
      return new ByteArray(BinaryUtil.encodeUint16(this.nameAlg)).concat(hash);
464
    }
465
  }
466
467
  static class TpmAlgHash {
468
    static final int SHA1 = 0x0004;
469
    static final int SHA256 = 0x000B;
470
    static final int SHA384 = 0x000C;
471
    static final int SHA512 = 0x000D;
472
  }
473
474
  private void verifyX5cRequirements(X509Certificate cert, ByteArray aaguid)
475
      throws CertificateParsingException {
476 1 1. verifyX5cRequirements : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED
    ExceptionUtil.assertTrue(
477 1 1. verifyX5cRequirements : negated conditional → KILLED
        cert.getVersion() == 3,
478
        "Invalid TPM attestation certificate: Version MUST be 3, but was: %s",
479
        cert.getVersion());
480
481 1 1. verifyX5cRequirements : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
    ExceptionUtil.assertTrue(
482
        cert.getSubjectX500Principal().getName().isEmpty(),
483
        "Invalid TPM attestation certificate: subject MUST be empty, but was: %s",
484
        cert.getSubjectX500Principal());
485
486
    boolean foundManufacturer = false;
487
    boolean foundModel = false;
488
    boolean foundVersion = false;
489
    for (List<?> n : cert.getSubjectAlternativeNames()) {
490 1 1. verifyX5cRequirements : negated conditional → KILLED
      if ((Integer) n.get(0) == 4) { // GeneralNames CHOICE 4: directoryName
491 1 1. verifyX5cRequirements : negated conditional → KILLED
        if (n.get(1) instanceof String) {
492
          try {
493
            for (final Rdn rdn : new LdapName((String) n.get(1)).getRdns()) {
494
              javax.naming.directory.Attributes attrs = rdn.toAttributes();
495 1 1. verifyX5cRequirements : negated conditional → KILLED
              foundManufacturer =
496 1 1. verifyX5cRequirements : negated conditional → KILLED
                  foundManufacturer || attrs.get(OID_TCG_AT_TPM_MANUFACTURER) != null;
497 2 1. verifyX5cRequirements : negated conditional → KILLED
2. verifyX5cRequirements : negated conditional → KILLED
              foundModel = foundModel || attrs.get(OID_TCG_AT_TPM_MODEL) != null;
498 2 1. verifyX5cRequirements : negated conditional → KILLED
2. verifyX5cRequirements : negated conditional → KILLED
              foundVersion = foundVersion || attrs.get(OID_TCG_AT_TPM_VERSION) != null;
499
            }
500
          } catch (InvalidNameException e) {
501
            throw new RuntimeException(
502
                "Failed to decode subject alternative name in TPM attestation cert", e);
503
          }
504
        } else {
505
          log.debug("Unknown type of SubjectAlternativeNames entry: {}", n.get(1));
506
        }
507
      }
508
    }
509 4 1. verifyX5cRequirements : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
2. verifyX5cRequirements : negated conditional → KILLED
3. verifyX5cRequirements : negated conditional → KILLED
4. verifyX5cRequirements : negated conditional → KILLED
    ExceptionUtil.assertTrue(
510
        foundManufacturer && foundModel && foundVersion,
511
        "Invalid TPM attestation certificate: The Subject Alternative Name extension MUST be set as defined in [TPMv2-EK-Profile] section 3.2.9.%s%s%s",
512 1 1. verifyX5cRequirements : negated conditional → SURVIVED
        foundManufacturer ? "" : " Missing TPM manufacturer.",
513 1 1. verifyX5cRequirements : negated conditional → SURVIVED
        foundModel ? "" : " Missing TPM model.",
514 1 1. verifyX5cRequirements : negated conditional → SURVIVED
        foundVersion ? "" : " Missing TPM version.");
515
516 1 1. verifyX5cRequirements : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
    ExceptionUtil.assertTrue(
517 2 1. verifyX5cRequirements : negated conditional → KILLED
2. verifyX5cRequirements : negated conditional → KILLED
        cert.getExtendedKeyUsage() != null && cert.getExtendedKeyUsage().contains("2.23.133.8.3"),
518
        "Invalid TPM attestation certificate: extended key usage extension MUST contain the OID 2.23.133.8.3, but was: %s",
519
        cert.getExtendedKeyUsage());
520
521 1 1. verifyX5cRequirements : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
    ExceptionUtil.assertTrue(
522 1 1. verifyX5cRequirements : negated conditional → KILLED
        cert.getBasicConstraints() == -1,
523
        "Invalid TPM attestation certificate: MUST NOT be a CA certificate, but was.");
524
525
    CertificateParser.parseFidoAaguidExtension(cert)
526 1 1. verifyX5cRequirements : removed call to java/util/Optional::ifPresent → KILLED
        .ifPresent(
527
            extensionAaguid -> {
528 1 1. lambda$verifyX5cRequirements$2 : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
              ExceptionUtil.assertTrue(
529
                  Arrays.equals(aaguid.getBytes(), extensionAaguid),
530
                  "Invalid TPM attestation certificate: X.509 extension \"id-fido-gen-ce-aaguid\" is present but does not match the authenticator AAGUID.");
531
            });
532
  }
533
534
  static final class TpmRsaScheme {
535
    static final int RSASSA = 0x0014;
536
  }
537
538
  /**
539
   * See:
540
   * https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
541
   * section 12.2.3.5
542
   */
543
  @Value
544
  private static class TpmsRsaParms implements Parameters {
545
546
    long exponent;
547
548
    private static TpmsRsaParms parse(ByteInputStream reader) throws IOException {
549
      final int symmetric = reader.readUnsignedShort();
550 2 1. parse : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
2. parse : negated conditional → KILLED
      ExceptionUtil.assertTrue(
551
          symmetric == TPM_ALG_NULL,
552
          "RSA key is expected to have \"symmetric\" set to TPM_ALG_NULL, was: 0x%04x",
553
          symmetric);
554
555
      final int scheme = reader.readUnsignedShort();
556 3 1. parse : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
2. parse : negated conditional → KILLED
3. parse : negated conditional → KILLED
      ExceptionUtil.assertTrue(
557
          scheme == TpmRsaScheme.RSASSA || scheme == TPM_ALG_NULL,
558
          "RSA key is expected to have \"scheme\" set to TPM_ALG_RSASSA or TPM_ALG_NULL, was: 0x%04x",
559
          scheme);
560
561
      reader.skipBytes(2); // key_bits is not used by this implementation
562
563
      int exponent = reader.readInt();
564 3 1. parse : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED
2. parse : changed conditional boundary → KILLED
3. parse : negated conditional → KILLED
      ExceptionUtil.assertTrue(
565
          exponent >= 0, "Exponent is too large and wrapped around to negative: %d", exponent);
566 1 1. parse : negated conditional → KILLED
      if (exponent == 0) {
567
        // When zero,  indicates  that  the  exponent  is  the  default  of 2^16 + 1
568
        exponent = (1 << 16) + 1;
569
      }
570
571 1 1. parse : replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier$TpmsRsaParms::parse → KILLED
      return new TpmsRsaParms(exponent);
572
    }
573
  }
574
575
  @Value
576
  private static class Tpm2bPublicKeyRsa implements Unique {
577
    ByteArray bytes;
578
579
    private static Tpm2bPublicKeyRsa parse(ByteInputStream reader) throws IOException {
580 1 1. parse : replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier$Tpm2bPublicKeyRsa::parse → KILLED
      return new Tpm2bPublicKeyRsa(new ByteArray(reader.read(reader.readUnsignedShort())));
581
    }
582
  }
583
584
  @Value
585
  private static class TpmsEccParms implements Parameters {
586
    int curve_id;
587
588
    private static TpmsEccParms parse(ByteInputStream reader) throws IOException {
589
      final int symmetric = reader.readUnsignedShort();
590
      final int scheme = reader.readUnsignedShort();
591 2 1. parse : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
2. parse : negated conditional → KILLED
      ExceptionUtil.assertTrue(
592
          symmetric == TPM_ALG_NULL,
593
          "ECC key is expected to have \"symmetric\" set to TPM_ALG_NULL, was: 0x%04x",
594
          symmetric);
595 2 1. parse : negated conditional → KILLED
2. parse : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
      ExceptionUtil.assertTrue(
596
          scheme == TPM_ALG_NULL,
597
          "ECC key is expected to have \"scheme\" set to TPM_ALG_NULL, was: 0x%04x",
598
          scheme);
599
600
      final int curve_id = reader.readUnsignedShort();
601
      reader.skipBytes(2); // kdf_scheme is not used by this implementation
602
603 1 1. parse : replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier$TpmsEccParms::parse → KILLED
      return new TpmsEccParms(curve_id);
604
    }
605
  }
606
607
  /**
608
   * TPMS_ECC_POINT
609
   *
610
   * <p>See
611
   * https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
612
   * Section 11.2.5.2
613
   */
614
  @Value
615
  private static class TpmsEccPoint implements Unique {
616
617
    ByteArray x;
618
    ByteArray y;
619
620
    private static TpmsEccPoint parse(ByteInputStream reader) throws IOException {
621
      final ByteArray x = new ByteArray(reader.read(reader.readUnsignedShort()));
622
      final ByteArray y = new ByteArray(reader.read(reader.readUnsignedShort()));
623
624 1 1. parse : replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier$TpmsEccPoint::parse → KILLED
      return new TpmsEccPoint(x, y);
625
    }
626
  }
627
628
  /**
629
   * TPM_ECC_CURVE
630
   *
631
   * <p>https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
632
   * section 6.4
633
   */
634
  private static class TpmEccCurve {
635
636
    private static final int NONE = 0x0000;
637
    private static final int NIST_P256 = 0x0003;
638
    private static final int NIST_P384 = 0x0004;
639
    private static final int NIST_P521 = 0x0005;
640
  }
641
642
  /**
643
   * the signature data is defined by [TPMv2-Part2] Section 10.12.8 (TPMS_ATTEST) as:
644
   * TPM_GENERATED_VALUE (0xff544347 aka "\xffTCG") TPMI_ST_ATTEST - always TPM_ST_ATTEST_CERTIFY
645
   * (0x8017) because signing procedure defines it should call TPM_Certify [TPMv2-Part3] Section
646
   * 18.2 TPM2B_NAME size (uint16) name (size long) TPM2B_DATA size (uint16) name (size long)
647
   * TPMS_CLOCK_INFO clock (uint64) resetCount (uint32) restartCount (uint32) safe (byte) 1 yes, 0
648
   * no firmwareVersion uint64 attested TPMS_CERTIFY_INFO (because TPM_ST_ATTEST_CERTIFY) name
649
   * TPM2B_NAME qualified_name TPM2B_NAME See:
650
   * https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
651
   * https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-3-Commands-01.38.pdf
652
   */
653
  @Value
654
  private static class TpmsAttest {
655
656
    ByteArray rawBytes;
657
    ByteArray extraData;
658
    ByteArray attestedName;
659
660
    private static TpmsAttest parse(byte[] certInfo) throws IOException {
661
      try (ByteInputStream reader = new ByteInputStream(certInfo)) {
662
        final ByteArray magic = new ByteArray(reader.read(4));
663
664
        // Verify that magic is set to TPM_GENERATED_VALUE.
665
        // see https://w3c.github.io/webauthn/#sctn-tpm-attestation
666
        // verification procedure
667 1 1. parse : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
        ExceptionUtil.assertTrue(
668
            magic.equals(TPM_GENERATED_VALUE), "magic field is invalid: %s", magic);
669
670
        // Verify that type is set to TPM_ST_ATTEST_CERTIFY.
671
        // see https://w3c.github.io/webauthn/#sctn-tpm-attestation
672
        // verification procedure
673
        final ByteArray type = new ByteArray(reader.read(2));
674 1 1. parse : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED
        ExceptionUtil.assertTrue(
675
            type.equals(TPM_ST_ATTEST_CERTIFY), "type field is invalid: %s", type);
676
677
        // qualifiedSigner is not used by this implementation
678
        reader.skipBytes(reader.readUnsignedShort());
679
680
        final ByteArray extraData = new ByteArray(reader.read(reader.readUnsignedShort()));
681
682
        // clockInfo is not used by this implementation
683
        reader.skipBytes(8 + 4 + 4 + 1);
684
685
        // firmwareVersion is not used by this implementation
686
        reader.skipBytes(8);
687
688
        final ByteArray attestedName = new ByteArray(reader.read(reader.readUnsignedShort()));
689
690
        // attestedQualifiedName is not used by this implementation
691
692
        return new TpmsAttest(new ByteArray(certInfo), extraData, attestedName);
693
      }
694
    }
695
  }
696
}

Mutations

90

1.1
Location : getAttestationType
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier::getAttestationType → KILLED

103

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

2.2
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

104

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

2.2
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

110

1.1
Location : verifyAttestationSignature
Killed by : none
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED

2.2
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

111

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

118

1.1
Location : lambda$verifyAttestationSignature$0
Killed by : none
replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier::lambda$verifyAttestationSignature$0 → NO_COVERAGE

121

1.1
Location : verifyAttestationSignature
Killed by : none
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED

2.2
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

122

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

131

1.1
Location : lambda$verifyAttestationSignature$1
Killed by : none
replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier::lambda$verifyAttestationSignature$1 → NO_COVERAGE

139

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

2.2
Location : verifyAttestationSignature
Killed by : none
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED

140

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

151

1.1
Location : verifyAttestationSignature
Killed by : none
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED

2.2
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

152

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

157

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

2.2
Location : verifyAttestationSignature
Killed by : none
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED

158

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

179

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/webauthn/TpmAttestationStatementVerifier::verifyPublicKeysMatch → KILLED

191

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/webauthn/TpmAttestationStatementVerifier::validateCertInfo → KILLED

196

1.1
Location : verifyAttestationSignature
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
replaced boolean return with false for com/yubico/webauthn/TpmAttestationStatementVerifier::verifyAttestationSignature → KILLED

239

1.1
Location : validateCertInfo
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

246

1.1
Location : validateCertInfo
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

254

1.1
Location : validateCertInfo
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

263

1.1
Location : validateCertInfo
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/webauthn/TpmAttestationStatementVerifier::verifyX5cRequirements → KILLED

291

1.1
Location : verifyPublicKeysMatch
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

337

1.1
Location : verifyPublicKeysMatch
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

344

1.1
Location : verifyPublicKeysMatch
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

349

1.1
Location : verifyPublicKeysMatch
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

386

1.1
Location : parse
Killed by : none
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED

2.2
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

3.3
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
Replaced bitwise AND with OR → KILLED

397

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

2.2
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

3.3
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
Replaced bitwise AND with OR → KILLED

402

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

405

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

412

1.1
Location : parse
Killed by : none
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED

413

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

463

1.1
Location : name
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier$TpmtPublic::name → KILLED

476

1.1
Location : verifyX5cRequirements
Killed by : none
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED

477

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

481

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

490

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

491

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

495

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

496

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

497

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

2.2
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

498

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

2.2
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

509

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

2.2
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

3.3
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

4.4
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

512

1.1
Location : verifyX5cRequirements
Killed by : none
negated conditional → SURVIVED

513

1.1
Location : verifyX5cRequirements
Killed by : none
negated conditional → SURVIVED

514

1.1
Location : verifyX5cRequirements
Killed by : none
negated conditional → SURVIVED

516

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

517

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

2.2
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

521

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

522

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

526

1.1
Location : verifyX5cRequirements
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to java/util/Optional::ifPresent → KILLED

528

1.1
Location : lambda$verifyX5cRequirements$2
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

550

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

2.2
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

556

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

2.2
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

3.3
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

564

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
changed conditional boundary → KILLED

2.2
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

3.3
Location : parse
Killed by : none
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED

566

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

571

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier$TpmsRsaParms::parse → KILLED

580

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier$Tpm2bPublicKeyRsa::parse → KILLED

591

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

2.2
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

595

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

2.2
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

603

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier$TpmsEccParms::parse → KILLED

624

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
replaced return value with null for com/yubico/webauthn/TpmAttestationStatementVerifier$TpmsEccPoint::parse → KILLED

667

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

674

1.1
Location : parse
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED

Active mutators

Tests examined


Report generated by PIT 1.15.0