1 package club.wpia.gigi.crypto;
3 import java.io.IOException;
4 import java.security.GeneralSecurityException;
5 import java.security.Signature;
6 import java.security.cert.CRLReason;
7 import java.security.cert.Extension;
8 import java.security.cert.X509Certificate;
11 import javax.security.auth.x500.X500Principal;
13 import sun.security.provider.certpath.CertId;
14 import sun.security.util.DerOutputStream;
15 import sun.security.util.DerValue;
16 import sun.security.util.ObjectIdentifier;
17 import sun.security.x509.AlgorithmId;
19 public class OCSPResponse {
21 private Extension nonceExt;
23 public static class SingleResponse {
25 private final CertId target;
27 private final Date thisUpdate;
29 private final Date nextUpdate;
31 private final Date revoked;
33 private final CRLReason res;
35 private final boolean unknown;
37 public SingleResponse(CertId target, Date thisUpdate, Date nextUpdate) {
38 this(target, thisUpdate, nextUpdate, null);
41 public SingleResponse(CertId target, Date thisUpdate, Date nextUpdate, Date revoked) {
42 this(target, thisUpdate, nextUpdate, revoked, null);
45 public SingleResponse(CertId target, Date thisUpdate, Date nextUpdate, Date revoked, CRLReason res) {
47 this.thisUpdate = thisUpdate;
48 this.nextUpdate = nextUpdate;
49 this.revoked = revoked;
54 public SingleResponse(CertId target, Date thisUpdate, Date nextUpdate, boolean unkown) {
56 this.thisUpdate = thisUpdate;
57 this.nextUpdate = nextUpdate;
60 this.unknown = unkown;
63 private DerValue produceSingleResponse() throws IOException {
64 try (DerOutputStream r = new DerOutputStream()) {
65 try (DerOutputStream target = new DerOutputStream()) {
66 this.target.encode(target);
67 if (revoked == null && !unknown) {
68 target.putTag(DerValue.TAG_CONTEXT, false, (byte) 0);
70 } else if (revoked == null && unknown) {
71 target.putTag(DerValue.TAG_CONTEXT, false, (byte) 2);
74 try (DerOutputStream gt = new DerOutputStream()) {
75 gt.putGeneralizedTime(revoked);
76 // revocationReason [0] EXPLICIT CRLReason OPTIONAL
78 try (DerOutputStream crlr = new DerOutputStream()) {
79 crlr.putEnumerated(res.ordinal());
80 gt.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0), crlr);
84 target.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 1), gt);
88 target.putGeneralizedTime(thisUpdate);
89 try (DerOutputStream gt = new DerOutputStream()) {
90 gt.putGeneralizedTime(nextUpdate);
91 target.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0), gt);
94 r.write(DerValue.tag_Sequence, target);
96 return new DerValue(r.toByteArray());
101 private final SingleResponse[] res;
103 private X509Certificate[] signers;
105 private final X500Principal dn;
107 private final byte[] keyHash;
109 public OCSPResponse(X500Principal dn, SingleResponse[] res) {
115 public OCSPResponse(byte[] keyHash, SingleResponse[] res) {
117 this.keyHash = keyHash;
121 private OCSPResponse() {
127 public void setSigners(X509Certificate[] signers) {
128 this.signers = signers;
132 * Produce possibly signed binary data for this OCSPResponse
135 * the signature to sign the data with. Always required for
136 * publicly visible instance.
137 * @return the binary representation
138 * @throws IOException
140 * @throws GeneralSecurityException
143 public byte[] produceResponce(Signature s) throws IOException, GeneralSecurityException {
144 try (DerOutputStream dos2 = new DerOutputStream()) {
145 try (DerOutputStream dos = new DerOutputStream()) {
147 dos.putEnumerated(0); // successful
148 ObjectIdentifier ocspBasic = new ObjectIdentifier(new int[] {
149 1, 3, 6, 1, 5, 5, 7, 48, 1, 1
151 try (DerOutputStream tagS = new DerOutputStream()) {
152 try (DerOutputStream responseBytes = new DerOutputStream()) {
153 responseBytes.putOID(ocspBasic);
154 responseBytes.putOctetString(produceBasicOCSPResponse(s));
155 tagS.write(DerValue.tag_Sequence, responseBytes);
157 dos.write((byte) 0xA0, tagS);
160 dos.putEnumerated(1); // malformed request
163 dos2.write(DerValue.tag_Sequence, dos);
165 return dos2.toByteArray();
170 private byte[] produceBasicOCSPResponse(Signature s) throws IOException, GeneralSecurityException {
172 try (DerOutputStream o = new DerOutputStream()) {
173 try (DerOutputStream basicReponse = new DerOutputStream()) {
174 produceResponseData(basicReponse);
175 byte[] toSign = basicReponse.toByteArray();
177 AlgorithmId.get(s.getAlgorithm()).encode(basicReponse);
179 basicReponse.putBitString(s.sign());
181 if (signers != null) {
182 try (DerOutputStream certSeq = new DerOutputStream()) {
183 try (DerOutputStream certs = new DerOutputStream()) {
184 for (X509Certificate signer : signers) {
185 certs.write(signer.getEncoded());
187 certSeq.write(DerValue.tag_Sequence, certs);
189 basicReponse.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0), certSeq);
193 o.write(DerValue.tag_Sequence, basicReponse.toByteArray());
195 return o.toByteArray();
200 private void produceResponseData(DerOutputStream basicReponse) throws IOException {
201 try (DerOutputStream tbsResp = new DerOutputStream()) {
202 produceResponderId(tbsResp);
203 tbsResp.putGeneralizedTime(new Date(System.currentTimeMillis()));
204 DerValue[] tgt = new DerValue[res.length];
206 for (SingleResponse c : res) {
207 tgt[i++] = c.produceSingleResponse();
209 tbsResp.putSequence(tgt);
211 if (nonceExt != null) {
212 try (DerOutputStream extsSeq = new DerOutputStream()) {
213 try (DerOutputStream extsOut = new DerOutputStream()) {
214 nonceExt.encode(extsOut);
215 extsSeq.write(DerValue.tag_Sequence, extsOut);
216 tbsResp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 1), extsSeq);
220 basicReponse.write(DerValue.tag_Sequence, tbsResp.toByteArray());
224 private void produceResponderId(DerOutputStream tbsResp) throws IOException {
226 tbsResp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 1), dn.getEncoded());
228 try (DerOutputStream dos = new DerOutputStream()) {
229 dos.putOctetString(keyHash);
230 tbsResp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 2), dos);
236 public void updateNonce(OCSPRequest or) {
237 nonceExt = or.getNonceExt();
240 public static byte[] invalid() throws IOException, GeneralSecurityException {
241 return new OCSPResponse().produceResponce(null);