1 package org.gudy.bouncycastle.asn1; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.IOException; 5 import java.util.Enumeration; 6 import java.util.Vector; 7 8 abstract public class ASN1Set 9 extends ASN1Object 10 { 11 protected Vector set = new Vector(); 12 13 /** 14 * return an ASN1Set from the given object. 15 * 16 * @param obj the object we want converted. 17 * @exception IllegalArgumentException if the object cannot be converted. 18 */ getInstance( Object obj)19 public static ASN1Set getInstance( 20 Object obj) 21 { 22 if (obj == null || obj instanceof ASN1Set) 23 { 24 return (ASN1Set)obj; 25 } 26 27 throw new IllegalArgumentException("unknown object in getInstance"); 28 } 29 30 /** 31 * Return an ASN1 set from a tagged object. There is a special 32 * case here, if an object appears to have been explicitly tagged on 33 * reading but we were expecting it to be implictly tagged in the 34 * normal course of events it indicates that we lost the surrounding 35 * set - so we need to add it back (this will happen if the tagged 36 * object is a sequence that contains other sequences). If you are 37 * dealing with implicitly tagged sets you really <b>should</b> 38 * be using this method. 39 * 40 * @param obj the tagged object. 41 * @param explicit true if the object is meant to be explicitly tagged 42 * false otherwise. 43 * @exception IllegalArgumentException if the tagged object cannot 44 * be converted. 45 */ getInstance( ASN1TaggedObject obj, boolean explicit)46 public static ASN1Set getInstance( 47 ASN1TaggedObject obj, 48 boolean explicit) 49 { 50 if (explicit) 51 { 52 if (!obj.isExplicit()) 53 { 54 throw new IllegalArgumentException("object implicit - explicit expected."); 55 } 56 57 return (ASN1Set)obj.getObject(); 58 } 59 else 60 { 61 // 62 // constructed object which appears to be explicitly tagged 63 // and it's really implicit means we have to add the 64 // surrounding sequence. 65 // 66 if (obj.isExplicit()) 67 { 68 ASN1Set set = new DERSet(obj.getObject()); 69 70 return set; 71 } 72 else 73 { 74 if (obj.getObject() instanceof ASN1Set) 75 { 76 return (ASN1Set)obj.getObject(); 77 } 78 79 // 80 // in this case the parser returns a sequence, convert it 81 // into a set. 82 // 83 ASN1EncodableVector v = new ASN1EncodableVector(); 84 85 if (obj.getObject() instanceof ASN1Sequence) 86 { 87 ASN1Sequence s = (ASN1Sequence)obj.getObject(); 88 Enumeration e = s.getObjects(); 89 90 while (e.hasMoreElements()) 91 { 92 v.add((DEREncodable)e.nextElement()); 93 } 94 95 return new DERSet(v, false); 96 } 97 } 98 } 99 100 throw new IllegalArgumentException( 101 "unknown object in getInstanceFromTagged"); 102 } 103 ASN1Set()104 public ASN1Set() 105 { 106 } 107 getObjects()108 public Enumeration getObjects() 109 { 110 return set.elements(); 111 } 112 113 /** 114 * return the object at the set postion indicated by index. 115 * 116 * @param index the set number (starting at zero) of the object 117 * @return the object at the set postion indicated by index. 118 */ getObjectAt( int index)119 public DEREncodable getObjectAt( 120 int index) 121 { 122 return (DEREncodable)set.elementAt(index); 123 } 124 125 /** 126 * return the number of objects in this set. 127 * 128 * @return the number of objects in this set. 129 */ size()130 public int size() 131 { 132 return set.size(); 133 } 134 parser()135 public ASN1SetParser parser() 136 { 137 final ASN1Set outer = this; 138 139 return new ASN1SetParser() 140 { 141 private final int max = size(); 142 143 private int index; 144 145 public DEREncodable readObject() throws IOException 146 { 147 if (index == max) 148 { 149 return null; 150 } 151 152 DEREncodable obj = getObjectAt(index++); 153 if (obj instanceof ASN1Sequence) 154 { 155 return ((ASN1Sequence)obj).parser(); 156 } 157 if (obj instanceof ASN1Set) 158 { 159 return ((ASN1Set)obj).parser(); 160 } 161 162 return obj; 163 } 164 165 public DERObject getDERObject() 166 { 167 return outer; 168 } 169 }; 170 } 171 hashCode()172 public int hashCode() 173 { 174 Enumeration e = this.getObjects(); 175 int hashCode = 0; 176 177 while (e.hasMoreElements()) 178 { 179 hashCode ^= e.nextElement().hashCode(); 180 } 181 182 return hashCode; 183 } 184 asn1Equals( DERObject o)185 boolean asn1Equals( 186 DERObject o) 187 { 188 if (!(o instanceof ASN1Set)) 189 { 190 return false; 191 } 192 193 ASN1Set other = (ASN1Set)o; 194 195 if (this.size() != other.size()) 196 { 197 return false; 198 } 199 200 Enumeration s1 = this.getObjects(); 201 Enumeration s2 = other.getObjects(); 202 203 while (s1.hasMoreElements()) 204 { 205 DERObject o1 = ((DEREncodable)s1.nextElement()).getDERObject(); 206 DERObject o2 = ((DEREncodable)s2.nextElement()).getDERObject(); 207 208 if (o1 == o2 || (o1 != null && o1.equals(o2))) 209 { 210 continue; 211 } 212 213 return false; 214 } 215 216 return true; 217 } 218 219 /** 220 * return true if a <= b (arrays are assumed padded with zeros). 221 */ lessThanOrEqual( byte[] a, byte[] b)222 private boolean lessThanOrEqual( 223 byte[] a, 224 byte[] b) 225 { 226 if (a.length <= b.length) 227 { 228 for (int i = 0; i != a.length; i++) 229 { 230 int l = a[i] & 0xff; 231 int r = b[i] & 0xff; 232 233 if (r > l) 234 { 235 return true; 236 } 237 else if (l > r) 238 { 239 return false; 240 } 241 } 242 243 return true; 244 } 245 else 246 { 247 for (int i = 0; i != b.length; i++) 248 { 249 int l = a[i] & 0xff; 250 int r = b[i] & 0xff; 251 252 if (r > l) 253 { 254 return true; 255 } 256 else if (l > r) 257 { 258 return false; 259 } 260 } 261 262 return false; 263 } 264 } 265 getEncoded( DEREncodable obj)266 private byte[] getEncoded( 267 DEREncodable obj) 268 { 269 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 270 ASN1OutputStream aOut = new ASN1OutputStream(bOut); 271 272 try 273 { 274 aOut.writeObject(obj); 275 } 276 catch (IOException e) 277 { 278 throw new IllegalArgumentException("cannot encode object added to SET"); 279 } 280 281 return bOut.toByteArray(); 282 } 283 sort()284 protected void sort() 285 { 286 if (set.size() > 1) 287 { 288 boolean swapped = true; 289 int lastSwap = set.size() - 1; 290 291 while (swapped) 292 { 293 int index = 0; 294 int swapIndex = 0; 295 byte[] a = getEncoded((DEREncodable)set.elementAt(0)); 296 297 swapped = false; 298 299 while (index != lastSwap) 300 { 301 byte[] b = getEncoded((DEREncodable)set.elementAt(index + 1)); 302 303 if (lessThanOrEqual(a, b)) 304 { 305 a = b; 306 } 307 else 308 { 309 Object o = set.elementAt(index); 310 311 set.setElementAt(set.elementAt(index + 1), index); 312 set.setElementAt(o, index + 1); 313 314 swapped = true; 315 swapIndex = index; 316 } 317 318 index++; 319 } 320 321 lastSwap = swapIndex; 322 } 323 } 324 } 325 addObject( DEREncodable obj)326 protected void addObject( 327 DEREncodable obj) 328 { 329 set.addElement(obj); 330 } 331 encode(DEROutputStream out)332 abstract void encode(DEROutputStream out) 333 throws IOException; 334 toString()335 public String toString() 336 { 337 return set.toString(); 338 } 339 } 340