WebAuthnCodecs.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.google.common.primitives.Bytes;
28
import com.upokecenter.cbor.CBORObject;
29
import com.yubico.internal.util.BinaryUtil;
30
import com.yubico.webauthn.data.ByteArray;
31
import com.yubico.webauthn.data.COSEAlgorithmIdentifier;
32
import java.io.IOException;
33
import java.math.BigInteger;
34
import java.security.KeyFactory;
35
import java.security.NoSuchAlgorithmException;
36
import java.security.PublicKey;
37
import java.security.interfaces.ECPublicKey;
38
import java.security.spec.InvalidKeySpecException;
39
import java.security.spec.RSAPublicKeySpec;
40
import java.security.spec.X509EncodedKeySpec;
41
import java.util.Arrays;
42
import java.util.HashMap;
43
import java.util.Map;
44
import java.util.Optional;
45
46
final class WebAuthnCodecs {
47
48
  private static final ByteArray EC_PUBLIC_KEY_OID =
49
      new ByteArray(
50
          new byte[] {
51
            0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 2, 1
52
          }); // OID 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type)
53
  private static final ByteArray P256_CURVE_OID =
54
      new ByteArray(
55
          new byte[] {
56
            0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 3, 1, 7 // OID 1.2.840.10045.3.1.7
57
          });
58
  private static final ByteArray P384_CURVE_OID =
59
      new ByteArray(new byte[] {0x2B, (byte) 0x81, 0x04, 0, 34}); // OID 1.3.132.0.34
60
  private static final ByteArray P521_CURVE_OID =
61
      new ByteArray(new byte[] {0x2B, (byte) 0x81, 0x04, 0, 35}); // OID 1.3.132.0.35
62
63
  static final ByteArray ED25519_ALG_ID =
64
      new ByteArray(
65
          new byte[] {
66
            // SEQUENCE (5 bytes)
67
            0x30,
68
            5,
69
            // OID (3 bytes)
70
            0x06,
71
            3,
72
            // OID 1.3.101.112
73
            0x2B,
74
            101,
75
            112
76
          });
77
78
  static final ByteArray ED448_ALG_ID =
79
      new ByteArray(
80
          new byte[] {
81
            // SEQUENCE (5 bytes)
82
            0x30,
83
            5,
84
            // OID (3 bytes)
85
            0x06,
86
            3,
87
            // OID 1.3.101.113
88
            0x2B,
89
            101,
90
            113
91
          });
92
93
  static final ByteArray ML_DSA_44_ALG_ID =
94
      new ByteArray(
95
          new byte[] {
96
            // SEQUENCE (11 bytes)
97
            0x30,
98
            0x0B,
99
            // OID (9 bytes)
100
            0x06,
101
            0x09,
102
            // OID 2.16.840.1.101.3.4.3.17
103
            0x60,
104
            (byte) 0x86,
105
            0x48,
106
            0x01,
107
            0x65,
108
            0x03,
109
            0x04,
110
            0x03,
111
            0x11
112
          });
113
114
  static final ByteArray ML_DSA_65_ALG_ID =
115
      new ByteArray(
116
          new byte[] {
117
            // SEQUENCE (11 bytes)
118
            0x30,
119
            0x0B,
120
            // OID (9 bytes)
121
            0x06,
122
            0x09,
123
            // OID 2.16.840.1.101.3.4.3.18
124
            0x60,
125
            (byte) 0x86,
126
            0x48,
127
            0x01,
128
            0x65,
129
            0x03,
130
            0x04,
131
            0x03,
132
            0x12
133
          });
134
135
  static final ByteArray ML_DSA_87_ALG_ID =
136
      new ByteArray(
137
          new byte[] {
138
            // SEQUENCE (11 bytes)
139
            0x30,
140
            0x0B,
141
            // OID (9 bytes)
142
            0x06,
143
            0x09,
144
            // OID 2.16.840.1.101.3.4.3.19
145
            0x60,
146
            (byte) 0x86,
147
            0x48,
148
            0x01,
149
            0x65,
150
            0x03,
151
            0x04,
152
            0x03,
153
            0x13
154
          });
155
156
  // See: https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves
157
  static final int COSE_CRV_P256 = 1;
158
  static final int COSE_CRV_P384 = 2;
159
  static final int COSE_CRV_P521 = 3;
160
  static final int COSE_CRV_ED25519 = 6;
161
  static final int COSE_CRV_ED448 = 7;
162
163
  static ByteArray ecPublicKeyToRaw(ECPublicKey key) {
164
165
    final int fieldSizeBytes =
166
        Math.toIntExact(
167 1 1. ecPublicKeyToRaw : Replaced double division with multiplication → KILLED
            Math.round(Math.ceil(key.getParams().getCurve().getField().getFieldSize() / 8.0)));
168
    byte[] x = key.getW().getAffineX().toByteArray();
169
    byte[] y = key.getW().getAffineY().toByteArray();
170 1 1. ecPublicKeyToRaw : Replaced integer subtraction with addition → KILLED
    byte[] xPadding = new byte[Math.max(0, fieldSizeBytes - x.length)];
171 1 1. ecPublicKeyToRaw : Replaced integer subtraction with addition → KILLED
    byte[] yPadding = new byte[Math.max(0, fieldSizeBytes - y.length)];
172
173 1 1. ecPublicKeyToRaw : removed call to java/util/Arrays::fill → SURVIVED
    Arrays.fill(xPadding, (byte) 0);
174 1 1. ecPublicKeyToRaw : removed call to java/util/Arrays::fill → SURVIVED
    Arrays.fill(yPadding, (byte) 0);
175
176 2 1. ecPublicKeyToRaw : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::ecPublicKeyToRaw → KILLED
2. ecPublicKeyToRaw : Replaced integer subtraction with addition → KILLED
    return new ByteArray(
177
        Bytes.concat(
178
            new byte[] {0x04},
179
            xPadding,
180 1 1. ecPublicKeyToRaw : Replaced integer subtraction with addition → KILLED
            Arrays.copyOfRange(x, Math.max(0, x.length - fieldSizeBytes), x.length),
181
            yPadding,
182
            Arrays.copyOfRange(y, Math.max(0, y.length - fieldSizeBytes), y.length)));
183
  }
184
185
  static ByteArray rawEcKeyToCose(ByteArray key) {
186
    final byte[] keyBytes = key.getBytes();
187
    final int len = keyBytes.length;
188 1 1. rawEcKeyToCose : Replaced integer subtraction with addition → KILLED
    final int lenSub1 = keyBytes.length - 1;
189 7 1. rawEcKeyToCose : negated conditional → SURVIVED
2. rawEcKeyToCose : negated conditional → SURVIVED
3. rawEcKeyToCose : negated conditional → NO_COVERAGE
4. rawEcKeyToCose : negated conditional → SURVIVED
5. rawEcKeyToCose : negated conditional → KILLED
6. rawEcKeyToCose : negated conditional → KILLED
7. rawEcKeyToCose : negated conditional → KILLED
    if (!(len == 64
190
        || len == 96
191
        || len == 132
192
        || (keyBytes[0] == 0x04 && (lenSub1 == 64 || lenSub1 == 96 || lenSub1 == 132)))) {
193
      throw new IllegalArgumentException(
194
          String.format(
195
              "Raw key must be 64, 96 or 132 bytes long, or start with 0x04 and be 65, 97 or 133 bytes long; was %d bytes starting with %02x",
196
              keyBytes.length, keyBytes[0]));
197
    }
198 3 1. rawEcKeyToCose : negated conditional → KILLED
2. rawEcKeyToCose : negated conditional → KILLED
3. rawEcKeyToCose : negated conditional → KILLED
    final int start = (len == 64 || len == 96 || len == 132) ? 0 : 1;
199 2 1. rawEcKeyToCose : Replaced integer division with multiplication → KILLED
2. rawEcKeyToCose : Replaced integer subtraction with addition → KILLED
    final int coordinateLength = (len - start) / 2;
200
201
    final Map<Long, Object> coseKey = new HashMap<>();
202
    coseKey.put(1L, 2L); // Key type: EC
203
204
    final COSEAlgorithmIdentifier coseAlg;
205
    final int coseCrv;
206 1 1. rawEcKeyToCose : Replaced integer subtraction with addition → KILLED
    switch (len - start) {
207
      case 64:
208
        coseAlg = COSEAlgorithmIdentifier.ES256;
209
        coseCrv = COSE_CRV_P256;
210
        break;
211
      case 96:
212
        coseAlg = COSEAlgorithmIdentifier.ES384;
213
        coseCrv = COSE_CRV_P384;
214
        break;
215
      case 132:
216
        coseAlg = COSEAlgorithmIdentifier.ES512;
217
        coseCrv = COSE_CRV_P521;
218
        break;
219
      default:
220
        throw new RuntimeException(
221
            "Failed to determine COSE EC algorithm. This should not be possible, please file a bug report.");
222
    }
223
    coseKey.put(3L, coseAlg.getId());
224
    coseKey.put(-1L, coseCrv);
225
226 1 1. rawEcKeyToCose : Replaced integer addition with subtraction → KILLED
    coseKey.put(-2L, Arrays.copyOfRange(keyBytes, start, start + coordinateLength)); // x
227
    coseKey.put(
228 3 1. rawEcKeyToCose : Replaced integer addition with subtraction → KILLED
2. rawEcKeyToCose : Replaced integer addition with subtraction → KILLED
3. rawEcKeyToCose : Replaced integer multiplication with division → KILLED
        -3L,
229
        Arrays.copyOfRange(keyBytes, start + coordinateLength, start + 2 * coordinateLength)); // y
230
231 1 1. rawEcKeyToCose : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::rawEcKeyToCose → KILLED
    return new ByteArray(CBORObject.FromObject(coseKey).EncodeToBytes());
232
  }
233
234
  static PublicKey importCosePublicKey(ByteArray key)
235
      throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
236
    CBORObject cose = CBORObject.DecodeFromBytes(key.getBytes());
237
    final int kty = cose.get(CBORObject.FromObject(1)).AsInt32();
238
    final CBORObject algCbor = cose.get(CBORObject.FromObject(3));
239 1 1. importCosePublicKey : removed call to com/yubico/webauthn/WebAuthnCodecs::validateKtyMatchesAlg → KILLED
    validateKtyMatchesAlg(kty, algCbor);
240
241
    switch (kty) {
242
      case 1:
243 1 1. importCosePublicKey : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCosePublicKey → KILLED
        return importCoseEdDsaPublicKey(cose);
244
      case 2:
245 1 1. importCosePublicKey : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCosePublicKey → KILLED
        return importCoseEcdsaPublicKey(cose);
246
      case 3:
247 1 1. importCosePublicKey : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCosePublicKey → KILLED
        return importCoseRsaPublicKey(cose);
248
      case 7:
249 1 1. importCosePublicKey : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCosePublicKey → KILLED
        return importCoseMlDsaPublicKey(cose);
250
      default:
251
        throw new IllegalArgumentException("Unsupported key type: " + kty);
252
    }
253
  }
