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