diff --git a/yubico-util/src/main/java/com/yubico/internal/util/BinaryUtil.java b/yubico-util/src/main/java/com/yubico/internal/util/BinaryUtil.java
index 037be9dec..c34858dbc 100644
--- a/yubico-util/src/main/java/com/yubico/internal/util/BinaryUtil.java
+++ b/yubico-util/src/main/java/com/yubico/internal/util/BinaryUtil.java
@@ -261,8 +261,8 @@ private static class ParseDerAnyResult {
DerTagClass tagClass;
boolean constructed;
byte tagValue;
- byte[] content;
- int nextOffset;
+ int valueStart;
+ int valueEnd;
}
@Value
@@ -342,14 +342,15 @@ private static ParseDerAnyResult parseDerAny(@NonNull byte[] der, int offset) {
DerTagClass.parse(tag),
(tag & 0x20) != 0,
(byte) (tag & 0x1f),
- Arrays.copyOfRange(der, contentLen.nextOffset, contentEnd),
+ contentLen.nextOffset,
contentEnd);
}
}
/**
- * Parse a DER header with the given tag value, constructed bit and tag class, and return a copy
- * of the value octets. If any of the three criteria do not match, return empty instead.
+ * Parse a DER header with the given tag value, constructed bit and tag class, and return the
+ * start and end offsets of the value octets. If any of the three criteria do not match, return
+ * empty instead.
*
* @param der DER source to read from.
* @param offset The offset in der
from which to start reading.
@@ -359,11 +360,12 @@ private static ParseDerAnyResult parseDerAny(@NonNull byte[] der, int offset) {
* bit) of the tag octet.
* @param expectTagClass The expected tag class. This is the 2 most significant bits of the tag
* octet.
- * @return A copy of the value octets, if the parsed tag matches expectTag
,
+ * @return The start and end offsets of the value octets, if the parsed tag matches
+ * expectTag
,
* constructed
and expectTagClass
, otherwise empty. {@link
* ParseDerResult#nextOffset} is always returned.
*/
- public static ParseDerResult> parseDerTaggedOrSkip(
+ public static ParseDerResult> parseDerTaggedOrSkip(
@NonNull byte[] der,
int offset,
byte expectTag,
@@ -373,16 +375,16 @@ public static ParseDerResult> parseDerTaggedOrSkip(
if (result.tagValue == expectTag
&& result.constructed == constructed
&& result.tagClass == expectTagClass) {
- return new ParseDerResult<>(Optional.of(result.content), result.nextOffset);
+ return new ParseDerResult<>(Optional.of(result.valueStart), result.valueEnd);
} else {
- return new ParseDerResult<>(Optional.empty(), result.nextOffset);
+ return new ParseDerResult<>(Optional.empty(), result.valueEnd);
}
}
/**
- * Parse a DER header with the given tag value, constructed bit and tag class, and return a copy
- * of the value octets. If any of the three criteria do not match, throw an {@link
- * IllegalArgumentException}.
+ * Parse a DER header with the given tag value, constructed bit and tag class, and return the
+ * start and end offsets of the value octets. If any of the three criteria do not match, throw an
+ * {@link IllegalArgumentException}.
*
* @param der DER source to read from.
* @param offset The offset in der
from which to start reading.
@@ -392,11 +394,12 @@ public static ParseDerResult> parseDerTaggedOrSkip(
* bit) of the tag octet.
* @param expectTagClass The expected tag class. This is the 2 most significant bits of the tag
* octet.
- * @return A copy of the value octets, if the parsed tag matches expectTag
,
+ * @return The start and end offsets of the value octets, if the parsed tag matches
+ * expectTag
,
* constructed
and expectTagClass
, otherwise empty. {@link
* ParseDerResult#nextOffset} is always returned.
*/
- private static ParseDerResult parseDerTagged(
+ private static ParseDerResult parseDerTagged(
@NonNull byte[] der,
int offset,
byte expectTag,
@@ -406,7 +409,7 @@ private static ParseDerResult parseDerTagged(
if (result.tagValue == expectTag) {
if (result.constructed == constructed) {
if (result.tagClass == expectTagClass) {
- return new ParseDerResult<>(result.content, result.nextOffset);
+ return new ParseDerResult<>(result.valueStart, result.valueEnd);
} else {
throw new IllegalArgumentException(
String.format(
@@ -476,16 +479,19 @@ public static ParseDerResult> parseDerSequenceContents(
*/
public static ParseDerResult> parseDerSequence(
@NonNull byte[] der, int offset, @NonNull ParseDerSequenceElementFunction parseElement) {
- final ParseDerResult seq =
+ final ParseDerResult seq =
parseDerTagged(der, offset, (byte) 0x10, true, DerTagClass.UNIVERSAL);
final ParseDerResult> res =
- parseDerSequenceContents(seq.result, 0, seq.result.length, parseElement);
+ parseDerSequenceContents(der, seq.result, seq.nextOffset, parseElement);
return new ParseDerResult<>(res.result, seq.nextOffset);
}
/** Parse an Octet String. */
public static ParseDerResult parseDerOctetString(@NonNull byte[] der, int offset) {
- return parseDerTagged(der, offset, (byte) 0x04, false, DerTagClass.UNIVERSAL);
+ ParseDerResult res =
+ parseDerTagged(der, offset, (byte) 0x04, false, DerTagClass.UNIVERSAL);
+ return new ParseDerResult<>(
+ Arrays.copyOfRange(der, res.result, res.nextOffset), res.nextOffset);
}
public static byte[] encodeDerObjectId(@NonNull byte[] oid) {
diff --git a/yubico-util/src/main/java/com/yubico/internal/util/CertificateParser.java b/yubico-util/src/main/java/com/yubico/internal/util/CertificateParser.java
index 9703a773c..f0314f0c8 100755
--- a/yubico-util/src/main/java/com/yubico/internal/util/CertificateParser.java
+++ b/yubico-util/src/main/java/com/yubico/internal/util/CertificateParser.java
@@ -208,30 +208,31 @@ public static ParseCrlDistributionPointsExtensionResult parseCrlDistributionPoin
(innerSequenceDer, distributionPointChoiceOffset) -> {
// DistributionPoint ::= SEQUENCE {
// distributionPoint [0] DistributionPointName OPTIONAL,
- final BinaryUtil.ParseDerResult> dpElement =
+ final BinaryUtil.ParseDerResult> dpElementOffsets =
BinaryUtil.parseDerTaggedOrSkip(
innerSequenceDer,
distributionPointChoiceOffset,
(byte) 0,
true,
BinaryUtil.DerTagClass.CONTEXT_SPECIFIC);
- if (dpElement.result.isPresent()) {
+ if (dpElementOffsets.result.isPresent()) {
// DistributionPointName ::= CHOICE {
// fullName [0] GeneralNames,
- final BinaryUtil.ParseDerResult> dpNameElement =
- BinaryUtil.parseDerTaggedOrSkip(
- dpElement.result.get(),
- 0,
- (byte) 0,
- true,
- BinaryUtil.DerTagClass.CONTEXT_SPECIFIC);
+ final BinaryUtil.ParseDerResult>
+ dpNameElementOffsets =
+ BinaryUtil.parseDerTaggedOrSkip(
+ innerSequenceDer,
+ dpElementOffsets.result.get(),
+ (byte) 0,
+ true,
+ BinaryUtil.DerTagClass.CONTEXT_SPECIFIC);
- if (dpNameElement.result.isPresent()) {
+ if (dpNameElementOffsets.result.isPresent()) {
return BinaryUtil.parseDerSequenceContents(
- dpNameElement.result.get(),
- 0,
- dpNameElement.result.get().length,
+ innerSequenceDer,
+ dpNameElementOffsets.result.get(),
+ dpNameElementOffsets.nextOffset,
(generalNamesDer, generalNamesElementOffset) -> {
// fullName [0] GeneralNames,
// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
@@ -243,21 +244,26 @@ public static ParseCrlDistributionPointsExtensionResult parseCrlDistributionPoin
// https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.2
// so the SEQUENCE tag in GeneralNames is implicit.
// The IA5String tag is also implicit from the CHOICE tag.
- final BinaryUtil.ParseDerResult> generalName =
- BinaryUtil.parseDerTaggedOrSkip(
- generalNamesDer,
- generalNamesElementOffset,
- (byte) 6,
- false,
- BinaryUtil.DerTagClass.CONTEXT_SPECIFIC);
- if (generalName.result.isPresent()) {
+ final BinaryUtil.ParseDerResult>
+ generalNameOffsets =
+ BinaryUtil.parseDerTaggedOrSkip(
+ generalNamesDer,
+ generalNamesElementOffset,
+ (byte) 6,
+ false,
+ BinaryUtil.DerTagClass.CONTEXT_SPECIFIC);
+ if (generalNameOffsets.result.isPresent()) {
String uriString =
new String(
- generalName.result.get(), StandardCharsets.US_ASCII);
+ Arrays.copyOfRange(
+ generalNamesDer,
+ generalNameOffsets.result.get(),
+ generalNameOffsets.nextOffset),
+ StandardCharsets.US_ASCII);
try {
return new BinaryUtil.ParseDerResult<>(
Optional.of(new URL(uriString)),
- generalName.nextOffset);
+ generalNameOffsets.nextOffset);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(
String.format(
@@ -267,7 +273,7 @@ public static ParseCrlDistributionPointsExtensionResult parseCrlDistributionPoin
}
} else {
return new BinaryUtil.ParseDerResult<>(
- Optional.empty(), generalName.nextOffset);
+ Optional.empty(), generalNameOffsets.nextOffset);
}
});
}
@@ -275,7 +281,7 @@ public static ParseCrlDistributionPointsExtensionResult parseCrlDistributionPoin
// Ignore all other forms of distribution points
return new BinaryUtil.ParseDerResult<>(
- Collections.emptyList(), dpElement.nextOffset);
+ Collections.emptyList(), dpElementOffsets.nextOffset);
}));
return distributionPoints.result.stream()