254
255
  private static void validateKtyMatchesAlg(int kty, CBORObject alg) {
256 1 1. validateKtyMatchesAlg : negated conditional → KILLED
    if (alg == null) {
257
      throw new IllegalArgumentException("COSE key is missing required \"alg\" (3) attribute");
258
    }
259
    Optional<COSEAlgorithmIdentifier> algId = COSEAlgorithmIdentifier.fromId(alg.AsInt32());
260 1 1. validateKtyMatchesAlg : negated conditional → KILLED
    if (!algId.isPresent()) {
261
      return;
262
    }
263
    final int expectedKty = getExpectedKty(algId.get());
264 1 1. validateKtyMatchesAlg : negated conditional → KILLED
    if (kty != expectedKty) {
265
      throw new IllegalArgumentException(
266
          String.format(
267
              "COSE key type (kty: %d) does not match algorithm (alg: %s, expected kty: %d)",
268
              kty, algId.get(), expectedKty));
269
    }
270
  }
271
272
  private static int getExpectedKty(COSEAlgorithmIdentifier alg) {
273
    switch (alg) {
274
      case EdDSA:
275
      case Ed25519:
276
      case Ed448:
277 1 1. getExpectedKty : replaced int return with 0 for com/yubico/webauthn/WebAuthnCodecs::getExpectedKty → KILLED
        return 1; // OKP
278
      case ES256:
279
      case ES384:
280
      case ES512:
281 1 1. getExpectedKty : replaced int return with 0 for com/yubico/webauthn/WebAuthnCodecs::getExpectedKty → KILLED
        return 2; // EC2
282
      case RS1:
283
      case RS256:
284
      case RS384:
285
      case RS512:
286 1 1. getExpectedKty : replaced int return with 0 for com/yubico/webauthn/WebAuthnCodecs::getExpectedKty → KILLED
        return 3; // RSA
287
      case ML_DSA_44:
288
      case ML_DSA_65:
289
      case ML_DSA_87:
290 1 1. getExpectedKty : replaced int return with 0 for com/yubico/webauthn/WebAuthnCodecs::getExpectedKty → KILLED
        return 7; // AKP
291
      default:
292
        throw new IllegalArgumentException("Unknown algorithm: " + alg);
293
    }
294
  }
