Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/util/DerValue.java
38830 views
/**1* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.util;2627import java.io.*;28import java.math.BigInteger;29import java.util.Date;30import sun.misc.IOUtils;3132/**33* Represents a single DER-encoded value. DER encoding rules are a subset34* of the "Basic" Encoding Rules (BER), but they only support a single way35* ("Definite" encoding) to encode any given value.36*37* <P>All DER-encoded data are triples <em>{type, length, data}</em>. This38* class represents such tagged values as they have been read (or constructed),39* and provides structured access to the encoded data.40*41* <P>At this time, this class supports only a subset of the types of DER42* data encodings which are defined. That subset is sufficient for parsing43* most X.509 certificates, and working with selected additional formats44* (such as PKCS #10 certificate requests, and some kinds of PKCS #7 data).45*46* A note with respect to T61/Teletex strings: From RFC 1617, section 4.1.347* and RFC 5280, section 8, we assume that this kind of string will contain48* ISO-8859-1 characters only.49*50*51* @author David Brownell52* @author Amit Kapoor53* @author Hemma Prafullchandra54*/55public class DerValue {56/** The tag class types */57public static final byte TAG_UNIVERSAL = (byte)0x000;58public static final byte TAG_APPLICATION = (byte)0x040;59public static final byte TAG_CONTEXT = (byte)0x080;60public static final byte TAG_PRIVATE = (byte)0x0c0;6162/** The DER tag of the value; one of the tag_ constants. */63public byte tag;6465protected DerInputBuffer buffer;6667/**68* The DER-encoded data of the value, never null69*/70public final DerInputStream data;7172private int length;7374/*75* The type starts at the first byte of the encoding, and76* is one of these tag_* values. That may be all the type77* data that is needed.78*/7980/*81* These tags are the "universal" tags ... they mean the same82* in all contexts. (Mask with 0x1f -- five bits.)83*/8485/** Tag value indicating an ASN.1 "BOOLEAN" value. */86public final static byte tag_Boolean = 0x01;8788/** Tag value indicating an ASN.1 "INTEGER" value. */89public final static byte tag_Integer = 0x02;9091/** Tag value indicating an ASN.1 "BIT STRING" value. */92public final static byte tag_BitString = 0x03;9394/** Tag value indicating an ASN.1 "OCTET STRING" value. */95public final static byte tag_OctetString = 0x04;9697/** Tag value indicating an ASN.1 "NULL" value. */98public final static byte tag_Null = 0x05;99100/** Tag value indicating an ASN.1 "OBJECT IDENTIFIER" value. */101public final static byte tag_ObjectId = 0x06;102103/** Tag value including an ASN.1 "ENUMERATED" value */104public final static byte tag_Enumerated = 0x0A;105106/** Tag value indicating an ASN.1 "UTF8String" value. */107public final static byte tag_UTF8String = 0x0C;108109/** Tag value including a "printable" string */110public final static byte tag_PrintableString = 0x13;111112/** Tag value including a "teletype" string */113public final static byte tag_T61String = 0x14;114115/** Tag value including an ASCII string */116public final static byte tag_IA5String = 0x16;117118/** Tag value indicating an ASN.1 "UTCTime" value. */119public final static byte tag_UtcTime = 0x17;120121/** Tag value indicating an ASN.1 "GeneralizedTime" value. */122public final static byte tag_GeneralizedTime = 0x18;123124/** Tag value indicating an ASN.1 "GenerallString" value. */125public final static byte tag_GeneralString = 0x1B;126127/** Tag value indicating an ASN.1 "UniversalString" value. */128public final static byte tag_UniversalString = 0x1C;129130/** Tag value indicating an ASN.1 "BMPString" value. */131public final static byte tag_BMPString = 0x1E;132133// CONSTRUCTED seq/set134135/**136* Tag value indicating an ASN.1137* "SEQUENCE" (zero to N elements, order is significant).138*/139public final static byte tag_Sequence = 0x30;140141/**142* Tag value indicating an ASN.1143* "SEQUENCE OF" (one to N elements, order is significant).144*/145public final static byte tag_SequenceOf = 0x30;146147/**148* Tag value indicating an ASN.1149* "SET" (zero to N members, order does not matter).150*/151public final static byte tag_Set = 0x31;152153/**154* Tag value indicating an ASN.1155* "SET OF" (one to N members, order does not matter).156*/157public final static byte tag_SetOf = 0x31;158159/*160* These values are the high order bits for the other kinds of tags.161*/162163/**164* Returns true if the tag class is UNIVERSAL.165*/166public boolean isUniversal() { return ((tag & 0x0c0) == 0x000); }167168/**169* Returns true if the tag class is APPLICATION.170*/171public boolean isApplication() { return ((tag & 0x0c0) == 0x040); }172173/**174* Returns true iff the CONTEXT SPECIFIC bit is set in the type tag.175* This is associated with the ASN.1 "DEFINED BY" syntax.176*/177public boolean isContextSpecific() { return ((tag & 0x0c0) == 0x080); }178179/**180* Returns true iff the CONTEXT SPECIFIC TAG matches the passed tag.181*/182public boolean isContextSpecific(byte cntxtTag) {183if (!isContextSpecific()) {184return false;185}186return ((tag & 0x01f) == cntxtTag);187}188189boolean isPrivate() { return ((tag & 0x0c0) == 0x0c0); }190191/** Returns true iff the CONSTRUCTED bit is set in the type tag. */192public boolean isConstructed() { return ((tag & 0x020) == 0x020); }193194/**195* Returns true iff the CONSTRUCTED TAG matches the passed tag.196*/197public boolean isConstructed(byte constructedTag) {198if (!isConstructed()) {199return false;200}201return ((tag & 0x01f) == constructedTag);202}203204/**205* Creates a PrintableString or UTF8string DER value from a string206*/207public DerValue(String value) throws IOException {208boolean isPrintableString = true;209for (int i = 0; i < value.length(); i++) {210if (!isPrintableStringChar(value.charAt(i))) {211isPrintableString = false;212break;213}214}215216data = init(isPrintableString ? tag_PrintableString : tag_UTF8String, value);217}218219/**220* Creates a string type DER value from a String object221* @param stringTag the tag for the DER value to create222* @param value the String object to use for the DER value223*/224public DerValue(byte stringTag, String value) throws IOException {225data = init(stringTag, value);226}227228// Creates a DerValue from a tag and some DER-encoded data w/ additional229// arg to control whether DER checks are enforced.230DerValue(byte tag, byte[] data, boolean allowBER) {231this.tag = tag;232buffer = new DerInputBuffer(data.clone(), allowBER);233length = data.length;234this.data = new DerInputStream(buffer);235this.data.mark(Integer.MAX_VALUE);236}237238/**239* Creates a DerValue from a tag and some DER-encoded data.240*241* @param tag the DER type tag242* @param data the DER-encoded data243*/244public DerValue(byte tag, byte[] data) {245this(tag, data, true);246}247248/*249* package private250*/251DerValue(DerInputBuffer in) throws IOException {252253// XXX must also parse BER-encoded constructed254// values such as sequences, sets...255tag = (byte)in.read();256byte lenByte = (byte)in.read();257length = DerInputStream.getLength(lenByte, in);258if (length == -1) { // indefinite length encoding found259DerInputBuffer inbuf = in.dup();260int readLen = inbuf.available();261int offset = 2; // for tag and length bytes262byte[] indefData = new byte[readLen + offset];263indefData[0] = tag;264indefData[1] = lenByte;265DataInputStream dis = new DataInputStream(inbuf);266dis.readFully(indefData, offset, readLen);267dis.close();268DerIndefLenConverter derIn = new DerIndefLenConverter();269inbuf = new DerInputBuffer(derIn.convert(indefData), in.allowBER);270if (tag != inbuf.read())271throw new IOException272("Indefinite length encoding not supported");273length = DerInputStream.getDefiniteLength(inbuf);274buffer = inbuf.dup();275buffer.truncate(length);276data = new DerInputStream(buffer);277// indefinite form is encoded by sending a length field with a278// length of 0. - i.e. [1000|0000].279// the object is ended by sending two zero bytes.280in.skip(length + offset);281} else {282283buffer = in.dup();284buffer.truncate(length);285data = new DerInputStream(buffer);286287in.skip(length);288}289}290291// Get an ASN.1/DER encoded datum from a buffer w/ additional292// arg to control whether DER checks are enforced.293DerValue(byte[] buf, boolean allowBER) throws IOException {294data = init(true, new ByteArrayInputStream(buf), allowBER);295}296297/**298* Get an ASN.1/DER encoded datum from a buffer. The299* entire buffer must hold exactly one datum, including300* its tag and length.301*302* @param buf buffer holding a single DER-encoded datum.303*/304public DerValue(byte[] buf) throws IOException {305this(buf, true);306}307308// Get an ASN.1/DER encoded datum from part of a buffer w/ additional309// arg to control whether DER checks are enforced.310DerValue(byte[] buf, int offset, int len, boolean allowBER)311throws IOException {312data = init(true, new ByteArrayInputStream(buf, offset, len), allowBER);313}314315/**316* Get an ASN.1/DER encoded datum from part of a buffer.317* That part of the buffer must hold exactly one datum, including318* its tag and length.319*320* @param buf the buffer321* @param offset start point of the single DER-encoded dataum322* @param length how many bytes are in the encoded datum323*/324public DerValue(byte[] buf, int offset, int len) throws IOException {325this(buf, offset, len, true);326}327328// Get an ASN1/DER encoded datum from an input stream w/ additional329// arg to control whether DER checks are enforced.330DerValue(InputStream in, boolean allowBER) throws IOException {331data = init(false, in, allowBER);332}333334/**335* Get an ASN1/DER encoded datum from an input stream. The336* stream may have additional data following the encoded datum.337* In case of indefinite length encoded datum, the input stream338* must hold only one datum.339*340* @param in the input stream holding a single DER datum,341* which may be followed by additional data342*/343public DerValue(InputStream in) throws IOException {344this(in, true);345}346347private DerInputStream init(byte stringTag, String value)348throws IOException {349String enc = null;350351tag = stringTag;352353switch (stringTag) {354case tag_PrintableString:355case tag_IA5String:356case tag_GeneralString:357enc = "ASCII";358break;359case tag_T61String:360enc = "ISO-8859-1";361break;362case tag_BMPString:363enc = "UnicodeBigUnmarked";364break;365case tag_UTF8String:366enc = "UTF8";367break;368// TBD: Need encoder for UniversalString before it can369// be handled.370default:371throw new IllegalArgumentException("Unsupported DER string type");372}373374byte[] buf = value.getBytes(enc);375length = buf.length;376buffer = new DerInputBuffer(buf, true);377DerInputStream result = new DerInputStream(buffer);378result.mark(Integer.MAX_VALUE);379return result;380}381382/*383* helper routine384*/385private DerInputStream init(boolean fullyBuffered, InputStream in,386boolean allowBER) throws IOException {387388tag = (byte)in.read();389byte lenByte = (byte)in.read();390length = DerInputStream.getLength(lenByte, in);391if (length == -1) { // indefinite length encoding found392int readLen = in.available();393int offset = 2; // for tag and length bytes394byte[] indefData = new byte[readLen + offset];395indefData[0] = tag;396indefData[1] = lenByte;397DataInputStream dis = new DataInputStream(in);398dis.readFully(indefData, offset, readLen);399dis.close();400DerIndefLenConverter derIn = new DerIndefLenConverter();401in = new ByteArrayInputStream(derIn.convert(indefData));402if (tag != in.read())403throw new IOException404("Indefinite length encoding not supported");405length = DerInputStream.getDefiniteLength(in);406}407408if (fullyBuffered && in.available() != length)409throw new IOException("extra data given to DerValue constructor");410411byte[] bytes = IOUtils.readExactlyNBytes(in, length);412413buffer = new DerInputBuffer(bytes, allowBER);414return new DerInputStream(buffer);415}416417/**418* Encode an ASN1/DER encoded datum onto a DER output stream.419*/420public void encode(DerOutputStream out)421throws IOException {422out.write(tag);423out.putLength(length);424// XXX yeech, excess copies ... DerInputBuffer.write(OutStream)425if (length > 0) {426byte[] value = new byte[length];427// always synchronized on data428synchronized (data) {429buffer.reset();430if (buffer.read(value) != length) {431throw new IOException("short DER value read (encode)");432}433out.write(value);434}435}436}437438public final DerInputStream getData() {439return data;440}441442public final byte getTag() {443return tag;444}445446/**447* Returns an ASN.1 BOOLEAN448*449* @return the boolean held in this DER value450*/451public boolean getBoolean() throws IOException {452if (tag != tag_Boolean) {453throw new IOException("DerValue.getBoolean, not a BOOLEAN " + tag);454}455if (length != 1) {456throw new IOException("DerValue.getBoolean, invalid length "457+ length);458}459if (buffer.read() != 0) {460return true;461}462return false;463}464465/**466* Returns an ASN.1 OBJECT IDENTIFIER.467*468* @return the OID held in this DER value469*/470public ObjectIdentifier getOID() throws IOException {471if (tag != tag_ObjectId)472throw new IOException("DerValue.getOID, not an OID " + tag);473return new ObjectIdentifier(buffer);474}475476private byte[] append(byte[] a, byte[] b) {477if (a == null)478return b;479480byte[] ret = new byte[a.length + b.length];481System.arraycopy(a, 0, ret, 0, a.length);482System.arraycopy(b, 0, ret, a.length, b.length);483484return ret;485}486487/**488* Returns an ASN.1 OCTET STRING489*490* @return the octet string held in this DER value491*/492public byte[] getOctetString() throws IOException {493494if (tag != tag_OctetString && !isConstructed(tag_OctetString)) {495throw new IOException(496"DerValue.getOctetString, not an Octet String: " + tag);497}498// Note: do not attempt to call buffer.read(bytes) at all. There's a499// known bug that it returns -1 instead of 0.500if (length == 0) {501return new byte[0];502}503504// Only allocate the array if there are enough bytes available.505// This only works for ByteArrayInputStream.506// The assignment below ensures that buffer has the required type.507ByteArrayInputStream arrayInput = buffer;508if (arrayInput.available() < length) {509throw new IOException("short read on DerValue buffer");510}511byte[] bytes = new byte[length];512arrayInput.read(bytes);513514if (isConstructed()) {515DerInputStream in = new DerInputStream(bytes, 0, bytes.length,516buffer.allowBER);517bytes = null;518while (in.available() != 0) {519bytes = append(bytes, in.getOctetString());520}521}522return bytes;523}524525/**526* Returns an ASN.1 INTEGER value as an integer.527*528* @return the integer held in this DER value.529*/530public int getInteger() throws IOException {531if (tag != tag_Integer) {532throw new IOException("DerValue.getInteger, not an int " + tag);533}534return buffer.getInteger(data.available());535}536537/**538* Returns an ASN.1 INTEGER value as a BigInteger.539*540* @return the integer held in this DER value as a BigInteger.541*/542public BigInteger getBigInteger() throws IOException {543if (tag != tag_Integer)544throw new IOException("DerValue.getBigInteger, not an int " + tag);545return buffer.getBigInteger(data.available(), false);546}547548/**549* Returns an ASN.1 INTEGER value as a positive BigInteger.550* This is just to deal with implementations that incorrectly encode551* some values as negative.552*553* @return the integer held in this DER value as a BigInteger.554*/555public BigInteger getPositiveBigInteger() throws IOException {556if (tag != tag_Integer)557throw new IOException("DerValue.getBigInteger, not an int " + tag);558return buffer.getBigInteger(data.available(), true);559}560561/**562* Returns an ASN.1 ENUMERATED value.563*564* @return the integer held in this DER value.565*/566public int getEnumerated() throws IOException {567if (tag != tag_Enumerated) {568throw new IOException("DerValue.getEnumerated, incorrect tag: "569+ tag);570}571return buffer.getInteger(data.available());572}573574/**575* Returns an ASN.1 BIT STRING value. The bit string must be byte-aligned.576*577* @return the bit string held in this value578*/579public byte[] getBitString() throws IOException {580if (tag != tag_BitString)581throw new IOException(582"DerValue.getBitString, not a bit string " + tag);583584return buffer.getBitString();585}586587/**588* Returns an ASN.1 BIT STRING value that need not be byte-aligned.589*590* @return a BitArray representing the bit string held in this value591*/592public BitArray getUnalignedBitString() throws IOException {593if (tag != tag_BitString)594throw new IOException(595"DerValue.getBitString, not a bit string " + tag);596597return buffer.getUnalignedBitString();598}599600/**601* Returns the name component as a Java string, regardless of its602* encoding restrictions (ASCII, T61, Printable, IA5, BMP, UTF8).603*/604// TBD: Need encoder for UniversalString before it can be handled.605public String getAsString() throws IOException {606if (tag == tag_UTF8String)607return getUTF8String();608else if (tag == tag_PrintableString)609return getPrintableString();610else if (tag == tag_T61String)611return getT61String();612else if (tag == tag_IA5String)613return getIA5String();614/*615else if (tag == tag_UniversalString)616return getUniversalString();617*/618else if (tag == tag_BMPString)619return getBMPString();620else if (tag == tag_GeneralString)621return getGeneralString();622else623return null;624}625626/**627* Returns an ASN.1 BIT STRING value, with the tag assumed implicit628* based on the parameter. The bit string must be byte-aligned.629*630* @params tagImplicit if true, the tag is assumed implicit.631* @return the bit string held in this value632*/633public byte[] getBitString(boolean tagImplicit) throws IOException {634if (!tagImplicit) {635if (tag != tag_BitString)636throw new IOException("DerValue.getBitString, not a bit string "637+ tag);638}639return buffer.getBitString();640}641642/**643* Returns an ASN.1 BIT STRING value, with the tag assumed implicit644* based on the parameter. The bit string need not be byte-aligned.645*646* @params tagImplicit if true, the tag is assumed implicit.647* @return the bit string held in this value648*/649public BitArray getUnalignedBitString(boolean tagImplicit)650throws IOException {651if (!tagImplicit) {652if (tag != tag_BitString)653throw new IOException("DerValue.getBitString, not a bit string "654+ tag);655}656return buffer.getUnalignedBitString();657}658659/**660* Helper routine to return all the bytes contained in the661* DerInputStream associated with this object.662*/663public byte[] getDataBytes() throws IOException {664byte[] retVal = new byte[length];665synchronized (data) {666data.reset();667data.getBytes(retVal);668}669return retVal;670}671672/**673* Returns an ASN.1 STRING value674*675* @return the printable string held in this value676*/677public String getPrintableString()678throws IOException {679if (tag != tag_PrintableString)680throw new IOException(681"DerValue.getPrintableString, not a string " + tag);682683return new String(getDataBytes(), "ASCII");684}685686/**687* Returns an ASN.1 T61 (Teletype) STRING value688*689* @return the teletype string held in this value690*/691public String getT61String() throws IOException {692if (tag != tag_T61String)693throw new IOException(694"DerValue.getT61String, not T61 " + tag);695696return new String(getDataBytes(), "ISO-8859-1");697}698699/**700* Returns an ASN.1 IA5 (ASCII) STRING value701*702* @return the ASCII string held in this value703*/704public String getIA5String() throws IOException {705if (tag != tag_IA5String)706throw new IOException(707"DerValue.getIA5String, not IA5 " + tag);708709return new String(getDataBytes(), "ASCII");710}711712/**713* Returns the ASN.1 BMP (Unicode) STRING value as a Java string.714*715* @return a string corresponding to the encoded BMPString held in716* this value717*/718public String getBMPString() throws IOException {719if (tag != tag_BMPString)720throw new IOException(721"DerValue.getBMPString, not BMP " + tag);722723// BMPString is the same as Unicode in big endian, unmarked724// format.725return new String(getDataBytes(), "UnicodeBigUnmarked");726}727728/**729* Returns the ASN.1 UTF-8 STRING value as a Java String.730*731* @return a string corresponding to the encoded UTF8String held in732* this value733*/734public String getUTF8String() throws IOException {735if (tag != tag_UTF8String)736throw new IOException(737"DerValue.getUTF8String, not UTF-8 " + tag);738739return new String(getDataBytes(), "UTF8");740}741742/**743* Returns the ASN.1 GENERAL STRING value as a Java String.744*745* @return a string corresponding to the encoded GeneralString held in746* this value747*/748public String getGeneralString() throws IOException {749if (tag != tag_GeneralString)750throw new IOException(751"DerValue.getGeneralString, not GeneralString " + tag);752753return new String(getDataBytes(), "ASCII");754}755756/**757* Returns a Date if the DerValue is UtcTime.758*759* @return the Date held in this DER value760*/761public Date getUTCTime() throws IOException {762if (tag != tag_UtcTime) {763throw new IOException("DerValue.getUTCTime, not a UtcTime: " + tag);764}765return buffer.getUTCTime(data.available());766}767768/**769* Returns a Date if the DerValue is GeneralizedTime.770*771* @return the Date held in this DER value772*/773public Date getGeneralizedTime() throws IOException {774if (tag != tag_GeneralizedTime) {775throw new IOException(776"DerValue.getGeneralizedTime, not a GeneralizedTime: " + tag);777}778return buffer.getGeneralizedTime(data.available());779}780781/**782* Bitwise equality comparison. DER encoded values have a single783* encoding, so that bitwise equality of the encoded values is an784* efficient way to establish equivalence of the unencoded values.785*786* @param other the object being compared with this one787*/788@Override789public boolean equals(Object o) {790if (this == o) {791return true;792}793if (!(o instanceof DerValue)) {794return false;795}796DerValue other = (DerValue) o;797if (tag != other.tag) {798return false;799}800if (data == other.data) {801return true;802}803804// make sure the order of lock is always consistent to avoid a deadlock805return (System.identityHashCode(this.data)806> System.identityHashCode(other.data)) ?807doEquals(this, other):808doEquals(other, this);809}810811/**812* Helper for public method equals()813*/814private static boolean doEquals(DerValue d1, DerValue d2) {815synchronized (d1.data) {816synchronized (d2.data) {817d1.data.reset();818d2.data.reset();819return d1.buffer.equals(d2.buffer);820}821}822}823824/**825* Returns a printable representation of the value.826*827* @return printable representation of the value828*/829@Override830public String toString() {831try {832833String str = getAsString();834if (str != null)835return "\"" + str + "\"";836if (tag == tag_Null)837return "[DerValue, null]";838if (tag == tag_ObjectId)839return "OID." + getOID();840841// integers842else843return "[DerValue, tag = " + tag844+ ", length = " + length + "]";845} catch (IOException e) {846throw new IllegalArgumentException("misformatted DER value");847}848}849850/**851* Returns a DER-encoded value, such that if it's passed to the852* DerValue constructor, a value equivalent to "this" is returned.853*854* @return DER-encoded value, including tag and length.855*/856public byte[] toByteArray() throws IOException {857DerOutputStream out = new DerOutputStream();858859encode(out);860data.reset();861return out.toByteArray();862}863864/**865* For "set" and "sequence" types, this function may be used866* to return a DER stream of the members of the set or sequence.867* This operation is not supported for primitive types such as868* integers or bit strings.869*/870public DerInputStream toDerInputStream() throws IOException {871if (tag == tag_Sequence || tag == tag_Set)872return new DerInputStream(buffer);873throw new IOException("toDerInputStream rejects tag type " + tag);874}875876/**877* Get the length of the encoded value.878*/879public int length() {880return length;881}882883/**884* Determine if a character is one of the permissible characters for885* PrintableString:886* A-Z, a-z, 0-9, space, apostrophe (39), left and right parentheses,887* plus sign, comma, hyphen, period, slash, colon, equals sign,888* and question mark.889*890* Characters that are *not* allowed in PrintableString include891* exclamation point, quotation mark, number sign, dollar sign,892* percent sign, ampersand, asterisk, semicolon, less than sign,893* greater than sign, at sign, left and right square brackets,894* backslash, circumflex (94), underscore, back quote (96),895* left and right curly brackets, vertical line, tilde,896* and the control codes (0-31 and 127).897*898* This list is based on X.680 (the ASN.1 spec).899*/900public static boolean isPrintableStringChar(char ch) {901if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||902(ch >= '0' && ch <= '9')) {903return true;904} else {905switch (ch) {906case ' ': /* space */907case '\'': /* apostrophe */908case '(': /* left paren */909case ')': /* right paren */910case '+': /* plus */911case ',': /* comma */912case '-': /* hyphen */913case '.': /* period */914case '/': /* slash */915case ':': /* colon */916case '=': /* equals */917case '?': /* question mark */918return true;919default:920return false;921}922}923}924925/**926* Create the tag of the attribute.927*928* @params class the tag class type, one of UNIVERSAL, CONTEXT,929* APPLICATION or PRIVATE930* @params form if true, the value is constructed, otherwise it931* is primitive.932* @params val the tag value933*/934public static byte createTag(byte tagClass, boolean form, byte val) {935byte tag = (byte)(tagClass | val);936if (form) {937tag |= (byte)0x20;938}939return (tag);940}941942/**943* Set the tag of the attribute. Commonly used to reset the944* tag value used for IMPLICIT encodings.945*946* @params tag the tag value947*/948public void resetTag(byte tag) {949this.tag = tag;950}951952/**953* Returns a hashcode for this DerValue.954*955* @return a hashcode for this DerValue.956*/957@Override958public int hashCode() {959return toString().hashCode();960}961}962963964