001 package org.apache.commons.ssl.asn1; 002 003 import java.io.ByteArrayOutputStream; 004 import java.io.IOException; 005 import java.util.Enumeration; 006 import java.util.Vector; 007 008 abstract public class ASN1Set 009 extends ASN1Object { 010 protected Vector set = new Vector(); 011 012 /** 013 * return an ASN1Set from the given object. 014 * 015 * @param obj the object we want converted. 016 * @throws IllegalArgumentException if the object cannot be converted. 017 */ 018 public static ASN1Set getInstance( 019 Object obj) { 020 if (obj == null || obj instanceof ASN1Set) { 021 return (ASN1Set) obj; 022 } 023 024 throw new IllegalArgumentException("unknown object in getInstance"); 025 } 026 027 /** 028 * Return an ASN1 set from a tagged object. There is a special 029 * case here, if an object appears to have been explicitly tagged on 030 * reading but we were expecting it to be implictly tagged in the 031 * normal course of events it indicates that we lost the surrounding 032 * set - so we need to add it back (this will happen if the tagged 033 * object is a sequence that contains other sequences). If you are 034 * dealing with implicitly tagged sets you really <b>should</b> 035 * be using this method. 036 * 037 * @param obj the tagged object. 038 * @param explicit true if the object is meant to be explicitly tagged 039 * false otherwise. 040 * @throws IllegalArgumentException if the tagged object cannot 041 * be converted. 042 */ 043 public static ASN1Set getInstance( 044 ASN1TaggedObject obj, 045 boolean explicit) { 046 if (explicit) { 047 if (!obj.isExplicit()) { 048 throw new IllegalArgumentException("object implicit - explicit expected."); 049 } 050 051 return (ASN1Set) obj.getObject(); 052 } else { 053 // 054 // constructed object which appears to be explicitly tagged 055 // and it's really implicit means we have to add the 056 // surrounding sequence. 057 // 058 if (obj.isExplicit()) { 059 ASN1Set set = new DERSet(obj.getObject()); 060 061 return set; 062 } else { 063 if (obj.getObject() instanceof ASN1Set) { 064 return (ASN1Set) obj.getObject(); 065 } 066 067 // 068 // in this case the parser returns a sequence, convert it 069 // into a set. 070 // 071 ASN1EncodableVector v = new ASN1EncodableVector(); 072 073 if (obj.getObject() instanceof ASN1Sequence) { 074 ASN1Sequence s = (ASN1Sequence) obj.getObject(); 075 Enumeration e = s.getObjects(); 076 077 while (e.hasMoreElements()) { 078 v.add((DEREncodable) e.nextElement()); 079 } 080 081 return new DERSet(v, false); 082 } 083 } 084 } 085 086 throw new IllegalArgumentException( 087 "unknown object in getInstanceFromTagged"); 088 } 089 090 public ASN1Set() { 091 } 092 093 public Enumeration getObjects() { 094 return set.elements(); 095 } 096 097 /** 098 * return the object at the set postion indicated by index. 099 * 100 * @param index the set number (starting at zero) of the object 101 * @return the object at the set postion indicated by index. 102 */ 103 public DEREncodable getObjectAt( 104 int index) { 105 return (DEREncodable) set.elementAt(index); 106 } 107 108 /** 109 * return the number of objects in this set. 110 * 111 * @return the number of objects in this set. 112 */ 113 public int size() { 114 return set.size(); 115 } 116 117 public ASN1SetParser parser() { 118 final ASN1Set outer = this; 119 120 return new ASN1SetParser() { 121 private final int max = size(); 122 123 private int index; 124 125 public DEREncodable readObject() throws IOException { 126 if (index == max) { 127 return null; 128 } 129 130 DEREncodable obj = getObjectAt(index++); 131 if (obj instanceof ASN1Sequence) { 132 return ((ASN1Sequence) obj).parser(); 133 } 134 if (obj instanceof ASN1Set) { 135 return ((ASN1Set) obj).parser(); 136 } 137 138 return obj; 139 } 140 141 public DERObject getDERObject() { 142 return outer; 143 } 144 }; 145 } 146 147 public int hashCode() { 148 Enumeration e = this.getObjects(); 149 int hashCode = 0; 150 151 while (e.hasMoreElements()) { 152 hashCode ^= e.nextElement().hashCode(); 153 } 154 155 return hashCode; 156 } 157 158 boolean asn1Equals( 159 DERObject o) { 160 if (!(o instanceof ASN1Set)) { 161 return false; 162 } 163 164 ASN1Set other = (ASN1Set) o; 165 166 if (this.size() != other.size()) { 167 return false; 168 } 169 170 Enumeration s1 = this.getObjects(); 171 Enumeration s2 = other.getObjects(); 172 173 while (s1.hasMoreElements()) { 174 DERObject o1 = ((DEREncodable) s1.nextElement()).getDERObject(); 175 DERObject o2 = ((DEREncodable) s2.nextElement()).getDERObject(); 176 177 if (o1 == o2 || (o1 != null && o1.equals(o2))) { 178 continue; 179 } 180 181 return false; 182 } 183 184 return true; 185 } 186 187 /** return true if a <= b (arrays are assumed padded with zeros). */ 188 private boolean lessThanOrEqual( 189 byte[] a, 190 byte[] b) { 191 if (a.length <= b.length) { 192 for (int i = 0; i != a.length; i++) { 193 int l = a[i] & 0xff; 194 int r = b[i] & 0xff; 195 196 if (r > l) { 197 return true; 198 } else if (l > r) { 199 return false; 200 } 201 } 202 203 return true; 204 } else { 205 for (int i = 0; i != b.length; i++) { 206 int l = a[i] & 0xff; 207 int r = b[i] & 0xff; 208 209 if (r > l) { 210 return true; 211 } else if (l > r) { 212 return false; 213 } 214 } 215 216 return false; 217 } 218 } 219 220 private byte[] getEncoded( 221 DEREncodable obj) { 222 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 223 ASN1OutputStream aOut = new ASN1OutputStream(bOut); 224 225 try { 226 aOut.writeObject(obj); 227 } 228 catch (IOException e) { 229 throw new IllegalArgumentException("cannot encode object added to SET"); 230 } 231 232 return bOut.toByteArray(); 233 } 234 235 protected void sort() { 236 if (set.size() > 1) { 237 boolean swapped = true; 238 int lastSwap = set.size() - 1; 239 240 while (swapped) { 241 int index = 0; 242 int swapIndex = 0; 243 byte[] a = getEncoded((DEREncodable) set.elementAt(0)); 244 245 swapped = false; 246 247 while (index != lastSwap) { 248 byte[] b = getEncoded((DEREncodable) set.elementAt(index + 1)); 249 250 if (lessThanOrEqual(a, b)) { 251 a = b; 252 } else { 253 Object o = set.elementAt(index); 254 255 set.setElementAt(set.elementAt(index + 1), index); 256 set.setElementAt(o, index + 1); 257 258 swapped = true; 259 swapIndex = index; 260 } 261 262 index++; 263 } 264 265 lastSwap = swapIndex; 266 } 267 } 268 } 269 270 protected void addObject( 271 DEREncodable obj) { 272 set.addElement(obj); 273 } 274 275 abstract void encode(DEROutputStream out) 276 throws IOException; 277 278 public String toString() { 279 return set.toString(); 280 } 281 }