295
296
  private static PublicKey importCoseRsaPublicKey(CBORObject cose)
297
      throws NoSuchAlgorithmException, InvalidKeySpecException {
298
    RSAPublicKeySpec spec =
299
        new RSAPublicKeySpec(
300
            new BigInteger(1, cose.get(CBORObject.FromObject(-1)).GetByteString()),
301
            new BigInteger(1, cose.get(CBORObject.FromObject(-2)).GetByteString()));
302 1 1. importCoseRsaPublicKey : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCoseRsaPublicKey → KILLED
    return KeyFactory.getInstance("RSA").generatePublic(spec);
303
  }
304
305
  private static PublicKey importCoseEcdsaPublicKey(CBORObject cose)
306
      throws NoSuchAlgorithmException, InvalidKeySpecException {
307
    final int crv = cose.get(CBORObject.FromObject(-1)).AsInt32Value();
308
    final byte[] x = cose.get(CBORObject.FromObject(-2)).GetByteString();
309
    final byte[] y = cose.get(CBORObject.FromObject(-3)).GetByteString();
310
311
    final byte[] curveOid;
312
    switch (crv) {
313
      case COSE_CRV_P256:
314
        curveOid = P256_CURVE_OID.getBytes();
315
        break;
316
317
      case COSE_CRV_P384:
318
        curveOid = P384_CURVE_OID.getBytes();
319
        break;
320
321
      case COSE_CRV_P521:
322
        curveOid = P521_CURVE_OID.getBytes();
323
        break;
324
325
      default:
326
        throw new IllegalArgumentException("Unknown COSE EC2 curve: " + crv);
327
    }
328
329
    final byte[] algId =
330
        BinaryUtil.encodeDerSequence(
331
            BinaryUtil.encodeDerObjectId(EC_PUBLIC_KEY_OID.getBytes()),
332
            BinaryUtil.encodeDerObjectId(curveOid));
333
334
    final byte[] rawKey =
335
        BinaryUtil.encodeDerBitStringWithZeroUnused(
336
            BinaryUtil.concat(
337
                new byte[] {0x04}, // Raw EC public key with x and y
338
                x,
339
                y));
340
341
    final byte[] x509Key = BinaryUtil.encodeDerSequence(algId, rawKey);
342
343
    KeyFactory kFact = KeyFactory.getInstance("EC");
344 1 1. importCoseEcdsaPublicKey : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCoseEcdsaPublicKey → KILLED
    return kFact.generatePublic(new X509EncodedKeySpec(x509Key));
345
  }
