001package org.apache.commons.ssl.org.bouncycastle.asn1.x509;
002
003import java.math.BigInteger;
004
005import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1EncodableVector;
006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Integer;
007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Object;
008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1TaggedObject;
011import org.apache.commons.ssl.org.bouncycastle.asn1.DERSequence;
012import org.apache.commons.ssl.org.bouncycastle.asn1.DERTaggedObject;
013
014/**
015 * Class for containing a restriction object subtrees in NameConstraints. See
016 * RFC 3280.
017 * 
018 * <pre>
019 *       
020 *       GeneralSubtree ::= SEQUENCE 
021 *       {
022 *         base                    GeneralName,
023 *         minimum         [0]     BaseDistance DEFAULT 0,
024 *         maximum         [1]     BaseDistance OPTIONAL 
025 *       }
026 * </pre>
027 * 
028 * @see org.bouncycastle.asn1.x509.NameConstraints
029 * 
030 */
031public class GeneralSubtree 
032    extends ASN1Object
033{
034    private static final BigInteger ZERO = BigInteger.valueOf(0);
035
036    private GeneralName base;
037
038    private ASN1Integer minimum;
039
040    private ASN1Integer maximum;
041
042    private GeneralSubtree(
043        ASN1Sequence seq) 
044    {
045        base = GeneralName.getInstance(seq.getObjectAt(0));
046
047        switch (seq.size()) 
048        {
049        case 1:
050            break;
051        case 2:
052            ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(1));
053            switch (o.getTagNo()) 
054            {
055            case 0:
056                minimum = ASN1Integer.getInstance(o, false);
057                break;
058            case 1:
059                maximum = ASN1Integer.getInstance(o, false);
060                break;
061            default:
062                throw new IllegalArgumentException("Bad tag number: "
063                        + o.getTagNo());
064            }
065            break;
066        case 3:
067        {
068            {
069                ASN1TaggedObject oMin = ASN1TaggedObject.getInstance(seq.getObjectAt(1));
070                if (oMin.getTagNo() != 0)
071                {
072                    throw new IllegalArgumentException("Bad tag number for 'minimum': " + oMin.getTagNo());
073                }
074                minimum = ASN1Integer.getInstance(oMin, false);
075            }
076
077            {
078                ASN1TaggedObject oMax = ASN1TaggedObject.getInstance(seq.getObjectAt(2));
079                if (oMax.getTagNo() != 1)
080                {
081                    throw new IllegalArgumentException("Bad tag number for 'maximum': " + oMax.getTagNo());
082                }
083                maximum = ASN1Integer.getInstance(oMax, false);
084            }
085
086            break;
087        }
088        default:
089            throw new IllegalArgumentException("Bad sequence size: "
090                    + seq.size());
091        }
092    }
093
094    /**
095     * Constructor from a given details.
096     * 
097     * According RFC 3280, the minimum and maximum fields are not used with any
098     * name forms, thus minimum MUST be zero, and maximum MUST be absent.
099     * <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}