1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.handler.ssl;
17
18 import io.netty5.buffer.api.Buffer;
19 import io.netty5.buffer.api.BufferAllocator;
20 import io.netty5.buffer.api.BufferHolder;
21 import io.netty5.buffer.api.SensitiveBufferAllocator;
22 import io.netty5.util.CharsetUtil;
23
24 import javax.security.auth.Destroyable;
25 import java.security.PrivateKey;
26
27 import static io.netty5.buffer.api.DefaultBufferAllocators.offHeapAllocator;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 public final class PemPrivateKey extends BufferHolder<PemPrivateKey> implements PrivateKey, PemEncoded {
43 private static final long serialVersionUID = 7978017465645018936L;
44
45 private static final byte[] BEGIN_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n".getBytes(CharsetUtil.US_ASCII);
46 private static final byte[] END_PRIVATE_KEY = "\n-----END PRIVATE KEY-----\n".getBytes(CharsetUtil.US_ASCII);
47
48 private static final String PKCS8_FORMAT = "PKCS#8";
49
50
51
52
53 static PemEncoded toPEM(PrivateKey key) {
54
55
56
57
58 if (key instanceof PemEncoded) {
59 return ((PemEncoded) key).copy();
60 }
61
62 byte[] bytes = key.getEncoded();
63 if (bytes == null) {
64 throw new IllegalArgumentException(key.getClass().getName() + " does not support encoding");
65 }
66
67 return toPEM(bytes);
68 }
69
70 static PemEncoded toPEM(byte[] bytes) {
71 BufferAllocator allocator = SensitiveBufferAllocator.sensitiveOffHeapAllocator();
72 try (Buffer encoded = allocator.copyOf(bytes);
73 Buffer base64 = SslUtils.toBase64(allocator, encoded)) {
74 int size = BEGIN_PRIVATE_KEY.length + base64.readableBytes() + END_PRIVATE_KEY.length;
75
76 boolean success = false;
77 final Buffer pem = allocator.allocate(size);
78 try {
79 pem.writeBytes(BEGIN_PRIVATE_KEY);
80 pem.writeBytes(base64);
81 pem.writeBytes(END_PRIVATE_KEY);
82
83 PemValue value = new PemValue(pem);
84 success = true;
85 return value;
86 } finally {
87
88 if (!success) {
89 pem.close();
90 }
91 }
92 }
93 }
94
95
96
97
98
99
100
101 public static PemPrivateKey valueOf(byte[] key) {
102 return valueOf(offHeapAllocator().copyOf(key));
103 }
104
105
106
107
108
109
110
111 public static PemPrivateKey valueOf(Buffer key) {
112 return new PemPrivateKey(key);
113 }
114
115 private PemPrivateKey(Buffer content) {
116 super(content.makeReadOnly());
117 }
118
119 @Override
120 public Buffer content() {
121 if (!isAccessible()) {
122 throw new IllegalStateException("PemPrivateKey is closed.");
123 }
124
125 return getBuffer();
126 }
127
128 @Override
129 public PemPrivateKey copy() {
130 Buffer buffer = getBuffer();
131 return new PemPrivateKey(buffer.copy(true));
132 }
133
134 @Override
135 protected PemPrivateKey receive(Buffer buf) {
136 return new PemPrivateKey(buf);
137 }
138
139 @Override
140 public byte[] getEncoded() {
141 throw new UnsupportedOperationException();
142 }
143
144 @Override
145 public String getAlgorithm() {
146 throw new UnsupportedOperationException();
147 }
148
149 @Override
150 public String getFormat() {
151 return PKCS8_FORMAT;
152 }
153
154 @Override
155 public void destroy() {
156 close();
157 }
158
159 @Override
160 public boolean isDestroyed() {
161 return !isAccessible();
162 }
163 }