346
347
  private static PublicKey importCoseEdDsaPublicKey(CBORObject cose)
348
      throws InvalidKeySpecException, NoSuchAlgorithmException {
349
    final int alg = cose.get(CBORObject.FromObject(3)).AsInt32();
350
    final int curveId = cose.get(CBORObject.FromObject(-1)).AsInt32();
351
    final ByteArray algorithmOid = coseCurveToEddsaAlgorithmOid(curveId);
352
    final byte[] rawKey = cose.get(CBORObject.FromObject(-2)).GetByteString();
353
    final byte[] x509Key =
354
        BinaryUtil.encodeDerSequence(
355
            algorithmOid.getBytes(), BinaryUtil.encodeDerBitStringWithZeroUnused(rawKey));
356
357
    KeyFactory kFact =
358
        KeyFactory.getInstance(
359
            getJavaAlgorithmName(
360
                COSEAlgorithmIdentifier.fromId(alg)
361 1 1. lambda$importCoseEdDsaPublicKey$0 : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::lambda$importCoseEdDsaPublicKey$0 → NO_COVERAGE
                    .orElseThrow(() -> new IllegalArgumentException("Unknown algorithm: " + alg))));
362 1 1. importCoseEdDsaPublicKey : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCoseEdDsaPublicKey → KILLED
    return kFact.generatePublic(new X509EncodedKeySpec(x509Key));
363
  }
