1/*
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.security.provider.certpath;
27
28import java.io.IOException;
29import java.security.cert.Extension;
30import java.util.Collections;
31import java.util.List;
32
33import sun.misc.HexDumpEncoder;
34import sun.security.util.*;
35
36/**
37 * This class can be used to generate an OCSP request and send it over
38 * an outputstream. Currently we do not support signing requests
39 * The OCSP Request is specified in RFC 2560 and
40 * the ASN.1 definition is as follows:
41 * <pre>
42 *
43 * OCSPRequest     ::=     SEQUENCE {
44 *      tbsRequest                  TBSRequest,
45 *      optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
46 *
47 *   TBSRequest      ::=     SEQUENCE {
48 *      version             [0]     EXPLICIT Version DEFAULT v1,
49 *      requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
50 *      requestList                 SEQUENCE OF Request,
51 *      requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
52 *
53 *  Signature       ::=     SEQUENCE {
54 *      signatureAlgorithm      AlgorithmIdentifier,
55 *      signature               BIT STRING,
56 *      certs               [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
57 *   }
58 *
59 *  Version         ::=             INTEGER  {  v1(0) }
60 *
61 *  Request         ::=     SEQUENCE {
62 *      reqCert                     CertID,
63 *      singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
64 *
65 *  CertID          ::= SEQUENCE {
66 *       hashAlgorithm  AlgorithmIdentifier,
67 *       issuerNameHash OCTET STRING, -- Hash of Issuer's DN
68 *       issuerKeyHash  OCTET STRING, -- Hash of Issuers public key
69 *       serialNumber   CertificateSerialNumber
70 * }
71 *
72 * </pre>
73 *
74 * @author      Ram Marti
75 */
76
77class OCSPRequest {
78
79    private static final Debug debug = Debug.getInstance("certpath");
80    private static final boolean dump = debug != null && Debug.isOn("ocsp");
81
82    // List of request CertIds
83    private final List<CertId> certIds;
84    private final List<Extension> extensions;
85    private byte[] nonce;
86
87    /*
88     * Constructs an OCSPRequest. This constructor is used
89     * to construct an unsigned OCSP Request for a single user cert.
90     */
91    OCSPRequest(CertId certId) {
92        this(Collections.singletonList(certId));
93    }
94
95    OCSPRequest(List<CertId> certIds) {
96        this.certIds = certIds;
97        this.extensions = Collections.<Extension>emptyList();
98    }
99
100    OCSPRequest(List<CertId> certIds, List<Extension> extensions) {
101        this.certIds = certIds;
102        this.extensions = extensions;
103    }
104
105    byte[] encodeBytes() throws IOException {
106
107        // encode tbsRequest
108        DerOutputStream tmp = new DerOutputStream();
109        DerOutputStream requestsOut = new DerOutputStream();
110        for (CertId certId : certIds) {
111            DerOutputStream certIdOut = new DerOutputStream();
112            certId.encode(certIdOut);
113            requestsOut.write(DerValue.tag_Sequence, certIdOut);
114        }
115
116        tmp.write(DerValue.tag_Sequence, requestsOut);
117        if (!extensions.isEmpty()) {
118            DerOutputStream extOut = new DerOutputStream();
119            for (Extension ext : extensions) {
120                ext.encode(extOut);
121                if (ext.getId().equals(OCSP.NONCE_EXTENSION_OID.toString())) {
122                    nonce = ext.getValue();
123                }
124            }
125            DerOutputStream extsOut = new DerOutputStream();
126            extsOut.write(DerValue.tag_Sequence, extOut);
127            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT,
128                                         true, (byte)2), extsOut);
129        }
130
131        DerOutputStream tbsRequest = new DerOutputStream();
132        tbsRequest.write(DerValue.tag_Sequence, tmp);
133
134        // OCSPRequest without the signature
135        DerOutputStream ocspRequest = new DerOutputStream();
136        ocspRequest.write(DerValue.tag_Sequence, tbsRequest);
137
138        byte[] bytes = ocspRequest.toByteArray();
139
140        if (dump) {
141            HexDumpEncoder hexEnc = new HexDumpEncoder();
142            debug.println("OCSPRequest bytes...\n\n" +
143                hexEnc.encode(bytes) + "\n");
144        }
145
146        return bytes;
147    }
148
149    List<CertId> getCertIds() {
150        return certIds;
151    }
152
153    byte[] getNonce() {
154        return nonce;
155    }
156}
157