1package org.bouncycastle.cert.ocsp;
2
3import java.io.ByteArrayOutputStream;
4import java.io.IOException;
5import java.io.OutputStream;
6import java.util.List;
7import java.util.Set;
8
9import org.bouncycastle.asn1.ASN1Encoding;
10import org.bouncycastle.asn1.ASN1Exception;
11import org.bouncycastle.asn1.ASN1InputStream;
12import org.bouncycastle.asn1.ASN1ObjectIdentifier;
13import org.bouncycastle.asn1.ASN1OutputStream;
14import org.bouncycastle.asn1.ASN1Sequence;
15import org.bouncycastle.asn1.ocsp.OCSPRequest;
16import org.bouncycastle.asn1.ocsp.Request;
17import org.bouncycastle.asn1.x509.Certificate;
18import org.bouncycastle.asn1.x509.Extension;
19import org.bouncycastle.asn1.x509.Extensions;
20import org.bouncycastle.asn1.x509.GeneralName;
21import org.bouncycastle.cert.CertIOException;
22import org.bouncycastle.cert.X509CertificateHolder;
23import org.bouncycastle.operator.ContentVerifier;
24import org.bouncycastle.operator.ContentVerifierProvider;
25
26/**
27 * <pre>
28 * OCSPRequest     ::=     SEQUENCE {
29 *       tbsRequest                  TBSRequest,
30 *       optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
31 *
32 *   TBSRequest      ::=     SEQUENCE {
33 *       version             [0]     EXPLICIT Version DEFAULT v1,
34 *       requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
35 *       requestList                 SEQUENCE OF Request,
36 *       requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
37 *
38 *   Signature       ::=     SEQUENCE {
39 *       signatureAlgorithm      AlgorithmIdentifier,
40 *       signature               BIT STRING,
41 *       certs               [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
42 *
43 *   Version         ::=             INTEGER  {  v1(0) }
44 *
45 *   Request         ::=     SEQUENCE {
46 *       reqCert                     CertID,
47 *       singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
48 *
49 *   CertID          ::=     SEQUENCE {
50 *       hashAlgorithm       AlgorithmIdentifier,
51 *       issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
52 *       issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
53 *       serialNumber        CertificateSerialNumber }
54 * </pre>
55 */
56public class OCSPReq
57{
58    private static final X509CertificateHolder[] EMPTY_CERTS = new X509CertificateHolder[0];
59
60    private OCSPRequest    req;
61    private Extensions extensions;
62
63    public OCSPReq(
64        OCSPRequest req)
65    {
66        this.req = req;
67        this.extensions = req.getTbsRequest().getRequestExtensions();
68    }
69
70    public OCSPReq(
71        byte[]          req)
72        throws IOException
73    {
74        this(new ASN1InputStream(req));
75    }
76
77    private OCSPReq(
78        ASN1InputStream aIn)
79        throws IOException
80    {
81        try
82        {
83            this.req = OCSPRequest.getInstance(aIn.readObject());
84            if (req == null)
85            {
86                throw new CertIOException("malformed request: no request data found");
87            }
88            this.extensions = req.getTbsRequest().getRequestExtensions();
89        }
90        catch (IllegalArgumentException e)
91        {
92            throw new CertIOException("malformed request: " + e.getMessage(), e);
93        }
94        catch (ClassCastException e)
95        {
96            throw new CertIOException("malformed request: " + e.getMessage(), e);
97        }
98        catch (ASN1Exception e)
99        {
100            throw new CertIOException("malformed request: " + e.getMessage(), e);
101        }
102    }
103
104    public int getVersionNumber()
105    {
106        return req.getTbsRequest().getVersion().getValue().intValue() + 1;
107    }
108
109    public GeneralName getRequestorName()
110    {
111        return GeneralName.getInstance(req.getTbsRequest().getRequestorName());
112    }
113
114    public Req[] getRequestList()
115    {
116        ASN1Sequence    seq = req.getTbsRequest().getRequestList();
117        Req[]           requests = new Req[seq.size()];
118
119        for (int i = 0; i != requests.length; i++)
120        {
121            requests[i] = new Req(Request.getInstance(seq.getObjectAt(i)));
122        }
123
124        return requests;
125    }
126
127    public boolean hasExtensions()
128    {
129        return extensions != null;
130    }
131
132    public Extension getExtension(ASN1ObjectIdentifier oid)
133    {
134        if (extensions != null)
135        {
136            return extensions.getExtension(oid);
137        }
138
139        return null;
140    }
141
142    public List getExtensionOIDs()
143    {
144        return OCSPUtils.getExtensionOIDs(extensions);
145    }
146
147    public Set getCriticalExtensionOIDs()
148    {
149        return OCSPUtils.getCriticalExtensionOIDs(extensions);
150    }
151
152    public Set getNonCriticalExtensionOIDs()
153    {
154        return OCSPUtils.getNonCriticalExtensionOIDs(extensions);
155    }
156
157    /**
158     * return the object identifier representing the signature algorithm
159     */
160    public ASN1ObjectIdentifier getSignatureAlgOID()
161    {
162        if (!this.isSigned())
163        {
164            return null;
165        }
166
167        return req.getOptionalSignature().getSignatureAlgorithm().getAlgorithm();
168    }
169
170    public byte[] getSignature()
171    {
172        if (!this.isSigned())
173        {
174            return null;
175        }
176
177        return req.getOptionalSignature().getSignature().getOctets();
178    }
179
180    public X509CertificateHolder[] getCerts()
181    {
182        //
183        // load the certificates if we have any
184        //
185        if (req.getOptionalSignature() != null)
186        {
187            ASN1Sequence s = req.getOptionalSignature().getCerts();
188
189            if (s != null)
190            {
191                X509CertificateHolder[] certs = new X509CertificateHolder[s.size()];
192
193                for (int i = 0; i != certs.length; i++)
194                {
195                    certs[i] = new X509CertificateHolder(Certificate.getInstance(s.getObjectAt(i)));
196                }
197
198                return certs;
199            }
200
201            return EMPTY_CERTS;
202        }
203        else
204        {
205            return EMPTY_CERTS;
206        }
207    }
208
209    /**
210     * Return whether or not this request is signed.
211     *
212     * @return true if signed false otherwise.
213     */
214    public boolean isSigned()
215    {
216        return req.getOptionalSignature() != null;
217    }
218
219    /**
220     * verify the signature against the TBSRequest object we contain.
221     */
222    public boolean isSignatureValid(
223        ContentVerifierProvider verifierProvider)
224        throws OCSPException
225    {
226        if (!this.isSigned())
227        {
228            throw new OCSPException("attempt to verify signature on unsigned object");
229        }
230
231        try
232        {
233            ContentVerifier verifier = verifierProvider.get(req.getOptionalSignature().getSignatureAlgorithm());
234            OutputStream sOut = verifier.getOutputStream();
235
236            sOut.write(req.getTbsRequest().getEncoded(ASN1Encoding.DER));
237
238            return verifier.verify(this.getSignature());
239        }
240        catch (Exception e)
241        {
242            throw new OCSPException("exception processing signature: " + e, e);
243        }
244    }
245
246    /**
247     * return the ASN.1 encoded representation of this object.
248     */
249    public byte[] getEncoded()
250        throws IOException
251    {
252        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
253        ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
254
255        aOut.writeObject(req);
256
257        return bOut.toByteArray();
258    }
259}
260