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