1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl;
17
18 import java.math.BigInteger;
19 import java.security.Principal;
20 import java.security.PublicKey;
21 import java.security.cert.CertificateEncodingException;
22 import java.security.cert.X509Certificate;
23 import java.util.Arrays;
24 import java.util.Date;
25 import java.util.Set;
26
27 import io.netty.buffer.ByteBuf;
28 import io.netty.buffer.ByteBufAllocator;
29 import io.netty.buffer.Unpooled;
30 import io.netty.util.CharsetUtil;
31 import io.netty.util.IllegalReferenceCountException;
32 import io.netty.util.internal.ObjectUtil;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public final class PemX509Certificate extends X509Certificate implements PemEncoded {
48
49 private static final byte[] BEGIN_CERT = "-----BEGIN CERTIFICATE-----\n".getBytes(CharsetUtil.US_ASCII);
50 private static final byte[] END_CERT = "\n-----END CERTIFICATE-----\n".getBytes(CharsetUtil.US_ASCII);
51
52
53
54
55 static PemEncoded toPEM(ByteBufAllocator allocator, boolean useDirect,
56 X509Certificate... chain) throws CertificateEncodingException {
57
58 if (chain == null || chain.length == 0) {
59 throw new IllegalArgumentException("X.509 certificate chain can't be null or empty");
60 }
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 new PemX509Certificate(content.copy());
205 }
206
207 @Override
208 public PemX509Certificate duplicate() {
209 return new PemX509Certificate(content.duplicate());
210 }
211
212 @Override
213 public PemX509Certificate retain() {
214 content.retain();
215 return this;
216 }
217
218 @Override
219 public PemX509Certificate retain(int increment) {
220 content.retain(increment);
221 return this;
222 }
223
224 @Override
225 public boolean release() {
226 return content.release();
227 }
228
229 @Override
230 public boolean release(int decrement) {
231 return content.release(decrement);
232 }
233
234 @Override
235 public byte[] getEncoded() {
236 throw new UnsupportedOperationException();
237 }
238
239 @Override
240 public boolean hasUnsupportedCriticalExtension() {
241 throw new UnsupportedOperationException();
242 }
243
244 @Override
245 public Set<String> getCriticalExtensionOIDs() {
246 throw new UnsupportedOperationException();
247 }
248
249 @Override
250 public Set<String> getNonCriticalExtensionOIDs() {
251 throw new UnsupportedOperationException();
252 }
253
254 @Override
255 public byte[] getExtensionValue(String oid) {
256 throw new UnsupportedOperationException();
257 }
258
259 @Override
260 public void checkValidity() {
261 throw new UnsupportedOperationException();
262 }
263
264 @Override
265 public void checkValidity(Date date) {
266 throw new UnsupportedOperationException();
267 }
268
269 @Override
270 public int getVersion() {
271 throw new UnsupportedOperationException();
272 }
273
274 @Override
275 public BigInteger getSerialNumber() {
276 throw new UnsupportedOperationException();
277 }
278
279 @Override
280 public Principal getIssuerDN() {
281 throw new UnsupportedOperationException();
282 }
283
284 @Override
285 public Principal getSubjectDN() {
286 throw new UnsupportedOperationException();
287 }
288
289 @Override
290 public Date getNotBefore() {
291 throw new UnsupportedOperationException();
292 }
293
294 @Override
295 public Date getNotAfter() {
296 throw new UnsupportedOperationException();
297 }
298
299 @Override
300 public byte[] getTBSCertificate() {
301 throw new UnsupportedOperationException();
302 }
303
304 @Override
305 public byte[] getSignature() {
306 throw new UnsupportedOperationException();
307 }
308
309 @Override
310 public String getSigAlgName() {
311 throw new UnsupportedOperationException();
312 }
313
314 @Override
315 public String getSigAlgOID() {
316 throw new UnsupportedOperationException();
317 }
318
319 @Override
320 public byte[] getSigAlgParams() {
321 throw new UnsupportedOperationException();
322 }
323
324 @Override
325 public boolean[] getIssuerUniqueID() {
326 throw new UnsupportedOperationException();
327 }
328
329 @Override
330 public boolean[] getSubjectUniqueID() {
331 throw new UnsupportedOperationException();
332 }
333
334 @Override
335 public boolean[] getKeyUsage() {
336 throw new UnsupportedOperationException();
337 }
338
339 @Override
340 public int getBasicConstraints() {
341 throw new UnsupportedOperationException();
342 }
343
344 @Override
345 public void verify(PublicKey key) {
346 throw new UnsupportedOperationException();
347 }
348
349 @Override
350 public void verify(PublicKey key, String sigProvider) {
351 throw new UnsupportedOperationException();
352 }
353
354 @Override
355 public PublicKey getPublicKey() {
356 throw new UnsupportedOperationException();
357 }
358
359 @Override
360 public boolean equals(Object o) {
361 if (o == this) {
362 return true;
363 } else if (!(o instanceof PemX509Certificate)) {
364 return false;
365 }
366
367 PemX509Certificate other = (PemX509Certificate) o;
368 return content.equals(other.content);
369 }
370
371 @Override
372 public int hashCode() {
373 return content.hashCode();
374 }
375
376 @Override
377 public String toString() {
378 return content.toString(CharsetUtil.UTF_8);
379 }
380 }