001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.geronimo.util.asn1; 019 020 import java.io.ByteArrayInputStream; 021 import java.io.ByteArrayOutputStream; 022 import java.io.EOFException; 023 import java.io.FilterInputStream; 024 import java.io.IOException; 025 import java.io.InputStream; 026 import java.util.Vector; 027 028 /** 029 * a general purpose ASN.1 decoder - note: this class differs from the 030 * others in that it returns null after it has read the last object in 031 * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is 032 * returned. 033 */ 034 public class ASN1InputStream 035 extends FilterInputStream 036 implements DERTags 037 { 038 private DERObject END_OF_STREAM = new DERObject() { 039 void encode( 040 DEROutputStream out) 041 throws IOException 042 { 043 throw new IOException("Eeek!"); 044 } 045 public int hashCode() 046 { 047 return 0; 048 } 049 public boolean equals( 050 Object o) 051 { 052 return o == this; 053 } 054 }; 055 boolean eofFound = false; 056 057 public ASN1InputStream( 058 InputStream is) 059 { 060 super(is); 061 } 062 063 public ASN1InputStream( 064 byte[] input) 065 { 066 super(new ByteArrayInputStream(input)); 067 } 068 069 protected int readLength() 070 throws IOException 071 { 072 int length = read(); 073 if (length < 0) 074 { 075 throw new IOException("EOF found when length expected"); 076 } 077 078 if (length == 0x80) 079 { 080 return -1; // indefinite-length encoding 081 } 082 083 if (length > 127) 084 { 085 int size = length & 0x7f; 086 087 if (size > 4) 088 { 089 throw new IOException("DER length more than 4 bytes"); 090 } 091 092 length = 0; 093 for (int i = 0; i < size; i++) 094 { 095 int next = read(); 096 097 if (next < 0) 098 { 099 throw new IOException("EOF found reading length"); 100 } 101 102 length = (length << 8) + next; 103 } 104 105 if (length < 0) 106 { 107 throw new IOException("corrupted steam - negative length found"); 108 } 109 } 110 111 return length; 112 } 113 114 protected void readFully( 115 byte[] bytes) 116 throws IOException 117 { 118 int left = bytes.length; 119 int len; 120 121 if (left == 0) 122 { 123 return; 124 } 125 126 while ((len = read(bytes, bytes.length - left, left)) > 0) 127 { 128 if ((left -= len) == 0) 129 { 130 return; 131 } 132 } 133 134 if (left != 0) 135 { 136 throw new EOFException("EOF encountered in middle of object"); 137 } 138 } 139 140 /** 141 * build an object given its tag and a byte stream to construct it 142 * from. 143 */ 144 protected DERObject buildObject( 145 int tag, 146 byte[] bytes) 147 throws IOException 148 { 149 if ((tag & APPLICATION) != 0) 150 { 151 return new DERApplicationSpecific(tag, bytes); 152 } 153 154 switch (tag) 155 { 156 case NULL: 157 return new DERNull(); 158 case SEQUENCE | CONSTRUCTED: 159 ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); 160 ASN1InputStream aIn = new ASN1InputStream(bIn); 161 ASN1EncodableVector v = new ASN1EncodableVector(); 162 163 DERObject obj = aIn.readObject(); 164 165 while (obj != null) 166 { 167 v.add(obj); 168 obj = aIn.readObject(); 169 } 170 171 return new DERSequence(v); 172 case SET | CONSTRUCTED: 173 bIn = new ByteArrayInputStream(bytes); 174 aIn = new ASN1InputStream(bIn); 175 v = new ASN1EncodableVector(); 176 177 obj = aIn.readObject(); 178 179 while (obj != null) 180 { 181 v.add(obj); 182 obj = aIn.readObject(); 183 } 184 185 return new DERSet(v, false); 186 case BOOLEAN: 187 return new DERBoolean(bytes); 188 case INTEGER: 189 return new DERInteger(bytes); 190 case ENUMERATED: 191 return new DEREnumerated(bytes); 192 case OBJECT_IDENTIFIER: 193 return new DERObjectIdentifier(bytes); 194 case BIT_STRING: 195 int padBits = bytes[0]; 196 byte[] data = new byte[bytes.length - 1]; 197 198 System.arraycopy(bytes, 1, data, 0, bytes.length - 1); 199 200 return new DERBitString(data, padBits); 201 case NUMERIC_STRING: 202 return new DERNumericString(bytes); 203 case UTF8_STRING: 204 return new DERUTF8String(bytes); 205 case PRINTABLE_STRING: 206 return new DERPrintableString(bytes); 207 case IA5_STRING: 208 return new DERIA5String(bytes); 209 case T61_STRING: 210 return new DERT61String(bytes); 211 case VISIBLE_STRING: 212 return new DERVisibleString(bytes); 213 case GENERAL_STRING: 214 return new DERGeneralString(bytes); 215 case UNIVERSAL_STRING: 216 return new DERUniversalString(bytes); 217 case BMP_STRING: 218 return new DERBMPString(bytes); 219 case OCTET_STRING: 220 return new DEROctetString(bytes); 221 case UTC_TIME: 222 return new DERUTCTime(bytes); 223 case GENERALIZED_TIME: 224 return new DERGeneralizedTime(bytes); 225 default: 226 // 227 // with tagged object tag number is bottom 5 bits 228 // 229 if ((tag & TAGGED) != 0) 230 { 231 int tagNo = tag & 0x1f; 232 233 if (tagNo == 0x1f) 234 { 235 int idx = 0; 236 237 tagNo = 0; 238 239 while ((bytes[idx] & 0x80) != 0) 240 { 241 tagNo |= (bytes[idx++] & 0x7f); 242 tagNo <<= 7; 243 } 244 245 tagNo |= (bytes[idx] & 0x7f); 246 247 byte[] tmp = bytes; 248 249 bytes = new byte[tmp.length - (idx + 1)]; 250 System.arraycopy(tmp, idx + 1, bytes, 0, bytes.length); 251 } 252 253 if (bytes.length == 0) // empty tag! 254 { 255 if ((tag & CONSTRUCTED) == 0) 256 { 257 return new DERTaggedObject(false, tagNo, new DERNull()); 258 } 259 else 260 { 261 return new DERTaggedObject(false, tagNo, new DERSequence()); 262 } 263 } 264 265 // 266 // simple type - implicit... return an octet string 267 // 268 if ((tag & CONSTRUCTED) == 0) 269 { 270 return new DERTaggedObject(false, tagNo, new DEROctetString(bytes)); 271 } 272 273 bIn = new ByteArrayInputStream(bytes); 274 aIn = new ASN1InputStream(bIn); 275 276 DEREncodable dObj = aIn.readObject(); 277 278 // 279 // explicitly tagged (probably!) - if it isn't we'd have to 280 // tell from the context 281 // 282 if (aIn.available() == 0) 283 { 284 return new DERTaggedObject(tagNo, dObj); 285 } 286 287 // 288 // another implicit object, we'll create a sequence... 289 // 290 v = new ASN1EncodableVector(); 291 292 while (dObj != null) 293 { 294 v.add(dObj); 295 dObj = aIn.readObject(); 296 } 297 298 return new DERTaggedObject(false, tagNo, new DERSequence(v)); 299 } 300 301 return new DERUnknownTag(tag, bytes); 302 } 303 } 304 305 /** 306 * read a string of bytes representing an indefinite length object. 307 */ 308 private byte[] readIndefiniteLengthFully() 309 throws IOException 310 { 311 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 312 int b, b1; 313 314 b1 = read(); 315 316 while ((b = read()) >= 0) 317 { 318 if (b1 == 0 && b == 0) 319 { 320 break; 321 } 322 323 bOut.write(b1); 324 b1 = b; 325 } 326 327 return bOut.toByteArray(); 328 } 329 330 private BERConstructedOctetString buildConstructedOctetString() 331 throws IOException 332 { 333 Vector octs = new Vector(); 334 335 for (;;) 336 { 337 DERObject o = readObject(); 338 339 if (o == END_OF_STREAM) 340 { 341 break; 342 } 343 344 octs.addElement(o); 345 } 346 347 return new BERConstructedOctetString(octs); 348 } 349 350 public DERObject readObject() 351 throws IOException 352 { 353 int tag = read(); 354 if (tag == -1) 355 { 356 if (eofFound) 357 { 358 throw new EOFException("attempt to read past end of file."); 359 } 360 361 eofFound = true; 362 363 return null; 364 } 365 366 int length = readLength(); 367 368 if (length < 0) // indefinite length method 369 { 370 switch (tag) 371 { 372 case NULL: 373 return new BERNull(); 374 case SEQUENCE | CONSTRUCTED: 375 ASN1EncodableVector v = new ASN1EncodableVector(); 376 377 for (;;) 378 { 379 DERObject obj = readObject(); 380 381 if (obj == END_OF_STREAM) 382 { 383 break; 384 } 385 386 v.add(obj); 387 } 388 return new BERSequence(v); 389 case SET | CONSTRUCTED: 390 v = new ASN1EncodableVector(); 391 392 for (;;) 393 { 394 DERObject obj = readObject(); 395 396 if (obj == END_OF_STREAM) 397 { 398 break; 399 } 400 401 v.add(obj); 402 } 403 return new BERSet(v, false); 404 case OCTET_STRING | CONSTRUCTED: 405 return buildConstructedOctetString(); 406 default: 407 // 408 // with tagged object tag number is bottom 5 bits 409 // 410 if ((tag & TAGGED) != 0) 411 { 412 int tagNo = tag & 0x1f; 413 414 if (tagNo == 0x1f) 415 { 416 int b = read(); 417 418 tagNo = 0; 419 420 while ((b >= 0) && ((b & 0x80) != 0)) 421 { 422 tagNo |= (b & 0x7f); 423 tagNo <<= 7; 424 b = read(); 425 } 426 427 tagNo |= (b & 0x7f); 428 } 429 430 // 431 // simple type - implicit... return an octet string 432 // 433 if ((tag & CONSTRUCTED) == 0) 434 { 435 byte[] bytes = readIndefiniteLengthFully(); 436 437 return new BERTaggedObject(false, tagNo, new DEROctetString(bytes)); 438 } 439 440 // 441 // either constructed or explicitly tagged 442 // 443 DERObject dObj = readObject(); 444 445 if (dObj == END_OF_STREAM) // empty tag! 446 { 447 return new DERTaggedObject(tagNo); 448 } 449 450 DERObject next = readObject(); 451 452 // 453 // explicitly tagged (probably!) - if it isn't we'd have to 454 // tell from the context 455 // 456 if (next == END_OF_STREAM) 457 { 458 return new BERTaggedObject(tagNo, dObj); 459 } 460 461 // 462 // another implicit object, we'll create a sequence... 463 // 464 v = new ASN1EncodableVector(); 465 466 v.add(dObj); 467 468 do 469 { 470 v.add(next); 471 next = readObject(); 472 } 473 while (next != END_OF_STREAM); 474 475 return new BERTaggedObject(false, tagNo, new BERSequence(v)); 476 } 477 478 throw new IOException("unknown BER object encountered"); 479 } 480 } 481 else 482 { 483 if (tag == 0 && length == 0) // end of contents marker. 484 { 485 return END_OF_STREAM; 486 } 487 488 byte[] bytes = new byte[length]; 489 490 readFully(bytes); 491 492 return buildObject(tag, bytes); 493 } 494 } 495 }