364
365
  private static ByteArray coseCurveToEddsaAlgorithmOid(int curveId) {
366
    switch (curveId) {
367
      case COSE_CRV_ED25519:
368 1 1. coseCurveToEddsaAlgorithmOid : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::coseCurveToEddsaAlgorithmOid → KILLED
        return ED25519_ALG_ID;
369
      case COSE_CRV_ED448:
370 1 1. coseCurveToEddsaAlgorithmOid : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::coseCurveToEddsaAlgorithmOid → KILLED
        return ED448_ALG_ID;
371
      default:
372
        throw new IllegalArgumentException("Unsupported EdDSA curve: " + curveId);
373
    }
374
  }
375
376
  private static PublicKey importCoseMlDsaPublicKey(CBORObject cose)
377
      throws InvalidKeySpecException, NoSuchAlgorithmException {
378
    final int alg = cose.get(CBORObject.FromObject(3)).AsInt32();
379
    final ByteArray algorithmId = mlDsaAlgorithmId(alg);
380
    final byte[] rawKey = cose.get(CBORObject.FromObject(-1)).GetByteString();
381
    final byte[] x509Key =
382
        BinaryUtil.encodeDerSequence(
383
            algorithmId.getBytes(), BinaryUtil.encodeDerBitStringWithZeroUnused(rawKey));
384
385
    KeyFactory kFact =
386
        KeyFactory.getInstance(
387
            getJavaAlgorithmName(
388
                COSEAlgorithmIdentifier.fromId(alg)
389 1 1. lambda$importCoseMlDsaPublicKey$1 : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::lambda$importCoseMlDsaPublicKey$1 → NO_COVERAGE
                    .orElseThrow(() -> new IllegalArgumentException("Unknown algorithm: " + alg))));
390 1 1. importCoseMlDsaPublicKey : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCoseMlDsaPublicKey → KILLED
    return kFact.generatePublic(new X509EncodedKeySpec(x509Key));
391
  }
392
393
  private static ByteArray mlDsaAlgorithmId(int alg) {
394
    switch (alg) {
395
      case -48:
396 1 1. mlDsaAlgorithmId : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::mlDsaAlgorithmId → KILLED
        return ML_DSA_44_ALG_ID;
397
      case -49:
398 1 1. mlDsaAlgorithmId : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::mlDsaAlgorithmId → KILLED
        return ML_DSA_65_ALG_ID;
399
      case -50:
400 1 1. mlDsaAlgorithmId : replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::mlDsaAlgorithmId → KILLED
        return ML_DSA_87_ALG_ID;
401
      default:
402
        throw new IllegalArgumentException("Unsupported ML-DSA algorithm: " + alg);
403
    }
404
  }
