1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl.util;
17
18 import io.netty.util.Recycler;
19 import io.netty.util.internal.ObjectUtil;
20
21 import java.io.ByteArrayInputStream;
22 import java.math.BigInteger;
23 import java.security.InvalidKeyException;
24 import java.security.NoSuchAlgorithmException;
25 import java.security.NoSuchProviderException;
26 import java.security.Principal;
27 import java.security.Provider;
28 import java.security.PublicKey;
29 import java.security.SignatureException;
30 import java.security.cert.CertificateEncodingException;
31 import java.security.cert.CertificateException;
32 import java.security.cert.CertificateExpiredException;
33 import java.security.cert.CertificateFactory;
34 import java.security.cert.CertificateNotYetValidException;
35 import java.security.cert.CertificateParsingException;
36 import java.security.cert.X509Certificate;
37 import java.util.Collection;
38 import java.util.Date;
39 import java.util.List;
40 import java.util.Set;
41 import javax.security.auth.x500.X500Principal;
42
43 public final class LazyX509Certificate extends X509Certificate {
44 private static final Recycler<CertFactoryHandle> CERT_FACTORIES = new Recycler<CertFactoryHandle>() {
45 @Override
46 protected CertFactoryHandle newObject(Handle<CertFactoryHandle> handle) {
47 try {
48 return new CertFactoryHandle(CertificateFactory.getInstance("X.509"), handle);
49 } catch (CertificateException e) {
50 throw new IllegalStateException(e);
51 }
52 }
53 };
54
55 private static final class CertFactoryHandle {
56 private final CertificateFactory factory;
57 private final Recycler.EnhancedHandle<CertFactoryHandle> handle;
58
59 private CertFactoryHandle(CertificateFactory factory, Recycler.Handle<CertFactoryHandle> handle) {
60 this.factory = factory;
61 this.handle = (Recycler.EnhancedHandle<CertFactoryHandle>) handle;
62 }
63
64 public X509Certificate generateCertificate(byte[] bytes) throws CertificateException {
65 return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(bytes));
66 }
67
68 public void recycle() {
69 handle.unguardedRecycle(this);
70 }
71 }
72
73 private final byte[] bytes;
74 private volatile X509Certificate wrapped;
75
76
77
78
79 public LazyX509Certificate(byte[] bytes) {
80 this.bytes = ObjectUtil.checkNotNull(bytes, "bytes");
81 }
82
83 @Override
84 public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException {
85 unwrap().checkValidity();
86 }
87
88 @Override
89 public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException {
90 unwrap().checkValidity(date);
91 }
92
93 @Override
94 public X500Principal getIssuerX500Principal() {
95 return unwrap().getIssuerX500Principal();
96 }
97
98 @Override
99 public X500Principal getSubjectX500Principal() {
100 return unwrap().getSubjectX500Principal();
101 }
102
103 @Override
104 public List<String> getExtendedKeyUsage() throws CertificateParsingException {
105 return unwrap().getExtendedKeyUsage();
106 }
107
108 @Override
109 public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
110 return unwrap().getSubjectAlternativeNames();
111 }
112
113 @Override
114 public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
115 return unwrap().getIssuerAlternativeNames();
116 }
117
118 @Override
119 public void verify(PublicKey key, Provider sigProvider)
120 throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
121 unwrap().verify(key, sigProvider);
122 }
123
124 @Override
125 public int getVersion() {
126 return unwrap().getVersion();
127 }
128
129 @Override
130 public BigInteger getSerialNumber() {
131 return unwrap().getSerialNumber();
132 }
133
134 @Override
135 public Principal getIssuerDN() {
136 return unwrap().getIssuerDN();
137 }
138
139 @Override
140 public Principal getSubjectDN() {
141 return unwrap().getSubjectDN();
142 }
143
144 @Override
145 public Date getNotBefore() {
146 return unwrap().getNotBefore();
147 }
148
149 @Override
150 public Date getNotAfter() {
151 return unwrap().getNotAfter();
152 }
153
154 @Override
155 public byte[] getTBSCertificate() throws CertificateEncodingException {
156 return unwrap().getTBSCertificate();
157 }
158
159 @Override
160 public byte[] getSignature() {
161 return unwrap().getSignature();
162 }
163
164 @Override
165 public String getSigAlgName() {
166 return unwrap().getSigAlgName();
167 }
168
169 @Override
170 public String getSigAlgOID() {
171 return unwrap().getSigAlgOID();
172 }
173
174 @Override
175 public byte[] getSigAlgParams() {
176 return unwrap().getSigAlgParams();
177 }
178
179 @Override
180 public boolean[] getIssuerUniqueID() {
181 return unwrap().getIssuerUniqueID();
182 }
183
184 @Override
185 public boolean[] getSubjectUniqueID() {
186 return unwrap().getSubjectUniqueID();
187 }
188
189 @Override
190 public boolean[] getKeyUsage() {
191 return unwrap().getKeyUsage();
192 }
193
194 @Override
195 public int getBasicConstraints() {
196 return unwrap().getBasicConstraints();
197 }
198
199 @Override
200 public byte[] getEncoded() {
201 return bytes.clone();
202 }
203
204 @Override
205 public void verify(PublicKey key)
206 throws CertificateException, NoSuchAlgorithmException,
207 InvalidKeyException, NoSuchProviderException, SignatureException {
208 unwrap().verify(key);
209 }
210
211 @Override
212 public void verify(PublicKey key, String sigProvider)
213 throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
214 NoSuchProviderException, SignatureException {
215 unwrap().verify(key, sigProvider);
216 }
217
218 @Override
219 public String toString() {
220 return unwrap().toString();
221 }
222
223 @Override
224 public PublicKey getPublicKey() {
225 return unwrap().getPublicKey();
226 }
227
228 @Override
229 public boolean hasUnsupportedCriticalExtension() {
230 return unwrap().hasUnsupportedCriticalExtension();
231 }
232
233 @Override
234 public Set<String> getCriticalExtensionOIDs() {
235 return unwrap().getCriticalExtensionOIDs();
236 }
237
238 @Override
239 public Set<String> getNonCriticalExtensionOIDs() {
240 return unwrap().getNonCriticalExtensionOIDs();
241 }
242
243 @Override
244 public byte[] getExtensionValue(String oid) {
245 return unwrap().getExtensionValue(oid);
246 }
247
248 private X509Certificate unwrap() {
249 X509Certificate wrapped = this.wrapped;
250 if (wrapped == null) {
251 CertFactoryHandle factory = null;
252 try {
253 factory = CERT_FACTORIES.get();
254 wrapped = this.wrapped = factory.generateCertificate(bytes);
255 } catch (CertificateException e) {
256 throw new IllegalStateException(e);
257 } finally {
258 if (factory != null) {
259 factory.recycle();
260 }
261 }
262 }
263 return wrapped;
264 }
265 }