ASN1. Indefinitive length encoding support with added tests
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java
index c1f46fc..6da9a25 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java
@@ -19,9 +19,10 @@
*/
package org.apache.kerby.asn1;
-import org.apache.kerby.asn1.type.Asn1Item;
+import org.apache.kerby.asn1.type.Asn1ParsingContainer;
import org.apache.kerby.asn1.type.Asn1Type;
import org.apache.kerby.asn1.util.Asn1Reader1;
+import org.apache.kerby.asn1.util.Asn1Reader2;
import org.apache.kerby.asn1.util.HexUtil;
import java.io.IOException;
@@ -54,18 +55,30 @@
return decode(ByteBuffer.wrap(content));
}
+ /*
public static Asn1Type decode(ByteBuffer content) throws IOException {
Asn1Reader1 reader = new Asn1Reader1(content);
Asn1Header header = reader.readHeader();
- Asn1Item result = new Asn1Item(header.getTag(), header.getValueBuffer());
+ Asn1Item result = new Asn1Item(header.getTag(), header.getBuffer());
result.useDefinitiveLength(header.isDefinitiveLength());
return result;
+ }*/
+
+ public static Asn1Type decode(ByteBuffer content) throws IOException {
+ return Asn1ParsingContainer.decodeOne(content);
}
public static void dump(Asn1Type value) {
- Asn1Dumper dumper = new Asn1Dumper();
+ dump(value, true);
+ }
+
+ public static void dump(Asn1Type value, boolean withType) {
+ Asn1Dumper dumper = new Asn1Dumper(withType);
+ if (!withType) {
+ dumper.dumpTypeInfo(value.getClass());
+ }
dumper.dumpType(0, value);
String output = dumper.output();
System.out.println(output);
@@ -77,6 +90,8 @@
Asn1Dumper dumper = new Asn1Dumper();
byte[] data = HexUtil.hex2bytes(hexStr);
dumper.dump(data);
+ String output = dumper.output();
+ System.out.println(output);
}
public static void dump(byte[] content) throws IOException {
@@ -85,6 +100,8 @@
System.out.println(hexStr);
Asn1Dumper dumper = new Asn1Dumper();
dumper.dump(content);
+ String output = dumper.output();
+ System.out.println(output);
}
public static void dump(ByteBuffer content) throws IOException {
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java
index 739e59d..4eee1e2 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java
@@ -19,6 +19,7 @@
*/
package org.apache.kerby.asn1;
+import org.apache.kerby.asn1.type.Asn1ParsingItem;
import org.apache.kerby.asn1.type.Asn1Simple;
import org.apache.kerby.asn1.type.Asn1Type;
@@ -26,9 +27,21 @@
import java.nio.ByteBuffer;
public final class Asn1Dumper {
-
+ private boolean withType;
private StringBuilder builder = new StringBuilder();
+ public Asn1Dumper() {
+ this.withType = true;
+ }
+
+ public Asn1Dumper(boolean withType) {
+ this.withType = withType;
+ }
+
+ public boolean withType() {
+ return withType;
+ }
+
public String output() {
return builder.toString();
}
@@ -50,17 +63,21 @@
dumpType(0, value);
}
- public void dumpType(int indents, Asn1Type value) {
+ public Asn1Dumper dumpType(int indents, Asn1Type value) {
if (value == null) {
indent(indents).append("null");
} else if (value instanceof Asn1Simple) {
indent(indents).append(value.toString());
+ } else if (value instanceof Asn1ParsingItem) {
+ indent(indents).append(value.toString());
} else if (value instanceof Asn1Dumpable) {
Asn1Dumpable dumpable = (Asn1Dumpable) value;
dumpable.dumpWith(this, indents);
} else {
append("<UNKNOWN>");
}
+
+ return this;
}
public Asn1Dumper indent(int numSpaces) {
@@ -84,6 +101,23 @@
return this;
}
+ public Asn1Dumper dumpTypeInfo(Class<?> cls) {
+ appendType(cls).newLine();
+ return this;
+ }
+
+ public Asn1Dumper dumpTypeInfo(int indents, Class<?> cls) {
+ if (withType()) {
+ indent(indents).appendType(cls).newLine();
+ }
+ return this;
+ }
+
+ private Asn1Dumper appendType(Class<?> cls) {
+ builder.append("<").append(cls.getSimpleName()).append(">");
+ return this;
+ }
+
public Asn1Dumper newLine() {
builder.append("\n");
return this;
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Header.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Header.java
index 0fbd047..1284039 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Header.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Header.java
@@ -24,24 +24,63 @@
public class Asn1Header {
private Tag tag;
private int length;
- private ByteBuffer valueBuffer;
+ private int bodyStart;
+ private int bodyEnd;
+ private ByteBuffer buffer;
- public Asn1Header(Tag tag, int length, ByteBuffer valueBuffer) {
+ public Asn1Header(Tag tag, int length,
+ int bodyStart, ByteBuffer buffer) {
this.tag = tag;
this.length = length;
- this.valueBuffer = valueBuffer;
+ this.bodyStart = bodyStart;
+ this.buffer = buffer;
+
+ this.bodyEnd = isDefinitiveLength() ? bodyStart + length : -1;
}
public Tag getTag() {
return tag;
}
+ public int getActualBodyLength() {
+ if (isDefinitiveLength()) {
+ return getLength();
+ } else if (getBodyEnd() != -1) {
+ return getBodyEnd() - getBodyStart();
+ }
+ return -1;
+ }
+
public int getLength() {
return length;
}
- public ByteBuffer getValueBuffer() {
- return valueBuffer;
+ public int getBodyStart() {
+ return bodyStart;
+ }
+
+ public int getBodyEnd() {
+ return bodyEnd;
+ }
+
+ public void setBodyEnd(int bodyEnd) {
+ this.bodyEnd = bodyEnd;
+ }
+
+ public ByteBuffer getBuffer() {
+ return buffer;
+ }
+
+ public ByteBuffer getBodyBuffer() {
+ ByteBuffer result = buffer.duplicate();
+ result.position(bodyStart);
+
+ int end = getBodyEnd();
+ if (end >= bodyStart) {
+ result.limit(end);
+ }
+
+ return result;
}
public boolean isEOC() {
@@ -51,4 +90,11 @@
public boolean isDefinitiveLength() {
return length != -1;
}
+
+ public byte[] readBodyBytes() {
+ ByteBuffer bodyBuffer = getBodyBuffer();
+ byte[] result = new byte[bodyBuffer.remaining()];
+ bodyBuffer.get(result);
+ return result;
+ }
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Tag.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Tag.java
index 2cf5e6b..6b19e1e 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/Tag.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/Tag.java
@@ -97,8 +97,8 @@
return tagClass().isContextSpecific();
}
- public boolean isTagged() {
- return tagClass().isTagged();
+ public boolean isSpecific() {
+ return tagClass().isSpecific();
}
@Override
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/TagClass.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/TagClass.java
index 8070692..8d02917 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/TagClass.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/TagClass.java
@@ -63,7 +63,7 @@
return this == CONTEXT_SPECIFIC;
}
- public boolean isTagged() {
+ public boolean isSpecific() {
return this == APPLICATION || this == CONTEXT_SPECIFIC;
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Any.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Any.java
index 617ec12..cda997c 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Any.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Any.java
@@ -20,6 +20,7 @@
package org.apache.kerby.asn1.type;
import org.apache.kerby.asn1.Asn1FieldInfo;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.UniversalTag;
import java.io.IOException;
@@ -66,6 +67,11 @@
}
@Override
+ protected void decodeBody(Asn1Header header) throws IOException {
+
+ }
+
+ @Override
protected void encodeBody(ByteBuffer buffer) {
((AbstractAsn1Type<?>) getValue()).encodeBody(buffer);
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BmpString.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BmpString.java
index c915e94..7c3d920 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BmpString.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BmpString.java
@@ -19,10 +19,10 @@
*/
package org.apache.kerby.asn1.type;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.UniversalTag;
import java.io.IOException;
-import java.nio.ByteBuffer;
public class Asn1BmpString extends Asn1Simple<String> {
public Asn1BmpString() {
@@ -61,10 +61,10 @@
}
@Override
- protected void decodeBody(ByteBuffer content) throws IOException {
- if (content.remaining() % 2 != 0) {
+ protected void decodeBody(Asn1Header header) throws IOException {
+ if (header.getLength() % 2 != 0) {
throw new IOException("Bad stream, BMP string expecting multiple of 2 bytes");
}
- super.decodeBody(content);
+ super.decodeBody(header);
}
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Boolean.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Boolean.java
index 319011d..61b8ef2 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Boolean.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Boolean.java
@@ -19,10 +19,10 @@
*/
package org.apache.kerby.asn1.type;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.UniversalTag;
import java.io.IOException;
-import java.nio.ByteBuffer;
/**
* ASN1 Boolean type
@@ -55,11 +55,11 @@
}
@Override
- protected void decodeBody(ByteBuffer content) throws IOException {
- if (content.remaining() != 1) {
+ protected void decodeBody(Asn1Header header) throws IOException {
+ if (header.getLength() != 1) {
throw new IOException("More than 1 byte found for Boolean");
}
- super.decodeBody(content);
+ super.decodeBody(header);
}
@Override
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Choice.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Choice.java
index e7eb853..dd6d873 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Choice.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Choice.java
@@ -21,6 +21,7 @@
import org.apache.kerby.asn1.Asn1;
import org.apache.kerby.asn1.Asn1FieldInfo;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.EnumType;
import org.apache.kerby.asn1.TaggingOption;
import org.apache.kerby.asn1.UniversalTag;
@@ -108,6 +109,11 @@
fields[foundPos] = item.getValue();
}
+ @Override
+ protected void decodeBody(Asn1Header header) throws IOException {
+
+ }
+
protected void decodeBody(ByteBuffer content) throws IOException {
// Not used
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionOf.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionOf.java
index 26acc0b..5e4bd70 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionOf.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionOf.java
@@ -6,19 +6,21 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.kerby.asn1.type;
+import org.apache.kerby.asn1.Asn1Dumper;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.UniversalTag;
import java.io.IOException;
@@ -26,33 +28,39 @@
import java.util.ArrayList;
import java.util.List;
-public abstract class Asn1CollectionOf<T extends Asn1Type> extends Asn1Collection
-{
+public abstract class Asn1CollectionOf<T extends Asn1Type>
+ extends Asn1Collection {
+
+ private List<T> elements = new ArrayList<>();
+
public Asn1CollectionOf(UniversalTag universalTag) {
super(universalTag);
}
- public List<T> getElements() {
+ @Override
+ protected void decodeBody(Asn1Header header) throws IOException {
+ super.decodeBody(header);
+
+ decodeElements();
+ }
+
+ private void decodeElements() throws IOException {
List<Asn1Type> items = getValue();
- int nElements = items != null ? items.size() : 0;
- List<T> results = new ArrayList<T>(nElements);
- if (nElements > 0) {
- for (Asn1Type itemObj : items) {
- if (itemObj instanceof Asn1Item) {
- Asn1Item item = (Asn1Item) itemObj;
- if (!item.isFullyDecoded()) {
- try {
- item.decodeValueAs(getElementType());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- itemObj = item.getValue();
+ for (Asn1Type itemObj : items) {
+ if (itemObj instanceof Asn1Item) {
+ Asn1Item item = (Asn1Item) itemObj;
+ if (!item.isFullyDecoded()) {
+ Asn1Type tmpValue = createElement();
+ item.decodeValueWith(tmpValue);
}
- results.add((T) itemObj);
+ itemObj = item.getValue();
}
+ elements.add((T) itemObj);
}
- return results;
+ }
+
+ public List<T> getElements() {
+ return elements;
}
public void setElements(List<T> elements) {
@@ -71,11 +79,31 @@
public void addElement(T element) {
super.addItem(element);
+ this.elements.add(element);
}
- protected Class<T> getElementType() {
+ private Class<T> getElementType() {
Class<T> elementType = (Class<T>) ((ParameterizedType)
- getClass().getGenericSuperclass()).getActualTypeArguments()[0];
+ getClass().getGenericSuperclass()).getActualTypeArguments()[0];
return elementType;
}
+
+ protected T createElement() throws IOException {
+ Class<?> eleType = getElementType();
+ try {
+ T result = (T) eleType.newInstance();
+ return result;
+ } catch (Exception e) {
+ throw new IOException("Failed to create element type", e);
+ }
+ }
+
+ @Override
+ public void dumpWith(Asn1Dumper dumper, int indents) {
+ dumper.dumpTypeInfo(indents, getClass());
+
+ for (Asn1Type aObj : elements) {
+ dumper.dumpType(indents + 4, aObj).newLine();
+ }
+ }
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionType.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionType.java
index 36082c4..70b78da 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionType.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1CollectionType.java
@@ -22,12 +22,14 @@
import org.apache.kerby.asn1.Asn1Dumpable;
import org.apache.kerby.asn1.Asn1Dumper;
import org.apache.kerby.asn1.Asn1FieldInfo;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.EnumType;
import org.apache.kerby.asn1.TaggingOption;
import org.apache.kerby.asn1.UniversalTag;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.List;
/**
* For collection type that may consist of tagged fields
@@ -80,15 +82,16 @@
}
@Override
- protected void decodeBody(ByteBuffer content) throws IOException {
- initFields();
+ protected void decodeBody(Asn1Header header) throws IOException {
+ checkAndInitFields();
Asn1Collection coll = createCollection();
coll.setLazy(true);
- coll.decode(tag(), content);
+ coll.decodeBody(header);
int lastPos = -1, foundPos = -1;
- for (Asn1Type itemObj : coll.getValue()) {
+ List<Asn1Type> decodedItems = coll.getValue();
+ for (Asn1Type itemObj : decodedItems) {
foundPos = -1;
Asn1Item item = (Asn1Item) itemObj;
for (int i = lastPos + 1; i < fieldInfos.length; ++i) {
@@ -123,12 +126,15 @@
}
}
- private void initFields() {
+ private void checkAndInitFields() {
for (int i = 0; i < fieldInfos.length; ++i) {
- try {
- fields[i] = fieldInfos[i].getType().newInstance();
- } catch (Exception e) {
- throw new IllegalArgumentException("Bad field info specified at index of " + i, e);
+ if (fields[i] == null) {
+ try {
+ fields[i] = fieldInfos[i].getType().newInstance();
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "Bad field info specified at index of " + i, e);
+ }
}
}
}
@@ -203,9 +209,7 @@
@Override
public void dumpWith(Asn1Dumper dumper, int indents) {
- String type = getClass().getSimpleName();
-
- dumper.indent(indents).append(type).newLine();
+ dumper.dumpTypeInfo(indents, getClass());
String fdName;
for (int i = 0; i < fieldInfos.length; i++) {
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Constructed.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Constructed.java
index 6008282..0ffa1db 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Constructed.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Constructed.java
@@ -19,7 +19,9 @@
*/
package org.apache.kerby.asn1.type;
-import org.apache.kerby.asn1.Asn1;
+import org.apache.kerby.asn1.Asn1Dumpable;
+import org.apache.kerby.asn1.Asn1Dumper;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.Tag;
import java.io.IOException;
@@ -30,7 +32,9 @@
/**
* ASN1 constructed types, mainly structured ones, but also some primitive ones.
*/
-public class Asn1Constructed extends AbstractAsn1Type<List<Asn1Type>> {
+public class Asn1Constructed
+ extends AbstractAsn1Type<List<Asn1Type>> implements Asn1Dumpable {
+
private boolean lazy = false;
public Asn1Constructed(Tag tag) {
@@ -78,30 +82,27 @@
}
@Override
- protected void decodeBody(ByteBuffer content) throws IOException {
- while (content.remaining() > 0) {
- Asn1Item item = (Asn1Item) Asn1.decode(content);
- if (item != null) {
- if (item.isSimple() && !isLazy()) {
- item.decodeValueAsSimple();
- addItem(item.getValue());
- } else {
- addItem(item);
- }
+ protected void decodeBody(Asn1Header header) throws IOException {
+ Asn1ParsingContainer container = new Asn1ParsingContainer(tag());
+ container.decode(header);
+
+ for (Asn1ParsingResult result : container.getParsingResults()) {
+ Asn1Item item = new Asn1Item(result);
+ if (item.isSimple() && !isLazy()) {
+ item.decodeValueAsSimple();
+ addItem(item.getValue());
+ } else {
+ addItem(item);
}
}
}
@Override
- public String toString() {
- String typeStr;
- if (tag().isUniversal()) {
- typeStr = tag().universalTag().toStr();
- } else if (tag().isAppSpecific()) {
- typeStr = "application " + tagNo();
- } else {
- typeStr = "[" + tagNo() + "]";
+ public void dumpWith(Asn1Dumper dumper, int indents) {
+ dumper.indent(indents).append(toString()).newLine();
+
+ for (Asn1Type aObj : getValue()) {
+ dumper.dumpType(indents + 4, aObj).newLine();
}
- return typeStr;
}
-}
+}
\ No newline at end of file
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Eoc.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Eoc.java
index fe80979..f8610ea 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Eoc.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Eoc.java
@@ -19,10 +19,10 @@
*/
package org.apache.kerby.asn1.type;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.UniversalTag;
import java.io.IOException;
-import java.nio.ByteBuffer;
/**
* To represent Asn1 End Of Content type
@@ -46,9 +46,14 @@
}
@Override
- protected void decodeBody(ByteBuffer content) throws IOException {
- if (content.remaining() != 0) {
+ protected void decodeBody(Asn1Header header) throws IOException {
+ if (header.getLength() != 0) {
throw new IOException("Unexpected bytes found for EOC");
}
}
+
+ @Override
+ public String toString() {
+ return "EOC";
+ }
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1GeneralizedTime.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1GeneralizedTime.java
index 0c2e1f9..48d0cef 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1GeneralizedTime.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1GeneralizedTime.java
@@ -43,7 +43,7 @@
}
public Asn1GeneralizedTime(Date date) {
- super(UniversalTag.UTC_TIME, date);
+ super(UniversalTag.GENERALIZED_TIME, date);
}
protected void toValue() throws IOException {
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Item.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Item.java
index efd0673..b3994ff 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Item.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Item.java
@@ -20,6 +20,7 @@
package org.apache.kerby.asn1.type;
import org.apache.kerby.asn1.Asn1Factory;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.Tag;
import org.apache.kerby.asn1.TaggingOption;
@@ -36,34 +37,27 @@
* tagged value.
*
* For not fully decoded value, you tell your case using isSimple/isCollection/
- * isTagged/isContextSpecific etc., then call decodeValueAsSimple/
+ * isSpecific/isContextSpecific etc., then call decodeValueAsSimple/
* decodeValueAsCollection/decodeValueAsImplicitTagged/decodeValueAsExplicitTagged etc.
* to decode it fully. Or if you have already derived the value holder or
* the holder type, you can use decodeValueWith or decodeValueAs with your
* holder or hodler type.
*/
public class Asn1Item extends AbstractAsn1Type<Asn1Type> {
- private ByteBuffer bodyContent;
+ private final Asn1ParsingResult parsingResult;
- public Asn1Item(Asn1Type value) {
- super(value.tag(), value);
+ public Asn1Item(Asn1ParsingResult parsingResult) {
+ super(parsingResult.tag());
+ this.parsingResult = parsingResult;
}
- public Asn1Item(Tag tag) {
+ public Asn1Item(Tag tag, Asn1ParsingResult parsingResult) {
super(tag);
+ this.parsingResult = parsingResult;
}
- public Asn1Item(Tag tag, ByteBuffer bodyContent) {
- super(tag);
- this.bodyContent = bodyContent;
- }
-
- public void setBodyContent(ByteBuffer bodyContent) {
- this.bodyContent = bodyContent;
- }
-
- public ByteBuffer getBodyContent() {
- return bodyContent;
+ public Asn1ParsingResult getParsingResult() {
+ return parsingResult;
}
@Override
@@ -71,7 +65,7 @@
if (getValue() != null) {
return ((AbstractAsn1Type<?>) getValue()).encodingBodyLength();
}
- return (int) bodyContent.remaining();
+ return parsingResult.encodingBodyLength();
}
@Override
@@ -82,8 +76,8 @@
}
@Override
- protected void decodeBody(ByteBuffer bodyContent) throws IOException {
- this.bodyContent = bodyContent;
+ protected void decodeBody(Asn1Header header) throws IOException {
+ this.parsingResult.decodeBody(header);
}
public boolean isFullyDecoded() {
@@ -132,15 +126,15 @@
public void decodeValueWith(Asn1Type value) throws IOException {
setValue(value);
value.useDefinitiveLength(isDefinitiveLength());
- ((AbstractAsn1Type<?>) value).decode(tag(), bodyContent);
+ ((Asn1Object) value).decode(parsingResult.getHeader());
}
public void decodeValueWith(Asn1Type value, TaggingOption taggingOption) throws IOException {
- if (!isTagged()) {
+ if (!isTagSpecific()) {
throw new IllegalArgumentException(
"Attempting to decode non-tagged value using tagging way");
}
- ((Asn1Object) value).taggedDecode(tag(), getBodyContent(), taggingOption);
+ ((Asn1Object) value).taggedDecode(parsingResult.getHeader(), taggingOption);
setValue(value);
}
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Null.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Null.java
index f1a4416..6affb95 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Null.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Null.java
@@ -19,10 +19,10 @@
*/
package org.apache.kerby.asn1.type;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.UniversalTag;
import java.io.IOException;
-import java.nio.ByteBuffer;
/**
* The Asn1 Null type
@@ -46,9 +46,14 @@
}
@Override
- protected void decodeBody(ByteBuffer content) throws IOException {
- if (content.remaining() != 0) {
+ protected void decodeBody(Asn1Header header) throws IOException {
+ if (header.getLength() != 0) {
throw new IOException("Unexpected bytes found for NULL");
}
}
+
+ @Override
+ public String toString() {
+ return "null";
+ }
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Object.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Object.java
index b4a5b7b..6b4a20c 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Object.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Object.java
@@ -23,7 +23,8 @@
import org.apache.kerby.asn1.Tag;
import org.apache.kerby.asn1.TaggingOption;
import org.apache.kerby.asn1.UniversalTag;
-import org.apache.kerby.asn1.util.Asn1Reader1;
+import org.apache.kerby.asn1.util.Asn1Reader;
+import org.apache.kerby.asn1.util.Asn1Reader2;
import org.apache.kerby.asn1.util.Asn1Util;
import java.io.IOException;
@@ -194,8 +195,12 @@
return tag.isContextSpecific();
}
- protected boolean isTagged() {
- return tag.isTagged();
+ protected boolean isTagSpecific() {
+ return tag.isSpecific();
+ }
+
+ protected boolean isEOC() {
+ return tag().isEOC();
}
public boolean isSimple() {
@@ -210,23 +215,23 @@
@Override
public void decode(ByteBuffer content) throws IOException {
- Asn1Reader1 reader = new Asn1Reader1(content);
+ Asn1Reader reader = new Asn1Reader2(content);
Asn1Header header = reader.readHeader();
useDefinitiveLength(header.isDefinitiveLength());
- decode(header.getTag(), header.getValueBuffer());
+ decode(header);
}
- public void decode(Tag tag, ByteBuffer content) throws IOException {
- if (!tag().equals(tag)) {
- throw new IOException("Unexpected tag " + tag
- + ", expecting " + tag());
+ public void decode(Asn1Header header) throws IOException {
+ if (!tag().equals(header.getTag())) {
+ throw new IOException("Unexpected tag " + header.getTag()
+ + ", expecting " + tag());
}
- decodeBody(content);
+ decodeBody(header);
}
- protected abstract void decodeBody(ByteBuffer content) throws IOException;
+ protected abstract void decodeBody(Asn1Header header) throws IOException;
protected int taggedEncodingLength(TaggingOption taggingOption) {
int taggingTagNo = taggingOption.getTagNo();
@@ -266,25 +271,25 @@
@Override
public void taggedDecode(ByteBuffer content,
TaggingOption taggingOption) throws IOException {
- Asn1Reader1 reader = new Asn1Reader1(content);
+ Asn1Reader reader = new Asn1Reader2(content);
Asn1Header header = reader.readHeader();
useDefinitiveLength(header.isDefinitiveLength());
- taggedDecode(header.getTag(), header.getValueBuffer(), taggingOption);
+ taggedDecode(header, taggingOption);
}
- protected void taggedDecode(Tag taggingTag, ByteBuffer content,
+ protected void taggedDecode(Asn1Header header,
TaggingOption taggingOption) throws IOException {
Tag expectedTaggingTagFlags = taggingOption.getTag(!isPrimitive());
- if (!expectedTaggingTagFlags.equals(taggingTag)) {
- throw new IOException("Unexpected tag " + taggingTag
+ if (!expectedTaggingTagFlags.equals(header.getTag())) {
+ throw new IOException("Unexpected tag " + header.getTag()
+ ", expecting " + expectedTaggingTagFlags);
}
if (taggingOption.isImplicit()) {
- decodeBody(content);
+ decodeBody(header);
} else {
- decode(content);
+ decode(header.getBodyBuffer());
}
}
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1OctetString.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1OctetString.java
index 46c9c32..88c4f46 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1OctetString.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1OctetString.java
@@ -19,11 +19,10 @@
*/
package org.apache.kerby.asn1.type;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.UniversalTag;
-import org.apache.kerby.asn1.util.Asn1Util;
import java.io.IOException;
-import java.nio.ByteBuffer;
public class Asn1OctetString extends Asn1Simple<byte[]> {
public Asn1OctetString() {
@@ -45,8 +44,8 @@
}
@Override
- protected void decodeBody(ByteBuffer content) throws IOException {
- setValue(Asn1Util.readAllLeftBytes(content));
+ protected void decodeBody(Asn1Header header) throws IOException {
+ setValue(header.readBodyBytes());
}
@Override
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1ParsingContainer.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1ParsingContainer.java
new file mode 100644
index 0000000..3bd5a7f
--- /dev/null
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1ParsingContainer.java
@@ -0,0 +1,165 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.asn1.type;
+
+import org.apache.kerby.asn1.Asn1Dumpable;
+import org.apache.kerby.asn1.Asn1Dumper;
+import org.apache.kerby.asn1.Asn1Header;
+import org.apache.kerby.asn1.Tag;
+import org.apache.kerby.asn1.util.Asn1Reader;
+import org.apache.kerby.asn1.util.Asn1Reader2;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * ASN1 constructed types, mainly structured ones, but also some primitive ones.
+ */
+public class Asn1ParsingContainer
+ extends Asn1ParsingResult implements Asn1Dumpable {
+
+ private List<Asn1ParsingResult> parsingResults = new ArrayList<>();
+
+ public Asn1ParsingContainer(Tag tag) {
+ super(tag);
+ }
+
+ public Asn1ParsingContainer(Asn1Header header) {
+ super(header);
+ usePrimitive(false);
+ }
+
+ public List<Asn1ParsingResult> getParsingResults() {
+ return parsingResults;
+ }
+
+ public void addItem(Asn1ParsingResult value) {
+ parsingResults.add(value);
+ }
+
+ public void clear() {
+ parsingResults.clear();
+ }
+
+ @Override
+ public void decode(ByteBuffer content) throws IOException {
+ Asn1Reader2 reader = new Asn1Reader2(content);
+ Asn1Header header = reader.readHeader();
+ Tag tmpTag = header.getTag();
+ useDefinitiveLength(header.isDefinitiveLength());
+
+ if (!tag().equals(tmpTag)) {
+ throw new IOException("Unexpected tag " + tmpTag
+ + ", expecting " + tag());
+ }
+
+ decode(header);
+ }
+
+ @Override
+ public void decode(Asn1Header header) throws IOException {
+ this.header = header;
+
+ Asn1Reader reader = new Asn1Reader2(header.getBuffer());
+ int pos = header.getBodyStart();
+ while (true) {
+ reader.setPosition(pos);
+ Asn1ParsingResult asn1Obj = decodeOne(reader);
+ if (asn1Obj == null) {
+ break;
+ }
+
+ pos += asn1Obj.encodingLength();
+ if (asn1Obj.isEOC()) {
+ break;
+ }
+
+ if (header.getBodyEnd() != -1 && pos >= header.getBodyEnd()) {
+ break;
+ }
+ }
+
+ header.setBodyEnd(pos);
+ }
+
+ private Asn1ParsingResult decodeOne(Asn1Reader reader) throws IOException {
+ return decodeOne(reader, this);
+ }
+
+ public static Asn1ParsingResult decodeOne(ByteBuffer content) throws IOException {
+ Asn1Reader reader = new Asn1Reader2(content);
+ return Asn1ParsingContainer.decodeOne(reader, null);
+ }
+
+ public static Asn1ParsingResult decodeOne(Asn1Reader reader,
+ Asn1ParsingContainer parent) throws IOException {
+ if (!reader.available()) {
+ return null;
+ }
+
+ Asn1Header header = reader.readHeader();
+ Tag tmpTag = header.getTag();
+ Asn1ParsingResult parsingResult;
+
+ if (tmpTag.isPrimitive()) {
+ parsingResult = new Asn1ParsingItem(header);
+ parsingResult.useDefinitiveLength(header.isDefinitiveLength());
+ } else {
+ Asn1ParsingContainer container = new Asn1ParsingContainer(tmpTag);
+ container.useDefinitiveLength(header.isDefinitiveLength());
+ container.decode(header);
+ parsingResult = container;
+ }
+
+ if (parsingResult != null && parent != null) {
+ parent.addItem(parsingResult);
+ }
+
+ return parsingResult;
+ }
+
+ @Override
+ public void dumpWith(Asn1Dumper dumper, int indents) {
+ dumper.indent(indents).append(toString()).newLine();
+
+ for (Asn1ParsingResult aObj : parsingResults) {
+ dumper.dumpType(indents + 4, aObj).newLine();
+ }
+ }
+
+ @Override
+ public String toString() {
+ String typeStr;
+ if (tag().isUniversal()) {
+ typeStr = tag().universalTag().toStr();
+ } else if (tag().isAppSpecific()) {
+ typeStr = "application " + tagNo();
+ } else {
+ typeStr = "[" + tagNo() + "]";
+ }
+ return typeStr + " ["
+ + "off=" + getOffset()
+ + ", len=" + encodingHeaderLength() + "+" + encodingBodyLength()
+ + (isDefinitiveLength() ? "" : "(undefined)")
+ + "]";
+ }
+}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1ParsingItem.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1ParsingItem.java
new file mode 100644
index 0000000..e7cffa3
--- /dev/null
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1ParsingItem.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.asn1.type;
+
+import org.apache.kerby.asn1.Asn1Header;
+
+/**
+ * Asn1Item serves two purposes:
+ * 1. Wrapping an existing Asn1Type value for Asn1Collection;
+ * 2. Wrapping a half decoded value whose body content is left to be decoded
+ * later when appropriate.
+ * Why not fully decoded at once? Lazy and decode on demand for collection, or
+ * impossible due to lacking key parameters.
+ */
+public class Asn1ParsingItem extends Asn1ParsingResult {
+
+ public Asn1ParsingItem(Asn1Header header) {
+ super(header);
+ }
+
+ @Override
+ public String toString() {
+ String valueStr = "##undecoded##";
+ String typeStr = tag().isUniversal() ? tag().universalTag().toStr()
+ : tag().tagClass().name().toLowerCase();
+ return typeStr + " ["
+ + "off=" + getOffset()
+ + ", len=" + encodingHeaderLength() + "+" + encodingBodyLength()
+ + "] "
+ + valueStr;
+ }
+}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1ParsingResult.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1ParsingResult.java
new file mode 100644
index 0000000..004fd02
--- /dev/null
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1ParsingResult.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.asn1.type;
+
+import org.apache.kerby.asn1.Asn1Header;
+import org.apache.kerby.asn1.Tag;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public abstract class Asn1ParsingResult extends AbstractAsn1Type<Asn1Type> {
+ protected Asn1Header header;
+
+ public Asn1ParsingResult(Tag tag) {
+ super(tag);
+ setValue(this);
+ }
+
+ public Asn1ParsingResult(Asn1Header header) {
+ super(header.getTag());
+ setValue(this);
+ this.header = header;
+ }
+
+ protected ByteBuffer getBodyBuffer() {
+ return header.getBodyBuffer();
+ }
+
+ protected Asn1Header getHeader() {
+ return header;
+ }
+
+ @Override
+ protected int encodingBodyLength() {
+ return header.getActualBodyLength();
+ }
+
+ @Override
+ protected void encodeBody(ByteBuffer buffer) {
+ buffer.put(header.getBodyBuffer());
+ }
+
+ protected int getOffset() {
+ return header.getBodyStart() - encodingHeaderLength();
+ }
+
+ @Override
+ protected void decodeBody(Asn1Header header) throws IOException {
+ // NOT USED FOR NOW SINCE WE DON'T DECODE THE BODY.
+ }
+
+ @Override
+ public String toString() {
+ String valueStr = "undecoded";
+ if (getValue() != null) {
+ Asn1Type val = getValue();
+ valueStr = (val != null ? val.toString() : "null");
+ }
+ String typeStr = tag().isUniversal() ? tag().universalTag().toStr()
+ : tag().tagClass().name().toLowerCase();
+ return typeStr + " ["
+ + "off=" + getOffset()
+ + ", len=" + encodingHeaderLength() + "+" + encodingBodyLength()
+ + "] "
+ + valueStr;
+ }
+}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Simple.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Simple.java
index 4358f65..6d08f70 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Simple.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Simple.java
@@ -19,6 +19,7 @@
*/
package org.apache.kerby.asn1.type;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.Tag;
import org.apache.kerby.asn1.UniversalTag;
import org.apache.kerby.asn1.util.Asn1Util;
@@ -92,8 +93,8 @@
}
@Override
- protected void decodeBody(ByteBuffer content) throws IOException {
- byte[] leftBytes = Asn1Util.readAllLeftBytes(content);
+ protected void decodeBody(Asn1Header header) throws IOException {
+ byte[] leftBytes = header.readBodyBytes();
if (leftBytes.length > 0) {
setBytes(leftBytes);
toValue();
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Tagging.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Tagging.java
index 8818c98..8a8ee3b 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Tagging.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Tagging.java
@@ -21,6 +21,7 @@
import org.apache.kerby.asn1.Asn1Dumpable;
import org.apache.kerby.asn1.Asn1Dumper;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.Tag;
import java.io.IOException;
@@ -61,7 +62,7 @@
@Override
protected int encodingBodyLength() {
- AbstractAsn1Type<?> value = (AbstractAsn1Type<?>) getValue();
+ Asn1Object value = (Asn1Object) getValue();
if (isImplicit()) {
return value.encodingBodyLength();
} else {
@@ -71,7 +72,7 @@
@Override
protected void encodeBody(ByteBuffer buffer) {
- AbstractAsn1Type<?> value = (AbstractAsn1Type<?>) getValue();
+ Asn1Object value = (Asn1Object) getValue();
if (isImplicit()) {
value.encodeBody(buffer);
} else {
@@ -80,12 +81,12 @@
}
@Override
- protected void decodeBody(ByteBuffer content) throws IOException {
- AbstractAsn1Type<?> value = (AbstractAsn1Type<?>) getValue();
+ protected void decodeBody(Asn1Header header) throws IOException {
+ Asn1Object value = (Asn1Object) getValue();
if (isImplicit()) {
- value.decodeBody(content);
+ value.decodeBody(header);
} else {
- value.decode(content);
+ value.decode(header.getBodyBuffer());
}
}
@@ -104,6 +105,7 @@
@Override
public void dumpWith(Asn1Dumper dumper, int indents) {
Asn1Type taggedValue = getValue();
+ dumper.dumpTypeInfo(indents, getClass());
dumper.dumpType(indents, taggedValue);
}
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1TaggingCollection.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1TaggingCollection.java
index 25dfbf3..4d3cbe2 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1TaggingCollection.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1TaggingCollection.java
@@ -22,6 +22,7 @@
import org.apache.kerby.asn1.Asn1Dumpable;
import org.apache.kerby.asn1.Asn1Dumper;
import org.apache.kerby.asn1.Asn1FieldInfo;
+import org.apache.kerby.asn1.Asn1Header;
import org.apache.kerby.asn1.EnumType;
import org.apache.kerby.asn1.Tag;
@@ -43,7 +44,7 @@
super(makeTag(isAppSpecific, taggingTagNo));
this.tagged = createTaggedCollection(tags);
setValue(tagged);
- this.tagging = new Asn1Tagging<Asn1CollectionType>(taggingTagNo,
+ this.tagging = new Asn1Tagging<>(taggingTagNo,
tagged, isAppSpecific, isImplicit);
}
@@ -135,8 +136,13 @@
}
@Override
- protected void decodeBody(ByteBuffer content) throws IOException {
- tagging.decodeBody(content);
+ public void decode(ByteBuffer content) throws IOException {
+ tagging.decode(content);
+ }
+
+ @Override
+ protected void decodeBody(Asn1Header header) throws IOException {
+ tagging.decodeBody(header);
}
protected <T extends Asn1Type> T getFieldAs(EnumType index, Class<T> t) {
@@ -178,6 +184,7 @@
@Override
public void dumpWith(Asn1Dumper dumper, int indents) {
Asn1Type taggedValue = getValue();
+ dumper.dumpTypeInfo(indents, getClass());
dumper.dumpType(indents, taggedValue);
}
}
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader.java
index 451e8ff..2590a48 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader.java
@@ -42,12 +42,19 @@
public Asn1Header readHeader() throws IOException {
Tag tag = readTag();
int valueLength = readLength();
+ int bodyStart = getPosition();
Asn1Header header = new Asn1Header(tag, valueLength,
- getValueBuffer(valueLength));
+ bodyStart, getValueBuffer(valueLength));
return header;
}
- protected abstract ByteBuffer getValueBuffer(int valueLength);
+ public abstract void setPosition(int position);
+
+ public abstract int getPosition();
+
+ public abstract boolean available();
+
+ public abstract ByteBuffer getValueBuffer(int valueLength);
protected abstract byte readByte() throws IOException;
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader1.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader1.java
index f53f99d..503507f 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader1.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader1.java
@@ -32,12 +32,27 @@
}
@Override
+ public void setPosition(int position) {
+ buffer.position(position);
+ }
+
+ @Override
+ public int getPosition() {
+ return buffer.position();
+ }
+
+ @Override
+ public boolean available() {
+ return buffer.remaining() > 0;
+ }
+
+ @Override
protected byte readByte() throws IOException {
return buffer.get();
}
@Override
- protected ByteBuffer getValueBuffer(int valueLength) {
+ public ByteBuffer getValueBuffer(int valueLength) {
ByteBuffer result = buffer.duplicate();
result.limit(buffer.position() + valueLength);
buffer.position(buffer.position() + valueLength);
diff --git a/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader2.java b/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader2.java
index 9351c3f..0136db4 100644
--- a/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader2.java
+++ b/kerby-asn1/src/main/java/org/apache/kerby/asn1/util/Asn1Reader2.java
@@ -38,20 +38,23 @@
this.position = buffer.position();
}
+ @Override
public int getPosition() {
return position;
}
+ @Override
public void setPosition(int position) {
this.position = position;
}
+ @Override
public boolean available() {
return position < buffer.limit();
}
@Override
- protected ByteBuffer getValueBuffer(int valueLength) {
+ public ByteBuffer getValueBuffer(int valueLength) {
return buffer;
}
diff --git a/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestAsn1Dump.java b/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestAsn1Dump.java
index 540de22..a5c64d9 100644
--- a/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestAsn1Dump.java
+++ b/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestAsn1Dump.java
@@ -19,15 +19,17 @@
*/
package org.apache.kerby.asn1;
+import org.apache.kerby.asn1.util.IOUtil;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
+import java.io.InputStream;
public class TestAsn1Dump {
- @Test
- public void testDecoding() throws IOException {
+ //@Test
+ public void testDump1WithPersonnelRecord() throws IOException {
try {
PersonnelRecord pr = TestData.createSamplePersonnel();
Asn1.dump(pr);
@@ -35,7 +37,51 @@
byte[] data = TestData.createSammplePersonnelEncodingData();
Asn1.dump(data);
} catch (Exception e) {
+ e.printStackTrace();
Assert.fail();
}
}
+
+ @Test
+ public void testDump1WithCompressedData() throws IOException {
+ String hexStr = readTxtFile("/compressed-data.txt");
+ try {
+ Asn1.dump(hexStr);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Assert.fail();
+ }
+ }
+
+ @Test
+ public void testDump1WithSignedData() throws IOException {
+ String hexStr = readTxtFile("/signed-data.txt");
+ try {
+ Asn1.dump(hexStr);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Assert.fail();
+ }
+ }
+
+ @Test
+ public void testDump1WithDerData() throws IOException {
+ byte[] data = readBinFile("/der-data.dat");
+ try {
+ Asn1.dump(data);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Assert.fail();
+ }
+ }
+
+ static String readTxtFile(String resource) throws IOException {
+ InputStream is = TestAsn1Dump.class.getResourceAsStream(resource);
+ return IOUtil.readInput(is);
+ }
+
+ static byte[] readBinFile(String resource) throws IOException {
+ InputStream is = TestAsn1Dump.class.getResourceAsStream(resource);
+ return IOUtil.readInputStream(is);
+ }
}
diff --git a/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestPersonnelRecord.java b/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestPersonnelRecord.java
index 81ce341..88349e2 100644
--- a/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestPersonnelRecord.java
+++ b/kerby-asn1/src/test/java/org/apache/kerby/asn1/TestPersonnelRecord.java
@@ -72,12 +72,14 @@
assertThat(encoded).isEqualTo(data);
}
- //@Test
+ @Test
public void testDecoding() throws IOException {
PersonnelRecord expected = TestData.createSamplePersonnel();
byte[] data = TestData.createSammplePersonnelEncodingData();
PersonnelRecord decoded = new PersonnelRecord();
+ //Asn1.dump(data);
decoded.decode(data);
+ Asn1.dump(decoded);
assertThat(expected.getName().getGivenName())
.isEqualTo(decoded.getName().getGivenName());
@@ -97,6 +99,8 @@
.isEqualTo(decoded.getNameOfSpouse().getInitial());
assertThat(expected.getNameOfSpouse().getFamilyName())
.isEqualTo(decoded.getNameOfSpouse().getFamilyName());
+ assertThat(decoded.getChildren().getElements().size())
+ .isEqualTo(expected.getChildren().getElements().size());
assertThat(expected.getChildren().getElements().get(0).getName().getGivenName())
.isEqualTo(decoded.getChildren().getElements().get(0).getName().getGivenName());
assertThat(expected.getChildren().getElements().get(0).getName().getInitial())
diff --git a/kerby-asn1/src/test/resources/compressed-data.txt b/kerby-asn1/src/test/resources/compressed-data.txt
new file mode 100644
index 0000000..3012abe
--- /dev/null
+++ b/kerby-asn1/src/test/resources/compressed-data.txt
@@ -0,0 +1 @@
+3080060B2A864886F70D0109100109A0803080020100300D060B2A864886F70D0109100308308006092A864886F70D010701A08024800482021E789CED945D6FDA301486EF2BF93FE4FA9560F15718AD76618C9BA15140492A75BD0B591A22D1002644E3DFD71E8516ED2FF4B573FC11FBB17D4E62BD69DAB2697BD9715BDE06F976BBAE8BBCAD37CD37339EF49E28BB0B9AFCB5FC11DBCD61CBFA7F292337FA3CC7E6CDFEA5B43DD3149B3F7553DD06CBBAC9EDF163C8B8DE6F37FBDA036F83BA59D74D7917BCD4EBF23F28B999A40A6188FD45BE652FC2F333F46F3D9DCF4CF02EDFB550493633C9A56B18D1301C808594E3D111988384EFA2089101244EB19823A5570909BD4A57A43341E0C9D57928439266F82E4F6CE1D9646462BFE39101CB2138678271D149C9F805C5DB427447263AB6E29DCFFE041333453844629C25FA3101A5C8921964242344D29511260FF78E1DBD834862EE1129BF88A505B75CB85C704ED9AE68AB420A24A58B4BD91465303BBC2E4B4B16268152F8E92216C487D605077A01DAE78CB987F78513BC6C5589B2EA442B48A69E20DAAA5DB6A2B52E239EA25A552B9C154393FBF908D9025AE1D1C78F613C7F80D66E07D5619DDB60BA397D4FFB605BDA202BEDEB9E6837616CA09D3B85E460D2F90FE32152E709C61915CE8A93FF9CF34C0AC198F075922A0D85911FAF0CB814125CB8176178F6DC201A60E04D24C9624E5D17EDE5790E7A0A20548A61D8F7711A43FDC2BF2564C72517BBE8C5179DF056F26EC7779CE1438AE2D8DAD517F58BFA4575FF70064A5277D9B14F77606C403F2E4B3231EA539B923773F79734000000000000000000000000
\ No newline at end of file
diff --git a/kerby-asn1/src/test/resources/der-data.dat b/kerby-asn1/src/test/resources/der-data.dat
new file mode 100644
index 0000000..6d503b3
--- /dev/null
+++ b/kerby-asn1/src/test/resources/der-data.dat
Binary files differ
diff --git a/kerby-asn1/src/test/resources/signed-data.txt b/kerby-asn1/src/test/resources/signed-data.txt
new file mode 100644
index 0000000..bf018ef
--- /dev/null
+++ b/kerby-asn1/src/test/resources/signed-data.txt
@@ -0,0 +1 @@
+308006092A864886F70D010702A0803080020101310B300906052B0E03021A0500308006092A864886F70D010701A0802480040C48656C6C6F20576F726C6421000000000000A08204623082020D30820176A003020102020101300D06092A864886F70D0101040500302531163014060355040A130D426F756E637920436173746C65310B3009060355040613024155301E170D3034313032343034333035385A170D3035303230313034333035385A302531163014060355040A130D426F756E637920436173746C65310B300906035504061302415530819F300D06092A864886F70D010101050003818D003081890281810098F7380B2100E80398F7186758DD352BA1387447F55842FCF1B5EC5762227546736BA52611227C44206BFBAA642A527759C7B095192A6F64D5B567796CC2D3DE358BD6677F181BDA39D75EC6B99300762845444AB396B118D246D9D888B82A046D2BCE968C9F90399EDBBB374E34E847AC0617B5F5C8D901A81E1071990DBB9F0203010001A34D304B301D0603551D0E041604147F88734A3A8E9FE01C96145CB044D67AE574ABD6301F0603551D230418301680147F88734A3A8E9FE01C96145CB044D67AE574ABD630090603551D1304023000300D06092A864886F70D010104050003818100530927B40EA47A37D1B9E5438372DCF0A72BE49EF86C374E96981A9F38F9AF1F183F4399EEFC1BA344B20BE91464F2A0BC6F278081F382B3CACFB5A761DD5F3A198B25C07ABE52E08C29B44DD3C711702B28F6F1C46B33A74AE3B0C3C97524574AB004030D96EC2793F9E8E0AEE297337631993997BC17C8D6BDC89E821D6E9D3082024D308201B6A003020102020102300D06092A864886F70D0101040500302531163014060355040A130D426F756E637920436173746C65310B3009060355040613024155301E170D3034313032343034333035395A170D3035303230313034333035395A3065311830160603550403130F4572696320482E2045636869646E613124302206092A864886F70D01090116156572696340626F756E6379636173746C652E6F726731163014060355040A130D426F756E637920436173746C65310B300906035504061302415530819F300D06092A864886F70D010101050003818D00308189028181009BEE429C653A5B8E625290AC686927E600EBB99BF78FFA3B37A6A09916618A468B1B6245E8409A5F5DE28A85497E6CC1B0F2B1000096C2E4D70A84925C6F2F88AFEAA521F02697D01D8121B5C0B40B122A96796DBF7290006C21FCF770A523EF48D9E44011AFB45ABEFBD8275C305BCA77CFF1BD8BD848ACD17F54DB2EA016230203010001A34D304B301D0603551D0E0416041440263A4B2717AE85A109BA21005537AEAF268D53301F0603551D230418301680147F88734A3A8E9FE01C96145CB044D67AE574ABD630090603551D1304023000300D06092A864886F70D01010405000381810011E223BCD90A30F53F6580AED53AA31993C4AA2FA0967B60DA10BF085D281B21C5A4CB86B4C7A9177A6E5BEBB328CD6CEB56ABDDA862769DD7161AFF18453F5F12B6E00A25237C858313FC3D18145A6422CD3417A56526865B017B5B8829511F340CC282D61F250F072482AC50271D59E08A54AB388D18A89EC7A4D6BA3390F13182012F3082012B020101302A302531163014060355040A130D426F756E637920436173746C65310B3009060355040613024155020102300906052B0E03021A0500A05D301806092A864886F70D010903310B06092A864886F70D010701301C06092A864886F70D010905310F170D3034313032343034333035395A302306092A864886F70D010904311604142EF7BDE608CE5404E97D5F042F95F89F1C232871300D06092A864886F70D010101050004818061DB7B7FE3719BBA6FF7AB4617373C48E23143BC98421188D601AF9FEF14D864AF2F13AC67CEA48E399BB82ED4C4B4FEF75AB3BCA4BE2765FEC3597CED06A6110851A2233114F753ACAE4D617868BA5AB496DB46C21EA493BF07691D2006D5E5209B6605432483CE476AA7AEE1CDDB02C56BE7C4BF827CC10F17C2F9340BC88C000000000000
\ No newline at end of file
diff --git a/kerby-kerb/kerb-core-test/src/test/java/org/apache/kerby/kerberos/kerb/codec/TestAsReqCodec.java b/kerby-kerb/kerb-core-test/src/test/java/org/apache/kerby/kerberos/kerb/codec/TestAsReqCodec.java
index 4c1786b..b8599a7 100644
--- a/kerby-kerb/kerb-core-test/src/test/java/org/apache/kerby/kerberos/kerb/codec/TestAsReqCodec.java
+++ b/kerby-kerb/kerb-core-test/src/test/java/org/apache/kerby/kerberos/kerb/codec/TestAsReqCodec.java
@@ -19,6 +19,7 @@
*/
package org.apache.kerby.kerberos.kerb.codec;
+import org.apache.kerby.asn1.Asn1;
import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
import org.apache.kerby.kerberos.kerb.type.base.HostAddrType;
import org.apache.kerby.kerberos.kerb.type.base.HostAddress;
@@ -44,18 +45,21 @@
import static org.assertj.core.api.Assertions.assertThat;
/**
- * Test AsReq message using a real 'correct' network packet captured from MS-AD to detective programming errors
- * and compatibility issues particularly regarding Kerberos crypto.
+ * Test AsReq message using a real 'correct' network packet captured from MS-AD
+ * to detective programming errors and compatibility issues particularly
+ * regarding Kerberos crypto.
*/
public class TestAsReqCodec {
@Test
public void test() throws IOException, ParseException {
byte[] bytes = CodecTestUtil.readBinaryFile("/asreq.token");
+ Asn1.dump(bytes);
ByteBuffer asReqToken = ByteBuffer.wrap(bytes);
AsReq asReq = new AsReq();
asReq.decode(asReqToken);
+ Asn1.dump(asReq, false);
assertThat(asReq.getPvno()).isEqualTo(5);
assertThat(asReq.getMsgType()).isEqualTo(KrbMessageType.AS_REQ);
diff --git a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/KrbCodec.java b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/KrbCodec.java
index 87d5731..43d4540 100644
--- a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/KrbCodec.java
+++ b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/KrbCodec.java
@@ -88,7 +88,7 @@
throw new IOException("To be supported krb message type with tag: " + tag);
}
- msg.decode(tag, header.getValueBuffer());
+ msg.decode(header);
return msg;
}