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