directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dran...@apache.org
Subject [09/13] directory-kerby git commit: Consolidated facility and support modules into kerby-common
Date Sat, 16 Jan 2016 09:38:37 GMT
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java
new file mode 100644
index 0000000..08a9019
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1.java
@@ -0,0 +1,188 @@
+/**
+ *  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;
+
+import org.apache.kerby.asn1.parse.Asn1ParseResult;
+import org.apache.kerby.asn1.parse.Asn1Parser;
+import org.apache.kerby.asn1.type.Asn1Type;
+import org.apache.kerby.asn1.util.HexUtil;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * The shortcut API for ASN1 encoding, decoding and dumping.
+ */
+public final class Asn1 {
+
+    private Asn1() {
+
+    }
+
+    /**
+     * Encode value into buffer.
+     * @param buffer
+     * @param value
+     * @throws IOException
+     */
+    public static void encode(ByteBuffer buffer, Asn1Type value) throws IOException {
+        value.encode(buffer);
+    }
+
+    /**
+     * Encode value and return the result.
+     * @param value
+     * @return
+     * @throws IOException
+     */
+    public static byte[] encode(Asn1Type value) throws IOException {
+        return value.encode();
+    }
+
+    /**
+     * Blindly decode content and return the result ASN1 object.
+     * @param content
+     * @return
+     * @throws IOException
+     */
+    public static Asn1Type decode(byte[] content) throws IOException {
+        return decode(ByteBuffer.wrap(content));
+    }
+
+    /**
+     * See avove.
+     */
+    public static Asn1Type decode(ByteBuffer content) throws IOException {
+        Asn1ParseResult parseResult = Asn1Parser.parse(content);
+        return Asn1Converter.convert(parseResult, false);
+    }
+
+    /**
+     * Decode using specified value container. Better to use this when the value
+     * type is known prior to the call.
+     * @param content
+     * @param value
+     * @throws IOException
+     */
+    public static void decode(byte[] content, Asn1Type value) throws IOException {
+        value.decode(content);
+    }
+
+    /**
+     * See avove.
+     */
+    public static void decode(ByteBuffer content, Asn1Type value) throws IOException {
+        value.decode(content);
+    }
+
+    /**
+     * Parse content and return parse result. Note this is different from decode,
+     * as it doesn't decode into values, only parse result info like offset,
+     * header len, body len and etc. are out.
+     * @param content
+     * @return
+     * @throws IOException
+     */
+    public static Asn1ParseResult parse(byte[] content) throws IOException {
+        return parse(ByteBuffer.wrap(content));
+    }
+
+    /**
+     * See avove.
+     */
+    public static Asn1ParseResult parse(ByteBuffer content) throws IOException {
+        return Asn1Parser.parse(content);
+    }
+
+    /**
+     * Dump out a value.
+     * @param value
+     */
+    public static void dump(Asn1Type value) {
+        Asn1Dumper dumper = new Asn1Dumper();
+        dumper.dumpType(0, value);
+        String output = dumper.output();
+        System.out.println(output);
+    }
+
+    /**
+     * Parse first, and then dump out the parse result.
+     * @param hexStr
+     * @throws IOException
+     */
+    public static void parseAndDump(String hexStr) throws IOException {
+        byte[] data = HexUtil.hex2bytes(hexStr);
+        parseAndDump(data);
+    }
+
+    /**
+     * See avove.
+     */
+    public static void parseAndDump(ByteBuffer content) throws IOException {
+        byte[] bytes = new byte[content.remaining()];
+        content.get(bytes);
+        parseAndDump(bytes);
+    }
+
+    /**
+     * See avove.
+     */
+    public static void parseAndDump(byte[] content) throws IOException {
+        String hexStr = HexUtil.bytesToHex(content);
+        Asn1Dumper dumper = new Asn1Dumper();
+        System.out.println("Dumping data:");
+        dumper.dumpData(hexStr);
+        dumper.parseAndDump(content);
+        String output = dumper.output();
+        System.out.println(output);
+    }
+
+    /**
+     * Decode first, and then dump out the decoded value.
+     * @param hexStr
+     * @throws IOException
+     */
+    public static void decodeAndDump(String hexStr) throws IOException {
+        byte[] data = HexUtil.hex2bytes(hexStr);
+        decodeAndDump(data);
+    }
+
+    /**
+     * See avove.
+     */
+    public static void decodeAndDump(ByteBuffer content) throws IOException {
+        byte[] bytes = new byte[content.remaining()];
+        content.get(bytes);
+        decodeAndDump(bytes);
+    }
+
+    /**
+     * See avove.
+     */
+    public static void decodeAndDump(byte[] content) throws IOException {
+        String hexStr = HexUtil.bytesToHex(content);
+        Asn1Dumper dumper = new Asn1Dumper();
+        System.out.println("Dumping data:");
+        dumper.dumpData(hexStr);
+        dumper.decodeAndDump(content);
+        String output = dumper.output();
+        System.out.println(output);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Binder.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Binder.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Binder.java
new file mode 100644
index 0000000..c73b63a
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Binder.java
@@ -0,0 +1,51 @@
+/**
+ *  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;
+
+import org.apache.kerby.asn1.parse.Asn1ParseResult;
+import org.apache.kerby.asn1.type.Asn1Encodeable;
+import org.apache.kerby.asn1.type.Asn1Type;
+
+import java.io.IOException;
+
+/**
+ * Decode and bind a parsing result to an ASN1 object.
+ */
+public final class Asn1Binder {
+
+    private Asn1Binder() {
+
+    }
+
+    public static void bind(Asn1ParseResult parseResult,
+                            Asn1Type value) throws IOException {
+        value.useDefinitiveLength(parseResult.isDefinitiveLength());
+        ((Asn1Encodeable) value).decode(parseResult);
+    }
+
+    public static void bindWithTagging(Asn1ParseResult parseResult, Asn1Type value,
+                                       TaggingOption taggingOption) throws IOException {
+        if (!parseResult.isTagSpecific()) {
+            throw new IllegalArgumentException(
+                "Attempting to decode non-tagged value using tagging way");
+        }
+        ((Asn1Encodeable) value).taggedDecode(parseResult, taggingOption);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Converter.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Converter.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Converter.java
new file mode 100644
index 0000000..f426764
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Converter.java
@@ -0,0 +1,88 @@
+/**
+ *  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;
+
+import org.apache.kerby.asn1.parse.Asn1ParseResult;
+import org.apache.kerby.asn1.type.Asn1Specific;
+import org.apache.kerby.asn1.type.Asn1Collection;
+import org.apache.kerby.asn1.type.Asn1Constructed;
+import org.apache.kerby.asn1.type.Asn1Encodeable;
+import org.apache.kerby.asn1.type.Asn1Simple;
+import org.apache.kerby.asn1.type.Asn1Type;
+
+import java.io.IOException;
+
+/**
+ * Converting a ASN1 parsing result into an ASN1 object.
+ */
+public final class Asn1Converter {
+
+    private Asn1Converter() {
+
+    }
+
+    public static Asn1Type convert(Asn1ParseResult parseResult,
+                                   boolean isLazy) throws IOException {
+        if (Asn1Simple.isSimple(parseResult.tag())) {
+            return Asn1Converter.convertAsSimple(parseResult);
+        } else if (Asn1Collection.isCollection(parseResult.tag())) {
+            return Asn1Converter.convertAsCollection(parseResult, isLazy);
+        } else if (!parseResult.tag().isPrimitive()) {
+            Asn1Encodeable tmpValue = new Asn1Constructed(parseResult.tag());
+            tmpValue.decode(parseResult);
+            return tmpValue;
+        } else if (parseResult.isTagSpecific()) {
+            Asn1Specific app = new Asn1Specific(parseResult.tag());
+            app.decode(parseResult);
+            return app;
+        } else {
+            throw new IOException("Unexpected item: " + parseResult.simpleInfo());
+        }
+    }
+
+    public static Asn1Type convertAsSimple(Asn1ParseResult parseResult) throws IOException {
+        Asn1Encodeable value = Asn1Simple.createSimple(parseResult.tagNo());
+        value.useDefinitiveLength(parseResult.isDefinitiveLength());
+        Asn1Binder.bind(parseResult, value);
+        return value;
+    }
+
+    public static Asn1Type convertAsCollection(Asn1ParseResult parseResult,
+                                               boolean isLazy) throws IOException {
+        Asn1Collection value = Asn1Collection.createCollection(parseResult.tag());
+        value.useDefinitiveLength(parseResult.isDefinitiveLength());
+        value.setLazy(isLazy);
+        Asn1Binder.bind(parseResult, value);
+        return value;
+    }
+
+    public static Asn1Type convertAs(Asn1ParseResult parseResult,
+                                     Class<? extends Asn1Type> type) throws IOException {
+        Asn1Type value;
+        try {
+            value = type.newInstance();
+        } catch (Exception e) {
+            throw new RuntimeException("Invalid type: "
+                + type.getCanonicalName(), e);
+        }
+        Asn1Binder.bind(parseResult, value);
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumpable.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumpable.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumpable.java
new file mode 100644
index 0000000..d4ae6d9
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumpable.java
@@ -0,0 +1,26 @@
+/**
+ *  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;
+
+public interface Asn1Dumpable {
+
+    void dumpWith(Asn1Dumper dumper, int indents);
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java
new file mode 100644
index 0000000..3368a44
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Dumper.java
@@ -0,0 +1,136 @@
+/**
+ *  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;
+
+import org.apache.kerby.asn1.parse.Asn1Item;
+import org.apache.kerby.asn1.parse.Asn1ParseResult;
+import org.apache.kerby.asn1.parse.Asn1Parser;
+import org.apache.kerby.asn1.type.Asn1Specific;
+import org.apache.kerby.asn1.type.Asn1Simple;
+import org.apache.kerby.asn1.type.Asn1Type;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public final class Asn1Dumper {
+    private StringBuilder builder = new StringBuilder();
+
+    public String output() {
+        return builder.toString();
+    }
+
+    public void parseAndDump(byte[] content) throws IOException {
+        parseAndDump(ByteBuffer.wrap(content));
+    }
+
+    public void decodeAndDump(byte[] content) throws IOException {
+        decodeAndDump(ByteBuffer.wrap(content));
+    }
+
+    public void decodeAndDump(ByteBuffer content) throws IOException {
+        Asn1Type value = Asn1.decode(content);
+        dumpType(0, value);
+    }
+
+    public void parseAndDump(ByteBuffer content) throws IOException {
+        Asn1ParseResult parseResult = Asn1Parser.parse(content);
+        dumpParseResult(0, parseResult);
+    }
+
+    public void dumpType(Asn1Type value) {
+        dumpType(0, 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 Asn1Dumpable) {
+            Asn1Dumpable dumpable = (Asn1Dumpable) value;
+            dumpable.dumpWith(this, indents);
+        } else if (value instanceof Asn1Specific) {
+            indent(indents).append(value.toString());
+        } else {
+            indent(indents).append("<Unknown>");
+        }
+
+        return this;
+    }
+
+    public Asn1Dumper dumpParseResult(int indents, Asn1ParseResult value) {
+        if (value == null) {
+            indent(indents).append("Null");
+        } else if (value instanceof Asn1Item) {
+            indent(indents).append(value.toString());
+        } else if (value instanceof Asn1Dumpable) {
+            Asn1Dumpable dumpable = (Asn1Dumpable) value;
+            dumpable.dumpWith(this, indents);
+        } else {
+            indent(indents).append("<Unknown>");
+        }
+
+        return this;
+    }
+
+    public Asn1Dumper indent(int numSpaces) {
+        for (int i = 0; i < numSpaces; i++) {
+            builder.append(' ');
+        }
+        return this;
+    }
+
+    public Asn1Dumper append(Asn1Simple<?> simpleValue) {
+        if (simpleValue != null) {
+            builder.append(simpleValue.toString());
+        } else {
+            builder.append("null");
+        }
+        return this;
+    }
+
+    public Asn1Dumper append(String string) {
+        builder.append(string);
+        return this;
+    }
+
+    public Asn1Dumper appendType(Class<?> cls) {
+        builder.append("<").append(cls.getSimpleName()).append("> ");
+        return this;
+    }
+
+    public Asn1Dumper newLine() {
+        builder.append("\n");
+        return this;
+    }
+
+    public Asn1Dumper dumpData(String hexData) {
+        int range = 100;
+        int pos = range;
+
+        while (pos < hexData.length()) {
+            System.out.println(hexData.substring(pos - range, pos));
+            pos = pos + range;
+        }
+        System.out.println(hexData.substring(pos - range, hexData.length()));
+
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Factory.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Factory.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Factory.java
new file mode 100644
index 0000000..7610751
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1Factory.java
@@ -0,0 +1,57 @@
+/**
+ *  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;
+
+import org.apache.kerby.asn1.type.Asn1Collection;
+import org.apache.kerby.asn1.type.Asn1Simple;
+import org.apache.kerby.asn1.type.Asn1Type;
+
+/**
+ * ASN1 type factory
+ */
+public class Asn1Factory {
+
+    /**
+     * Create an ASN1 type with specified tag number
+     * @param tagNo The tag number
+     * @return ASN1 type
+     */
+    public static Asn1Type create(int tagNo) {
+        UniversalTag tagNoEnum = UniversalTag.fromValue(tagNo);
+        if (tagNoEnum != UniversalTag.UNKNOWN) {
+            return create(tagNoEnum);
+        }
+        throw new IllegalArgumentException("Unexpected tag " + tagNo);
+    }
+
+    /**
+     * Create an ASN1 type with specified tag
+     * @param tagNo The tag number
+     * @return ASN1 type
+     */
+    public static Asn1Type create(UniversalTag tagNo) {
+        if (Asn1Simple.isSimple(tagNo)) {
+            return Asn1Simple.createSimple(tagNo);
+        } else if (Asn1Collection.isCollection(tagNo)) {
+            return Asn1Collection.createCollection(tagNo);
+        }
+        throw new IllegalArgumentException("Unexpected tag " + tagNo);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1FieldInfo.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1FieldInfo.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1FieldInfo.java
new file mode 100644
index 0000000..72182b0
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Asn1FieldInfo.java
@@ -0,0 +1,107 @@
+/**
+ *  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;
+
+import org.apache.kerby.asn1.type.Asn1Type;
+
+/**
+ * Representing a field in a ASN1 collection or choice.
+ */
+public class Asn1FieldInfo {
+    private EnumType index;
+    private int tagNo = -1; // Indicate a non-tagged field
+    private boolean isImplicit;
+    private Class<? extends Asn1Type> type;
+
+    /**
+     * Constructor for a tagged field, the tagNo being the same of index.
+     * @param index
+     * @param type
+     * @param isImplicit
+     */
+    public Asn1FieldInfo(EnumType index, Class<? extends Asn1Type> type,
+                         boolean isImplicit) {
+        this(index, index.getValue(), type, isImplicit);
+    }
+
+    /**
+     * Constructor for a tagged field.
+     * @param index
+     * @param tagNo
+     * @param type
+     * @param isImplicit
+     */
+    public Asn1FieldInfo(EnumType index, int tagNo, Class<? extends Asn1Type> type,
+                         boolean isImplicit) {
+        this.index = index;
+        this.tagNo = tagNo;
+        this.type = type;
+        this.isImplicit = isImplicit;
+    }
+
+    /**
+     * Constructor for a non-tagged field.
+     * @param index
+     * @param type
+     */
+    public Asn1FieldInfo(EnumType index, Class<? extends Asn1Type> type) {
+        this.index = index;
+        this.type = type;
+        this.tagNo = -1; // Indicate a non-tagged field
+    }
+
+    public boolean isTagged() {
+        return tagNo != -1;
+    }
+
+    public TaggingOption getTaggingOption() {
+        if (isImplicit) {
+            return TaggingOption.newImplicitContextSpecific(tagNo);
+        } else {
+            return TaggingOption.newExplicitContextSpecific(tagNo);
+        }
+    }
+
+    public int getTagNo() {
+        return tagNo;
+    }
+
+    public EnumType getIndex() {
+        return index;
+    }
+
+    public boolean isImplicit() {
+        return isImplicit;
+    }
+
+    public Asn1Type createFieldValue() {
+        try {
+            return type.newInstance();
+        } catch (Exception e) {
+            throw new IllegalArgumentException(
+                "Bad field type provided, no default constructor?", e);
+        }
+    }
+
+    public Tag getFieldTag() {
+        Asn1Type fieldValue = createFieldValue();
+        return fieldValue.tag();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/EnumType.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/EnumType.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/EnumType.java
new file mode 100644
index 0000000..e0166ec
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/EnumType.java
@@ -0,0 +1,37 @@
+/**
+ *  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;
+
+/**
+ * A helper interface used by Asn1Enumerated.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface EnumType {
+    /**
+     * @return the Enum element value
+     */
+    int getValue();
+    
+    /**
+     * @return The enum element name
+     */
+    String getName();
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/ExplicitField.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/ExplicitField.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/ExplicitField.java
new file mode 100644
index 0000000..7142dc0
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/ExplicitField.java
@@ -0,0 +1,46 @@
+/**
+ *  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;
+
+import org.apache.kerby.asn1.type.Asn1Type;
+
+/**
+ * Representing an explicitly tagged field in a ASN1 collection or choice.
+ */
+public class ExplicitField extends Asn1FieldInfo {
+
+    /**
+     * Constructor for an explicitly tagged field.
+     * @param index
+     * @param type
+     */
+    public ExplicitField(EnumType index, int tagNo, Class<? extends Asn1Type> type) {
+        super(index, tagNo, type, false);
+    }
+
+    /**
+     * Constructor for an explicitly tagged field, the tagNo being the same of index.
+     * @param index
+     * @param type
+     */
+    public ExplicitField(EnumType index, Class<? extends Asn1Type> type) {
+        super(index, index.getValue(), type, false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/ImplicitField.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/ImplicitField.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/ImplicitField.java
new file mode 100644
index 0000000..f488847
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/ImplicitField.java
@@ -0,0 +1,46 @@
+/**
+ *  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;
+
+import org.apache.kerby.asn1.type.Asn1Type;
+
+/**
+ * Representing an implicitly tagged field in a ASN1 collection or choice.
+ */
+public class ImplicitField extends Asn1FieldInfo {
+
+    /**
+     * Constructor for an implicitly tagged field.
+     * @param index
+     * @param type
+     */
+    public ImplicitField(EnumType index, int tagNo, Class<? extends Asn1Type> type) {
+        super(index, tagNo, type, true);
+    }
+
+    /**
+     * Constructor for an implicitly tagged field, the tagNo being the same of index.
+     * @param index
+     * @param type
+     */
+    public ImplicitField(EnumType index, Class<? extends Asn1Type> type) {
+        super(index, index.getValue(), type, true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Tag.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Tag.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Tag.java
new file mode 100644
index 0000000..d248802
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/Tag.java
@@ -0,0 +1,160 @@
+/**
+ *  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;
+
+/**
+ * ASN1, a tagged system.
+ */
+public class Tag {
+    private int tagFlags = 0;
+    private int tagNo = 0;
+
+    public Tag(int tag) {
+        this.tagFlags = tag & 0xE0;
+        this.tagNo = tag & 0x1F;
+    }
+
+    public Tag(UniversalTag tag) {
+        this.tagFlags = TagClass.UNIVERSAL.getValue();
+        this.tagNo = tag.getValue();
+    }
+
+    public Tag(int tagFlags, int tagNo) {
+        this.tagFlags = tagFlags & 0xE0;
+        this.tagNo = tagNo;
+    }
+
+    public Tag(TagClass tagClass, int tagNo) {
+        this.tagFlags = tagClass.getValue();
+        this.tagNo = tagNo;
+    }
+
+    public Tag(Tag other) {
+        this(other.tagFlags, other.tagNo);
+    }
+
+    public TagClass tagClass() {
+        return TagClass.fromTag(tagFlags);
+    }
+
+    public void usePrimitive(boolean isPrimitive) {
+        if (isPrimitive) {
+            tagFlags &= ~0x20;
+        } else {
+            tagFlags |= 0x20;
+        }
+    }
+
+    public boolean isPrimitive() {
+        return (tagFlags & 0x20) == 0;
+    }
+
+    public int tagFlags() {
+        return tagFlags;
+    }
+
+    public int tagNo() {
+        return tagNo;
+    }
+
+    public UniversalTag universalTag() {
+        if (isUniversal()) {
+            return UniversalTag.fromValue(tagNo());
+        }
+        return UniversalTag.UNKNOWN;
+    }
+
+    public boolean isEOC() {
+        return universalTag() == UniversalTag.EOC;
+    }
+
+    public boolean isNull() {
+        return universalTag() == UniversalTag.NULL;
+    }
+
+    public boolean isUniversal() {
+        return tagClass().isUniversal();
+    }
+
+    public boolean isAppSpecific() {
+        return tagClass().isAppSpecific();
+    }
+
+    public boolean isContextSpecific() {
+        return tagClass().isContextSpecific();
+    }
+
+    public boolean isSpecific() {
+        return tagClass().isSpecific();
+    }
+
+    public byte tagByte() {
+        int n = tagFlags | (tagNo < 0x1F ? tagNo : 0x1F);
+        return (byte) (n & 0xFF);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        Tag tag = (Tag) o;
+
+        if (tagFlags != tag.tagFlags) {
+            return false;
+        }
+
+        return tagNo == tag.tagNo;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = tagFlags;
+        result = 31 * result + tagNo;
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("0x%02X", tagByte());
+    }
+
+    public String typeStr() {
+        if (isUniversal()) {
+            return universalTag().toStr();
+        } else if (isAppSpecific()) {
+            return "application [" + tagNo() + "]";
+        } else {
+            return "context [" + tagNo() + "]";
+        }
+    }
+
+    public static Tag newAppTag(int tagNo) {
+        return new Tag(TagClass.APPLICATION, tagNo);
+    }
+
+    public static Tag newCtxTag(int tagNo) {
+        return new Tag(TagClass.CONTEXT_SPECIFIC, tagNo);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/TagClass.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/TagClass.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/TagClass.java
new file mode 100644
index 0000000..8d02917
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/TagClass.java
@@ -0,0 +1,99 @@
+/**
+ *  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;
+
+/**
+ * Tag class defined by the spec.
+ */
+public enum TagClass {
+    UNKNOWN(-1),
+    UNIVERSAL(0x00),
+    APPLICATION(0x40),
+    CONTEXT_SPECIFIC(0x80),
+    PRIVATE(0xC0);
+
+    private int value;
+
+    /**
+     * The constructor given the value.
+     * @param value
+     */
+    private TagClass(int value) {
+        this.value = value;
+    }
+
+    /**
+     * Get the tag class value.
+     * @return value
+     */
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * Tell it's universal or not.
+     * @return true if it's universal otherwise false
+     */
+    public boolean isUniversal() {
+        return this == UNIVERSAL;
+    }
+
+    public boolean isAppSpecific() {
+        return this == APPLICATION;
+    }
+
+    public boolean isContextSpecific() {
+        return this == CONTEXT_SPECIFIC;
+    }
+
+    public boolean isSpecific() {
+        return this == APPLICATION || this == CONTEXT_SPECIFIC;
+    }
+
+    /**
+     * Converted from an integer
+     * @param value The int value of tag class
+     * @return tag class
+     */
+    public static TagClass fromValue(int value) {
+        // Optimized by Emmanuel
+        switch (value) {
+            case 0x00:
+                return TagClass.UNIVERSAL;
+            case 0x40:
+                return TagClass.APPLICATION;
+            case 0x80:
+                return TagClass.CONTEXT_SPECIFIC;
+            case 0xC0:
+                return TagClass.PRIVATE;
+            default:
+                return TagClass.UNKNOWN;
+        }
+    }
+
+    /**
+     * Converted from a tag value, which contains tag class info.
+     * @param tag The int value of tag class
+     * @return tag class
+     */
+    public static TagClass fromTag(int tag) {
+        return fromValue(tag & 0xC0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/TaggingOption.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/TaggingOption.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/TaggingOption.java
new file mode 100644
index 0000000..154e1ab
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/TaggingOption.java
@@ -0,0 +1,119 @@
+/**
+ *  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;
+
+/**
+ * Tagging option for tagging an ASN1 type.
+ */
+public final class TaggingOption {
+    /** The tag number. We limit it to an int, although it's theorically unlimited */
+    private int tagNo;
+    
+    /** A flag set to TRUE when the tag is IMPLICIT */
+    private boolean isImplicit;
+    
+    /** A flag set to TRUE when the tag is an APPLICATION tag */
+    private boolean isAppSpecific;
+
+    /**
+     * Create an implicit application specific tagging option with tagNo.
+     * @param tagNo The tag number
+     * @return tagging option
+     */
+    public static TaggingOption newImplicitAppSpecific(int tagNo) {
+        return new TaggingOption(tagNo, true, true);
+    }
+
+    /**
+     * Create an explicit application specific tagging option with tagNo.
+     * @param tagNo The tag number
+     * @return tagging option
+     */
+    public static TaggingOption newExplicitAppSpecific(int tagNo) {
+        return new TaggingOption(tagNo, false, true);
+    }
+
+    /**
+     * Create an implicit context specific tagging option with tagNo.
+     * @param tagNo The tag number
+     * @return tagging option
+     */
+    public static TaggingOption newImplicitContextSpecific(int tagNo) {
+        return new TaggingOption(tagNo, true, false);
+    }
+
+    /**
+     * Create an explicit context specific tagging option with tagNo.
+     * @param tagNo The tag number
+     * @return tagging option
+     */
+    public static TaggingOption newExplicitContextSpecific(int tagNo) {
+        return new TaggingOption(tagNo, false, false);
+    }
+
+    /**
+     * The private constructor.
+     * @param tagNo The tag number
+     * @param isImplicit Implicit or not
+     * @param isAppSpecific App specific or not
+     */
+    private TaggingOption(int tagNo, boolean isImplicit, boolean isAppSpecific) {
+        this.tagNo = tagNo;
+        this.isImplicit = isImplicit;
+        this.isAppSpecific = isAppSpecific;
+    }
+
+    /**
+     * Make tag giving it's tagged constructed.
+     * @param isTaggedConstructed Tagged constructed or not
+     * @return tag
+     */
+    public Tag getTag(boolean isTaggedConstructed) {
+        boolean isConstructed = isImplicit ? isTaggedConstructed : true;
+        TagClass tagClass = isAppSpecific ? TagClass.APPLICATION : TagClass.CONTEXT_SPECIFIC;
+        int flags = tagClass.getValue() | (isConstructed ? 0x20 : 0x00);
+
+        return new Tag(flags, tagNo);
+    }
+
+    /**
+     * Get the tag number.
+     * @return tag number
+     */
+    public int getTagNo() {
+        return tagNo;
+    }
+
+    /**
+     * Tell it's application specific or not.
+     * @return true if it's application specific otherwise false
+     */
+    public boolean isAppSpecific() {
+        return isAppSpecific;
+    }
+
+    /**
+     * Tell it's implicit or not.
+     * @return true if it's implicit otherwise false
+     */
+    public boolean isImplicit() {
+        return isImplicit;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/UniversalTag.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/UniversalTag.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/UniversalTag.java
new file mode 100644
index 0000000..3fc5026
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/UniversalTag.java
@@ -0,0 +1,132 @@
+/**
+ *  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;
+
+/**
+ * An enumeration for every ASN.1 UNIVERSAL type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum UniversalTag {
+    UNKNOWN             (-1),
+    CHOICE              (-2),   // Only for internal using
+    ANY                 (-3),   // Only for internal using
+    EOC                 (0),    // End of content, use by BER
+    BOOLEAN             (0x01),
+    INTEGER             (0x02),
+    BIT_STRING          (0x03),
+    OCTET_STRING        (0x04),
+    NULL                (0x05),
+    OBJECT_IDENTIFIER   (0x06),
+    OBJECT_DESCRIPTOR   (0x07),
+    EXTERNAL            (0x08),
+    REAL                (0x09),
+    ENUMERATED          (0x0a),
+    EMBEDDED_PDV        (0x0b),
+    UTF8_STRING         (0x0c),
+    RELATIVE_OID        (0x0d),
+    RESERVED_14         (0x0e),
+    RESERVED_15         (0x0f),
+    SEQUENCE            (0x10),
+    SEQUENCE_OF         (0x10),
+    SET                 (0x11),
+    SET_OF              (0x11),
+    NUMERIC_STRING      (0x12),
+    PRINTABLE_STRING    (0x13),
+    T61_STRING          (0x14),
+    VIDEOTEX_STRING     (0x15),
+    IA5_STRING          (0x16),
+    UTC_TIME            (0x17),
+    GENERALIZED_TIME    (0x18),
+    GRAPHIC_STRING      (0x19),
+    VISIBLE_STRING      (0x1a),
+    GENERAL_STRING      (0x1b),
+    UNIVERSAL_STRING    (0x1c),
+    CHARACTER_STRING    (0x1d),
+    BMP_STRING          (0x1e),
+    RESERVED_31         (0x1f);
+
+    /** The tag value */
+    private int value;
+
+    /**
+     * Create an instance of this class
+     */
+    private UniversalTag(int value) {
+        this.value = value;
+    }
+
+    /**
+     * @return The associated tag value
+     */
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * Retrieve the UniversalTag associated with a given value
+     * @param value The integer value
+     * @return The associated UniversalTag
+     */
+    public static UniversalTag fromValue(int value) {
+        switch (value) {
+            case -2 : return CHOICE;
+            case 0x00 : return EOC;
+            case 0x01 : return BOOLEAN;
+            case 0x02 : return INTEGER;
+            case 0x03 : return BIT_STRING;
+            case 0x04 : return OCTET_STRING;
+            case 0x05 : return NULL;
+            case 0x06 : return OBJECT_IDENTIFIER;
+            case 0x07 : return OBJECT_DESCRIPTOR;
+            case 0x08 : return EXTERNAL;
+            case 0x09 : return REAL;
+            case 0x0A : return ENUMERATED;
+            case 0x0B : return EMBEDDED_PDV;
+            case 0x0C : return UTF8_STRING;
+            case 0x0D : return RELATIVE_OID;
+            case 0x0E : return RESERVED_14;
+            case 0x0F : return RESERVED_15;
+            case 0x10 : return SEQUENCE;
+            case 0x11 : return SET;
+            case 0x12 : return NUMERIC_STRING;
+            case 0x13 : return PRINTABLE_STRING;
+            case 0x14 : return T61_STRING;
+            case 0x15 : return VIDEOTEX_STRING;
+            case 0x16 : return IA5_STRING;
+            case 0x17 : return UTC_TIME;
+            case 0x18 : return GENERALIZED_TIME;
+            case 0x19 : return GRAPHIC_STRING;
+            case 0x1A : return VISIBLE_STRING;
+            case 0x1B : return GENERAL_STRING;
+            case 0x1C : return UNIVERSAL_STRING;
+            case 0x1D : return CHARACTER_STRING;
+            case 0x1E : return BMP_STRING;
+            case 0x1F : return RESERVED_31;
+            default : return UNKNOWN;
+        }
+    }
+
+    public String toStr() {
+        String typeStr = toString();
+        typeStr = typeStr.replace('_', ' ');
+        return typeStr.toLowerCase();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Container.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Container.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Container.java
new file mode 100644
index 0000000..d52b63f
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Container.java
@@ -0,0 +1,81 @@
+/**
+ *  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.parse;
+
+import org.apache.kerby.asn1.Asn1Dumpable;
+import org.apache.kerby.asn1.Asn1Dumper;
+
+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 Asn1Container
+    extends Asn1ParseResult implements Asn1Dumpable {
+
+    private List<Asn1ParseResult> children = new ArrayList<>();
+
+    public Asn1Container(Asn1Header header, int bodyStart, ByteBuffer buffer) {
+        super(header, bodyStart, buffer);
+    }
+
+    public List<Asn1ParseResult> getChildren() {
+        return children;
+    }
+
+    public void addItem(Asn1ParseResult value) {
+        children.add(value);
+    }
+
+    public void clear() {
+        children.clear();
+    }
+
+    @Override
+    public void dumpWith(Asn1Dumper dumper, int indents) {
+        dumper.indent(indents).append(toString());
+        if (children.size() > 0) {
+            dumper.newLine();
+        }
+
+        int i = children.size();
+        for (Asn1ParseResult aObj : children) {
+            dumper.dumpParseResult(indents + 4, aObj);
+            i--;
+            if (i > 0) {
+                dumper.newLine();
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        String typeStr = tag().typeStr();
+        typeStr += " ["
+            + "tag=" + tag()
+            + ", off=" + getOffset()
+            + ", len=" + getHeaderLength() + "+" + getBodyLength()
+            + (isDefinitiveLength() ? "" : "(undefined)")
+            + "]";
+        return typeStr;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1DerivedItem.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1DerivedItem.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1DerivedItem.java
new file mode 100644
index 0000000..41db80e
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1DerivedItem.java
@@ -0,0 +1,86 @@
+/**
+ *  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.parse;
+
+import org.apache.kerby.asn1.Tag;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Combine multiple parts in a container into a single item, for primitive types
+ * that use constructed encoding.
+ */
+public class Asn1DerivedItem extends Asn1Item {
+
+    private final Asn1Container container;
+    private final Tag newTag;
+    private int newBodyLength;
+    private ByteBuffer newBodyBuffer;
+
+    public Asn1DerivedItem(Tag newTag, Asn1Container container) {
+        super(container.getHeader(), container.getBodyStart(),
+            container.getBuffer());
+
+        this.newTag = newTag;
+        this.container = container;
+        this.newBodyLength = -1;
+    }
+
+    @Override
+    public Tag tag() {
+        return newTag;
+    }
+
+    private int computeBodyLength() {
+        int totalLen = 0;
+        for (Asn1ParseResult parseItem : container.getChildren()) {
+            totalLen += parseItem.getBodyLength();
+        }
+
+        return totalLen;
+    }
+
+    private ByteBuffer makeBodyBuffer() {
+        ByteBuffer tmpBuffer = ByteBuffer.allocate(getBodyLength());
+        for (Asn1ParseResult parseItem : container.getChildren()) {
+            tmpBuffer.put(parseItem.getBodyBuffer());
+        }
+        tmpBuffer.flip();
+
+        return tmpBuffer;
+    }
+
+    @Override
+    public ByteBuffer getBodyBuffer() {
+        if (newBodyBuffer == null) {
+            newBodyBuffer = makeBodyBuffer();
+        }
+        return newBodyBuffer;
+    }
+
+    @Override
+    public int getBodyLength() {
+        if (newBodyLength == -1) {
+            newBodyLength = computeBodyLength();
+        }
+
+        return newBodyLength;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Header.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Header.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Header.java
new file mode 100644
index 0000000..8d90ac1
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Header.java
@@ -0,0 +1,48 @@
+/**
+ *  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.parse;
+
+import org.apache.kerby.asn1.Tag;
+
+public class Asn1Header {
+    private Tag tag;
+    private int length;
+
+    public Asn1Header(Tag tag, int length) {
+        this.tag = tag;
+        this.length = length;
+    }
+
+    public Tag getTag() {
+        return tag;
+    }
+
+    public int getLength() {
+        return length;
+    }
+
+    public boolean isEOC() {
+        return length == 0 && tag.isEOC();
+    }
+
+    public boolean isDefinitiveLength() {
+        return length != -1;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Item.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Item.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Item.java
new file mode 100644
index 0000000..066d0aa
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Item.java
@@ -0,0 +1,34 @@
+/**
+ *  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.parse;
+
+import java.nio.ByteBuffer;
+
+public class Asn1Item extends Asn1ParseResult {
+
+    public Asn1Item(Asn1Header header, int bodyStart, ByteBuffer buffer) {
+        super(header, bodyStart, buffer);
+    }
+
+    @Override
+    public String toString() {
+        return simpleInfo();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1ParseResult.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1ParseResult.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1ParseResult.java
new file mode 100644
index 0000000..0152cfc
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1ParseResult.java
@@ -0,0 +1,124 @@
+/**
+ *  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.parse;
+
+import org.apache.kerby.asn1.type.Asn1Object;
+import org.apache.kerby.asn1.util.Asn1Util;
+
+import java.nio.ByteBuffer;
+
+public abstract class Asn1ParseResult extends Asn1Object {
+    private Asn1Header header;
+    private int bodyStart;
+    private int bodyEnd;
+    private ByteBuffer buffer;
+
+    public Asn1ParseResult(Asn1Header header,
+                           int bodyStart, ByteBuffer buffer) {
+        super(header.getTag());
+        this.header = header;
+        this.bodyStart = bodyStart;
+        this.buffer = buffer;
+
+        this.bodyEnd = isDefinitiveLength() ? bodyStart + header.getLength() : -1;
+    }
+
+    public Asn1Header getHeader() {
+        return header;
+    }
+
+    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 byte[] readBodyBytes() {
+        ByteBuffer bodyBuffer = getBodyBuffer();
+        byte[] result = new byte[bodyBuffer.remaining()];
+        bodyBuffer.get(result);
+        return result;
+    }
+
+    public boolean isDefinitiveLength() {
+        return header.isDefinitiveLength();
+    }
+
+    public int getEncodingLength() {
+        return getHeaderLength() + getBodyLength();
+    }
+
+    public int getHeaderLength() {
+        int bodyLen = getBodyLength();
+        int headerLen = Asn1Util.lengthOfTagLength(header.getTag().tagNo());
+        headerLen += (header.isDefinitiveLength()
+            ? Asn1Util.lengthOfBodyLength(bodyLen) : 1);
+        return headerLen;
+    }
+
+    public int getOffset() {
+        return getBodyStart() - getHeaderLength();
+    }
+
+    public int getBodyLength() {
+        if (isDefinitiveLength()) {
+            return header.getLength();
+        } else if (getBodyEnd() != -1) {
+            return getBodyEnd() - getBodyStart();
+        }
+        return -1;
+    }
+
+
+    public boolean checkBodyFinished(int pos) {
+        return getBodyEnd() != -1 && pos >= getBodyEnd();
+    }
+
+    @Override
+    public String simpleInfo() {
+        return tag().typeStr() + " ["
+            + "tag=" + tag()
+            + ", off=" + getOffset()
+            + ", len=" + getHeaderLength() + "+" + getBodyLength()
+            + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Parser.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Parser.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Parser.java
new file mode 100644
index 0000000..ff90719
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Parser.java
@@ -0,0 +1,85 @@
+/**
+ *  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.parse;
+
+import org.apache.kerby.asn1.Tag;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * ASN1 parser.
+ */
+public class Asn1Parser {
+
+    public static void parse(Asn1Container container) throws IOException {
+        Asn1Reader reader = new Asn1Reader(container.getBuffer());
+        int pos = container.getBodyStart();
+        while (true) {
+            reader.setPosition(pos);
+            Asn1ParseResult asn1Obj = parse(reader);
+            if (asn1Obj == null) {
+                break;
+            }
+
+            container.addItem(asn1Obj);
+
+            pos += asn1Obj.getEncodingLength();
+            if (asn1Obj.isEOC()) {
+                break;
+            }
+
+            if (container.checkBodyFinished(pos)) {
+                break;
+            }
+        }
+
+        container.setBodyEnd(pos);
+    }
+
+    public static Asn1ParseResult parse(ByteBuffer content) throws IOException {
+        Asn1Reader reader = new Asn1Reader(content);
+        return parse(reader);
+    }
+
+    public static Asn1ParseResult parse(Asn1Reader reader) throws IOException {
+        if (!reader.available()) {
+            return null;
+        }
+
+        Asn1Header header = reader.readHeader();
+        Tag tmpTag = header.getTag();
+        int bodyStart = reader.getPosition();
+        Asn1ParseResult parseResult;
+
+        if (tmpTag.isPrimitive()) {
+            parseResult = new Asn1Item(header, bodyStart, reader.getBuffer());
+        } else {
+            Asn1Container container = new Asn1Container(header,
+                bodyStart, reader.getBuffer());
+            if (header.getLength() != 0) {
+                parse(container);
+            }
+            parseResult = container;
+        }
+
+        return parseResult;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Reader.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Reader.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Reader.java
new file mode 100644
index 0000000..89994f8
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/parse/Asn1Reader.java
@@ -0,0 +1,126 @@
+/**
+ *  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.parse;
+
+import org.apache.kerby.asn1.Tag;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * ASN1 reader for positional reading.
+ */
+public final class Asn1Reader {
+    private ByteBuffer buffer;
+    private int position;
+
+    public ByteBuffer getBuffer() {
+        return buffer;
+    }
+
+    public Asn1Header readHeader() throws IOException {
+        Tag tag = readTag();
+        int valueLength = readLength();
+        Asn1Header header = new Asn1Header(tag, valueLength);
+        return header;
+    }
+
+    public Asn1Reader(ByteBuffer buffer) {
+        this.buffer = buffer;
+        this.position = buffer.position();
+    }
+
+    public int getPosition() {
+        return position;
+    }
+
+    public void setPosition(int position) {
+        this.position = position;
+    }
+
+    public boolean available() {
+        return position < buffer.limit();
+    }
+
+    protected byte readByte() throws IOException {
+        return buffer.get(position++);
+    }
+
+    private Tag readTag() throws IOException {
+        int tagFlags = readTagFlags();
+        int tagNo = readTagNo(tagFlags);
+        return new Tag(tagFlags, tagNo);
+    }
+
+    private int readTagFlags() throws IOException {
+        int tagFlags = readByte() & 0xff;
+        return tagFlags;
+    }
+
+    private int readTagNo(int tagFlags) throws IOException {
+        int tagNo = tagFlags & 0x1f;
+
+        if (tagNo == 0x1f) {
+            tagNo = 0;
+
+            int b = readByte() & 0xff;
+            if ((b & 0x7f) == 0) {
+                throw new IOException("Invalid high tag number found");
+            }
+
+            while (b >= 0 && (b & 0x80) != 0) {
+                tagNo |= b & 0x7f;
+                tagNo <<= 7;
+                b = readByte();
+            }
+
+            tagNo |= b & 0x7f;
+        }
+
+        return tagNo;
+    }
+
+    private int readLength() throws IOException {
+        int result = readByte() & 0xff;
+        if (result == 0x80) {
+            return -1; // non-definitive length
+        }
+
+        if (result > 127) {
+            int length = result & 0x7f;
+            if (length > 4) {
+                throw new IOException("Bad length of more than 4 bytes: " + length);
+            }
+
+            result = 0;
+            int tmp;
+            for (int i = 0; i < length; i++) {
+                tmp = readByte() & 0xff;
+                result = (result << 8) + tmp;
+            }
+        }
+
+        if (result < 0) {
+            throw new IOException("Invalid length " + result);
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/AbstractAsn1Type.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/AbstractAsn1Type.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/AbstractAsn1Type.java
new file mode 100644
index 0000000..96c68a1
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/AbstractAsn1Type.java
@@ -0,0 +1,83 @@
+/**
+ *  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.Tag;
+import org.apache.kerby.asn1.UniversalTag;
+
+/**
+ * The abstract ASN1 type for all the ASN1 types. It provides basic
+ * encoding and decoding utilities.
+ *
+ * @param <T> the type of the value encoded/decoded or wrapped by this
+ */
+public abstract class AbstractAsn1Type<T> extends Asn1Encodeable {
+    // The wrapped real value.
+    private T value;
+
+    /**
+     * Default constructor.
+     * @param tag the tag
+     * @param value the value
+     */
+    public AbstractAsn1Type(Tag tag, T value) {
+        super(tag);
+        this.value = value;
+    }
+
+    /**
+     * Default constructor.
+     * @param tag the tag
+     */
+    public AbstractAsn1Type(Tag tag) {
+        super(tag);
+    }
+
+    /**
+     * Default constructor with an universal tag.
+     * @param tag the tag
+     * @param value the value
+     */
+    public AbstractAsn1Type(UniversalTag tag, T value) {
+        super(tag);
+        this.value = value;
+    }
+
+    /**
+     * Default constructor with an universal tag.
+     * @param tag the tag
+     */
+    public AbstractAsn1Type(UniversalTag tag) {
+        super(tag);
+    }
+
+    public T getValue() {
+        return value;
+    }
+
+    public void setValue(T value) {
+        this.value = value;
+    }
+
+    @Override
+    public String toString() {
+        return tag().typeStr();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Any.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Any.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Any.java
new file mode 100644
index 0000000..3c35173
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1Any.java
@@ -0,0 +1,212 @@
+/**
+ *  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.Asn1Binder;
+import org.apache.kerby.asn1.Asn1Converter;
+import org.apache.kerby.asn1.Asn1Dumpable;
+import org.apache.kerby.asn1.Asn1Dumper;
+import org.apache.kerby.asn1.Asn1FieldInfo;
+import org.apache.kerby.asn1.Tag;
+import org.apache.kerby.asn1.TaggingOption;
+import org.apache.kerby.asn1.UniversalTag;
+import org.apache.kerby.asn1.parse.Asn1ParseResult;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Can be any valid ASN-1 ojbect, limited or not limited.
+ */
+public class Asn1Any
+    extends AbstractAsn1Type<Asn1Type> implements Asn1Dumpable {
+    private Class<? extends Asn1Type> valueType;
+    private Asn1FieldInfo decodeInfo;
+    private Asn1ParseResult parseResult;
+    private boolean isBlindlyDecoded = true;
+
+    public Asn1Any() {
+        super(UniversalTag.ANY);
+    }
+
+    public Asn1Any(Asn1Type anyValue) {
+        this();
+        setValue(anyValue);
+    }
+
+    @Override
+    public Tag tag() {
+        if (getValue() != null) {
+            return getValue().tag();
+        } else if (parseResult != null) {
+            return parseResult.tag();
+        }
+        return super.tag();
+    }
+
+    public void setValueType(Class<? extends Asn1Type> valueType) {
+        this.valueType = valueType;
+    }
+
+    public void setDecodeInfo(Asn1FieldInfo decodeInfo) {
+        this.decodeInfo = decodeInfo;
+    }
+
+    public Asn1ParseResult getParseResult() {
+        return parseResult;
+    }
+
+    @Override
+    public void encode(ByteBuffer buffer) throws IOException {
+        Asn1Encodeable theValue = (Asn1Encodeable) getValue();
+
+        if (theValue != null) {
+            if (!isBlindlyDecoded) {
+                if (decodeInfo.isTagged()) {
+                    TaggingOption taggingOption =
+                        decodeInfo.getTaggingOption();
+                    theValue.taggedEncode(buffer, taggingOption);
+                } else {
+                    theValue.encode(buffer);
+                }
+            } else {
+                theValue.encode(buffer);
+            }
+        }
+    }
+
+    @Override
+    public int encodingLength() {
+        Asn1Encodeable theValue = (Asn1Encodeable) getValue();
+
+        if (theValue != null) {
+            if (!isBlindlyDecoded) {
+                if (decodeInfo.isTagged()) {
+                    TaggingOption taggingOption =
+                        decodeInfo.getTaggingOption();
+                    return theValue.taggedEncodingLength(taggingOption);
+                } else {
+                    return theValue.encodingLength();
+                }
+            } else {
+                return theValue.encodingLength();
+            }
+        }
+
+        return super.encodingLength();
+    }
+
+    @Override
+    protected int encodingBodyLength() {
+        Asn1Encodeable theValue = (Asn1Encodeable) getValue();
+
+        if (theValue == null) {
+            return 0;
+        }
+
+        return -1; // Indicate error, shouldn't be here.
+    }
+
+    @Override
+    public void decode(ByteBuffer content) throws IOException {
+        setValue(null);
+
+        super.decode(content);
+    }
+
+    @Override
+    public void decode(Asn1ParseResult parseResult) throws IOException {
+        // Avoid the tag checking here.
+        decodeBody(parseResult);
+    }
+
+    @Override
+    protected void decodeBody(Asn1ParseResult parseResult) throws IOException {
+        this.parseResult = parseResult;
+
+        if (valueType != null) {
+            typeAwareDecode(valueType);
+        } else {
+            blindlyDecode();
+        }
+    }
+
+    private void blindlyDecode() throws IOException {
+        Asn1Type anyValue = Asn1Converter.convert(parseResult, false);
+        if (decodeInfo != null && decodeInfo.isTagged()) {
+            // Escape the wrapper
+            Asn1Constructed constructed = (Asn1Constructed) anyValue;
+            Asn1Type innerValue = constructed.getValue().get(0);
+            setValue(innerValue);
+        } else {
+            setValue(anyValue);
+        }
+
+        isBlindlyDecoded = true;
+    }
+
+    protected <T extends Asn1Type> T getValueAs(Class<T> t) {
+        Asn1Type value = getValue();
+        if (value != null && !isBlindlyDecoded) {
+            return (T) value;
+        }
+
+        if (valueType != null && valueType != t) {
+            throw new RuntimeException("Required value type isn't the same"
+            + " with the value type set before");
+        }
+
+        try {
+            typeAwareDecode(t);
+        } catch (IOException e) {
+            throw new RuntimeException("Type aware decoding of Any type failed");
+        }
+
+        return (T) getValue();
+    }
+
+    private <T extends Asn1Type> void typeAwareDecode(Class<T> t) throws IOException {
+        T result;
+        try {
+            result = t.newInstance();
+        } catch (Exception e) {
+            throw new IOException("No default constructor?", e);
+        }
+
+        if (parseResult.isContextSpecific()) {
+            Asn1Binder.bindWithTagging(parseResult, result,
+                decodeInfo.getTaggingOption());
+        } else {
+            Asn1Binder.bind(parseResult, result);
+        }
+
+        setValue(result);
+        isBlindlyDecoded = false;
+    }
+
+    @Override
+    public void dumpWith(Asn1Dumper dumper, int indents) {
+        Asn1Type theValue = getValue();
+        dumper.indent(indents).append("<Any>").newLine();
+        //dumper.append(simpleInfo()).newLine();
+        dumper.dumpType(indents, theValue);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BitString.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BitString.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BitString.java
new file mode 100644
index 0000000..1b921e1
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BitString.java
@@ -0,0 +1,108 @@
+/**
+ *  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.UniversalTag;
+
+import java.io.IOException;
+
+public class Asn1BitString extends Asn1Simple<byte[]> {
+    private int padding;
+
+    public Asn1BitString() {
+        this(null);
+    }
+
+    public Asn1BitString(byte[] value) {
+        this(value, 0);
+    }
+
+    public Asn1BitString(byte[] value, int padding) {
+        super(UniversalTag.BIT_STRING, value);
+        this.padding = padding;
+    }
+
+    public void setPadding(int padding) {
+        this.padding = padding;
+    }
+
+    public int getPadding() {
+        return padding;
+    }
+
+    @Override
+    protected int encodingBodyLength() {
+        byte[] body = getValue();
+        if (body != null) {
+            return body.length + 1;
+        }
+        return 0;
+    }
+
+    @Override
+    protected void toBytes() {
+        byte[] bytes = new byte[encodingBodyLength()];
+        byte[] body = getValue();
+        if (body != null) {
+            bytes[0] = (byte) padding;
+            System.arraycopy(body, 0, bytes, 1, bytes.length - 1);
+        }
+        setBytes(bytes);
+    }
+
+    @Override
+    protected void toValue() throws IOException {
+        byte[] bytes = getBytes();
+        if (bytes.length < 1) {
+            throw new IOException("Bad stream, zero bytes found for bitstring");
+        }
+        int paddingBits = bytes[0];
+        validatePaddingBits(paddingBits);
+        setPadding(paddingBits);
+
+        byte[] newBytes = new byte[bytes.length - 1];
+        if (bytes.length > 1) {
+            System.arraycopy(bytes, 1, newBytes, 0, bytes.length - 1);
+        }
+        setValue(newBytes);
+    }
+
+    private void validatePaddingBits(int paddingBits) throws IOException {
+        if (paddingBits < 0 || paddingBits > 7) {
+            throw new IOException("Bad padding number: " + paddingBits + ", should be in [0, 7]");
+        }
+    }
+
+    @Override
+    public String toString() {
+        String typeStr = tag().typeStr() + " ["
+            + "tag=" + tag()
+            + ", len=" + getHeaderLength() + "+" + getBodyLength()
+            + "] ";
+
+        byte[] valueBytes = getValue();
+        String valueStr = "<null>";
+        if (valueBytes != null) {
+            valueStr = "<" + valueBytes.length + " bytes>";
+        }
+
+        return typeStr + valueStr;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9e4dbd6e/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BmpString.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BmpString.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BmpString.java
new file mode 100644
index 0000000..294649e
--- /dev/null
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/type/Asn1BmpString.java
@@ -0,0 +1,70 @@
+/**
+ *  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.UniversalTag;
+import org.apache.kerby.asn1.parse.Asn1ParseResult;
+
+import java.io.IOException;
+
+public class Asn1BmpString extends Asn1Simple<String> {
+    public Asn1BmpString() {
+        super(UniversalTag.BMP_STRING);
+    }
+
+    public Asn1BmpString(String value) {
+        super(UniversalTag.BMP_STRING, value);
+    }
+
+    @Override
+    protected int encodingBodyLength() {
+        return getValue().length() * 2;
+    }
+
+    protected void toBytes() {
+        String strValue = getValue();
+        int len = strValue.length();
+        byte[] bytes = new byte[len * 2];
+        
+        for (int i = 0; i != len; i++) {
+            char c = strValue.charAt(i);
+            bytes[2 * i] = (byte) (c >> 8);
+            bytes[2 * i + 1] = (byte) c;
+        }
+        setBytes(bytes);
+    }
+
+    protected void toValue() throws IOException {
+        byte[] bytes = getBytes();
+        char[] chars = new char[bytes.length / 2];
+        for (int i = 0; i != chars.length; i++) {
+            chars[i] = (char) ((bytes[2 * i] << 8) | (bytes[2 * i + 1] & 0xff));
+        }
+        setValue(new String(chars));
+    }
+
+    @Override
+    protected void decodeBody(Asn1ParseResult parseResult) throws IOException {
+        if (parseResult.getBodyLength() % 2 != 0) {
+            throw new IOException("Bad stream, BMP string expecting multiple of 2 bytes");
+        }
+        super.decodeBody(parseResult);
+    }
+}


Mime
View raw message