OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [gnu/] [java/] [security/] [der/] [DERReader.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* DERReader.java -- parses ASN.1 DER sequences
2
   Copyright (C) 2003 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package gnu.java.security.der;
40
 
41
import gnu.java.security.OID;
42
 
43
import java.io.BufferedInputStream;
44
import java.io.ByteArrayInputStream;
45
import java.io.ByteArrayOutputStream;
46
import java.io.EOFException;
47
import java.io.IOException;
48
import java.io.InputStream;
49
import java.math.BigInteger;
50
import java.util.Calendar;
51
import java.util.Date;
52
import java.util.TimeZone;
53
 
54
/**
55
 * This class decodes DER sequences into Java objects. The methods of
56
 * this class do not have knowledge of higher-levels of structure in the
57
 * DER stream -- such as ASN.1 constructions -- and it is therefore up
58
 * to the calling application to determine if the data are structured
59
 * properly by inspecting the {@link DERValue} that is returned.
60
 *
61
 * @author Casey Marshall (csm@gnu.org)
62
 */
63
public class DERReader implements DER
64
{
65
 
66
  // Fields.
67
  // ------------------------------------------------------------------------
68
 
69
  protected InputStream in;
70
 
71
  protected final ByteArrayOutputStream encBuf;
72
 
73
  // Constructor.
74
  // ------------------------------------------------------------------------
75
 
76
  /**
77
   * Create a new DER reader from a byte array.
78
   *
79
   * @param in The encoded bytes.
80
   */
81
  public DERReader(byte[] in)
82
  {
83
    this(new ByteArrayInputStream(in));
84
  }
85
 
86
  public DERReader (byte[] in, int off, int len)
87
  {
88
    this (new ByteArrayInputStream (in, off, len));
89
  }
90
 
91
  /**
92
   * Create a new DER readed from an input stream.
93
   *
94
   * @param in The encoded bytes.
95
   */
96
  public DERReader(InputStream in)
97
  {
98
    if (!in.markSupported())
99
      this.in = new BufferedInputStream(in, 16384);
100
    else
101
      this.in = in;
102
    encBuf = new ByteArrayOutputStream(2048);
103
  }
104
 
105
  // Class methods.
106
  // ------------------------------------------------------------------------
107
 
108
  /**
109
   * Convenience method for reading a single primitive value from the
110
   * given byte array.
111
   *
112
   * @param encoded The encoded bytes.
113
   * @throws IOException If the bytes do not represent an encoded
114
   * object.
115
   */
116
  public static DERValue read(byte[] encoded) throws IOException
117
  {
118
    return new DERReader(encoded).read();
119
  }
120
 
121
  // Instance methods.
122
  // ------------------------------------------------------------------------
123
 
124
  public void skip (int bytes) throws IOException
125
  {
126
    in.skip (bytes);
127
  }
128
 
129
  /**
130
   * Decode a single value from the input stream, returning it in a new
131
   * {@link DERValue}. By "single value" we mean any single type in its
132
   * entirety -- including constructed types such as SEQUENCE and all
133
   * the values they contain. Usually it is sufficient to call this
134
   * method once to parse and return the top-level structure, then to
135
   * inspect the returned value for the proper contents.
136
   *
137
   * @return The parsed DER structure.
138
   * @throws IOException If an error occurs reading from the input
139
   * stream.
140
   * @throws DEREncodingException If the input does not represent a
141
   * valid DER stream.
142
   */
143
  public DERValue read() throws IOException
144
  {
145
    int tag = in.read();
146
    if (tag == -1)
147
      throw new EOFException();
148
    encBuf.write(tag);
149
    int len = readLength();
150
    DERValue value = null;
151
    if ((tag & CONSTRUCTED) == CONSTRUCTED)
152
      {
153
        in.mark(2048);
154
        byte[] encoded = new byte[len];
155
        in.read(encoded);
156
        encBuf.write(encoded);
157
        value = new DERValue(tag, len, CONSTRUCTED_VALUE, encBuf.toByteArray());
158
        in.reset();
159
        encBuf.reset();
160
        return value;
161
      }
162
    switch (tag & 0xC0)
163
      {
164
        case UNIVERSAL:
165
          value = new DERValue(tag, len, readUniversal(tag, len),
166
            encBuf.toByteArray());
167
          encBuf.reset();
168
          break;
169
        case CONTEXT:
170
          byte[] encoded = new byte[len];
171
          in.read(encoded);
172
          encBuf.write(encoded);
173
          value = new DERValue(tag, len, encoded, encBuf.toByteArray());
174
          encBuf.reset();
175
          break;
176
        case APPLICATION:
177
          // This should not be reached, since (I think) APPLICATION is
178
          // always constructed.
179
          throw new DEREncodingException("non-constructed APPLICATION data");
180
        default:
181
          throw new DEREncodingException("PRIVATE class not supported");
182
      }
183
    return value;
184
  }
185
 
186
  protected int readLength() throws IOException
187
  {
188
    int i = in.read();
189
    if (i == -1)
190
      throw new EOFException();
191
    encBuf.write(i);
192
    if ((i & ~0x7F) == 0)
193
      {
194
        return i;
195
      }
196
    else if (i < 0xFF)
197
      {
198
        byte[] octets = new byte[i & 0x7F];
199
        in.read(octets);
200
        encBuf.write(octets);
201
        return new BigInteger(1, octets).intValue();
202
      }
203
    throw new DEREncodingException();
204
  }
205
 
206
  // Own methods.
207
  // ------------------------------------------------------------------------
208
 
209
  private Object readUniversal(int tag, int len) throws IOException
210
  {
211
    byte[] value = new byte[len];
212
    in.read(value);
213
    encBuf.write(value);
214
    switch (tag & 0x1F)
215
      {
216
        case BOOLEAN:
217
          if (value.length != 1)
218
            throw new DEREncodingException();
219
          return Boolean.valueOf(value[0] != 0);
220
        case NULL:
221
          if (len != 0)
222
            throw new DEREncodingException();
223
          return null;
224
        case INTEGER:
225
        case ENUMERATED:
226
          return new BigInteger(value);
227
        case BIT_STRING:
228
          byte[] bits = new byte[len - 1];
229
          System.arraycopy(value, 1, bits, 0, bits.length);
230
          return new BitString(bits, value[0] & 0xFF);
231
        case OCTET_STRING:
232
          return value;
233
        case NUMERIC_STRING:
234
        case PRINTABLE_STRING:
235
        case T61_STRING:
236
        case VIDEOTEX_STRING:
237
        case IA5_STRING:
238
        case GRAPHIC_STRING:
239
        case ISO646_STRING:
240
        case GENERAL_STRING:
241
        case UNIVERSAL_STRING:
242
        case BMP_STRING:
243
        case UTF8_STRING:
244
          return makeString(tag, value);
245
        case UTC_TIME:
246
        case GENERALIZED_TIME:
247
          return makeTime(tag, value);
248
        case OBJECT_IDENTIFIER:
249
          return new OID(value);
250
        case RELATIVE_OID:
251
          return new OID(value, true);
252
        default:
253
          throw new DEREncodingException("unknown tag " + tag);
254
      }
255
  }
256
 
257
  private static String makeString(int tag, byte[] value)
258
    throws IOException
259
  {
260
    switch (tag & 0x1F)
261
      {
262
        case NUMERIC_STRING:
263
        case PRINTABLE_STRING:
264
        case T61_STRING:
265
        case VIDEOTEX_STRING:
266
        case IA5_STRING:
267
        case GRAPHIC_STRING:
268
        case ISO646_STRING:
269
        case GENERAL_STRING:
270
          return fromIso88591(value);
271
 
272
        case UNIVERSAL_STRING:
273
          // XXX The docs say UniversalString is encoded in four bytes
274
          // per character, but Java has no support (yet) for UTF-32.
275
          //return new String(buf, "UTF-32");
276
        case BMP_STRING:
277
          return fromUtf16Be(value);
278
 
279
        case UTF8_STRING:
280
          return fromUtf8(value);
281
 
282
        default:
283
          throw new DEREncodingException("unknown string tag");
284
      }
285
  }
286
 
287
  private static String fromIso88591(byte[] bytes)
288
  {
289
    StringBuffer str = new StringBuffer(bytes.length);
290
    for (int i = 0; i < bytes.length; i++)
291
      str.append((char) (bytes[i] & 0xFF));
292
    return str.toString();
293
  }
294
 
295
  private static String fromUtf16Be(byte[] bytes) throws IOException
296
  {
297
    if ((bytes.length & 0x01) != 0)
298
      throw new IOException("UTF-16 bytes are odd in length");
299
    StringBuffer str = new StringBuffer(bytes.length / 2);
300
    for (int i = 0; i < bytes.length; i += 2)
301
      {
302
        char c = (char) ((bytes[i] << 8) & 0xFF);
303
        c |= (char) (bytes[i+1] & 0xFF);
304
        str.append(c);
305
      }
306
    return str.toString();
307
  }
308
 
309
  private static String fromUtf8(byte[] bytes) throws IOException
310
  {
311
    StringBuffer str = new StringBuffer((int)(bytes.length / 1.5));
312
    for (int i = 0; i < bytes.length; )
313
      {
314
        char c = 0;
315
        if ((bytes[i] & 0xE0) == 0xE0)
316
          {
317
            if ((i + 2) >= bytes.length)
318
              throw new IOException("short UTF-8 input");
319
            c = (char) ((bytes[i++] & 0x0F) << 12);
320
            if ((bytes[i] & 0x80) != 0x80)
321
              throw new IOException("malformed UTF-8 input");
322
            c |= (char) ((bytes[i++] & 0x3F) << 6);
323
            if ((bytes[i] & 0x80) != 0x80)
324
              throw new IOException("malformed UTF-8 input");
325
            c |= (char) (bytes[i++] & 0x3F);
326
          }
327
        else if ((bytes[i] & 0xC0) == 0xC0)
328
          {
329
            if ((i + 1) >= bytes.length)
330
              throw new IOException("short input");
331
            c = (char) ((bytes[i++] & 0x1F) << 6);
332
            if ((bytes[i] & 0x80) != 0x80)
333
              throw new IOException("malformed UTF-8 input");
334
            c |= (char) (bytes[i++] & 0x3F);
335
          }
336
        else if ((bytes[i] & 0xFF) < 0x80)
337
          {
338
            c = (char) (bytes[i++] & 0xFF);
339
          }
340
        else
341
          throw new IOException("badly formed UTF-8 sequence");
342
        str.append(c);
343
      }
344
    return str.toString();
345
  }
346
 
347
  private Date makeTime(int tag, byte[] value) throws IOException
348
  {
349
    Calendar calendar = Calendar.getInstance();
350
    String str = makeString(PRINTABLE_STRING, value);
351
 
352
    // Classpath's SimpleDateFormat does not work for parsing these
353
    // types of times, so we do this by hand.
354
    String date = str;
355
    String tz = "";
356
    if (str.indexOf("+") > 0)
357
      {
358
        date = str.substring(0, str.indexOf("+"));
359
        tz = str.substring(str.indexOf("+"));
360
      }
361
    else if (str.indexOf("-") > 0)
362
      {
363
        date = str.substring(0, str.indexOf("-"));
364
        tz = str.substring(str.indexOf("-"));
365
      }
366
    else if (str.endsWith("Z"))
367
      {
368
        date = str.substring(0, str.length()-2);
369
        tz = "Z";
370
      }
371
    if (!tz.equals("Z") && tz.length() > 0)
372
      calendar.setTimeZone(TimeZone.getTimeZone(tz));
373
    else
374
      calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
375
    if ((tag & 0x1F) == UTC_TIME)
376
      {
377
        if (date.length() < 10)  // must be at least 10 chars long
378
          throw new DEREncodingException("cannot parse date");
379
        // UTCTime is of the form "yyMMddHHmm[ss](Z|(+|-)hhmm)"
380
        try
381
          {
382
            int year = Integer.parseInt(str.substring(0, 2));
383
            if (year < 50)
384
              year += 2000;
385
            else
386
              year += 1900;
387
            calendar.set(year,
388
              Integer.parseInt(str.substring( 2,  4))-1,  // month
389
              Integer.parseInt(str.substring( 4,  6)),    // day
390
              Integer.parseInt(str.substring( 6,  8)),    // hour
391
              Integer.parseInt(str.substring( 8, 10)));   // minute
392
            if (date.length() == 12)
393
              calendar.set(Calendar.SECOND,
394
                Integer.parseInt(str.substring(10, 12)));
395
          }
396
        catch (NumberFormatException nfe)
397
          {
398
            throw new DEREncodingException("cannot parse date");
399
          }
400
      }
401
    else
402
      {
403
        if (date.length() < 10)  // must be at least 10 chars long
404
          throw new DEREncodingException("cannot parse date");
405
        // GeneralTime is of the form "yyyyMMddHH[mm[ss[(.|,)SSSS]]]"
406
        // followed by "Z" or "(+|-)hh[mm]"
407
        try
408
          {
409
            calendar.set(
410
              Integer.parseInt(date.substring(0, 4)),      // year
411
              Integer.parseInt(date.substring(4, 6))-1,    // month
412
              Integer.parseInt(date.substring(6, 8)),      // day
413
              Integer.parseInt(date.substring(8, 10)), 0); // hour, min
414
            switch (date.length())
415
              {
416
                case 19:
417
                case 18:
418
                case 17:
419
                case 16:
420
                  calendar.set(Calendar.MILLISECOND,
421
                    Integer.parseInt(date.substring(15)));
422
                case 14:
423
                  calendar.set(Calendar.SECOND,
424
                    Integer.parseInt(date.substring(12, 14)));
425
                case 12:
426
                  calendar.set(Calendar.MINUTE,
427
                    Integer.parseInt(date.substring(10, 12)));
428
              }
429
          }
430
        catch (NumberFormatException nfe)
431
          {
432
            throw new DEREncodingException("cannot parse date");
433
          }
434
      }
435
    return calendar.getTime();
436
  }
437
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.