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