1package org.bouncycastle.asn1.x509; 2 3import java.math.BigInteger; 4 5import org.bouncycastle.asn1.ASN1EncodableVector; 6import org.bouncycastle.asn1.ASN1Integer; 7import org.bouncycastle.asn1.ASN1Object; 8import org.bouncycastle.asn1.ASN1Primitive; 9import org.bouncycastle.asn1.ASN1Sequence; 10import org.bouncycastle.asn1.ASN1TaggedObject; 11import org.bouncycastle.asn1.DERSequence; 12import org.bouncycastle.asn1.DERTaggedObject; 13 14/** 15 * Class for containing a restriction object subtrees in NameConstraints. See 16 * RFC 3280. 17 * 18 * <pre> 19 * 20 * GeneralSubtree ::= SEQUENCE 21 * { 22 * base GeneralName, 23 * minimum [0] BaseDistance DEFAULT 0, 24 * maximum [1] BaseDistance OPTIONAL 25 * } 26 * </pre> 27 * 28 * @see org.bouncycastle.asn1.x509.NameConstraints 29 * 30 */ 31public class GeneralSubtree 32 extends ASN1Object 33{ 34 private static final BigInteger ZERO = BigInteger.valueOf(0); 35 36 private GeneralName base; 37 38 private ASN1Integer minimum; 39 40 private ASN1Integer maximum; 41 42 private GeneralSubtree( 43 ASN1Sequence seq) 44 { 45 base = GeneralName.getInstance(seq.getObjectAt(0)); 46 47 switch (seq.size()) 48 { 49 case 1: 50 break; 51 case 2: 52 ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(1)); 53 switch (o.getTagNo()) 54 { 55 case 0: 56 minimum = ASN1Integer.getInstance(o, false); 57 break; 58 case 1: 59 maximum = ASN1Integer.getInstance(o, false); 60 break; 61 default: 62 throw new IllegalArgumentException("Bad tag number: " 63 + o.getTagNo()); 64 } 65 break; 66 case 3: 67 { 68 { 69 ASN1TaggedObject oMin = ASN1TaggedObject.getInstance(seq.getObjectAt(1)); 70 if (oMin.getTagNo() != 0) 71 { 72 throw new IllegalArgumentException("Bad tag number for 'minimum': " + oMin.getTagNo()); 73 } 74 minimum = ASN1Integer.getInstance(oMin, false); 75 } 76 77 { 78 ASN1TaggedObject oMax = ASN1TaggedObject.getInstance(seq.getObjectAt(2)); 79 if (oMax.getTagNo() != 1) 80 { 81 throw new IllegalArgumentException("Bad tag number for 'maximum': " + oMax.getTagNo()); 82 } 83 maximum = ASN1Integer.getInstance(oMax, false); 84 } 85 86 break; 87 } 88 default: 89 throw new IllegalArgumentException("Bad sequence size: " 90 + seq.size()); 91 } 92 } 93 94 /** 95 * Constructor from a given details. 96 * 97 * According RFC 3280, the minimum and maximum fields are not used with any 98 * name forms, thus minimum MUST be zero, and maximum MUST be absent. 99 * <p> 100 * If minimum is <code>null</code>, zero is assumed, if 101 * maximum is <code>null</code>, maximum is absent. 102 * 103 * @param base 104 * A restriction. 105 * @param minimum 106 * Minimum 107 * 108 * @param maximum 109 * Maximum 110 */ 111 public GeneralSubtree( 112 GeneralName base, 113 BigInteger minimum, 114 BigInteger maximum) 115 { 116 this.base = base; 117 if (maximum != null) 118 { 119 this.maximum = new ASN1Integer(maximum); 120 } 121 if (minimum == null) 122 { 123 this.minimum = null; 124 } 125 else 126 { 127 this.minimum = new ASN1Integer(minimum); 128 } 129 } 130 131 public GeneralSubtree(GeneralName base) 132 { 133 this(base, null, null); 134 } 135 136 public static GeneralSubtree getInstance( 137 ASN1TaggedObject o, 138 boolean explicit) 139 { 140 return new GeneralSubtree(ASN1Sequence.getInstance(o, explicit)); 141 } 142 143 public static GeneralSubtree getInstance( 144 Object obj) 145 { 146 if (obj == null) 147 { 148 return null; 149 } 150 151 if (obj instanceof GeneralSubtree) 152 { 153 return (GeneralSubtree) obj; 154 } 155 156 return new GeneralSubtree(ASN1Sequence.getInstance(obj)); 157 } 158 159 public GeneralName getBase() 160 { 161 return base; 162 } 163 164 public BigInteger getMinimum() 165 { 166 if (minimum == null) 167 { 168 return ZERO; 169 } 170 171 return minimum.getValue(); 172 } 173 174 public BigInteger getMaximum() 175 { 176 if (maximum == null) 177 { 178 return null; 179 } 180 181 return maximum.getValue(); 182 } 183 184 /** 185 * Produce an object suitable for an ASN1OutputStream. 186 * 187 * Returns: 188 * 189 * <pre> 190 * GeneralSubtree ::= SEQUENCE 191 * { 192 * base GeneralName, 193 * minimum [0] BaseDistance DEFAULT 0, 194 * maximum [1] BaseDistance OPTIONAL 195 * } 196 * </pre> 197 * 198 * @return a ASN1Primitive 199 */ 200 public ASN1Primitive toASN1Primitive() 201 { 202 ASN1EncodableVector v = new ASN1EncodableVector(); 203 204 v.add(base); 205 206 if (minimum != null && !minimum.getValue().equals(ZERO)) 207 { 208 v.add(new DERTaggedObject(false, 0, minimum)); 209 } 210 211 if (maximum != null) 212 { 213 v.add(new DERTaggedObject(false, 1, maximum)); 214 } 215 216 return new DERSequence(v); 217 } 218} 219