CertificateParser.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.internal.util;
26
27
import java.io.ByteArrayInputStream;
28
import java.io.InputStream;
29
import java.net.MalformedURLException;
30
import java.net.URL;
31
import java.nio.ByteBuffer;
32
import java.nio.charset.StandardCharsets;
33
import java.security.MessageDigest;
34
import java.security.NoSuchAlgorithmException;
35
import java.security.cert.Certificate;
36
import java.security.cert.CertificateException;
37
import java.security.cert.CertificateFactory;
38
import java.security.cert.X509Certificate;
39
import java.util.ArrayList;
40
import java.util.Arrays;
41
import java.util.Base64;
42
import java.util.Collection;
43
import java.util.Collections;
44
import java.util.List;
45
import java.util.Optional;
46
import lombok.Value;
47
48
public class CertificateParser {
49
  public static final String ID_FIDO_GEN_CE_AAGUID = "1.3.6.1.4.1.45724.1.1.4";
50
  public static final String OID_CRL_DISTRIBUTION_POINTS = "2.5.29.31";
51
  private static final Base64.Decoder BASE64_DECODER = Base64.getDecoder();
52
53
  private static final List<String> FIXSIG =
54
      Arrays.asList(
55
          "CN=Yubico U2F EE Serial 776137165",
56
          "CN=Yubico U2F EE Serial 1086591525",
57
          "CN=Yubico U2F EE Serial 1973679733",
58
          "CN=Yubico U2F EE Serial 13503277888",
59
          "CN=Yubico U2F EE Serial 13831167861",
60
          "CN=Yubico U2F EE Serial 14803321578");
61
62
  private static final int UNUSED_BITS_BYTE_INDEX_FROM_END = 257;
63
64
  public static X509Certificate parsePem(String pemEncodedCert) throws CertificateException {
65 1 1. parsePem : replaced return value with null for com/yubico/internal/util/CertificateParser::parsePem → KILLED
    return parseDer(
66
        pemEncodedCert
67
            .replaceAll("-----BEGIN CERTIFICATE-----", "")
68
            .replaceAll("-----END CERTIFICATE-----", "")
69
            .replaceAll("\n", ""));
70
  }
71
72
  public static X509Certificate parseDer(String base64DerEncodedCert) throws CertificateException {
73 1 1. parseDer : replaced return value with null for com/yubico/internal/util/CertificateParser::parseDer → KILLED
    return parseDer(BASE64_DECODER.decode(base64DerEncodedCert));
74
  }
75
76
  public static X509Certificate parseDer(byte[] derEncodedCert) throws CertificateException {
77 1 1. parseDer : replaced return value with null for com/yubico/internal/util/CertificateParser::parseDer → KILLED
    return parseDer(new ByteArrayInputStream(derEncodedCert));
78
  }
79
80
  public static X509Certificate parseDer(InputStream is) throws CertificateException {
81
    X509Certificate cert =
82
        (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
83
    // Some known certs have an incorrect "unused bits" value, which causes problems on newer
84
    // versions of BouncyCastle.
85 1 1. parseDer : negated conditional → SURVIVED
    if (FIXSIG.contains(cert.getSubjectX500Principal().getName())) {
86
      byte[] encoded = cert.getEncoded();
87
88 2 1. parseDer : changed conditional boundary → SURVIVED
2. parseDer : negated conditional → KILLED
      if (encoded.length >= UNUSED_BITS_BYTE_INDEX_FROM_END) {
89 1 1. parseDer : Replaced integer subtraction with addition → KILLED
        encoded[encoded.length - UNUSED_BITS_BYTE_INDEX_FROM_END] =
90
            0; // Fix the "unused bits" field (should always be 0).
91
      } else {
92
        throw new IllegalArgumentException(
93
            String.format(
94
                "Expected DER encoded cert to be at least %d bytes, was %d: %s",
95
                UNUSED_BITS_BYTE_INDEX_FROM_END, encoded.length, cert));
96
      }
97
98
      cert =
99
          (X509Certificate)
100
              CertificateFactory.getInstance("X.509")
101
                  .generateCertificate(new ByteArrayInputStream(encoded));
102
    }
103 1 1. parseDer : replaced return value with null for com/yubico/internal/util/CertificateParser::parseDer → KILLED
    return cert;
104
  }
105
106
  /**
107
   * Compute a Subject Key Identifier as defined as method (1) in RFC 5280 section 4.2.1.2.
108
   *
109
   * @throws NoSuchAlgorithmException if the SHA-1 hash algorithm is not available.
110
   * @see <a href="https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.2">Internet X.509
111
   *     Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile,
112
   *     section 4.2.1.2. Subject Key Identifier</a>
113
   */
114
  public static byte[] computeSubjectKeyIdentifier(final Certificate cert)
115
      throws NoSuchAlgorithmException {
116
    final byte[] spki = cert.getPublicKey().getEncoded();
117
118
    // SubjectPublicKeyInfo  ::=  SEQUENCE  {
119
    //     algorithm            AlgorithmIdentifier,
120
    //     subjectPublicKey     BIT STRING  }
121
    final byte algLength = spki[2 + 1];
122
123
    // BIT STRING begins with one octet specifying number of unused bits at end;
124
    // this is not included in the content to hash for a Subject Key Identifier.
125 2 1. computeSubjectKeyIdentifier : Replaced integer addition with subtraction → KILLED
2. computeSubjectKeyIdentifier : Replaced integer addition with subtraction → KILLED
    final int spkBitsStart = 2 + 2 + 2 + algLength + 1;
126
127 1 1. computeSubjectKeyIdentifier : replaced return value with null for com/yubico/internal/util/CertificateParser::computeSubjectKeyIdentifier → KILLED
    return MessageDigest.getInstance("SHA-1")
128
        .digest(Arrays.copyOfRange(spki, spkBitsStart, spki.length));
129
  }
130
131
  /**
132
   * Parses an AAGUID into bytes. Refer to <a
133
   * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-packed-attestation-cert-requirements">Packed
134
   * Attestation Statement Certificate Requirements</a> on the W3C web site for details of the ASN.1
135
   * structure that this method parses.
136
   *
137
   * @param bytes the bytes making up value of the extension
138
   * @return the bytes of the AAGUID
139
   */
140
  private static byte[] parseAaguid(byte[] bytes) {
141
142 2 1. parseAaguid : negated conditional → NO_COVERAGE
2. parseAaguid : negated conditional → NO_COVERAGE
    if (bytes != null && bytes.length == 20) {
143
      ByteBuffer buffer = ByteBuffer.wrap(bytes);
144
145 1 1. parseAaguid : negated conditional → NO_COVERAGE
      if (buffer.get() == (byte) 0x04
146 1 1. parseAaguid : negated conditional → NO_COVERAGE
          && buffer.get() == (byte) 0x12
147 1 1. parseAaguid : negated conditional → NO_COVERAGE
          && buffer.get() == (byte) 0x04
148 1 1. parseAaguid : negated conditional → NO_COVERAGE
          && buffer.get() == (byte) 0x10) {
149
        byte[] aaguidBytes = new byte[16];
150
        buffer.get(aaguidBytes);
151
152 1 1. parseAaguid : replaced return value with null for com/yubico/internal/util/CertificateParser::parseAaguid → NO_COVERAGE
        return aaguidBytes;
153
      }
154
    }
155
156
    throw new IllegalArgumentException(
157
        "X.509 extension 1.3.6.1.4.1.45724.1.1.4 (id-fido-gen-ce-aaguid) is not valid.");
158
  }
159
160
  public static Optional<byte[]> parseFidoAaguidExtension(X509Certificate cert) {
161
    Optional<byte[]> result =
162
        Optional.ofNullable(cert.getExtensionValue(ID_FIDO_GEN_CE_AAGUID))
163
            .map(CertificateParser::parseAaguid);
164 1 1. parseFidoAaguidExtension : removed call to java/util/Optional::ifPresent → NO_COVERAGE
    result.ifPresent(
165
        aaguid -> {
166 1 1. lambda$parseFidoAaguidExtension$0 : negated conditional → NO_COVERAGE
          if (cert.getCriticalExtensionOIDs().contains(ID_FIDO_GEN_CE_AAGUID)) {
167
            throw new IllegalArgumentException(
168
                String.format(
169
                    "X.509 extension %s (id-fido-gen-ce-aaguid) must not be marked critical.",
170
                    ID_FIDO_GEN_CE_AAGUID));
171
          }
172
        });
173 1 1. parseFidoAaguidExtension : replaced return value with Optional.empty for com/yubico/internal/util/CertificateParser::parseFidoAaguidExtension → NO_COVERAGE
    return result;
174
  }
175
176
  @Value
177
  public static class ParseCrlDistributionPointsExtensionResult {
178
    /**
179
     * The successfully parsed distribution point URLs. If the CRLDistributionPoints extension is
180
     * not present, this will be an empty list.
181
     */
182
    Collection<URL> distributionPoints;
183
184
    /**
185
     * True if and only if the CRLDistributionPoints extension is present and contains anything that
186
     * is not a <code>distributionPoint [0] DistributionPointName</code> containing a <code>
187
     * fullName [0] GeneralNames</code> containing exactly one <code>
188
     * uniformResourceIdentifier [6]  IA5String</code>
189
     */
190
    boolean anyDistributionPointUnsupported;
191
  }
192
193
  public static ParseCrlDistributionPointsExtensionResult parseCrlDistributionPointsExtension(
194
      X509Certificate cert) {
195
    final byte[] crldpExtension = cert.getExtensionValue(OID_CRL_DISTRIBUTION_POINTS);
196 1 1. parseCrlDistributionPointsExtension : negated conditional → NO_COVERAGE
    if (crldpExtension != null) {
197
      BinaryUtil.ParseDerResult<byte[]> octetString =
198
          BinaryUtil.parseDerOctetString(crldpExtension, 0);
199
      try {
200
        BinaryUtil.ParseDerResult<List<List<List<Optional<URL>>>>> distributionPoints =
201
            BinaryUtil.parseDerSequence(
202
                octetString.result,
203
                0,
204
                (outerSequenceDer, distributionPointOffset) ->
205 1 1. lambda$parseCrlDistributionPointsExtension$3 : replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$3 → NO_COVERAGE
                    BinaryUtil.parseDerSequence(
206
                        outerSequenceDer,
207
                        distributionPointOffset,
208
                        (innerSequenceDer, distributionPointChoiceOffset) -> {
209
                          // DistributionPoint ::= SEQUENCE {
210
                          //     distributionPoint       [0]     DistributionPointName OPTIONAL,
211
                          final BinaryUtil.ParseDerResult<Optional<Integer>> dpElementOffsets =
212
                              BinaryUtil.parseDerTaggedOrSkip(
213
                                  innerSequenceDer,
214
                                  distributionPointChoiceOffset,
215
                                  (byte) 0,
216
                                  true,
217
                                  BinaryUtil.DerTagClass.CONTEXT_SPECIFIC);
218 1 1. lambda$parseCrlDistributionPointsExtension$2 : negated conditional → NO_COVERAGE
                          if (dpElementOffsets.result.isPresent()) {
219
220
                            // DistributionPointName ::= CHOICE {
221
                            //     fullName                [0]     GeneralNames,
222
                            final BinaryUtil.ParseDerResult<Optional<Integer>>
223
                                dpNameElementOffsets =
224
                                    BinaryUtil.parseDerTaggedOrSkip(
225
                                        innerSequenceDer,
226
                                        dpElementOffsets.result.get(),
227
                                        (byte) 0,
228
                                        true,
229
                                        BinaryUtil.DerTagClass.CONTEXT_SPECIFIC);
230
231 1 1. lambda$parseCrlDistributionPointsExtension$2 : negated conditional → NO_COVERAGE
                            if (dpNameElementOffsets.result.isPresent()) {
232 1 1. lambda$parseCrlDistributionPointsExtension$2 : replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$2 → NO_COVERAGE
                              return BinaryUtil.parseDerSequenceContents(
233
                                  innerSequenceDer,
234
                                  dpNameElementOffsets.result.get(),
235
                                  dpNameElementOffsets.nextOffset,
236
                                  (generalNamesDer, generalNamesElementOffset) -> {
237
                                    // fullName                [0]     GeneralNames,
238
                                    // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
239
                                    // GeneralName ::= CHOICE {
240
                                    //     uniformResourceIdentifier [6]  IA5String,
241
                                    //
242
                                    // GeneralNames is defined in RFC 5280 appendix 2 which uses
243
                                    // IMPLICIT tagging
244
                                    // https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.2
245
                                    // so the SEQUENCE tag in GeneralNames is implicit.
246
                                    // The IA5String tag is also implicit from the CHOICE tag.
247
                                    final BinaryUtil.ParseDerResult<Optional<Integer>>
248
                                        generalNameOffsets =
249
                                            BinaryUtil.parseDerTaggedOrSkip(
250
                                                generalNamesDer,
251
                                                generalNamesElementOffset,
252
                                                (byte) 6,
253
                                                false,
254
                                                BinaryUtil.DerTagClass.CONTEXT_SPECIFIC);
255 1 1. lambda$parseCrlDistributionPointsExtension$1 : negated conditional → NO_COVERAGE
                                    if (generalNameOffsets.result.isPresent()) {
256
                                      String uriString =
257
                                          new String(
258
                                              Arrays.copyOfRange(
259
                                                  generalNamesDer,
260
                                                  generalNameOffsets.result.get(),
261
                                                  generalNameOffsets.nextOffset),
262
                                              StandardCharsets.US_ASCII);
263
                                      try {
264 1 1. lambda$parseCrlDistributionPointsExtension$1 : replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$1 → NO_COVERAGE
                                        return new BinaryUtil.ParseDerResult<>(
265
                                            Optional.of(new URL(uriString)),
266
                                            generalNameOffsets.nextOffset);
267
                                      } catch (MalformedURLException e) {
268
                                        throw new IllegalArgumentException(
269
                                            String.format(
270
                                                "Invalid URL in CRLDistributionPoints: %s",
271
                                                uriString),
272
                                            e);
273
                                      }
274
                                    } else {
275 1 1. lambda$parseCrlDistributionPointsExtension$1 : replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$1 → NO_COVERAGE
                                      return new BinaryUtil.ParseDerResult<>(
276
                                          Optional.empty(), generalNameOffsets.nextOffset);
277
                                    }
278
                                  });
279
                            }
280
                          }
281
282
                          // Ignore all other forms of distribution points
283 1 1. lambda$parseCrlDistributionPointsExtension$2 : replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$2 → NO_COVERAGE
                          return new BinaryUtil.ParseDerResult<>(
284
                              Collections.emptyList(), dpElementOffsets.nextOffset);
285
                        }));
286
287 1 1. parseCrlDistributionPointsExtension : replaced return value with null for com/yubico/internal/util/CertificateParser::parseCrlDistributionPointsExtension → NO_COVERAGE
        return distributionPoints.result.stream()
288
            .flatMap(Collection::stream)
289
            .flatMap(Collection::stream)
290
            .reduce(
291
                new ParseCrlDistributionPointsExtensionResult(new ArrayList<>(), false),
292
                (result, next) -> {
293 1 1. lambda$parseCrlDistributionPointsExtension$4 : negated conditional → NO_COVERAGE
                  if (next.isPresent()) {
294
                    List<URL> dp = new ArrayList<>(result.distributionPoints);
295
                    dp.add(next.get());
296 1 1. lambda$parseCrlDistributionPointsExtension$4 : replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$4 → NO_COVERAGE
                    return new ParseCrlDistributionPointsExtensionResult(
297
                        dp, result.anyDistributionPointUnsupported);
298
                  } else {
299 1 1. lambda$parseCrlDistributionPointsExtension$4 : replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$4 → NO_COVERAGE
                    return new ParseCrlDistributionPointsExtensionResult(
300
                        result.distributionPoints, true);
301
                  }
302
                },
303
                (resultA, resultB) -> {
304
                  List<URL> dp = new ArrayList<>(resultA.distributionPoints);
305
                  dp.addAll(resultB.distributionPoints);
306 1 1. lambda$parseCrlDistributionPointsExtension$5 : replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$5 → NO_COVERAGE
                  return new ParseCrlDistributionPointsExtensionResult(
307
                      dp,
308 1 1. lambda$parseCrlDistributionPointsExtension$5 : negated conditional → NO_COVERAGE
                      resultA.anyDistributionPointUnsupported
309 1 1. lambda$parseCrlDistributionPointsExtension$5 : negated conditional → NO_COVERAGE
                          || resultB.anyDistributionPointUnsupported);
310
                });
311
312
      } catch (IllegalArgumentException e) {
313
        throw new IllegalArgumentException(
314
            String.format(
315
                "X.509 extension %s (id-ce-cRLDistributionPoints) is incorrectly encoded.",
316
                OID_CRL_DISTRIBUTION_POINTS),
317
            e);
318
      }
319
320
    } else {
321 1 1. parseCrlDistributionPointsExtension : replaced return value with null for com/yubico/internal/util/CertificateParser::parseCrlDistributionPointsExtension → NO_COVERAGE
      return new ParseCrlDistributionPointsExtensionResult(Collections.emptySet(), false);
322
    }
323
  }
324
}

Mutations

65

1.1
Location : parsePem
Killed by : com.yubico.internal.util.CertificateParserTest.subjectPublicKeyIdentifierIsCorrect(com.yubico.internal.util.CertificateParserTest)
replaced return value with null for com/yubico/internal/util/CertificateParser::parsePem → KILLED

73

1.1
Location : parseDer
Killed by : com.yubico.internal.util.CertificateParserTest.subjectPublicKeyIdentifierIsCorrect(com.yubico.internal.util.CertificateParserTest)
replaced return value with null for com/yubico/internal/util/CertificateParser::parseDer → KILLED

77

1.1
Location : parseDer
Killed by : com.yubico.internal.util.CertificateParserTest.subjectPublicKeyIdentifierIsCorrect(com.yubico.internal.util.CertificateParserTest)
replaced return value with null for com/yubico/internal/util/CertificateParser::parseDer → KILLED

85

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

88

1.1
Location : parseDer
Killed by : com.yubico.internal.util.CertificateParserTest.parsePemDoesNotReturnNull(com.yubico.internal.util.CertificateParserTest)
negated conditional → KILLED

2.2
Location : parseDer
Killed by : none
changed conditional boundary → SURVIVED

89

1.1
Location : parseDer
Killed by : com.yubico.internal.util.CertificateParserTest.parsePemDoesNotReturnNull(com.yubico.internal.util.CertificateParserTest)
Replaced integer subtraction with addition → KILLED

103

1.1
Location : parseDer
Killed by : com.yubico.internal.util.CertificateParserTest.subjectPublicKeyIdentifierIsCorrect(com.yubico.internal.util.CertificateParserTest)
replaced return value with null for com/yubico/internal/util/CertificateParser::parseDer → KILLED

125

1.1
Location : computeSubjectKeyIdentifier
Killed by : com.yubico.internal.util.CertificateParserTest.subjectPublicKeyIdentifierIsCorrect(com.yubico.internal.util.CertificateParserTest)
Replaced integer addition with subtraction → KILLED

2.2
Location : computeSubjectKeyIdentifier
Killed by : com.yubico.internal.util.CertificateParserTest.subjectPublicKeyIdentifierIsCorrect(com.yubico.internal.util.CertificateParserTest)
Replaced integer addition with subtraction → KILLED

127

1.1
Location : computeSubjectKeyIdentifier
Killed by : com.yubico.internal.util.CertificateParserTest.subjectPublicKeyIdentifierIsCorrect(com.yubico.internal.util.CertificateParserTest)
replaced return value with null for com/yubico/internal/util/CertificateParser::computeSubjectKeyIdentifier → KILLED

142

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

2.2
Location : parseAaguid
Killed by : none
negated conditional → NO_COVERAGE

145

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

146

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

147

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

148

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

152

1.1
Location : parseAaguid
Killed by : none
replaced return value with null for com/yubico/internal/util/CertificateParser::parseAaguid → NO_COVERAGE

164

1.1
Location : parseFidoAaguidExtension
Killed by : none
removed call to java/util/Optional::ifPresent → NO_COVERAGE

166

1.1
Location : lambda$parseFidoAaguidExtension$0
Killed by : none
negated conditional → NO_COVERAGE

173

1.1
Location : parseFidoAaguidExtension
Killed by : none
replaced return value with Optional.empty for com/yubico/internal/util/CertificateParser::parseFidoAaguidExtension → NO_COVERAGE

196

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

205

1.1
Location : lambda$parseCrlDistributionPointsExtension$3
Killed by : none
replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$3 → NO_COVERAGE

218

1.1
Location : lambda$parseCrlDistributionPointsExtension$2
Killed by : none
negated conditional → NO_COVERAGE

231

1.1
Location : lambda$parseCrlDistributionPointsExtension$2
Killed by : none
negated conditional → NO_COVERAGE

232

1.1
Location : lambda$parseCrlDistributionPointsExtension$2
Killed by : none
replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$2 → NO_COVERAGE

255

1.1
Location : lambda$parseCrlDistributionPointsExtension$1
Killed by : none
negated conditional → NO_COVERAGE

264

1.1
Location : lambda$parseCrlDistributionPointsExtension$1
Killed by : none
replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$1 → NO_COVERAGE

275

1.1
Location : lambda$parseCrlDistributionPointsExtension$1
Killed by : none
replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$1 → NO_COVERAGE

283

1.1
Location : lambda$parseCrlDistributionPointsExtension$2
Killed by : none
replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$2 → NO_COVERAGE

287

1.1
Location : parseCrlDistributionPointsExtension
Killed by : none
replaced return value with null for com/yubico/internal/util/CertificateParser::parseCrlDistributionPointsExtension → NO_COVERAGE

293

1.1
Location : lambda$parseCrlDistributionPointsExtension$4
Killed by : none
negated conditional → NO_COVERAGE

296

1.1
Location : lambda$parseCrlDistributionPointsExtension$4
Killed by : none
replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$4 → NO_COVERAGE

299

1.1
Location : lambda$parseCrlDistributionPointsExtension$4
Killed by : none
replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$4 → NO_COVERAGE

306

1.1
Location : lambda$parseCrlDistributionPointsExtension$5
Killed by : none
replaced return value with null for com/yubico/internal/util/CertificateParser::lambda$parseCrlDistributionPointsExtension$5 → NO_COVERAGE

308

1.1
Location : lambda$parseCrlDistributionPointsExtension$5
Killed by : none
negated conditional → NO_COVERAGE

309

1.1
Location : lambda$parseCrlDistributionPointsExtension$5
Killed by : none
negated conditional → NO_COVERAGE

321

1.1
Location : parseCrlDistributionPointsExtension
Killed by : none
replaced return value with null for com/yubico/internal/util/CertificateParser::parseCrlDistributionPointsExtension → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.15.0