001: /*
002: * Title: Oyster Project
003: * Description: S/MIME email sending capabilities
004: * @Author Vladimir Radisic
005: * @Version 2.1.6
006: */
007:
008: package org.enhydra.oyster.der;
009:
010: import org.enhydra.oyster.exception.SMIMEException;
011: import org.enhydra.oyster.exception.ErrorStorage;
012:
013: /**
014: * Every element of data represented in ASN.1 notation should be encoded
015: * in the process of implementation. It can be done according to BER (Basic
016: * Encoding Rules) or according to DER (Distinguish Encoding Rules). DERObject
017: * class is the root class (super class) of all classes used in DER encodings
018: * of variety elements in data structures used by SMIME.<BR>
019: * <BR>
020: * DER encoding of elements can be performed in two forms: definite form and
021: * indefinite form. DERObject class represents definite form of encoding. Every
022: * encoded element, according to this rules, involves three parts: Identifier
023: * Octet (which represents Tag Type of the encoding data), Length Octets (one
024: * or more octets with the information about number of octets (bytes) in the
025: * content), and Content Octets (they represent data which have to be DER
026: * encoded). <BR>
027: * <BR>
028: * DERObject can be structured or primitive, which depends on his content.
029: */
030: public class DERObject {
031:
032: /**
033: * Identifier octet of DER encoding element. It must be in the range 0-255.
034: */
035: private int identifierOctet;
036:
037: /**
038: * Length Octets of DER encoding element.
039: */
040: private String lengthOctets = "";
041:
042: /**
043: * Content Octets of DER encoding element.
044: */
045: private String contentOctets = "";
046:
047: /**
048: * Type of element number (part of Identifier Octet). It must be in the
049: * range 0-30.
050: */
051: private int tagTypeNumber = 0;
052:
053: /**
054: * Class Type of element (part of Identifier Octet). It can have values:
055: * 0-Universal, 64-Application, 128-Context, 192-Private (Default 0)
056: */
057: private int tagClassType = 0;
058:
059: /**
060: * Complexity type of element. It can have values: 0-Primitive, 32-Structured
061: * (Default 0)
062: */
063: private int tagComplexity = 0;
064:
065: /**
066: * Total lenght (number of octets) of DER object (Default 0)
067: */
068: private int totalLength = 0;
069:
070: /**
071: * Creates DER Object with defined value for identifier octet.
072: * @param identifierOctet0 must be in the range 0-255 (whithouth 31)
073: * @exception SMIMEException in case of invalid identifierOctet0 parameter
074: */
075: public DERObject(int identifierOctet0) throws SMIMEException {
076: if (identifierOctet0 < 0)
077: throw new SMIMEException(1000);
078: else if (identifierOctet0 > 255)
079: throw new SMIMEException(1001);
080: else if ((identifierOctet0 & 31) == 31)
081: throw new SMIMEException(1002);
082: identifierOctet = identifierOctet0;
083: tagClassType = identifierOctet0 & 192;
084: tagComplexity = identifierOctet0 & 32;
085: tagTypeNumber = identifierOctet0 & 31;
086: totalLength = 1; // Current length of DER object (contain only Identifier octet)
087: }
088:
089: /**
090: * Creates DER Object with defined value for identifier octet and values of
091: * content octets
092: * @param identifierOctet0 must be in the range 0-255 (whithouth 31)
093: * @param content0 content of DER Object
094: * @exception SMIMEException in case of invalid identifierOctet0 parameter,
095: * or in case of adding content to DER object of type Null DER object
096: */
097: public DERObject(int identifierOctet0, byte[] content0)
098: throws SMIMEException {
099: this (identifierOctet0);
100: this .addContent(content0);
101: }
102:
103: /**
104: * Defines the Lenght Octets which is the part of DEROctet
105: * @param len0 number of octets in the content
106: * @return String representation of Length Octets that correspond to len0 number
107: * @exception SMIMEException caused by non SMIMEException which is:
108: * UnsupportedEncodingException.
109: */
110: private String lengthDERPart(int len0) throws SMIMEException {
111: String returnString = null;
112: if (len0 < 128) {
113: byte[] lenByte = new byte[1];
114: lenByte[0] = (byte) len0;
115: try {
116: returnString = new String(lenByte, "ISO-8859-1");
117: } catch (Exception e) {
118: throw new SMIMEException(e);
119: }
120: return returnString;
121: } else {
122: int i = 1, a = 1; // i: Number of required bits in length0 number
123: for (; (a * 2) <= len0; i++)
124: a = a * 2;
125: i = (int) Math.ceil((double) i / 8); // Number of required bytes for holding length data
126: byte[] lenByte = new byte[i + 1]; // + 1 for first byte in length string
127: lenByte[0] = (byte) (i); // First byte define number of following bytes used for holding length data
128: lenByte[0] = (byte) ((int) lenByte[0] | 128); // Indicate complex length octets with bit #8 set to 1
129: for (; i > 0; i--) {
130: a = 255 << ((lenByte.length - i - 1) * 8);
131: lenByte[i] = (byte) ((len0 & a) >> ((lenByte.length - i - 1) * 8));
132: }
133: try {
134: returnString = new String(lenByte, "ISO-8859-1");
135: } catch (Exception e) {
136: throw new SMIMEException(e);
137: }
138: return returnString;
139: }
140: }
141:
142: /**
143: * Adds content to DER Object. Used only when the content isn't added earlier
144: * via second type of constructor in DERObject.
145: * @param content0 content octets for adding to DERObject
146: * @exception SMIMEException when adding content to DER object is of type
147: * Null DER object. Also, it can be caused by non SMIMEException which is:
148: * UnsupportedEncodingException.
149: */
150: void addContent(byte[] content0) throws SMIMEException {
151: if (identifierOctet == 5)
152: throw new SMIMEException(1003);
153: try {
154: contentOctets = contentOctets.concat(new String(content0,
155: "ISO-8859-1"));
156: lengthOctets = lengthDERPart(contentOctets.length());
157: totalLength = 1 + contentOctets.length()
158: + lengthOctets.length();
159: } catch (Exception e) {
160: throw new SMIMEException(e);
161: }
162: }
163:
164: /**
165: * Returns DER encoded object
166: * @return DERObject as byte array
167: * @exception SMIMEException if content of DER object is absent. Also, it can be
168: * caused by non SMIMEException which is: UnsupportedEncodingException.
169: */
170: public byte[] getDEREncoded() throws SMIMEException {
171: if (totalLength == 1 && identifierOctet != 5)
172: throw new SMIMEException(1004);
173: byte[] returnByteArray = null; // Variable for returning DER encoding object represented as byte array
174: try {
175: byte[] temp = { (byte) identifierOctet }; // Import identifier octet in DER object string (first byte of string)
176: String derOctet = new String(temp, "ISO-8859-1"); // String with returning DER value
177: if (identifierOctet == 5) // Special DER format is for Null DER object
178: {
179: temp[0] = (byte) 0x00;
180: contentOctets = contentOctets.concat(new String(temp,
181: "ISO-8859-1"));
182: derOctet = derOctet.concat(contentOctets);
183: totalLength = 2;
184: returnByteArray = derOctet.getBytes("ISO-8859-1"); // Null DER value
185: } else {
186: derOctet = derOctet.concat(lengthOctets).concat(
187: contentOctets);
188: totalLength = 1 + contentOctets.length()
189: + lengthOctets.length();
190: returnByteArray = derOctet.getBytes("ISO-8859-1");
191: }
192: } catch (Exception e) {
193: throw new SMIMEException(e);
194: }
195: return returnByteArray;
196: }
197:
198: /**
199: * Returns Identifier Octet
200: * @return Identifier Octet in the range 0-255
201: */
202: public int getIdentifierOctet() {
203: return identifierOctet;
204: }
205:
206: /**
207: * Returns Tag Type
208: * @return Tag Type in the range 0-30
209: */
210: public int getTagTypeNumber() {
211: return tagTypeNumber;
212: }
213:
214: /**
215: * Returns Class Type
216: * @return 0-Universal, 64-Application, 128-Context, 192-Private (Default 0)
217: */
218: public int getTagClassType() {
219: return tagClassType;
220: }
221:
222: /**
223: * Returns Tag Complexity
224: * @return 0-primitive, 32-structured (Default 0)
225: */
226: public int getTagComplexity() {
227: return tagComplexity;
228: }
229:
230: /**
231: * Returns size of content part in DER object (Number of content octets).
232: * @return Number of content octets in DER encoded object
233: */
234: public int getContentPartSize() {
235: return contentOctets.length();
236: }
237:
238: /**
239: * Returns size of length part in DER object (Number of length octets).
240: * @return Number of length octets in DER encoded object
241: */
242: public int getLengthPartSize() {
243: return lengthOctets.length();
244: }
245:
246: /**
247: * Return content octets part from DER object.
248: * @return Number of content octets in DER encoded object
249: * @exception SMIMEException caused by non SMIMEException which is:
250: * UnsupportedEncodingException .
251: */
252: public byte[] getContentOctets() throws SMIMEException {
253: byte[] returnByteArray = null;
254: try {
255: returnByteArray = contentOctets.getBytes("ISO-8859-1");
256: } catch (Exception e) {
257: throw new SMIMEException(e);
258: }
259: return returnByteArray;
260: }
261:
262: /**
263: * Return length octets part from DER object.
264: * @return Number of length octets in DER encoded object
265: * @exception SMIMEException caused by non SMIMEException which is:
266: * UnsupportedEncodingException.
267: */
268: public byte[] getLengthOctets() throws SMIMEException {
269: byte[] returnByteArray = null;
270: try {
271: returnByteArray = lengthOctets.getBytes("ISO-8859-1");
272: } catch (Exception e) {
273: throw new SMIMEException(e);
274: }
275: return returnByteArray;
276: }
277:
278: /**
279: * Returns total length of DER object
280: * @return Total length of DER Object (involves identifier octet, length
281: * octets and content octets)
282: */
283: public int getTotalSize() {
284: if (tagTypeNumber == 5)
285: return totalLength + 1;
286: return totalLength;
287: }
288: }
|