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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [java/] [security/] [der/] [DERReader.java] - Blame information for rev 769

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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