1package org.bouncycastle.asn1.x509;
2
3import java.math.BigInteger;
4
5import org.bouncycastle.asn1.ASN1Boolean;
6import org.bouncycastle.asn1.ASN1EncodableVector;
7import org.bouncycastle.asn1.ASN1Integer;
8import org.bouncycastle.asn1.ASN1Object;
9import org.bouncycastle.asn1.ASN1Primitive;
10import org.bouncycastle.asn1.ASN1Sequence;
11import org.bouncycastle.asn1.ASN1TaggedObject;
12import org.bouncycastle.asn1.DERBoolean;
13import org.bouncycastle.asn1.DERSequence;
14
15public class BasicConstraints
16    extends ASN1Object
17{
18    ASN1Boolean  cA = ASN1Boolean.getInstance(false);
19    ASN1Integer  pathLenConstraint = null;
20
21    public static BasicConstraints getInstance(
22        ASN1TaggedObject obj,
23        boolean          explicit)
24    {
25        return getInstance(ASN1Sequence.getInstance(obj, explicit));
26    }
27
28    public static BasicConstraints getInstance(
29        Object  obj)
30    {
31        if (obj instanceof BasicConstraints)
32        {
33            return (BasicConstraints)obj;
34        }
35        if (obj instanceof X509Extension)
36        {
37            return getInstance(X509Extension.convertValueToObject((X509Extension)obj));
38        }
39        if (obj != null)
40        {
41            return new BasicConstraints(ASN1Sequence.getInstance(obj));
42        }
43
44        return null;
45    }
46
47    public static BasicConstraints fromExtensions(Extensions extensions)
48    {
49        return BasicConstraints.getInstance(extensions.getExtensionParsedValue(Extension.basicConstraints));
50    }
51
52    private BasicConstraints(
53        ASN1Sequence   seq)
54    {
55        if (seq.size() == 0)
56        {
57            this.cA = null;
58            this.pathLenConstraint = null;
59        }
60        else
61        {
62            if (seq.getObjectAt(0) instanceof DERBoolean)
63            {
64                this.cA = DERBoolean.getInstance(seq.getObjectAt(0));
65            }
66            else
67            {
68                this.cA = null;
69                this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(0));
70            }
71            if (seq.size() > 1)
72            {
73                if (this.cA != null)
74                {
75                    this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(1));
76                }
77                else
78                {
79                    throw new IllegalArgumentException("wrong sequence in constructor");
80                }
81            }
82        }
83    }
84
85    public BasicConstraints(
86        boolean cA)
87    {
88        if (cA)
89        {
90            this.cA = ASN1Boolean.getInstance(true);
91        }
92        else
93        {
94            this.cA = null;
95        }
96        this.pathLenConstraint = null;
97    }
98
99    /**
100     * create a cA=true object for the given path length constraint.
101     *
102     * @param pathLenConstraint
103     */
104    public BasicConstraints(
105        int     pathLenConstraint)
106    {
107        this.cA = ASN1Boolean.getInstance(true);
108        this.pathLenConstraint = new ASN1Integer(pathLenConstraint);
109    }
110
111    public boolean isCA()
112    {
113        return (cA != null) && cA.isTrue();
114    }
115
116    public BigInteger getPathLenConstraint()
117    {
118        if (pathLenConstraint != null)
119        {
120            return pathLenConstraint.getValue();
121        }
122
123        return null;
124    }
125
126    /**
127     * Produce an object suitable for an ASN1OutputStream.
128     * <pre>
129     * BasicConstraints := SEQUENCE {
130     *    cA                  BOOLEAN DEFAULT FALSE,
131     *    pathLenConstraint   INTEGER (0..MAX) OPTIONAL
132     * }
133     * </pre>
134     */
135    public ASN1Primitive toASN1Primitive()
136    {
137        ASN1EncodableVector  v = new ASN1EncodableVector();
138
139        if (cA != null)
140        {
141            v.add(cA);
142        }
143
144        if (pathLenConstraint != null)  // yes some people actually do this when cA is false...
145        {
146            v.add(pathLenConstraint);
147        }
148
149        return new DERSequence(v);
150    }
151
152    public String toString()
153    {
154        if (pathLenConstraint == null)
155        {
156            if (cA == null)
157            {
158                return "BasicConstraints: isCa(false)";
159            }
160            return "BasicConstraints: isCa(" + this.isCA() + ")";
161        }
162        return "BasicConstraints: isCa(" + this.isCA() + "), pathLenConstraint = " + pathLenConstraint.getValue();
163    }
164}
165