1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl;
17
18 import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
19
20 import java.math.BigInteger;
21 import java.security.Principal;
22 import java.security.PublicKey;
23 import java.security.cert.CertificateEncodingException;
24 import java.security.cert.X509Certificate;
25 import java.util.Arrays;
26 import java.util.Date;
27 import java.util.Set;
28
29 import io.netty.buffer.ByteBuf;
30 import io.netty.buffer.ByteBufAllocator;
31 import io.netty.buffer.Unpooled;
32 import io.netty.util.CharsetUtil;
33 import io.netty.util.IllegalReferenceCountException;
34 import io.netty.util.internal.ObjectUtil;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public final class PemX509Certificate extends X509Certificate implements PemEncoded {
50
51 private static final byte[] BEGIN_CERT = "-----BEGIN CERTIFICATE-----\n".getBytes(CharsetUtil.US_ASCII);
52 private static final byte[] END_CERT = "\n-----END CERTIFICATE-----\n".getBytes(CharsetUtil.US_ASCII);
53
54
55
56
57 static PemEncoded toPEM(ByteBufAllocator allocator, boolean useDirect,
58 X509Certificate... chain) throws CertificateEncodingException {
59
60 checkNonEmpty(chain, "chain");
61
62
63
64
65
66
67 if (chain.length == 1) {
68 X509Certificate first = chain[0];
69 if (first instanceof PemEncoded) {
70 return ((PemEncoded) first).retain();
71 }
72 }
73
74 boolean success = false;
75 ByteBuf pem = null;
76 try {
77 for (X509Certificate cert : chain) {
78
79 if (cert == null) {
80 throw new IllegalArgumentException("Null element in chain: " + Arrays.toString(chain));
81 }
82
83 if (cert instanceof PemEncoded) {
84 pem = append(allocator, useDirect, (PemEncoded) cert, chain.length, pem);
85 } else {
86 pem = append(allocator, useDirect, cert, chain.length, pem);
87 }
88 }
89
90 PemValue value = new PemValue(pem, false);
91 success = true;
92 return value;
93 } finally {
94
95 if (!success && pem != null) {
96 pem.release();
97 }
98 }
99 }
100
101
102
103
104
105 private static ByteBuf append(ByteBufAllocator allocator, boolean useDirect,
106 PemEncoded encoded, int count, ByteBuf pem) {
107
108 ByteBuf content = encoded.content();
109
110 if (pem == null) {
111
112 pem = newBuffer(allocator, useDirect, content.readableBytes() * count);
113 }
114
115 pem.writeBytes(content.slice());
116 return pem;
117 }
118
119
120
121
122
123 private static ByteBuf append(ByteBufAllocator allocator, boolean useDirect,
124 X509Certificate cert, int count, ByteBuf pem) throws CertificateEncodingException {
125
126 ByteBuf encoded = Unpooled.wrappedBuffer(cert.getEncoded());
127 try {
128 ByteBuf base64 = SslUtils.toBase64(allocator, encoded);
129 try {
130 if (pem == null) {
131
132
133
134 pem = newBuffer(allocator, useDirect,
135 (BEGIN_CERT.length + base64.readableBytes() + END_CERT.length) * count);
136 }
137
138 pem.writeBytes(BEGIN_CERT);
139 pem.writeBytes(base64);
140 pem.writeBytes(END_CERT);
141 } finally {
142 base64.release();
143 }
144 } finally {
145 encoded.release();
146 }
147
148 return pem;
149 }
150
151 private static ByteBuf newBuffer(ByteBufAllocator allocator, boolean useDirect, int initialCapacity) {
152 return useDirect ? allocator.directBuffer(initialCapacity) : allocator.buffer(initialCapacity);
153 }
154
155
156
157
158
159
160
161 public static PemX509Certificate valueOf(byte[] key) {
162 return valueOf(Unpooled.wrappedBuffer(key));
163 }
164
165
166
167
168
169
170
171 public static PemX509Certificate valueOf(ByteBuf key) {
172 return new PemX509Certificate(key);
173 }
174
175 private final ByteBuf content;
176
177 private PemX509Certificate(ByteBuf content) {
178 this.content = ObjectUtil.checkNotNull(content, "content");
179 }
180
181 @Override
182 public boolean isSensitive() {
183
184 return false;
185 }
186
187 @Override
188 public int refCnt() {
189 return content.refCnt();
190 }
191
192 @Override
193 public ByteBuf content() {
194 int count = refCnt();
195 if (count <= 0) {
196 throw new IllegalReferenceCountException(count);
197 }
198
199 return content;
200 }
201
202 @Override
203 public PemX509Certificate copy() {
204 return replace(content.copy());
205 }
206
207 @Override
208 public PemX509Certificate duplicate() {
209 return replace(content.duplicate());
210 }
211
212 @Override
213 public PemX509Certificate retainedDuplicate() {
214 return replace(content.retainedDuplicate());
215 }
216
217 @Override
218 public PemX509Certificate replace(ByteBuf content) {
219 return new PemX509Certificate(content);
220 }
221
222 @Override
223 public PemX509Certificate retain() {
224 content.retain();
225 return this;
226 }
227
228 @Override
229 public PemX509Certificate retain(int increment) {
230 content.retain(increment);
231 return this;
232 }
233
234 @Override
235 public PemX509Certificate touch() {
236 content.touch();
237 return this;
238 }
239
240 @Override
241 public PemX509Certificate touch(Object hint) {
242 content.touch(hint);
243 return this;
244 }
245
246 @Override
247 public boolean release() {
248 return content.release();
249 }
250
251 @Override
252 public boolean release(int decrement) {
253 return content.release(decrement);
254 }
255
256 @Override
257 public byte[] getEncoded() {
258 throw new UnsupportedOperationException();
259 }
260
261 @Override
262 public boolean hasUnsupportedCriticalExtension() {
263 throw new UnsupportedOperationException();
264 }
265
266 @Override
267 public Set<String> getCriticalExtensionOIDs() {
268 throw new UnsupportedOperationException();
269 }
270
271 @Override
272 public Set<String> getNonCriticalExtensionOIDs() {
273 throw new UnsupportedOperationException();
274 }
275
276 @Override
277 public byte[] getExtensionValue(String oid) {
278 throw new UnsupportedOperationException();
279 }
280
281 @Override
282 public void checkValidity() {
283 throw new UnsupportedOperationException();
284 }
285
286 @Override
287 public void checkValidity(Date date) {
288 throw new UnsupportedOperationException();
289 }
290
291 @Override
292 public int getVersion() {
293 throw new UnsupportedOperationException();
294 }
295
296 @Override
297 public BigInteger getSerialNumber() {
298 throw new UnsupportedOperationException();
299 }
300
301 @Override
302 public Principal getIssuerDN() {
303 throw new UnsupportedOperationException();
304 }
305
306 @Override
307 public Principal getSubjectDN() {
308 throw new UnsupportedOperationException();
309 }
310
311 @Override
312 public Date getNotBefore() {
313 throw new UnsupportedOperationException();
314 }
315
316 @Override
317 public Date getNotAfter() {
318 throw new UnsupportedOperationException();
319 }
320
321 @Override
322 public byte[] getTBSCertificate() {
323 throw new UnsupportedOperationException();
324 }
325
326 @Override
327 public byte[] getSignature() {
328 throw new UnsupportedOperationException();
329 }
330
331 @Override
332 public String getSigAlgName() {
333 throw new UnsupportedOperationException();
334 }
335
336 @Override
337 public String getSigAlgOID() {
338 throw new UnsupportedOperationException();
339 }
340
341 @Override
342 public byte[] getSigAlgParams() {
343 throw new UnsupportedOperationException();
344 }
345
346 @Override
347 public boolean[] getIssuerUniqueID() {
348 throw new UnsupportedOperationException();
349 }
350
351 @Override
352 public boolean[] getSubjectUniqueID() {
353 throw new UnsupportedOperationException();
354 }
355
356 @Override
357 public boolean[] getKeyUsage() {
358 throw new UnsupportedOperationException();
359 }
360
361 @Override
362 public int getBasicConstraints() {
363 throw new UnsupportedOperationException();
364 }
365
366 @Override
367 public void verify(PublicKey key) {
368 throw new UnsupportedOperationException();
369 }
370
371 @Override
372 public void verify(PublicKey key, String sigProvider) {
373 throw new UnsupportedOperationException();
374 }
375
376 @Override
377 public PublicKey getPublicKey() {
378 throw new UnsupportedOperationException();
379 }
380
381 @Override
382 public boolean equals(Object o) {
383 if (o == this) {
384 return true;
385 }
386 if (!(o instanceof PemX509Certificate)) {
387 return false;
388 }
389
390 PemX509Certificate other = (PemX509Certificate) o;
391 return content.equals(other.content);
392 }
393
394 @Override
395 public int hashCode() {
396 return content.hashCode();
397 }
398
399 @Override
400 public String toString() {
401 return content.toString(CharsetUtil.UTF_8);
402 }
403 }