405
406
  static String getJavaAlgorithmName(COSEAlgorithmIdentifier alg) {
407
    switch (alg) {
408
      case EdDSA:
409
      case Ed25519:
410 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "Ed25519";
411
      case Ed448:
412 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "Ed448";
413
      case ES256:
414 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "SHA256withECDSA";
415
      case ES384:
416 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "SHA384withECDSA";
417
      case ES512:
418 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "SHA512withECDSA";
419
      case RS256:
420 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "SHA256withRSA";
421
      case RS384:
422 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "SHA384withRSA";
423
      case RS512:
424 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "SHA512withRSA";
425
      case RS1:
426 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "SHA1withRSA";
427
      case ML_DSA_44:
428 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "ML-DSA-44";
429
      case ML_DSA_65:
430 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "ML-DSA-65";
431
      case ML_DSA_87:
432 1 1. getJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED
        return "ML-DSA-87";
433
      default:
434
        throw new IllegalArgumentException("Unknown algorithm: " + alg);
435
    }
436
  }
437
438
  static String jwsAlgorithmNameToJavaAlgorithmName(String alg) {
439 1 1. jwsAlgorithmNameToJavaAlgorithmName : negated conditional → KILLED
    switch (alg) {
440
      case "RS256":
441 1 1. jwsAlgorithmNameToJavaAlgorithmName : replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::jwsAlgorithmNameToJavaAlgorithmName → KILLED
        return "SHA256withRSA";
442
    }
443
    throw new IllegalArgumentException("Unknown algorithm: " + alg);
444
  }
445
}

Mutations

167

1.1
Location : ecPublicKeyToRaw
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced double division with multiplication → KILLED

170

1.1
Location : ecPublicKeyToRaw
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced integer subtraction with addition → KILLED

171

1.1
Location : ecPublicKeyToRaw
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced integer subtraction with addition → KILLED

173

1.1
Location : ecPublicKeyToRaw
Killed by : none
removed call to java/util/Arrays::fill → SURVIVED
Covering tests

174

1.1
Location : ecPublicKeyToRaw
Killed by : none
removed call to java/util/Arrays::fill → SURVIVED
Covering tests

176

1.1
Location : ecPublicKeyToRaw
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::ecPublicKeyToRaw → KILLED

2.2
Location : ecPublicKeyToRaw
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced integer subtraction with addition → KILLED

180

1.1
Location : ecPublicKeyToRaw
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced integer subtraction with addition → KILLED

188

1.1
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced integer subtraction with addition → KILLED

189

1.1
Location : rawEcKeyToCose
Killed by : none
negated conditional → SURVIVED
Covering tests

2.2
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
negated conditional → KILLED

3.3
Location : rawEcKeyToCose
Killed by : none
negated conditional → SURVIVED Covering tests

4.4
Location : rawEcKeyToCose
Killed by : none
negated conditional → NO_COVERAGE

5.5
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
negated conditional → KILLED

6.6
Location : rawEcKeyToCose
Killed by : none
negated conditional → SURVIVED Covering tests

7.7
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
negated conditional → KILLED

198

1.1
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
negated conditional → KILLED

2.2
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
negated conditional → KILLED

3.3
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
negated conditional → KILLED

199

1.1
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced integer division with multiplication → KILLED

2.2
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.RelyingPartyUserIdentificationSpec
Replaced integer subtraction with addition → KILLED

206

1.1
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced integer subtraction with addition → KILLED

226

1.1
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced integer addition with subtraction → KILLED

228

1.1
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced integer addition with subtraction → KILLED

2.2
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced integer addition with subtraction → KILLED

3.3
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
Replaced integer multiplication with division → KILLED

231

1.1
Location : rawEcKeyToCose
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::rawEcKeyToCose → KILLED

239

1.1
Location : importCosePublicKey
Killed by : com.yubico.webauthn.WebAuthnCodecsSpec
removed call to com/yubico/webauthn/WebAuthnCodecs::validateKtyMatchesAlg → KILLED

