1 package org.bouncycastle.asn1; 2 3 import java.io.IOException; 4 import java.util.Enumeration; 5 import java.util.Vector; 6 7 public abstract class ASN1Sequence 8 extends ASN1Object 9 { 10 private Vector seq = new Vector(); 11 12 /** 13 * return an ASN1Sequence from the given object. 14 * 15 * @param obj the object we want converted. 16 * @exception IllegalArgumentException if the object cannot be converted. 17 */ getInstance( Object obj)18 public static ASN1Sequence getInstance( 19 Object obj) 20 { 21 if (obj == null || obj instanceof ASN1Sequence) 22 { 23 return (ASN1Sequence)obj; 24 } 25 else if (obj instanceof byte[]) 26 { 27 try 28 { 29 return ASN1Sequence.getInstance(ASN1Object.fromByteArray((byte[])obj)); 30 } 31 catch (IOException e) 32 { 33 throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage()); 34 } 35 } 36 37 throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 38 } 39 40 /** 41 * Return an ASN1 sequence from a tagged object. There is a special 42 * case here, if an object appears to have been explicitly tagged on 43 * reading but we were expecting it to be implicitly tagged in the 44 * normal course of events it indicates that we lost the surrounding 45 * sequence - so we need to add it back (this will happen if the tagged 46 * object is a sequence that contains other sequences). If you are 47 * dealing with implicitly tagged sequences you really <b>should</b> 48 * be using this method. 49 * 50 * @param obj the tagged object. 51 * @param explicit true if the object is meant to be explicitly tagged, 52 * false otherwise. 53 * @exception IllegalArgumentException if the tagged object cannot 54 * be converted. 55 */ getInstance( ASN1TaggedObject obj, boolean explicit)56 public static ASN1Sequence getInstance( 57 ASN1TaggedObject obj, 58 boolean explicit) 59 { 60 if (explicit) 61 { 62 if (!obj.isExplicit()) 63 { 64 throw new IllegalArgumentException("object implicit - explicit expected."); 65 } 66 67 return (ASN1Sequence)obj.getObject(); 68 } 69 else 70 { 71 // 72 // constructed object which appears to be explicitly tagged 73 // when it should be implicit means we have to add the 74 // surrounding sequence. 75 // 76 if (obj.isExplicit()) 77 { 78 if (obj instanceof BERTaggedObject) 79 { 80 return new BERSequence(obj.getObject()); 81 } 82 else 83 { 84 return new DERSequence(obj.getObject()); 85 } 86 } 87 else 88 { 89 if (obj.getObject() instanceof ASN1Sequence) 90 { 91 return (ASN1Sequence)obj.getObject(); 92 } 93 } 94 } 95 96 throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 97 } 98 getObjects()99 public Enumeration getObjects() 100 { 101 return seq.elements(); 102 } 103 parser()104 public ASN1SequenceParser parser() 105 { 106 final ASN1Sequence outer = this; 107 108 return new ASN1SequenceParser() 109 { 110 private final int max = size(); 111 112 private int index; 113 114 public DEREncodable readObject() throws IOException 115 { 116 if (index == max) 117 { 118 return null; 119 } 120 121 DEREncodable obj = getObjectAt(index++); 122 if (obj instanceof ASN1Sequence) 123 { 124 return ((ASN1Sequence)obj).parser(); 125 } 126 if (obj instanceof ASN1Set) 127 { 128 return ((ASN1Set)obj).parser(); 129 } 130 131 return obj; 132 } 133 134 public DERObject getLoadedObject() 135 { 136 return outer; 137 } 138 139 public DERObject getDERObject() 140 { 141 return outer; 142 } 143 }; 144 } 145 146 /** 147 * return the object at the sequence position indicated by index. 148 * 149 * @param index the sequence number (starting at zero) of the object 150 * @return the object at the sequence position indicated by index. 151 */ getObjectAt( int index)152 public DEREncodable getObjectAt( 153 int index) 154 { 155 return (DEREncodable)seq.elementAt(index); 156 } 157 158 /** 159 * return the number of objects in this sequence. 160 * 161 * @return the number of objects in this sequence. 162 */ size()163 public int size() 164 { 165 return seq.size(); 166 } 167 hashCode()168 public int hashCode() 169 { 170 Enumeration e = this.getObjects(); 171 int hashCode = size(); 172 173 while (e.hasMoreElements()) 174 { 175 Object o = getNext(e); 176 hashCode *= 17; 177 178 hashCode ^= o.hashCode(); 179 } 180 181 return hashCode; 182 } 183 asn1Equals( DERObject o)184 boolean asn1Equals( 185 DERObject o) 186 { 187 if (!(o instanceof ASN1Sequence)) 188 { 189 return false; 190 } 191 192 ASN1Sequence other = (ASN1Sequence)o; 193 194 if (this.size() != other.size()) 195 { 196 return false; 197 } 198 199 Enumeration s1 = this.getObjects(); 200 Enumeration s2 = other.getObjects(); 201 202 while (s1.hasMoreElements()) 203 { 204 DEREncodable obj1 = getNext(s1); 205 DEREncodable obj2 = getNext(s2); 206 207 DERObject o1 = obj1.getDERObject(); 208 DERObject o2 = obj2.getDERObject(); 209 210 if (o1 == o2 || o1.equals(o2)) 211 { 212 continue; 213 } 214 215 return false; 216 } 217 218 return true; 219 } 220 getNext(Enumeration e)221 private DEREncodable getNext(Enumeration e) 222 { 223 DEREncodable encObj = (DEREncodable)e.nextElement(); 224 225 // unfortunately null was allowed as a substitute for DER null 226 if (encObj == null) 227 { 228 return DERNull.INSTANCE; 229 } 230 231 return encObj; 232 } 233 addObject( DEREncodable obj)234 protected void addObject( 235 DEREncodable obj) 236 { 237 seq.addElement(obj); 238 } 239 encode(DEROutputStream out)240 abstract void encode(DEROutputStream out) 241 throws IOException; 242 toString()243 public String toString() 244 { 245 return seq.toString(); 246 } 247 } 248