1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty5.example.ocsp;
18
19 import io.netty5.bootstrap.ServerBootstrap;
20 import io.netty5.channel.Channel;
21 import io.netty5.channel.ChannelInitializer;
22 import io.netty5.channel.ChannelPipeline;
23 import io.netty5.handler.ssl.OpenSsl;
24 import io.netty5.handler.ssl.ReferenceCountedOpenSslContext;
25 import io.netty5.handler.ssl.ReferenceCountedOpenSslEngine;
26 import io.netty5.handler.ssl.SslContextBuilder;
27 import io.netty5.handler.ssl.SslHandler;
28 import io.netty5.handler.ssl.SslProvider;
29 import io.netty5.util.CharsetUtil;
30 import org.bouncycastle.asn1.ocsp.OCSPResponseStatus;
31 import org.bouncycastle.cert.X509CertificateHolder;
32 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
33 import org.bouncycastle.cert.ocsp.BasicOCSPResp;
34 import org.bouncycastle.cert.ocsp.CertificateStatus;
35 import org.bouncycastle.cert.ocsp.OCSPReq;
36 import org.bouncycastle.cert.ocsp.OCSPResp;
37 import org.bouncycastle.cert.ocsp.SingleResp;
38 import org.bouncycastle.jce.provider.BouncyCastleProvider;
39 import org.bouncycastle.openssl.PEMParser;
40
41 import java.io.BufferedReader;
42 import java.io.FileNotFoundException;
43 import java.io.InputStream;
44 import java.io.InputStreamReader;
45 import java.io.Reader;
46 import java.math.BigInteger;
47 import java.net.URI;
48 import java.security.PrivateKey;
49 import java.security.cert.X509Certificate;
50 import java.util.ArrayList;
51 import java.util.List;
52 import java.util.concurrent.TimeUnit;
53
54
55
56
57
58 @SuppressWarnings("unused")
59 public class OcspServerExample {
60 public static void main(String[] args) throws Exception {
61
62 PrivateKey privateKey = null;
63
64
65
66
67 X509Certificate[] keyCertChain = parseCertificates(OcspServerExample.class, "netty_io_chain.pem");
68
69 X509Certificate certificate = keyCertChain[0];
70 X509Certificate issuer = keyCertChain[keyCertChain.length - 1];
71
72
73
74 URI uri = OcspUtils.ocspUri(certificate);
75 System.out.println("OCSP Responder URI: " + uri);
76
77 if (uri == null) {
78 throw new IllegalStateException("The CA/certificate doesn't have an OCSP responder");
79 }
80
81
82 OCSPReq request = new OcspRequestBuilder()
83 .certificate(certificate)
84 .issuer(issuer)
85 .build();
86
87
88 OCSPResp response = OcspUtils.request(uri, request, 5L, TimeUnit.SECONDS);
89 if (response.getStatus() != OCSPResponseStatus.SUCCESSFUL) {
90 throw new IllegalStateException("response-status=" + response.getStatus());
91 }
92
93
94 BasicOCSPResp basicResponse = (BasicOCSPResp) response.getResponseObject();
95 SingleResp first = basicResponse.getResponses()[0];
96
97 CertificateStatus status = first.getCertStatus();
98 System.out.println("Status: " + (status == CertificateStatus.GOOD ? "Good" : status));
99 System.out.println("This Update: " + first.getThisUpdate());
100 System.out.println("Next Update: " + first.getNextUpdate());
101
102 if (status != null) {
103 throw new IllegalStateException("certificate-status=" + status);
104 }
105
106 BigInteger certSerial = certificate.getSerialNumber();
107 BigInteger ocspSerial = first.getCertID().getSerialNumber();
108 if (!certSerial.equals(ocspSerial)) {
109 throw new IllegalStateException("Bad Serials=" + certSerial + " vs. " + ocspSerial);
110 }
111
112
113
114
115 if (!OpenSsl.isAvailable()) {
116 throw new IllegalStateException("OpenSSL is not available!");
117 }
118
119 if (!OpenSsl.isOcspSupported()) {
120 throw new IllegalStateException("OCSP is not supported!");
121 }
122
123 if (privateKey == null) {
124 throw new IllegalStateException("Because we don't have a PrivateKey we can't continue past this point.");
125 }
126
127 ReferenceCountedOpenSslContext context =
128 (ReferenceCountedOpenSslContext) SslContextBuilder.forServer(privateKey, keyCertChain)
129 .sslProvider(SslProvider.OPENSSL)
130 .enableOcsp(true)
131 .build();
132
133 try {
134 ServerBootstrap bootstrap = new ServerBootstrap()
135 .childHandler(newServerHandler(context, response));
136
137
138 } finally {
139 context.release();
140 }
141 }
142
143 private static ChannelInitializer<Channel> newServerHandler(final ReferenceCountedOpenSslContext context,
144 final OCSPResp response) {
145 return new ChannelInitializer<>() {
146 @Override
147 protected void initChannel(Channel ch) throws Exception {
148 SslHandler sslHandler = context.newHandler(ch.bufferAllocator());
149
150 if (response != null) {
151 ReferenceCountedOpenSslEngine engine
152 = (ReferenceCountedOpenSslEngine) sslHandler.engine();
153
154 engine.setOcspResponse(response.getEncoded());
155 }
156
157 ChannelPipeline pipeline = ch.pipeline();
158 pipeline.addLast(sslHandler);
159
160
161 }
162 };
163 }
164
165 private static X509Certificate[] parseCertificates(Class<?> clazz, String name) throws Exception {
166 try (InputStream in = clazz.getResourceAsStream(name)) {
167 if (in == null) {
168 throw new FileNotFoundException("clazz=" + clazz + ", name=" + name);
169 }
170 try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, CharsetUtil.US_ASCII))) {
171 return parseCertificates(reader);
172 }
173 }
174 }
175
176 private static X509Certificate[] parseCertificates(Reader reader) throws Exception {
177
178 JcaX509CertificateConverter converter = new JcaX509CertificateConverter()
179 .setProvider(new BouncyCastleProvider());
180
181 List<X509Certificate> dst = new ArrayList<>();
182
183 try (PEMParser parser = new PEMParser(reader)) {
184 X509CertificateHolder holder;
185
186 while ((holder = (X509CertificateHolder) parser.readObject()) != null) {
187 X509Certificate certificate = converter.getCertificate(holder);
188 if (certificate == null) {
189 continue;
190 }
191
192 dst.add(certificate);
193 }
194 }
195
196 return dst.toArray(new X509Certificate[0]);
197 }
198 }