GeneralSubtree.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
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