001package org.apache.commons.ssl.org.bouncycastle.asn1.util; 002 003import java.io.IOException; 004import java.util.Enumeration; 005 006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Boolean; 007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Encodable; 008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Enumerated; 009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1GeneralizedTime; 010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Integer; 011import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1ObjectIdentifier; 012import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1OctetString; 013import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive; 014import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence; 015import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Set; 016import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1TaggedObject; 017import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1UTCTime; 018import org.apache.commons.ssl.org.bouncycastle.asn1.BERApplicationSpecific; 019import org.apache.commons.ssl.org.bouncycastle.asn1.BEROctetString; 020import org.apache.commons.ssl.org.bouncycastle.asn1.BERSequence; 021import org.apache.commons.ssl.org.bouncycastle.asn1.BERSet; 022import org.apache.commons.ssl.org.bouncycastle.asn1.BERTaggedObject; 023import org.apache.commons.ssl.org.bouncycastle.asn1.BERTags; 024import org.apache.commons.ssl.org.bouncycastle.asn1.DERApplicationSpecific; 025import org.apache.commons.ssl.org.bouncycastle.asn1.DERBMPString; 026import org.apache.commons.ssl.org.bouncycastle.asn1.DERBitString; 027import org.apache.commons.ssl.org.bouncycastle.asn1.DERExternal; 028import org.apache.commons.ssl.org.bouncycastle.asn1.DERIA5String; 029import org.apache.commons.ssl.org.bouncycastle.asn1.DERNull; 030import org.apache.commons.ssl.org.bouncycastle.asn1.DERPrintableString; 031import org.apache.commons.ssl.org.bouncycastle.asn1.DERSequence; 032import org.apache.commons.ssl.org.bouncycastle.asn1.DERT61String; 033import org.apache.commons.ssl.org.bouncycastle.asn1.DERUTF8String; 034import org.apache.commons.ssl.org.bouncycastle.asn1.DERVisibleString; 035import org.bouncycastle.util.encoders.Hex; 036 037public class ASN1Dump 038{ 039 private static final String TAB = " "; 040 private static final int SAMPLE_SIZE = 32; 041 042 /** 043 * dump a DER object as a formatted string with indentation 044 * 045 * @param obj the ASN1Primitive to be dumped out. 046 */ 047 static void _dumpAsString( 048 String indent, 049 boolean verbose, 050 ASN1Primitive obj, 051 StringBuffer buf) 052 { 053 String nl = System.getProperty("line.separator"); 054 if (obj instanceof ASN1Sequence) 055 { 056 Enumeration e = ((ASN1Sequence)obj).getObjects(); 057 String tab = indent + TAB; 058 059 buf.append(indent); 060 if (obj instanceof BERSequence) 061 { 062 buf.append("BER Sequence"); 063 } 064 else if (obj instanceof DERSequence) 065 { 066 buf.append("DER Sequence"); 067 } 068 else 069 { 070 buf.append("Sequence"); 071 } 072 073 buf.append(nl); 074 075 while (e.hasMoreElements()) 076 { 077 Object o = e.nextElement(); 078 079 if (o == null || o.equals(DERNull.INSTANCE)) 080 { 081 buf.append(tab); 082 buf.append("NULL"); 083 buf.append(nl); 084 } 085 else if (o instanceof ASN1Primitive) 086 { 087 _dumpAsString(tab, verbose, (ASN1Primitive)o, buf); 088 } 089 else 090 { 091 _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf); 092 } 093 } 094 } 095 else if (obj instanceof ASN1TaggedObject) 096 { 097 String tab = indent + TAB; 098 099 buf.append(indent); 100 if (obj instanceof BERTaggedObject) 101 { 102 buf.append("BER Tagged ["); 103 } 104 else 105 { 106 buf.append("Tagged ["); 107 } 108 109 ASN1TaggedObject o = (ASN1TaggedObject)obj; 110 111 buf.append(Integer.toString(o.getTagNo())); 112 buf.append(']'); 113 114 if (!o.isExplicit()) 115 { 116 buf.append(" IMPLICIT "); 117 } 118 119 buf.append(nl); 120 121 if (o.isEmpty()) 122 { 123 buf.append(tab); 124 buf.append("EMPTY"); 125 buf.append(nl); 126 } 127 else 128 { 129 _dumpAsString(tab, verbose, o.getObject(), buf); 130 } 131 } 132 else if (obj instanceof ASN1Set) 133 { 134 Enumeration e = ((ASN1Set)obj).getObjects(); 135 String tab = indent + TAB; 136 137 buf.append(indent); 138 139 if (obj instanceof BERSet) 140 { 141 buf.append("BER Set"); 142 } 143 else 144 { 145 buf.append("DER Set"); 146 } 147 148 buf.append(nl); 149 150 while (e.hasMoreElements()) 151 { 152 Object o = e.nextElement(); 153 154 if (o == null) 155 { 156 buf.append(tab); 157 buf.append("NULL"); 158 buf.append(nl); 159 } 160 else if (o instanceof ASN1Primitive) 161 { 162 _dumpAsString(tab, verbose, (ASN1Primitive)o, buf); 163 } 164 else 165 { 166 _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf); 167 } 168 } 169 } 170 else if (obj instanceof ASN1OctetString) 171 { 172 ASN1OctetString oct = (ASN1OctetString)obj; 173 174 if (obj instanceof BEROctetString) 175 { 176 buf.append(indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] "); 177 } 178 else 179 { 180 buf.append(indent + "DER Octet String" + "[" + oct.getOctets().length + "] "); 181 } 182 if (verbose) 183 { 184 buf.append(dumpBinaryDataAsString(indent, oct.getOctets())); 185 } 186 else 187 { 188 buf.append(nl); 189 } 190 } 191 else if (obj instanceof ASN1ObjectIdentifier) 192 { 193 buf.append(indent + "ObjectIdentifier(" + ((ASN1ObjectIdentifier)obj).getId() + ")" + nl); 194 } 195 else if (obj instanceof ASN1Boolean) 196 { 197 buf.append(indent + "Boolean(" + ((ASN1Boolean)obj).isTrue() + ")" + nl); 198 } 199 else if (obj instanceof ASN1Integer) 200 { 201 buf.append(indent + "Integer(" + ((ASN1Integer)obj).getValue() + ")" + nl); 202 } 203 else if (obj instanceof DERBitString) 204 { 205 DERBitString bt = (DERBitString)obj; 206 buf.append(indent + "DER Bit String" + "[" + bt.getBytes().length + ", " + bt.getPadBits() + "] "); 207 if (verbose) 208 { 209 buf.append(dumpBinaryDataAsString(indent, bt.getBytes())); 210 } 211 else 212 { 213 buf.append(nl); 214 } 215 } 216 else if (obj instanceof DERIA5String) 217 { 218 buf.append(indent + "IA5String(" + ((DERIA5String)obj).getString() + ") " + nl); 219 } 220 else if (obj instanceof DERUTF8String) 221 { 222 buf.append(indent + "UTF8String(" + ((DERUTF8String)obj).getString() + ") " + nl); 223 } 224 else if (obj instanceof DERPrintableString) 225 { 226 buf.append(indent + "PrintableString(" + ((DERPrintableString)obj).getString() + ") " + nl); 227 } 228 else if (obj instanceof DERVisibleString) 229 { 230 buf.append(indent + "VisibleString(" + ((DERVisibleString)obj).getString() + ") " + nl); 231 } 232 else if (obj instanceof DERBMPString) 233 { 234 buf.append(indent + "BMPString(" + ((DERBMPString)obj).getString() + ") " + nl); 235 } 236 else if (obj instanceof DERT61String) 237 { 238 buf.append(indent + "T61String(" + ((DERT61String)obj).getString() + ") " + nl); 239 } 240 else if (obj instanceof ASN1UTCTime) 241 { 242 buf.append(indent + "UTCTime(" + ((ASN1UTCTime)obj).getTime() + ") " + nl); 243 } 244 else if (obj instanceof ASN1GeneralizedTime) 245 { 246 buf.append(indent + "GeneralizedTime(" + ((ASN1GeneralizedTime)obj).getTime() + ") " + nl); 247 } 248 else if (obj instanceof BERApplicationSpecific) 249 { 250 buf.append(outputApplicationSpecific("BER", indent, verbose, obj, nl)); 251 } 252 else if (obj instanceof DERApplicationSpecific) 253 { 254 buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl)); 255 } 256 else if (obj instanceof ASN1Enumerated) 257 { 258 ASN1Enumerated en = (ASN1Enumerated) obj; 259 buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl); 260 } 261 else if (obj instanceof DERExternal) 262 { 263 DERExternal ext = (DERExternal) obj; 264 buf.append(indent + "External " + nl); 265 String tab = indent + TAB; 266 if (ext.getDirectReference() != null) 267 { 268 buf.append(tab + "Direct Reference: " + ext.getDirectReference().getId() + nl); 269 } 270 if (ext.getIndirectReference() != null) 271 { 272 buf.append(tab + "Indirect Reference: " + ext.getIndirectReference().toString() + nl); 273 } 274 if (ext.getDataValueDescriptor() != null) 275 { 276 _dumpAsString(tab, verbose, ext.getDataValueDescriptor(), buf); 277 } 278 buf.append(tab + "Encoding: " + ext.getEncoding() + nl); 279 _dumpAsString(tab, verbose, ext.getExternalContent(), buf); 280 } 281 else 282 { 283 buf.append(indent + obj.toString() + nl); 284 } 285 } 286 287 private static String outputApplicationSpecific(String type, String indent, boolean verbose, ASN1Primitive obj, String nl) 288 { 289 DERApplicationSpecific app = (DERApplicationSpecific)obj; 290 StringBuffer buf = new StringBuffer(); 291 292 if (app.isConstructed()) 293 { 294 try 295 { 296 ASN1Sequence s = ASN1Sequence.getInstance(app.getObject(BERTags.SEQUENCE)); 297 buf.append(indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "]" + nl); 298 for (Enumeration e = s.getObjects(); e.hasMoreElements();) 299 { 300 _dumpAsString(indent + TAB, verbose, (ASN1Primitive)e.nextElement(), buf); 301 } 302 } 303 catch (IOException e) 304 { 305 buf.append(e); 306 } 307 return buf.toString(); 308 } 309 310 return indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "] (" + new String(Hex.encode(app.getContents())) + ")" + nl; 311 } 312 313 /** 314 * dump out a DER object as a formatted string, in non-verbose mode. 315 * 316 * @param obj the ASN1Primitive to be dumped out. 317 * @return the resulting string. 318 */ 319 public static String dumpAsString( 320 Object obj) 321 { 322 return dumpAsString(obj, false); 323 } 324 325 /** 326 * Dump out the object as a string. 327 * 328 * @param obj the object to be dumped 329 * @param verbose if true, dump out the contents of octet and bit strings. 330 * @return the resulting string. 331 */ 332 public static String dumpAsString( 333 Object obj, 334 boolean verbose) 335 { 336 StringBuffer buf = new StringBuffer(); 337 338 if (obj instanceof ASN1Primitive) 339 { 340 _dumpAsString("", verbose, (ASN1Primitive)obj, buf); 341 } 342 else if (obj instanceof ASN1Encodable) 343 { 344 _dumpAsString("", verbose, ((ASN1Encodable)obj).toASN1Primitive(), buf); 345 } 346 else 347 { 348 return "unknown object type " + obj.toString(); 349 } 350 351 return buf.toString(); 352 } 353 354 private static String dumpBinaryDataAsString(String indent, byte[] bytes) 355 { 356 String nl = System.getProperty("line.separator"); 357 StringBuffer buf = new StringBuffer(); 358 359 indent += TAB; 360 361 buf.append(nl); 362 for (int i = 0; i < bytes.length; i += SAMPLE_SIZE) 363 { 364 if (bytes.length - i > SAMPLE_SIZE) 365 { 366 buf.append(indent); 367 buf.append(new String(Hex.encode(bytes, i, SAMPLE_SIZE))); 368 buf.append(TAB); 369 buf.append(calculateAscString(bytes, i, SAMPLE_SIZE)); 370 buf.append(nl); 371 } 372 else 373 { 374 buf.append(indent); 375 buf.append(new String(Hex.encode(bytes, i, bytes.length - i))); 376 for (int j = bytes.length - i; j != SAMPLE_SIZE; j++) 377 { 378 buf.append(" "); 379 } 380 buf.append(TAB); 381 buf.append(calculateAscString(bytes, i, bytes.length - i)); 382 buf.append(nl); 383 } 384 } 385 386 return buf.toString(); 387 } 388 389 private static String calculateAscString(byte[] bytes, int off, int len) 390 { 391 StringBuffer buf = new StringBuffer(); 392 393 for (int i = off; i != off + len; i++) 394 { 395 if (bytes[i] >= ' ' && bytes[i] <= '~') 396 { 397 buf.append((char)bytes[i]); 398 } 399 } 400 401 return buf.toString(); 402 } 403}