243

1.1
Location : importCosePublicKey
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCosePublicKey → KILLED

245

1.1
Location : importCosePublicKey
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCosePublicKey → KILLED

247

1.1
Location : importCosePublicKey
Killed by : com.yubico.webauthn.RelyingPartyV2AssertionSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCosePublicKey → KILLED

249

1.1
Location : importCosePublicKey
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCosePublicKey → KILLED

256

1.1
Location : validateKtyMatchesAlg
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
negated conditional → KILLED

260

1.1
Location : validateKtyMatchesAlg
Killed by : com.yubico.webauthn.WebAuthnCodecsSpec
negated conditional → KILLED

264

1.1
Location : validateKtyMatchesAlg
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
negated conditional → KILLED

277

1.1
Location : getExpectedKty
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced int return with 0 for com/yubico/webauthn/WebAuthnCodecs::getExpectedKty → KILLED

281

1.1
Location : getExpectedKty
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
replaced int return with 0 for com/yubico/webauthn/WebAuthnCodecs::getExpectedKty → KILLED

286

1.1
Location : getExpectedKty
Killed by : com.yubico.webauthn.RelyingPartyV2AssertionSpec
replaced int return with 0 for com/yubico/webauthn/WebAuthnCodecs::getExpectedKty → KILLED

290

1.1
Location : getExpectedKty
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced int return with 0 for com/yubico/webauthn/WebAuthnCodecs::getExpectedKty → KILLED

302

1.1
Location : importCoseRsaPublicKey
Killed by : com.yubico.webauthn.RelyingPartyV2AssertionSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCoseRsaPublicKey → KILLED

344

1.1
Location : importCoseEcdsaPublicKey
Killed by : com.yubico.webauthn.data.AuthenticatorDataSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCoseEcdsaPublicKey → KILLED

361

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

362

1.1
Location : importCoseEdDsaPublicKey
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCoseEdDsaPublicKey → KILLED

368

1.1
Location : coseCurveToEddsaAlgorithmOid
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::coseCurveToEddsaAlgorithmOid → KILLED

370

1.1
Location : coseCurveToEddsaAlgorithmOid
Killed by : com.yubico.webauthn.RelyingPartyV2AssertionSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::coseCurveToEddsaAlgorithmOid → KILLED

389

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

390

1.1
Location : importCoseMlDsaPublicKey
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::importCoseMlDsaPublicKey → KILLED

396

1.1
Location : mlDsaAlgorithmId
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::mlDsaAlgorithmId → KILLED

398

1.1
Location : mlDsaAlgorithmId
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::mlDsaAlgorithmId → KILLED

400

1.1
Location : mlDsaAlgorithmId
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with null for com/yubico/webauthn/WebAuthnCodecs::mlDsaAlgorithmId → KILLED

410

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

412

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyV2AssertionSpec
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

414

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyTest.doesNotLogWarningIfAllAlgorithmsAvailable(com.yubico.webauthn.RelyingPartyTest)
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

416

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

418

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

420

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyTest.doesNotLogWarningIfAllAlgorithmsAvailable(com.yubico.webauthn.RelyingPartyTest)
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

422

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyTest.defaultSettingsLogWarningIfSomeAlgorithmNotAvailable(com.yubico.webauthn.RelyingPartyTest)
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

424

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyTest.defaultSettingsLogWarningIfSomeAlgorithmNotAvailable(com.yubico.webauthn.RelyingPartyTest)
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

426

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyV2AssertionSpec
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

428

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

430

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

432

1.1
Location : getJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyCeremoniesSpec
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::getJavaAlgorithmName → KILLED

439

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

441

1.1
Location : jwsAlgorithmNameToJavaAlgorithmName
Killed by : com.yubico.webauthn.RelyingPartyV2RegistrationSpec
replaced return value with "" for com/yubico/webauthn/WebAuthnCodecs::jwsAlgorithmNameToJavaAlgorithmName → KILLED

Active mutators

Tests examined


Report generated by PIT 1.20.3