]> WPIA git - gigi.git/blob - src/club/wpia/gigi/crypto/OCSPRequest.java
add: implement OCSP serving
[gigi.git] / src / club / wpia / gigi / crypto / OCSPRequest.java
1 package club.wpia.gigi.crypto;
2
3 import java.io.IOException;
4 import java.security.cert.Extension;
5 import java.util.Collections;
6 import java.util.LinkedList;
7 import java.util.List;
8
9 import sun.security.provider.certpath.CertId;
10 import sun.security.util.DerInputStream;
11 import sun.security.util.DerOutputStream;
12 import sun.security.util.DerValue;
13 import sun.security.util.ObjectIdentifier;
14
15 /**
16  * Adapted from {@link sun.security.provider.certpath.OCSPRequest}
17  */
18 public class OCSPRequest {
19
20     static final ObjectIdentifier NONCE_EXTENSION_OID = ObjectIdentifier.newInternal(new int[] {
21             1, 3, 6, 1, 5, 5, 7, 48, 1, 2
22     });
23
24     // List of request CertIds
25     private final List<CertId> certIds;
26
27     private final List<Extension> extensions;
28
29     private byte[] nonce;
30
31     private Extension nonceExt;
32
33     /*
34      * Constructs an OCSPRequest. This constructor is used to construct an
35      * unsigned OCSP Request for a single user cert.
36      */
37     OCSPRequest(CertId certId) {
38         this(Collections.singletonList(certId));
39     }
40
41     OCSPRequest(List<CertId> certIds) {
42         this.certIds = certIds;
43         this.extensions = Collections.<Extension>emptyList();
44     }
45
46     OCSPRequest(List<CertId> certIds, List<Extension> extensions) {
47         this.certIds = certIds;
48         this.extensions = extensions;
49     }
50
51     /**
52      * Creates a new OCSPRequest from its binary data.
53      * 
54      * @param in
55      *            the binary form of the OCSP request.
56      * @throws IOException
57      *             if the input is malformed
58      */
59     public OCSPRequest(byte[] in) throws IOException {
60         DerInputStream dis = new DerInputStream(in);
61         DerInputStream req = dis.getDerValue().getData();
62         DerInputStream tbsreq = req.getDerValue().getData();
63         // req.getDerValue()optional signature
64
65         LinkedList<Extension> exts = new LinkedList<>();
66         LinkedList<CertId> cis = new LinkedList<>();
67         // handles the content of structure
68         // @formatter:off
69         //TBSRequest ::= SEQUENCE {
70         //    version             [0] EXPLICIT Version DEFAULT v1,
71         //    requestorName       [1] EXPLICIT GeneralName OPTIONAL,
72         //    requestList             SEQUENCE OF Request,
73         //    requestExtensions   [2] EXPLICIT Extensions OPTIONAL }
74         // @formatter:on
75         while (tbsreq.available() > 0) {
76             // Handle content
77             if (tbsreq.peekByte() == DerValue.tag_Sequence) {
78                 for (DerValue certId : tbsreq.getSequence(1)) {
79                     CertId ci = new CertId(certId.getData().getDerValue().getData());
80                     cis.add(ci);
81                 }
82                 // Handle extensions
83             } else if (tbsreq.peekByte() == DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 2)) {
84                 DerValue[] seq = tbsreq.getDerValue().getData().getSequence(5);
85                 for (DerValue derValue : seq) {
86                     sun.security.x509.Extension e = new sun.security.x509.Extension(derValue);
87                     if (e.getExtensionId().equals((Object) NONCE_EXTENSION_OID)) {
88                         nonce = e.getValue();
89                         nonceExt = e;
90                     } else if (e.isCritical()) {
91                         throw new IOException("Unknown critical extension");
92                     }
93
94                     exts.add(e);
95                 }
96                 // Skip any other element
97             } else {
98                 tbsreq.getDerValue();
99             }
100         }
101
102         if (exts.isEmpty()) {
103             extensions = null;
104         } else {
105             extensions = Collections.unmodifiableList(exts);
106         }
107         certIds = Collections.unmodifiableList(cis);
108     }
109
110     byte[] encodeBytes() throws IOException {
111
112         // encode tbsRequest
113         DerOutputStream tmp = new DerOutputStream();
114         DerOutputStream requestsOut = new DerOutputStream();
115         for (CertId certId : certIds) {
116             DerOutputStream certIdOut = new DerOutputStream();
117             certId.encode(certIdOut);
118             requestsOut.write(DerValue.tag_Sequence, certIdOut);
119         }
120
121         tmp.write(DerValue.tag_Sequence, requestsOut);
122         if ( !extensions.isEmpty()) {
123             DerOutputStream extOut = new DerOutputStream();
124             for (Extension ext : extensions) {
125                 ext.encode(extOut);
126                 if (ext.getId().equals(NONCE_EXTENSION_OID.toString())) {
127                     nonce = ext.getValue();
128                     nonceExt = ext;
129                 }
130             }
131             DerOutputStream extsOut = new DerOutputStream();
132             extsOut.write(DerValue.tag_Sequence, extOut);
133             tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 2), extsOut);
134         }
135
136         DerOutputStream tbsRequest = new DerOutputStream();
137         tbsRequest.write(DerValue.tag_Sequence, tmp);
138
139         // OCSPRequest without the signature
140         DerOutputStream ocspRequest = new DerOutputStream();
141         ocspRequest.write(DerValue.tag_Sequence, tbsRequest);
142
143         byte[] bytes = ocspRequest.toByteArray();
144
145         return bytes;
146     }
147
148     public List<CertId> getCertIds() {
149         return certIds;
150     }
151
152     byte[] getNonce() {
153         return nonce;
154     }
155
156     public Extension getNonceExt() {
157         return nonceExt;
158     }
159 }