View Javadoc
1   /*
2    * Copyright 2017 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License, version
5    * 2.0 (the "License"); you may not use this file except in compliance with the
6    * License. You may obtain a copy of the License at:
7    *
8    * https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  
17  package io.netty5.example.ocsp;
18  
19  import org.bouncycastle.asn1.DEROctetString;
20  import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
21  import org.bouncycastle.asn1.x509.Extension;
22  import org.bouncycastle.asn1.x509.Extensions;
23  import org.bouncycastle.cert.X509CertificateHolder;
24  import org.bouncycastle.cert.ocsp.CertificateID;
25  import org.bouncycastle.cert.ocsp.OCSPException;
26  import org.bouncycastle.cert.ocsp.OCSPReq;
27  import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
28  import org.bouncycastle.operator.DigestCalculator;
29  
30  import java.io.IOException;
31  import java.math.BigInteger;
32  import java.security.SecureRandom;
33  import java.security.cert.CertificateEncodingException;
34  import java.security.cert.X509Certificate;
35  
36  import static java.util.Objects.requireNonNull;
37  
38  /**
39   * This is a simplified version of BC's own {@link OCSPReqBuilder}.
40   *
41   * @see OCSPReqBuilder
42   */
43  public class OcspRequestBuilder {
44  
45      private static final SecureRandom GENERATOR = new SecureRandom();
46  
47      private SecureRandom generator = GENERATOR;
48  
49      private DigestCalculator calculator = Digester.sha1();
50  
51      private X509Certificate certificate;
52  
53      private X509Certificate issuer;
54  
55      public OcspRequestBuilder generator(SecureRandom generator) {
56          this.generator = generator;
57          return this;
58      }
59  
60      public OcspRequestBuilder calculator(DigestCalculator calculator) {
61          this.calculator = calculator;
62          return this;
63      }
64  
65      public OcspRequestBuilder certificate(X509Certificate certificate) {
66          this.certificate = certificate;
67          return this;
68      }
69  
70      public OcspRequestBuilder issuer(X509Certificate issuer) {
71          this.issuer = issuer;
72          return this;
73      }
74  
75      /**
76       * ATTENTION: The returned {@link OCSPReq} is not re-usable/cacheable! It contains a one-time nonce
77       * and CA's will (should) reject subsequent requests that have the same nonce value.
78       */
79      public OCSPReq build() throws OCSPException, IOException, CertificateEncodingException {
80          SecureRandom generator = requireNonNull(this.generator, "generator");
81          DigestCalculator calculator = requireNonNull(this.calculator, "calculator");
82          X509Certificate certificate = requireNonNull(this.certificate, "certificate");
83          X509Certificate issuer = requireNonNull(this.issuer, "issuer");
84  
85          BigInteger serial = certificate.getSerialNumber();
86  
87          CertificateID certId = new CertificateID(calculator,
88                  new X509CertificateHolder(issuer.getEncoded()), serial);
89  
90          OCSPReqBuilder builder = new OCSPReqBuilder();
91          builder.addRequest(certId);
92  
93          byte[] nonce = new byte[8];
94          generator.nextBytes(nonce);
95  
96          Extension[] extensions = new Extension[] {
97                  new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false,
98                          new DEROctetString(nonce)) };
99  
100         builder.setRequestExtensions(new Extensions(extensions));
101 
102         return builder.build();
103     }
104 }