1package org.bouncycastle.asn1.x509;
2
3import org.bouncycastle.asn1.ASN1Encodable;
4import org.bouncycastle.asn1.ASN1EncodableVector;
5import org.bouncycastle.asn1.ASN1Sequence;
6import org.bouncycastle.asn1.ASN1TaggedObject;
7import org.bouncycastle.asn1.DERBitString;
8import org.bouncycastle.asn1.DEREnumerated;
9import org.bouncycastle.asn1.DERObject;
10import org.bouncycastle.asn1.DERObjectIdentifier;
11import org.bouncycastle.asn1.DERSequence;
12
13/**
14 * ObjectDigestInfo ASN.1 structure used in v2 attribute certificates.
15 *
16 * <pre>
17 *
18 *    ObjectDigestInfo ::= SEQUENCE {
19 *         digestedObjectType  ENUMERATED {
20 *                 publicKey            (0),
21 *                 publicKeyCert        (1),
22 *                 otherObjectTypes     (2) },
23 *                         -- otherObjectTypes MUST NOT
24 *                         -- be used in this profile
25 *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,
26 *         digestAlgorithm     AlgorithmIdentifier,
27 *         objectDigest        BIT STRING
28 *    }
29 *
30 * </pre>
31 *
32 */
33public class ObjectDigestInfo
34    extends ASN1Encodable
35{
36    /**
37     * The public key is hashed.
38     */
39    public final static int publicKey = 0;
40
41    /**
42     * The public key certificate is hashed.
43     */
44    public final static int publicKeyCert = 1;
45
46    /**
47     * An other object is hashed.
48     */
49    public final static int otherObjectDigest = 2;
50
51    DEREnumerated digestedObjectType;
52
53    DERObjectIdentifier otherObjectTypeID;
54
55    AlgorithmIdentifier digestAlgorithm;
56
57    DERBitString objectDigest;
58
59    public static ObjectDigestInfo getInstance(
60        Object obj)
61    {
62        if (obj == null || obj instanceof ObjectDigestInfo)
63        {
64            return (ObjectDigestInfo)obj;
65        }
66
67        if (obj instanceof ASN1Sequence)
68        {
69            return new ObjectDigestInfo((ASN1Sequence)obj);
70        }
71
72        throw new IllegalArgumentException("illegal object in getInstance: "
73            + obj.getClass().getName());
74    }
75
76    public static ObjectDigestInfo getInstance(
77        ASN1TaggedObject obj,
78        boolean          explicit)
79    {
80        return getInstance(ASN1Sequence.getInstance(obj, explicit));
81    }
82
83    /**
84     * Constructor from given details.
85     * <p>
86     * If <code>digestedObjectType</code> is not {@link #publicKeyCert} or
87     * {@link #publicKey} <code>otherObjectTypeID</code> must be given,
88     * otherwise it is ignored.
89     *
90     * @param digestedObjectType The digest object type.
91     * @param otherObjectTypeID The object type ID for
92     *            <code>otherObjectDigest</code>.
93     * @param digestAlgorithm The algorithm identifier for the hash.
94     * @param objectDigest The hash value.
95     */
96    public ObjectDigestInfo(
97        int digestedObjectType,
98        String otherObjectTypeID,
99        AlgorithmIdentifier digestAlgorithm,
100        byte[] objectDigest)
101    {
102        this.digestedObjectType = new DEREnumerated(digestedObjectType);
103        if (digestedObjectType == otherObjectDigest)
104        {
105            this.otherObjectTypeID = new DERObjectIdentifier(otherObjectTypeID);
106        }
107
108        this.digestAlgorithm = digestAlgorithm;
109
110        this.objectDigest = new DERBitString(objectDigest);
111    }
112
113    private ObjectDigestInfo(
114        ASN1Sequence seq)
115    {
116        if (seq.size() > 4 || seq.size() < 3)
117        {
118            throw new IllegalArgumentException("Bad sequence size: "
119                + seq.size());
120        }
121
122        digestedObjectType = DEREnumerated.getInstance(seq.getObjectAt(0));
123
124        int offset = 0;
125
126        if (seq.size() == 4)
127        {
128            otherObjectTypeID = DERObjectIdentifier.getInstance(seq.getObjectAt(1));
129            offset++;
130        }
131
132        digestAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1 + offset));
133
134        objectDigest = DERBitString.getInstance(seq.getObjectAt(2 + offset));
135    }
136
137    public DEREnumerated getDigestedObjectType()
138    {
139        return digestedObjectType;
140    }
141
142    public DERObjectIdentifier getOtherObjectTypeID()
143    {
144        return otherObjectTypeID;
145    }
146
147    public AlgorithmIdentifier getDigestAlgorithm()
148    {
149        return digestAlgorithm;
150    }
151
152    public DERBitString getObjectDigest()
153    {
154        return objectDigest;
155    }
156
157    /**
158     * Produce an object suitable for an ASN1OutputStream.
159     *
160     * <pre>
161     *
162     *    ObjectDigestInfo ::= SEQUENCE {
163     *         digestedObjectType  ENUMERATED {
164     *                 publicKey            (0),
165     *                 publicKeyCert        (1),
166     *                 otherObjectTypes     (2) },
167     *                         -- otherObjectTypes MUST NOT
168     *                         -- be used in this profile
169     *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,
170     *         digestAlgorithm     AlgorithmIdentifier,
171     *         objectDigest        BIT STRING
172     *    }
173     *
174     * </pre>
175     */
176    public DERObject toASN1Object()
177    {
178        ASN1EncodableVector v = new ASN1EncodableVector();
179
180        v.add(digestedObjectType);
181
182        if (otherObjectTypeID != null)
183        {
184            v.add(otherObjectTypeID);
185        }
186
187        v.add(digestAlgorithm);
188        v.add(objectDigest);
189
190        return new DERSequence(v);
191    }
192}
193