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