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()