Home | History | Annotate | Download | only in util
      1 package org.bouncycastle.asn1.util;
      2 
      3 import java.io.IOException;
      4 import java.util.Enumeration;
      5 
      6 import org.bouncycastle.asn1.ASN1OctetString;
      7 import org.bouncycastle.asn1.ASN1Sequence;
      8 import org.bouncycastle.asn1.ASN1Set;
      9 import org.bouncycastle.asn1.BERApplicationSpecific;
     10 import org.bouncycastle.asn1.BERConstructedOctetString;
     11 import org.bouncycastle.asn1.BERConstructedSequence;
     12 import org.bouncycastle.asn1.BERSequence;
     13 import org.bouncycastle.asn1.BERSet;
     14 import org.bouncycastle.asn1.BERTaggedObject;
     15 import org.bouncycastle.asn1.DERApplicationSpecific;
     16 import org.bouncycastle.asn1.DERBMPString;
     17 import org.bouncycastle.asn1.DERBitString;
     18 import org.bouncycastle.asn1.DERBoolean;
     19 import org.bouncycastle.asn1.DERConstructedSequence;
     20 import org.bouncycastle.asn1.DERConstructedSet;
     21 import org.bouncycastle.asn1.DEREncodable;
     22 import org.bouncycastle.asn1.DEREnumerated;
     23 import org.bouncycastle.asn1.DERExternal;
     24 import org.bouncycastle.asn1.DERGeneralizedTime;
     25 import org.bouncycastle.asn1.DERIA5String;
     26 import org.bouncycastle.asn1.DERInteger;
     27 import org.bouncycastle.asn1.DERNull;
     28 import org.bouncycastle.asn1.DERObject;
     29 import org.bouncycastle.asn1.DERObjectIdentifier;
     30 import org.bouncycastle.asn1.DEROctetString;
     31 import org.bouncycastle.asn1.DERPrintableString;
     32 import org.bouncycastle.asn1.DERSequence;
     33 import org.bouncycastle.asn1.DERSet;
     34 import org.bouncycastle.asn1.DERT61String;
     35 import org.bouncycastle.asn1.DERTaggedObject;
     36 import org.bouncycastle.asn1.DERTags;
     37 import org.bouncycastle.asn1.DERUTCTime;
     38 import org.bouncycastle.asn1.DERUTF8String;
     39 import org.bouncycastle.asn1.DERUnknownTag;
     40 import org.bouncycastle.asn1.DERVisibleString;
     41 import org.bouncycastle.util.encoders.Hex;
     42 
     43 public class ASN1Dump
     44 {
     45     private static final String  TAB = "    ";
     46     private static final int SAMPLE_SIZE = 32;
     47 
     48     /**
     49      * dump a DER object as a formatted string with indentation
     50      *
     51      * @param obj the DERObject to be dumped out.
     52      */
     53     static void _dumpAsString(
     54         String      indent,
     55         boolean     verbose,
     56         DERObject   obj,
     57         StringBuffer    buf)
     58     {
     59         String nl = System.getProperty("line.separator");
     60         if (obj instanceof ASN1Sequence)
     61         {
     62             Enumeration     e = ((ASN1Sequence)obj).getObjects();
     63             String          tab = indent + TAB;
     64 
     65             buf.append(indent);
     66             if (obj instanceof BERConstructedSequence)
     67             {
     68                 buf.append("BER ConstructedSequence");
     69             }
     70             else if (obj instanceof DERConstructedSequence)
     71             {
     72                 buf.append("DER ConstructedSequence");
     73             }
     74             else if (obj instanceof BERSequence)
     75             {
     76                 buf.append("BER Sequence");
     77             }
     78             else if (obj instanceof DERSequence)
     79             {
     80                 buf.append("DER Sequence");
     81             }
     82             else
     83             {
     84                 buf.append("Sequence");
     85             }
     86 
     87             buf.append(nl);
     88 
     89             while (e.hasMoreElements())
     90             {
     91                 Object  o = e.nextElement();
     92 
     93                 // BEGIN android-changed
     94                 if (o == null || o.equals(DERNull.INSTANCE))
     95                 // END android-changed
     96                 {
     97                     buf.append(tab);
     98                     buf.append("NULL");
     99                     buf.append(nl);
    100                 }
    101                 else if (o instanceof DERObject)
    102                 {
    103                     _dumpAsString(tab, verbose, (DERObject)o, buf);
    104                 }
    105                 else
    106                 {
    107                     _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
    108                 }
    109             }
    110         }
    111         else if (obj instanceof DERTaggedObject)
    112         {
    113             String          tab = indent + TAB;
    114 
    115             buf.append(indent);
    116             if (obj instanceof BERTaggedObject)
    117             {
    118                 buf.append("BER Tagged [");
    119             }
    120             else
    121             {
    122                 buf.append("Tagged [");
    123             }
    124 
    125             DERTaggedObject o = (DERTaggedObject)obj;
    126 
    127             buf.append(Integer.toString(o.getTagNo()));
    128             buf.append(']');
    129 
    130             if (!o.isExplicit())
    131             {
    132                 buf.append(" IMPLICIT ");
    133             }
    134 
    135             buf.append(nl);
    136 
    137             if (o.isEmpty())
    138             {
    139                 buf.append(tab);
    140                 buf.append("EMPTY");
    141                 buf.append(nl);
    142             }
    143             else
    144             {
    145                 _dumpAsString(tab, verbose, o.getObject(), buf);
    146             }
    147         }
    148         else if (obj instanceof DERConstructedSet)
    149         {
    150             Enumeration     e = ((ASN1Set)obj).getObjects();
    151             String          tab = indent + TAB;
    152 
    153             buf.append(indent);
    154             buf.append("ConstructedSet");
    155             buf.append(nl);
    156 
    157             while (e.hasMoreElements())
    158             {
    159                 Object  o = e.nextElement();
    160 
    161                 if (o == null)
    162                 {
    163                     buf.append(tab);
    164                     buf.append("NULL");
    165                     buf.append(nl);
    166                 }
    167                 else if (o instanceof DERObject)
    168                 {
    169                     _dumpAsString(tab, verbose, (DERObject)o, buf);
    170                 }
    171                 else
    172                 {
    173                     _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
    174                 }
    175             }
    176         }
    177         else if (obj instanceof BERSet)
    178         {
    179             Enumeration     e = ((ASN1Set)obj).getObjects();
    180             String          tab = indent + TAB;
    181 
    182             buf.append(indent);
    183             buf.append("BER Set");
    184             buf.append(nl);
    185 
    186             while (e.hasMoreElements())
    187             {
    188                 Object  o = e.nextElement();
    189 
    190                 if (o == null)
    191                 {
    192                     buf.append(tab);
    193                     buf.append("NULL");
    194                     buf.append(nl);
    195                 }
    196                 else if (o instanceof DERObject)
    197                 {
    198                     _dumpAsString(tab, verbose, (DERObject)o, buf);
    199                 }
    200                 else
    201                 {
    202                     _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
    203                 }
    204             }
    205         }
    206         else if (obj instanceof DERSet)
    207         {
    208             Enumeration     e = ((ASN1Set)obj).getObjects();
    209             String          tab = indent + TAB;
    210 
    211             buf.append(indent);
    212             buf.append("DER Set");
    213             buf.append(nl);
    214 
    215             while (e.hasMoreElements())
    216             {
    217                 Object  o = e.nextElement();
    218 
    219                 if (o == null)
    220                 {
    221                     buf.append(tab);
    222                     buf.append("NULL");
    223                     buf.append(nl);
    224                 }
    225                 else if (o instanceof DERObject)
    226                 {
    227                     _dumpAsString(tab, verbose, (DERObject)o, buf);
    228                 }
    229                 else
    230                 {
    231                     _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
    232                 }
    233             }
    234         }
    235         else if (obj instanceof DERObjectIdentifier)
    236         {
    237             buf.append(indent + "ObjectIdentifier(" + ((DERObjectIdentifier)obj).getId() + ")" + nl);
    238         }
    239         else if (obj instanceof DERBoolean)
    240         {
    241             buf.append(indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + nl);
    242         }
    243         else if (obj instanceof DERInteger)
    244         {
    245             buf.append(indent + "Integer(" + ((DERInteger)obj).getValue() + ")" + nl);
    246         }
    247         else if (obj instanceof BERConstructedOctetString)
    248         {
    249             ASN1OctetString oct = (ASN1OctetString)obj;
    250             buf.append(indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] ");
    251             if (verbose)
    252             {
    253                 buf.append(dumpBinaryDataAsString(indent, oct.getOctets()));
    254             }
    255             else{
    256                 buf.append(nl);
    257             }
    258         }
    259         else if (obj instanceof DEROctetString)
    260         {
    261             ASN1OctetString oct = (ASN1OctetString)obj;
    262             buf.append(indent + "DER Octet String" + "[" + oct.getOctets().length + "] ");
    263             if (verbose)
    264             {
    265                 buf.append(dumpBinaryDataAsString(indent, oct.getOctets()));
    266             }
    267             else{
    268                 buf.append(nl);
    269             }
    270         }
    271         else if (obj instanceof DERBitString)
    272         {
    273             DERBitString bt = (DERBitString)obj;
    274             buf.append(indent + "DER Bit String" + "[" + bt.getBytes().length + ", " + bt.getPadBits() + "] ");
    275             if (verbose)
    276             {
    277                 buf.append(dumpBinaryDataAsString(indent, bt.getBytes()));
    278             }
    279             else{
    280                 buf.append(nl);
    281             }
    282         }
    283         else if (obj instanceof DERIA5String)
    284         {
    285             buf.append(indent + "IA5String(" + ((DERIA5String)obj).getString() + ") " + nl);
    286         }
    287         else if (obj instanceof DERUTF8String)
    288         {
    289             buf.append(indent + "UTF8String(" + ((DERUTF8String)obj).getString() + ") " + nl);
    290         }
    291         else if (obj instanceof DERPrintableString)
    292         {
    293             buf.append(indent + "PrintableString(" + ((DERPrintableString)obj).getString() + ") " + nl);
    294         }
    295         else if (obj instanceof DERVisibleString)
    296         {
    297             buf.append(indent + "VisibleString(" + ((DERVisibleString)obj).getString() + ") " + nl);
    298         }
    299         else if (obj instanceof DERBMPString)
    300         {
    301             buf.append(indent + "BMPString(" + ((DERBMPString)obj).getString() + ") " + nl);
    302         }
    303         else if (obj instanceof DERT61String)
    304         {
    305             buf.append(indent + "T61String(" + ((DERT61String)obj).getString() + ") " + nl);
    306         }
    307         else if (obj instanceof DERUTCTime)
    308         {
    309             buf.append(indent + "UTCTime(" + ((DERUTCTime)obj).getTime() + ") " + nl);
    310         }
    311         else if (obj instanceof DERGeneralizedTime)
    312         {
    313             buf.append(indent + "GeneralizedTime(" + ((DERGeneralizedTime)obj).getTime() + ") " + nl);
    314         }
    315         else if (obj instanceof DERUnknownTag)
    316         {
    317             buf.append(indent + "Unknown " + Integer.toString(((DERUnknownTag)obj).getTag(), 16) + " " + new String(Hex.encode(((DERUnknownTag)obj).getData())) + nl);
    318         }
    319         else if (obj instanceof BERApplicationSpecific)
    320         {
    321             buf.append(outputApplicationSpecific("BER", indent, verbose, obj, nl));
    322         }
    323         else if (obj instanceof DERApplicationSpecific)
    324         {
    325             buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl));
    326         }
    327         else if (obj instanceof DEREnumerated)
    328         {
    329             DEREnumerated en = (DEREnumerated) obj;
    330             buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl);
    331         }
    332         else if (obj instanceof DERExternal)
    333         {
    334             DERExternal ext = (DERExternal) obj;
    335             buf.append(indent + "External " + nl);
    336             String          tab = indent + TAB;
    337             if (ext.getDirectReference() != null)
    338             {
    339                 buf.append(tab + "Direct Reference: " + ext.getDirectReference().getId() + nl);
    340             }
    341             if (ext.getIndirectReference() != null)
    342             {
    343                 buf.append(tab + "Indirect Reference: " + ext.getIndirectReference().toString() + nl);
    344             }
    345             if (ext.getDataValueDescriptor() != null)
    346             {
    347                 _dumpAsString(tab, verbose, ext.getDataValueDescriptor(), buf);
    348             }
    349             buf.append(tab + "Encoding: " + ext.getEncoding() + nl);
    350             _dumpAsString(tab, verbose, ext.getExternalContent(), buf);
    351         }
    352         else
    353         {
    354             buf.append(indent + obj.toString() + nl);
    355         }
    356     }
    357 
    358     private static String outputApplicationSpecific(String type, String indent, boolean verbose, DERObject obj, String nl)
    359     {
    360         DERApplicationSpecific app = (DERApplicationSpecific)obj;
    361         StringBuffer buf = new StringBuffer();
    362 
    363         if (app.isConstructed())
    364         {
    365             try
    366             {
    367                 ASN1Sequence s = ASN1Sequence.getInstance(app.getObject(DERTags.SEQUENCE));
    368                 buf.append(indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "]" + nl);
    369                 for (Enumeration e = s.getObjects(); e.hasMoreElements();)
    370                 {
    371                     _dumpAsString(indent + TAB, verbose, (DERObject)e.nextElement(), buf);
    372                 }
    373             }
    374             catch (IOException e)
    375             {
    376                 buf.append(e);
    377             }
    378             return buf.toString();
    379         }
    380 
    381         return indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "] (" + new String(Hex.encode(app.getContents())) + ")" + nl;
    382     }
    383 
    384     /**
    385      * dump out a DER object as a formatted string, in non-verbose mode.
    386      *
    387      * @param obj the DERObject to be dumped out.
    388      * @return  the resulting string.
    389      */
    390     public static String dumpAsString(
    391         Object   obj)
    392     {
    393         return dumpAsString(obj, false);
    394     }
    395 
    396     /**
    397      * Dump out the object as a string.
    398      *
    399      * @param obj  the object to be dumped
    400      * @param verbose  if true, dump out the contents of octet and bit strings.
    401      * @return  the resulting string.
    402      */
    403     public static String dumpAsString(
    404         Object   obj,
    405         boolean  verbose)
    406     {
    407         StringBuffer buf = new StringBuffer();
    408 
    409         if (obj instanceof DERObject)
    410         {
    411             _dumpAsString("", verbose, (DERObject)obj, buf);
    412         }
    413         else if (obj instanceof DEREncodable)
    414         {
    415             _dumpAsString("", verbose, ((DEREncodable)obj).getDERObject(), buf);
    416         }
    417         else
    418         {
    419             return "unknown object type " + obj.toString();
    420         }
    421 
    422         return buf.toString();
    423     }
    424 
    425     private static String dumpBinaryDataAsString(String indent, byte[] bytes)
    426     {
    427         String nl = System.getProperty("line.separator");
    428         StringBuffer buf = new StringBuffer();
    429 
    430         indent += TAB;
    431 
    432         buf.append(nl);
    433         for (int i = 0; i < bytes.length; i += SAMPLE_SIZE)
    434         {
    435             if (bytes.length - i > SAMPLE_SIZE)
    436             {
    437                 buf.append(indent);
    438                 buf.append(new String(Hex.encode(bytes, i, SAMPLE_SIZE)));
    439                 buf.append(TAB);
    440                 buf.append(calculateAscString(bytes, i, SAMPLE_SIZE));
    441                 buf.append(nl);
    442             }
    443             else
    444             {
    445                 buf.append(indent);
    446                 buf.append(new String(Hex.encode(bytes, i, bytes.length - i)));
    447                 for (int j = bytes.length - i; j != SAMPLE_SIZE; j++)
    448                 {
    449                     buf.append("  ");
    450                 }
    451                 buf.append(TAB);
    452                 buf.append(calculateAscString(bytes, i, bytes.length - i));
    453                 buf.append(nl);
    454             }
    455         }
    456 
    457         return buf.toString();
    458     }
    459 
    460     private static String calculateAscString(byte[] bytes, int off, int len)
    461     {
    462         StringBuffer buf = new StringBuffer();
    463 
    464         for (int i = off; i != off + len; i++)
    465         {
    466             if (bytes[i] >= ' ' && bytes[i] <= '~')
    467             {
    468                 buf.append((char)bytes[i]);
    469             }
    470         }
    471 
    472         return buf.toString();
    473     }
    474 }
    475