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.security.PrivateKey;
19
20 import javax.security.auth.Destroyable;
21
22 import io.netty.buffer.ByteBuf;
23 import io.netty.buffer.ByteBufAllocator;
24 import io.netty.buffer.Unpooled;
25 import io.netty.util.AbstractReferenceCounted;
26 import io.netty.util.CharsetUtil;
27 import io.netty.util.IllegalReferenceCountException;
28 import io.netty.util.internal.ObjectUtil;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public final class PemPrivateKey extends AbstractReferenceCounted implements PrivateKey, PemEncoded {
44 private static final long serialVersionUID = 7978017465645018936L;
45
46 private static final byte[] BEGIN_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n".getBytes(CharsetUtil.US_ASCII);
47 private static final byte[] END_PRIVATE_KEY = "\n-----END PRIVATE KEY-----\n".getBytes(CharsetUtil.US_ASCII);
48
49 private static final String PKCS8_FORMAT = "PKCS#8";
50
51
52
53
54 static PemEncoded toPEM(ByteBufAllocator allocator, boolean useDirect, PrivateKey key) {
55
56
57
58
59 if (key instanceof PemEncoded) {
60 return ((PemEncoded) key).retain();
61 }
62
63 byte[] bytes = key.getEncoded();
64 if (bytes == null) {
65 throw new IllegalArgumentException(key.getClass().getName() + " does not support encoding");
66 }
67
68 return toPEM(allocator, useDirect, bytes);
69 }
70
71 static PemEncoded toPEM(ByteBufAllocator allocator, boolean useDirect, byte[] bytes) {
72 ByteBuf encoded = Unpooled.wrappedBuffer(bytes);
73 try {
74 ByteBuf base64 = SslUtils.toBase64(allocator, encoded);
75 try {
76 int size = BEGIN_PRIVATE_KEY.length + base64.readableBytes() + END_PRIVATE_KEY.length;
77
78 boolean success = false;
79 final ByteBuf pem = useDirect ? allocator.directBuffer(size) : allocator.buffer(size);
80 try {
81 pem.writeBytes(BEGIN_PRIVATE_KEY);
82 pem.writeBytes(base64);
83 pem.writeBytes(END_PRIVATE_KEY);
84
85 PemValue value = new PemValue(pem, true);
86 success = true;
87 return value;
88 } finally {
89
90 if (!success) {
91 SslUtils.zerooutAndRelease(pem);
92 }
93 }
94 } finally {
95 SslUtils.zerooutAndRelease(base64);
96 }
97 } finally {
98 SslUtils.zerooutAndRelease(encoded);
99 }
100 }
101
102
103
104
105
106
107
108 public static PemPrivateKey valueOf(byte[] key) {
109 return valueOf(Unpooled.wrappedBuffer(key));
110 }
111
112
113
114
115
116
117
118 public static PemPrivateKey valueOf(ByteBuf key) {
119 return new PemPrivateKey(key);
120 }
121
122 private final ByteBuf content;
123
124 private PemPrivateKey(ByteBuf content) {
125 this.content = ObjectUtil.checkNotNull(content, "content");
126 }
127
128 @Override
129 public boolean isSensitive() {
130 return true;
131 }
132
133 @Override
134 public ByteBuf content() {
135 int count = refCnt();
136 if (count <= 0) {
137 throw new IllegalReferenceCountException(count);
138 }
139
140 return content;
141 }
142
143 @Override
144 public PemPrivateKey copy() {
145 return replace(content.copy());
146 }
147
148 @Override
149 public PemPrivateKey duplicate() {
150 return replace(content.duplicate());
151 }
152
153 @Override
154 public PemPrivateKey retainedDuplicate() {
155 return replace(content.retainedDuplicate());
156 }
157
158 @Override
159 public PemPrivateKey replace(ByteBuf content) {
160 return new PemPrivateKey(content);
161 }
162
163 @Override
164 public PemPrivateKey touch() {
165 content.touch();
166 return this;
167 }
168
169 @Override
170 public PemPrivateKey touch(Object hint) {
171 content.touch(hint);
172 return this;
173 }
174
175 @Override
176 public PemPrivateKey retain() {
177 return (PemPrivateKey) super.retain();
178 }
179
180 @Override
181 public PemPrivateKey retain(int increment) {
182 return (PemPrivateKey) super.retain(increment);
183 }
184
185 @Override
186 protected void deallocate() {
187
188
189 SslUtils.zerooutAndRelease(content);
190 }
191
192 @Override
193 public byte[] getEncoded() {
194 throw new UnsupportedOperationException();
195 }
196
197 @Override
198 public String getAlgorithm() {
199 throw new UnsupportedOperationException();
200 }
201
202 @Override
203 public String getFormat() {
204 return PKCS8_FORMAT;
205 }
206
207
208
209
210
211
212
213
214 @Override
215 public void destroy() {
216 release(refCnt());
217 }
218
219
220
221
222
223
224
225
226 @Override
227 public boolean isDestroyed() {
228 return refCnt() == 0;
229 }
230 }