AAGUID.java

1
package com.yubico.fido.metadata;
2
3
import com.fasterxml.jackson.annotation.JsonCreator;
4
import com.fasterxml.jackson.annotation.JsonValue;
5
import com.yubico.internal.util.ExceptionUtil;
6
import com.yubico.webauthn.data.ByteArray;
7
import com.yubico.webauthn.data.exception.HexException;
8
import java.util.regex.Matcher;
9
import java.util.regex.Pattern;
10
import lombok.AccessLevel;
11
import lombok.Getter;
12
import lombok.ToString;
13
import lombok.Value;
14
15
/**
16
 * Some authenticators have an AAGUID, which is a 128-bit identifier that indicates the type (e.g.
17
 * make and model) of the authenticator. The AAGUID MUST be chosen by the manufacturer to be
18
 * identical across all substantially identical authenticators made by that manufacturer, and
19
 * different (with probability 1-2-128 or greater) from the AAGUIDs of all other types of
20
 * authenticators.
21
 *
22
 * <p>The AAGUID is represented as a string (e.g. "7a98c250-6808-11cf-b73b-00aa00b677a7") consisting
23
 * of 5 hex strings separated by a dash ("-"), see [RFC4122].
24
 *
25
 * @see <a
26
 *     href="https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.0-ps-20210518.html#typedefdef-aaguid">FIDO
27
 *     Metadata Statement §3.1. Authenticator Attestation GUID (AAGUID) typedef</a>
28
 * @see <a href="https://tools.ietf.org/html/rfc4122">RFC 4122: A Universally Unique IDentifier
29
 *     (UUID) URN Namespace</a>
30
 */
31
@Value
32
@Getter(AccessLevel.NONE)
33
@ToString(includeFieldNames = false, onlyExplicitlyIncluded = true)
34
public class AAGUID {
35
36
  private static final Pattern AAGUID_PATTERN =
37
      Pattern.compile(
38
          "^([0-9a-fA-F]{8})-?([0-9a-fA-F]{4})-?([0-9a-fA-F]{4})-?([0-9a-fA-F]{4})-?([0-9a-fA-F]{12})$");
39
40
  private static final ByteArray ZERO =
41
      new ByteArray(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
42
43
  ByteArray value;
44
45
  /**
46
   * Construct an AAGUID from its raw binary representation.
47
   *
48
   * <p>This is the inverse of {@link #asBytes()}.
49
   *
50
   * @param value a {@link ByteArray} of length exactly 16.
51
   */
52
  public AAGUID(ByteArray value) {
53 1 1. <init> : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → SURVIVED
    ExceptionUtil.assertTrue(
54 1 1. <init> : negated conditional → KILLED
        value.size() == 16,
55
        "AAGUID as bytes must be exactly 16 bytes long, was %d: %s",
56
        value.size(),
57
        value);
58
    this.value = value;
59
  }
60
61
  /**
62
   * The 16-byte binary representation of this AAGUID, for example <code>
63
   * 7a98c250680811cfb73b00aa00b677a7</code> when hex-encoded.
64
   *
65
   * <p>This is the inverse of {@link #AAGUID(ByteArray)}.
66
   */
67
  public ByteArray asBytes() {
68 1 1. asBytes : replaced return value with null for com/yubico/fido/metadata/AAGUID::asBytes → KILLED
    return value;
69
  }
70
71
  /**
72
   * The 32-character hexadecimal representation of this AAGUID, for example <code>
73
   * "7a98c250680811cfb73b00aa00b677a7"</code>.
74
   */
75
  public String asHexString() {
76 1 1. asHexString : replaced return value with "" for com/yubico/fido/metadata/AAGUID::asHexString → KILLED
    return value.getHex();
77
  }
78
79
  /**
80
   * The 36-character string representation of this AAGUID, for example <code>
81
   * "7a98c250-6808-11cf-b73b-00aa00b677a7"</code>.
82
   */
83
  @JsonValue
84
  @ToString.Include
85
  public String asGuidString() {
86
    final String hex = value.getHex();
87 1 1. asGuidString : replaced return value with "" for com/yubico/fido/metadata/AAGUID::asGuidString → KILLED
    return String.format(
88
        "%s-%s-%s-%s-%s",
89
        hex.substring(0, 8),
90
        hex.substring(8, 8 + 4),
91
        hex.substring(8 + 4, 8 + 4 + 4),
92
        hex.substring(8 + 4 + 4, 8 + 4 + 4 + 4),
93
        hex.substring(8 + 4 + 4 + 4, 8 + 4 + 4 + 4 + 12));
94
  }
95
96
  /**
97
   * <code>true</code> if and only if this {@link AAGUID} consists of all zeroes. This typically
98
   * indicates that an authenticator has no AAGUID, or that the AAGUID has been redacted.
99
   */
100
  public boolean isZero() {
101 2 1. isZero : replaced boolean return with true for com/yubico/fido/metadata/AAGUID::isZero → KILLED
2. isZero : replaced boolean return with false for com/yubico/fido/metadata/AAGUID::isZero → KILLED
    return ZERO.equals(value);
102
  }
103
104
  private static ByteArray parse(String value) {
105
    Matcher matcher = AAGUID_PATTERN.matcher(value);
106 1 1. parse : negated conditional → KILLED
    if (matcher.find()) {
107
      try {
108 1 1. parse : replaced return value with null for com/yubico/fido/metadata/AAGUID::parse → KILLED
        return ByteArray.fromHex(matcher.group(1))
109
            .concat(ByteArray.fromHex(matcher.group(2)))
110
            .concat(ByteArray.fromHex(matcher.group(3)))
111
            .concat(ByteArray.fromHex(matcher.group(4)))
112
            .concat(ByteArray.fromHex(matcher.group(5)));
113
      } catch (HexException e) {
114
        throw new RuntimeException(
115
            "This exception should be impossible, please file a bug report.", e);
116
      }
117
    } else {
118
      throw new IllegalArgumentException("Value does not match AAGUID pattern: " + value);
119
    }
120
  }
121
122
  @JsonCreator
123
  private static AAGUID fromString(String aaguid) {
124 1 1. fromString : replaced return value with null for com/yubico/fido/metadata/AAGUID::fromString → KILLED
    return new AAGUID(parse(aaguid));
125
  }
126
}

Mutations

53

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

54

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

68

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

76

1.1
Location : asHexString
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with "" for com/yubico/fido/metadata/AAGUID::asHexString → KILLED

87

1.1
Location : asGuidString
Killed by : com.yubico.fido.metadata.FidoMds3Spec
replaced return value with "" for com/yubico/fido/metadata/AAGUID::asGuidString → KILLED

101

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

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

106

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

108

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

124

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

Active mutators

Tests examined


Report generated by PIT 1.15.0