mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			356 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			356 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Java
		
	
	
	
/* DERWriter.java -- write Java types in DER format.
 | 
						|
   Copyright (C) 2003, 2004, 2005, 2010  Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package gnu.java.security.der;
 | 
						|
 | 
						|
import gnu.java.security.OID;
 | 
						|
 | 
						|
import java.io.ByteArrayOutputStream;
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.OutputStream;
 | 
						|
 | 
						|
import java.math.BigInteger;
 | 
						|
 | 
						|
import java.text.SimpleDateFormat;
 | 
						|
 | 
						|
import java.util.Date;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.List;
 | 
						|
import java.util.Set;
 | 
						|
import java.util.TimeZone;
 | 
						|
 | 
						|
/**
 | 
						|
 * Methods that allow various Java types to be written as a DER
 | 
						|
 * (Distinguished Encoding Rules) stream to the specified output stream.
 | 
						|
 * DER is used to encode ASN.1 constructions, but this class provides no
 | 
						|
 * methods for interacting with ASN.1. Rather, callers should construct
 | 
						|
 * their output objects properly for whatever ASN.1 construct is being
 | 
						|
 * output.
 | 
						|
 *
 | 
						|
 * <p>This class only defines static methods; there are no instance
 | 
						|
 * variables needed.
 | 
						|
 *
 | 
						|
 * @author Casey Marshall (csm@gnu.org)
 | 
						|
 */
 | 
						|
