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