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 |
|
54 |
1.1 |
|
68 |
1.1 |
|
76 |
1.1 |
|
87 |
1.1 |
|
101 |
1.1 2.2 |
|
106 |
1.1 |
|
108 |
1.1 |
|
124 |
1.1 |