public class DERWriter implements DER
 | 
						|
{
 | 
						|
 | 
						|
  // Constructors.
 | 
						|
  // ------------------------------------------------------------------------
 | 
						|
 | 
						|
  /** This class only has static methods. */
 | 
						|
  private DERWriter()
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  // Class methods.
 | 
						|
  // ------------------------------------------------------------------------
 | 
						|
 | 
						|
  public static int write(OutputStream out, DERValue object)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    if (DER.CONSTRUCTED_VALUE.equals (object.getValue ()))
 | 
						|
      {
 | 
						|
        out.write (object.getEncoded ());
 | 
						|
        return object.getLength ();
 | 
						|
      }
 | 
						|
 | 
						|
    out.write(object.getExternalTag());
 | 
						|
    Object value = object.getValue();
 | 
						|
    if (value == null)
 | 
						|
      {
 | 
						|
        writeLength(out, 0);
 | 
						|
        return 0;
 | 
						|
      }
 | 
						|
    if (value instanceof Boolean)
 | 
						|
      return writeBoolean(out, (Boolean) value);
 | 
						|
    else if (value instanceof BigInteger)
 | 
						|
      return writeInteger(out, (BigInteger) value);
 | 
						|
    else if (value instanceof Date)
 | 
						|
      return writeDate(out, object.getExternalTag(), (Date) value);
 | 
						|
    else if (value instanceof String)
 | 
						|
      return writeString(out, object.getExternalTag(), (String) value);
 | 
						|
    else if (value instanceof List)
 | 
						|
      return writeSequence(out, (List) value);
 | 
						|
    else if (value instanceof Set)
 | 
						|
      return writeSet(out, (Set) value);
 | 
						|
    else if (value instanceof BitString)
 | 
						|
      return writeBitString(out, (BitString) value);
 | 
						|
    else if (value instanceof OID)
 | 
						|
      return writeOID(out, (OID) value);
 | 
						|
    else if (value instanceof byte[])
 | 
						|
      {
 | 
						|
        writeLength(out, ((byte[]) value).length);
 | 
						|
        out.write((byte[]) value);
 | 
						|
        return ((byte[]) value).length;
 | 
						|
      }
 | 
						|
    else if (value instanceof DERValue)
 | 
						|
      {
 | 
						|
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
 | 
						|
        write(bout, (DERValue) value);
 | 
						|
        byte[] buf = bout.toByteArray();
 | 
						|
        writeLength(out, buf.length);
 | 
						|
        out.write(buf);
 | 
						|
        return buf.length;
 | 
						|
      }
 | 
						|
    else
 | 
						|
      throw new DEREncodingException("cannot encode " + value.getClass().getName());
 | 
						|
  }
 | 
						|
 | 
						|
  public static int definiteEncodingSize(int length)
 | 
						|
  {
 | 
						|
    if (length < 128)
 | 
						|
      return 1;
 | 
						|
    else if (length < 256)
 | 
						|
      return 2;
 | 
						|
    else if (length < 65536)
 | 
						|
      return 3;
 | 
						|
    else if (length < 16777216)
 | 
						|
      return 4;
 | 
						|
    else
 | 
						|
      return 5;
 | 
						|
  }
 | 
						|
 | 
						|
  // Own methods.
 | 
						|
  // ------------------------------------------------------------------------
 | 
						|
 | 
						|
  /**
 | 
						|
   * Write a BOOLEAN type to the given output stream.
 | 
						|
   *
 | 
						|
   * @param out The sink output stream.
 | 
						|
   * @param b   The boolean value to write.
 | 
						|
   */
 | 
						|
  private static int writeBoolean(OutputStream out, Boolean b)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    writeLength(out, 1);
 | 
						|
    if (b.booleanValue())
 | 
						|
      out.write(0xFF);
 | 
						|
    else
 | 
						|
      out.write(0);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Write an INTEGER type to the given output stream.
 | 
						|
   *
 | 
						|
   * @param out The sink output stream.
 | 
						|
   * @param integer The integer to write.
 | 
						|
   */
 | 
						|
  private static int writeInteger(OutputStream out, BigInteger integer)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    byte[] bytes = integer.toByteArray();
 | 
						|
    writeLength(out, bytes.length);
 | 
						|
    out.write(bytes);
 | 
						|
    return bytes.length;
 | 
						|
  }
 | 
						|
 | 
						|
  private static int writeSequence(OutputStream out, List sequence)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    ByteArrayOutputStream bout = new ByteArrayOutputStream();
 | 
						|
    for (Iterator i = sequence.iterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        write(bout, (DERValue) i.next());
 | 
						|
      }
 | 
						|
    byte[] buf = bout.toByteArray();
 | 
						|
    writeLength(out, buf.length);
 | 
						|
    out.write(buf);
 | 
						|
    return buf.length;
 | 
						|
  }
 | 
						|
 | 
						|
  private static int writeSet(OutputStream out, Set set)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    ByteArrayOutputStream bout = new ByteArrayOutputStream();
 | 
						|
    for (Iterator i = set.iterator(); i.hasNext(); )
 | 
						|
      {
 | 
						|
        write(bout, (DERValue) i.next());
 | 
						|
      }
 | 
						|
    byte[] buf = bout.toByteArray();
 | 
						|
    writeLength(out, buf.length);
 | 
						|
    out.write(buf);
 | 
						|
    return buf.length;
 | 
						|
  }
 | 
						|
 | 
						|
  private static int writeOID(OutputStream out, OID oid)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    byte[] der = oid.getDER();
 | 
						|
    writeLength(out, der.length);
 | 
						|
    out.write(der);
 | 
						|
    return der.length;
 | 
						|
  }
 | 
						|
 | 
						|
  private static int writeBitString(OutputStream out, BitString bs)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    byte[] buf = bs.getShiftedByteArray();
 | 
						|
    writeLength(out, buf.length + 1);
 | 
						|
    out.write(bs.getIgnoredBits());
 | 
						|
    out.write(buf);
 | 
						|
    return buf.length + 1;
 | 
						|
  }
 | 
						|
 | 
						|
  private static int writeString(OutputStream out, int tag, String str)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    byte[] b = null;
 | 
						|
    switch (tag & 0x1F)
 | 
						|
      {
 | 
						|
        case NUMERIC_STRING:
 | 
						|
        case PRINTABLE_STRING:
 | 
						|
        case T61_STRING:
 | 
						|
        case VIDEOTEX_STRING:
 | 
						|
        case IA5_STRING:
 | 
						|
        case GRAPHIC_STRING:
 | 
						|
        case ISO646_STRING:
 | 
						|
        case GENERAL_STRING:
 | 
						|
          b = toIso88591(str);
 | 
						|
          break;
 | 
						|
 | 
						|
        case UNIVERSAL_STRING:
 | 
						|
        case BMP_STRING:
 | 
						|
          b = toUtf16Be(str);
 | 
						|
          break;
 | 
						|
 | 
						|
        case UTF8_STRING:
 | 
						|
        default:
 | 
						|
          b = toUtf8(str);
 | 
						|
          break;
 | 
						|
      }
 | 
						|
    writeLength(out, b.length);
 | 
						|
    out.write(b);
 | 
						|
    return b.length;
 | 
						|
  }
 | 
						|
 | 
						|
  private static byte[] toIso88591(String string)
 | 
						|
  {
 | 
						|
    byte[] result = new byte[string.length()];
 | 
						|
    for (int i = 0; i < string.length(); i++)
 | 
						|
      result[i] = (byte) string.charAt(i);
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  private static byte[] toUtf16Be(String string)
 | 
						|
  {
 | 
						|
    byte[] result = new byte[string.length() * 2];
 | 
						|
    for (int i = 0; i < string.length(); i++)
 | 
						|
      {
 | 
						|
        result[i*2  ] = (byte) ((string.charAt(i) >>> 8) & 0xFF);
 | 
						|
        result[i*2+1] = (byte)  (string.charAt(i) & 0xFF);
 | 
						|
      }
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  private static byte[] toUtf8(String string)
 | 
						|
  {
 | 
						|
    int len = string.length();
 | 
						|
    ByteArrayOutputStream buf = new ByteArrayOutputStream(len + (len >> 1));
 | 
						|
    for (int i = 0; i < len; i++)
 | 
						|
      {
 | 
						|
        char c = string.charAt(i);
 | 
						|
        if (c < 0x0080)
 | 
						|
          buf.write(c & 0xFF);
 | 
						|
        else if (c < 0x0800)
 | 
						|
          {
 | 
						|
            buf.write(0xC0 | ((c >>> 6) & 0x3F));
 | 
						|
            buf.write(0x80 |  (c & 0x3F));
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            buf.write(0xE0 | ((c >>> 12) & 0x0F));
 | 
						|
            buf.write(0x80 | ((c >>>  6) & 0x3F));
 | 
						|
            buf.write(0x80 |  (c & 0x3F));
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return buf.toByteArray();
 | 
						|
  }
 | 
						|
 | 
						|
  private static int writeDate(OutputStream out, int tag, Date date)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    SimpleDateFormat sdf = null;
 | 
						|
    if ((tag & 0x1F) == UTC_TIME)
 | 
						|
      sdf = new SimpleDateFormat("yyMMddHHmmss'Z'");
 | 
						|
    else
 | 
						|
      sdf = new SimpleDateFormat("yyyyMMddHHmmss'.'SSS'Z'");
 | 
						|
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
 | 
						|
    byte[] b = sdf.format(date).getBytes("ISO-8859-1");
 | 
						|
    writeLength(out, b.length);
 | 
						|
    out.write(b);
 | 
						|
    return b.length;
 | 
						|
  }
 | 
						|
 | 
						|
  // Package method.
 | 
						|
  // ------------------------------------------------------------------------
 | 
						|
 | 
						|
  static void writeLength(OutputStream out, int len) throws IOException
 | 
						|
  {
 | 
						|
    if (len < 128)
 | 
						|
      out.write(len);
 | 
						|
    else if (len < 256)
 | 
						|
      {
 | 
						|
        out.write(0x81);
 | 
						|
        out.write(len);
 | 
						|
      }
 | 
						|
    else if (len < 65536)
 | 
						|
      {
 | 
						|
        out.write(0x82);
 | 
						|
        out.write(len >> 8);
 | 
						|
        out.write(len);
 | 
						|
      }
 | 
						|
    else if (len < 16777216)
 | 
						|
      {
 | 
						|
        out.write(0x83);
 | 
						|
        out.write(len >> 16);
 | 
						|
        out.write(len >>  8);
 | 
						|
        out.write(len);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        out.write(0x84);
 | 
						|
        out.write(len >> 24);
 | 
						|
        out.write(len >> 16);
 | 
						|
        out.write(len >>  8);
 | 
						|
        out.write(len);
 | 
						|
      }
 | 
						|
  }
 | 
						|
}
 |