/** *ReadbytesfromthestreamandannotatethestreamasASN.1. * *@paraminaDataInputStream *@paramoutanAppendablefortheoutput *@paramavailablethenumberofbytestoreadfromthestream(ifgreaterthanzero) *@paramprefixastringtoprefixeachlineofoutput,usedforindentation *@throwsIOExceptionifanI/Oerroroccurs
*/
@SuppressWarnings("fallthrough") privateint annotate(DataInputStream in, Appendable out, int available, String prefix) throws IOException { int origAvailable = available; while (available != 0 || origAvailable < 0) { // Read the tag int tag = in.readByte() & 0xff;
available--; if (tagType(tag) == 0x1f) { // Multi-byte tag
tag = 0; int tagbits; do {
tagbits = in.readByte();
available--;
tag = (tag << 7) | (tagbits & 0x7f);
} while ((tagbits & 0x80) == 0x80);
} // Decode the length int len = in.readByte() & 0xff;
available--; if (len > 0x80) { // multi-byte encoded length int nbytes = len & 0x7f; if (nbytes > 4) {
out.append("***** Tag: ")
.append(tagName(tag))
.append(", Range of length error: ")
.append(Integer.toString(len))
.append(" bytes");
out.append(System.lineSeparator()); return available; // return the unread length
}
len = 0; for (; nbytes > 0; nbytes--) { int inc = in.readByte() & 0xff;
len = (len << 8) | inc;
available -= 1;
}
} elseif (len == 0x80) { // Tag with Indefinite-length; flag the length as unknown
len = -1;
} elseif (available < 0 && origAvailable < 0) { // started out unknown; set available to the length of this tagged value
available = len;
}
out.append(prefix); // start with indent switch (tag) { case TAG_EndOfContent: // End-of-contents octets; len == 0
out.append("END-OF-CONTENT");
out.append(System.lineSeparator()); // end of indefinite-length constructed, return zero remaining return0; case TAG_Integer: case TAG_Enumerated: switch (len) { case1:
out.append(String.format("BYTE %d. ", in.readByte()));
available -= 1; break; case2:
out.append(String.format("SHORT %d. ", in.readShort()));
available -= 2; break; case4:
out.append(String.format("INTEGER %d. ", in.readInt()));
available -= 4; break; case8:
out.append(String.format("LONG %d. ", in.readLong()));
available -= 8; break; default: byte[] bytes = newbyte[len]; int l = in.read(bytes);
BigInteger big = new BigInteger(bytes);
out.append("BIG INTEGER [" + len + "] ");
out.append(big.toString());
out.append(".");
available -= len; break;
} break; case TAG_ObjectId: byte[] oid = newbyte[len]; int l1 = in.read(oid);
available -= l1;
String s = oidName(oid);
out.append(tagName(tag) + " [" + len + "] ");
out.append(s);
out.append(' '); break;
case TAG_OctetString: case TAG_UtcTime: case TAG_GeneralizedTime:
out.append(tagName(tag) + " [" + len + "] "); // fall through case TAG_PrintableString: case TAG_IA5String: case TAG_GeneralString: { // Check if the contents are too long or not printable byte[] buf = newbyte[Math.min(32, len)]; int l = in.read(buf, 0, buf.length); if (countPrintable(buf, l) > l / 2) { // If more than 1/2 are printable, show the string
out.append("'"); for (int i = 0; i < l; i++) { char c = toASNPrintable((char) buf[i]);
out.append((c > 0) ? c : '.');
}
out.append("'"); if (l < len) {
out.append("..."); // identify the truncation
}
out.append(' ');
} else {
out.append("<Unprintable> ");
} // Skip the rest while (l < len) {
l += (int)in.skip(len - l);
}
available -= len; break;
} case TAG_Null:
out.append("NULL "); break; case TAG_Boolean: int b = in.readByte();
available--;
out.append((b == 0) ? "FALSE " : "TRUE "); break; case TAG_UTF8String:
out.append(getString(in, len, StandardCharsets.UTF_8));
out.append(' ');
available -= len; break; case TAG_T61String:
out.append(getString(in, len, StandardCharsets.ISO_8859_1));
out.append(' ');
available -= len; break; case TAG_UniversalString: case TAG_BMPString:
out.append(getString(in, len, StandardCharsets.UTF_16BE));
out.append(' ');
available -= len; break; case TAG_BitString:
out.append(String.format("%s [%d]", tagName(tag), len)); do { var skipped = in.skip(len);
len -= skipped;
available -= skipped;
} while (len > 0); break; default: { if (tag == TAG_Sequence ||
tag == TAG_Set ||
isApplication(tag) ||
isConstructed(tag)) {
String lenStr = (len < 0) ? "INDEFINITE" : Integer.toString(len); // Handle nesting if (isApplication(tag)) {
out.append(String.format("APPLICATION %d. [%s] {%n", tagType(tag), lenStr));
} else {
out.append(String.format("%s [%s]%n", tagName(tag), lenStr));
} int remaining = annotate(in, out, len, prefix + " "); if (len > 0) {
available -= len - remaining;
} continue;
} else { // Any other tag not already handled, dump the bytes
out.append(String.format("%s[%d]: ", tagName(tag), len));
formatBytes(in, out, len);
available -= len; break;
}
}
}
out.append(System.lineSeparator());
} return available;
}
/** *Readsbytesfromthestreamandannotatesthemashexadecimal. *@paraminaninputStream *@paramouttheAppendablefortheformattedbytes *@paramlenthenumberofbytestoread *@throwsIOExceptionifanI/Oerroroccurs
*/ privatevoid formatBytes(DataInputStream in, Appendable out, int len) throws IOException { int b = in.readByte() & 0xff;
out.append(String.format("%02x", b)); for (int i = 1; i < len; i++) {
b = in.readByte() & 0xff;
out.append(String.format(",%02x", b));
}
}
/** *ReturnsastringreadfromthestreamconvertedtotheCharset. *@paraminaninputStream *@paramlenthenumberofbytestoread *@paramcharsettheCharset *@returnastringreadfromthestreamconvertedtotheCharset. *@throwsIOExceptionifanI/Oerroroccurs
*/ private String getString(DataInputStream in, int len, Charset charset) throws IOException { byte[] bytes = newbyte[len]; int l = in.read(bytes); returnnew String(bytes, charset);
}
/** *Returnsthetagnamebasedonthetagvalue. *@paramtagthetagvalue *@returnaStringrepresentationofthetag.
*/ private String tagName(int tag) {
String tagString = (isConstructed(tag) ? "CONSTRUCTED " : "") + tagNames[tagType(tag)]; switch (tag & 0xc0) { case TAG_APPLICATION: return"APPLICATION " + tagString; case TAG_PRIVATE: return"PRIVATE " + tagString; case TAG_CONTEXT: return tagString; case TAG_UNIVERSAL: if (tag > 0 && tag < tagNames.length) return tagNames[tag]; if (tag == TAG_Set) return"SET"; if (tag == TAG_Sequence) return"SEQUENCE"; return"UNIVERSAL " + tagString; default: return"TAG__" + (tag & 0xc0);
}
}
/** *ReturnsthestringrepresentationoftheOIDextractedfromthebytes. *ThenumericOIDislookedupintheinternalsun.security.util.KnownOIDsclass. *Ifanameisfounditisaddedtothereturnedstring. *@parambytesbytesholdingtheOID *@returnastringrepresentingOIDorthenumericOID
*/ privatestatic String oidName(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 4); int first = bytes[0] / 40; int second = bytes[0] % 40;
sb.append(first).append('.').append(second); int valn = 0; for (int i = 1; i < bytes.length; i++) {
valn = valn * 128 + (bytes[i] & 0x7f); if ((bytes[i] & 0x80) == 0) {
sb.append('.');
sb.append(valn);
valn = 0;
}
}
String noid = sb.toString(); try { // Look up the OID; if the class is not accessible just return the numeric form Class<?> cl = Class.forName("sun.security.util.KnownOIDs");
Method findMatch = cl.getDeclaredMethod("findMatch", String.class);
Object oid = findMatch.invoke(null, noid); return (oid == null) ? noid : noid + " (" + oid.toString() + ")";
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { return noid;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.