Use local copy of latest bndlib code for pre-release testing purposes
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1347815 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/libg/asn1/BER.java b/bundleplugin/src/main/java/aQute/libg/asn1/BER.java
new file mode 100644
index 0000000..4416dd4
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/asn1/BER.java
@@ -0,0 +1,472 @@
+package aQute.libg.asn1;
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+
+public class BER implements Types {
+ DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss\\Z");
+
+ final DataInputStream xin;
+ long position;
+
+ public BER(InputStream in) {
+ this.xin = new DataInputStream(in);
+ }
+
+ public void dump(PrintStream out) throws Exception {
+ int type = readByte();
+ long length = readLength();
+ if (type == -1 || length == -1)
+ throw new EOFException("Empty file");
+ dump(out, type, length, "");
+ }
+
+ void dump(PrintStream out, int type, long length, String indent)
+ throws Exception {
+ int clss = type >> 6;
+ int nmbr = type & 0x1F;
+ boolean cnst = (type & 0x20) != 0;
+
+ String tag = "[" + nmbr + "]";
+ if (clss == 0)
+ tag = TAGS[nmbr];
+
+ if (cnst) {
+ System.err.printf("%5d %s %s %s%n", length, indent, CLASSES[clss],
+ tag);
+ while (length > 1) {
+ long atStart = getPosition();
+ int t2 = read();
+ long l2 = readLength();
+ dump(out, t2, l2, indent + " ");
+ length -= getPosition() - atStart;
+ }
+ } else {
+ assert length < Integer.MAX_VALUE;
+ assert length >= 0;
+ byte[] data = new byte[(int) length];
+ readFully(data);
+ String summary;
+
+ switch (nmbr) {
+ case BOOLEAN:
+ assert length == 1;
+ summary = data[0] != 0 ? "true" : "false";
+ break;
+
+ case INTEGER:
+ long n = toLong(data);
+ summary = n + "";
+ break;
+
+ case UTF8_STRING:
+ case IA5STRING:
+ case VISIBLE_STRING:
+ case UNIVERSAL_STRING:
+ case PRINTABLE_STRING:
+ case UTCTIME:
+ summary = new String(data, "UTF-8");
+ break;
+
+ case OBJECT_IDENTIFIER:
+ summary = readOID(data);
+ break;
+
+ case GENERALIZED_TIME:
+ case GRAPHIC_STRING:
+ case GENERAL_STRING:
+ case CHARACTER_STRING:
+
+ case REAL:
+ case EOC:
+ case BIT_STRING:
+ case OCTET_STRING:
+ case NULL:
+ case OBJECT_DESCRIPTOR:
+ case EXTERNAL:
+ case ENUMERATED:
+ case EMBEDDED_PDV:
+ case RELATIVE_OID:
+ case NUMERIC_STRING:
+ case T61_STRING:
+ case VIDEOTEX_STRING:
+ case BMP_STRING:
+ default:
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 10 && i < data.length; i++) {
+ sb.append(Integer.toHexString(data[i]));
+ }
+ if (data.length > 10) {
+ sb.append("...");
+ }
+ summary = sb.toString();
+ break;
+ }
+ out.printf("%5d %s %s %s %s\n", length, indent, CLASSES[clss], tag,
+ summary);
+ }
+ }
+
+ long toLong(byte[] data) {
+ if (data[0] < 0) {
+ for (int i = 0; i < data.length; i++)
+ data[i] = (byte) (0xFF ^ data[i]);
+
+ return -(toLong(data) + 1);
+ }
+ long n = 0;
+ for (int i = 0; i < data.length; i++) {
+ n = n * 256 + data[i];
+ }
+ return n;
+ }
+
+ /**
+ * 8.1.3.3 For the definite form, the length octets shall consist of one or
+ * more octets, and shall represent the number of octets in the contents
+ * octets using either the short form (see 8.1.3.4) or the long form (see
+ * 8.1.3.5) as a sender's option. NOTE – The short form can only be used if
+ * the number of octets in the contents octets is less than or equal to 127.
+ * 8.1.3.4 In the short form, the length octets shall consist of a single
+ * octet in which bit 8 is zero and bits 7 to 1 encode the number of octets
+ * in the contents octets (which may be zero), as an unsigned binary integer
+ * with bit 7 as the most significant bit. EXAMPLE L = 38 can be encoded as
+ * 001001102 8.1.3.5 In the long form, the length octets shall consist of an
+ * initial octet and one or more subsequent octets. The initial octet shall
+ * be encoded as follows: a) bit 8 shall be one; b) bits 7 to 1 shall encode
+ * the number of subsequent octets in the length octets, as an unsigned
+ * binary integer with bit 7 as the most significant bit; c) the value
+ * 111111112 shall not be used. ISO/IEC 8825-1:2003 (E) NOTE 1 – This
+ * restriction is introduced for possible future extension. Bits 8 to 1 of
+ * the first subsequent octet, followed by bits 8 to 1 of the second
+ * subsequent octet, followed in turn by bits 8 to 1 of each further octet
+ * up to and including the last subsequent octet, shall be the encoding of
+ * an unsigned binary integer equal to the number of octets in the contents
+ * octets, with bit 8 of the first subsequent octet as the most significant
+ * bit. EXAMPLE L = 201 can be encoded as: 100000012 110010012 NOTE 2 – In
+ * the long form, it is a sender's option whether to use more length octets
+ * than the minimum necessary. 8.1.3.6 For the indefinite form, the length
+ * octets indicate that the contents octets are terminated by
+ * end-of-contents octets (see 8.1.5), and shall consist of a single octet.
+ * 8.1.3.6.1 The single octet shall have bit 8 set to one, and bits 7 to 1
+ * set to zero. 8.1.3.6.2 If this form of length is used, then
+ * end-of-contents octets (see 8.1.5) shall be present in the encoding
+ * following the contents octets. 8.1.4 Contents octets The contents octets
+ * shall consist of zero, one or more octets, and shall encode the data
+ * value as specified in subsequent clauses. NOTE – The contents octets
+ * depend on the type of the data value; subsequent clauses follow the same
+ * sequence as the definition of types in ASN.1. 8.1.5 End-of-contents
+ * octets The end-of-contents octets shall be present if the length is
+ * encoded as specified in 8.1.3.6, otherwise they shall not be present. The
+ * end-of-contents octets shall consist of two zero octets. NOTE – The
+ * end-of-contents octets can be considered as the encoding of a value whose
+ * tag is universal class, whose form is primitive, whose number of the tag
+ * is zero, and whose contents are absent, thus:
+ *
+ * End-of-contents Length Contents 0016 0016 Absent
+ *
+ * @return
+ */
+ private long readLength() throws IOException {
+ long n = readByte();
+ if (n > 0) {
+ // short form
+ return n;
+ }
+ // long form
+ int count = (int) (n & 0x7F);
+ if (count == 0) {
+ // indefinite form
+ return 0;
+ }
+ n = 0;
+ while (count-- > 0) {
+ n = n * 256 + read();
+ }
+ return n;
+ }
+
+ private int readByte() throws IOException {
+ position++;
+ return xin.readByte();
+ }
+
+ private void readFully(byte[] data) throws IOException {
+ position += data.length;
+ xin.readFully(data);
+ }
+
+ private long getPosition() {
+ return position;
+ }
+
+ private int read() throws IOException {
+ position++;
+ return xin.read();
+ }
+
+ String readOID(byte[] data) {
+ StringBuilder sb = new StringBuilder();
+ sb.append((0xFF & data[0]) / 40);
+ sb.append(".");
+ sb.append((0xFF & data[0]) % 40);
+
+ int i = 0;
+ while (++i < data.length) {
+ int n = 0;
+ while (data[i] < 0) {
+ n = n * 128 + (0x7F & data[i]);
+ i++;
+ }
+ n = n * 128 + data[i];
+ sb.append(".");
+ sb.append(n);
+ }
+
+ return sb.toString();
+ }
+
+ int getPayloadLength(PDU pdu) throws Exception {
+ switch (pdu.getTag() & 0x1F) {
+ case EOC:
+ return 1;
+
+ case BOOLEAN:
+ return 1;
+
+ case INTEGER:
+ return size(pdu.getInt());
+
+ case UTF8_STRING:
+ String s = pdu.getString();
+ byte[] encoded = s.getBytes("UTF-8");
+ return encoded.length;
+
+ case IA5STRING:
+ case VISIBLE_STRING:
+ case UNIVERSAL_STRING:
+ case PRINTABLE_STRING:
+ case GENERALIZED_TIME:
+ case GRAPHIC_STRING:
+ case GENERAL_STRING:
+ case CHARACTER_STRING:
+ case UTCTIME:
+ case NUMERIC_STRING: {
+ String str = pdu.getString();
+ encoded = str.getBytes("ASCII");
+ return encoded.length;
+ }
+
+ case OBJECT_IDENTIFIER:
+ case REAL:
+ case BIT_STRING:
+ return pdu.getBytes().length;
+
+ case OCTET_STRING:
+ case NULL:
+ case OBJECT_DESCRIPTOR:
+ case EXTERNAL:
+ case ENUMERATED:
+ case EMBEDDED_PDV:
+ case RELATIVE_OID:
+ case T61_STRING:
+ case VIDEOTEX_STRING:
+ case BMP_STRING:
+ return pdu.getBytes().length;
+
+ default:
+ throw new IllegalArgumentException("Invalid type: " + pdu);
+ }
+ }
+
+ int size(long value) {
+ if (value < 128)
+ return 1;
+
+ if (value <= 0xFF)
+ return 2;
+
+ if (value <= 0xFFFF)
+ return 3;
+
+ if (value <= 0xFFFFFF)
+ return 4;
+
+ if (value <= 0xFFFFFFFF)
+ return 5;
+
+ if (value <= 0xFFFFFFFFFFL)
+ return 6;
+
+ if (value <= 0xFFFFFFFFFFFFL)
+ return 7;
+
+ if (value <= 0xFFFFFFFFFFFFFFL)
+ return 8;
+
+ if (value <= 0xFFFFFFFFFFFFFFFFL)
+ return 9;
+
+ throw new IllegalArgumentException("length too long");
+ }
+
+ public void write(OutputStream out, PDU pdu) throws Exception {
+ byte id = 0;
+
+ switch (pdu.getClss()) {
+ case UNIVERSAL:
+ id |= 0;
+ break;
+ case APPLICATION:
+ id |= 0x40;
+ break;
+ case CONTEXT:
+ id |= 0x80;
+ break;
+ case PRIVATE:
+ id |= 0xC0;
+ break;
+ }
+
+ if (pdu.isConstructed())
+ id |= 0x20;
+
+ int tag = pdu.getTag();
+ if (tag >= 0 && tag < 31) {
+ id |= tag;
+ } else {
+ throw new UnsupportedOperationException("Cant do tags > 30");
+ }
+
+ out.write(id);
+
+ int length = getPayloadLength(pdu);
+ int size = size(length);
+ if (size == 1) {
+ out.write(length);
+ } else {
+ out.write(size);
+ while (--size >= 0) {
+ byte data = (byte) ((length >> (size * 8)) & 0xFF);
+ out.write(data);
+ }
+ }
+ writePayload(out, pdu);
+ }
+
+ void writePayload(OutputStream out, PDU pdu) throws Exception {
+ switch (pdu.getTag()) {
+ case EOC:
+ out.write(0);
+ break;
+
+ case BOOLEAN:
+ if (pdu.getBoolean())
+ out.write(-1);
+ else
+ out.write(0);
+ break;
+
+ case ENUMERATED:
+ case INTEGER: {
+ long value = pdu.getInt();
+ int size = size(value);
+ for (int i = size; i >= 0; i--) {
+ byte b = (byte) ((value >> (i * 8)) & 0xFF);
+ out.write(b);
+ }
+ }
+
+ case BIT_STRING: {
+ byte bytes[] = pdu.getBytes();
+ int unused = bytes[0];
+ assert unused <= 7;
+ int[] mask = { 0xFF, 0x7F, 0x3F, 0x1F, 0xF, 0x7, 0x3, 0x1 };
+ bytes[bytes.length - 1] &= (byte) mask[unused];
+ out.write(bytes);
+ break;
+ }
+
+ case RELATIVE_OID:
+ case OBJECT_IDENTIFIER: {
+ int[] oid = pdu.getOID();
+ assert oid.length > 2;
+ assert oid[0] < 4;
+ assert oid[1] < 40;
+ byte top = (byte) (oid[0] * 40 + oid[1]);
+ out.write(top);
+ for (int i = 2; i < oid.length; i++) {
+ putOid(out,oid[i]);
+ }
+ break;
+ }
+
+ case OCTET_STRING: {
+ byte bytes[] = pdu.getBytes();
+ out.write(bytes);
+ break;
+ }
+
+ case NULL:
+ break;
+
+ case BMP_STRING:
+ case GRAPHIC_STRING:
+ case VISIBLE_STRING:
+ case GENERAL_STRING:
+ case UNIVERSAL_STRING:
+ case CHARACTER_STRING:
+ case NUMERIC_STRING:
+ case PRINTABLE_STRING:
+ case VIDEOTEX_STRING:
+ case T61_STRING:
+ case REAL:
+ case EMBEDDED_PDV:
+ case EXTERNAL:
+ throw new UnsupportedEncodingException("dont know real, embedded PDV or external");
+
+ case UTF8_STRING: {
+ String s = pdu.getString();
+ byte [] data = s.getBytes("UTF-8");
+ out.write(data);
+ break;
+ }
+
+ case OBJECT_DESCRIPTOR:
+ case IA5STRING:
+ String s = pdu.getString();
+ byte [] data = s.getBytes("ASCII");
+ out.write(data);
+ break;
+
+
+ case SEQUENCE:
+ case SET: {
+ PDU pdus[] = pdu.getChildren();
+ for ( PDU p : pdus ) {
+ write(out, p);
+ }
+ }
+
+
+ case UTCTIME:
+ case GENERALIZED_TIME:
+ Date date = pdu.getDate();
+ String ss= df.format(date);
+ byte d[] = ss.getBytes("ASCII");
+ out.write(d);
+ break;
+
+ }
+ }
+
+
+ private void putOid(OutputStream out, int i) throws IOException {
+ if (i > 127) {
+ putOid(out, i >> 7);
+ out.write(0x80 + (i & 0x7F));
+ } else
+ out.write(i & 0x7F);
+ }
+}
diff --git a/bundleplugin/src/main/java/aQute/libg/asn1/PDU.java b/bundleplugin/src/main/java/aQute/libg/asn1/PDU.java
new file mode 100644
index 0000000..033928c
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/asn1/PDU.java
@@ -0,0 +1,114 @@
+package aQute.libg.asn1;
+
+import java.util.*;
+
+public class PDU implements Types, Iterable<PDU> {
+ final int identifier;
+ final Object payload;
+ byte data[] = new byte[100];
+
+
+ public PDU(int id, Object payload) {
+ identifier = id;
+ this.payload = payload;
+ }
+
+ public PDU(Date payload) {
+ identifier = UTCTIME;
+ this.payload = payload;
+ }
+
+ public PDU(int n) {
+ this(UNIVERSAL+INTEGER, n);
+ }
+
+ public PDU(boolean value) {
+ this(UNIVERSAL+BOOLEAN, value);
+ }
+
+ public PDU(String s) throws Exception {
+ this(UNIVERSAL+IA5STRING, s);
+ }
+
+ public PDU(byte[] data) {
+ this(UNIVERSAL+OCTET_STRING, data);
+ }
+
+ public PDU(BitSet bits) {
+ this(UNIVERSAL+BIT_STRING, bits);
+ }
+
+ public PDU(int top, int l1, int... remainder) {
+ identifier = UNIVERSAL+OBJECT_IDENTIFIER;
+ int[] ids = new int[remainder.length + 2];
+ ids[0] = top;
+ ids[1] = l1;
+ System.arraycopy(remainder, 0, ids, 2, remainder.length);
+ payload = ids;
+ }
+
+ public PDU(int tag, PDU... set) {
+ this(tag,(Object)set);
+ }
+
+ public PDU(PDU... set) {
+ this(SEQUENCE+CONSTRUCTED,set);
+ }
+
+
+ public int getTag() {
+ return identifier & TAGMASK;
+ }
+
+ int getClss() {
+ return identifier & CLASSMASK;
+ }
+
+ public boolean isConstructed() {
+ return (identifier & CONSTRUCTED) != 0;
+ }
+
+ public String getString() {
+ return (String) payload;
+ }
+
+ public Iterator<PDU> iterator() {
+ return Arrays.asList((PDU[]) payload).iterator();
+ }
+
+
+ public int[] getOID() {
+ assert getTag() == OBJECT_IDENTIFIER;
+ return (int[]) payload;
+ }
+
+ public Boolean getBoolean() {
+ assert getTag() == BOOLEAN;
+ return (Boolean) payload;
+ }
+
+ public BitSet getBits() {
+ assert getTag() == BIT_STRING;
+ return (BitSet) payload;
+ }
+
+ public int getInt() {
+ assert getTag() == INTEGER || getTag() == ENUMERATED;
+ return (Integer) payload;
+ }
+
+ public byte[] getBytes() {
+ return (byte[]) payload;
+ }
+
+ public PDU[] getChildren() {
+ assert isConstructed();
+ return (PDU[]) payload;
+ }
+
+ public Date getDate() {
+ assert getTag() == UTCTIME || getTag() == GENERALIZED_TIME;
+ return (Date) payload;
+ }
+
+}
diff --git a/bundleplugin/src/main/java/aQute/libg/asn1/Types.java b/bundleplugin/src/main/java/aQute/libg/asn1/Types.java
new file mode 100644
index 0000000..630ed1c
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/asn1/Types.java
@@ -0,0 +1,65 @@
+package aQute.libg.asn1;
+
+public interface Types {
+ int UNIVERSAL = 0x00000000;
+ int APPLICATION = 0x40000000;
+ int CONTEXT = 0x80000000;
+ int PRIVATE = 0xC0000000;
+ int CLASSMASK = 0xC0000000;
+ int CONSTRUCTED = 0x20000000;
+ int TAGMASK = 0x1FFFFFFF;
+
+ String [] CLASSES = {"U", "A", "C", "P"};
+
+ // Payload Primitve
+ int EOC = 0; // null
+ // x
+ int BOOLEAN = 1; // Boolean
+ // x
+ int INTEGER = 2; // Long
+ // x
+ int BIT_STRING = 3; // byte
+ // [] -
+ int OCTET_STRING = 4; // byte
+ // [] -
+ int NULL = 5; // null
+ // x
+ int OBJECT_IDENTIFIER = 6; // int[]
+ // x
+ int OBJECT_DESCRIPTOR = 7; //
+ int EXTERNAL = 8; //
+ int REAL = 9; // double
+ // x
+ int ENUMERATED = 10; //
+ int EMBEDDED_PDV = 11; //
+ int UTF8_STRING = 12; // String
+ int RELATIVE_OID = 13; //
+ int SEQUENCE = 16; //
+ int SET = 17;
+ int NUMERIC_STRING = 18; // String
+ int PRINTABLE_STRING = 19; // String
+ int T61_STRING = 20; // String
+ int VIDEOTEX_STRING = 21; // String
+ int IA5STRING = 22; // String
+ int UTCTIME = 23; // Date
+ int GENERALIZED_TIME = 24; // Date
+ int GRAPHIC_STRING = 25; // String
+ int VISIBLE_STRING = 26; // String
+ int GENERAL_STRING = 27; // String
+ int UNIVERSAL_STRING = 28; // String
+ int CHARACTER_STRING = 29; // String
+ int BMP_STRING = 30; // byte[]
+
+ String[] TAGS = { "EOC ",
+ "BOOLEAN ", "INTEGER ", "BIT_STRING ",
+ "OCTET_STRING ", "NULL ", "OBJECT_IDENTIFIER ",
+ "OBJECT_DESCRIPTOR ", "EXTERNAL ", "REAL ",
+ "ENUMERATED ", "EMBEDDED_PDV ", "UTF8_STRING ",
+ "RELATIVE_OID ", "?(14) ", "?(15) ",
+ "SEQUENCE ", "SET ", "NUMERIC_STRING ",
+ "PRINTABLE_STRING ", "T61_STRING ", "VIDEOTEX_STRING ",
+ "IA5STRING ", "UTCTIME ", "GENERALIZED_TIME ",
+ "GRAPHIC_STRING ", "VISIBLE_STRING ", "GENERAL_STRING ",
+ "UNIVERSAL_STRING ", "CHARACTER_STRING ", "BMP_STRING ", };
+
+}
diff --git a/bundleplugin/src/main/java/aQute/libg/asn1/algorithms b/bundleplugin/src/main/java/aQute/libg/asn1/algorithms
new file mode 100644
index 0000000..4fb6ab4
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/asn1/algorithms
@@ -0,0 +1,22 @@
+---------------------------------------------------------------------------
+SignatureAlgorithm digestAlgo (I) signatureAlgo (RFC 2630)
+ (II) digestEncrAlgo(PKCS#7)
+---------------------------------------------------------------------------
+(A) sha1WithRSA 1.3.14.3.2.26 (Ia) 1.2.840.113549.1.1.5
+ (1.2.840.113549.1.1.5) (Ib) 1.2.840.113549.1.1.1
+ (II) 1.2.840.113549.1.1.1
+
+
+(B) md5WithRSA 1.2.840.1x9.2.5 (Ia) 1.2.840.113549.1.1.4
+ (1.2.840.113549.1.1.4) (Ib) 1.2.840.113549.1.1.1
+ (II) 1.2.840.113549.1.1.1
+
+
+(C) ripeMD160WithRsa 1.3.36.3.2.1 (Ia) 1.3.36.3.3.1.2
+ (1.3.36.3.3.1.2) (Ib) 1.2.840.113549.1.1.1
+ (II) 1.2.840.113549.1.1.1
+
+
+(D) sha1WithDsa 1.3.14.3.2.26 (Ia) 1.2.840.10040.4.3
+ (1.2.840.10040.4.3) (Ib) 1.2.840.10040.4.1 (?)
+ (II) 1.2.840.10040.4.1
diff --git a/bundleplugin/src/main/java/aQute/libg/asn1/packageinfo b/bundleplugin/src/main/java/aQute/libg/asn1/packageinfo
new file mode 100644
index 0000000..7c8de03
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/asn1/packageinfo
@@ -0,0 +1 @@
+version 1.0